From 4d26b47e6c671d3209d456bc30c3ed8dce49ccef Mon Sep 17 00:00:00 2001 From: Sven Meyer Date: Wed, 28 Aug 2024 11:30:44 +0200 Subject: [PATCH 01/61] Add license and gitignore --- boomerangScope-SootUp/.gitignore | 2 + boomerangScope-SootUp/LICENSE.txt | 277 + .../target/apidocs/allclasses-index.html | 227 - .../target/apidocs/allclasses.html | 44 - .../target/apidocs/allpackages-index.html | 165 - .../scene/sootup/BoomerangPreInterceptor.html | 360 - .../sootup/JimpleUpControlFlowGraph.html | 417 - .../scene/sootup/JimpleUpDeclaredMethod.html | 517 - .../scene/sootup/JimpleUpDoubleVal.html | 413 - .../boomerang/scene/sootup/JimpleUpField.html | 410 - .../scene/sootup/JimpleUpIfStatement.html | 423 - .../sootup/JimpleUpInstanceFieldRef.html | 388 - .../scene/sootup/JimpleUpInvokeExpr.html | 478 - .../scene/sootup/JimpleUpMethod.html | 739 -- .../scene/sootup/JimpleUpStatement.html | 1037 -- .../scene/sootup/JimpleUpStaticFieldVal.html | 903 -- .../boomerang/scene/sootup/JimpleUpType.html | 456 - .../boomerang/scene/sootup/JimpleUpVal.html | 936 -- .../scene/sootup/JimpleUpWrappedClass.html | 494 - .../scene/sootup/SootUpCallGraph.html | 298 - .../boomerang/scene/sootup/SootUpClient.html | 379 - .../scene/sootup/SootUpDataFlowScope.html | 312 - .../class-use/BoomerangPreInterceptor.html | 147 - .../class-use/JimpleUpControlFlowGraph.html | 147 - .../class-use/JimpleUpDeclaredMethod.html | 147 - .../sootup/class-use/JimpleUpDoubleVal.html | 147 - .../scene/sootup/class-use/JimpleUpField.html | 175 - .../sootup/class-use/JimpleUpIfStatement.html | 147 - .../class-use/JimpleUpInstanceFieldRef.html | 147 - .../sootup/class-use/JimpleUpInvokeExpr.html | 175 - .../sootup/class-use/JimpleUpMethod.html | 252 - .../sootup/class-use/JimpleUpStatement.html | 147 - .../class-use/JimpleUpStaticFieldVal.html | 147 - .../scene/sootup/class-use/JimpleUpType.html | 147 - .../scene/sootup/class-use/JimpleUpVal.html | 176 - .../class-use/JimpleUpWrappedClass.html | 147 - .../sootup/class-use/SootUpCallGraph.html | 147 - .../scene/sootup/class-use/SootUpClient.html | 176 - .../sootup/class-use/SootUpDataFlowScope.html | 147 - .../scene/sootup/package-summary.html | 229 - .../boomerang/scene/sootup/package-tree.html | 205 - .../boomerang/scene/sootup/package-use.html | 183 - .../target/apidocs/constant-values.html | 149 - .../target/apidocs/deprecated-list.html | 147 - .../target/apidocs/element-list | 1 - .../target/apidocs/help-doc.html | 273 - .../target/apidocs/index-all.html | 738 -- .../target/apidocs/index.html | 23 - .../apidocs/jquery/external/jquery/jquery.js | 10598 --------------- .../images/ui-bg_glass_55_fbf9ee_1x400.png | Bin 335 -> 0 bytes .../images/ui-bg_glass_65_dadada_1x400.png | Bin 262 -> 0 bytes .../images/ui-bg_glass_75_dadada_1x400.png | Bin 262 -> 0 bytes .../images/ui-bg_glass_75_e6e6e6_1x400.png | Bin 262 -> 0 bytes .../images/ui-bg_glass_95_fef1ec_1x400.png | Bin 332 -> 0 bytes .../ui-bg_highlight-soft_75_cccccc_1x100.png | Bin 280 -> 0 bytes .../jquery/images/ui-icons_222222_256x240.png | Bin 6922 -> 0 bytes .../jquery/images/ui-icons_2e83ff_256x240.png | Bin 4549 -> 0 bytes .../jquery/images/ui-icons_454545_256x240.png | Bin 6992 -> 0 bytes .../jquery/images/ui-icons_888888_256x240.png | Bin 6999 -> 0 bytes .../jquery/images/ui-icons_cd0a0a_256x240.png | Bin 4549 -> 0 bytes .../target/apidocs/jquery/jquery-3.5.1.js | 10872 ---------------- .../target/apidocs/jquery/jquery-ui.css | 582 - .../target/apidocs/jquery/jquery-ui.js | 2659 ---- .../target/apidocs/jquery/jquery-ui.min.css | 7 - .../target/apidocs/jquery/jquery-ui.min.js | 6 - .../apidocs/jquery/jquery-ui.structure.css | 156 - .../jquery/jquery-ui.structure.min.css | 5 - .../jquery/jszip-utils/dist/jszip-utils-ie.js | 56 - .../jszip-utils/dist/jszip-utils-ie.min.js | 10 - .../jquery/jszip-utils/dist/jszip-utils.js | 118 - .../jszip-utils/dist/jszip-utils.min.js | 10 - .../target/apidocs/jquery/jszip/dist/jszip.js | 30 - .../apidocs/jquery/jszip/dist/jszip.min.js | 13 - .../target/apidocs/member-search-index.js | 1 - .../target/apidocs/member-search-index.zip | Bin 2286 -> 0 bytes .../target/apidocs/overview-tree.html | 209 - .../target/apidocs/package-search-index.js | 1 - .../target/apidocs/package-search-index.zip | Bin 238 -> 0 bytes .../target/apidocs/resources/glass.png | Bin 499 -> 0 bytes .../target/apidocs/resources/x.png | Bin 394 -> 0 bytes .../target/apidocs/script.js | 149 - .../target/apidocs/search.js | 326 - .../target/apidocs/stylesheet.css | 906 -- .../target/apidocs/type-search-index.js | 1 - .../target/apidocs/type-search-index.zip | Bin 392 -> 0 bytes ...erangScope-SootUp-3.1.2-Sparse-javadoc.jar | Bin 435466 -> 0 bytes ...erangScope-SootUp-3.1.2-Sparse-sources.jar | Bin 18931 -> 0 bytes .../boomerangScope-SootUp-3.1.2-Sparse.jar | Bin 36582 -> 0 bytes .../javadoc-options-javadoc-resources.xml | 10 - .../javadoc-bundle-options/package-list | 217 - .../target/maven-archiver/pom.properties | 5 - .../maven-javadoc-plugin-stale-data.txt | 101 - .../compile/default-compile/createdFiles.lst | 18 - .../compile/default-compile/inputFiles.lst | 17 - .../default-testCompile/createdFiles.lst | 0 .../default-testCompile/inputFiles.lst | 0 96 files changed, 279 insertions(+), 41145 deletions(-) create mode 100644 boomerangScope-SootUp/.gitignore create mode 100644 boomerangScope-SootUp/LICENSE.txt delete mode 100644 boomerangScope-SootUp/target/apidocs/allclasses-index.html delete mode 100644 boomerangScope-SootUp/target/apidocs/allclasses.html delete mode 100644 boomerangScope-SootUp/target/apidocs/allpackages-index.html delete mode 100644 boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/BoomerangPreInterceptor.html delete mode 100644 boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/JimpleUpControlFlowGraph.html delete mode 100644 boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/JimpleUpDeclaredMethod.html delete mode 100644 boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/JimpleUpDoubleVal.html delete mode 100644 boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/JimpleUpField.html delete mode 100644 boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/JimpleUpIfStatement.html delete mode 100644 boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/JimpleUpInstanceFieldRef.html delete mode 100644 boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/JimpleUpInvokeExpr.html delete mode 100644 boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/JimpleUpMethod.html delete mode 100644 boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/JimpleUpStatement.html delete mode 100644 boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/JimpleUpStaticFieldVal.html delete mode 100644 boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/JimpleUpType.html delete mode 100644 boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/JimpleUpVal.html delete mode 100644 boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/JimpleUpWrappedClass.html delete mode 100644 boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/SootUpCallGraph.html delete mode 100644 boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/SootUpClient.html delete mode 100644 boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/SootUpDataFlowScope.html delete mode 100644 boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/BoomerangPreInterceptor.html delete mode 100644 boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/JimpleUpControlFlowGraph.html delete mode 100644 boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/JimpleUpDeclaredMethod.html delete mode 100644 boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/JimpleUpDoubleVal.html delete mode 100644 boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/JimpleUpField.html delete mode 100644 boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/JimpleUpIfStatement.html delete mode 100644 boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/JimpleUpInstanceFieldRef.html delete mode 100644 boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/JimpleUpInvokeExpr.html delete mode 100644 boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/JimpleUpMethod.html delete mode 100644 boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/JimpleUpStatement.html delete mode 100644 boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/JimpleUpStaticFieldVal.html delete mode 100644 boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/JimpleUpType.html delete mode 100644 boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/JimpleUpVal.html delete mode 100644 boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/JimpleUpWrappedClass.html delete mode 100644 boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/SootUpCallGraph.html delete mode 100644 boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/SootUpClient.html delete mode 100644 boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/SootUpDataFlowScope.html delete mode 100644 boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/package-summary.html delete mode 100644 boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/package-tree.html delete mode 100644 boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/package-use.html delete mode 100644 boomerangScope-SootUp/target/apidocs/constant-values.html delete mode 100644 boomerangScope-SootUp/target/apidocs/deprecated-list.html delete mode 100644 boomerangScope-SootUp/target/apidocs/element-list delete mode 100644 boomerangScope-SootUp/target/apidocs/help-doc.html delete mode 100644 boomerangScope-SootUp/target/apidocs/index-all.html delete mode 100644 boomerangScope-SootUp/target/apidocs/index.html delete mode 100644 boomerangScope-SootUp/target/apidocs/jquery/external/jquery/jquery.js delete mode 100644 boomerangScope-SootUp/target/apidocs/jquery/images/ui-bg_glass_55_fbf9ee_1x400.png delete mode 100644 boomerangScope-SootUp/target/apidocs/jquery/images/ui-bg_glass_65_dadada_1x400.png delete mode 100644 boomerangScope-SootUp/target/apidocs/jquery/images/ui-bg_glass_75_dadada_1x400.png delete mode 100644 boomerangScope-SootUp/target/apidocs/jquery/images/ui-bg_glass_75_e6e6e6_1x400.png delete mode 100644 boomerangScope-SootUp/target/apidocs/jquery/images/ui-bg_glass_95_fef1ec_1x400.png delete mode 100644 boomerangScope-SootUp/target/apidocs/jquery/images/ui-bg_highlight-soft_75_cccccc_1x100.png delete mode 100644 boomerangScope-SootUp/target/apidocs/jquery/images/ui-icons_222222_256x240.png delete mode 100644 boomerangScope-SootUp/target/apidocs/jquery/images/ui-icons_2e83ff_256x240.png delete mode 100644 boomerangScope-SootUp/target/apidocs/jquery/images/ui-icons_454545_256x240.png delete mode 100644 boomerangScope-SootUp/target/apidocs/jquery/images/ui-icons_888888_256x240.png delete mode 100644 boomerangScope-SootUp/target/apidocs/jquery/images/ui-icons_cd0a0a_256x240.png delete mode 100644 boomerangScope-SootUp/target/apidocs/jquery/jquery-3.5.1.js delete mode 100644 boomerangScope-SootUp/target/apidocs/jquery/jquery-ui.css delete mode 100644 boomerangScope-SootUp/target/apidocs/jquery/jquery-ui.js delete mode 100644 boomerangScope-SootUp/target/apidocs/jquery/jquery-ui.min.css delete mode 100644 boomerangScope-SootUp/target/apidocs/jquery/jquery-ui.min.js delete mode 100644 boomerangScope-SootUp/target/apidocs/jquery/jquery-ui.structure.css delete mode 100644 boomerangScope-SootUp/target/apidocs/jquery/jquery-ui.structure.min.css delete mode 100644 boomerangScope-SootUp/target/apidocs/jquery/jszip-utils/dist/jszip-utils-ie.js delete mode 100644 boomerangScope-SootUp/target/apidocs/jquery/jszip-utils/dist/jszip-utils-ie.min.js delete mode 100644 boomerangScope-SootUp/target/apidocs/jquery/jszip-utils/dist/jszip-utils.js delete mode 100644 boomerangScope-SootUp/target/apidocs/jquery/jszip-utils/dist/jszip-utils.min.js delete mode 100644 boomerangScope-SootUp/target/apidocs/jquery/jszip/dist/jszip.js delete mode 100644 boomerangScope-SootUp/target/apidocs/jquery/jszip/dist/jszip.min.js delete mode 100644 boomerangScope-SootUp/target/apidocs/member-search-index.js delete mode 100644 boomerangScope-SootUp/target/apidocs/member-search-index.zip delete mode 100644 boomerangScope-SootUp/target/apidocs/overview-tree.html delete mode 100644 boomerangScope-SootUp/target/apidocs/package-search-index.js delete mode 100644 boomerangScope-SootUp/target/apidocs/package-search-index.zip delete mode 100644 boomerangScope-SootUp/target/apidocs/resources/glass.png delete mode 100644 boomerangScope-SootUp/target/apidocs/resources/x.png delete mode 100644 boomerangScope-SootUp/target/apidocs/script.js delete mode 100644 boomerangScope-SootUp/target/apidocs/search.js delete mode 100644 boomerangScope-SootUp/target/apidocs/stylesheet.css delete mode 100644 boomerangScope-SootUp/target/apidocs/type-search-index.js delete mode 100644 boomerangScope-SootUp/target/apidocs/type-search-index.zip delete mode 100644 boomerangScope-SootUp/target/boomerangScope-SootUp-3.1.2-Sparse-javadoc.jar delete mode 100644 boomerangScope-SootUp/target/boomerangScope-SootUp-3.1.2-Sparse-sources.jar delete mode 100644 boomerangScope-SootUp/target/boomerangScope-SootUp-3.1.2-Sparse.jar delete mode 100644 boomerangScope-SootUp/target/javadoc-bundle-options/javadoc-options-javadoc-resources.xml delete mode 100644 boomerangScope-SootUp/target/javadoc-bundle-options/package-list delete mode 100644 boomerangScope-SootUp/target/maven-archiver/pom.properties delete mode 100644 boomerangScope-SootUp/target/maven-javadoc-plugin-stale-data.txt delete mode 100644 boomerangScope-SootUp/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst delete mode 100644 boomerangScope-SootUp/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst delete mode 100644 boomerangScope-SootUp/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/createdFiles.lst delete mode 100644 boomerangScope-SootUp/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst diff --git a/boomerangScope-SootUp/.gitignore b/boomerangScope-SootUp/.gitignore new file mode 100644 index 000000000..0f630157f --- /dev/null +++ b/boomerangScope-SootUp/.gitignore @@ -0,0 +1,2 @@ +/target/ +/bin/ diff --git a/boomerangScope-SootUp/LICENSE.txt b/boomerangScope-SootUp/LICENSE.txt new file mode 100644 index 000000000..e23ece2c8 --- /dev/null +++ b/boomerangScope-SootUp/LICENSE.txt @@ -0,0 +1,277 @@ +Eclipse Public License - v 2.0 + + THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE + PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION + OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. + +1. DEFINITIONS + +"Contribution" means: + + a) in the case of the initial Contributor, the initial content + Distributed under this Agreement, and + + b) in the case of each subsequent Contributor: + i) changes to the Program, and + ii) additions to the Program; + where such changes and/or additions to the Program originate from + and are Distributed by that particular Contributor. A Contribution + "originates" from a Contributor if it was added to the Program by + such Contributor itself or anyone acting on such Contributor's behalf. + Contributions do not include changes or additions to the Program that + are not Modified Works. + +"Contributor" means any person or entity that Distributes the Program. + +"Licensed Patents" mean patent claims licensable by a Contributor which +are necessarily infringed by the use or sale of its Contribution alone +or when combined with the Program. + +"Program" means the Contributions Distributed in accordance with this +Agreement. + +"Recipient" means anyone who receives the Program under this Agreement +or any Secondary License (as applicable), including Contributors. + +"Derivative Works" shall mean any work, whether in Source Code or other +form, that is based on (or derived from) the Program and for which the +editorial revisions, annotations, elaborations, or other modifications +represent, as a whole, an original work of authorship. + +"Modified Works" shall mean any work in Source Code or other form that +results from an addition to, deletion from, or modification of the +contents of the Program, including, for purposes of clarity any new file +in Source Code form that contains any contents of the Program. Modified +Works shall not include works that contain only declarations, +interfaces, types, classes, structures, or files of the Program solely +in each case in order to link to, bind by name, or subclass the Program +or Modified Works thereof. + +"Distribute" means the acts of a) distributing or b) making available +in any manner that enables the transfer of a copy. + +"Source Code" means the form of a Program preferred for making +modifications, including but not limited to software source code, +documentation source, and configuration files. + +"Secondary License" means either the GNU General Public License, +Version 2.0, or any later versions of that license, including any +exceptions or additional permissions as identified by the initial +Contributor. + +2. GRANT OF RIGHTS + + a) Subject to the terms of this Agreement, each Contributor hereby + grants Recipient a non-exclusive, worldwide, royalty-free copyright + license to reproduce, prepare Derivative Works of, publicly display, + publicly perform, Distribute and sublicense the Contribution of such + Contributor, if any, and such Derivative Works. + + b) Subject to the terms of this Agreement, each Contributor hereby + grants Recipient a non-exclusive, worldwide, royalty-free patent + license under Licensed Patents to make, use, sell, offer to sell, + import and otherwise transfer the Contribution of such Contributor, + if any, in Source Code or other form. This patent license shall + apply to the combination of the Contribution and the Program if, at + the time the Contribution is added by the Contributor, such addition + of the Contribution causes such combination to be covered by the + Licensed Patents. The patent license shall not apply to any other + combinations which include the Contribution. No hardware per se is + licensed hereunder. + + c) Recipient understands that although each Contributor grants the + licenses to its Contributions set forth herein, no assurances are + provided by any Contributor that the Program does not infringe the + patent or other intellectual property rights of any other entity. + Each Contributor disclaims any liability to Recipient for claims + brought by any other entity based on infringement of intellectual + property rights or otherwise. As a condition to exercising the + rights and licenses granted hereunder, each Recipient hereby + assumes sole responsibility to secure any other intellectual + property rights needed, if any. For example, if a third party + patent license is required to allow Recipient to Distribute the + Program, it is Recipient's responsibility to acquire that license + before distributing the Program. + + d) Each Contributor represents that to its knowledge it has + sufficient copyright rights in its Contribution, if any, to grant + the copyright license set forth in this Agreement. + + e) Notwithstanding the terms of any Secondary License, no + Contributor makes additional grants to any Recipient (other than + those set forth in this Agreement) as a result of such Recipient's + receipt of the Program under the terms of a Secondary License + (if permitted under the terms of Section 3). + +3. REQUIREMENTS + +3.1 If a Contributor Distributes the Program in any form, then: + + a) the Program must also be made available as Source Code, in + accordance with section 3.2, and the Contributor must accompany + the Program with a statement that the Source Code for the Program + is available under this Agreement, and informs Recipients how to + obtain it in a reasonable manner on or through a medium customarily + used for software exchange; and + + b) the Contributor may Distribute the Program under a license + different than this Agreement, provided that such license: + i) effectively disclaims on behalf of all other Contributors all + warranties and conditions, express and implied, including + warranties or conditions of title and non-infringement, and + implied warranties or conditions of merchantability and fitness + for a particular purpose; + + ii) effectively excludes on behalf of all other Contributors all + liability for damages, including direct, indirect, special, + incidental and consequential damages, such as lost profits; + + iii) does not attempt to limit or alter the recipients' rights + in the Source Code under section 3.2; and + + iv) requires any subsequent distribution of the Program by any + party to be under a license that satisfies the requirements + of this section 3. + +3.2 When the Program is Distributed as Source Code: + + a) it must be made available under this Agreement, or if the + Program (i) is combined with other material in a separate file or + files made available under a Secondary License, and (ii) the initial + Contributor attached to the Source Code the notice described in + Exhibit A of this Agreement, then the Program may be made available + under the terms of such Secondary Licenses, and + + b) a copy of this Agreement must be included with each copy of + the Program. + +3.3 Contributors may not remove or alter any copyright, patent, +trademark, attribution notices, disclaimers of warranty, or limitations +of liability ("notices") contained within the Program from any copy of +the Program which they Distribute, provided that Contributors may add +their own appropriate notices. + +4. COMMERCIAL DISTRIBUTION + +Commercial distributors of software may accept certain responsibilities +with respect to end users, business partners and the like. While this +license is intended to facilitate the commercial use of the Program, +the Contributor who includes the Program in a commercial product +offering should do so in a manner which does not create potential +liability for other Contributors. Therefore, if a Contributor includes +the Program in a commercial product offering, such Contributor +("Commercial Contributor") hereby agrees to defend and indemnify every +other Contributor ("Indemnified Contributor") against any losses, +damages and costs (collectively "Losses") arising from claims, lawsuits +and other legal actions brought by a third party against the Indemnified +Contributor to the extent caused by the acts or omissions of such +Commercial Contributor in connection with its distribution of the Program +in a commercial product offering. The obligations in this section do not +apply to any claims or Losses relating to any actual or alleged +intellectual property infringement. In order to qualify, an Indemnified +Contributor must: a) promptly notify the Commercial Contributor in +writing of such claim, and b) allow the Commercial Contributor to control, +and cooperate with the Commercial Contributor in, the defense and any +related settlement negotiations. The Indemnified Contributor may +participate in any such claim at its own expense. + +For example, a Contributor might include the Program in a commercial +product offering, Product X. That Contributor is then a Commercial +Contributor. If that Commercial Contributor then makes performance +claims, or offers warranties related to Product X, those performance +claims and warranties are such Commercial Contributor's responsibility +alone. Under this section, the Commercial Contributor would have to +defend claims against the other Contributors related to those performance +claims and warranties, and if a court requires any other Contributor to +pay any damages as a result, the Commercial Contributor must pay +those damages. + +5. NO WARRANTY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT +PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN "AS IS" +BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR +IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF +TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR +PURPOSE. Each Recipient is solely responsible for determining the +appropriateness of using and distributing the Program and assumes all +risks associated with its exercise of rights under this Agreement, +including but not limited to the risks and costs of program errors, +compliance with applicable laws, damage to or loss of data, programs +or equipment, and unavailability or interruption of operations. + +6. DISCLAIMER OF LIABILITY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT +PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS +SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST +PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE +EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + +7. GENERAL + +If any provision of this Agreement is invalid or unenforceable under +applicable law, it shall not affect the validity or enforceability of +the remainder of the terms of this Agreement, and without further +action by the parties hereto, such provision shall be reformed to the +minimum extent necessary to make such provision valid and enforceable. + +If Recipient institutes patent litigation against any entity +(including a cross-claim or counterclaim in a lawsuit) alleging that the +Program itself (excluding combinations of the Program with other software +or hardware) infringes such Recipient's patent(s), then such Recipient's +rights granted under Section 2(b) shall terminate as of the date such +litigation is filed. + +All Recipient's rights under this Agreement shall terminate if it +fails to comply with any of the material terms or conditions of this +Agreement and does not cure such failure in a reasonable period of +time after becoming aware of such noncompliance. If all Recipient's +rights under this Agreement terminate, Recipient agrees to cease use +and distribution of the Program as soon as reasonably practicable. +However, Recipient's obligations under this Agreement and any licenses +granted by Recipient relating to the Program shall continue and survive. + +Everyone is permitted to copy and distribute copies of this Agreement, +but in order to avoid inconsistency the Agreement is copyrighted and +may only be modified in the following manner. The Agreement Steward +reserves the right to publish new versions (including revisions) of +this Agreement from time to time. No one other than the Agreement +Steward has the right to modify this Agreement. The Eclipse Foundation +is the initial Agreement Steward. The Eclipse Foundation may assign the +responsibility to serve as the Agreement Steward to a suitable separate +entity. Each new version of the Agreement will be given a distinguishing +version number. The Program (including Contributions) may always be +Distributed subject to the version of the Agreement under which it was +received. In addition, after a new version of the Agreement is published, +Contributor may elect to Distribute the Program (including its +Contributions) under the new version. + +Except as expressly stated in Sections 2(a) and 2(b) above, Recipient +receives no rights or licenses to the intellectual property of any +Contributor under this Agreement, whether expressly, by implication, +estoppel or otherwise. All rights in the Program not expressly granted +under this Agreement are reserved. Nothing in this Agreement is intended +to be enforceable by any entity that is not a Contributor or Recipient. +No third-party beneficiary rights are created under this Agreement. + +Exhibit A - Form of Secondary Licenses Notice + +"This Source Code may also be made available under the following +Secondary Licenses when the conditions for such availability set forth +in the Eclipse Public License, v. 2.0 are satisfied: {name license(s), +version(s), and exceptions or additional permissions here}." + + Simply including a copy of this Agreement, including this Exhibit A + is not sufficient to license the Source Code under Secondary Licenses. + + If it is not possible or desirable to put the notice in a particular + file, then You may include the notice in a location (such as a LICENSE + file in a relevant directory) where a recipient would be likely to + look for such a notice. + + You may add additional accurate notices of copyright ownership. \ No newline at end of file diff --git a/boomerangScope-SootUp/target/apidocs/allclasses-index.html b/boomerangScope-SootUp/target/apidocs/allclasses-index.html deleted file mode 100644 index 6f44a166a..000000000 --- a/boomerangScope-SootUp/target/apidocs/allclasses-index.html +++ /dev/null @@ -1,227 +0,0 @@ - - - - - -All Classes (boomerangScope-SootUp 3.1.2-Sparse API) - - - - - - - - - - - - - - -
- -
-
-
-

All Classes

-
-
- -
-
- - - diff --git a/boomerangScope-SootUp/target/apidocs/allclasses.html b/boomerangScope-SootUp/target/apidocs/allclasses.html deleted file mode 100644 index 43e9b8de7..000000000 --- a/boomerangScope-SootUp/target/apidocs/allclasses.html +++ /dev/null @@ -1,44 +0,0 @@ - - - - - -All Classes (boomerangScope-SootUp 3.1.2-Sparse API) - - - - - - - - - - - - -

All Classes

-
- -
- - diff --git a/boomerangScope-SootUp/target/apidocs/allpackages-index.html b/boomerangScope-SootUp/target/apidocs/allpackages-index.html deleted file mode 100644 index beff8eaeb..000000000 --- a/boomerangScope-SootUp/target/apidocs/allpackages-index.html +++ /dev/null @@ -1,165 +0,0 @@ - - - - - -All Packages (boomerangScope-SootUp 3.1.2-Sparse API) - - - - - - - - - - - - - - -
- -
-
-
-

All Packages

-
-
- -
-
- - - diff --git a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/BoomerangPreInterceptor.html b/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/BoomerangPreInterceptor.html deleted file mode 100644 index bdafba49d..000000000 --- a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/BoomerangPreInterceptor.html +++ /dev/null @@ -1,360 +0,0 @@ - - - - - -BoomerangPreInterceptor (boomerangScope-SootUp 3.1.2-Sparse API) - - - - - - - - - - - - - - -
- -
- -
-
- -

Class BoomerangPreInterceptor

-
-
- -
-
    -
  • -
    -
    All Implemented Interfaces:
    -
    sootup.core.transform.BodyInterceptor
    -
    -
    -
    public class BoomerangPreInterceptor
    -extends Object
    -implements sootup.core.transform.BodyInterceptor
    -
  • -
-
-
- -
-
-
    -
  • - -
    -
      -
    • - - -

      Field Detail

      - - - -
        -
      • -

        TRANSFORM_CONSTANTS

        -
        public static boolean TRANSFORM_CONSTANTS
        -
      • -
      -
    • -
    -
    - -
    -
      -
    • - - -

      Constructor Detail

      - - - -
        -
      • -

        BoomerangPreInterceptor

        -
        public BoomerangPreInterceptor()
        -
      • -
      -
    • -
    -
    - -
    -
      -
    • - - -

      Method Detail

      - - - -
        -
      • -

        interceptBody

        -
        public void interceptBody​(@Nonnull
        -                          sootup.core.model.Body.BodyBuilder bodyBuilder,
        -                          @Nonnull
        -                          sootup.core.views.View view)
        -
        -
        Specified by:
        -
        interceptBody in interface sootup.core.transform.BodyInterceptor
        -
        -
      • -
      -
    • -
    -
    -
  • -
-
-
-
- - - - diff --git a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/JimpleUpControlFlowGraph.html b/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/JimpleUpControlFlowGraph.html deleted file mode 100644 index be3cad433..000000000 --- a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/JimpleUpControlFlowGraph.html +++ /dev/null @@ -1,417 +0,0 @@ - - - - - -JimpleUpControlFlowGraph (boomerangScope-SootUp 3.1.2-Sparse API) - - - - - - - - - - - - - - -
- -
- -
-
- -

Class JimpleUpControlFlowGraph

-
-
- -
- -
-
- -
-
- -
-
-
- - - - diff --git a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/JimpleUpDeclaredMethod.html b/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/JimpleUpDeclaredMethod.html deleted file mode 100644 index a61e7fbcb..000000000 --- a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/JimpleUpDeclaredMethod.html +++ /dev/null @@ -1,517 +0,0 @@ - - - - - -JimpleUpDeclaredMethod (boomerangScope-SootUp 3.1.2-Sparse API) - - - - - - - - - - - - - - -
- -
- -
-
- -

Class JimpleUpDeclaredMethod

-
-
- -
- -
-
- -
-
- -
-
-
- - - - diff --git a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/JimpleUpDoubleVal.html b/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/JimpleUpDoubleVal.html deleted file mode 100644 index fc1cbea70..000000000 --- a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/JimpleUpDoubleVal.html +++ /dev/null @@ -1,413 +0,0 @@ - - - - - -JimpleUpDoubleVal (boomerangScope-SootUp 3.1.2-Sparse API) - - - - - - - - - - - - - - -
- -
- -
-
- -

Class JimpleUpDoubleVal

-
-
- -
- -
-
- -
-
- -
-
-
- - - - diff --git a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/JimpleUpField.html b/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/JimpleUpField.html deleted file mode 100644 index eea239b84..000000000 --- a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/JimpleUpField.html +++ /dev/null @@ -1,410 +0,0 @@ - - - - - -JimpleUpField (boomerangScope-SootUp 3.1.2-Sparse API) - - - - - - - - - - - - - - -
- -
- -
-
- -

Class JimpleUpField

-
-
- -
-
    -
  • -
    -
    All Implemented Interfaces:
    -
    wpds.interfaces.Location
    -
    -
    -
    public class JimpleUpField
    -extends Field
    -
  • -
-
-
- -
-
-
    -
  • - -
    -
      -
    • - - -

      Constructor Detail

      - - - -
        -
      • -

        JimpleUpField

        -
        public JimpleUpField​(sootup.java.core.JavaSootField delegate)
        -
      • -
      -
    • -
    -
    - -
    -
      -
    • - - -

      Method Detail

      - - - -
        -
      • -

        getDelegate

        -
        public sootup.java.core.JavaSootField getDelegate()
        -
      • -
      - - - -
        -
      • -

        isInnerClassField

        -
        public boolean isInnerClassField()
        -
        -
        Overrides:
        -
        isInnerClassField in class Field
        -
        -
      • -
      - - - -
        -
      • -

        hashCode

        -
        public int hashCode()
        -
        -
        Overrides:
        -
        hashCode in class Field
        -
        -
      • -
      - - - -
        -
      • -

        equals

        -
        public boolean equals​(Object obj)
        -
        -
        Overrides:
        -
        equals in class Field
        -
        -
      • -
      - - - - -
    • -
    -
    -
  • -
-
-
-
- - - - diff --git a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/JimpleUpIfStatement.html b/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/JimpleUpIfStatement.html deleted file mode 100644 index 6db4e8602..000000000 --- a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/JimpleUpIfStatement.html +++ /dev/null @@ -1,423 +0,0 @@ - - - - - -JimpleUpIfStatement (boomerangScope-SootUp 3.1.2-Sparse API) - - - - - - - - - - - - - - -
- -
- -
-
- -

Class JimpleUpIfStatement

-
-
- -
- -
-
- -
-
- -
-
-
- - - - diff --git a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/JimpleUpInstanceFieldRef.html b/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/JimpleUpInstanceFieldRef.html deleted file mode 100644 index 47abe5c30..000000000 --- a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/JimpleUpInstanceFieldRef.html +++ /dev/null @@ -1,388 +0,0 @@ - - - - - -JimpleUpInstanceFieldRef (boomerangScope-SootUp 3.1.2-Sparse API) - - - - - - - - - - - - - - -
- -
- -
-
- -

Class JimpleUpInstanceFieldRef

-
-
- -
- -
-
- -
-
- -
-
-
- - - - diff --git a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/JimpleUpInvokeExpr.html b/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/JimpleUpInvokeExpr.html deleted file mode 100644 index 4f40d022c..000000000 --- a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/JimpleUpInvokeExpr.html +++ /dev/null @@ -1,478 +0,0 @@ - - - - - -JimpleUpInvokeExpr (boomerangScope-SootUp 3.1.2-Sparse API) - - - - - - - - - - - - - - -
- -
- -
-
- -

Class JimpleUpInvokeExpr

-
-
- -
- -
-
- -
-
- -
-
-
- - - - diff --git a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/JimpleUpMethod.html b/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/JimpleUpMethod.html deleted file mode 100644 index 4efe3c255..000000000 --- a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/JimpleUpMethod.html +++ /dev/null @@ -1,739 +0,0 @@ - - - - - -JimpleUpMethod (boomerangScope-SootUp 3.1.2-Sparse API) - - - - - - - - - - - - - - -
- -
- -
-
- -

Class JimpleUpMethod

-
-
- -
-
    -
  • -
    -
    All Implemented Interfaces:
    -
    wpds.interfaces.Location
    -
    -
    -
    public class JimpleUpMethod
    -extends Method
    -
  • -
-
-
- -
-
- -
-
-
- - - - diff --git a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/JimpleUpStatement.html b/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/JimpleUpStatement.html deleted file mode 100644 index 8c8504ab8..000000000 --- a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/JimpleUpStatement.html +++ /dev/null @@ -1,1037 +0,0 @@ - - - - - -JimpleUpStatement (boomerangScope-SootUp 3.1.2-Sparse API) - - - - - - - - - - - - - - -
- -
- -
-
- -

Class JimpleUpStatement

-
-
- -
-
    -
  • -
    -
    All Implemented Interfaces:
    -
    wpds.interfaces.Location
    -
    -
    -
    public class JimpleUpStatement
    -extends Statement
    -
  • -
-
-
- -
-
- -
-
-
- - - - diff --git a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/JimpleUpStaticFieldVal.html b/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/JimpleUpStaticFieldVal.html deleted file mode 100644 index f29bc836a..000000000 --- a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/JimpleUpStaticFieldVal.html +++ /dev/null @@ -1,903 +0,0 @@ - - - - - -JimpleUpStaticFieldVal (boomerangScope-SootUp 3.1.2-Sparse API) - - - - - - - - - - - - - - -
- -
- -
-
- -

Class JimpleUpStaticFieldVal

-
-
- -
- -
-
- -
-
- -
-
-
- - - - diff --git a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/JimpleUpType.html b/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/JimpleUpType.html deleted file mode 100644 index 5142d44b8..000000000 --- a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/JimpleUpType.html +++ /dev/null @@ -1,456 +0,0 @@ - - - - - -JimpleUpType (boomerangScope-SootUp 3.1.2-Sparse API) - - - - - - - - - - - - - - -
- -
- -
-
- -

Class JimpleUpType

-
-
- -
-
    -
  • -
    -
    All Implemented Interfaces:
    -
    Type
    -
    -
    -
    public class JimpleUpType
    -extends Object
    -implements Type
    -
  • -
-
-
- -
-
-
    -
  • - -
    -
      -
    • - - -

      Constructor Detail

      - - - -
        -
      • -

        JimpleUpType

        -
        public JimpleUpType​(sootup.core.types.Type delegate)
        -
      • -
      -
    • -
    -
    - -
    -
      -
    • - - -

      Method Detail

      - - - -
        -
      • -

        isNullType

        -
        public boolean isNullType()
        -
        -
        Specified by:
        -
        isNullType in interface Type
        -
        -
      • -
      - - - -
        -
      • -

        isRefType

        -
        public boolean isRefType()
        -
        -
        Specified by:
        -
        isRefType in interface Type
        -
        -
      • -
      - - - -
        -
      • -

        isArrayType

        -
        public boolean isArrayType()
        -
        -
        Specified by:
        -
        isArrayType in interface Type
        -
        -
      • -
      - - - - - - - - - - - -
        -
      • -

        doesCastFail

        -
        public boolean doesCastFail​(Type targetVal,
        -                            Val target)
        -
        -
        Specified by:
        -
        doesCastFail in interface Type
        -
        -
      • -
      - - - -
        -
      • -

        isSubtypeOf

        -
        public boolean isSubtypeOf​(String type)
        -
        -
        Specified by:
        -
        isSubtypeOf in interface Type
        -
        -
      • -
      - - - -
        -
      • -

        isBooleanType

        -
        public boolean isBooleanType()
        -
        -
        Specified by:
        -
        isBooleanType in interface Type
        -
        -
      • -
      - - - -
        -
      • -

        getDelegate

        -
        public sootup.core.types.Type getDelegate()
        -
      • -
      -
    • -
    -
    -
  • -
-
-
-
- - - - diff --git a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/JimpleUpVal.html b/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/JimpleUpVal.html deleted file mode 100644 index 1037524a7..000000000 --- a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/JimpleUpVal.html +++ /dev/null @@ -1,936 +0,0 @@ - - - - - -JimpleUpVal (boomerangScope-SootUp 3.1.2-Sparse API) - - - - - - - - - - - - - - -
- -
- -
-
- -

Class JimpleUpVal

-
-
- -
- -
-
- -
-
-
    -
  • - -
    -
      -
    • - - -

      Constructor Detail

      - - - -
        -
      • -

        JimpleUpVal

        -
        public JimpleUpVal​(sootup.core.jimple.basic.Value delegate,
        -                   JimpleUpMethod method)
        -
      • -
      - - - - -
    • -
    -
    - -
    -
      -
    • - - -

      Method Detail

      - - - -
        -
      • -

        getType

        -
        public Type getType()
        -
        -
        Specified by:
        -
        getType in class Val
        -
        -
      • -
      - - - -
        -
      • -

        isStatic

        -
        public boolean isStatic()
        -
        -
        Specified by:
        -
        isStatic in class Val
        -
        -
      • -
      - - - -
        -
      • -

        isNewExpr

        -
        public boolean isNewExpr()
        -
        -
        Specified by:
        -
        isNewExpr in class Val
        -
        -
      • -
      - - - - - - - - - - - -
        -
      • -

        isLocal

        -
        public boolean isLocal()
        -
        -
        Specified by:
        -
        isLocal in class Val
        -
        -
      • -
      - - - -
        -
      • -

        isArrayAllocationVal

        -
        public boolean isArrayAllocationVal()
        -
        -
        Specified by:
        -
        isArrayAllocationVal in class Val
        -
        -
      • -
      - - - -
        -
      • -

        isNull

        -
        public boolean isNull()
        -
        -
        Specified by:
        -
        isNull in class Val
        -
        -
      • -
      - - - -
        -
      • -

        isStringConstant

        -
        public boolean isStringConstant()
        -
        -
        Specified by:
        -
        isStringConstant in class Val
        -
        -
      • -
      - - - - - - - -
        -
      • -

        isStringBufferOrBuilder

        -
        public boolean isStringBufferOrBuilder()
        -
        -
        Specified by:
        -
        isStringBufferOrBuilder in class Val
        -
        -
      • -
      - - - -
        -
      • -

        isThrowableAllocationType

        -
        public boolean isThrowableAllocationType()
        -
        -
        Specified by:
        -
        isThrowableAllocationType in class Val
        -
        -
      • -
      - - - -
        -
      • -

        isCast

        -
        public boolean isCast()
        -
        -
        Specified by:
        -
        isCast in class Val
        -
        -
      • -
      - - - -
        -
      • -

        getCastOp

        -
        public Val getCastOp()
        -
        -
        Specified by:
        -
        getCastOp in class Val
        -
        -
      • -
      - - - -
        -
      • -

        isArrayRef

        -
        public boolean isArrayRef()
        -
        -
        Specified by:
        -
        isArrayRef in class Val
        -
        -
      • -
      - - - -
        -
      • -

        isInstanceOfExpr

        -
        public boolean isInstanceOfExpr()
        -
        -
        Specified by:
        -
        isInstanceOfExpr in class Val
        -
        -
      • -
      - - - -
        -
      • -

        getInstanceOfOp

        -
        public Val getInstanceOfOp()
        -
        -
        Specified by:
        -
        getInstanceOfOp in class Val
        -
        -
      • -
      - - - -
        -
      • -

        isLengthExpr

        -
        public boolean isLengthExpr()
        -
        -
        Specified by:
        -
        isLengthExpr in class Val
        -
        -
      • -
      - - - -
        -
      • -

        getLengthOp

        -
        public Val getLengthOp()
        -
        -
        Specified by:
        -
        getLengthOp in class Val
        -
        -
      • -
      - - - -
        -
      • -

        isIntConstant

        -
        public boolean isIntConstant()
        -
        -
        Specified by:
        -
        isIntConstant in class Val
        -
        -
      • -
      - - - -
        -
      • -

        isClassConstant

        -
        public boolean isClassConstant()
        -
        -
        Specified by:
        -
        isClassConstant in class Val
        -
        -
      • -
      - - - - - - - - - - - -
        -
      • -

        withSecondVal

        -
        public Val withSecondVal​(Val leftOp)
        -
        -
        Overrides:
        -
        withSecondVal in class Val
        -
        -
      • -
      - - - -
        -
      • -

        isLongConstant

        -
        public boolean isLongConstant()
        -
        -
        Specified by:
        -
        isLongConstant in class Val
        -
        -
      • -
      - - - -
        -
      • -

        getIntValue

        -
        public int getIntValue()
        -
        -
        Specified by:
        -
        getIntValue in class Val
        -
        -
      • -
      - - - -
        -
      • -

        getLongValue

        -
        public long getLongValue()
        -
        -
        Specified by:
        -
        getLongValue in class Val
        -
        -
      • -
      - - - - - - - - - - - -
        -
      • -

        getDelegate

        -
        public sootup.core.jimple.basic.Value getDelegate()
        -
      • -
      - - - -
        -
      • -

        hashCode

        -
        public int hashCode()
        -
        -
        Overrides:
        -
        hashCode in class Val
        -
        -
      • -
      - - - -
        -
      • -

        equals

        -
        public boolean equals​(Object obj)
        -
        -
        Overrides:
        -
        equals in class Val
        -
        -
      • -
      - - - -
        -
      • -

        toString

        -
        public String toString()
        -
        -
        Overrides:
        -
        toString in class Val
        -
        -
      • -
      -
    • -
    -
    -
  • -
-
-
-
- - - - diff --git a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/JimpleUpWrappedClass.html b/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/JimpleUpWrappedClass.html deleted file mode 100644 index 50d7185d1..000000000 --- a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/JimpleUpWrappedClass.html +++ /dev/null @@ -1,494 +0,0 @@ - - - - - -JimpleUpWrappedClass (boomerangScope-SootUp 3.1.2-Sparse API) - - - - - - - - - - - - - - -
- -
- -
-
- -

Class JimpleUpWrappedClass

-
-
- -
- -
-
- -
-
- -
-
-
- - - - diff --git a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/SootUpCallGraph.html b/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/SootUpCallGraph.html deleted file mode 100644 index 9a062a666..000000000 --- a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/SootUpCallGraph.html +++ /dev/null @@ -1,298 +0,0 @@ - - - - - -SootUpCallGraph (boomerangScope-SootUp 3.1.2-Sparse API) - - - - - - - - - - - - - - -
- -
- -
-
- -

Class SootUpCallGraph

-
-
- -
-
    -
  • -
    -
    public class SootUpCallGraph
    -extends CallGraph
    -
  • -
-
-
- -
-
-
    -
  • - -
    -
      -
    • - - -

      Constructor Detail

      - - - -
        -
      • -

        SootUpCallGraph

        -
        public SootUpCallGraph​(sootup.callgraph.CallGraph callGraph,
        -                       Collection<sootup.core.signatures.MethodSignature> entryPoints)
        -
      • -
      -
    • -
    -
    -
  • -
-
-
-
- - - - diff --git a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/SootUpClient.html b/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/SootUpClient.html deleted file mode 100644 index 2b1359499..000000000 --- a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/SootUpClient.html +++ /dev/null @@ -1,379 +0,0 @@ - - - - - -SootUpClient (boomerangScope-SootUp 3.1.2-Sparse API) - - - - - - - - - - - - - - -
- -
- -
-
- -

Class SootUpClient

-
-
- -
-
    -
  • -
    -
    public class SootUpClient
    -extends Object
    -
  • -
-
-
- -
-
-
    -
  • - -
    -
      -
    • - - -

      Method Detail

      - - - -
        -
      • -

        setInstance

        -
        public static void setInstance​(sootup.java.core.views.JavaView view,
        -                               sootup.java.core.JavaIdentifierFactory idFactory)
        -
      • -
      - - - -
        -
      • -

        getInstance

        -
        public static SootUpClient getInstance()
        -
      • -
      - - - -
        -
      • -

        getView

        -
        public sootup.java.core.views.JavaView getView()
        -
      • -
      - - - -
        -
      • -

        getIdentifierFactory

        -
        public sootup.java.core.JavaIdentifierFactory getIdentifierFactory()
        -
      • -
      - - - -
        -
      • -

        getSootClass

        -
        public sootup.java.core.JavaSootClass getSootClass​(sootup.core.types.ClassType classType)
        -
      • -
      - - - -
        -
      • -

        getSootMethod

        -
        public sootup.java.core.JavaSootMethod getSootMethod​(sootup.core.signatures.MethodSignature methodSignature)
        -
      • -
      - - - -
        -
      • -

        getSootField

        -
        public sootup.java.core.JavaSootField getSootField​(sootup.core.signatures.FieldSignature fieldSignature)
        -
      • -
      - - - -
        -
      • -

        isConstructor

        -
        public static boolean isConstructor​(sootup.java.core.JavaSootMethod sootMethod)
        -
      • -
      - - - -
        -
      • -

        isStaticInitializer

        -
        public static boolean isStaticInitializer​(sootup.java.core.JavaSootMethod sootMethod)
        -
      • -
      -
    • -
    -
    -
  • -
-
-
-
- - - - diff --git a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/SootUpDataFlowScope.html b/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/SootUpDataFlowScope.html deleted file mode 100644 index d242c450d..000000000 --- a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/SootUpDataFlowScope.html +++ /dev/null @@ -1,312 +0,0 @@ - - - - - -SootUpDataFlowScope (boomerangScope-SootUp 3.1.2-Sparse API) - - - - - - - - - - - - - - -
- -
- -
-
- -

Class SootUpDataFlowScope

-
-
- -
-
    -
  • -
    -
    public class SootUpDataFlowScope
    -extends Object
    -
  • -
-
-
- -
-
-
    -
  • - -
    -
      -
    • - - -

      Constructor Detail

      - - - -
        -
      • -

        SootUpDataFlowScope

        -
        public SootUpDataFlowScope()
        -
      • -
      -
    • -
    -
    - -
    -
      -
    • - - -

      Method Detail

      - - - -
        -
      • -

        make

        -
        public static DataFlowScope make()
        -
        Default DataFlowScope that excludes native methods and methods from third-party libraries
        -
        -
        Returns:
        -
        the dataflow scope
        -
        -
      • -
      -
    • -
    -
    -
  • -
-
-
-
- - - - diff --git a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/BoomerangPreInterceptor.html b/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/BoomerangPreInterceptor.html deleted file mode 100644 index 295f170f8..000000000 --- a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/BoomerangPreInterceptor.html +++ /dev/null @@ -1,147 +0,0 @@ - - - - - -Uses of Class boomerang.scene.sootup.BoomerangPreInterceptor (boomerangScope-SootUp 3.1.2-Sparse API) - - - - - - - - - - - - - - -
- -
-
-
-

Uses of Class
boomerang.scene.sootup.BoomerangPreInterceptor

-
-
No usage of boomerang.scene.sootup.BoomerangPreInterceptor
-
- - - diff --git a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/JimpleUpControlFlowGraph.html b/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/JimpleUpControlFlowGraph.html deleted file mode 100644 index 0660ecdc7..000000000 --- a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/JimpleUpControlFlowGraph.html +++ /dev/null @@ -1,147 +0,0 @@ - - - - - -Uses of Class boomerang.scene.sootup.JimpleUpControlFlowGraph (boomerangScope-SootUp 3.1.2-Sparse API) - - - - - - - - - - - - - - -
- -
-
-
-

Uses of Class
boomerang.scene.sootup.JimpleUpControlFlowGraph

-
-
No usage of boomerang.scene.sootup.JimpleUpControlFlowGraph
-
- - - diff --git a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/JimpleUpDeclaredMethod.html b/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/JimpleUpDeclaredMethod.html deleted file mode 100644 index c2bd01946..000000000 --- a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/JimpleUpDeclaredMethod.html +++ /dev/null @@ -1,147 +0,0 @@ - - - - - -Uses of Class boomerang.scene.sootup.JimpleUpDeclaredMethod (boomerangScope-SootUp 3.1.2-Sparse API) - - - - - - - - - - - - - - -
- -
-
-
-

Uses of Class
boomerang.scene.sootup.JimpleUpDeclaredMethod

-
-
No usage of boomerang.scene.sootup.JimpleUpDeclaredMethod
-
- - - diff --git a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/JimpleUpDoubleVal.html b/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/JimpleUpDoubleVal.html deleted file mode 100644 index e9831a10a..000000000 --- a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/JimpleUpDoubleVal.html +++ /dev/null @@ -1,147 +0,0 @@ - - - - - -Uses of Class boomerang.scene.sootup.JimpleUpDoubleVal (boomerangScope-SootUp 3.1.2-Sparse API) - - - - - - - - - - - - - - -
- -
-
-
-

Uses of Class
boomerang.scene.sootup.JimpleUpDoubleVal

-
-
No usage of boomerang.scene.sootup.JimpleUpDoubleVal
-
- - - diff --git a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/JimpleUpField.html b/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/JimpleUpField.html deleted file mode 100644 index 06c06ed37..000000000 --- a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/JimpleUpField.html +++ /dev/null @@ -1,175 +0,0 @@ - - - - - -Uses of Class boomerang.scene.sootup.JimpleUpField (boomerangScope-SootUp 3.1.2-Sparse API) - - - - - - - - - - - - - - -
- -
-
-
-

Uses of Class
boomerang.scene.sootup.JimpleUpField

-
-
- -
-
- - - diff --git a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/JimpleUpIfStatement.html b/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/JimpleUpIfStatement.html deleted file mode 100644 index 1a34e423e..000000000 --- a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/JimpleUpIfStatement.html +++ /dev/null @@ -1,147 +0,0 @@ - - - - - -Uses of Class boomerang.scene.sootup.JimpleUpIfStatement (boomerangScope-SootUp 3.1.2-Sparse API) - - - - - - - - - - - - - - -
- -
-
-
-

Uses of Class
boomerang.scene.sootup.JimpleUpIfStatement

-
-
No usage of boomerang.scene.sootup.JimpleUpIfStatement
-
- - - diff --git a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/JimpleUpInstanceFieldRef.html b/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/JimpleUpInstanceFieldRef.html deleted file mode 100644 index faf7e6b86..000000000 --- a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/JimpleUpInstanceFieldRef.html +++ /dev/null @@ -1,147 +0,0 @@ - - - - - -Uses of Class boomerang.scene.sootup.JimpleUpInstanceFieldRef (boomerangScope-SootUp 3.1.2-Sparse API) - - - - - - - - - - - - - - -
- -
-
-
-

Uses of Class
boomerang.scene.sootup.JimpleUpInstanceFieldRef

-
-
No usage of boomerang.scene.sootup.JimpleUpInstanceFieldRef
-
- - - diff --git a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/JimpleUpInvokeExpr.html b/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/JimpleUpInvokeExpr.html deleted file mode 100644 index 2b52d7b50..000000000 --- a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/JimpleUpInvokeExpr.html +++ /dev/null @@ -1,175 +0,0 @@ - - - - - -Uses of Class boomerang.scene.sootup.JimpleUpInvokeExpr (boomerangScope-SootUp 3.1.2-Sparse API) - - - - - - - - - - - - - - -
- -
-
-
-

Uses of Class
boomerang.scene.sootup.JimpleUpInvokeExpr

-
-
- -
-
- - - diff --git a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/JimpleUpMethod.html b/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/JimpleUpMethod.html deleted file mode 100644 index ff254cc86..000000000 --- a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/JimpleUpMethod.html +++ /dev/null @@ -1,252 +0,0 @@ - - - - - -Uses of Class boomerang.scene.sootup.JimpleUpMethod (boomerangScope-SootUp 3.1.2-Sparse API) - - - - - - - - - - - - - - -
- -
-
-
-

Uses of Class
boomerang.scene.sootup.JimpleUpMethod

-
-
- -
-
- - - diff --git a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/JimpleUpStatement.html b/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/JimpleUpStatement.html deleted file mode 100644 index 76ccd2b5b..000000000 --- a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/JimpleUpStatement.html +++ /dev/null @@ -1,147 +0,0 @@ - - - - - -Uses of Class boomerang.scene.sootup.JimpleUpStatement (boomerangScope-SootUp 3.1.2-Sparse API) - - - - - - - - - - - - - - -
- -
-
-
-

Uses of Class
boomerang.scene.sootup.JimpleUpStatement

-
-
No usage of boomerang.scene.sootup.JimpleUpStatement
-
- - - diff --git a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/JimpleUpStaticFieldVal.html b/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/JimpleUpStaticFieldVal.html deleted file mode 100644 index 2e9ad69a2..000000000 --- a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/JimpleUpStaticFieldVal.html +++ /dev/null @@ -1,147 +0,0 @@ - - - - - -Uses of Class boomerang.scene.sootup.JimpleUpStaticFieldVal (boomerangScope-SootUp 3.1.2-Sparse API) - - - - - - - - - - - - - - -
- -
-
-
-

Uses of Class
boomerang.scene.sootup.JimpleUpStaticFieldVal

-
-
No usage of boomerang.scene.sootup.JimpleUpStaticFieldVal
-
- - - diff --git a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/JimpleUpType.html b/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/JimpleUpType.html deleted file mode 100644 index 087f98b1c..000000000 --- a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/JimpleUpType.html +++ /dev/null @@ -1,147 +0,0 @@ - - - - - -Uses of Class boomerang.scene.sootup.JimpleUpType (boomerangScope-SootUp 3.1.2-Sparse API) - - - - - - - - - - - - - - -
- -
-
-
-

Uses of Class
boomerang.scene.sootup.JimpleUpType

-
-
No usage of boomerang.scene.sootup.JimpleUpType
-
- - - diff --git a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/JimpleUpVal.html b/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/JimpleUpVal.html deleted file mode 100644 index 953efa667..000000000 --- a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/JimpleUpVal.html +++ /dev/null @@ -1,176 +0,0 @@ - - - - - -Uses of Class boomerang.scene.sootup.JimpleUpVal (boomerangScope-SootUp 3.1.2-Sparse API) - - - - - - - - - - - - - - -
- -
-
-
-

Uses of Class
boomerang.scene.sootup.JimpleUpVal

-
-
- -
-
- - - diff --git a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/JimpleUpWrappedClass.html b/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/JimpleUpWrappedClass.html deleted file mode 100644 index e538c520b..000000000 --- a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/JimpleUpWrappedClass.html +++ /dev/null @@ -1,147 +0,0 @@ - - - - - -Uses of Class boomerang.scene.sootup.JimpleUpWrappedClass (boomerangScope-SootUp 3.1.2-Sparse API) - - - - - - - - - - - - - - -
- -
-
-
-

Uses of Class
boomerang.scene.sootup.JimpleUpWrappedClass

-
-
No usage of boomerang.scene.sootup.JimpleUpWrappedClass
-
- - - diff --git a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/SootUpCallGraph.html b/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/SootUpCallGraph.html deleted file mode 100644 index b6ed185f6..000000000 --- a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/SootUpCallGraph.html +++ /dev/null @@ -1,147 +0,0 @@ - - - - - -Uses of Class boomerang.scene.sootup.SootUpCallGraph (boomerangScope-SootUp 3.1.2-Sparse API) - - - - - - - - - - - - - - -
- -
-
-
-

Uses of Class
boomerang.scene.sootup.SootUpCallGraph

-
-
No usage of boomerang.scene.sootup.SootUpCallGraph
-
- - - diff --git a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/SootUpClient.html b/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/SootUpClient.html deleted file mode 100644 index d0f884a38..000000000 --- a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/SootUpClient.html +++ /dev/null @@ -1,176 +0,0 @@ - - - - - -Uses of Class boomerang.scene.sootup.SootUpClient (boomerangScope-SootUp 3.1.2-Sparse API) - - - - - - - - - - - - - - -
- -
-
-
-

Uses of Class
boomerang.scene.sootup.SootUpClient

-
-
- -
-
- - - diff --git a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/SootUpDataFlowScope.html b/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/SootUpDataFlowScope.html deleted file mode 100644 index 4e3375bca..000000000 --- a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/class-use/SootUpDataFlowScope.html +++ /dev/null @@ -1,147 +0,0 @@ - - - - - -Uses of Class boomerang.scene.sootup.SootUpDataFlowScope (boomerangScope-SootUp 3.1.2-Sparse API) - - - - - - - - - - - - - - -
- -
-
-
-

Uses of Class
boomerang.scene.sootup.SootUpDataFlowScope

-
-
No usage of boomerang.scene.sootup.SootUpDataFlowScope
-
- - - diff --git a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/package-summary.html b/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/package-summary.html deleted file mode 100644 index 45678f996..000000000 --- a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/package-summary.html +++ /dev/null @@ -1,229 +0,0 @@ - - - - - -boomerang.scene.sootup (boomerangScope-SootUp 3.1.2-Sparse API) - - - - - - - - - - - - - - -
- -
-
-
-

Package boomerang.scene.sootup

-
-
- -
-
- - - diff --git a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/package-tree.html b/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/package-tree.html deleted file mode 100644 index ccb02f179..000000000 --- a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/package-tree.html +++ /dev/null @@ -1,205 +0,0 @@ - - - - - -boomerang.scene.sootup Class Hierarchy (boomerangScope-SootUp 3.1.2-Sparse API) - - - - - - - - - - - - - - -
- -
-
-
-

Hierarchy For Package boomerang.scene.sootup

-
-
-
-

Class Hierarchy

- -
-
-
- - - diff --git a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/package-use.html b/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/package-use.html deleted file mode 100644 index f107472b5..000000000 --- a/boomerangScope-SootUp/target/apidocs/boomerang/scene/sootup/package-use.html +++ /dev/null @@ -1,183 +0,0 @@ - - - - - -Uses of Package boomerang.scene.sootup (boomerangScope-SootUp 3.1.2-Sparse API) - - - - - - - - - - - - - - -
- -
-
-
-

Uses of Package
boomerang.scene.sootup

-
-
- -
-
- - - diff --git a/boomerangScope-SootUp/target/apidocs/constant-values.html b/boomerangScope-SootUp/target/apidocs/constant-values.html deleted file mode 100644 index f9492a745..000000000 --- a/boomerangScope-SootUp/target/apidocs/constant-values.html +++ /dev/null @@ -1,149 +0,0 @@ - - - - - -Constant Field Values (boomerangScope-SootUp 3.1.2-Sparse API) - - - - - - - - - - - - - - -
- -
-
-
-

Constant Field Values

-
-

Contents

-
-
-
- - - diff --git a/boomerangScope-SootUp/target/apidocs/deprecated-list.html b/boomerangScope-SootUp/target/apidocs/deprecated-list.html deleted file mode 100644 index 39e98731e..000000000 --- a/boomerangScope-SootUp/target/apidocs/deprecated-list.html +++ /dev/null @@ -1,147 +0,0 @@ - - - - - -Deprecated List (boomerangScope-SootUp 3.1.2-Sparse API) - - - - - - - - - - - - - - -
- -
-
-
-

Deprecated API

-

Contents

-
-
- - - diff --git a/boomerangScope-SootUp/target/apidocs/element-list b/boomerangScope-SootUp/target/apidocs/element-list deleted file mode 100644 index 6ac43dfc8..000000000 --- a/boomerangScope-SootUp/target/apidocs/element-list +++ /dev/null @@ -1 +0,0 @@ -boomerang.scene.sootup diff --git a/boomerangScope-SootUp/target/apidocs/help-doc.html b/boomerangScope-SootUp/target/apidocs/help-doc.html deleted file mode 100644 index f329f75fb..000000000 --- a/boomerangScope-SootUp/target/apidocs/help-doc.html +++ /dev/null @@ -1,273 +0,0 @@ - - - - - -API Help (boomerangScope-SootUp 3.1.2-Sparse API) - - - - - - - - - - - - - - -
- -
-
-
-

How This API Document Is Organized

-
This API (Application Programming Interface) document has pages corresponding to the items in the navigation bar, described as follows.
-
-
-
    -
  • -
    -

    Package

    -

    Each package has a page that contains a list of its classes and interfaces, with a summary for each. These pages may contain six categories:

    -
      -
    • Interfaces
    • -
    • Classes
    • -
    • Enums
    • -
    • Exceptions
    • -
    • Errors
    • -
    • Annotation Types
    • -
    -
    -
  • -
  • -
    -

    Class or Interface

    -

    Each class, interface, nested class and nested interface has its own separate page. Each of these pages has three sections consisting of a class/interface description, summary tables, and detailed member descriptions:

    -
      -
    • Class Inheritance Diagram
    • -
    • Direct Subclasses
    • -
    • All Known Subinterfaces
    • -
    • All Known Implementing Classes
    • -
    • Class or Interface Declaration
    • -
    • Class or Interface Description
    • -
    -
    -
      -
    • Nested Class Summary
    • -
    • Field Summary
    • -
    • Property Summary
    • -
    • Constructor Summary
    • -
    • Method Summary
    • -
    -
    -
      -
    • Field Detail
    • -
    • Property Detail
    • -
    • Constructor Detail
    • -
    • Method Detail
    • -
    -

    Each summary entry contains the first sentence from the detailed description for that item. The summary entries are alphabetical, while the detailed descriptions are in the order they appear in the source code. This preserves the logical groupings established by the programmer.

    -
    -
  • -
  • -
    -

    Annotation Type

    -

    Each annotation type has its own separate page with the following sections:

    -
      -
    • Annotation Type Declaration
    • -
    • Annotation Type Description
    • -
    • Required Element Summary
    • -
    • Optional Element Summary
    • -
    • Element Detail
    • -
    -
    -
  • -
  • -
    -

    Enum

    -

    Each enum has its own separate page with the following sections:

    -
      -
    • Enum Declaration
    • -
    • Enum Description
    • -
    • Enum Constant Summary
    • -
    • Enum Constant Detail
    • -
    -
    -
  • -
  • -
    -

    Use

    -

    Each documented package, class and interface has its own Use page. This page describes what packages, classes, methods, constructors and fields use any part of the given class or package. Given a class or interface A, its "Use" page includes subclasses of A, fields declared as A, methods that return A, and methods and constructors with parameters of type A. You can access this page by first going to the package, class or interface, then clicking on the "Use" link in the navigation bar.

    -
    -
  • -
  • -
    -

    Tree (Class Hierarchy)

    -

    There is a Class Hierarchy page for all packages, plus a hierarchy for each package. Each hierarchy page contains a list of classes and a list of interfaces. Classes are organized by inheritance structure starting with java.lang.Object. Interfaces do not inherit from java.lang.Object.

    -
      -
    • When viewing the Overview page, clicking on "Tree" displays the hierarchy for all packages.
    • -
    • When viewing a particular package, class or interface page, clicking on "Tree" displays the hierarchy for only that package.
    • -
    -
    -
  • -
  • -
    -

    Deprecated API

    -

    The Deprecated API page lists all of the API that have been deprecated. A deprecated API is not recommended for use, generally due to improvements, and a replacement API is usually given. Deprecated APIs may be removed in future implementations.

    -
    -
  • -
  • -
    -

    Index

    -

    The Index contains an alphabetic index of all classes, interfaces, constructors, methods, and fields, as well as lists of all packages and all classes.

    -
    -
  • -
  • -
    -

    All Classes

    -

    The All Classes link shows all classes and interfaces except non-static nested types.

    -
    -
  • -
  • -
    -

    Serialized Form

    -

    Each serializable or externalizable class has a description of its serialization fields and methods. This information is of interest to re-implementors, not to developers using the API. While there is no link in the navigation bar, you can get to this information by going to any serialized class and clicking "Serialized Form" in the "See also" section of the class description.

    -
    -
  • -
  • -
    -

    Constant Field Values

    -

    The Constant Field Values page lists the static final fields and their values.

    -
    -
  • -
  • -
    -

    Search

    -

    You can search for definitions of modules, packages, types, fields, methods and other terms defined in the API, using some or all of the name. "Camel-case" abbreviations are supported: for example, "InpStr" will find "InputStream" and "InputStreamReader".

    -
    -
  • -
-
-This help file applies to API documentation generated by the standard doclet.
-
- - - diff --git a/boomerangScope-SootUp/target/apidocs/index-all.html b/boomerangScope-SootUp/target/apidocs/index-all.html deleted file mode 100644 index 908293884..000000000 --- a/boomerangScope-SootUp/target/apidocs/index-all.html +++ /dev/null @@ -1,738 +0,0 @@ - - - - - -Index (boomerangScope-SootUp 3.1.2-Sparse API) - - - - - - - - - - - - - - -
- -
-
-
A B C D E F G H I J K M O S T U W 
All Classes All Packages - - -

A

-
-
asUnbalanced(ControlFlowGraph.Edge) - Method in class boomerang.scene.sootup.JimpleUpStaticFieldVal
-
 
-
asUnbalanced(ControlFlowGraph.Edge) - Method in class boomerang.scene.sootup.JimpleUpVal
-
 
-
- - - -

B

-
-
boomerang.scene.sootup - package boomerang.scene.sootup
-
 
-
BoomerangPreInterceptor - Class in boomerang.scene.sootup
-
 
-
BoomerangPreInterceptor() - Constructor for class boomerang.scene.sootup.BoomerangPreInterceptor
-
 
-
buildCache() - Method in class boomerang.scene.sootup.JimpleUpControlFlowGraph
-
 
-
- - - -

C

-
-
containsInvokeExpr() - Method in class boomerang.scene.sootup.JimpleUpStatement
-
 
-
containsStaticFieldAccess() - Method in class boomerang.scene.sootup.JimpleUpStatement
-
 
-
create(Stmt, JimpleUpMethod) - Static method in class boomerang.scene.sootup.JimpleUpStatement
-
 
-
- - - -

D

-
-
doesCastFail(Type, Val) - Method in class boomerang.scene.sootup.JimpleUpType
-
 
-
- - - -

E

-
-
equals(Object) - Method in class boomerang.scene.sootup.JimpleUpDeclaredMethod
-
 
-
equals(Object) - Method in class boomerang.scene.sootup.JimpleUpDoubleVal
-
 
-
equals(Object) - Method in class boomerang.scene.sootup.JimpleUpField
-
 
-
equals(Object) - Method in class boomerang.scene.sootup.JimpleUpIfStatement
-
 
-
equals(Object) - Method in class boomerang.scene.sootup.JimpleUpInstanceFieldRef
-
 
-
equals(Object) - Method in class boomerang.scene.sootup.JimpleUpInvokeExpr
-
 
-
equals(Object) - Method in class boomerang.scene.sootup.JimpleUpMethod
-
 
-
equals(Object) - Method in class boomerang.scene.sootup.JimpleUpStatement
-
 
-
equals(Object) - Method in class boomerang.scene.sootup.JimpleUpStaticFieldVal
-
 
-
equals(Object) - Method in class boomerang.scene.sootup.JimpleUpVal
-
 
-
equals(Object) - Method in class boomerang.scene.sootup.JimpleUpWrappedClass
-
 
-
evaluate(Val) - Method in class boomerang.scene.sootup.JimpleUpIfStatement
-
 
-
- - - -

F

-
-
field() - Method in class boomerang.scene.sootup.JimpleUpStaticFieldVal
-
 
-
- - - -

G

-
-
getArg(int) - Method in class boomerang.scene.sootup.JimpleUpInvokeExpr
-
 
-
getArgs() - Method in class boomerang.scene.sootup.JimpleUpInvokeExpr
-
 
-
getArrayBase() - Method in class boomerang.scene.sootup.JimpleUpStatement
-
 
-
getArrayBase() - Method in class boomerang.scene.sootup.JimpleUpStaticFieldVal
-
 
-
getArrayBase() - Method in class boomerang.scene.sootup.JimpleUpVal
-
 
-
getArrayBaseType() - Method in class boomerang.scene.sootup.JimpleUpType
-
 
-
getBase() - Method in class boomerang.scene.sootup.JimpleUpInstanceFieldRef
-
 
-
getBase() - Method in class boomerang.scene.sootup.JimpleUpInvokeExpr
-
 
-
getCalledMethod() - Method in class boomerang.scene.sootup.JimpleUpDeclaredMethod
-
 
-
getCastOp() - Method in class boomerang.scene.sootup.JimpleUpStaticFieldVal
-
 
-
getCastOp() - Method in class boomerang.scene.sootup.JimpleUpVal
-
 
-
getClassConstantType() - Method in class boomerang.scene.sootup.JimpleUpStaticFieldVal
-
 
-
getClassConstantType() - Method in class boomerang.scene.sootup.JimpleUpVal
-
 
-
getControlFlowGraph() - Method in class boomerang.scene.sootup.JimpleUpMethod
-
 
-
getDeclaringClass() - Method in class boomerang.scene.sootup.JimpleUpDeclaredMethod
-
 
-
getDeclaringClass() - Method in class boomerang.scene.sootup.JimpleUpMethod
-
 
-
getDelegate() - Method in class boomerang.scene.sootup.JimpleUpDeclaredMethod
-
 
-
getDelegate() - Method in class boomerang.scene.sootup.JimpleUpField
-
 
-
getDelegate() - Method in class boomerang.scene.sootup.JimpleUpMethod
-
 
-
getDelegate() - Method in class boomerang.scene.sootup.JimpleUpStatement
-
 
-
getDelegate() - Method in class boomerang.scene.sootup.JimpleUpType
-
 
-
getDelegate() - Method in class boomerang.scene.sootup.JimpleUpVal
-
 
-
getDelegate() - Method in class boomerang.scene.sootup.JimpleUpWrappedClass
-
 
-
getEndColumnNumber() - Method in class boomerang.scene.sootup.JimpleUpStatement
-
 
-
getEndLineNumber() - Method in class boomerang.scene.sootup.JimpleUpStatement
-
 
-
getEndPoints() - Method in class boomerang.scene.sootup.JimpleUpControlFlowGraph
-
 
-
getFalseVariable() - Method in class boomerang.scene.sootup.JimpleUpDoubleVal
-
 
-
getField() - Method in class boomerang.scene.sootup.JimpleUpInstanceFieldRef
-
 
-
getFieldLoad() - Method in class boomerang.scene.sootup.JimpleUpStatement
-
 
-
getFieldStore() - Method in class boomerang.scene.sootup.JimpleUpStatement
-
 
-
getFullyQualifiedName() - Method in class boomerang.scene.sootup.JimpleUpWrappedClass
-
 
-
getIdentifierFactory() - Method in class boomerang.scene.sootup.SootUpClient
-
 
-
getIfStmt() - Method in class boomerang.scene.sootup.JimpleUpStatement
-
 
-
getInstance() - Static method in class boomerang.scene.sootup.SootUpClient
-
 
-
getInstanceOfOp() - Method in class boomerang.scene.sootup.JimpleUpStaticFieldVal
-
 
-
getInstanceOfOp() - Method in class boomerang.scene.sootup.JimpleUpVal
-
 
-
getIntValue() - Method in class boomerang.scene.sootup.JimpleUpStaticFieldVal
-
 
-
getIntValue() - Method in class boomerang.scene.sootup.JimpleUpVal
-
 
-
getInvokeExpr() - Method in class boomerang.scene.sootup.JimpleUpStatement
-
 
-
getLeftOp() - Method in class boomerang.scene.sootup.JimpleUpStatement
-
 
-
getLengthOp() - Method in class boomerang.scene.sootup.JimpleUpStaticFieldVal
-
 
-
getLengthOp() - Method in class boomerang.scene.sootup.JimpleUpVal
-
 
-
getLoadedField() - Method in class boomerang.scene.sootup.JimpleUpStatement
-
 
-
getLocals() - Method in class boomerang.scene.sootup.JimpleUpMethod
-
 
-
getLongValue() - Method in class boomerang.scene.sootup.JimpleUpStaticFieldVal
-
 
-
getLongValue() - Method in class boomerang.scene.sootup.JimpleUpVal
-
 
-
getMethod() - Method in class boomerang.scene.sootup.JimpleUpInvokeExpr
-
 
-
getMethods() - Method in class boomerang.scene.sootup.JimpleUpWrappedClass
-
 
-
getName() - Method in class boomerang.scene.sootup.JimpleUpDeclaredMethod
-
 
-
getName() - Method in class boomerang.scene.sootup.JimpleUpMethod
-
 
-
getName() - Method in class boomerang.scene.sootup.JimpleUpWrappedClass
-
 
-
getNewExprType() - Method in class boomerang.scene.sootup.JimpleUpStaticFieldVal
-
 
-
getNewExprType() - Method in class boomerang.scene.sootup.JimpleUpVal
-
 
-
getParameterLocals() - Method in class boomerang.scene.sootup.JimpleUpMethod
-
 
-
getParameterType(int) - Method in class boomerang.scene.sootup.JimpleUpMethod
-
 
-
getParameterTypes() - Method in class boomerang.scene.sootup.JimpleUpMethod
-
 
-
getPhiVals() - Method in class boomerang.scene.sootup.JimpleUpStatement
-
 
-
getPredsOf(Statement) - Method in class boomerang.scene.sootup.JimpleUpControlFlowGraph
-
 
-
getReturnOp() - Method in class boomerang.scene.sootup.JimpleUpStatement
-
 
-
getRightOp() - Method in class boomerang.scene.sootup.JimpleUpStatement
-
 
-
getSignature() - Method in class boomerang.scene.sootup.JimpleUpDeclaredMethod
-
 
-
getSootClass(ClassType) - Method in class boomerang.scene.sootup.SootUpClient
-
 
-
getSootField(FieldSignature) - Method in class boomerang.scene.sootup.SootUpClient
-
 
-
getSootMethod(MethodSignature) - Method in class boomerang.scene.sootup.SootUpClient
-
 
-
getStartColumnNumber() - Method in class boomerang.scene.sootup.JimpleUpStatement
-
 
-
getStartLineNumber() - Method in class boomerang.scene.sootup.JimpleUpStatement
-
 
-
getStartPoints() - Method in class boomerang.scene.sootup.JimpleUpControlFlowGraph
-
 
-
getStatements() - Method in class boomerang.scene.sootup.JimpleUpControlFlowGraph
-
 
-
getStatements() - Method in class boomerang.scene.sootup.JimpleUpMethod
-
 
-
getStaticField() - Method in class boomerang.scene.sootup.JimpleUpStatement
-
 
-
getStringValue() - Method in class boomerang.scene.sootup.JimpleUpStaticFieldVal
-
 
-
getStringValue() - Method in class boomerang.scene.sootup.JimpleUpVal
-
 
-
getSubSignature() - Method in class boomerang.scene.sootup.JimpleUpDeclaredMethod
-
 
-
getSubSignature() - Method in class boomerang.scene.sootup.JimpleUpMethod
-
 
-
getSuccsOf(Statement) - Method in class boomerang.scene.sootup.JimpleUpControlFlowGraph
-
 
-
getSuperclass() - Method in class boomerang.scene.sootup.JimpleUpWrappedClass
-
 
-
getTarget() - Method in class boomerang.scene.sootup.JimpleUpIfStatement
-
 
-
getThisLocal() - Method in class boomerang.scene.sootup.JimpleUpMethod
-
 
-
getType() - Method in class boomerang.scene.sootup.JimpleUpStaticFieldVal
-
 
-
getType() - Method in class boomerang.scene.sootup.JimpleUpVal
-
 
-
getType() - Method in class boomerang.scene.sootup.JimpleUpWrappedClass
-
 
-
getVariableName() - Method in class boomerang.scene.sootup.JimpleUpStaticFieldVal
-
 
-
getVariableName() - Method in class boomerang.scene.sootup.JimpleUpVal
-
 
-
getView() - Method in class boomerang.scene.sootup.SootUpClient
-
 
-
getWrappedClass() - Method in class boomerang.scene.sootup.JimpleUpType
-
 
-
getWrittenField() - Method in class boomerang.scene.sootup.JimpleUpStatement
-
 
-
- - - -

H

-
-
hashCode() - Method in class boomerang.scene.sootup.JimpleUpDeclaredMethod
-
 
-
hashCode() - Method in class boomerang.scene.sootup.JimpleUpDoubleVal
-
 
-
hashCode() - Method in class boomerang.scene.sootup.JimpleUpField
-
 
-
hashCode() - Method in class boomerang.scene.sootup.JimpleUpIfStatement
-
 
-
hashCode() - Method in class boomerang.scene.sootup.JimpleUpInstanceFieldRef
-
 
-
hashCode() - Method in class boomerang.scene.sootup.JimpleUpInvokeExpr
-
 
-
hashCode() - Method in class boomerang.scene.sootup.JimpleUpMethod
-
 
-
hashCode() - Method in class boomerang.scene.sootup.JimpleUpStatement
-
 
-
hashCode() - Method in class boomerang.scene.sootup.JimpleUpStaticFieldVal
-
 
-
hashCode() - Method in class boomerang.scene.sootup.JimpleUpVal
-
 
-
hashCode() - Method in class boomerang.scene.sootup.JimpleUpWrappedClass
-
 
-
hasSuperclass() - Method in class boomerang.scene.sootup.JimpleUpWrappedClass
-
 
-
- - - -

I

-
-
interceptBody(Body.BodyBuilder, View) - Method in class boomerang.scene.sootup.BoomerangPreInterceptor
-
 
-
INTERNAL_POOL - Static variable in class boomerang.scene.sootup.JimpleUpMethod
-
 
-
isApplicationClass() - Method in class boomerang.scene.sootup.JimpleUpWrappedClass
-
 
-
isArrayAllocationVal() - Method in class boomerang.scene.sootup.JimpleUpStaticFieldVal
-
 
-
isArrayAllocationVal() - Method in class boomerang.scene.sootup.JimpleUpVal
-
 
-
isArrayLoad() - Method in class boomerang.scene.sootup.JimpleUpStatement
-
 
-
isArrayRef() - Method in class boomerang.scene.sootup.JimpleUpStaticFieldVal
-
 
-
isArrayRef() - Method in class boomerang.scene.sootup.JimpleUpVal
-
 
-
isArrayStore() - Method in class boomerang.scene.sootup.JimpleUpStatement
-
 
-
isArrayType() - Method in class boomerang.scene.sootup.JimpleUpType
-
 
-
isAssign() - Method in class boomerang.scene.sootup.JimpleUpStatement
-
 
-
isBooleanType() - Method in class boomerang.scene.sootup.JimpleUpType
-
 
-
isCast() - Method in class boomerang.scene.sootup.JimpleUpStatement
-
 
-
isCast() - Method in class boomerang.scene.sootup.JimpleUpStaticFieldVal
-
 
-
isCast() - Method in class boomerang.scene.sootup.JimpleUpVal
-
 
-
isCatchStmt() - Method in class boomerang.scene.sootup.JimpleUpStatement
-
 
-
isClassConstant() - Method in class boomerang.scene.sootup.JimpleUpStaticFieldVal
-
 
-
isClassConstant() - Method in class boomerang.scene.sootup.JimpleUpVal
-
 
-
isConstructor() - Method in class boomerang.scene.sootup.JimpleUpDeclaredMethod
-
 
-
isConstructor() - Method in class boomerang.scene.sootup.JimpleUpMethod
-
 
-
isConstructor(JavaSootMethod) - Static method in class boomerang.scene.sootup.SootUpClient
-
 
-
isFieldLoad() - Method in class boomerang.scene.sootup.JimpleUpStatement
-
 
-
isFieldLoadWithBase(Val) - Method in class boomerang.scene.sootup.JimpleUpStatement
-
 
-
isFieldStore() - Method in class boomerang.scene.sootup.JimpleUpStatement
-
 
-
isFieldWriteWithBase(Val) - Method in class boomerang.scene.sootup.JimpleUpStatement
-
 
-
isIdentityStmt() - Method in class boomerang.scene.sootup.JimpleUpStatement
-
 
-
isIfStmt() - Method in class boomerang.scene.sootup.JimpleUpStatement
-
 
-
isInnerClassField() - Method in class boomerang.scene.sootup.JimpleUpField
-
 
-
isInstanceInvokeExpr() - Method in class boomerang.scene.sootup.JimpleUpInvokeExpr
-
 
-
isInstanceOfExpr() - Method in class boomerang.scene.sootup.JimpleUpStaticFieldVal
-
 
-
isInstanceOfExpr() - Method in class boomerang.scene.sootup.JimpleUpVal
-
 
-
isInstanceOfStatement(Val) - Method in class boomerang.scene.sootup.JimpleUpStatement
-
 
-
isIntConstant() - Method in class boomerang.scene.sootup.JimpleUpStaticFieldVal
-
 
-
isIntConstant() - Method in class boomerang.scene.sootup.JimpleUpVal
-
 
-
isLengthExpr() - Method in class boomerang.scene.sootup.JimpleUpStaticFieldVal
-
 
-
isLengthExpr() - Method in class boomerang.scene.sootup.JimpleUpVal
-
 
-
isLocal() - Method in class boomerang.scene.sootup.JimpleUpStaticFieldVal
-
 
-
isLocal() - Method in class boomerang.scene.sootup.JimpleUpVal
-
 
-
isLongConstant() - Method in class boomerang.scene.sootup.JimpleUpStaticFieldVal
-
 
-
isLongConstant() - Method in class boomerang.scene.sootup.JimpleUpVal
-
 
-
isMultiArrayAllocation() - Method in class boomerang.scene.sootup.JimpleUpStatement
-
 
-
isNative() - Method in class boomerang.scene.sootup.JimpleUpDeclaredMethod
-
 
-
isNative() - Method in class boomerang.scene.sootup.JimpleUpMethod
-
 
-
isNewExpr() - Method in class boomerang.scene.sootup.JimpleUpStaticFieldVal
-
 
-
isNewExpr() - Method in class boomerang.scene.sootup.JimpleUpVal
-
 
-
isNull() - Method in class boomerang.scene.sootup.JimpleUpStaticFieldVal
-
 
-
isNull() - Method in class boomerang.scene.sootup.JimpleUpVal
-
 
-
isNullType() - Method in class boomerang.scene.sootup.JimpleUpType
-
 
-
isParameterLocal(Val) - Method in class boomerang.scene.sootup.JimpleUpMethod
-
 
-
isPhiStatement() - Method in class boomerang.scene.sootup.JimpleUpStatement
-
 
-
isPublic() - Method in class boomerang.scene.sootup.JimpleUpMethod
-
 
-
isRefType() - Method in class boomerang.scene.sootup.JimpleUpType
-
 
-
isReturnStmt() - Method in class boomerang.scene.sootup.JimpleUpStatement
-
 
-
isSpecialInvokeExpr() - Method in class boomerang.scene.sootup.JimpleUpInvokeExpr
-
 
-
isStatic() - Method in class boomerang.scene.sootup.JimpleUpDeclaredMethod
-
 
-
isStatic() - Method in class boomerang.scene.sootup.JimpleUpMethod
-
 
-
isStatic() - Method in class boomerang.scene.sootup.JimpleUpStaticFieldVal
-
 
-
isStatic() - Method in class boomerang.scene.sootup.JimpleUpVal
-
 
-
isStaticFieldLoad() - Method in class boomerang.scene.sootup.JimpleUpStatement
-
 
-
isStaticFieldStore() - Method in class boomerang.scene.sootup.JimpleUpStatement
-
 
-
isStaticInitializer() - Method in class boomerang.scene.sootup.JimpleUpMethod
-
 
-
isStaticInitializer(JavaSootMethod) - Static method in class boomerang.scene.sootup.SootUpClient
-
 
-
isStaticInvokeExpr() - Method in class boomerang.scene.sootup.JimpleUpInvokeExpr
-
 
-
isStringAllocation() - Method in class boomerang.scene.sootup.JimpleUpStatement
-
 
-
isStringBufferOrBuilder() - Method in class boomerang.scene.sootup.JimpleUpStaticFieldVal
-
 
-
isStringBufferOrBuilder() - Method in class boomerang.scene.sootup.JimpleUpVal
-
 
-
isStringConstant() - Method in class boomerang.scene.sootup.JimpleUpStaticFieldVal
-
 
-
isStringConstant() - Method in class boomerang.scene.sootup.JimpleUpVal
-
 
-
isSubtypeOf(String) - Method in class boomerang.scene.sootup.JimpleUpType
-
 
-
isThisLocal(Val) - Method in class boomerang.scene.sootup.JimpleUpMethod
-
 
-
isThrowableAllocationType() - Method in class boomerang.scene.sootup.JimpleUpStaticFieldVal
-
 
-
isThrowableAllocationType() - Method in class boomerang.scene.sootup.JimpleUpVal
-
 
-
isThrowStmt() - Method in class boomerang.scene.sootup.JimpleUpStatement
-
 
-
- - - -

J

-
-
JimpleUpControlFlowGraph - Class in boomerang.scene.sootup
-
 
-
JimpleUpControlFlowGraph(JimpleUpMethod) - Constructor for class boomerang.scene.sootup.JimpleUpControlFlowGraph
-
 
-
JimpleUpDeclaredMethod - Class in boomerang.scene.sootup
-
 
-
JimpleUpDeclaredMethod(JimpleUpInvokeExpr, JavaSootMethod) - Constructor for class boomerang.scene.sootup.JimpleUpDeclaredMethod
-
 
-
JimpleUpDoubleVal - Class in boomerang.scene.sootup
-
 
-
JimpleUpDoubleVal(Value, JimpleUpMethod, Val) - Constructor for class boomerang.scene.sootup.JimpleUpDoubleVal
-
 
-
JimpleUpField - Class in boomerang.scene.sootup
-
 
-
JimpleUpField(JavaSootField) - Constructor for class boomerang.scene.sootup.JimpleUpField
-
 
-
JimpleUpIfStatement - Class in boomerang.scene.sootup
-
 
-
JimpleUpIfStatement(JIfStmt, JimpleUpMethod) - Constructor for class boomerang.scene.sootup.JimpleUpIfStatement
-
 
-
JimpleUpInstanceFieldRef - Class in boomerang.scene.sootup
-
 
-
JimpleUpInstanceFieldRef(JInstanceFieldRef, JimpleUpMethod) - Constructor for class boomerang.scene.sootup.JimpleUpInstanceFieldRef
-
 
-
JimpleUpInvokeExpr - Class in boomerang.scene.sootup
-
 
-
JimpleUpInvokeExpr(AbstractInvokeExpr, JimpleUpMethod) - Constructor for class boomerang.scene.sootup.JimpleUpInvokeExpr
-
 
-
JimpleUpMethod - Class in boomerang.scene.sootup
-
 
-
JimpleUpMethod(JavaSootMethod) - Constructor for class boomerang.scene.sootup.JimpleUpMethod
-
 
-
JimpleUpStatement - Class in boomerang.scene.sootup
-
 
-
JimpleUpStaticFieldVal - Class in boomerang.scene.sootup
-
 
-
JimpleUpStaticFieldVal(JimpleUpField, Method) - Constructor for class boomerang.scene.sootup.JimpleUpStaticFieldVal
-
 
-
JimpleUpType - Class in boomerang.scene.sootup
-
 
-
JimpleUpType(Type) - Constructor for class boomerang.scene.sootup.JimpleUpType
-
 
-
JimpleUpVal - Class in boomerang.scene.sootup
-
 
-
JimpleUpVal(Value, JimpleUpMethod) - Constructor for class boomerang.scene.sootup.JimpleUpVal
-
 
-
JimpleUpVal(Value, JimpleUpMethod, ControlFlowGraph.Edge) - Constructor for class boomerang.scene.sootup.JimpleUpVal
-
 
-
JimpleUpWrappedClass - Class in boomerang.scene.sootup
-
 
-
JimpleUpWrappedClass(JavaSootClass) - Constructor for class boomerang.scene.sootup.JimpleUpWrappedClass
-
 
-
- - - -

K

-
-
killAtIfStmt(Val, Statement) - Method in class boomerang.scene.sootup.JimpleUpStatement
-
 
-
- - - -

M

-
-
make() - Static method in class boomerang.scene.sootup.SootUpDataFlowScope
-
-
Default DataFlowScope that excludes native methods and methods from third-party libraries
-
-
- - - -

O

-
-
of(JavaSootMethod) - Static method in class boomerang.scene.sootup.JimpleUpMethod
-
 
-
- - - -

S

-
-
setInstance(JavaView, JavaIdentifierFactory) - Static method in class boomerang.scene.sootup.SootUpClient
-
 
-
SootUpCallGraph - Class in boomerang.scene.sootup
-
 
-
SootUpCallGraph(CallGraph, Collection<MethodSignature>) - Constructor for class boomerang.scene.sootup.SootUpCallGraph
-
 
-
SootUpClient - Class in boomerang.scene.sootup
-
 
-
SootUpDataFlowScope - Class in boomerang.scene.sootup
-
 
-
SootUpDataFlowScope() - Constructor for class boomerang.scene.sootup.SootUpDataFlowScope
-
 
-
- - - -

T

-
-
toString() - Method in class boomerang.scene.sootup.JimpleUpDeclaredMethod
-
 
-
toString() - Method in class boomerang.scene.sootup.JimpleUpDoubleVal
-
 
-
toString() - Method in class boomerang.scene.sootup.JimpleUpField
-
 
-
toString() - Method in class boomerang.scene.sootup.JimpleUpIfStatement
-
 
-
toString() - Method in class boomerang.scene.sootup.JimpleUpInstanceFieldRef
-
 
-
toString() - Method in class boomerang.scene.sootup.JimpleUpInvokeExpr
-
 
-
toString() - Method in class boomerang.scene.sootup.JimpleUpMethod
-
 
-
toString() - Method in class boomerang.scene.sootup.JimpleUpStatement
-
 
-
toString() - Method in class boomerang.scene.sootup.JimpleUpStaticFieldVal
-
 
-
toString() - Method in class boomerang.scene.sootup.JimpleUpVal
-
 
-
toString() - Method in class boomerang.scene.sootup.JimpleUpWrappedClass
-
 
-
TRANSFORM_CONSTANTS - Static variable in class boomerang.scene.sootup.BoomerangPreInterceptor
-
 
-
- - - -

U

-
-
uses(Val) - Method in class boomerang.scene.sootup.JimpleUpIfStatement
-
 
-
- - - -

W

-
-
withNewMethod(Method) - Method in class boomerang.scene.sootup.JimpleUpStaticFieldVal
-
 
-
withNewMethod(Method) - Method in class boomerang.scene.sootup.JimpleUpVal
-
 
-
withSecondVal(Val) - Method in class boomerang.scene.sootup.JimpleUpVal
-
 
-
-A B C D E F G H I J K M O S T U W 
All Classes All Packages
-
- - - diff --git a/boomerangScope-SootUp/target/apidocs/index.html b/boomerangScope-SootUp/target/apidocs/index.html deleted file mode 100644 index a86dcafe2..000000000 --- a/boomerangScope-SootUp/target/apidocs/index.html +++ /dev/null @@ -1,23 +0,0 @@ - - - - - -boomerangScope-SootUp 3.1.2-Sparse API - - - - - - - -
- -

boomerang/scene/sootup/package-summary.html

-
- - diff --git a/boomerangScope-SootUp/target/apidocs/jquery/external/jquery/jquery.js b/boomerangScope-SootUp/target/apidocs/jquery/external/jquery/jquery.js deleted file mode 100644 index 5b16efa11..000000000 --- a/boomerangScope-SootUp/target/apidocs/jquery/external/jquery/jquery.js +++ /dev/null @@ -1,10598 +0,0 @@ -/*! - * jQuery JavaScript Library v3.4.1 - * https://jquery.com/ - * - * Includes Sizzle.js - * https://sizzlejs.com/ - * - * Copyright JS Foundation and other contributors - * Released under the MIT license - * https://jquery.org/license - * - * Date: 2019-05-01T21:04Z - */ -( function( global, factory ) { - - "use strict"; - - if ( typeof module === "object" && typeof module.exports === "object" ) { - - // For CommonJS and CommonJS-like environments where a proper `window` - // is present, execute the factory and get jQuery. - // For environments that do not have a `window` with a `document` - // (such as Node.js), expose a factory as module.exports. - // This accentuates the need for the creation of a real `window`. - // e.g. var jQuery = require("jquery")(window); - // See ticket #14549 for more info. - module.exports = global.document ? - factory( global, true ) : - function( w ) { - if ( !w.document ) { - throw new Error( "jQuery requires a window with a document" ); - } - return factory( w ); - }; - } else { - factory( global ); - } - -// Pass this if window is not defined yet -} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) { - -// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1 -// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode -// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common -// enough that all such attempts are guarded in a try block. -"use strict"; - -var arr = []; - -var document = window.document; - -var getProto = Object.getPrototypeOf; - -var slice = arr.slice; - -var concat = arr.concat; - -var push = arr.push; - -var indexOf = arr.indexOf; - -var class2type = {}; - -var toString = class2type.toString; - -var hasOwn = class2type.hasOwnProperty; - -var fnToString = hasOwn.toString; - -var ObjectFunctionString = fnToString.call( Object ); - -var support = {}; - -var isFunction = function isFunction( obj ) { - - // Support: Chrome <=57, Firefox <=52 - // In some browsers, typeof returns "function" for HTML elements - // (i.e., `typeof document.createElement( "object" ) === "function"`). - // We don't want to classify *any* DOM node as a function. - return typeof obj === "function" && typeof obj.nodeType !== "number"; - }; - - -var isWindow = function isWindow( obj ) { - return obj != null && obj === obj.window; - }; - - - - - var preservedScriptAttributes = { - type: true, - src: true, - nonce: true, - noModule: true - }; - - function DOMEval( code, node, doc ) { - doc = doc || document; - - var i, val, - script = doc.createElement( "script" ); - - script.text = code; - if ( node ) { - for ( i in preservedScriptAttributes ) { - - // Support: Firefox 64+, Edge 18+ - // Some browsers don't support the "nonce" property on scripts. - // On the other hand, just using `getAttribute` is not enough as - // the `nonce` attribute is reset to an empty string whenever it - // becomes browsing-context connected. - // See https://github.com/whatwg/html/issues/2369 - // See https://html.spec.whatwg.org/#nonce-attributes - // The `node.getAttribute` check was added for the sake of - // `jQuery.globalEval` so that it can fake a nonce-containing node - // via an object. - val = node[ i ] || node.getAttribute && node.getAttribute( i ); - if ( val ) { - script.setAttribute( i, val ); - } - } - } - doc.head.appendChild( script ).parentNode.removeChild( script ); - } - - -function toType( obj ) { - if ( obj == null ) { - return obj + ""; - } - - // Support: Android <=2.3 only (functionish RegExp) - return typeof obj === "object" || typeof obj === "function" ? - class2type[ toString.call( obj ) ] || "object" : - typeof obj; -} -/* global Symbol */ -// Defining this global in .eslintrc.json would create a danger of using the global -// unguarded in another place, it seems safer to define global only for this module - - - -var - version = "3.4.1", - - // Define a local copy of jQuery - jQuery = function( selector, context ) { - - // The jQuery object is actually just the init constructor 'enhanced' - // Need init if jQuery is called (just allow error to be thrown if not included) - return new jQuery.fn.init( selector, context ); - }, - - // Support: Android <=4.0 only - // Make sure we trim BOM and NBSP - rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g; - -jQuery.fn = jQuery.prototype = { - - // The current version of jQuery being used - jquery: version, - - constructor: jQuery, - - // The default length of a jQuery object is 0 - length: 0, - - toArray: function() { - return slice.call( this ); - }, - - // Get the Nth element in the matched element set OR - // Get the whole matched element set as a clean array - get: function( num ) { - - // Return all the elements in a clean array - if ( num == null ) { - return slice.call( this ); - } - - // Return just the one element from the set - return num < 0 ? this[ num + this.length ] : this[ num ]; - }, - - // Take an array of elements and push it onto the stack - // (returning the new matched element set) - pushStack: function( elems ) { - - // Build a new jQuery matched element set - var ret = jQuery.merge( this.constructor(), elems ); - - // Add the old object onto the stack (as a reference) - ret.prevObject = this; - - // Return the newly-formed element set - return ret; - }, - - // Execute a callback for every element in the matched set. - each: function( callback ) { - return jQuery.each( this, callback ); - }, - - map: function( callback ) { - return this.pushStack( jQuery.map( this, function( elem, i ) { - return callback.call( elem, i, elem ); - } ) ); - }, - - slice: function() { - return this.pushStack( slice.apply( this, arguments ) ); - }, - - first: function() { - return this.eq( 0 ); - }, - - last: function() { - return this.eq( -1 ); - }, - - eq: function( i ) { - var len = this.length, - j = +i + ( i < 0 ? len : 0 ); - return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); - }, - - end: function() { - return this.prevObject || this.constructor(); - }, - - // For internal use only. - // Behaves like an Array's method, not like a jQuery method. - push: push, - sort: arr.sort, - splice: arr.splice -}; - -jQuery.extend = jQuery.fn.extend = function() { - var options, name, src, copy, copyIsArray, clone, - target = arguments[ 0 ] || {}, - i = 1, - length = arguments.length, - deep = false; - - // Handle a deep copy situation - if ( typeof target === "boolean" ) { - deep = target; - - // Skip the boolean and the target - target = arguments[ i ] || {}; - i++; - } - - // Handle case when target is a string or something (possible in deep copy) - if ( typeof target !== "object" && !isFunction( target ) ) { - target = {}; - } - - // Extend jQuery itself if only one argument is passed - if ( i === length ) { - target = this; - i--; - } - - for ( ; i < length; i++ ) { - - // Only deal with non-null/undefined values - if ( ( options = arguments[ i ] ) != null ) { - - // Extend the base object - for ( name in options ) { - copy = options[ name ]; - - // Prevent Object.prototype pollution - // Prevent never-ending loop - if ( name === "__proto__" || target === copy ) { - continue; - } - - // Recurse if we're merging plain objects or arrays - if ( deep && copy && ( jQuery.isPlainObject( copy ) || - ( copyIsArray = Array.isArray( copy ) ) ) ) { - src = target[ name ]; - - // Ensure proper type for the source value - if ( copyIsArray && !Array.isArray( src ) ) { - clone = []; - } else if ( !copyIsArray && !jQuery.isPlainObject( src ) ) { - clone = {}; - } else { - clone = src; - } - copyIsArray = false; - - // Never move original objects, clone them - target[ name ] = jQuery.extend( deep, clone, copy ); - - // Don't bring in undefined values - } else if ( copy !== undefined ) { - target[ name ] = copy; - } - } - } - } - - // Return the modified object - return target; -}; - -jQuery.extend( { - - // Unique for each copy of jQuery on the page - expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), - - // Assume jQuery is ready without the ready module - isReady: true, - - error: function( msg ) { - throw new Error( msg ); - }, - - noop: function() {}, - - isPlainObject: function( obj ) { - var proto, Ctor; - - // Detect obvious negatives - // Use toString instead of jQuery.type to catch host objects - if ( !obj || toString.call( obj ) !== "[object Object]" ) { - return false; - } - - proto = getProto( obj ); - - // Objects with no prototype (e.g., `Object.create( null )`) are plain - if ( !proto ) { - return true; - } - - // Objects with prototype are plain iff they were constructed by a global Object function - Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor; - return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString; - }, - - isEmptyObject: function( obj ) { - var name; - - for ( name in obj ) { - return false; - } - return true; - }, - - // Evaluates a script in a global context - globalEval: function( code, options ) { - DOMEval( code, { nonce: options && options.nonce } ); - }, - - each: function( obj, callback ) { - var length, i = 0; - - if ( isArrayLike( obj ) ) { - length = obj.length; - for ( ; i < length; i++ ) { - if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { - break; - } - } - } else { - for ( i in obj ) { - if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { - break; - } - } - } - - return obj; - }, - - // Support: Android <=4.0 only - trim: function( text ) { - return text == null ? - "" : - ( text + "" ).replace( rtrim, "" ); - }, - - // results is for internal usage only - makeArray: function( arr, results ) { - var ret = results || []; - - if ( arr != null ) { - if ( isArrayLike( Object( arr ) ) ) { - jQuery.merge( ret, - typeof arr === "string" ? - [ arr ] : arr - ); - } else { - push.call( ret, arr ); - } - } - - return ret; - }, - - inArray: function( elem, arr, i ) { - return arr == null ? -1 : indexOf.call( arr, elem, i ); - }, - - // Support: Android <=4.0 only, PhantomJS 1 only - // push.apply(_, arraylike) throws on ancient WebKit - merge: function( first, second ) { - var len = +second.length, - j = 0, - i = first.length; - - for ( ; j < len; j++ ) { - first[ i++ ] = second[ j ]; - } - - first.length = i; - - return first; - }, - - grep: function( elems, callback, invert ) { - var callbackInverse, - matches = [], - i = 0, - length = elems.length, - callbackExpect = !invert; - - // Go through the array, only saving the items - // that pass the validator function - for ( ; i < length; i++ ) { - callbackInverse = !callback( elems[ i ], i ); - if ( callbackInverse !== callbackExpect ) { - matches.push( elems[ i ] ); - } - } - - return matches; - }, - - // arg is for internal usage only - map: function( elems, callback, arg ) { - var length, value, - i = 0, - ret = []; - - // Go through the array, translating each of the items to their new values - if ( isArrayLike( elems ) ) { - length = elems.length; - for ( ; i < length; i++ ) { - value = callback( elems[ i ], i, arg ); - - if ( value != null ) { - ret.push( value ); - } - } - - // Go through every key on the object, - } else { - for ( i in elems ) { - value = callback( elems[ i ], i, arg ); - - if ( value != null ) { - ret.push( value ); - } - } - } - - // Flatten any nested arrays - return concat.apply( [], ret ); - }, - - // A global GUID counter for objects - guid: 1, - - // jQuery.support is not used in Core but other projects attach their - // properties to it so it needs to exist. - support: support -} ); - -if ( typeof Symbol === "function" ) { - jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; -} - -// Populate the class2type map -jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), -function( i, name ) { - class2type[ "[object " + name + "]" ] = name.toLowerCase(); -} ); - -function isArrayLike( obj ) { - - // Support: real iOS 8.2 only (not reproducible in simulator) - // `in` check used to prevent JIT error (gh-2145) - // hasOwn isn't used here due to false negatives - // regarding Nodelist length in IE - var length = !!obj && "length" in obj && obj.length, - type = toType( obj ); - - if ( isFunction( obj ) || isWindow( obj ) ) { - return false; - } - - return type === "array" || length === 0 || - typeof length === "number" && length > 0 && ( length - 1 ) in obj; -} -var Sizzle = -/*! - * Sizzle CSS Selector Engine v2.3.4 - * https://sizzlejs.com/ - * - * Copyright JS Foundation and other contributors - * Released under the MIT license - * https://js.foundation/ - * - * Date: 2019-04-08 - */ -(function( window ) { - -var i, - support, - Expr, - getText, - isXML, - tokenize, - compile, - select, - outermostContext, - sortInput, - hasDuplicate, - - // Local document vars - setDocument, - document, - docElem, - documentIsHTML, - rbuggyQSA, - rbuggyMatches, - matches, - contains, - - // Instance-specific data - expando = "sizzle" + 1 * new Date(), - preferredDoc = window.document, - dirruns = 0, - done = 0, - classCache = createCache(), - tokenCache = createCache(), - compilerCache = createCache(), - nonnativeSelectorCache = createCache(), - sortOrder = function( a, b ) { - if ( a === b ) { - hasDuplicate = true; - } - return 0; - }, - - // Instance methods - hasOwn = ({}).hasOwnProperty, - arr = [], - pop = arr.pop, - push_native = arr.push, - push = arr.push, - slice = arr.slice, - // Use a stripped-down indexOf as it's faster than native - // https://jsperf.com/thor-indexof-vs-for/5 - indexOf = function( list, elem ) { - var i = 0, - len = list.length; - for ( ; i < len; i++ ) { - if ( list[i] === elem ) { - return i; - } - } - return -1; - }, - - booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped", - - // Regular expressions - - // http://www.w3.org/TR/css3-selectors/#whitespace - whitespace = "[\\x20\\t\\r\\n\\f]", - - // http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier - identifier = "(?:\\\\.|[\\w-]|[^\0-\\xa0])+", - - // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors - attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + - // Operator (capture 2) - "*([*^$|!~]?=)" + whitespace + - // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]" - "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace + - "*\\]", - - pseudos = ":(" + identifier + ")(?:\\((" + - // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: - // 1. quoted (capture 3; capture 4 or capture 5) - "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + - // 2. simple (capture 6) - "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + - // 3. anything else (capture 2) - ".*" + - ")\\)|)", - - // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter - rwhitespace = new RegExp( whitespace + "+", "g" ), - rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), - - rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), - rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ), - rdescend = new RegExp( whitespace + "|>" ), - - rpseudo = new RegExp( pseudos ), - ridentifier = new RegExp( "^" + identifier + "$" ), - - matchExpr = { - "ID": new RegExp( "^#(" + identifier + ")" ), - "CLASS": new RegExp( "^\\.(" + identifier + ")" ), - "TAG": new RegExp( "^(" + identifier + "|[*])" ), - "ATTR": new RegExp( "^" + attributes ), - "PSEUDO": new RegExp( "^" + pseudos ), - "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + - "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + - "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), - "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), - // For use in libraries implementing .is() - // We use this for POS matching in `select` - "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + - whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) - }, - - rhtml = /HTML$/i, - rinputs = /^(?:input|select|textarea|button)$/i, - rheader = /^h\d$/i, - - rnative = /^[^{]+\{\s*\[native \w/, - - // Easily-parseable/retrievable ID or TAG or CLASS selectors - rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, - - rsibling = /[+~]/, - - // CSS escapes - // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters - runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ), - funescape = function( _, escaped, escapedWhitespace ) { - var high = "0x" + escaped - 0x10000; - // NaN means non-codepoint - // Support: Firefox<24 - // Workaround erroneous numeric interpretation of +"0x" - return high !== high || escapedWhitespace ? - escaped : - high < 0 ? - // BMP codepoint - String.fromCharCode( high + 0x10000 ) : - // Supplemental Plane codepoint (surrogate pair) - String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); - }, - - // CSS string/identifier serialization - // https://drafts.csswg.org/cssom/#common-serializing-idioms - rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g, - fcssescape = function( ch, asCodePoint ) { - if ( asCodePoint ) { - - // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER - if ( ch === "\0" ) { - return "\uFFFD"; - } - - // Control characters and (dependent upon position) numbers get escaped as code points - return ch.slice( 0, -1 ) + "\\" + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; - } - - // Other potentially-special ASCII characters get backslash-escaped - return "\\" + ch; - }, - - // Used for iframes - // See setDocument() - // Removing the function wrapper causes a "Permission Denied" - // error in IE - unloadHandler = function() { - setDocument(); - }, - - inDisabledFieldset = addCombinator( - function( elem ) { - return elem.disabled === true && elem.nodeName.toLowerCase() === "fieldset"; - }, - { dir: "parentNode", next: "legend" } - ); - -// Optimize for push.apply( _, NodeList ) -try { - push.apply( - (arr = slice.call( preferredDoc.childNodes )), - preferredDoc.childNodes - ); - // Support: Android<4.0 - // Detect silently failing push.apply - arr[ preferredDoc.childNodes.length ].nodeType; -} catch ( e ) { - push = { apply: arr.length ? - - // Leverage slice if possible - function( target, els ) { - push_native.apply( target, slice.call(els) ); - } : - - // Support: IE<9 - // Otherwise append directly - function( target, els ) { - var j = target.length, - i = 0; - // Can't trust NodeList.length - while ( (target[j++] = els[i++]) ) {} - target.length = j - 1; - } - }; -} - -function Sizzle( selector, context, results, seed ) { - var m, i, elem, nid, match, groups, newSelector, - newContext = context && context.ownerDocument, - - // nodeType defaults to 9, since context defaults to document - nodeType = context ? context.nodeType : 9; - - results = results || []; - - // Return early from calls with invalid selector or context - if ( typeof selector !== "string" || !selector || - nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { - - return results; - } - - // Try to shortcut find operations (as opposed to filters) in HTML documents - if ( !seed ) { - - if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) { - setDocument( context ); - } - context = context || document; - - if ( documentIsHTML ) { - - // If the selector is sufficiently simple, try using a "get*By*" DOM method - // (excepting DocumentFragment context, where the methods don't exist) - if ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) { - - // ID selector - if ( (m = match[1]) ) { - - // Document context - if ( nodeType === 9 ) { - if ( (elem = context.getElementById( m )) ) { - - // Support: IE, Opera, Webkit - // TODO: identify versions - // getElementById can match elements by name instead of ID - if ( elem.id === m ) { - results.push( elem ); - return results; - } - } else { - return results; - } - - // Element context - } else { - - // Support: IE, Opera, Webkit - // TODO: identify versions - // getElementById can match elements by name instead of ID - if ( newContext && (elem = newContext.getElementById( m )) && - contains( context, elem ) && - elem.id === m ) { - - results.push( elem ); - return results; - } - } - - // Type selector - } else if ( match[2] ) { - push.apply( results, context.getElementsByTagName( selector ) ); - return results; - - // Class selector - } else if ( (m = match[3]) && support.getElementsByClassName && - context.getElementsByClassName ) { - - push.apply( results, context.getElementsByClassName( m ) ); - return results; - } - } - - // Take advantage of querySelectorAll - if ( support.qsa && - !nonnativeSelectorCache[ selector + " " ] && - (!rbuggyQSA || !rbuggyQSA.test( selector )) && - - // Support: IE 8 only - // Exclude object elements - (nodeType !== 1 || context.nodeName.toLowerCase() !== "object") ) { - - newSelector = selector; - newContext = context; - - // qSA considers elements outside a scoping root when evaluating child or - // descendant combinators, which is not what we want. - // In such cases, we work around the behavior by prefixing every selector in the - // list with an ID selector referencing the scope context. - // Thanks to Andrew Dupont for this technique. - if ( nodeType === 1 && rdescend.test( selector ) ) { - - // Capture the context ID, setting it first if necessary - if ( (nid = context.getAttribute( "id" )) ) { - nid = nid.replace( rcssescape, fcssescape ); - } else { - context.setAttribute( "id", (nid = expando) ); - } - - // Prefix every selector in the list - groups = tokenize( selector ); - i = groups.length; - while ( i-- ) { - groups[i] = "#" + nid + " " + toSelector( groups[i] ); - } - newSelector = groups.join( "," ); - - // Expand context for sibling selectors - newContext = rsibling.test( selector ) && testContext( context.parentNode ) || - context; - } - - try { - push.apply( results, - newContext.querySelectorAll( newSelector ) - ); - return results; - } catch ( qsaError ) { - nonnativeSelectorCache( selector, true ); - } finally { - if ( nid === expando ) { - context.removeAttribute( "id" ); - } - } - } - } - } - - // All others - return select( selector.replace( rtrim, "$1" ), context, results, seed ); -} - -/** - * Create key-value caches of limited size - * @returns {function(string, object)} Returns the Object data after storing it on itself with - * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) - * deleting the oldest entry - */ -function createCache() { - var keys = []; - - function cache( key, value ) { - // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) - if ( keys.push( key + " " ) > Expr.cacheLength ) { - // Only keep the most recent entries - delete cache[ keys.shift() ]; - } - return (cache[ key + " " ] = value); - } - return cache; -} - -/** - * Mark a function for special use by Sizzle - * @param {Function} fn The function to mark - */ -function markFunction( fn ) { - fn[ expando ] = true; - return fn; -} - -/** - * Support testing using an element - * @param {Function} fn Passed the created element and returns a boolean result - */ -function assert( fn ) { - var el = document.createElement("fieldset"); - - try { - return !!fn( el ); - } catch (e) { - return false; - } finally { - // Remove from its parent by default - if ( el.parentNode ) { - el.parentNode.removeChild( el ); - } - // release memory in IE - el = null; - } -} - -/** - * Adds the same handler for all of the specified attrs - * @param {String} attrs Pipe-separated list of attributes - * @param {Function} handler The method that will be applied - */ -function addHandle( attrs, handler ) { - var arr = attrs.split("|"), - i = arr.length; - - while ( i-- ) { - Expr.attrHandle[ arr[i] ] = handler; - } -} - -/** - * Checks document order of two siblings - * @param {Element} a - * @param {Element} b - * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b - */ -function siblingCheck( a, b ) { - var cur = b && a, - diff = cur && a.nodeType === 1 && b.nodeType === 1 && - a.sourceIndex - b.sourceIndex; - - // Use IE sourceIndex if available on both nodes - if ( diff ) { - return diff; - } - - // Check if b follows a - if ( cur ) { - while ( (cur = cur.nextSibling) ) { - if ( cur === b ) { - return -1; - } - } - } - - return a ? 1 : -1; -} - -/** - * Returns a function to use in pseudos for input types - * @param {String} type - */ -function createInputPseudo( type ) { - return function( elem ) { - var name = elem.nodeName.toLowerCase(); - return name === "input" && elem.type === type; - }; -} - -/** - * Returns a function to use in pseudos for buttons - * @param {String} type - */ -function createButtonPseudo( type ) { - return function( elem ) { - var name = elem.nodeName.toLowerCase(); - return (name === "input" || name === "button") && elem.type === type; - }; -} - -/** - * Returns a function to use in pseudos for :enabled/:disabled - * @param {Boolean} disabled true for :disabled; false for :enabled - */ -function createDisabledPseudo( disabled ) { - - // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable - return function( elem ) { - - // Only certain elements can match :enabled or :disabled - // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled - // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled - if ( "form" in elem ) { - - // Check for inherited disabledness on relevant non-disabled elements: - // * listed form-associated elements in a disabled fieldset - // https://html.spec.whatwg.org/multipage/forms.html#category-listed - // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled - // * option elements in a disabled optgroup - // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled - // All such elements have a "form" property. - if ( elem.parentNode && elem.disabled === false ) { - - // Option elements defer to a parent optgroup if present - if ( "label" in elem ) { - if ( "label" in elem.parentNode ) { - return elem.parentNode.disabled === disabled; - } else { - return elem.disabled === disabled; - } - } - - // Support: IE 6 - 11 - // Use the isDisabled shortcut property to check for disabled fieldset ancestors - return elem.isDisabled === disabled || - - // Where there is no isDisabled, check manually - /* jshint -W018 */ - elem.isDisabled !== !disabled && - inDisabledFieldset( elem ) === disabled; - } - - return elem.disabled === disabled; - - // Try to winnow out elements that can't be disabled before trusting the disabled property. - // Some victims get caught in our net (label, legend, menu, track), but it shouldn't - // even exist on them, let alone have a boolean value. - } else if ( "label" in elem ) { - return elem.disabled === disabled; - } - - // Remaining elements are neither :enabled nor :disabled - return false; - }; -} - -/** - * Returns a function to use in pseudos for positionals - * @param {Function} fn - */ -function createPositionalPseudo( fn ) { - return markFunction(function( argument ) { - argument = +argument; - return markFunction(function( seed, matches ) { - var j, - matchIndexes = fn( [], seed.length, argument ), - i = matchIndexes.length; - - // Match elements found at the specified indexes - while ( i-- ) { - if ( seed[ (j = matchIndexes[i]) ] ) { - seed[j] = !(matches[j] = seed[j]); - } - } - }); - }); -} - -/** - * Checks a node for validity as a Sizzle context - * @param {Element|Object=} context - * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value - */ -function testContext( context ) { - return context && typeof context.getElementsByTagName !== "undefined" && context; -} - -// Expose support vars for convenience -support = Sizzle.support = {}; - -/** - * Detects XML nodes - * @param {Element|Object} elem An element or a document - * @returns {Boolean} True iff elem is a non-HTML XML node - */ -isXML = Sizzle.isXML = function( elem ) { - var namespace = elem.namespaceURI, - docElem = (elem.ownerDocument || elem).documentElement; - - // Support: IE <=8 - // Assume HTML when documentElement doesn't yet exist, such as inside loading iframes - // https://bugs.jquery.com/ticket/4833 - return !rhtml.test( namespace || docElem && docElem.nodeName || "HTML" ); -}; - -/** - * Sets document-related variables once based on the current document - * @param {Element|Object} [doc] An element or document object to use to set the document - * @returns {Object} Returns the current document - */ -setDocument = Sizzle.setDocument = function( node ) { - var hasCompare, subWindow, - doc = node ? node.ownerDocument || node : preferredDoc; - - // Return early if doc is invalid or already selected - if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) { - return document; - } - - // Update global variables - document = doc; - docElem = document.documentElement; - documentIsHTML = !isXML( document ); - - // Support: IE 9-11, Edge - // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) - if ( preferredDoc !== document && - (subWindow = document.defaultView) && subWindow.top !== subWindow ) { - - // Support: IE 11, Edge - if ( subWindow.addEventListener ) { - subWindow.addEventListener( "unload", unloadHandler, false ); - - // Support: IE 9 - 10 only - } else if ( subWindow.attachEvent ) { - subWindow.attachEvent( "onunload", unloadHandler ); - } - } - - /* Attributes - ---------------------------------------------------------------------- */ - - // Support: IE<8 - // Verify that getAttribute really returns attributes and not properties - // (excepting IE8 booleans) - support.attributes = assert(function( el ) { - el.className = "i"; - return !el.getAttribute("className"); - }); - - /* getElement(s)By* - ---------------------------------------------------------------------- */ - - // Check if getElementsByTagName("*") returns only elements - support.getElementsByTagName = assert(function( el ) { - el.appendChild( document.createComment("") ); - return !el.getElementsByTagName("*").length; - }); - - // Support: IE<9 - support.getElementsByClassName = rnative.test( document.getElementsByClassName ); - - // Support: IE<10 - // Check if getElementById returns elements by name - // The broken getElementById methods don't pick up programmatically-set names, - // so use a roundabout getElementsByName test - support.getById = assert(function( el ) { - docElem.appendChild( el ).id = expando; - return !document.getElementsByName || !document.getElementsByName( expando ).length; - }); - - // ID filter and find - if ( support.getById ) { - Expr.filter["ID"] = function( id ) { - var attrId = id.replace( runescape, funescape ); - return function( elem ) { - return elem.getAttribute("id") === attrId; - }; - }; - Expr.find["ID"] = function( id, context ) { - if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { - var elem = context.getElementById( id ); - return elem ? [ elem ] : []; - } - }; - } else { - Expr.filter["ID"] = function( id ) { - var attrId = id.replace( runescape, funescape ); - return function( elem ) { - var node = typeof elem.getAttributeNode !== "undefined" && - elem.getAttributeNode("id"); - return node && node.value === attrId; - }; - }; - - // Support: IE 6 - 7 only - // getElementById is not reliable as a find shortcut - Expr.find["ID"] = function( id, context ) { - if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { - var node, i, elems, - elem = context.getElementById( id ); - - if ( elem ) { - - // Verify the id attribute - node = elem.getAttributeNode("id"); - if ( node && node.value === id ) { - return [ elem ]; - } - - // Fall back on getElementsByName - elems = context.getElementsByName( id ); - i = 0; - while ( (elem = elems[i++]) ) { - node = elem.getAttributeNode("id"); - if ( node && node.value === id ) { - return [ elem ]; - } - } - } - - return []; - } - }; - } - - // Tag - Expr.find["TAG"] = support.getElementsByTagName ? - function( tag, context ) { - if ( typeof context.getElementsByTagName !== "undefined" ) { - return context.getElementsByTagName( tag ); - - // DocumentFragment nodes don't have gEBTN - } else if ( support.qsa ) { - return context.querySelectorAll( tag ); - } - } : - - function( tag, context ) { - var elem, - tmp = [], - i = 0, - // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too - results = context.getElementsByTagName( tag ); - - // Filter out possible comments - if ( tag === "*" ) { - while ( (elem = results[i++]) ) { - if ( elem.nodeType === 1 ) { - tmp.push( elem ); - } - } - - return tmp; - } - return results; - }; - - // Class - Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) { - if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { - return context.getElementsByClassName( className ); - } - }; - - /* QSA/matchesSelector - ---------------------------------------------------------------------- */ - - // QSA and matchesSelector support - - // matchesSelector(:active) reports false when true (IE9/Opera 11.5) - rbuggyMatches = []; - - // qSa(:focus) reports false when true (Chrome 21) - // We allow this because of a bug in IE8/9 that throws an error - // whenever `document.activeElement` is accessed on an iframe - // So, we allow :focus to pass through QSA all the time to avoid the IE error - // See https://bugs.jquery.com/ticket/13378 - rbuggyQSA = []; - - if ( (support.qsa = rnative.test( document.querySelectorAll )) ) { - // Build QSA regex - // Regex strategy adopted from Diego Perini - assert(function( el ) { - // Select is set to empty string on purpose - // This is to test IE's treatment of not explicitly - // setting a boolean content attribute, - // since its presence should be enough - // https://bugs.jquery.com/ticket/12359 - docElem.appendChild( el ).innerHTML = "" + - ""; - - // Support: IE8, Opera 11-12.16 - // Nothing should be selected when empty strings follow ^= or $= or *= - // The test attribute must be unknown in Opera but "safe" for WinRT - // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section - if ( el.querySelectorAll("[msallowcapture^='']").length ) { - rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); - } - - // Support: IE8 - // Boolean attributes and "value" are not treated correctly - if ( !el.querySelectorAll("[selected]").length ) { - rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); - } - - // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+ - if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) { - rbuggyQSA.push("~="); - } - - // Webkit/Opera - :checked should return selected option elements - // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked - // IE8 throws error here and will not see later tests - if ( !el.querySelectorAll(":checked").length ) { - rbuggyQSA.push(":checked"); - } - - // Support: Safari 8+, iOS 8+ - // https://bugs.webkit.org/show_bug.cgi?id=136851 - // In-page `selector#id sibling-combinator selector` fails - if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) { - rbuggyQSA.push(".#.+[+~]"); - } - }); - - assert(function( el ) { - el.innerHTML = "" + - ""; - - // Support: Windows 8 Native Apps - // The type and name attributes are restricted during .innerHTML assignment - var input = document.createElement("input"); - input.setAttribute( "type", "hidden" ); - el.appendChild( input ).setAttribute( "name", "D" ); - - // Support: IE8 - // Enforce case-sensitivity of name attribute - if ( el.querySelectorAll("[name=d]").length ) { - rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); - } - - // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) - // IE8 throws error here and will not see later tests - if ( el.querySelectorAll(":enabled").length !== 2 ) { - rbuggyQSA.push( ":enabled", ":disabled" ); - } - - // Support: IE9-11+ - // IE's :disabled selector does not pick up the children of disabled fieldsets - docElem.appendChild( el ).disabled = true; - if ( el.querySelectorAll(":disabled").length !== 2 ) { - rbuggyQSA.push( ":enabled", ":disabled" ); - } - - // Opera 10-11 does not throw on post-comma invalid pseudos - el.querySelectorAll("*,:x"); - rbuggyQSA.push(",.*:"); - }); - } - - if ( (support.matchesSelector = rnative.test( (matches = docElem.matches || - docElem.webkitMatchesSelector || - docElem.mozMatchesSelector || - docElem.oMatchesSelector || - docElem.msMatchesSelector) )) ) { - - assert(function( el ) { - // Check to see if it's possible to do matchesSelector - // on a disconnected node (IE 9) - support.disconnectedMatch = matches.call( el, "*" ); - - // This should fail with an exception - // Gecko does not error, returns false instead - matches.call( el, "[s!='']:x" ); - rbuggyMatches.push( "!=", pseudos ); - }); - } - - rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") ); - rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") ); - - /* Contains - ---------------------------------------------------------------------- */ - hasCompare = rnative.test( docElem.compareDocumentPosition ); - - // Element contains another - // Purposefully self-exclusive - // As in, an element does not contain itself - contains = hasCompare || rnative.test( docElem.contains ) ? - function( a, b ) { - var adown = a.nodeType === 9 ? a.documentElement : a, - bup = b && b.parentNode; - return a === bup || !!( bup && bup.nodeType === 1 && ( - adown.contains ? - adown.contains( bup ) : - a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 - )); - } : - function( a, b ) { - if ( b ) { - while ( (b = b.parentNode) ) { - if ( b === a ) { - return true; - } - } - } - return false; - }; - - /* Sorting - ---------------------------------------------------------------------- */ - - // Document order sorting - sortOrder = hasCompare ? - function( a, b ) { - - // Flag for duplicate removal - if ( a === b ) { - hasDuplicate = true; - return 0; - } - - // Sort on method existence if only one input has compareDocumentPosition - var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; - if ( compare ) { - return compare; - } - - // Calculate position if both inputs belong to the same document - compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ? - a.compareDocumentPosition( b ) : - - // Otherwise we know they are disconnected - 1; - - // Disconnected nodes - if ( compare & 1 || - (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) { - - // Choose the first element that is related to our preferred document - if ( a === document || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) { - return -1; - } - if ( b === document || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) { - return 1; - } - - // Maintain original order - return sortInput ? - ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : - 0; - } - - return compare & 4 ? -1 : 1; - } : - function( a, b ) { - // Exit early if the nodes are identical - if ( a === b ) { - hasDuplicate = true; - return 0; - } - - var cur, - i = 0, - aup = a.parentNode, - bup = b.parentNode, - ap = [ a ], - bp = [ b ]; - - // Parentless nodes are either documents or disconnected - if ( !aup || !bup ) { - return a === document ? -1 : - b === document ? 1 : - aup ? -1 : - bup ? 1 : - sortInput ? - ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : - 0; - - // If the nodes are siblings, we can do a quick check - } else if ( aup === bup ) { - return siblingCheck( a, b ); - } - - // Otherwise we need full lists of their ancestors for comparison - cur = a; - while ( (cur = cur.parentNode) ) { - ap.unshift( cur ); - } - cur = b; - while ( (cur = cur.parentNode) ) { - bp.unshift( cur ); - } - - // Walk down the tree looking for a discrepancy - while ( ap[i] === bp[i] ) { - i++; - } - - return i ? - // Do a sibling check if the nodes have a common ancestor - siblingCheck( ap[i], bp[i] ) : - - // Otherwise nodes in our document sort first - ap[i] === preferredDoc ? -1 : - bp[i] === preferredDoc ? 1 : - 0; - }; - - return document; -}; - -Sizzle.matches = function( expr, elements ) { - return Sizzle( expr, null, null, elements ); -}; - -Sizzle.matchesSelector = function( elem, expr ) { - // Set document vars if needed - if ( ( elem.ownerDocument || elem ) !== document ) { - setDocument( elem ); - } - - if ( support.matchesSelector && documentIsHTML && - !nonnativeSelectorCache[ expr + " " ] && - ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && - ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { - - try { - var ret = matches.call( elem, expr ); - - // IE 9's matchesSelector returns false on disconnected nodes - if ( ret || support.disconnectedMatch || - // As well, disconnected nodes are said to be in a document - // fragment in IE 9 - elem.document && elem.document.nodeType !== 11 ) { - return ret; - } - } catch (e) { - nonnativeSelectorCache( expr, true ); - } - } - - return Sizzle( expr, document, null, [ elem ] ).length > 0; -}; - -Sizzle.contains = function( context, elem ) { - // Set document vars if needed - if ( ( context.ownerDocument || context ) !== document ) { - setDocument( context ); - } - return contains( context, elem ); -}; - -Sizzle.attr = function( elem, name ) { - // Set document vars if needed - if ( ( elem.ownerDocument || elem ) !== document ) { - setDocument( elem ); - } - - var fn = Expr.attrHandle[ name.toLowerCase() ], - // Don't get fooled by Object.prototype properties (jQuery #13807) - val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? - fn( elem, name, !documentIsHTML ) : - undefined; - - return val !== undefined ? - val : - support.attributes || !documentIsHTML ? - elem.getAttribute( name ) : - (val = elem.getAttributeNode(name)) && val.specified ? - val.value : - null; -}; - -Sizzle.escape = function( sel ) { - return (sel + "").replace( rcssescape, fcssescape ); -}; - -Sizzle.error = function( msg ) { - throw new Error( "Syntax error, unrecognized expression: " + msg ); -}; - -/** - * Document sorting and removing duplicates - * @param {ArrayLike} results - */ -Sizzle.uniqueSort = function( results ) { - var elem, - duplicates = [], - j = 0, - i = 0; - - // Unless we *know* we can detect duplicates, assume their presence - hasDuplicate = !support.detectDuplicates; - sortInput = !support.sortStable && results.slice( 0 ); - results.sort( sortOrder ); - - if ( hasDuplicate ) { - while ( (elem = results[i++]) ) { - if ( elem === results[ i ] ) { - j = duplicates.push( i ); - } - } - while ( j-- ) { - results.splice( duplicates[ j ], 1 ); - } - } - - // Clear input after sorting to release objects - // See https://github.com/jquery/sizzle/pull/225 - sortInput = null; - - return results; -}; - -/** - * Utility function for retrieving the text value of an array of DOM nodes - * @param {Array|Element} elem - */ -getText = Sizzle.getText = function( elem ) { - var node, - ret = "", - i = 0, - nodeType = elem.nodeType; - - if ( !nodeType ) { - // If no nodeType, this is expected to be an array - while ( (node = elem[i++]) ) { - // Do not traverse comment nodes - ret += getText( node ); - } - } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { - // Use textContent for elements - // innerText usage removed for consistency of new lines (jQuery #11153) - if ( typeof elem.textContent === "string" ) { - return elem.textContent; - } else { - // Traverse its children - for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { - ret += getText( elem ); - } - } - } else if ( nodeType === 3 || nodeType === 4 ) { - return elem.nodeValue; - } - // Do not include comment or processing instruction nodes - - return ret; -}; - -Expr = Sizzle.selectors = { - - // Can be adjusted by the user - cacheLength: 50, - - createPseudo: markFunction, - - match: matchExpr, - - attrHandle: {}, - - find: {}, - - relative: { - ">": { dir: "parentNode", first: true }, - " ": { dir: "parentNode" }, - "+": { dir: "previousSibling", first: true }, - "~": { dir: "previousSibling" } - }, - - preFilter: { - "ATTR": function( match ) { - match[1] = match[1].replace( runescape, funescape ); - - // Move the given value to match[3] whether quoted or unquoted - match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape ); - - if ( match[2] === "~=" ) { - match[3] = " " + match[3] + " "; - } - - return match.slice( 0, 4 ); - }, - - "CHILD": function( match ) { - /* matches from matchExpr["CHILD"] - 1 type (only|nth|...) - 2 what (child|of-type) - 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) - 4 xn-component of xn+y argument ([+-]?\d*n|) - 5 sign of xn-component - 6 x of xn-component - 7 sign of y-component - 8 y of y-component - */ - match[1] = match[1].toLowerCase(); - - if ( match[1].slice( 0, 3 ) === "nth" ) { - // nth-* requires argument - if ( !match[3] ) { - Sizzle.error( match[0] ); - } - - // numeric x and y parameters for Expr.filter.CHILD - // remember that false/true cast respectively to 0/1 - match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) ); - match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" ); - - // other types prohibit arguments - } else if ( match[3] ) { - Sizzle.error( match[0] ); - } - - return match; - }, - - "PSEUDO": function( match ) { - var excess, - unquoted = !match[6] && match[2]; - - if ( matchExpr["CHILD"].test( match[0] ) ) { - return null; - } - - // Accept quoted arguments as-is - if ( match[3] ) { - match[2] = match[4] || match[5] || ""; - - // Strip excess characters from unquoted arguments - } else if ( unquoted && rpseudo.test( unquoted ) && - // Get excess from tokenize (recursively) - (excess = tokenize( unquoted, true )) && - // advance to the next closing parenthesis - (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) { - - // excess is a negative index - match[0] = match[0].slice( 0, excess ); - match[2] = unquoted.slice( 0, excess ); - } - - // Return only captures needed by the pseudo filter method (type and argument) - return match.slice( 0, 3 ); - } - }, - - filter: { - - "TAG": function( nodeNameSelector ) { - var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); - return nodeNameSelector === "*" ? - function() { return true; } : - function( elem ) { - return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; - }; - }, - - "CLASS": function( className ) { - var pattern = classCache[ className + " " ]; - - return pattern || - (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) && - classCache( className, function( elem ) { - return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || "" ); - }); - }, - - "ATTR": function( name, operator, check ) { - return function( elem ) { - var result = Sizzle.attr( elem, name ); - - if ( result == null ) { - return operator === "!="; - } - if ( !operator ) { - return true; - } - - result += ""; - - return operator === "=" ? result === check : - operator === "!=" ? result !== check : - operator === "^=" ? check && result.indexOf( check ) === 0 : - operator === "*=" ? check && result.indexOf( check ) > -1 : - operator === "$=" ? check && result.slice( -check.length ) === check : - operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 : - operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : - false; - }; - }, - - "CHILD": function( type, what, argument, first, last ) { - var simple = type.slice( 0, 3 ) !== "nth", - forward = type.slice( -4 ) !== "last", - ofType = what === "of-type"; - - return first === 1 && last === 0 ? - - // Shortcut for :nth-*(n) - function( elem ) { - return !!elem.parentNode; - } : - - function( elem, context, xml ) { - var cache, uniqueCache, outerCache, node, nodeIndex, start, - dir = simple !== forward ? "nextSibling" : "previousSibling", - parent = elem.parentNode, - name = ofType && elem.nodeName.toLowerCase(), - useCache = !xml && !ofType, - diff = false; - - if ( parent ) { - - // :(first|last|only)-(child|of-type) - if ( simple ) { - while ( dir ) { - node = elem; - while ( (node = node[ dir ]) ) { - if ( ofType ? - node.nodeName.toLowerCase() === name : - node.nodeType === 1 ) { - - return false; - } - } - // Reverse direction for :only-* (if we haven't yet done so) - start = dir = type === "only" && !start && "nextSibling"; - } - return true; - } - - start = [ forward ? parent.firstChild : parent.lastChild ]; - - // non-xml :nth-child(...) stores cache data on `parent` - if ( forward && useCache ) { - - // Seek `elem` from a previously-cached index - - // ...in a gzip-friendly way - node = parent; - outerCache = node[ expando ] || (node[ expando ] = {}); - - // Support: IE <9 only - // Defend against cloned attroperties (jQuery gh-1709) - uniqueCache = outerCache[ node.uniqueID ] || - (outerCache[ node.uniqueID ] = {}); - - cache = uniqueCache[ type ] || []; - nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; - diff = nodeIndex && cache[ 2 ]; - node = nodeIndex && parent.childNodes[ nodeIndex ]; - - while ( (node = ++nodeIndex && node && node[ dir ] || - - // Fallback to seeking `elem` from the start - (diff = nodeIndex = 0) || start.pop()) ) { - - // When found, cache indexes on `parent` and break - if ( node.nodeType === 1 && ++diff && node === elem ) { - uniqueCache[ type ] = [ dirruns, nodeIndex, diff ]; - break; - } - } - - } else { - // Use previously-cached element index if available - if ( useCache ) { - // ...in a gzip-friendly way - node = elem; - outerCache = node[ expando ] || (node[ expando ] = {}); - - // Support: IE <9 only - // Defend against cloned attroperties (jQuery gh-1709) - uniqueCache = outerCache[ node.uniqueID ] || - (outerCache[ node.uniqueID ] = {}); - - cache = uniqueCache[ type ] || []; - nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; - diff = nodeIndex; - } - - // xml :nth-child(...) - // or :nth-last-child(...) or :nth(-last)?-of-type(...) - if ( diff === false ) { - // Use the same loop as above to seek `elem` from the start - while ( (node = ++nodeIndex && node && node[ dir ] || - (diff = nodeIndex = 0) || start.pop()) ) { - - if ( ( ofType ? - node.nodeName.toLowerCase() === name : - node.nodeType === 1 ) && - ++diff ) { - - // Cache the index of each encountered element - if ( useCache ) { - outerCache = node[ expando ] || (node[ expando ] = {}); - - // Support: IE <9 only - // Defend against cloned attroperties (jQuery gh-1709) - uniqueCache = outerCache[ node.uniqueID ] || - (outerCache[ node.uniqueID ] = {}); - - uniqueCache[ type ] = [ dirruns, diff ]; - } - - if ( node === elem ) { - break; - } - } - } - } - } - - // Incorporate the offset, then check against cycle size - diff -= last; - return diff === first || ( diff % first === 0 && diff / first >= 0 ); - } - }; - }, - - "PSEUDO": function( pseudo, argument ) { - // pseudo-class names are case-insensitive - // http://www.w3.org/TR/selectors/#pseudo-classes - // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters - // Remember that setFilters inherits from pseudos - var args, - fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || - Sizzle.error( "unsupported pseudo: " + pseudo ); - - // The user may use createPseudo to indicate that - // arguments are needed to create the filter function - // just as Sizzle does - if ( fn[ expando ] ) { - return fn( argument ); - } - - // But maintain support for old signatures - if ( fn.length > 1 ) { - args = [ pseudo, pseudo, "", argument ]; - return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? - markFunction(function( seed, matches ) { - var idx, - matched = fn( seed, argument ), - i = matched.length; - while ( i-- ) { - idx = indexOf( seed, matched[i] ); - seed[ idx ] = !( matches[ idx ] = matched[i] ); - } - }) : - function( elem ) { - return fn( elem, 0, args ); - }; - } - - return fn; - } - }, - - pseudos: { - // Potentially complex pseudos - "not": markFunction(function( selector ) { - // Trim the selector passed to compile - // to avoid treating leading and trailing - // spaces as combinators - var input = [], - results = [], - matcher = compile( selector.replace( rtrim, "$1" ) ); - - return matcher[ expando ] ? - markFunction(function( seed, matches, context, xml ) { - var elem, - unmatched = matcher( seed, null, xml, [] ), - i = seed.length; - - // Match elements unmatched by `matcher` - while ( i-- ) { - if ( (elem = unmatched[i]) ) { - seed[i] = !(matches[i] = elem); - } - } - }) : - function( elem, context, xml ) { - input[0] = elem; - matcher( input, null, xml, results ); - // Don't keep the element (issue #299) - input[0] = null; - return !results.pop(); - }; - }), - - "has": markFunction(function( selector ) { - return function( elem ) { - return Sizzle( selector, elem ).length > 0; - }; - }), - - "contains": markFunction(function( text ) { - text = text.replace( runescape, funescape ); - return function( elem ) { - return ( elem.textContent || getText( elem ) ).indexOf( text ) > -1; - }; - }), - - // "Whether an element is represented by a :lang() selector - // is based solely on the element's language value - // being equal to the identifier C, - // or beginning with the identifier C immediately followed by "-". - // The matching of C against the element's language value is performed case-insensitively. - // The identifier C does not have to be a valid language name." - // http://www.w3.org/TR/selectors/#lang-pseudo - "lang": markFunction( function( lang ) { - // lang value must be a valid identifier - if ( !ridentifier.test(lang || "") ) { - Sizzle.error( "unsupported lang: " + lang ); - } - lang = lang.replace( runescape, funescape ).toLowerCase(); - return function( elem ) { - var elemLang; - do { - if ( (elemLang = documentIsHTML ? - elem.lang : - elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) { - - elemLang = elemLang.toLowerCase(); - return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; - } - } while ( (elem = elem.parentNode) && elem.nodeType === 1 ); - return false; - }; - }), - - // Miscellaneous - "target": function( elem ) { - var hash = window.location && window.location.hash; - return hash && hash.slice( 1 ) === elem.id; - }, - - "root": function( elem ) { - return elem === docElem; - }, - - "focus": function( elem ) { - return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex); - }, - - // Boolean properties - "enabled": createDisabledPseudo( false ), - "disabled": createDisabledPseudo( true ), - - "checked": function( elem ) { - // In CSS3, :checked should return both checked and selected elements - // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked - var nodeName = elem.nodeName.toLowerCase(); - return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); - }, - - "selected": function( elem ) { - // Accessing this property makes selected-by-default - // options in Safari work properly - if ( elem.parentNode ) { - elem.parentNode.selectedIndex; - } - - return elem.selected === true; - }, - - // Contents - "empty": function( elem ) { - // http://www.w3.org/TR/selectors/#empty-pseudo - // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), - // but not by others (comment: 8; processing instruction: 7; etc.) - // nodeType < 6 works because attributes (2) do not appear as children - for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { - if ( elem.nodeType < 6 ) { - return false; - } - } - return true; - }, - - "parent": function( elem ) { - return !Expr.pseudos["empty"]( elem ); - }, - - // Element/input types - "header": function( elem ) { - return rheader.test( elem.nodeName ); - }, - - "input": function( elem ) { - return rinputs.test( elem.nodeName ); - }, - - "button": function( elem ) { - var name = elem.nodeName.toLowerCase(); - return name === "input" && elem.type === "button" || name === "button"; - }, - - "text": function( elem ) { - var attr; - return elem.nodeName.toLowerCase() === "input" && - elem.type === "text" && - - // Support: IE<8 - // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" - ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" ); - }, - - // Position-in-collection - "first": createPositionalPseudo(function() { - return [ 0 ]; - }), - - "last": createPositionalPseudo(function( matchIndexes, length ) { - return [ length - 1 ]; - }), - - "eq": createPositionalPseudo(function( matchIndexes, length, argument ) { - return [ argument < 0 ? argument + length : argument ]; - }), - - "even": createPositionalPseudo(function( matchIndexes, length ) { - var i = 0; - for ( ; i < length; i += 2 ) { - matchIndexes.push( i ); - } - return matchIndexes; - }), - - "odd": createPositionalPseudo(function( matchIndexes, length ) { - var i = 1; - for ( ; i < length; i += 2 ) { - matchIndexes.push( i ); - } - return matchIndexes; - }), - - "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { - var i = argument < 0 ? - argument + length : - argument > length ? - length : - argument; - for ( ; --i >= 0; ) { - matchIndexes.push( i ); - } - return matchIndexes; - }), - - "gt": createPositionalPseudo(function( matchIndexes, length, argument ) { - var i = argument < 0 ? argument + length : argument; - for ( ; ++i < length; ) { - matchIndexes.push( i ); - } - return matchIndexes; - }) - } -}; - -Expr.pseudos["nth"] = Expr.pseudos["eq"]; - -// Add button/input type pseudos -for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { - Expr.pseudos[ i ] = createInputPseudo( i ); -} -for ( i in { submit: true, reset: true } ) { - Expr.pseudos[ i ] = createButtonPseudo( i ); -} - -// Easy API for creating new setFilters -function setFilters() {} -setFilters.prototype = Expr.filters = Expr.pseudos; -Expr.setFilters = new setFilters(); - -tokenize = Sizzle.tokenize = function( selector, parseOnly ) { - var matched, match, tokens, type, - soFar, groups, preFilters, - cached = tokenCache[ selector + " " ]; - - if ( cached ) { - return parseOnly ? 0 : cached.slice( 0 ); - } - - soFar = selector; - groups = []; - preFilters = Expr.preFilter; - - while ( soFar ) { - - // Comma and first run - if ( !matched || (match = rcomma.exec( soFar )) ) { - if ( match ) { - // Don't consume trailing commas as valid - soFar = soFar.slice( match[0].length ) || soFar; - } - groups.push( (tokens = []) ); - } - - matched = false; - - // Combinators - if ( (match = rcombinators.exec( soFar )) ) { - matched = match.shift(); - tokens.push({ - value: matched, - // Cast descendant combinators to space - type: match[0].replace( rtrim, " " ) - }); - soFar = soFar.slice( matched.length ); - } - - // Filters - for ( type in Expr.filter ) { - if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || - (match = preFilters[ type ]( match ))) ) { - matched = match.shift(); - tokens.push({ - value: matched, - type: type, - matches: match - }); - soFar = soFar.slice( matched.length ); - } - } - - if ( !matched ) { - break; - } - } - - // Return the length of the invalid excess - // if we're just parsing - // Otherwise, throw an error or return tokens - return parseOnly ? - soFar.length : - soFar ? - Sizzle.error( selector ) : - // Cache the tokens - tokenCache( selector, groups ).slice( 0 ); -}; - -function toSelector( tokens ) { - var i = 0, - len = tokens.length, - selector = ""; - for ( ; i < len; i++ ) { - selector += tokens[i].value; - } - return selector; -} - -function addCombinator( matcher, combinator, base ) { - var dir = combinator.dir, - skip = combinator.next, - key = skip || dir, - checkNonElements = base && key === "parentNode", - doneName = done++; - - return combinator.first ? - // Check against closest ancestor/preceding element - function( elem, context, xml ) { - while ( (elem = elem[ dir ]) ) { - if ( elem.nodeType === 1 || checkNonElements ) { - return matcher( elem, context, xml ); - } - } - return false; - } : - - // Check against all ancestor/preceding elements - function( elem, context, xml ) { - var oldCache, uniqueCache, outerCache, - newCache = [ dirruns, doneName ]; - - // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching - if ( xml ) { - while ( (elem = elem[ dir ]) ) { - if ( elem.nodeType === 1 || checkNonElements ) { - if ( matcher( elem, context, xml ) ) { - return true; - } - } - } - } else { - while ( (elem = elem[ dir ]) ) { - if ( elem.nodeType === 1 || checkNonElements ) { - outerCache = elem[ expando ] || (elem[ expando ] = {}); - - // Support: IE <9 only - // Defend against cloned attroperties (jQuery gh-1709) - uniqueCache = outerCache[ elem.uniqueID ] || (outerCache[ elem.uniqueID ] = {}); - - if ( skip && skip === elem.nodeName.toLowerCase() ) { - elem = elem[ dir ] || elem; - } else if ( (oldCache = uniqueCache[ key ]) && - oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { - - // Assign to newCache so results back-propagate to previous elements - return (newCache[ 2 ] = oldCache[ 2 ]); - } else { - // Reuse newcache so results back-propagate to previous elements - uniqueCache[ key ] = newCache; - - // A match means we're done; a fail means we have to keep checking - if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) { - return true; - } - } - } - } - } - return false; - }; -} - -function elementMatcher( matchers ) { - return matchers.length > 1 ? - function( elem, context, xml ) { - var i = matchers.length; - while ( i-- ) { - if ( !matchers[i]( elem, context, xml ) ) { - return false; - } - } - return true; - } : - matchers[0]; -} - -function multipleContexts( selector, contexts, results ) { - var i = 0, - len = contexts.length; - for ( ; i < len; i++ ) { - Sizzle( selector, contexts[i], results ); - } - return results; -} - -function condense( unmatched, map, filter, context, xml ) { - var elem, - newUnmatched = [], - i = 0, - len = unmatched.length, - mapped = map != null; - - for ( ; i < len; i++ ) { - if ( (elem = unmatched[i]) ) { - if ( !filter || filter( elem, context, xml ) ) { - newUnmatched.push( elem ); - if ( mapped ) { - map.push( i ); - } - } - } - } - - return newUnmatched; -} - -function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { - if ( postFilter && !postFilter[ expando ] ) { - postFilter = setMatcher( postFilter ); - } - if ( postFinder && !postFinder[ expando ] ) { - postFinder = setMatcher( postFinder, postSelector ); - } - return markFunction(function( seed, results, context, xml ) { - var temp, i, elem, - preMap = [], - postMap = [], - preexisting = results.length, - - // Get initial elements from seed or context - elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ), - - // Prefilter to get matcher input, preserving a map for seed-results synchronization - matcherIn = preFilter && ( seed || !selector ) ? - condense( elems, preMap, preFilter, context, xml ) : - elems, - - matcherOut = matcher ? - // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, - postFinder || ( seed ? preFilter : preexisting || postFilter ) ? - - // ...intermediate processing is necessary - [] : - - // ...otherwise use results directly - results : - matcherIn; - - // Find primary matches - if ( matcher ) { - matcher( matcherIn, matcherOut, context, xml ); - } - - // Apply postFilter - if ( postFilter ) { - temp = condense( matcherOut, postMap ); - postFilter( temp, [], context, xml ); - - // Un-match failing elements by moving them back to matcherIn - i = temp.length; - while ( i-- ) { - if ( (elem = temp[i]) ) { - matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem); - } - } - } - - if ( seed ) { - if ( postFinder || preFilter ) { - if ( postFinder ) { - // Get the final matcherOut by condensing this intermediate into postFinder contexts - temp = []; - i = matcherOut.length; - while ( i-- ) { - if ( (elem = matcherOut[i]) ) { - // Restore matcherIn since elem is not yet a final match - temp.push( (matcherIn[i] = elem) ); - } - } - postFinder( null, (matcherOut = []), temp, xml ); - } - - // Move matched elements from seed to results to keep them synchronized - i = matcherOut.length; - while ( i-- ) { - if ( (elem = matcherOut[i]) && - (temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) { - - seed[temp] = !(results[temp] = elem); - } - } - } - - // Add elements to results, through postFinder if defined - } else { - matcherOut = condense( - matcherOut === results ? - matcherOut.splice( preexisting, matcherOut.length ) : - matcherOut - ); - if ( postFinder ) { - postFinder( null, results, matcherOut, xml ); - } else { - push.apply( results, matcherOut ); - } - } - }); -} - -function matcherFromTokens( tokens ) { - var checkContext, matcher, j, - len = tokens.length, - leadingRelative = Expr.relative[ tokens[0].type ], - implicitRelative = leadingRelative || Expr.relative[" "], - i = leadingRelative ? 1 : 0, - - // The foundational matcher ensures that elements are reachable from top-level context(s) - matchContext = addCombinator( function( elem ) { - return elem === checkContext; - }, implicitRelative, true ), - matchAnyContext = addCombinator( function( elem ) { - return indexOf( checkContext, elem ) > -1; - }, implicitRelative, true ), - matchers = [ function( elem, context, xml ) { - var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( - (checkContext = context).nodeType ? - matchContext( elem, context, xml ) : - matchAnyContext( elem, context, xml ) ); - // Avoid hanging onto element (issue #299) - checkContext = null; - return ret; - } ]; - - for ( ; i < len; i++ ) { - if ( (matcher = Expr.relative[ tokens[i].type ]) ) { - matchers = [ addCombinator(elementMatcher( matchers ), matcher) ]; - } else { - matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches ); - - // Return special upon seeing a positional matcher - if ( matcher[ expando ] ) { - // Find the next relative operator (if any) for proper handling - j = ++i; - for ( ; j < len; j++ ) { - if ( Expr.relative[ tokens[j].type ] ) { - break; - } - } - return setMatcher( - i > 1 && elementMatcher( matchers ), - i > 1 && toSelector( - // If the preceding token was a descendant combinator, insert an implicit any-element `*` - tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" }) - ).replace( rtrim, "$1" ), - matcher, - i < j && matcherFromTokens( tokens.slice( i, j ) ), - j < len && matcherFromTokens( (tokens = tokens.slice( j )) ), - j < len && toSelector( tokens ) - ); - } - matchers.push( matcher ); - } - } - - return elementMatcher( matchers ); -} - -function matcherFromGroupMatchers( elementMatchers, setMatchers ) { - var bySet = setMatchers.length > 0, - byElement = elementMatchers.length > 0, - superMatcher = function( seed, context, xml, results, outermost ) { - var elem, j, matcher, - matchedCount = 0, - i = "0", - unmatched = seed && [], - setMatched = [], - contextBackup = outermostContext, - // We must always have either seed elements or outermost context - elems = seed || byElement && Expr.find["TAG"]( "*", outermost ), - // Use integer dirruns iff this is the outermost matcher - dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1), - len = elems.length; - - if ( outermost ) { - outermostContext = context === document || context || outermost; - } - - // Add elements passing elementMatchers directly to results - // Support: IE<9, Safari - // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id - for ( ; i !== len && (elem = elems[i]) != null; i++ ) { - if ( byElement && elem ) { - j = 0; - if ( !context && elem.ownerDocument !== document ) { - setDocument( elem ); - xml = !documentIsHTML; - } - while ( (matcher = elementMatchers[j++]) ) { - if ( matcher( elem, context || document, xml) ) { - results.push( elem ); - break; - } - } - if ( outermost ) { - dirruns = dirrunsUnique; - } - } - - // Track unmatched elements for set filters - if ( bySet ) { - // They will have gone through all possible matchers - if ( (elem = !matcher && elem) ) { - matchedCount--; - } - - // Lengthen the array for every element, matched or not - if ( seed ) { - unmatched.push( elem ); - } - } - } - - // `i` is now the count of elements visited above, and adding it to `matchedCount` - // makes the latter nonnegative. - matchedCount += i; - - // Apply set filters to unmatched elements - // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount` - // equals `i`), unless we didn't visit _any_ elements in the above loop because we have - // no element matchers and no seed. - // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that - // case, which will result in a "00" `matchedCount` that differs from `i` but is also - // numerically zero. - if ( bySet && i !== matchedCount ) { - j = 0; - while ( (matcher = setMatchers[j++]) ) { - matcher( unmatched, setMatched, context, xml ); - } - - if ( seed ) { - // Reintegrate element matches to eliminate the need for sorting - if ( matchedCount > 0 ) { - while ( i-- ) { - if ( !(unmatched[i] || setMatched[i]) ) { - setMatched[i] = pop.call( results ); - } - } - } - - // Discard index placeholder values to get only actual matches - setMatched = condense( setMatched ); - } - - // Add matches to results - push.apply( results, setMatched ); - - // Seedless set matches succeeding multiple successful matchers stipulate sorting - if ( outermost && !seed && setMatched.length > 0 && - ( matchedCount + setMatchers.length ) > 1 ) { - - Sizzle.uniqueSort( results ); - } - } - - // Override manipulation of globals by nested matchers - if ( outermost ) { - dirruns = dirrunsUnique; - outermostContext = contextBackup; - } - - return unmatched; - }; - - return bySet ? - markFunction( superMatcher ) : - superMatcher; -} - -compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { - var i, - setMatchers = [], - elementMatchers = [], - cached = compilerCache[ selector + " " ]; - - if ( !cached ) { - // Generate a function of recursive functions that can be used to check each element - if ( !match ) { - match = tokenize( selector ); - } - i = match.length; - while ( i-- ) { - cached = matcherFromTokens( match[i] ); - if ( cached[ expando ] ) { - setMatchers.push( cached ); - } else { - elementMatchers.push( cached ); - } - } - - // Cache the compiled function - cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) ); - - // Save selector and tokenization - cached.selector = selector; - } - return cached; -}; - -/** - * A low-level selection function that works with Sizzle's compiled - * selector functions - * @param {String|Function} selector A selector or a pre-compiled - * selector function built with Sizzle.compile - * @param {Element} context - * @param {Array} [results] - * @param {Array} [seed] A set of elements to match against - */ -select = Sizzle.select = function( selector, context, results, seed ) { - var i, tokens, token, type, find, - compiled = typeof selector === "function" && selector, - match = !seed && tokenize( (selector = compiled.selector || selector) ); - - results = results || []; - - // Try to minimize operations if there is only one selector in the list and no seed - // (the latter of which guarantees us context) - if ( match.length === 1 ) { - - // Reduce context if the leading compound selector is an ID - tokens = match[0] = match[0].slice( 0 ); - if ( tokens.length > 2 && (token = tokens[0]).type === "ID" && - context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[1].type ] ) { - - context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0]; - if ( !context ) { - return results; - - // Precompiled matchers will still verify ancestry, so step up a level - } else if ( compiled ) { - context = context.parentNode; - } - - selector = selector.slice( tokens.shift().value.length ); - } - - // Fetch a seed set for right-to-left matching - i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length; - while ( i-- ) { - token = tokens[i]; - - // Abort if we hit a combinator - if ( Expr.relative[ (type = token.type) ] ) { - break; - } - if ( (find = Expr.find[ type ]) ) { - // Search, expanding context for leading sibling combinators - if ( (seed = find( - token.matches[0].replace( runescape, funescape ), - rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context - )) ) { - - // If seed is empty or no tokens remain, we can return early - tokens.splice( i, 1 ); - selector = seed.length && toSelector( tokens ); - if ( !selector ) { - push.apply( results, seed ); - return results; - } - - break; - } - } - } - } - - // Compile and execute a filtering function if one is not provided - // Provide `match` to avoid retokenization if we modified the selector above - ( compiled || compile( selector, match ) )( - seed, - context, - !documentIsHTML, - results, - !context || rsibling.test( selector ) && testContext( context.parentNode ) || context - ); - return results; -}; - -// One-time assignments - -// Sort stability -support.sortStable = expando.split("").sort( sortOrder ).join("") === expando; - -// Support: Chrome 14-35+ -// Always assume duplicates if they aren't passed to the comparison function -support.detectDuplicates = !!hasDuplicate; - -// Initialize against the default document -setDocument(); - -// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) -// Detached nodes confoundingly follow *each other* -support.sortDetached = assert(function( el ) { - // Should return 1, but returns 4 (following) - return el.compareDocumentPosition( document.createElement("fieldset") ) & 1; -}); - -// Support: IE<8 -// Prevent attribute/property "interpolation" -// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx -if ( !assert(function( el ) { - el.innerHTML = ""; - return el.firstChild.getAttribute("href") === "#" ; -}) ) { - addHandle( "type|href|height|width", function( elem, name, isXML ) { - if ( !isXML ) { - return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); - } - }); -} - -// Support: IE<9 -// Use defaultValue in place of getAttribute("value") -if ( !support.attributes || !assert(function( el ) { - el.innerHTML = ""; - el.firstChild.setAttribute( "value", "" ); - return el.firstChild.getAttribute( "value" ) === ""; -}) ) { - addHandle( "value", function( elem, name, isXML ) { - if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { - return elem.defaultValue; - } - }); -} - -// Support: IE<9 -// Use getAttributeNode to fetch booleans when getAttribute lies -if ( !assert(function( el ) { - return el.getAttribute("disabled") == null; -}) ) { - addHandle( booleans, function( elem, name, isXML ) { - var val; - if ( !isXML ) { - return elem[ name ] === true ? name.toLowerCase() : - (val = elem.getAttributeNode( name )) && val.specified ? - val.value : - null; - } - }); -} - -return Sizzle; - -})( window ); - - - -jQuery.find = Sizzle; -jQuery.expr = Sizzle.selectors; - -// Deprecated -jQuery.expr[ ":" ] = jQuery.expr.pseudos; -jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort; -jQuery.text = Sizzle.getText; -jQuery.isXMLDoc = Sizzle.isXML; -jQuery.contains = Sizzle.contains; -jQuery.escapeSelector = Sizzle.escape; - - - - -var dir = function( elem, dir, until ) { - var matched = [], - truncate = until !== undefined; - - while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) { - if ( elem.nodeType === 1 ) { - if ( truncate && jQuery( elem ).is( until ) ) { - break; - } - matched.push( elem ); - } - } - return matched; -}; - - -var siblings = function( n, elem ) { - var matched = []; - - for ( ; n; n = n.nextSibling ) { - if ( n.nodeType === 1 && n !== elem ) { - matched.push( n ); - } - } - - return matched; -}; - - -var rneedsContext = jQuery.expr.match.needsContext; - - - -function nodeName( elem, name ) { - - return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); - -}; -var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i ); - - - -// Implement the identical functionality for filter and not -function winnow( elements, qualifier, not ) { - if ( isFunction( qualifier ) ) { - return jQuery.grep( elements, function( elem, i ) { - return !!qualifier.call( elem, i, elem ) !== not; - } ); - } - - // Single element - if ( qualifier.nodeType ) { - return jQuery.grep( elements, function( elem ) { - return ( elem === qualifier ) !== not; - } ); - } - - // Arraylike of elements (jQuery, arguments, Array) - if ( typeof qualifier !== "string" ) { - return jQuery.grep( elements, function( elem ) { - return ( indexOf.call( qualifier, elem ) > -1 ) !== not; - } ); - } - - // Filtered directly for both simple and complex selectors - return jQuery.filter( qualifier, elements, not ); -} - -jQuery.filter = function( expr, elems, not ) { - var elem = elems[ 0 ]; - - if ( not ) { - expr = ":not(" + expr + ")"; - } - - if ( elems.length === 1 && elem.nodeType === 1 ) { - return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : []; - } - - return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { - return elem.nodeType === 1; - } ) ); -}; - -jQuery.fn.extend( { - find: function( selector ) { - var i, ret, - len = this.length, - self = this; - - if ( typeof selector !== "string" ) { - return this.pushStack( jQuery( selector ).filter( function() { - for ( i = 0; i < len; i++ ) { - if ( jQuery.contains( self[ i ], this ) ) { - return true; - } - } - } ) ); - } - - ret = this.pushStack( [] ); - - for ( i = 0; i < len; i++ ) { - jQuery.find( selector, self[ i ], ret ); - } - - return len > 1 ? jQuery.uniqueSort( ret ) : ret; - }, - filter: function( selector ) { - return this.pushStack( winnow( this, selector || [], false ) ); - }, - not: function( selector ) { - return this.pushStack( winnow( this, selector || [], true ) ); - }, - is: function( selector ) { - return !!winnow( - this, - - // If this is a positional/relative selector, check membership in the returned set - // so $("p:first").is("p:last") won't return true for a doc with two "p". - typeof selector === "string" && rneedsContext.test( selector ) ? - jQuery( selector ) : - selector || [], - false - ).length; - } -} ); - - -// Initialize a jQuery object - - -// A central reference to the root jQuery(document) -var rootjQuery, - - // A simple way to check for HTML strings - // Prioritize #id over to avoid XSS via location.hash (#9521) - // Strict HTML recognition (#11290: must start with <) - // Shortcut simple #id case for speed - rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/, - - init = jQuery.fn.init = function( selector, context, root ) { - var match, elem; - - // HANDLE: $(""), $(null), $(undefined), $(false) - if ( !selector ) { - return this; - } - - // Method init() accepts an alternate rootjQuery - // so migrate can support jQuery.sub (gh-2101) - root = root || rootjQuery; - - // Handle HTML strings - if ( typeof selector === "string" ) { - if ( selector[ 0 ] === "<" && - selector[ selector.length - 1 ] === ">" && - selector.length >= 3 ) { - - // Assume that strings that start and end with <> are HTML and skip the regex check - match = [ null, selector, null ]; - - } else { - match = rquickExpr.exec( selector ); - } - - // Match html or make sure no context is specified for #id - if ( match && ( match[ 1 ] || !context ) ) { - - // HANDLE: $(html) -> $(array) - if ( match[ 1 ] ) { - context = context instanceof jQuery ? context[ 0 ] : context; - - // Option to run scripts is true for back-compat - // Intentionally let the error be thrown if parseHTML is not present - jQuery.merge( this, jQuery.parseHTML( - match[ 1 ], - context && context.nodeType ? context.ownerDocument || context : document, - true - ) ); - - // HANDLE: $(html, props) - if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) { - for ( match in context ) { - - // Properties of context are called as methods if possible - if ( isFunction( this[ match ] ) ) { - this[ match ]( context[ match ] ); - - // ...and otherwise set as attributes - } else { - this.attr( match, context[ match ] ); - } - } - } - - return this; - - // HANDLE: $(#id) - } else { - elem = document.getElementById( match[ 2 ] ); - - if ( elem ) { - - // Inject the element directly into the jQuery object - this[ 0 ] = elem; - this.length = 1; - } - return this; - } - - // HANDLE: $(expr, $(...)) - } else if ( !context || context.jquery ) { - return ( context || root ).find( selector ); - - // HANDLE: $(expr, context) - // (which is just equivalent to: $(context).find(expr) - } else { - return this.constructor( context ).find( selector ); - } - - // HANDLE: $(DOMElement) - } else if ( selector.nodeType ) { - this[ 0 ] = selector; - this.length = 1; - return this; - - // HANDLE: $(function) - // Shortcut for document ready - } else if ( isFunction( selector ) ) { - return root.ready !== undefined ? - root.ready( selector ) : - - // Execute immediately if ready is not present - selector( jQuery ); - } - - return jQuery.makeArray( selector, this ); - }; - -// Give the init function the jQuery prototype for later instantiation -init.prototype = jQuery.fn; - -// Initialize central reference -rootjQuery = jQuery( document ); - - -var rparentsprev = /^(?:parents|prev(?:Until|All))/, - - // Methods guaranteed to produce a unique set when starting from a unique set - guaranteedUnique = { - children: true, - contents: true, - next: true, - prev: true - }; - -jQuery.fn.extend( { - has: function( target ) { - var targets = jQuery( target, this ), - l = targets.length; - - return this.filter( function() { - var i = 0; - for ( ; i < l; i++ ) { - if ( jQuery.contains( this, targets[ i ] ) ) { - return true; - } - } - } ); - }, - - closest: function( selectors, context ) { - var cur, - i = 0, - l = this.length, - matched = [], - targets = typeof selectors !== "string" && jQuery( selectors ); - - // Positional selectors never match, since there's no _selection_ context - if ( !rneedsContext.test( selectors ) ) { - for ( ; i < l; i++ ) { - for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) { - - // Always skip document fragments - if ( cur.nodeType < 11 && ( targets ? - targets.index( cur ) > -1 : - - // Don't pass non-elements to Sizzle - cur.nodeType === 1 && - jQuery.find.matchesSelector( cur, selectors ) ) ) { - - matched.push( cur ); - break; - } - } - } - } - - return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched ); - }, - - // Determine the position of an element within the set - index: function( elem ) { - - // No argument, return index in parent - if ( !elem ) { - return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1; - } - - // Index in selector - if ( typeof elem === "string" ) { - return indexOf.call( jQuery( elem ), this[ 0 ] ); - } - - // Locate the position of the desired element - return indexOf.call( this, - - // If it receives a jQuery object, the first element is used - elem.jquery ? elem[ 0 ] : elem - ); - }, - - add: function( selector, context ) { - return this.pushStack( - jQuery.uniqueSort( - jQuery.merge( this.get(), jQuery( selector, context ) ) - ) - ); - }, - - addBack: function( selector ) { - return this.add( selector == null ? - this.prevObject : this.prevObject.filter( selector ) - ); - } -} ); - -function sibling( cur, dir ) { - while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {} - return cur; -} - -jQuery.each( { - parent: function( elem ) { - var parent = elem.parentNode; - return parent && parent.nodeType !== 11 ? parent : null; - }, - parents: function( elem ) { - return dir( elem, "parentNode" ); - }, - parentsUntil: function( elem, i, until ) { - return dir( elem, "parentNode", until ); - }, - next: function( elem ) { - return sibling( elem, "nextSibling" ); - }, - prev: function( elem ) { - return sibling( elem, "previousSibling" ); - }, - nextAll: function( elem ) { - return dir( elem, "nextSibling" ); - }, - prevAll: function( elem ) { - return dir( elem, "previousSibling" ); - }, - nextUntil: function( elem, i, until ) { - return dir( elem, "nextSibling", until ); - }, - prevUntil: function( elem, i, until ) { - return dir( elem, "previousSibling", until ); - }, - siblings: function( elem ) { - return siblings( ( elem.parentNode || {} ).firstChild, elem ); - }, - children: function( elem ) { - return siblings( elem.firstChild ); - }, - contents: function( elem ) { - if ( typeof elem.contentDocument !== "undefined" ) { - return elem.contentDocument; - } - - // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only - // Treat the template element as a regular one in browsers that - // don't support it. - if ( nodeName( elem, "template" ) ) { - elem = elem.content || elem; - } - - return jQuery.merge( [], elem.childNodes ); - } -}, function( name, fn ) { - jQuery.fn[ name ] = function( until, selector ) { - var matched = jQuery.map( this, fn, until ); - - if ( name.slice( -5 ) !== "Until" ) { - selector = until; - } - - if ( selector && typeof selector === "string" ) { - matched = jQuery.filter( selector, matched ); - } - - if ( this.length > 1 ) { - - // Remove duplicates - if ( !guaranteedUnique[ name ] ) { - jQuery.uniqueSort( matched ); - } - - // Reverse order for parents* and prev-derivatives - if ( rparentsprev.test( name ) ) { - matched.reverse(); - } - } - - return this.pushStack( matched ); - }; -} ); -var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g ); - - - -// Convert String-formatted options into Object-formatted ones -function createOptions( options ) { - var object = {}; - jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) { - object[ flag ] = true; - } ); - return object; -} - -/* - * Create a callback list using the following parameters: - * - * options: an optional list of space-separated options that will change how - * the callback list behaves or a more traditional option object - * - * By default a callback list will act like an event callback list and can be - * "fired" multiple times. - * - * Possible options: - * - * once: will ensure the callback list can only be fired once (like a Deferred) - * - * memory: will keep track of previous values and will call any callback added - * after the list has been fired right away with the latest "memorized" - * values (like a Deferred) - * - * unique: will ensure a callback can only be added once (no duplicate in the list) - * - * stopOnFalse: interrupt callings when a callback returns false - * - */ -jQuery.Callbacks = function( options ) { - - // Convert options from String-formatted to Object-formatted if needed - // (we check in cache first) - options = typeof options === "string" ? - createOptions( options ) : - jQuery.extend( {}, options ); - - var // Flag to know if list is currently firing - firing, - - // Last fire value for non-forgettable lists - memory, - - // Flag to know if list was already fired - fired, - - // Flag to prevent firing - locked, - - // Actual callback list - list = [], - - // Queue of execution data for repeatable lists - queue = [], - - // Index of currently firing callback (modified by add/remove as needed) - firingIndex = -1, - - // Fire callbacks - fire = function() { - - // Enforce single-firing - locked = locked || options.once; - - // Execute callbacks for all pending executions, - // respecting firingIndex overrides and runtime changes - fired = firing = true; - for ( ; queue.length; firingIndex = -1 ) { - memory = queue.shift(); - while ( ++firingIndex < list.length ) { - - // Run callback and check for early termination - if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false && - options.stopOnFalse ) { - - // Jump to end and forget the data so .add doesn't re-fire - firingIndex = list.length; - memory = false; - } - } - } - - // Forget the data if we're done with it - if ( !options.memory ) { - memory = false; - } - - firing = false; - - // Clean up if we're done firing for good - if ( locked ) { - - // Keep an empty list if we have data for future add calls - if ( memory ) { - list = []; - - // Otherwise, this object is spent - } else { - list = ""; - } - } - }, - - // Actual Callbacks object - self = { - - // Add a callback or a collection of callbacks to the list - add: function() { - if ( list ) { - - // If we have memory from a past run, we should fire after adding - if ( memory && !firing ) { - firingIndex = list.length - 1; - queue.push( memory ); - } - - ( function add( args ) { - jQuery.each( args, function( _, arg ) { - if ( isFunction( arg ) ) { - if ( !options.unique || !self.has( arg ) ) { - list.push( arg ); - } - } else if ( arg && arg.length && toType( arg ) !== "string" ) { - - // Inspect recursively - add( arg ); - } - } ); - } )( arguments ); - - if ( memory && !firing ) { - fire(); - } - } - return this; - }, - - // Remove a callback from the list - remove: function() { - jQuery.each( arguments, function( _, arg ) { - var index; - while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { - list.splice( index, 1 ); - - // Handle firing indexes - if ( index <= firingIndex ) { - firingIndex--; - } - } - } ); - return this; - }, - - // Check if a given callback is in the list. - // If no argument is given, return whether or not list has callbacks attached. - has: function( fn ) { - return fn ? - jQuery.inArray( fn, list ) > -1 : - list.length > 0; - }, - - // Remove all callbacks from the list - empty: function() { - if ( list ) { - list = []; - } - return this; - }, - - // Disable .fire and .add - // Abort any current/pending executions - // Clear all callbacks and values - disable: function() { - locked = queue = []; - list = memory = ""; - return this; - }, - disabled: function() { - return !list; - }, - - // Disable .fire - // Also disable .add unless we have memory (since it would have no effect) - // Abort any pending executions - lock: function() { - locked = queue = []; - if ( !memory && !firing ) { - list = memory = ""; - } - return this; - }, - locked: function() { - return !!locked; - }, - - // Call all callbacks with the given context and arguments - fireWith: function( context, args ) { - if ( !locked ) { - args = args || []; - args = [ context, args.slice ? args.slice() : args ]; - queue.push( args ); - if ( !firing ) { - fire(); - } - } - return this; - }, - - // Call all the callbacks with the given arguments - fire: function() { - self.fireWith( this, arguments ); - return this; - }, - - // To know if the callbacks have already been called at least once - fired: function() { - return !!fired; - } - }; - - return self; -}; - - -function Identity( v ) { - return v; -} -function Thrower( ex ) { - throw ex; -} - -function adoptValue( value, resolve, reject, noValue ) { - var method; - - try { - - // Check for promise aspect first to privilege synchronous behavior - if ( value && isFunction( ( method = value.promise ) ) ) { - method.call( value ).done( resolve ).fail( reject ); - - // Other thenables - } else if ( value && isFunction( ( method = value.then ) ) ) { - method.call( value, resolve, reject ); - - // Other non-thenables - } else { - - // Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer: - // * false: [ value ].slice( 0 ) => resolve( value ) - // * true: [ value ].slice( 1 ) => resolve() - resolve.apply( undefined, [ value ].slice( noValue ) ); - } - - // For Promises/A+, convert exceptions into rejections - // Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in - // Deferred#then to conditionally suppress rejection. - } catch ( value ) { - - // Support: Android 4.0 only - // Strict mode functions invoked without .call/.apply get global-object context - reject.apply( undefined, [ value ] ); - } -} - -jQuery.extend( { - - Deferred: function( func ) { - var tuples = [ - - // action, add listener, callbacks, - // ... .then handlers, argument index, [final state] - [ "notify", "progress", jQuery.Callbacks( "memory" ), - jQuery.Callbacks( "memory" ), 2 ], - [ "resolve", "done", jQuery.Callbacks( "once memory" ), - jQuery.Callbacks( "once memory" ), 0, "resolved" ], - [ "reject", "fail", jQuery.Callbacks( "once memory" ), - jQuery.Callbacks( "once memory" ), 1, "rejected" ] - ], - state = "pending", - promise = { - state: function() { - return state; - }, - always: function() { - deferred.done( arguments ).fail( arguments ); - return this; - }, - "catch": function( fn ) { - return promise.then( null, fn ); - }, - - // Keep pipe for back-compat - pipe: function( /* fnDone, fnFail, fnProgress */ ) { - var fns = arguments; - - return jQuery.Deferred( function( newDefer ) { - jQuery.each( tuples, function( i, tuple ) { - - // Map tuples (progress, done, fail) to arguments (done, fail, progress) - var fn = isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ]; - - // deferred.progress(function() { bind to newDefer or newDefer.notify }) - // deferred.done(function() { bind to newDefer or newDefer.resolve }) - // deferred.fail(function() { bind to newDefer or newDefer.reject }) - deferred[ tuple[ 1 ] ]( function() { - var returned = fn && fn.apply( this, arguments ); - if ( returned && isFunction( returned.promise ) ) { - returned.promise() - .progress( newDefer.notify ) - .done( newDefer.resolve ) - .fail( newDefer.reject ); - } else { - newDefer[ tuple[ 0 ] + "With" ]( - this, - fn ? [ returned ] : arguments - ); - } - } ); - } ); - fns = null; - } ).promise(); - }, - then: function( onFulfilled, onRejected, onProgress ) { - var maxDepth = 0; - function resolve( depth, deferred, handler, special ) { - return function() { - var that = this, - args = arguments, - mightThrow = function() { - var returned, then; - - // Support: Promises/A+ section 2.3.3.3.3 - // https://promisesaplus.com/#point-59 - // Ignore double-resolution attempts - if ( depth < maxDepth ) { - return; - } - - returned = handler.apply( that, args ); - - // Support: Promises/A+ section 2.3.1 - // https://promisesaplus.com/#point-48 - if ( returned === deferred.promise() ) { - throw new TypeError( "Thenable self-resolution" ); - } - - // Support: Promises/A+ sections 2.3.3.1, 3.5 - // https://promisesaplus.com/#point-54 - // https://promisesaplus.com/#point-75 - // Retrieve `then` only once - then = returned && - - // Support: Promises/A+ section 2.3.4 - // https://promisesaplus.com/#point-64 - // Only check objects and functions for thenability - ( typeof returned === "object" || - typeof returned === "function" ) && - returned.then; - - // Handle a returned thenable - if ( isFunction( then ) ) { - - // Special processors (notify) just wait for resolution - if ( special ) { - then.call( - returned, - resolve( maxDepth, deferred, Identity, special ), - resolve( maxDepth, deferred, Thrower, special ) - ); - - // Normal processors (resolve) also hook into progress - } else { - - // ...and disregard older resolution values - maxDepth++; - - then.call( - returned, - resolve( maxDepth, deferred, Identity, special ), - resolve( maxDepth, deferred, Thrower, special ), - resolve( maxDepth, deferred, Identity, - deferred.notifyWith ) - ); - } - - // Handle all other returned values - } else { - - // Only substitute handlers pass on context - // and multiple values (non-spec behavior) - if ( handler !== Identity ) { - that = undefined; - args = [ returned ]; - } - - // Process the value(s) - // Default process is resolve - ( special || deferred.resolveWith )( that, args ); - } - }, - - // Only normal processors (resolve) catch and reject exceptions - process = special ? - mightThrow : - function() { - try { - mightThrow(); - } catch ( e ) { - - if ( jQuery.Deferred.exceptionHook ) { - jQuery.Deferred.exceptionHook( e, - process.stackTrace ); - } - - // Support: Promises/A+ section 2.3.3.3.4.1 - // https://promisesaplus.com/#point-61 - // Ignore post-resolution exceptions - if ( depth + 1 >= maxDepth ) { - - // Only substitute handlers pass on context - // and multiple values (non-spec behavior) - if ( handler !== Thrower ) { - that = undefined; - args = [ e ]; - } - - deferred.rejectWith( that, args ); - } - } - }; - - // Support: Promises/A+ section 2.3.3.3.1 - // https://promisesaplus.com/#point-57 - // Re-resolve promises immediately to dodge false rejection from - // subsequent errors - if ( depth ) { - process(); - } else { - - // Call an optional hook to record the stack, in case of exception - // since it's otherwise lost when execution goes async - if ( jQuery.Deferred.getStackHook ) { - process.stackTrace = jQuery.Deferred.getStackHook(); - } - window.setTimeout( process ); - } - }; - } - - return jQuery.Deferred( function( newDefer ) { - - // progress_handlers.add( ... ) - tuples[ 0 ][ 3 ].add( - resolve( - 0, - newDefer, - isFunction( onProgress ) ? - onProgress : - Identity, - newDefer.notifyWith - ) - ); - - // fulfilled_handlers.add( ... ) - tuples[ 1 ][ 3 ].add( - resolve( - 0, - newDefer, - isFunction( onFulfilled ) ? - onFulfilled : - Identity - ) - ); - - // rejected_handlers.add( ... ) - tuples[ 2 ][ 3 ].add( - resolve( - 0, - newDefer, - isFunction( onRejected ) ? - onRejected : - Thrower - ) - ); - } ).promise(); - }, - - // Get a promise for this deferred - // If obj is provided, the promise aspect is added to the object - promise: function( obj ) { - return obj != null ? jQuery.extend( obj, promise ) : promise; - } - }, - deferred = {}; - - // Add list-specific methods - jQuery.each( tuples, function( i, tuple ) { - var list = tuple[ 2 ], - stateString = tuple[ 5 ]; - - // promise.progress = list.add - // promise.done = list.add - // promise.fail = list.add - promise[ tuple[ 1 ] ] = list.add; - - // Handle state - if ( stateString ) { - list.add( - function() { - - // state = "resolved" (i.e., fulfilled) - // state = "rejected" - state = stateString; - }, - - // rejected_callbacks.disable - // fulfilled_callbacks.disable - tuples[ 3 - i ][ 2 ].disable, - - // rejected_handlers.disable - // fulfilled_handlers.disable - tuples[ 3 - i ][ 3 ].disable, - - // progress_callbacks.lock - tuples[ 0 ][ 2 ].lock, - - // progress_handlers.lock - tuples[ 0 ][ 3 ].lock - ); - } - - // progress_handlers.fire - // fulfilled_handlers.fire - // rejected_handlers.fire - list.add( tuple[ 3 ].fire ); - - // deferred.notify = function() { deferred.notifyWith(...) } - // deferred.resolve = function() { deferred.resolveWith(...) } - // deferred.reject = function() { deferred.rejectWith(...) } - deferred[ tuple[ 0 ] ] = function() { - deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments ); - return this; - }; - - // deferred.notifyWith = list.fireWith - // deferred.resolveWith = list.fireWith - // deferred.rejectWith = list.fireWith - deferred[ tuple[ 0 ] + "With" ] = list.fireWith; - } ); - - // Make the deferred a promise - promise.promise( deferred ); - - // Call given func if any - if ( func ) { - func.call( deferred, deferred ); - } - - // All done! - return deferred; - }, - - // Deferred helper - when: function( singleValue ) { - var - - // count of uncompleted subordinates - remaining = arguments.length, - - // count of unprocessed arguments - i = remaining, - - // subordinate fulfillment data - resolveContexts = Array( i ), - resolveValues = slice.call( arguments ), - - // the master Deferred - master = jQuery.Deferred(), - - // subordinate callback factory - updateFunc = function( i ) { - return function( value ) { - resolveContexts[ i ] = this; - resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; - if ( !( --remaining ) ) { - master.resolveWith( resolveContexts, resolveValues ); - } - }; - }; - - // Single- and empty arguments are adopted like Promise.resolve - if ( remaining <= 1 ) { - adoptValue( singleValue, master.done( updateFunc( i ) ).resolve, master.reject, - !remaining ); - - // Use .then() to unwrap secondary thenables (cf. gh-3000) - if ( master.state() === "pending" || - isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) { - - return master.then(); - } - } - - // Multiple arguments are aggregated like Promise.all array elements - while ( i-- ) { - adoptValue( resolveValues[ i ], updateFunc( i ), master.reject ); - } - - return master.promise(); - } -} ); - - -// These usually indicate a programmer mistake during development, -// warn about them ASAP rather than swallowing them by default. -var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/; - -jQuery.Deferred.exceptionHook = function( error, stack ) { - - // Support: IE 8 - 9 only - // Console exists when dev tools are open, which can happen at any time - if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) { - window.console.warn( "jQuery.Deferred exception: " + error.message, error.stack, stack ); - } -}; - - - - -jQuery.readyException = function( error ) { - window.setTimeout( function() { - throw error; - } ); -}; - - - - -// The deferred used on DOM ready -var readyList = jQuery.Deferred(); - -jQuery.fn.ready = function( fn ) { - - readyList - .then( fn ) - - // Wrap jQuery.readyException in a function so that the lookup - // happens at the time of error handling instead of callback - // registration. - .catch( function( error ) { - jQuery.readyException( error ); - } ); - - return this; -}; - -jQuery.extend( { - - // Is the DOM ready to be used? Set to true once it occurs. - isReady: false, - - // A counter to track how many items to wait for before - // the ready event fires. See #6781 - readyWait: 1, - - // Handle when the DOM is ready - ready: function( wait ) { - - // Abort if there are pending holds or we're already ready - if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { - return; - } - - // Remember that the DOM is ready - jQuery.isReady = true; - - // If a normal DOM Ready event fired, decrement, and wait if need be - if ( wait !== true && --jQuery.readyWait > 0 ) { - return; - } - - // If there are functions bound, to execute - readyList.resolveWith( document, [ jQuery ] ); - } -} ); - -jQuery.ready.then = readyList.then; - -// The ready event handler and self cleanup method -function completed() { - document.removeEventListener( "DOMContentLoaded", completed ); - window.removeEventListener( "load", completed ); - jQuery.ready(); -} - -// Catch cases where $(document).ready() is called -// after the browser event has already occurred. -// Support: IE <=9 - 10 only -// Older IE sometimes signals "interactive" too soon -if ( document.readyState === "complete" || - ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) { - - // Handle it asynchronously to allow scripts the opportunity to delay ready - window.setTimeout( jQuery.ready ); - -} else { - - // Use the handy event callback - document.addEventListener( "DOMContentLoaded", completed ); - - // A fallback to window.onload, that will always work - window.addEventListener( "load", completed ); -} - - - - -// Multifunctional method to get and set values of a collection -// The value/s can optionally be executed if it's a function -var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { - var i = 0, - len = elems.length, - bulk = key == null; - - // Sets many values - if ( toType( key ) === "object" ) { - chainable = true; - for ( i in key ) { - access( elems, fn, i, key[ i ], true, emptyGet, raw ); - } - - // Sets one value - } else if ( value !== undefined ) { - chainable = true; - - if ( !isFunction( value ) ) { - raw = true; - } - - if ( bulk ) { - - // Bulk operations run against the entire set - if ( raw ) { - fn.call( elems, value ); - fn = null; - - // ...except when executing function values - } else { - bulk = fn; - fn = function( elem, key, value ) { - return bulk.call( jQuery( elem ), value ); - }; - } - } - - if ( fn ) { - for ( ; i < len; i++ ) { - fn( - elems[ i ], key, raw ? - value : - value.call( elems[ i ], i, fn( elems[ i ], key ) ) - ); - } - } - } - - if ( chainable ) { - return elems; - } - - // Gets - if ( bulk ) { - return fn.call( elems ); - } - - return len ? fn( elems[ 0 ], key ) : emptyGet; -}; - - -// Matches dashed string for camelizing -var rmsPrefix = /^-ms-/, - rdashAlpha = /-([a-z])/g; - -// Used by camelCase as callback to replace() -function fcamelCase( all, letter ) { - return letter.toUpperCase(); -} - -// Convert dashed to camelCase; used by the css and data modules -// Support: IE <=9 - 11, Edge 12 - 15 -// Microsoft forgot to hump their vendor prefix (#9572) -function camelCase( string ) { - return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); -} -var acceptData = function( owner ) { - - // Accepts only: - // - Node - // - Node.ELEMENT_NODE - // - Node.DOCUMENT_NODE - // - Object - // - Any - return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType ); -}; - - - - -function Data() { - this.expando = jQuery.expando + Data.uid++; -} - -Data.uid = 1; - -Data.prototype = { - - cache: function( owner ) { - - // Check if the owner object already has a cache - var value = owner[ this.expando ]; - - // If not, create one - if ( !value ) { - value = {}; - - // We can accept data for non-element nodes in modern browsers, - // but we should not, see #8335. - // Always return an empty object. - if ( acceptData( owner ) ) { - - // If it is a node unlikely to be stringify-ed or looped over - // use plain assignment - if ( owner.nodeType ) { - owner[ this.expando ] = value; - - // Otherwise secure it in a non-enumerable property - // configurable must be true to allow the property to be - // deleted when data is removed - } else { - Object.defineProperty( owner, this.expando, { - value: value, - configurable: true - } ); - } - } - } - - return value; - }, - set: function( owner, data, value ) { - var prop, - cache = this.cache( owner ); - - // Handle: [ owner, key, value ] args - // Always use camelCase key (gh-2257) - if ( typeof data === "string" ) { - cache[ camelCase( data ) ] = value; - - // Handle: [ owner, { properties } ] args - } else { - - // Copy the properties one-by-one to the cache object - for ( prop in data ) { - cache[ camelCase( prop ) ] = data[ prop ]; - } - } - return cache; - }, - get: function( owner, key ) { - return key === undefined ? - this.cache( owner ) : - - // Always use camelCase key (gh-2257) - owner[ this.expando ] && owner[ this.expando ][ camelCase( key ) ]; - }, - access: function( owner, key, value ) { - - // In cases where either: - // - // 1. No key was specified - // 2. A string key was specified, but no value provided - // - // Take the "read" path and allow the get method to determine - // which value to return, respectively either: - // - // 1. The entire cache object - // 2. The data stored at the key - // - if ( key === undefined || - ( ( key && typeof key === "string" ) && value === undefined ) ) { - - return this.get( owner, key ); - } - - // When the key is not a string, or both a key and value - // are specified, set or extend (existing objects) with either: - // - // 1. An object of properties - // 2. A key and value - // - this.set( owner, key, value ); - - // Since the "set" path can have two possible entry points - // return the expected data based on which path was taken[*] - return value !== undefined ? value : key; - }, - remove: function( owner, key ) { - var i, - cache = owner[ this.expando ]; - - if ( cache === undefined ) { - return; - } - - if ( key !== undefined ) { - - // Support array or space separated string of keys - if ( Array.isArray( key ) ) { - - // If key is an array of keys... - // We always set camelCase keys, so remove that. - key = key.map( camelCase ); - } else { - key = camelCase( key ); - - // If a key with the spaces exists, use it. - // Otherwise, create an array by matching non-whitespace - key = key in cache ? - [ key ] : - ( key.match( rnothtmlwhite ) || [] ); - } - - i = key.length; - - while ( i-- ) { - delete cache[ key[ i ] ]; - } - } - - // Remove the expando if there's no more data - if ( key === undefined || jQuery.isEmptyObject( cache ) ) { - - // Support: Chrome <=35 - 45 - // Webkit & Blink performance suffers when deleting properties - // from DOM nodes, so set to undefined instead - // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted) - if ( owner.nodeType ) { - owner[ this.expando ] = undefined; - } else { - delete owner[ this.expando ]; - } - } - }, - hasData: function( owner ) { - var cache = owner[ this.expando ]; - return cache !== undefined && !jQuery.isEmptyObject( cache ); - } -}; -var dataPriv = new Data(); - -var dataUser = new Data(); - - - -// Implementation Summary -// -// 1. Enforce API surface and semantic compatibility with 1.9.x branch -// 2. Improve the module's maintainability by reducing the storage -// paths to a single mechanism. -// 3. Use the same single mechanism to support "private" and "user" data. -// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData) -// 5. Avoid exposing implementation details on user objects (eg. expando properties) -// 6. Provide a clear path for implementation upgrade to WeakMap in 2014 - -var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, - rmultiDash = /[A-Z]/g; - -function getData( data ) { - if ( data === "true" ) { - return true; - } - - if ( data === "false" ) { - return false; - } - - if ( data === "null" ) { - return null; - } - - // Only convert to a number if it doesn't change the string - if ( data === +data + "" ) { - return +data; - } - - if ( rbrace.test( data ) ) { - return JSON.parse( data ); - } - - return data; -} - -function dataAttr( elem, key, data ) { - var name; - - // If nothing was found internally, try to fetch any - // data from the HTML5 data-* attribute - if ( data === undefined && elem.nodeType === 1 ) { - name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase(); - data = elem.getAttribute( name ); - - if ( typeof data === "string" ) { - try { - data = getData( data ); - } catch ( e ) {} - - // Make sure we set the data so it isn't changed later - dataUser.set( elem, key, data ); - } else { - data = undefined; - } - } - return data; -} - -jQuery.extend( { - hasData: function( elem ) { - return dataUser.hasData( elem ) || dataPriv.hasData( elem ); - }, - - data: function( elem, name, data ) { - return dataUser.access( elem, name, data ); - }, - - removeData: function( elem, name ) { - dataUser.remove( elem, name ); - }, - - // TODO: Now that all calls to _data and _removeData have been replaced - // with direct calls to dataPriv methods, these can be deprecated. - _data: function( elem, name, data ) { - return dataPriv.access( elem, name, data ); - }, - - _removeData: function( elem, name ) { - dataPriv.remove( elem, name ); - } -} ); - -jQuery.fn.extend( { - data: function( key, value ) { - var i, name, data, - elem = this[ 0 ], - attrs = elem && elem.attributes; - - // Gets all values - if ( key === undefined ) { - if ( this.length ) { - data = dataUser.get( elem ); - - if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) { - i = attrs.length; - while ( i-- ) { - - // Support: IE 11 only - // The attrs elements can be null (#14894) - if ( attrs[ i ] ) { - name = attrs[ i ].name; - if ( name.indexOf( "data-" ) === 0 ) { - name = camelCase( name.slice( 5 ) ); - dataAttr( elem, name, data[ name ] ); - } - } - } - dataPriv.set( elem, "hasDataAttrs", true ); - } - } - - return data; - } - - // Sets multiple values - if ( typeof key === "object" ) { - return this.each( function() { - dataUser.set( this, key ); - } ); - } - - return access( this, function( value ) { - var data; - - // The calling jQuery object (element matches) is not empty - // (and therefore has an element appears at this[ 0 ]) and the - // `value` parameter was not undefined. An empty jQuery object - // will result in `undefined` for elem = this[ 0 ] which will - // throw an exception if an attempt to read a data cache is made. - if ( elem && value === undefined ) { - - // Attempt to get data from the cache - // The key will always be camelCased in Data - data = dataUser.get( elem, key ); - if ( data !== undefined ) { - return data; - } - - // Attempt to "discover" the data in - // HTML5 custom data-* attrs - data = dataAttr( elem, key ); - if ( data !== undefined ) { - return data; - } - - // We tried really hard, but the data doesn't exist. - return; - } - - // Set the data... - this.each( function() { - - // We always store the camelCased key - dataUser.set( this, key, value ); - } ); - }, null, value, arguments.length > 1, null, true ); - }, - - removeData: function( key ) { - return this.each( function() { - dataUser.remove( this, key ); - } ); - } -} ); - - -jQuery.extend( { - queue: function( elem, type, data ) { - var queue; - - if ( elem ) { - type = ( type || "fx" ) + "queue"; - queue = dataPriv.get( elem, type ); - - // Speed up dequeue by getting out quickly if this is just a lookup - if ( data ) { - if ( !queue || Array.isArray( data ) ) { - queue = dataPriv.access( elem, type, jQuery.makeArray( data ) ); - } else { - queue.push( data ); - } - } - return queue || []; - } - }, - - dequeue: function( elem, type ) { - type = type || "fx"; - - var queue = jQuery.queue( elem, type ), - startLength = queue.length, - fn = queue.shift(), - hooks = jQuery._queueHooks( elem, type ), - next = function() { - jQuery.dequeue( elem, type ); - }; - - // If the fx queue is dequeued, always remove the progress sentinel - if ( fn === "inprogress" ) { - fn = queue.shift(); - startLength--; - } - - if ( fn ) { - - // Add a progress sentinel to prevent the fx queue from being - // automatically dequeued - if ( type === "fx" ) { - queue.unshift( "inprogress" ); - } - - // Clear up the last queue stop function - delete hooks.stop; - fn.call( elem, next, hooks ); - } - - if ( !startLength && hooks ) { - hooks.empty.fire(); - } - }, - - // Not public - generate a queueHooks object, or return the current one - _queueHooks: function( elem, type ) { - var key = type + "queueHooks"; - return dataPriv.get( elem, key ) || dataPriv.access( elem, key, { - empty: jQuery.Callbacks( "once memory" ).add( function() { - dataPriv.remove( elem, [ type + "queue", key ] ); - } ) - } ); - } -} ); - -jQuery.fn.extend( { - queue: function( type, data ) { - var setter = 2; - - if ( typeof type !== "string" ) { - data = type; - type = "fx"; - setter--; - } - - if ( arguments.length < setter ) { - return jQuery.queue( this[ 0 ], type ); - } - - return data === undefined ? - this : - this.each( function() { - var queue = jQuery.queue( this, type, data ); - - // Ensure a hooks for this queue - jQuery._queueHooks( this, type ); - - if ( type === "fx" && queue[ 0 ] !== "inprogress" ) { - jQuery.dequeue( this, type ); - } - } ); - }, - dequeue: function( type ) { - return this.each( function() { - jQuery.dequeue( this, type ); - } ); - }, - clearQueue: function( type ) { - return this.queue( type || "fx", [] ); - }, - - // Get a promise resolved when queues of a certain type - // are emptied (fx is the type by default) - promise: function( type, obj ) { - var tmp, - count = 1, - defer = jQuery.Deferred(), - elements = this, - i = this.length, - resolve = function() { - if ( !( --count ) ) { - defer.resolveWith( elements, [ elements ] ); - } - }; - - if ( typeof type !== "string" ) { - obj = type; - type = undefined; - } - type = type || "fx"; - - while ( i-- ) { - tmp = dataPriv.get( elements[ i ], type + "queueHooks" ); - if ( tmp && tmp.empty ) { - count++; - tmp.empty.add( resolve ); - } - } - resolve(); - return defer.promise( obj ); - } -} ); -var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source; - -var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ); - - -var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; - -var documentElement = document.documentElement; - - - - var isAttached = function( elem ) { - return jQuery.contains( elem.ownerDocument, elem ); - }, - composed = { composed: true }; - - // Support: IE 9 - 11+, Edge 12 - 18+, iOS 10.0 - 10.2 only - // Check attachment across shadow DOM boundaries when possible (gh-3504) - // Support: iOS 10.0-10.2 only - // Early iOS 10 versions support `attachShadow` but not `getRootNode`, - // leading to errors. We need to check for `getRootNode`. - if ( documentElement.getRootNode ) { - isAttached = function( elem ) { - return jQuery.contains( elem.ownerDocument, elem ) || - elem.getRootNode( composed ) === elem.ownerDocument; - }; - } -var isHiddenWithinTree = function( elem, el ) { - - // isHiddenWithinTree might be called from jQuery#filter function; - // in that case, element will be second argument - elem = el || elem; - - // Inline style trumps all - return elem.style.display === "none" || - elem.style.display === "" && - - // Otherwise, check computed style - // Support: Firefox <=43 - 45 - // Disconnected elements can have computed display: none, so first confirm that elem is - // in the document. - isAttached( elem ) && - - jQuery.css( elem, "display" ) === "none"; - }; - -var swap = function( elem, options, callback, args ) { - var ret, name, - old = {}; - - // Remember the old values, and insert the new ones - for ( name in options ) { - old[ name ] = elem.style[ name ]; - elem.style[ name ] = options[ name ]; - } - - ret = callback.apply( elem, args || [] ); - - // Revert the old values - for ( name in options ) { - elem.style[ name ] = old[ name ]; - } - - return ret; -}; - - - - -function adjustCSS( elem, prop, valueParts, tween ) { - var adjusted, scale, - maxIterations = 20, - currentValue = tween ? - function() { - return tween.cur(); - } : - function() { - return jQuery.css( elem, prop, "" ); - }, - initial = currentValue(), - unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ), - - // Starting value computation is required for potential unit mismatches - initialInUnit = elem.nodeType && - ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && - rcssNum.exec( jQuery.css( elem, prop ) ); - - if ( initialInUnit && initialInUnit[ 3 ] !== unit ) { - - // Support: Firefox <=54 - // Halve the iteration target value to prevent interference from CSS upper bounds (gh-2144) - initial = initial / 2; - - // Trust units reported by jQuery.css - unit = unit || initialInUnit[ 3 ]; - - // Iteratively approximate from a nonzero starting point - initialInUnit = +initial || 1; - - while ( maxIterations-- ) { - - // Evaluate and update our best guess (doubling guesses that zero out). - // Finish if the scale equals or crosses 1 (making the old*new product non-positive). - jQuery.style( elem, prop, initialInUnit + unit ); - if ( ( 1 - scale ) * ( 1 - ( scale = currentValue() / initial || 0.5 ) ) <= 0 ) { - maxIterations = 0; - } - initialInUnit = initialInUnit / scale; - - } - - initialInUnit = initialInUnit * 2; - jQuery.style( elem, prop, initialInUnit + unit ); - - // Make sure we update the tween properties later on - valueParts = valueParts || []; - } - - if ( valueParts ) { - initialInUnit = +initialInUnit || +initial || 0; - - // Apply relative offset (+=/-=) if specified - adjusted = valueParts[ 1 ] ? - initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] : - +valueParts[ 2 ]; - if ( tween ) { - tween.unit = unit; - tween.start = initialInUnit; - tween.end = adjusted; - } - } - return adjusted; -} - - -var defaultDisplayMap = {}; - -function getDefaultDisplay( elem ) { - var temp, - doc = elem.ownerDocument, - nodeName = elem.nodeName, - display = defaultDisplayMap[ nodeName ]; - - if ( display ) { - return display; - } - - temp = doc.body.appendChild( doc.createElement( nodeName ) ); - display = jQuery.css( temp, "display" ); - - temp.parentNode.removeChild( temp ); - - if ( display === "none" ) { - display = "block"; - } - defaultDisplayMap[ nodeName ] = display; - - return display; -} - -function showHide( elements, show ) { - var display, elem, - values = [], - index = 0, - length = elements.length; - - // Determine new display value for elements that need to change - for ( ; index < length; index++ ) { - elem = elements[ index ]; - if ( !elem.style ) { - continue; - } - - display = elem.style.display; - if ( show ) { - - // Since we force visibility upon cascade-hidden elements, an immediate (and slow) - // check is required in this first loop unless we have a nonempty display value (either - // inline or about-to-be-restored) - if ( display === "none" ) { - values[ index ] = dataPriv.get( elem, "display" ) || null; - if ( !values[ index ] ) { - elem.style.display = ""; - } - } - if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) { - values[ index ] = getDefaultDisplay( elem ); - } - } else { - if ( display !== "none" ) { - values[ index ] = "none"; - - // Remember what we're overwriting - dataPriv.set( elem, "display", display ); - } - } - } - - // Set the display of the elements in a second loop to avoid constant reflow - for ( index = 0; index < length; index++ ) { - if ( values[ index ] != null ) { - elements[ index ].style.display = values[ index ]; - } - } - - return elements; -} - -jQuery.fn.extend( { - show: function() { - return showHide( this, true ); - }, - hide: function() { - return showHide( this ); - }, - toggle: function( state ) { - if ( typeof state === "boolean" ) { - return state ? this.show() : this.hide(); - } - - return this.each( function() { - if ( isHiddenWithinTree( this ) ) { - jQuery( this ).show(); - } else { - jQuery( this ).hide(); - } - } ); - } -} ); -var rcheckableType = ( /^(?:checkbox|radio)$/i ); - -var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]*)/i ); - -var rscriptType = ( /^$|^module$|\/(?:java|ecma)script/i ); - - - -// We have to close these tags to support XHTML (#13200) -var wrapMap = { - - // Support: IE <=9 only - option: [ 1, "" ], - - // XHTML parsers do not magically insert elements in the - // same way that tag soup parsers do. So we cannot shorten - // this by omitting or other required elements. - thead: [ 1, "", "
" ], - col: [ 2, "", "
" ], - tr: [ 2, "", "
" ], - td: [ 3, "", "
" ], - - _default: [ 0, "", "" ] -}; - -// Support: IE <=9 only -wrapMap.optgroup = wrapMap.option; - -wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; -wrapMap.th = wrapMap.td; - - -function getAll( context, tag ) { - - // Support: IE <=9 - 11 only - // Use typeof to avoid zero-argument method invocation on host objects (#15151) - var ret; - - if ( typeof context.getElementsByTagName !== "undefined" ) { - ret = context.getElementsByTagName( tag || "*" ); - - } else if ( typeof context.querySelectorAll !== "undefined" ) { - ret = context.querySelectorAll( tag || "*" ); - - } else { - ret = []; - } - - if ( tag === undefined || tag && nodeName( context, tag ) ) { - return jQuery.merge( [ context ], ret ); - } - - return ret; -} - - -// Mark scripts as having already been evaluated -function setGlobalEval( elems, refElements ) { - var i = 0, - l = elems.length; - - for ( ; i < l; i++ ) { - dataPriv.set( - elems[ i ], - "globalEval", - !refElements || dataPriv.get( refElements[ i ], "globalEval" ) - ); - } -} - - -var rhtml = /<|&#?\w+;/; - -function buildFragment( elems, context, scripts, selection, ignored ) { - var elem, tmp, tag, wrap, attached, j, - fragment = context.createDocumentFragment(), - nodes = [], - i = 0, - l = elems.length; - - for ( ; i < l; i++ ) { - elem = elems[ i ]; - - if ( elem || elem === 0 ) { - - // Add nodes directly - if ( toType( elem ) === "object" ) { - - // Support: Android <=4.0 only, PhantomJS 1 only - // push.apply(_, arraylike) throws on ancient WebKit - jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); - - // Convert non-html into a text node - } else if ( !rhtml.test( elem ) ) { - nodes.push( context.createTextNode( elem ) ); - - // Convert html into DOM nodes - } else { - tmp = tmp || fragment.appendChild( context.createElement( "div" ) ); - - // Deserialize a standard representation - tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase(); - wrap = wrapMap[ tag ] || wrapMap._default; - tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ]; - - // Descend through wrappers to the right content - j = wrap[ 0 ]; - while ( j-- ) { - tmp = tmp.lastChild; - } - - // Support: Android <=4.0 only, PhantomJS 1 only - // push.apply(_, arraylike) throws on ancient WebKit - jQuery.merge( nodes, tmp.childNodes ); - - // Remember the top-level container - tmp = fragment.firstChild; - - // Ensure the created nodes are orphaned (#12392) - tmp.textContent = ""; - } - } - } - - // Remove wrapper from fragment - fragment.textContent = ""; - - i = 0; - while ( ( elem = nodes[ i++ ] ) ) { - - // Skip elements already in the context collection (trac-4087) - if ( selection && jQuery.inArray( elem, selection ) > -1 ) { - if ( ignored ) { - ignored.push( elem ); - } - continue; - } - - attached = isAttached( elem ); - - // Append to fragment - tmp = getAll( fragment.appendChild( elem ), "script" ); - - // Preserve script evaluation history - if ( attached ) { - setGlobalEval( tmp ); - } - - // Capture executables - if ( scripts ) { - j = 0; - while ( ( elem = tmp[ j++ ] ) ) { - if ( rscriptType.test( elem.type || "" ) ) { - scripts.push( elem ); - } - } - } - } - - return fragment; -} - - -( function() { - var fragment = document.createDocumentFragment(), - div = fragment.appendChild( document.createElement( "div" ) ), - input = document.createElement( "input" ); - - // Support: Android 4.0 - 4.3 only - // Check state lost if the name is set (#11217) - // Support: Windows Web Apps (WWA) - // `name` and `type` must use .setAttribute for WWA (#14901) - input.setAttribute( "type", "radio" ); - input.setAttribute( "checked", "checked" ); - input.setAttribute( "name", "t" ); - - div.appendChild( input ); - - // Support: Android <=4.1 only - // Older WebKit doesn't clone checked state correctly in fragments - support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; - - // Support: IE <=11 only - // Make sure textarea (and checkbox) defaultValue is properly cloned - div.innerHTML = ""; - support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; -} )(); - - -var - rkeyEvent = /^key/, - rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/, - rtypenamespace = /^([^.]*)(?:\.(.+)|)/; - -function returnTrue() { - return true; -} - -function returnFalse() { - return false; -} - -// Support: IE <=9 - 11+ -// focus() and blur() are asynchronous, except when they are no-op. -// So expect focus to be synchronous when the element is already active, -// and blur to be synchronous when the element is not already active. -// (focus and blur are always synchronous in other supported browsers, -// this just defines when we can count on it). -function expectSync( elem, type ) { - return ( elem === safeActiveElement() ) === ( type === "focus" ); -} - -// Support: IE <=9 only -// Accessing document.activeElement can throw unexpectedly -// https://bugs.jquery.com/ticket/13393 -function safeActiveElement() { - try { - return document.activeElement; - } catch ( err ) { } -} - -function on( elem, types, selector, data, fn, one ) { - var origFn, type; - - // Types can be a map of types/handlers - if ( typeof types === "object" ) { - - // ( types-Object, selector, data ) - if ( typeof selector !== "string" ) { - - // ( types-Object, data ) - data = data || selector; - selector = undefined; - } - for ( type in types ) { - on( elem, type, selector, data, types[ type ], one ); - } - return elem; - } - - if ( data == null && fn == null ) { - - // ( types, fn ) - fn = selector; - data = selector = undefined; - } else if ( fn == null ) { - if ( typeof selector === "string" ) { - - // ( types, selector, fn ) - fn = data; - data = undefined; - } else { - - // ( types, data, fn ) - fn = data; - data = selector; - selector = undefined; - } - } - if ( fn === false ) { - fn = returnFalse; - } else if ( !fn ) { - return elem; - } - - if ( one === 1 ) { - origFn = fn; - fn = function( event ) { - - // Can use an empty set, since event contains the info - jQuery().off( event ); - return origFn.apply( this, arguments ); - }; - - // Use same guid so caller can remove using origFn - fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); - } - return elem.each( function() { - jQuery.event.add( this, types, fn, data, selector ); - } ); -} - -/* - * Helper functions for managing events -- not part of the public interface. - * Props to Dean Edwards' addEvent library for many of the ideas. - */ -jQuery.event = { - - global: {}, - - add: function( elem, types, handler, data, selector ) { - - var handleObjIn, eventHandle, tmp, - events, t, handleObj, - special, handlers, type, namespaces, origType, - elemData = dataPriv.get( elem ); - - // Don't attach events to noData or text/comment nodes (but allow plain objects) - if ( !elemData ) { - return; - } - - // Caller can pass in an object of custom data in lieu of the handler - if ( handler.handler ) { - handleObjIn = handler; - handler = handleObjIn.handler; - selector = handleObjIn.selector; - } - - // Ensure that invalid selectors throw exceptions at attach time - // Evaluate against documentElement in case elem is a non-element node (e.g., document) - if ( selector ) { - jQuery.find.matchesSelector( documentElement, selector ); - } - - // Make sure that the handler has a unique ID, used to find/remove it later - if ( !handler.guid ) { - handler.guid = jQuery.guid++; - } - - // Init the element's event structure and main handler, if this is the first - if ( !( events = elemData.events ) ) { - events = elemData.events = {}; - } - if ( !( eventHandle = elemData.handle ) ) { - eventHandle = elemData.handle = function( e ) { - - // Discard the second event of a jQuery.event.trigger() and - // when an event is called after a page has unloaded - return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ? - jQuery.event.dispatch.apply( elem, arguments ) : undefined; - }; - } - - // Handle multiple events separated by a space - types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; - t = types.length; - while ( t-- ) { - tmp = rtypenamespace.exec( types[ t ] ) || []; - type = origType = tmp[ 1 ]; - namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); - - // There *must* be a type, no attaching namespace-only handlers - if ( !type ) { - continue; - } - - // If event changes its type, use the special event handlers for the changed type - special = jQuery.event.special[ type ] || {}; - - // If selector defined, determine special event api type, otherwise given type - type = ( selector ? special.delegateType : special.bindType ) || type; - - // Update special based on newly reset type - special = jQuery.event.special[ type ] || {}; - - // handleObj is passed to all event handlers - handleObj = jQuery.extend( { - type: type, - origType: origType, - data: data, - handler: handler, - guid: handler.guid, - selector: selector, - needsContext: selector && jQuery.expr.match.needsContext.test( selector ), - namespace: namespaces.join( "." ) - }, handleObjIn ); - - // Init the event handler queue if we're the first - if ( !( handlers = events[ type ] ) ) { - handlers = events[ type ] = []; - handlers.delegateCount = 0; - - // Only use addEventListener if the special events handler returns false - if ( !special.setup || - special.setup.call( elem, data, namespaces, eventHandle ) === false ) { - - if ( elem.addEventListener ) { - elem.addEventListener( type, eventHandle ); - } - } - } - - if ( special.add ) { - special.add.call( elem, handleObj ); - - if ( !handleObj.handler.guid ) { - handleObj.handler.guid = handler.guid; - } - } - - // Add to the element's handler list, delegates in front - if ( selector ) { - handlers.splice( handlers.delegateCount++, 0, handleObj ); - } else { - handlers.push( handleObj ); - } - - // Keep track of which events have ever been used, for event optimization - jQuery.event.global[ type ] = true; - } - - }, - - // Detach an event or set of events from an element - remove: function( elem, types, handler, selector, mappedTypes ) { - - var j, origCount, tmp, - events, t, handleObj, - special, handlers, type, namespaces, origType, - elemData = dataPriv.hasData( elem ) && dataPriv.get( elem ); - - if ( !elemData || !( events = elemData.events ) ) { - return; - } - - // Once for each type.namespace in types; type may be omitted - types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; - t = types.length; - while ( t-- ) { - tmp = rtypenamespace.exec( types[ t ] ) || []; - type = origType = tmp[ 1 ]; - namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); - - // Unbind all events (on this namespace, if provided) for the element - if ( !type ) { - for ( type in events ) { - jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); - } - continue; - } - - special = jQuery.event.special[ type ] || {}; - type = ( selector ? special.delegateType : special.bindType ) || type; - handlers = events[ type ] || []; - tmp = tmp[ 2 ] && - new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ); - - // Remove matching events - origCount = j = handlers.length; - while ( j-- ) { - handleObj = handlers[ j ]; - - if ( ( mappedTypes || origType === handleObj.origType ) && - ( !handler || handler.guid === handleObj.guid ) && - ( !tmp || tmp.test( handleObj.namespace ) ) && - ( !selector || selector === handleObj.selector || - selector === "**" && handleObj.selector ) ) { - handlers.splice( j, 1 ); - - if ( handleObj.selector ) { - handlers.delegateCount--; - } - if ( special.remove ) { - special.remove.call( elem, handleObj ); - } - } - } - - // Remove generic event handler if we removed something and no more handlers exist - // (avoids potential for endless recursion during removal of special event handlers) - if ( origCount && !handlers.length ) { - if ( !special.teardown || - special.teardown.call( elem, namespaces, elemData.handle ) === false ) { - - jQuery.removeEvent( elem, type, elemData.handle ); - } - - delete events[ type ]; - } - } - - // Remove data and the expando if it's no longer used - if ( jQuery.isEmptyObject( events ) ) { - dataPriv.remove( elem, "handle events" ); - } - }, - - dispatch: function( nativeEvent ) { - - // Make a writable jQuery.Event from the native event object - var event = jQuery.event.fix( nativeEvent ); - - var i, j, ret, matched, handleObj, handlerQueue, - args = new Array( arguments.length ), - handlers = ( dataPriv.get( this, "events" ) || {} )[ event.type ] || [], - special = jQuery.event.special[ event.type ] || {}; - - // Use the fix-ed jQuery.Event rather than the (read-only) native event - args[ 0 ] = event; - - for ( i = 1; i < arguments.length; i++ ) { - args[ i ] = arguments[ i ]; - } - - event.delegateTarget = this; - - // Call the preDispatch hook for the mapped type, and let it bail if desired - if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { - return; - } - - // Determine handlers - handlerQueue = jQuery.event.handlers.call( this, event, handlers ); - - // Run delegates first; they may want to stop propagation beneath us - i = 0; - while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) { - event.currentTarget = matched.elem; - - j = 0; - while ( ( handleObj = matched.handlers[ j++ ] ) && - !event.isImmediatePropagationStopped() ) { - - // If the event is namespaced, then each handler is only invoked if it is - // specially universal or its namespaces are a superset of the event's. - if ( !event.rnamespace || handleObj.namespace === false || - event.rnamespace.test( handleObj.namespace ) ) { - - event.handleObj = handleObj; - event.data = handleObj.data; - - ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle || - handleObj.handler ).apply( matched.elem, args ); - - if ( ret !== undefined ) { - if ( ( event.result = ret ) === false ) { - event.preventDefault(); - event.stopPropagation(); - } - } - } - } - } - - // Call the postDispatch hook for the mapped type - if ( special.postDispatch ) { - special.postDispatch.call( this, event ); - } - - return event.result; - }, - - handlers: function( event, handlers ) { - var i, handleObj, sel, matchedHandlers, matchedSelectors, - handlerQueue = [], - delegateCount = handlers.delegateCount, - cur = event.target; - - // Find delegate handlers - if ( delegateCount && - - // Support: IE <=9 - // Black-hole SVG instance trees (trac-13180) - cur.nodeType && - - // Support: Firefox <=42 - // Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861) - // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click - // Support: IE 11 only - // ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343) - !( event.type === "click" && event.button >= 1 ) ) { - - for ( ; cur !== this; cur = cur.parentNode || this ) { - - // Don't check non-elements (#13208) - // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) - if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) { - matchedHandlers = []; - matchedSelectors = {}; - for ( i = 0; i < delegateCount; i++ ) { - handleObj = handlers[ i ]; - - // Don't conflict with Object.prototype properties (#13203) - sel = handleObj.selector + " "; - - if ( matchedSelectors[ sel ] === undefined ) { - matchedSelectors[ sel ] = handleObj.needsContext ? - jQuery( sel, this ).index( cur ) > -1 : - jQuery.find( sel, this, null, [ cur ] ).length; - } - if ( matchedSelectors[ sel ] ) { - matchedHandlers.push( handleObj ); - } - } - if ( matchedHandlers.length ) { - handlerQueue.push( { elem: cur, handlers: matchedHandlers } ); - } - } - } - } - - // Add the remaining (directly-bound) handlers - cur = this; - if ( delegateCount < handlers.length ) { - handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } ); - } - - return handlerQueue; - }, - - addProp: function( name, hook ) { - Object.defineProperty( jQuery.Event.prototype, name, { - enumerable: true, - configurable: true, - - get: isFunction( hook ) ? - function() { - if ( this.originalEvent ) { - return hook( this.originalEvent ); - } - } : - function() { - if ( this.originalEvent ) { - return this.originalEvent[ name ]; - } - }, - - set: function( value ) { - Object.defineProperty( this, name, { - enumerable: true, - configurable: true, - writable: true, - value: value - } ); - } - } ); - }, - - fix: function( originalEvent ) { - return originalEvent[ jQuery.expando ] ? - originalEvent : - new jQuery.Event( originalEvent ); - }, - - special: { - load: { - - // Prevent triggered image.load events from bubbling to window.load - noBubble: true - }, - click: { - - // Utilize native event to ensure correct state for checkable inputs - setup: function( data ) { - - // For mutual compressibility with _default, replace `this` access with a local var. - // `|| data` is dead code meant only to preserve the variable through minification. - var el = this || data; - - // Claim the first handler - if ( rcheckableType.test( el.type ) && - el.click && nodeName( el, "input" ) ) { - - // dataPriv.set( el, "click", ... ) - leverageNative( el, "click", returnTrue ); - } - - // Return false to allow normal processing in the caller - return false; - }, - trigger: function( data ) { - - // For mutual compressibility with _default, replace `this` access with a local var. - // `|| data` is dead code meant only to preserve the variable through minification. - var el = this || data; - - // Force setup before triggering a click - if ( rcheckableType.test( el.type ) && - el.click && nodeName( el, "input" ) ) { - - leverageNative( el, "click" ); - } - - // Return non-false to allow normal event-path propagation - return true; - }, - - // For cross-browser consistency, suppress native .click() on links - // Also prevent it if we're currently inside a leveraged native-event stack - _default: function( event ) { - var target = event.target; - return rcheckableType.test( target.type ) && - target.click && nodeName( target, "input" ) && - dataPriv.get( target, "click" ) || - nodeName( target, "a" ); - } - }, - - beforeunload: { - postDispatch: function( event ) { - - // Support: Firefox 20+ - // Firefox doesn't alert if the returnValue field is not set. - if ( event.result !== undefined && event.originalEvent ) { - event.originalEvent.returnValue = event.result; - } - } - } - } -}; - -// Ensure the presence of an event listener that handles manually-triggered -// synthetic events by interrupting progress until reinvoked in response to -// *native* events that it fires directly, ensuring that state changes have -// already occurred before other listeners are invoked. -function leverageNative( el, type, expectSync ) { - - // Missing expectSync indicates a trigger call, which must force setup through jQuery.event.add - if ( !expectSync ) { - if ( dataPriv.get( el, type ) === undefined ) { - jQuery.event.add( el, type, returnTrue ); - } - return; - } - - // Register the controller as a special universal handler for all event namespaces - dataPriv.set( el, type, false ); - jQuery.event.add( el, type, { - namespace: false, - handler: function( event ) { - var notAsync, result, - saved = dataPriv.get( this, type ); - - if ( ( event.isTrigger & 1 ) && this[ type ] ) { - - // Interrupt processing of the outer synthetic .trigger()ed event - // Saved data should be false in such cases, but might be a leftover capture object - // from an async native handler (gh-4350) - if ( !saved.length ) { - - // Store arguments for use when handling the inner native event - // There will always be at least one argument (an event object), so this array - // will not be confused with a leftover capture object. - saved = slice.call( arguments ); - dataPriv.set( this, type, saved ); - - // Trigger the native event and capture its result - // Support: IE <=9 - 11+ - // focus() and blur() are asynchronous - notAsync = expectSync( this, type ); - this[ type ](); - result = dataPriv.get( this, type ); - if ( saved !== result || notAsync ) { - dataPriv.set( this, type, false ); - } else { - result = {}; - } - if ( saved !== result ) { - - // Cancel the outer synthetic event - event.stopImmediatePropagation(); - event.preventDefault(); - return result.value; - } - - // If this is an inner synthetic event for an event with a bubbling surrogate - // (focus or blur), assume that the surrogate already propagated from triggering the - // native event and prevent that from happening again here. - // This technically gets the ordering wrong w.r.t. to `.trigger()` (in which the - // bubbling surrogate propagates *after* the non-bubbling base), but that seems - // less bad than duplication. - } else if ( ( jQuery.event.special[ type ] || {} ).delegateType ) { - event.stopPropagation(); - } - - // If this is a native event triggered above, everything is now in order - // Fire an inner synthetic event with the original arguments - } else if ( saved.length ) { - - // ...and capture the result - dataPriv.set( this, type, { - value: jQuery.event.trigger( - - // Support: IE <=9 - 11+ - // Extend with the prototype to reset the above stopImmediatePropagation() - jQuery.extend( saved[ 0 ], jQuery.Event.prototype ), - saved.slice( 1 ), - this - ) - } ); - - // Abort handling of the native event - event.stopImmediatePropagation(); - } - } - } ); -} - -jQuery.removeEvent = function( elem, type, handle ) { - - // This "if" is needed for plain objects - if ( elem.removeEventListener ) { - elem.removeEventListener( type, handle ); - } -}; - -jQuery.Event = function( src, props ) { - - // Allow instantiation without the 'new' keyword - if ( !( this instanceof jQuery.Event ) ) { - return new jQuery.Event( src, props ); - } - - // Event object - if ( src && src.type ) { - this.originalEvent = src; - this.type = src.type; - - // Events bubbling up the document may have been marked as prevented - // by a handler lower down the tree; reflect the correct value. - this.isDefaultPrevented = src.defaultPrevented || - src.defaultPrevented === undefined && - - // Support: Android <=2.3 only - src.returnValue === false ? - returnTrue : - returnFalse; - - // Create target properties - // Support: Safari <=6 - 7 only - // Target should not be a text node (#504, #13143) - this.target = ( src.target && src.target.nodeType === 3 ) ? - src.target.parentNode : - src.target; - - this.currentTarget = src.currentTarget; - this.relatedTarget = src.relatedTarget; - - // Event type - } else { - this.type = src; - } - - // Put explicitly provided properties onto the event object - if ( props ) { - jQuery.extend( this, props ); - } - - // Create a timestamp if incoming event doesn't have one - this.timeStamp = src && src.timeStamp || Date.now(); - - // Mark it as fixed - this[ jQuery.expando ] = true; -}; - -// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding -// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html -jQuery.Event.prototype = { - constructor: jQuery.Event, - isDefaultPrevented: returnFalse, - isPropagationStopped: returnFalse, - isImmediatePropagationStopped: returnFalse, - isSimulated: false, - - preventDefault: function() { - var e = this.originalEvent; - - this.isDefaultPrevented = returnTrue; - - if ( e && !this.isSimulated ) { - e.preventDefault(); - } - }, - stopPropagation: function() { - var e = this.originalEvent; - - this.isPropagationStopped = returnTrue; - - if ( e && !this.isSimulated ) { - e.stopPropagation(); - } - }, - stopImmediatePropagation: function() { - var e = this.originalEvent; - - this.isImmediatePropagationStopped = returnTrue; - - if ( e && !this.isSimulated ) { - e.stopImmediatePropagation(); - } - - this.stopPropagation(); - } -}; - -// Includes all common event props including KeyEvent and MouseEvent specific props -jQuery.each( { - altKey: true, - bubbles: true, - cancelable: true, - changedTouches: true, - ctrlKey: true, - detail: true, - eventPhase: true, - metaKey: true, - pageX: true, - pageY: true, - shiftKey: true, - view: true, - "char": true, - code: true, - charCode: true, - key: true, - keyCode: true, - button: true, - buttons: true, - clientX: true, - clientY: true, - offsetX: true, - offsetY: true, - pointerId: true, - pointerType: true, - screenX: true, - screenY: true, - targetTouches: true, - toElement: true, - touches: true, - - which: function( event ) { - var button = event.button; - - // Add which for key events - if ( event.which == null && rkeyEvent.test( event.type ) ) { - return event.charCode != null ? event.charCode : event.keyCode; - } - - // Add which for click: 1 === left; 2 === middle; 3 === right - if ( !event.which && button !== undefined && rmouseEvent.test( event.type ) ) { - if ( button & 1 ) { - return 1; - } - - if ( button & 2 ) { - return 3; - } - - if ( button & 4 ) { - return 2; - } - - return 0; - } - - return event.which; - } -}, jQuery.event.addProp ); - -jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateType ) { - jQuery.event.special[ type ] = { - - // Utilize native event if possible so blur/focus sequence is correct - setup: function() { - - // Claim the first handler - // dataPriv.set( this, "focus", ... ) - // dataPriv.set( this, "blur", ... ) - leverageNative( this, type, expectSync ); - - // Return false to allow normal processing in the caller - return false; - }, - trigger: function() { - - // Force setup before trigger - leverageNative( this, type ); - - // Return non-false to allow normal event-path propagation - return true; - }, - - delegateType: delegateType - }; -} ); - -// Create mouseenter/leave events using mouseover/out and event-time checks -// so that event delegation works in jQuery. -// Do the same for pointerenter/pointerleave and pointerover/pointerout -// -// Support: Safari 7 only -// Safari sends mouseenter too often; see: -// https://bugs.chromium.org/p/chromium/issues/detail?id=470258 -// for the description of the bug (it existed in older Chrome versions as well). -jQuery.each( { - mouseenter: "mouseover", - mouseleave: "mouseout", - pointerenter: "pointerover", - pointerleave: "pointerout" -}, function( orig, fix ) { - jQuery.event.special[ orig ] = { - delegateType: fix, - bindType: fix, - - handle: function( event ) { - var ret, - target = this, - related = event.relatedTarget, - handleObj = event.handleObj; - - // For mouseenter/leave call the handler if related is outside the target. - // NB: No relatedTarget if the mouse left/entered the browser window - if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) { - event.type = handleObj.origType; - ret = handleObj.handler.apply( this, arguments ); - event.type = fix; - } - return ret; - } - }; -} ); - -jQuery.fn.extend( { - - on: function( types, selector, data, fn ) { - return on( this, types, selector, data, fn ); - }, - one: function( types, selector, data, fn ) { - return on( this, types, selector, data, fn, 1 ); - }, - off: function( types, selector, fn ) { - var handleObj, type; - if ( types && types.preventDefault && types.handleObj ) { - - // ( event ) dispatched jQuery.Event - handleObj = types.handleObj; - jQuery( types.delegateTarget ).off( - handleObj.namespace ? - handleObj.origType + "." + handleObj.namespace : - handleObj.origType, - handleObj.selector, - handleObj.handler - ); - return this; - } - if ( typeof types === "object" ) { - - // ( types-object [, selector] ) - for ( type in types ) { - this.off( type, selector, types[ type ] ); - } - return this; - } - if ( selector === false || typeof selector === "function" ) { - - // ( types [, fn] ) - fn = selector; - selector = undefined; - } - if ( fn === false ) { - fn = returnFalse; - } - return this.each( function() { - jQuery.event.remove( this, types, fn, selector ); - } ); - } -} ); - - -var - - /* eslint-disable max-len */ - - // See https://github.com/eslint/eslint/issues/3229 - rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi, - - /* eslint-enable */ - - // Support: IE <=10 - 11, Edge 12 - 13 only - // In IE/Edge using regex groups here causes severe slowdowns. - // See https://connect.microsoft.com/IE/feedback/details/1736512/ - rnoInnerhtml = /\s*$/g; - -// Prefer a tbody over its parent table for containing new rows -function manipulationTarget( elem, content ) { - if ( nodeName( elem, "table" ) && - nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) { - - return jQuery( elem ).children( "tbody" )[ 0 ] || elem; - } - - return elem; -} - -// Replace/restore the type attribute of script elements for safe DOM manipulation -function disableScript( elem ) { - elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type; - return elem; -} -function restoreScript( elem ) { - if ( ( elem.type || "" ).slice( 0, 5 ) === "true/" ) { - elem.type = elem.type.slice( 5 ); - } else { - elem.removeAttribute( "type" ); - } - - return elem; -} - -function cloneCopyEvent( src, dest ) { - var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events; - - if ( dest.nodeType !== 1 ) { - return; - } - - // 1. Copy private data: events, handlers, etc. - if ( dataPriv.hasData( src ) ) { - pdataOld = dataPriv.access( src ); - pdataCur = dataPriv.set( dest, pdataOld ); - events = pdataOld.events; - - if ( events ) { - delete pdataCur.handle; - pdataCur.events = {}; - - for ( type in events ) { - for ( i = 0, l = events[ type ].length; i < l; i++ ) { - jQuery.event.add( dest, type, events[ type ][ i ] ); - } - } - } - } - - // 2. Copy user data - if ( dataUser.hasData( src ) ) { - udataOld = dataUser.access( src ); - udataCur = jQuery.extend( {}, udataOld ); - - dataUser.set( dest, udataCur ); - } -} - -// Fix IE bugs, see support tests -function fixInput( src, dest ) { - var nodeName = dest.nodeName.toLowerCase(); - - // Fails to persist the checked state of a cloned checkbox or radio button. - if ( nodeName === "input" && rcheckableType.test( src.type ) ) { - dest.checked = src.checked; - - // Fails to return the selected option to the default selected state when cloning options - } else if ( nodeName === "input" || nodeName === "textarea" ) { - dest.defaultValue = src.defaultValue; - } -} - -function domManip( collection, args, callback, ignored ) { - - // Flatten any nested arrays - args = concat.apply( [], args ); - - var fragment, first, scripts, hasScripts, node, doc, - i = 0, - l = collection.length, - iNoClone = l - 1, - value = args[ 0 ], - valueIsFunction = isFunction( value ); - - // We can't cloneNode fragments that contain checked, in WebKit - if ( valueIsFunction || - ( l > 1 && typeof value === "string" && - !support.checkClone && rchecked.test( value ) ) ) { - return collection.each( function( index ) { - var self = collection.eq( index ); - if ( valueIsFunction ) { - args[ 0 ] = value.call( this, index, self.html() ); - } - domManip( self, args, callback, ignored ); - } ); - } - - if ( l ) { - fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored ); - first = fragment.firstChild; - - if ( fragment.childNodes.length === 1 ) { - fragment = first; - } - - // Require either new content or an interest in ignored elements to invoke the callback - if ( first || ignored ) { - scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); - hasScripts = scripts.length; - - // Use the original fragment for the last item - // instead of the first because it can end up - // being emptied incorrectly in certain situations (#8070). - for ( ; i < l; i++ ) { - node = fragment; - - if ( i !== iNoClone ) { - node = jQuery.clone( node, true, true ); - - // Keep references to cloned scripts for later restoration - if ( hasScripts ) { - - // Support: Android <=4.0 only, PhantomJS 1 only - // push.apply(_, arraylike) throws on ancient WebKit - jQuery.merge( scripts, getAll( node, "script" ) ); - } - } - - callback.call( collection[ i ], node, i ); - } - - if ( hasScripts ) { - doc = scripts[ scripts.length - 1 ].ownerDocument; - - // Reenable scripts - jQuery.map( scripts, restoreScript ); - - // Evaluate executable scripts on first document insertion - for ( i = 0; i < hasScripts; i++ ) { - node = scripts[ i ]; - if ( rscriptType.test( node.type || "" ) && - !dataPriv.access( node, "globalEval" ) && - jQuery.contains( doc, node ) ) { - - if ( node.src && ( node.type || "" ).toLowerCase() !== "module" ) { - - // Optional AJAX dependency, but won't run scripts if not present - if ( jQuery._evalUrl && !node.noModule ) { - jQuery._evalUrl( node.src, { - nonce: node.nonce || node.getAttribute( "nonce" ) - } ); - } - } else { - DOMEval( node.textContent.replace( rcleanScript, "" ), node, doc ); - } - } - } - } - } - } - - return collection; -} - -function remove( elem, selector, keepData ) { - var node, - nodes = selector ? jQuery.filter( selector, elem ) : elem, - i = 0; - - for ( ; ( node = nodes[ i ] ) != null; i++ ) { - if ( !keepData && node.nodeType === 1 ) { - jQuery.cleanData( getAll( node ) ); - } - - if ( node.parentNode ) { - if ( keepData && isAttached( node ) ) { - setGlobalEval( getAll( node, "script" ) ); - } - node.parentNode.removeChild( node ); - } - } - - return elem; -} - -jQuery.extend( { - htmlPrefilter: function( html ) { - return html.replace( rxhtmlTag, "<$1>" ); - }, - - clone: function( elem, dataAndEvents, deepDataAndEvents ) { - var i, l, srcElements, destElements, - clone = elem.cloneNode( true ), - inPage = isAttached( elem ); - - // Fix IE cloning issues - if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && - !jQuery.isXMLDoc( elem ) ) { - - // We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2 - destElements = getAll( clone ); - srcElements = getAll( elem ); - - for ( i = 0, l = srcElements.length; i < l; i++ ) { - fixInput( srcElements[ i ], destElements[ i ] ); - } - } - - // Copy the events from the original to the clone - if ( dataAndEvents ) { - if ( deepDataAndEvents ) { - srcElements = srcElements || getAll( elem ); - destElements = destElements || getAll( clone ); - - for ( i = 0, l = srcElements.length; i < l; i++ ) { - cloneCopyEvent( srcElements[ i ], destElements[ i ] ); - } - } else { - cloneCopyEvent( elem, clone ); - } - } - - // Preserve script evaluation history - destElements = getAll( clone, "script" ); - if ( destElements.length > 0 ) { - setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); - } - - // Return the cloned set - return clone; - }, - - cleanData: function( elems ) { - var data, elem, type, - special = jQuery.event.special, - i = 0; - - for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) { - if ( acceptData( elem ) ) { - if ( ( data = elem[ dataPriv.expando ] ) ) { - if ( data.events ) { - for ( type in data.events ) { - if ( special[ type ] ) { - jQuery.event.remove( elem, type ); - - // This is a shortcut to avoid jQuery.event.remove's overhead - } else { - jQuery.removeEvent( elem, type, data.handle ); - } - } - } - - // Support: Chrome <=35 - 45+ - // Assign undefined instead of using delete, see Data#remove - elem[ dataPriv.expando ] = undefined; - } - if ( elem[ dataUser.expando ] ) { - - // Support: Chrome <=35 - 45+ - // Assign undefined instead of using delete, see Data#remove - elem[ dataUser.expando ] = undefined; - } - } - } - } -} ); - -jQuery.fn.extend( { - detach: function( selector ) { - return remove( this, selector, true ); - }, - - remove: function( selector ) { - return remove( this, selector ); - }, - - text: function( value ) { - return access( this, function( value ) { - return value === undefined ? - jQuery.text( this ) : - this.empty().each( function() { - if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { - this.textContent = value; - } - } ); - }, null, value, arguments.length ); - }, - - append: function() { - return domManip( this, arguments, function( elem ) { - if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { - var target = manipulationTarget( this, elem ); - target.appendChild( elem ); - } - } ); - }, - - prepend: function() { - return domManip( this, arguments, function( elem ) { - if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { - var target = manipulationTarget( this, elem ); - target.insertBefore( elem, target.firstChild ); - } - } ); - }, - - before: function() { - return domManip( this, arguments, function( elem ) { - if ( this.parentNode ) { - this.parentNode.insertBefore( elem, this ); - } - } ); - }, - - after: function() { - return domManip( this, arguments, function( elem ) { - if ( this.parentNode ) { - this.parentNode.insertBefore( elem, this.nextSibling ); - } - } ); - }, - - empty: function() { - var elem, - i = 0; - - for ( ; ( elem = this[ i ] ) != null; i++ ) { - if ( elem.nodeType === 1 ) { - - // Prevent memory leaks - jQuery.cleanData( getAll( elem, false ) ); - - // Remove any remaining nodes - elem.textContent = ""; - } - } - - return this; - }, - - clone: function( dataAndEvents, deepDataAndEvents ) { - dataAndEvents = dataAndEvents == null ? false : dataAndEvents; - deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; - - return this.map( function() { - return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); - } ); - }, - - html: function( value ) { - return access( this, function( value ) { - var elem = this[ 0 ] || {}, - i = 0, - l = this.length; - - if ( value === undefined && elem.nodeType === 1 ) { - return elem.innerHTML; - } - - // See if we can take a shortcut and just use innerHTML - if ( typeof value === "string" && !rnoInnerhtml.test( value ) && - !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { - - value = jQuery.htmlPrefilter( value ); - - try { - for ( ; i < l; i++ ) { - elem = this[ i ] || {}; - - // Remove element nodes and prevent memory leaks - if ( elem.nodeType === 1 ) { - jQuery.cleanData( getAll( elem, false ) ); - elem.innerHTML = value; - } - } - - elem = 0; - - // If using innerHTML throws an exception, use the fallback method - } catch ( e ) {} - } - - if ( elem ) { - this.empty().append( value ); - } - }, null, value, arguments.length ); - }, - - replaceWith: function() { - var ignored = []; - - // Make the changes, replacing each non-ignored context element with the new content - return domManip( this, arguments, function( elem ) { - var parent = this.parentNode; - - if ( jQuery.inArray( this, ignored ) < 0 ) { - jQuery.cleanData( getAll( this ) ); - if ( parent ) { - parent.replaceChild( elem, this ); - } - } - - // Force callback invocation - }, ignored ); - } -} ); - -jQuery.each( { - appendTo: "append", - prependTo: "prepend", - insertBefore: "before", - insertAfter: "after", - replaceAll: "replaceWith" -}, function( name, original ) { - jQuery.fn[ name ] = function( selector ) { - var elems, - ret = [], - insert = jQuery( selector ), - last = insert.length - 1, - i = 0; - - for ( ; i <= last; i++ ) { - elems = i === last ? this : this.clone( true ); - jQuery( insert[ i ] )[ original ]( elems ); - - // Support: Android <=4.0 only, PhantomJS 1 only - // .get() because push.apply(_, arraylike) throws on ancient WebKit - push.apply( ret, elems.get() ); - } - - return this.pushStack( ret ); - }; -} ); -var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" ); - -var getStyles = function( elem ) { - - // Support: IE <=11 only, Firefox <=30 (#15098, #14150) - // IE throws on elements created in popups - // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" - var view = elem.ownerDocument.defaultView; - - if ( !view || !view.opener ) { - view = window; - } - - return view.getComputedStyle( elem ); - }; - -var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" ); - - - -( function() { - - // Executing both pixelPosition & boxSizingReliable tests require only one layout - // so they're executed at the same time to save the second computation. - function computeStyleTests() { - - // This is a singleton, we need to execute it only once - if ( !div ) { - return; - } - - container.style.cssText = "position:absolute;left:-11111px;width:60px;" + - "margin-top:1px;padding:0;border:0"; - div.style.cssText = - "position:relative;display:block;box-sizing:border-box;overflow:scroll;" + - "margin:auto;border:1px;padding:1px;" + - "width:60%;top:1%"; - documentElement.appendChild( container ).appendChild( div ); - - var divStyle = window.getComputedStyle( div ); - pixelPositionVal = divStyle.top !== "1%"; - - // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44 - reliableMarginLeftVal = roundPixelMeasures( divStyle.marginLeft ) === 12; - - // Support: Android 4.0 - 4.3 only, Safari <=9.1 - 10.1, iOS <=7.0 - 9.3 - // Some styles come back with percentage values, even though they shouldn't - div.style.right = "60%"; - pixelBoxStylesVal = roundPixelMeasures( divStyle.right ) === 36; - - // Support: IE 9 - 11 only - // Detect misreporting of content dimensions for box-sizing:border-box elements - boxSizingReliableVal = roundPixelMeasures( divStyle.width ) === 36; - - // Support: IE 9 only - // Detect overflow:scroll screwiness (gh-3699) - // Support: Chrome <=64 - // Don't get tricked when zoom affects offsetWidth (gh-4029) - div.style.position = "absolute"; - scrollboxSizeVal = roundPixelMeasures( div.offsetWidth / 3 ) === 12; - - documentElement.removeChild( container ); - - // Nullify the div so it wouldn't be stored in the memory and - // it will also be a sign that checks already performed - div = null; - } - - function roundPixelMeasures( measure ) { - return Math.round( parseFloat( measure ) ); - } - - var pixelPositionVal, boxSizingReliableVal, scrollboxSizeVal, pixelBoxStylesVal, - reliableMarginLeftVal, - container = document.createElement( "div" ), - div = document.createElement( "div" ); - - // Finish early in limited (non-browser) environments - if ( !div.style ) { - return; - } - - // Support: IE <=9 - 11 only - // Style of cloned element affects source element cloned (#8908) - div.style.backgroundClip = "content-box"; - div.cloneNode( true ).style.backgroundClip = ""; - support.clearCloneStyle = div.style.backgroundClip === "content-box"; - - jQuery.extend( support, { - boxSizingReliable: function() { - computeStyleTests(); - return boxSizingReliableVal; - }, - pixelBoxStyles: function() { - computeStyleTests(); - return pixelBoxStylesVal; - }, - pixelPosition: function() { - computeStyleTests(); - return pixelPositionVal; - }, - reliableMarginLeft: function() { - computeStyleTests(); - return reliableMarginLeftVal; - }, - scrollboxSize: function() { - computeStyleTests(); - return scrollboxSizeVal; - } - } ); -} )(); - - -function curCSS( elem, name, computed ) { - var width, minWidth, maxWidth, ret, - - // Support: Firefox 51+ - // Retrieving style before computed somehow - // fixes an issue with getting wrong values - // on detached elements - style = elem.style; - - computed = computed || getStyles( elem ); - - // getPropertyValue is needed for: - // .css('filter') (IE 9 only, #12537) - // .css('--customProperty) (#3144) - if ( computed ) { - ret = computed.getPropertyValue( name ) || computed[ name ]; - - if ( ret === "" && !isAttached( elem ) ) { - ret = jQuery.style( elem, name ); - } - - // A tribute to the "awesome hack by Dean Edwards" - // Android Browser returns percentage for some values, - // but width seems to be reliably pixels. - // This is against the CSSOM draft spec: - // https://drafts.csswg.org/cssom/#resolved-values - if ( !support.pixelBoxStyles() && rnumnonpx.test( ret ) && rboxStyle.test( name ) ) { - - // Remember the original values - width = style.width; - minWidth = style.minWidth; - maxWidth = style.maxWidth; - - // Put in the new values to get a computed value out - style.minWidth = style.maxWidth = style.width = ret; - ret = computed.width; - - // Revert the changed values - style.width = width; - style.minWidth = minWidth; - style.maxWidth = maxWidth; - } - } - - return ret !== undefined ? - - // Support: IE <=9 - 11 only - // IE returns zIndex value as an integer. - ret + "" : - ret; -} - - -function addGetHookIf( conditionFn, hookFn ) { - - // Define the hook, we'll check on the first run if it's really needed. - return { - get: function() { - if ( conditionFn() ) { - - // Hook not needed (or it's not possible to use it due - // to missing dependency), remove it. - delete this.get; - return; - } - - // Hook needed; redefine it so that the support test is not executed again. - return ( this.get = hookFn ).apply( this, arguments ); - } - }; -} - - -var cssPrefixes = [ "Webkit", "Moz", "ms" ], - emptyStyle = document.createElement( "div" ).style, - vendorProps = {}; - -// Return a vendor-prefixed property or undefined -function vendorPropName( name ) { - - // Check for vendor prefixed names - var capName = name[ 0 ].toUpperCase() + name.slice( 1 ), - i = cssPrefixes.length; - - while ( i-- ) { - name = cssPrefixes[ i ] + capName; - if ( name in emptyStyle ) { - return name; - } - } -} - -// Return a potentially-mapped jQuery.cssProps or vendor prefixed property -function finalPropName( name ) { - var final = jQuery.cssProps[ name ] || vendorProps[ name ]; - - if ( final ) { - return final; - } - if ( name in emptyStyle ) { - return name; - } - return vendorProps[ name ] = vendorPropName( name ) || name; -} - - -var - - // Swappable if display is none or starts with table - // except "table", "table-cell", or "table-caption" - // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display - rdisplayswap = /^(none|table(?!-c[ea]).+)/, - rcustomProp = /^--/, - cssShow = { position: "absolute", visibility: "hidden", display: "block" }, - cssNormalTransform = { - letterSpacing: "0", - fontWeight: "400" - }; - -function setPositiveNumber( elem, value, subtract ) { - - // Any relative (+/-) values have already been - // normalized at this point - var matches = rcssNum.exec( value ); - return matches ? - - // Guard against undefined "subtract", e.g., when used as in cssHooks - Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) : - value; -} - -function boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computedVal ) { - var i = dimension === "width" ? 1 : 0, - extra = 0, - delta = 0; - - // Adjustment may not be necessary - if ( box === ( isBorderBox ? "border" : "content" ) ) { - return 0; - } - - for ( ; i < 4; i += 2 ) { - - // Both box models exclude margin - if ( box === "margin" ) { - delta += jQuery.css( elem, box + cssExpand[ i ], true, styles ); - } - - // If we get here with a content-box, we're seeking "padding" or "border" or "margin" - if ( !isBorderBox ) { - - // Add padding - delta += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); - - // For "border" or "margin", add border - if ( box !== "padding" ) { - delta += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); - - // But still keep track of it otherwise - } else { - extra += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); - } - - // If we get here with a border-box (content + padding + border), we're seeking "content" or - // "padding" or "margin" - } else { - - // For "content", subtract padding - if ( box === "content" ) { - delta -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); - } - - // For "content" or "padding", subtract border - if ( box !== "margin" ) { - delta -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); - } - } - } - - // Account for positive content-box scroll gutter when requested by providing computedVal - if ( !isBorderBox && computedVal >= 0 ) { - - // offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border - // Assuming integer scroll gutter, subtract the rest and round down - delta += Math.max( 0, Math.ceil( - elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - - computedVal - - delta - - extra - - 0.5 - - // If offsetWidth/offsetHeight is unknown, then we can't determine content-box scroll gutter - // Use an explicit zero to avoid NaN (gh-3964) - ) ) || 0; - } - - return delta; -} - -function getWidthOrHeight( elem, dimension, extra ) { - - // Start with computed style - var styles = getStyles( elem ), - - // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-4322). - // Fake content-box until we know it's needed to know the true value. - boxSizingNeeded = !support.boxSizingReliable() || extra, - isBorderBox = boxSizingNeeded && - jQuery.css( elem, "boxSizing", false, styles ) === "border-box", - valueIsBorderBox = isBorderBox, - - val = curCSS( elem, dimension, styles ), - offsetProp = "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ); - - // Support: Firefox <=54 - // Return a confounding non-pixel value or feign ignorance, as appropriate. - if ( rnumnonpx.test( val ) ) { - if ( !extra ) { - return val; - } - val = "auto"; - } - - - // Fall back to offsetWidth/offsetHeight when value is "auto" - // This happens for inline elements with no explicit setting (gh-3571) - // Support: Android <=4.1 - 4.3 only - // Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602) - // Support: IE 9-11 only - // Also use offsetWidth/offsetHeight for when box sizing is unreliable - // We use getClientRects() to check for hidden/disconnected. - // In those cases, the computed value can be trusted to be border-box - if ( ( !support.boxSizingReliable() && isBorderBox || - val === "auto" || - !parseFloat( val ) && jQuery.css( elem, "display", false, styles ) === "inline" ) && - elem.getClientRects().length ) { - - isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; - - // Where available, offsetWidth/offsetHeight approximate border box dimensions. - // Where not available (e.g., SVG), assume unreliable box-sizing and interpret the - // retrieved value as a content box dimension. - valueIsBorderBox = offsetProp in elem; - if ( valueIsBorderBox ) { - val = elem[ offsetProp ]; - } - } - - // Normalize "" and auto - val = parseFloat( val ) || 0; - - // Adjust for the element's box model - return ( val + - boxModelAdjustment( - elem, - dimension, - extra || ( isBorderBox ? "border" : "content" ), - valueIsBorderBox, - styles, - - // Provide the current computed size to request scroll gutter calculation (gh-3589) - val - ) - ) + "px"; -} - -jQuery.extend( { - - // Add in style property hooks for overriding the default - // behavior of getting and setting a style property - cssHooks: { - opacity: { - get: function( elem, computed ) { - if ( computed ) { - - // We should always get a number back from opacity - var ret = curCSS( elem, "opacity" ); - return ret === "" ? "1" : ret; - } - } - } - }, - - // Don't automatically add "px" to these possibly-unitless properties - cssNumber: { - "animationIterationCount": true, - "columnCount": true, - "fillOpacity": true, - "flexGrow": true, - "flexShrink": true, - "fontWeight": true, - "gridArea": true, - "gridColumn": true, - "gridColumnEnd": true, - "gridColumnStart": true, - "gridRow": true, - "gridRowEnd": true, - "gridRowStart": true, - "lineHeight": true, - "opacity": true, - "order": true, - "orphans": true, - "widows": true, - "zIndex": true, - "zoom": true - }, - - // Add in properties whose names you wish to fix before - // setting or getting the value - cssProps: {}, - - // Get and set the style property on a DOM Node - style: function( elem, name, value, extra ) { - - // Don't set styles on text and comment nodes - if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { - return; - } - - // Make sure that we're working with the right name - var ret, type, hooks, - origName = camelCase( name ), - isCustomProp = rcustomProp.test( name ), - style = elem.style; - - // Make sure that we're working with the right name. We don't - // want to query the value if it is a CSS custom property - // since they are user-defined. - if ( !isCustomProp ) { - name = finalPropName( origName ); - } - - // Gets hook for the prefixed version, then unprefixed version - hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; - - // Check if we're setting a value - if ( value !== undefined ) { - type = typeof value; - - // Convert "+=" or "-=" to relative numbers (#7345) - if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) { - value = adjustCSS( elem, name, ret ); - - // Fixes bug #9237 - type = "number"; - } - - // Make sure that null and NaN values aren't set (#7116) - if ( value == null || value !== value ) { - return; - } - - // If a number was passed in, add the unit (except for certain CSS properties) - // The isCustomProp check can be removed in jQuery 4.0 when we only auto-append - // "px" to a few hardcoded values. - if ( type === "number" && !isCustomProp ) { - value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" ); - } - - // background-* props affect original clone's values - if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) { - style[ name ] = "inherit"; - } - - // If a hook was provided, use that value, otherwise just set the specified value - if ( !hooks || !( "set" in hooks ) || - ( value = hooks.set( elem, value, extra ) ) !== undefined ) { - - if ( isCustomProp ) { - style.setProperty( name, value ); - } else { - style[ name ] = value; - } - } - - } else { - - // If a hook was provided get the non-computed value from there - if ( hooks && "get" in hooks && - ( ret = hooks.get( elem, false, extra ) ) !== undefined ) { - - return ret; - } - - // Otherwise just get the value from the style object - return style[ name ]; - } - }, - - css: function( elem, name, extra, styles ) { - var val, num, hooks, - origName = camelCase( name ), - isCustomProp = rcustomProp.test( name ); - - // Make sure that we're working with the right name. We don't - // want to modify the value if it is a CSS custom property - // since they are user-defined. - if ( !isCustomProp ) { - name = finalPropName( origName ); - } - - // Try prefixed name followed by the unprefixed name - hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; - - // If a hook was provided get the computed value from there - if ( hooks && "get" in hooks ) { - val = hooks.get( elem, true, extra ); - } - - // Otherwise, if a way to get the computed value exists, use that - if ( val === undefined ) { - val = curCSS( elem, name, styles ); - } - - // Convert "normal" to computed value - if ( val === "normal" && name in cssNormalTransform ) { - val = cssNormalTransform[ name ]; - } - - // Make numeric if forced or a qualifier was provided and val looks numeric - if ( extra === "" || extra ) { - num = parseFloat( val ); - return extra === true || isFinite( num ) ? num || 0 : val; - } - - return val; - } -} ); - -jQuery.each( [ "height", "width" ], function( i, dimension ) { - jQuery.cssHooks[ dimension ] = { - get: function( elem, computed, extra ) { - if ( computed ) { - - // Certain elements can have dimension info if we invisibly show them - // but it must have a current display style that would benefit - return rdisplayswap.test( jQuery.css( elem, "display" ) ) && - - // Support: Safari 8+ - // Table columns in Safari have non-zero offsetWidth & zero - // getBoundingClientRect().width unless display is changed. - // Support: IE <=11 only - // Running getBoundingClientRect on a disconnected node - // in IE throws an error. - ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ? - swap( elem, cssShow, function() { - return getWidthOrHeight( elem, dimension, extra ); - } ) : - getWidthOrHeight( elem, dimension, extra ); - } - }, - - set: function( elem, value, extra ) { - var matches, - styles = getStyles( elem ), - - // Only read styles.position if the test has a chance to fail - // to avoid forcing a reflow. - scrollboxSizeBuggy = !support.scrollboxSize() && - styles.position === "absolute", - - // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-3991) - boxSizingNeeded = scrollboxSizeBuggy || extra, - isBorderBox = boxSizingNeeded && - jQuery.css( elem, "boxSizing", false, styles ) === "border-box", - subtract = extra ? - boxModelAdjustment( - elem, - dimension, - extra, - isBorderBox, - styles - ) : - 0; - - // Account for unreliable border-box dimensions by comparing offset* to computed and - // faking a content-box to get border and padding (gh-3699) - if ( isBorderBox && scrollboxSizeBuggy ) { - subtract -= Math.ceil( - elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - - parseFloat( styles[ dimension ] ) - - boxModelAdjustment( elem, dimension, "border", false, styles ) - - 0.5 - ); - } - - // Convert to pixels if value adjustment is needed - if ( subtract && ( matches = rcssNum.exec( value ) ) && - ( matches[ 3 ] || "px" ) !== "px" ) { - - elem.style[ dimension ] = value; - value = jQuery.css( elem, dimension ); - } - - return setPositiveNumber( elem, value, subtract ); - } - }; -} ); - -jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft, - function( elem, computed ) { - if ( computed ) { - return ( parseFloat( curCSS( elem, "marginLeft" ) ) || - elem.getBoundingClientRect().left - - swap( elem, { marginLeft: 0 }, function() { - return elem.getBoundingClientRect().left; - } ) - ) + "px"; - } - } -); - -// These hooks are used by animate to expand properties -jQuery.each( { - margin: "", - padding: "", - border: "Width" -}, function( prefix, suffix ) { - jQuery.cssHooks[ prefix + suffix ] = { - expand: function( value ) { - var i = 0, - expanded = {}, - - // Assumes a single number if not a string - parts = typeof value === "string" ? value.split( " " ) : [ value ]; - - for ( ; i < 4; i++ ) { - expanded[ prefix + cssExpand[ i ] + suffix ] = - parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; - } - - return expanded; - } - }; - - if ( prefix !== "margin" ) { - jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; - } -} ); - -jQuery.fn.extend( { - css: function( name, value ) { - return access( this, function( elem, name, value ) { - var styles, len, - map = {}, - i = 0; - - if ( Array.isArray( name ) ) { - styles = getStyles( elem ); - len = name.length; - - for ( ; i < len; i++ ) { - map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); - } - - return map; - } - - return value !== undefined ? - jQuery.style( elem, name, value ) : - jQuery.css( elem, name ); - }, name, value, arguments.length > 1 ); - } -} ); - - -function Tween( elem, options, prop, end, easing ) { - return new Tween.prototype.init( elem, options, prop, end, easing ); -} -jQuery.Tween = Tween; - -Tween.prototype = { - constructor: Tween, - init: function( elem, options, prop, end, easing, unit ) { - this.elem = elem; - this.prop = prop; - this.easing = easing || jQuery.easing._default; - this.options = options; - this.start = this.now = this.cur(); - this.end = end; - this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); - }, - cur: function() { - var hooks = Tween.propHooks[ this.prop ]; - - return hooks && hooks.get ? - hooks.get( this ) : - Tween.propHooks._default.get( this ); - }, - run: function( percent ) { - var eased, - hooks = Tween.propHooks[ this.prop ]; - - if ( this.options.duration ) { - this.pos = eased = jQuery.easing[ this.easing ]( - percent, this.options.duration * percent, 0, 1, this.options.duration - ); - } else { - this.pos = eased = percent; - } - this.now = ( this.end - this.start ) * eased + this.start; - - if ( this.options.step ) { - this.options.step.call( this.elem, this.now, this ); - } - - if ( hooks && hooks.set ) { - hooks.set( this ); - } else { - Tween.propHooks._default.set( this ); - } - return this; - } -}; - -Tween.prototype.init.prototype = Tween.prototype; - -Tween.propHooks = { - _default: { - get: function( tween ) { - var result; - - // Use a property on the element directly when it is not a DOM element, - // or when there is no matching style property that exists. - if ( tween.elem.nodeType !== 1 || - tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) { - return tween.elem[ tween.prop ]; - } - - // Passing an empty string as a 3rd parameter to .css will automatically - // attempt a parseFloat and fallback to a string if the parse fails. - // Simple values such as "10px" are parsed to Float; - // complex values such as "rotate(1rad)" are returned as-is. - result = jQuery.css( tween.elem, tween.prop, "" ); - - // Empty strings, null, undefined and "auto" are converted to 0. - return !result || result === "auto" ? 0 : result; - }, - set: function( tween ) { - - // Use step hook for back compat. - // Use cssHook if its there. - // Use .style if available and use plain properties where available. - if ( jQuery.fx.step[ tween.prop ] ) { - jQuery.fx.step[ tween.prop ]( tween ); - } else if ( tween.elem.nodeType === 1 && ( - jQuery.cssHooks[ tween.prop ] || - tween.elem.style[ finalPropName( tween.prop ) ] != null ) ) { - jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); - } else { - tween.elem[ tween.prop ] = tween.now; - } - } - } -}; - -// Support: IE <=9 only -// Panic based approach to setting things on disconnected nodes -Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { - set: function( tween ) { - if ( tween.elem.nodeType && tween.elem.parentNode ) { - tween.elem[ tween.prop ] = tween.now; - } - } -}; - -jQuery.easing = { - linear: function( p ) { - return p; - }, - swing: function( p ) { - return 0.5 - Math.cos( p * Math.PI ) / 2; - }, - _default: "swing" -}; - -jQuery.fx = Tween.prototype.init; - -// Back compat <1.8 extension point -jQuery.fx.step = {}; - - - - -var - fxNow, inProgress, - rfxtypes = /^(?:toggle|show|hide)$/, - rrun = /queueHooks$/; - -function schedule() { - if ( inProgress ) { - if ( document.hidden === false && window.requestAnimationFrame ) { - window.requestAnimationFrame( schedule ); - } else { - window.setTimeout( schedule, jQuery.fx.interval ); - } - - jQuery.fx.tick(); - } -} - -// Animations created synchronously will run synchronously -function createFxNow() { - window.setTimeout( function() { - fxNow = undefined; - } ); - return ( fxNow = Date.now() ); -} - -// Generate parameters to create a standard animation -function genFx( type, includeWidth ) { - var which, - i = 0, - attrs = { height: type }; - - // If we include width, step value is 1 to do all cssExpand values, - // otherwise step value is 2 to skip over Left and Right - includeWidth = includeWidth ? 1 : 0; - for ( ; i < 4; i += 2 - includeWidth ) { - which = cssExpand[ i ]; - attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; - } - - if ( includeWidth ) { - attrs.opacity = attrs.width = type; - } - - return attrs; -} - -function createTween( value, prop, animation ) { - var tween, - collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ), - index = 0, - length = collection.length; - for ( ; index < length; index++ ) { - if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) { - - // We're done with this property - return tween; - } - } -} - -function defaultPrefilter( elem, props, opts ) { - var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display, - isBox = "width" in props || "height" in props, - anim = this, - orig = {}, - style = elem.style, - hidden = elem.nodeType && isHiddenWithinTree( elem ), - dataShow = dataPriv.get( elem, "fxshow" ); - - // Queue-skipping animations hijack the fx hooks - if ( !opts.queue ) { - hooks = jQuery._queueHooks( elem, "fx" ); - if ( hooks.unqueued == null ) { - hooks.unqueued = 0; - oldfire = hooks.empty.fire; - hooks.empty.fire = function() { - if ( !hooks.unqueued ) { - oldfire(); - } - }; - } - hooks.unqueued++; - - anim.always( function() { - - // Ensure the complete handler is called before this completes - anim.always( function() { - hooks.unqueued--; - if ( !jQuery.queue( elem, "fx" ).length ) { - hooks.empty.fire(); - } - } ); - } ); - } - - // Detect show/hide animations - for ( prop in props ) { - value = props[ prop ]; - if ( rfxtypes.test( value ) ) { - delete props[ prop ]; - toggle = toggle || value === "toggle"; - if ( value === ( hidden ? "hide" : "show" ) ) { - - // Pretend to be hidden if this is a "show" and - // there is still data from a stopped show/hide - if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) { - hidden = true; - - // Ignore all other no-op show/hide data - } else { - continue; - } - } - orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop ); - } - } - - // Bail out if this is a no-op like .hide().hide() - propTween = !jQuery.isEmptyObject( props ); - if ( !propTween && jQuery.isEmptyObject( orig ) ) { - return; - } - - // Restrict "overflow" and "display" styles during box animations - if ( isBox && elem.nodeType === 1 ) { - - // Support: IE <=9 - 11, Edge 12 - 15 - // Record all 3 overflow attributes because IE does not infer the shorthand - // from identically-valued overflowX and overflowY and Edge just mirrors - // the overflowX value there. - opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; - - // Identify a display type, preferring old show/hide data over the CSS cascade - restoreDisplay = dataShow && dataShow.display; - if ( restoreDisplay == null ) { - restoreDisplay = dataPriv.get( elem, "display" ); - } - display = jQuery.css( elem, "display" ); - if ( display === "none" ) { - if ( restoreDisplay ) { - display = restoreDisplay; - } else { - - // Get nonempty value(s) by temporarily forcing visibility - showHide( [ elem ], true ); - restoreDisplay = elem.style.display || restoreDisplay; - display = jQuery.css( elem, "display" ); - showHide( [ elem ] ); - } - } - - // Animate inline elements as inline-block - if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) { - if ( jQuery.css( elem, "float" ) === "none" ) { - - // Restore the original display value at the end of pure show/hide animations - if ( !propTween ) { - anim.done( function() { - style.display = restoreDisplay; - } ); - if ( restoreDisplay == null ) { - display = style.display; - restoreDisplay = display === "none" ? "" : display; - } - } - style.display = "inline-block"; - } - } - } - - if ( opts.overflow ) { - style.overflow = "hidden"; - anim.always( function() { - style.overflow = opts.overflow[ 0 ]; - style.overflowX = opts.overflow[ 1 ]; - style.overflowY = opts.overflow[ 2 ]; - } ); - } - - // Implement show/hide animations - propTween = false; - for ( prop in orig ) { - - // General show/hide setup for this element animation - if ( !propTween ) { - if ( dataShow ) { - if ( "hidden" in dataShow ) { - hidden = dataShow.hidden; - } - } else { - dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } ); - } - - // Store hidden/visible for toggle so `.stop().toggle()` "reverses" - if ( toggle ) { - dataShow.hidden = !hidden; - } - - // Show elements before animating them - if ( hidden ) { - showHide( [ elem ], true ); - } - - /* eslint-disable no-loop-func */ - - anim.done( function() { - - /* eslint-enable no-loop-func */ - - // The final step of a "hide" animation is actually hiding the element - if ( !hidden ) { - showHide( [ elem ] ); - } - dataPriv.remove( elem, "fxshow" ); - for ( prop in orig ) { - jQuery.style( elem, prop, orig[ prop ] ); - } - } ); - } - - // Per-property setup - propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim ); - if ( !( prop in dataShow ) ) { - dataShow[ prop ] = propTween.start; - if ( hidden ) { - propTween.end = propTween.start; - propTween.start = 0; - } - } - } -} - -function propFilter( props, specialEasing ) { - var index, name, easing, value, hooks; - - // camelCase, specialEasing and expand cssHook pass - for ( index in props ) { - name = camelCase( index ); - easing = specialEasing[ name ]; - value = props[ index ]; - if ( Array.isArray( value ) ) { - easing = value[ 1 ]; - value = props[ index ] = value[ 0 ]; - } - - if ( index !== name ) { - props[ name ] = value; - delete props[ index ]; - } - - hooks = jQuery.cssHooks[ name ]; - if ( hooks && "expand" in hooks ) { - value = hooks.expand( value ); - delete props[ name ]; - - // Not quite $.extend, this won't overwrite existing keys. - // Reusing 'index' because we have the correct "name" - for ( index in value ) { - if ( !( index in props ) ) { - props[ index ] = value[ index ]; - specialEasing[ index ] = easing; - } - } - } else { - specialEasing[ name ] = easing; - } - } -} - -function Animation( elem, properties, options ) { - var result, - stopped, - index = 0, - length = Animation.prefilters.length, - deferred = jQuery.Deferred().always( function() { - - // Don't match elem in the :animated selector - delete tick.elem; - } ), - tick = function() { - if ( stopped ) { - return false; - } - var currentTime = fxNow || createFxNow(), - remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), - - // Support: Android 2.3 only - // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497) - temp = remaining / animation.duration || 0, - percent = 1 - temp, - index = 0, - length = animation.tweens.length; - - for ( ; index < length; index++ ) { - animation.tweens[ index ].run( percent ); - } - - deferred.notifyWith( elem, [ animation, percent, remaining ] ); - - // If there's more to do, yield - if ( percent < 1 && length ) { - return remaining; - } - - // If this was an empty animation, synthesize a final progress notification - if ( !length ) { - deferred.notifyWith( elem, [ animation, 1, 0 ] ); - } - - // Resolve the animation and report its conclusion - deferred.resolveWith( elem, [ animation ] ); - return false; - }, - animation = deferred.promise( { - elem: elem, - props: jQuery.extend( {}, properties ), - opts: jQuery.extend( true, { - specialEasing: {}, - easing: jQuery.easing._default - }, options ), - originalProperties: properties, - originalOptions: options, - startTime: fxNow || createFxNow(), - duration: options.duration, - tweens: [], - createTween: function( prop, end ) { - var tween = jQuery.Tween( elem, animation.opts, prop, end, - animation.opts.specialEasing[ prop ] || animation.opts.easing ); - animation.tweens.push( tween ); - return tween; - }, - stop: function( gotoEnd ) { - var index = 0, - - // If we are going to the end, we want to run all the tweens - // otherwise we skip this part - length = gotoEnd ? animation.tweens.length : 0; - if ( stopped ) { - return this; - } - stopped = true; - for ( ; index < length; index++ ) { - animation.tweens[ index ].run( 1 ); - } - - // Resolve when we played the last frame; otherwise, reject - if ( gotoEnd ) { - deferred.notifyWith( elem, [ animation, 1, 0 ] ); - deferred.resolveWith( elem, [ animation, gotoEnd ] ); - } else { - deferred.rejectWith( elem, [ animation, gotoEnd ] ); - } - return this; - } - } ), - props = animation.props; - - propFilter( props, animation.opts.specialEasing ); - - for ( ; index < length; index++ ) { - result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts ); - if ( result ) { - if ( isFunction( result.stop ) ) { - jQuery._queueHooks( animation.elem, animation.opts.queue ).stop = - result.stop.bind( result ); - } - return result; - } - } - - jQuery.map( props, createTween, animation ); - - if ( isFunction( animation.opts.start ) ) { - animation.opts.start.call( elem, animation ); - } - - // Attach callbacks from options - animation - .progress( animation.opts.progress ) - .done( animation.opts.done, animation.opts.complete ) - .fail( animation.opts.fail ) - .always( animation.opts.always ); - - jQuery.fx.timer( - jQuery.extend( tick, { - elem: elem, - anim: animation, - queue: animation.opts.queue - } ) - ); - - return animation; -} - -jQuery.Animation = jQuery.extend( Animation, { - - tweeners: { - "*": [ function( prop, value ) { - var tween = this.createTween( prop, value ); - adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween ); - return tween; - } ] - }, - - tweener: function( props, callback ) { - if ( isFunction( props ) ) { - callback = props; - props = [ "*" ]; - } else { - props = props.match( rnothtmlwhite ); - } - - var prop, - index = 0, - length = props.length; - - for ( ; index < length; index++ ) { - prop = props[ index ]; - Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || []; - Animation.tweeners[ prop ].unshift( callback ); - } - }, - - prefilters: [ defaultPrefilter ], - - prefilter: function( callback, prepend ) { - if ( prepend ) { - Animation.prefilters.unshift( callback ); - } else { - Animation.prefilters.push( callback ); - } - } -} ); - -jQuery.speed = function( speed, easing, fn ) { - var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { - complete: fn || !fn && easing || - isFunction( speed ) && speed, - duration: speed, - easing: fn && easing || easing && !isFunction( easing ) && easing - }; - - // Go to the end state if fx are off - if ( jQuery.fx.off ) { - opt.duration = 0; - - } else { - if ( typeof opt.duration !== "number" ) { - if ( opt.duration in jQuery.fx.speeds ) { - opt.duration = jQuery.fx.speeds[ opt.duration ]; - - } else { - opt.duration = jQuery.fx.speeds._default; - } - } - } - - // Normalize opt.queue - true/undefined/null -> "fx" - if ( opt.queue == null || opt.queue === true ) { - opt.queue = "fx"; - } - - // Queueing - opt.old = opt.complete; - - opt.complete = function() { - if ( isFunction( opt.old ) ) { - opt.old.call( this ); - } - - if ( opt.queue ) { - jQuery.dequeue( this, opt.queue ); - } - }; - - return opt; -}; - -jQuery.fn.extend( { - fadeTo: function( speed, to, easing, callback ) { - - // Show any hidden elements after setting opacity to 0 - return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show() - - // Animate to the value specified - .end().animate( { opacity: to }, speed, easing, callback ); - }, - animate: function( prop, speed, easing, callback ) { - var empty = jQuery.isEmptyObject( prop ), - optall = jQuery.speed( speed, easing, callback ), - doAnimation = function() { - - // Operate on a copy of prop so per-property easing won't be lost - var anim = Animation( this, jQuery.extend( {}, prop ), optall ); - - // Empty animations, or finishing resolves immediately - if ( empty || dataPriv.get( this, "finish" ) ) { - anim.stop( true ); - } - }; - doAnimation.finish = doAnimation; - - return empty || optall.queue === false ? - this.each( doAnimation ) : - this.queue( optall.queue, doAnimation ); - }, - stop: function( type, clearQueue, gotoEnd ) { - var stopQueue = function( hooks ) { - var stop = hooks.stop; - delete hooks.stop; - stop( gotoEnd ); - }; - - if ( typeof type !== "string" ) { - gotoEnd = clearQueue; - clearQueue = type; - type = undefined; - } - if ( clearQueue && type !== false ) { - this.queue( type || "fx", [] ); - } - - return this.each( function() { - var dequeue = true, - index = type != null && type + "queueHooks", - timers = jQuery.timers, - data = dataPriv.get( this ); - - if ( index ) { - if ( data[ index ] && data[ index ].stop ) { - stopQueue( data[ index ] ); - } - } else { - for ( index in data ) { - if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { - stopQueue( data[ index ] ); - } - } - } - - for ( index = timers.length; index--; ) { - if ( timers[ index ].elem === this && - ( type == null || timers[ index ].queue === type ) ) { - - timers[ index ].anim.stop( gotoEnd ); - dequeue = false; - timers.splice( index, 1 ); - } - } - - // Start the next in the queue if the last step wasn't forced. - // Timers currently will call their complete callbacks, which - // will dequeue but only if they were gotoEnd. - if ( dequeue || !gotoEnd ) { - jQuery.dequeue( this, type ); - } - } ); - }, - finish: function( type ) { - if ( type !== false ) { - type = type || "fx"; - } - return this.each( function() { - var index, - data = dataPriv.get( this ), - queue = data[ type + "queue" ], - hooks = data[ type + "queueHooks" ], - timers = jQuery.timers, - length = queue ? queue.length : 0; - - // Enable finishing flag on private data - data.finish = true; - - // Empty the queue first - jQuery.queue( this, type, [] ); - - if ( hooks && hooks.stop ) { - hooks.stop.call( this, true ); - } - - // Look for any active animations, and finish them - for ( index = timers.length; index--; ) { - if ( timers[ index ].elem === this && timers[ index ].queue === type ) { - timers[ index ].anim.stop( true ); - timers.splice( index, 1 ); - } - } - - // Look for any animations in the old queue and finish them - for ( index = 0; index < length; index++ ) { - if ( queue[ index ] && queue[ index ].finish ) { - queue[ index ].finish.call( this ); - } - } - - // Turn off finishing flag - delete data.finish; - } ); - } -} ); - -jQuery.each( [ "toggle", "show", "hide" ], function( i, name ) { - var cssFn = jQuery.fn[ name ]; - jQuery.fn[ name ] = function( speed, easing, callback ) { - return speed == null || typeof speed === "boolean" ? - cssFn.apply( this, arguments ) : - this.animate( genFx( name, true ), speed, easing, callback ); - }; -} ); - -// Generate shortcuts for custom animations -jQuery.each( { - slideDown: genFx( "show" ), - slideUp: genFx( "hide" ), - slideToggle: genFx( "toggle" ), - fadeIn: { opacity: "show" }, - fadeOut: { opacity: "hide" }, - fadeToggle: { opacity: "toggle" } -}, function( name, props ) { - jQuery.fn[ name ] = function( speed, easing, callback ) { - return this.animate( props, speed, easing, callback ); - }; -} ); - -jQuery.timers = []; -jQuery.fx.tick = function() { - var timer, - i = 0, - timers = jQuery.timers; - - fxNow = Date.now(); - - for ( ; i < timers.length; i++ ) { - timer = timers[ i ]; - - // Run the timer and safely remove it when done (allowing for external removal) - if ( !timer() && timers[ i ] === timer ) { - timers.splice( i--, 1 ); - } - } - - if ( !timers.length ) { - jQuery.fx.stop(); - } - fxNow = undefined; -}; - -jQuery.fx.timer = function( timer ) { - jQuery.timers.push( timer ); - jQuery.fx.start(); -}; - -jQuery.fx.interval = 13; -jQuery.fx.start = function() { - if ( inProgress ) { - return; - } - - inProgress = true; - schedule(); -}; - -jQuery.fx.stop = function() { - inProgress = null; -}; - -jQuery.fx.speeds = { - slow: 600, - fast: 200, - - // Default speed - _default: 400 -}; - - -// Based off of the plugin by Clint Helfers, with permission. -// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/ -jQuery.fn.delay = function( time, type ) { - time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; - type = type || "fx"; - - return this.queue( type, function( next, hooks ) { - var timeout = window.setTimeout( next, time ); - hooks.stop = function() { - window.clearTimeout( timeout ); - }; - } ); -}; - - -( function() { - var input = document.createElement( "input" ), - select = document.createElement( "select" ), - opt = select.appendChild( document.createElement( "option" ) ); - - input.type = "checkbox"; - - // Support: Android <=4.3 only - // Default value for a checkbox should be "on" - support.checkOn = input.value !== ""; - - // Support: IE <=11 only - // Must access selectedIndex to make default options select - support.optSelected = opt.selected; - - // Support: IE <=11 only - // An input loses its value after becoming a radio - input = document.createElement( "input" ); - input.value = "t"; - input.type = "radio"; - support.radioValue = input.value === "t"; -} )(); - - -var boolHook, - attrHandle = jQuery.expr.attrHandle; - -jQuery.fn.extend( { - attr: function( name, value ) { - return access( this, jQuery.attr, name, value, arguments.length > 1 ); - }, - - removeAttr: function( name ) { - return this.each( function() { - jQuery.removeAttr( this, name ); - } ); - } -} ); - -jQuery.extend( { - attr: function( elem, name, value ) { - var ret, hooks, - nType = elem.nodeType; - - // Don't get/set attributes on text, comment and attribute nodes - if ( nType === 3 || nType === 8 || nType === 2 ) { - return; - } - - // Fallback to prop when attributes are not supported - if ( typeof elem.getAttribute === "undefined" ) { - return jQuery.prop( elem, name, value ); - } - - // Attribute hooks are determined by the lowercase version - // Grab necessary hook if one is defined - if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { - hooks = jQuery.attrHooks[ name.toLowerCase() ] || - ( jQuery.expr.match.bool.test( name ) ? boolHook : undefined ); - } - - if ( value !== undefined ) { - if ( value === null ) { - jQuery.removeAttr( elem, name ); - return; - } - - if ( hooks && "set" in hooks && - ( ret = hooks.set( elem, value, name ) ) !== undefined ) { - return ret; - } - - elem.setAttribute( name, value + "" ); - return value; - } - - if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { - return ret; - } - - ret = jQuery.find.attr( elem, name ); - - // Non-existent attributes return null, we normalize to undefined - return ret == null ? undefined : ret; - }, - - attrHooks: { - type: { - set: function( elem, value ) { - if ( !support.radioValue && value === "radio" && - nodeName( elem, "input" ) ) { - var val = elem.value; - elem.setAttribute( "type", value ); - if ( val ) { - elem.value = val; - } - return value; - } - } - } - }, - - removeAttr: function( elem, value ) { - var name, - i = 0, - - // Attribute names can contain non-HTML whitespace characters - // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 - attrNames = value && value.match( rnothtmlwhite ); - - if ( attrNames && elem.nodeType === 1 ) { - while ( ( name = attrNames[ i++ ] ) ) { - elem.removeAttribute( name ); - } - } - } -} ); - -// Hooks for boolean attributes -boolHook = { - set: function( elem, value, name ) { - if ( value === false ) { - - // Remove boolean attributes when set to false - jQuery.removeAttr( elem, name ); - } else { - elem.setAttribute( name, name ); - } - return name; - } -}; - -jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) { - var getter = attrHandle[ name ] || jQuery.find.attr; - - attrHandle[ name ] = function( elem, name, isXML ) { - var ret, handle, - lowercaseName = name.toLowerCase(); - - if ( !isXML ) { - - // Avoid an infinite loop by temporarily removing this function from the getter - handle = attrHandle[ lowercaseName ]; - attrHandle[ lowercaseName ] = ret; - ret = getter( elem, name, isXML ) != null ? - lowercaseName : - null; - attrHandle[ lowercaseName ] = handle; - } - return ret; - }; -} ); - - - - -var rfocusable = /^(?:input|select|textarea|button)$/i, - rclickable = /^(?:a|area)$/i; - -jQuery.fn.extend( { - prop: function( name, value ) { - return access( this, jQuery.prop, name, value, arguments.length > 1 ); - }, - - removeProp: function( name ) { - return this.each( function() { - delete this[ jQuery.propFix[ name ] || name ]; - } ); - } -} ); - -jQuery.extend( { - prop: function( elem, name, value ) { - var ret, hooks, - nType = elem.nodeType; - - // Don't get/set properties on text, comment and attribute nodes - if ( nType === 3 || nType === 8 || nType === 2 ) { - return; - } - - if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { - - // Fix name and attach hooks - name = jQuery.propFix[ name ] || name; - hooks = jQuery.propHooks[ name ]; - } - - if ( value !== undefined ) { - if ( hooks && "set" in hooks && - ( ret = hooks.set( elem, value, name ) ) !== undefined ) { - return ret; - } - - return ( elem[ name ] = value ); - } - - if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { - return ret; - } - - return elem[ name ]; - }, - - propHooks: { - tabIndex: { - get: function( elem ) { - - // Support: IE <=9 - 11 only - // elem.tabIndex doesn't always return the - // correct value when it hasn't been explicitly set - // https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ - // Use proper attribute retrieval(#12072) - var tabindex = jQuery.find.attr( elem, "tabindex" ); - - if ( tabindex ) { - return parseInt( tabindex, 10 ); - } - - if ( - rfocusable.test( elem.nodeName ) || - rclickable.test( elem.nodeName ) && - elem.href - ) { - return 0; - } - - return -1; - } - } - }, - - propFix: { - "for": "htmlFor", - "class": "className" - } -} ); - -// Support: IE <=11 only -// Accessing the selectedIndex property -// forces the browser to respect setting selected -// on the option -// The getter ensures a default option is selected -// when in an optgroup -// eslint rule "no-unused-expressions" is disabled for this code -// since it considers such accessions noop -if ( !support.optSelected ) { - jQuery.propHooks.selected = { - get: function( elem ) { - - /* eslint no-unused-expressions: "off" */ - - var parent = elem.parentNode; - if ( parent && parent.parentNode ) { - parent.parentNode.selectedIndex; - } - return null; - }, - set: function( elem ) { - - /* eslint no-unused-expressions: "off" */ - - var parent = elem.parentNode; - if ( parent ) { - parent.selectedIndex; - - if ( parent.parentNode ) { - parent.parentNode.selectedIndex; - } - } - } - }; -} - -jQuery.each( [ - "tabIndex", - "readOnly", - "maxLength", - "cellSpacing", - "cellPadding", - "rowSpan", - "colSpan", - "useMap", - "frameBorder", - "contentEditable" -], function() { - jQuery.propFix[ this.toLowerCase() ] = this; -} ); - - - - - // Strip and collapse whitespace according to HTML spec - // https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace - function stripAndCollapse( value ) { - var tokens = value.match( rnothtmlwhite ) || []; - return tokens.join( " " ); - } - - -function getClass( elem ) { - return elem.getAttribute && elem.getAttribute( "class" ) || ""; -} - -function classesToArray( value ) { - if ( Array.isArray( value ) ) { - return value; - } - if ( typeof value === "string" ) { - return value.match( rnothtmlwhite ) || []; - } - return []; -} - -jQuery.fn.extend( { - addClass: function( value ) { - var classes, elem, cur, curValue, clazz, j, finalValue, - i = 0; - - if ( isFunction( value ) ) { - return this.each( function( j ) { - jQuery( this ).addClass( value.call( this, j, getClass( this ) ) ); - } ); - } - - classes = classesToArray( value ); - - if ( classes.length ) { - while ( ( elem = this[ i++ ] ) ) { - curValue = getClass( elem ); - cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); - - if ( cur ) { - j = 0; - while ( ( clazz = classes[ j++ ] ) ) { - if ( cur.indexOf( " " + clazz + " " ) < 0 ) { - cur += clazz + " "; - } - } - - // Only assign if different to avoid unneeded rendering. - finalValue = stripAndCollapse( cur ); - if ( curValue !== finalValue ) { - elem.setAttribute( "class", finalValue ); - } - } - } - } - - return this; - }, - - removeClass: function( value ) { - var classes, elem, cur, curValue, clazz, j, finalValue, - i = 0; - - if ( isFunction( value ) ) { - return this.each( function( j ) { - jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) ); - } ); - } - - if ( !arguments.length ) { - return this.attr( "class", "" ); - } - - classes = classesToArray( value ); - - if ( classes.length ) { - while ( ( elem = this[ i++ ] ) ) { - curValue = getClass( elem ); - - // This expression is here for better compressibility (see addClass) - cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); - - if ( cur ) { - j = 0; - while ( ( clazz = classes[ j++ ] ) ) { - - // Remove *all* instances - while ( cur.indexOf( " " + clazz + " " ) > -1 ) { - cur = cur.replace( " " + clazz + " ", " " ); - } - } - - // Only assign if different to avoid unneeded rendering. - finalValue = stripAndCollapse( cur ); - if ( curValue !== finalValue ) { - elem.setAttribute( "class", finalValue ); - } - } - } - } - - return this; - }, - - toggleClass: function( value, stateVal ) { - var type = typeof value, - isValidValue = type === "string" || Array.isArray( value ); - - if ( typeof stateVal === "boolean" && isValidValue ) { - return stateVal ? this.addClass( value ) : this.removeClass( value ); - } - - if ( isFunction( value ) ) { - return this.each( function( i ) { - jQuery( this ).toggleClass( - value.call( this, i, getClass( this ), stateVal ), - stateVal - ); - } ); - } - - return this.each( function() { - var className, i, self, classNames; - - if ( isValidValue ) { - - // Toggle individual class names - i = 0; - self = jQuery( this ); - classNames = classesToArray( value ); - - while ( ( className = classNames[ i++ ] ) ) { - - // Check each className given, space separated list - if ( self.hasClass( className ) ) { - self.removeClass( className ); - } else { - self.addClass( className ); - } - } - - // Toggle whole class name - } else if ( value === undefined || type === "boolean" ) { - className = getClass( this ); - if ( className ) { - - // Store className if set - dataPriv.set( this, "__className__", className ); - } - - // If the element has a class name or if we're passed `false`, - // then remove the whole classname (if there was one, the above saved it). - // Otherwise bring back whatever was previously saved (if anything), - // falling back to the empty string if nothing was stored. - if ( this.setAttribute ) { - this.setAttribute( "class", - className || value === false ? - "" : - dataPriv.get( this, "__className__" ) || "" - ); - } - } - } ); - }, - - hasClass: function( selector ) { - var className, elem, - i = 0; - - className = " " + selector + " "; - while ( ( elem = this[ i++ ] ) ) { - if ( elem.nodeType === 1 && - ( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) { - return true; - } - } - - return false; - } -} ); - - - - -var rreturn = /\r/g; - -jQuery.fn.extend( { - val: function( value ) { - var hooks, ret, valueIsFunction, - elem = this[ 0 ]; - - if ( !arguments.length ) { - if ( elem ) { - hooks = jQuery.valHooks[ elem.type ] || - jQuery.valHooks[ elem.nodeName.toLowerCase() ]; - - if ( hooks && - "get" in hooks && - ( ret = hooks.get( elem, "value" ) ) !== undefined - ) { - return ret; - } - - ret = elem.value; - - // Handle most common string cases - if ( typeof ret === "string" ) { - return ret.replace( rreturn, "" ); - } - - // Handle cases where value is null/undef or number - return ret == null ? "" : ret; - } - - return; - } - - valueIsFunction = isFunction( value ); - - return this.each( function( i ) { - var val; - - if ( this.nodeType !== 1 ) { - return; - } - - if ( valueIsFunction ) { - val = value.call( this, i, jQuery( this ).val() ); - } else { - val = value; - } - - // Treat null/undefined as ""; convert numbers to string - if ( val == null ) { - val = ""; - - } else if ( typeof val === "number" ) { - val += ""; - - } else if ( Array.isArray( val ) ) { - val = jQuery.map( val, function( value ) { - return value == null ? "" : value + ""; - } ); - } - - hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; - - // If set returns undefined, fall back to normal setting - if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) { - this.value = val; - } - } ); - } -} ); - -jQuery.extend( { - valHooks: { - option: { - get: function( elem ) { - - var val = jQuery.find.attr( elem, "value" ); - return val != null ? - val : - - // Support: IE <=10 - 11 only - // option.text throws exceptions (#14686, #14858) - // Strip and collapse whitespace - // https://html.spec.whatwg.org/#strip-and-collapse-whitespace - stripAndCollapse( jQuery.text( elem ) ); - } - }, - select: { - get: function( elem ) { - var value, option, i, - options = elem.options, - index = elem.selectedIndex, - one = elem.type === "select-one", - values = one ? null : [], - max = one ? index + 1 : options.length; - - if ( index < 0 ) { - i = max; - - } else { - i = one ? index : 0; - } - - // Loop through all the selected options - for ( ; i < max; i++ ) { - option = options[ i ]; - - // Support: IE <=9 only - // IE8-9 doesn't update selected after form reset (#2551) - if ( ( option.selected || i === index ) && - - // Don't return options that are disabled or in a disabled optgroup - !option.disabled && - ( !option.parentNode.disabled || - !nodeName( option.parentNode, "optgroup" ) ) ) { - - // Get the specific value for the option - value = jQuery( option ).val(); - - // We don't need an array for one selects - if ( one ) { - return value; - } - - // Multi-Selects return an array - values.push( value ); - } - } - - return values; - }, - - set: function( elem, value ) { - var optionSet, option, - options = elem.options, - values = jQuery.makeArray( value ), - i = options.length; - - while ( i-- ) { - option = options[ i ]; - - /* eslint-disable no-cond-assign */ - - if ( option.selected = - jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1 - ) { - optionSet = true; - } - - /* eslint-enable no-cond-assign */ - } - - // Force browsers to behave consistently when non-matching value is set - if ( !optionSet ) { - elem.selectedIndex = -1; - } - return values; - } - } - } -} ); - -// Radios and checkboxes getter/setter -jQuery.each( [ "radio", "checkbox" ], function() { - jQuery.valHooks[ this ] = { - set: function( elem, value ) { - if ( Array.isArray( value ) ) { - return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 ); - } - } - }; - if ( !support.checkOn ) { - jQuery.valHooks[ this ].get = function( elem ) { - return elem.getAttribute( "value" ) === null ? "on" : elem.value; - }; - } -} ); - - - - -// Return jQuery for attributes-only inclusion - - -support.focusin = "onfocusin" in window; - - -var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, - stopPropagationCallback = function( e ) { - e.stopPropagation(); - }; - -jQuery.extend( jQuery.event, { - - trigger: function( event, data, elem, onlyHandlers ) { - - var i, cur, tmp, bubbleType, ontype, handle, special, lastElement, - eventPath = [ elem || document ], - type = hasOwn.call( event, "type" ) ? event.type : event, - namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; - - cur = lastElement = tmp = elem = elem || document; - - // Don't do events on text and comment nodes - if ( elem.nodeType === 3 || elem.nodeType === 8 ) { - return; - } - - // focus/blur morphs to focusin/out; ensure we're not firing them right now - if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { - return; - } - - if ( type.indexOf( "." ) > -1 ) { - - // Namespaced trigger; create a regexp to match event type in handle() - namespaces = type.split( "." ); - type = namespaces.shift(); - namespaces.sort(); - } - ontype = type.indexOf( ":" ) < 0 && "on" + type; - - // Caller can pass in a jQuery.Event object, Object, or just an event type string - event = event[ jQuery.expando ] ? - event : - new jQuery.Event( type, typeof event === "object" && event ); - - // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) - event.isTrigger = onlyHandlers ? 2 : 3; - event.namespace = namespaces.join( "." ); - event.rnamespace = event.namespace ? - new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) : - null; - - // Clean up the event in case it is being reused - event.result = undefined; - if ( !event.target ) { - event.target = elem; - } - - // Clone any incoming data and prepend the event, creating the handler arg list - data = data == null ? - [ event ] : - jQuery.makeArray( data, [ event ] ); - - // Allow special events to draw outside the lines - special = jQuery.event.special[ type ] || {}; - if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { - return; - } - - // Determine event propagation path in advance, per W3C events spec (#9951) - // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) - if ( !onlyHandlers && !special.noBubble && !isWindow( elem ) ) { - - bubbleType = special.delegateType || type; - if ( !rfocusMorph.test( bubbleType + type ) ) { - cur = cur.parentNode; - } - for ( ; cur; cur = cur.parentNode ) { - eventPath.push( cur ); - tmp = cur; - } - - // Only add window if we got to document (e.g., not plain obj or detached DOM) - if ( tmp === ( elem.ownerDocument || document ) ) { - eventPath.push( tmp.defaultView || tmp.parentWindow || window ); - } - } - - // Fire handlers on the event path - i = 0; - while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { - lastElement = cur; - event.type = i > 1 ? - bubbleType : - special.bindType || type; - - // jQuery handler - handle = ( dataPriv.get( cur, "events" ) || {} )[ event.type ] && - dataPriv.get( cur, "handle" ); - if ( handle ) { - handle.apply( cur, data ); - } - - // Native handler - handle = ontype && cur[ ontype ]; - if ( handle && handle.apply && acceptData( cur ) ) { - event.result = handle.apply( cur, data ); - if ( event.result === false ) { - event.preventDefault(); - } - } - } - event.type = type; - - // If nobody prevented the default action, do it now - if ( !onlyHandlers && !event.isDefaultPrevented() ) { - - if ( ( !special._default || - special._default.apply( eventPath.pop(), data ) === false ) && - acceptData( elem ) ) { - - // Call a native DOM method on the target with the same name as the event. - // Don't do default actions on window, that's where global variables be (#6170) - if ( ontype && isFunction( elem[ type ] ) && !isWindow( elem ) ) { - - // Don't re-trigger an onFOO event when we call its FOO() method - tmp = elem[ ontype ]; - - if ( tmp ) { - elem[ ontype ] = null; - } - - // Prevent re-triggering of the same event, since we already bubbled it above - jQuery.event.triggered = type; - - if ( event.isPropagationStopped() ) { - lastElement.addEventListener( type, stopPropagationCallback ); - } - - elem[ type ](); - - if ( event.isPropagationStopped() ) { - lastElement.removeEventListener( type, stopPropagationCallback ); - } - - jQuery.event.triggered = undefined; - - if ( tmp ) { - elem[ ontype ] = tmp; - } - } - } - } - - return event.result; - }, - - // Piggyback on a donor event to simulate a different one - // Used only for `focus(in | out)` events - simulate: function( type, elem, event ) { - var e = jQuery.extend( - new jQuery.Event(), - event, - { - type: type, - isSimulated: true - } - ); - - jQuery.event.trigger( e, null, elem ); - } - -} ); - -jQuery.fn.extend( { - - trigger: function( type, data ) { - return this.each( function() { - jQuery.event.trigger( type, data, this ); - } ); - }, - triggerHandler: function( type, data ) { - var elem = this[ 0 ]; - if ( elem ) { - return jQuery.event.trigger( type, data, elem, true ); - } - } -} ); - - -// Support: Firefox <=44 -// Firefox doesn't have focus(in | out) events -// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787 -// -// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1 -// focus(in | out) events fire after focus & blur events, -// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order -// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857 -if ( !support.focusin ) { - jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) { - - // Attach a single capturing handler on the document while someone wants focusin/focusout - var handler = function( event ) { - jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) ); - }; - - jQuery.event.special[ fix ] = { - setup: function() { - var doc = this.ownerDocument || this, - attaches = dataPriv.access( doc, fix ); - - if ( !attaches ) { - doc.addEventListener( orig, handler, true ); - } - dataPriv.access( doc, fix, ( attaches || 0 ) + 1 ); - }, - teardown: function() { - var doc = this.ownerDocument || this, - attaches = dataPriv.access( doc, fix ) - 1; - - if ( !attaches ) { - doc.removeEventListener( orig, handler, true ); - dataPriv.remove( doc, fix ); - - } else { - dataPriv.access( doc, fix, attaches ); - } - } - }; - } ); -} -var location = window.location; - -var nonce = Date.now(); - -var rquery = ( /\?/ ); - - - -// Cross-browser xml parsing -jQuery.parseXML = function( data ) { - var xml; - if ( !data || typeof data !== "string" ) { - return null; - } - - // Support: IE 9 - 11 only - // IE throws on parseFromString with invalid input. - try { - xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" ); - } catch ( e ) { - xml = undefined; - } - - if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) { - jQuery.error( "Invalid XML: " + data ); - } - return xml; -}; - - -var - rbracket = /\[\]$/, - rCRLF = /\r?\n/g, - rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, - rsubmittable = /^(?:input|select|textarea|keygen)/i; - -function buildParams( prefix, obj, traditional, add ) { - var name; - - if ( Array.isArray( obj ) ) { - - // Serialize array item. - jQuery.each( obj, function( i, v ) { - if ( traditional || rbracket.test( prefix ) ) { - - // Treat each array item as a scalar. - add( prefix, v ); - - } else { - - // Item is non-scalar (array or object), encode its numeric index. - buildParams( - prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]", - v, - traditional, - add - ); - } - } ); - - } else if ( !traditional && toType( obj ) === "object" ) { - - // Serialize object item. - for ( name in obj ) { - buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); - } - - } else { - - // Serialize scalar item. - add( prefix, obj ); - } -} - -// Serialize an array of form elements or a set of -// key/values into a query string -jQuery.param = function( a, traditional ) { - var prefix, - s = [], - add = function( key, valueOrFunction ) { - - // If value is a function, invoke it and use its return value - var value = isFunction( valueOrFunction ) ? - valueOrFunction() : - valueOrFunction; - - s[ s.length ] = encodeURIComponent( key ) + "=" + - encodeURIComponent( value == null ? "" : value ); - }; - - if ( a == null ) { - return ""; - } - - // If an array was passed in, assume that it is an array of form elements. - if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { - - // Serialize the form elements - jQuery.each( a, function() { - add( this.name, this.value ); - } ); - - } else { - - // If traditional, encode the "old" way (the way 1.3.2 or older - // did it), otherwise encode params recursively. - for ( prefix in a ) { - buildParams( prefix, a[ prefix ], traditional, add ); - } - } - - // Return the resulting serialization - return s.join( "&" ); -}; - -jQuery.fn.extend( { - serialize: function() { - return jQuery.param( this.serializeArray() ); - }, - serializeArray: function() { - return this.map( function() { - - // Can add propHook for "elements" to filter or add form elements - var elements = jQuery.prop( this, "elements" ); - return elements ? jQuery.makeArray( elements ) : this; - } ) - .filter( function() { - var type = this.type; - - // Use .is( ":disabled" ) so that fieldset[disabled] works - return this.name && !jQuery( this ).is( ":disabled" ) && - rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) && - ( this.checked || !rcheckableType.test( type ) ); - } ) - .map( function( i, elem ) { - var val = jQuery( this ).val(); - - if ( val == null ) { - return null; - } - - if ( Array.isArray( val ) ) { - return jQuery.map( val, function( val ) { - return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; - } ); - } - - return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; - } ).get(); - } -} ); - - -var - r20 = /%20/g, - rhash = /#.*$/, - rantiCache = /([?&])_=[^&]*/, - rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg, - - // #7653, #8125, #8152: local protocol detection - rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, - rnoContent = /^(?:GET|HEAD)$/, - rprotocol = /^\/\//, - - /* Prefilters - * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) - * 2) These are called: - * - BEFORE asking for a transport - * - AFTER param serialization (s.data is a string if s.processData is true) - * 3) key is the dataType - * 4) the catchall symbol "*" can be used - * 5) execution will start with transport dataType and THEN continue down to "*" if needed - */ - prefilters = {}, - - /* Transports bindings - * 1) key is the dataType - * 2) the catchall symbol "*" can be used - * 3) selection will start with transport dataType and THEN go to "*" if needed - */ - transports = {}, - - // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression - allTypes = "*/".concat( "*" ), - - // Anchor tag for parsing the document origin - originAnchor = document.createElement( "a" ); - originAnchor.href = location.href; - -// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport -function addToPrefiltersOrTransports( structure ) { - - // dataTypeExpression is optional and defaults to "*" - return function( dataTypeExpression, func ) { - - if ( typeof dataTypeExpression !== "string" ) { - func = dataTypeExpression; - dataTypeExpression = "*"; - } - - var dataType, - i = 0, - dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || []; - - if ( isFunction( func ) ) { - - // For each dataType in the dataTypeExpression - while ( ( dataType = dataTypes[ i++ ] ) ) { - - // Prepend if requested - if ( dataType[ 0 ] === "+" ) { - dataType = dataType.slice( 1 ) || "*"; - ( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func ); - - // Otherwise append - } else { - ( structure[ dataType ] = structure[ dataType ] || [] ).push( func ); - } - } - } - }; -} - -// Base inspection function for prefilters and transports -function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) { - - var inspected = {}, - seekingTransport = ( structure === transports ); - - function inspect( dataType ) { - var selected; - inspected[ dataType ] = true; - jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) { - var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR ); - if ( typeof dataTypeOrTransport === "string" && - !seekingTransport && !inspected[ dataTypeOrTransport ] ) { - - options.dataTypes.unshift( dataTypeOrTransport ); - inspect( dataTypeOrTransport ); - return false; - } else if ( seekingTransport ) { - return !( selected = dataTypeOrTransport ); - } - } ); - return selected; - } - - return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" ); -} - -// A special extend for ajax options -// that takes "flat" options (not to be deep extended) -// Fixes #9887 -function ajaxExtend( target, src ) { - var key, deep, - flatOptions = jQuery.ajaxSettings.flatOptions || {}; - - for ( key in src ) { - if ( src[ key ] !== undefined ) { - ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; - } - } - if ( deep ) { - jQuery.extend( true, target, deep ); - } - - return target; -} - -/* Handles responses to an ajax request: - * - finds the right dataType (mediates between content-type and expected dataType) - * - returns the corresponding response - */ -function ajaxHandleResponses( s, jqXHR, responses ) { - - var ct, type, finalDataType, firstDataType, - contents = s.contents, - dataTypes = s.dataTypes; - - // Remove auto dataType and get content-type in the process - while ( dataTypes[ 0 ] === "*" ) { - dataTypes.shift(); - if ( ct === undefined ) { - ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" ); - } - } - - // Check if we're dealing with a known content-type - if ( ct ) { - for ( type in contents ) { - if ( contents[ type ] && contents[ type ].test( ct ) ) { - dataTypes.unshift( type ); - break; - } - } - } - - // Check to see if we have a response for the expected dataType - if ( dataTypes[ 0 ] in responses ) { - finalDataType = dataTypes[ 0 ]; - } else { - - // Try convertible dataTypes - for ( type in responses ) { - if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) { - finalDataType = type; - break; - } - if ( !firstDataType ) { - firstDataType = type; - } - } - - // Or just use first one - finalDataType = finalDataType || firstDataType; - } - - // If we found a dataType - // We add the dataType to the list if needed - // and return the corresponding response - if ( finalDataType ) { - if ( finalDataType !== dataTypes[ 0 ] ) { - dataTypes.unshift( finalDataType ); - } - return responses[ finalDataType ]; - } -} - -/* Chain conversions given the request and the original response - * Also sets the responseXXX fields on the jqXHR instance - */ -function ajaxConvert( s, response, jqXHR, isSuccess ) { - var conv2, current, conv, tmp, prev, - converters = {}, - - // Work with a copy of dataTypes in case we need to modify it for conversion - dataTypes = s.dataTypes.slice(); - - // Create converters map with lowercased keys - if ( dataTypes[ 1 ] ) { - for ( conv in s.converters ) { - converters[ conv.toLowerCase() ] = s.converters[ conv ]; - } - } - - current = dataTypes.shift(); - - // Convert to each sequential dataType - while ( current ) { - - if ( s.responseFields[ current ] ) { - jqXHR[ s.responseFields[ current ] ] = response; - } - - // Apply the dataFilter if provided - if ( !prev && isSuccess && s.dataFilter ) { - response = s.dataFilter( response, s.dataType ); - } - - prev = current; - current = dataTypes.shift(); - - if ( current ) { - - // There's only work to do if current dataType is non-auto - if ( current === "*" ) { - - current = prev; - - // Convert response if prev dataType is non-auto and differs from current - } else if ( prev !== "*" && prev !== current ) { - - // Seek a direct converter - conv = converters[ prev + " " + current ] || converters[ "* " + current ]; - - // If none found, seek a pair - if ( !conv ) { - for ( conv2 in converters ) { - - // If conv2 outputs current - tmp = conv2.split( " " ); - if ( tmp[ 1 ] === current ) { - - // If prev can be converted to accepted input - conv = converters[ prev + " " + tmp[ 0 ] ] || - converters[ "* " + tmp[ 0 ] ]; - if ( conv ) { - - // Condense equivalence converters - if ( conv === true ) { - conv = converters[ conv2 ]; - - // Otherwise, insert the intermediate dataType - } else if ( converters[ conv2 ] !== true ) { - current = tmp[ 0 ]; - dataTypes.unshift( tmp[ 1 ] ); - } - break; - } - } - } - } - - // Apply converter (if not an equivalence) - if ( conv !== true ) { - - // Unless errors are allowed to bubble, catch and return them - if ( conv && s.throws ) { - response = conv( response ); - } else { - try { - response = conv( response ); - } catch ( e ) { - return { - state: "parsererror", - error: conv ? e : "No conversion from " + prev + " to " + current - }; - } - } - } - } - } - } - - return { state: "success", data: response }; -} - -jQuery.extend( { - - // Counter for holding the number of active queries - active: 0, - - // Last-Modified header cache for next request - lastModified: {}, - etag: {}, - - ajaxSettings: { - url: location.href, - type: "GET", - isLocal: rlocalProtocol.test( location.protocol ), - global: true, - processData: true, - async: true, - contentType: "application/x-www-form-urlencoded; charset=UTF-8", - - /* - timeout: 0, - data: null, - dataType: null, - username: null, - password: null, - cache: null, - throws: false, - traditional: false, - headers: {}, - */ - - accepts: { - "*": allTypes, - text: "text/plain", - html: "text/html", - xml: "application/xml, text/xml", - json: "application/json, text/javascript" - }, - - contents: { - xml: /\bxml\b/, - html: /\bhtml/, - json: /\bjson\b/ - }, - - responseFields: { - xml: "responseXML", - text: "responseText", - json: "responseJSON" - }, - - // Data converters - // Keys separate source (or catchall "*") and destination types with a single space - converters: { - - // Convert anything to text - "* text": String, - - // Text to html (true = no transformation) - "text html": true, - - // Evaluate text as a json expression - "text json": JSON.parse, - - // Parse text as xml - "text xml": jQuery.parseXML - }, - - // For options that shouldn't be deep extended: - // you can add your own custom options here if - // and when you create one that shouldn't be - // deep extended (see ajaxExtend) - flatOptions: { - url: true, - context: true - } - }, - - // Creates a full fledged settings object into target - // with both ajaxSettings and settings fields. - // If target is omitted, writes into ajaxSettings. - ajaxSetup: function( target, settings ) { - return settings ? - - // Building a settings object - ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) : - - // Extending ajaxSettings - ajaxExtend( jQuery.ajaxSettings, target ); - }, - - ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), - ajaxTransport: addToPrefiltersOrTransports( transports ), - - // Main method - ajax: function( url, options ) { - - // If url is an object, simulate pre-1.5 signature - if ( typeof url === "object" ) { - options = url; - url = undefined; - } - - // Force options to be an object - options = options || {}; - - var transport, - - // URL without anti-cache param - cacheURL, - - // Response headers - responseHeadersString, - responseHeaders, - - // timeout handle - timeoutTimer, - - // Url cleanup var - urlAnchor, - - // Request state (becomes false upon send and true upon completion) - completed, - - // To know if global events are to be dispatched - fireGlobals, - - // Loop variable - i, - - // uncached part of the url - uncached, - - // Create the final options object - s = jQuery.ajaxSetup( {}, options ), - - // Callbacks context - callbackContext = s.context || s, - - // Context for global events is callbackContext if it is a DOM node or jQuery collection - globalEventContext = s.context && - ( callbackContext.nodeType || callbackContext.jquery ) ? - jQuery( callbackContext ) : - jQuery.event, - - // Deferreds - deferred = jQuery.Deferred(), - completeDeferred = jQuery.Callbacks( "once memory" ), - - // Status-dependent callbacks - statusCode = s.statusCode || {}, - - // Headers (they are sent all at once) - requestHeaders = {}, - requestHeadersNames = {}, - - // Default abort message - strAbort = "canceled", - - // Fake xhr - jqXHR = { - readyState: 0, - - // Builds headers hashtable if needed - getResponseHeader: function( key ) { - var match; - if ( completed ) { - if ( !responseHeaders ) { - responseHeaders = {}; - while ( ( match = rheaders.exec( responseHeadersString ) ) ) { - responseHeaders[ match[ 1 ].toLowerCase() + " " ] = - ( responseHeaders[ match[ 1 ].toLowerCase() + " " ] || [] ) - .concat( match[ 2 ] ); - } - } - match = responseHeaders[ key.toLowerCase() + " " ]; - } - return match == null ? null : match.join( ", " ); - }, - - // Raw string - getAllResponseHeaders: function() { - return completed ? responseHeadersString : null; - }, - - // Caches the header - setRequestHeader: function( name, value ) { - if ( completed == null ) { - name = requestHeadersNames[ name.toLowerCase() ] = - requestHeadersNames[ name.toLowerCase() ] || name; - requestHeaders[ name ] = value; - } - return this; - }, - - // Overrides response content-type header - overrideMimeType: function( type ) { - if ( completed == null ) { - s.mimeType = type; - } - return this; - }, - - // Status-dependent callbacks - statusCode: function( map ) { - var code; - if ( map ) { - if ( completed ) { - - // Execute the appropriate callbacks - jqXHR.always( map[ jqXHR.status ] ); - } else { - - // Lazy-add the new callbacks in a way that preserves old ones - for ( code in map ) { - statusCode[ code ] = [ statusCode[ code ], map[ code ] ]; - } - } - } - return this; - }, - - // Cancel the request - abort: function( statusText ) { - var finalText = statusText || strAbort; - if ( transport ) { - transport.abort( finalText ); - } - done( 0, finalText ); - return this; - } - }; - - // Attach deferreds - deferred.promise( jqXHR ); - - // Add protocol if not provided (prefilters might expect it) - // Handle falsy url in the settings object (#10093: consistency with old signature) - // We also use the url parameter if available - s.url = ( ( url || s.url || location.href ) + "" ) - .replace( rprotocol, location.protocol + "//" ); - - // Alias method option to type as per ticket #12004 - s.type = options.method || options.type || s.method || s.type; - - // Extract dataTypes list - s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnothtmlwhite ) || [ "" ]; - - // A cross-domain request is in order when the origin doesn't match the current origin. - if ( s.crossDomain == null ) { - urlAnchor = document.createElement( "a" ); - - // Support: IE <=8 - 11, Edge 12 - 15 - // IE throws exception on accessing the href property if url is malformed, - // e.g. http://example.com:80x/ - try { - urlAnchor.href = s.url; - - // Support: IE <=8 - 11 only - // Anchor's host property isn't correctly set when s.url is relative - urlAnchor.href = urlAnchor.href; - s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !== - urlAnchor.protocol + "//" + urlAnchor.host; - } catch ( e ) { - - // If there is an error parsing the URL, assume it is crossDomain, - // it can be rejected by the transport if it is invalid - s.crossDomain = true; - } - } - - // Convert data if not already a string - if ( s.data && s.processData && typeof s.data !== "string" ) { - s.data = jQuery.param( s.data, s.traditional ); - } - - // Apply prefilters - inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); - - // If request was aborted inside a prefilter, stop there - if ( completed ) { - return jqXHR; - } - - // We can fire global events as of now if asked to - // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118) - fireGlobals = jQuery.event && s.global; - - // Watch for a new set of requests - if ( fireGlobals && jQuery.active++ === 0 ) { - jQuery.event.trigger( "ajaxStart" ); - } - - // Uppercase the type - s.type = s.type.toUpperCase(); - - // Determine if request has content - s.hasContent = !rnoContent.test( s.type ); - - // Save the URL in case we're toying with the If-Modified-Since - // and/or If-None-Match header later on - // Remove hash to simplify url manipulation - cacheURL = s.url.replace( rhash, "" ); - - // More options handling for requests with no content - if ( !s.hasContent ) { - - // Remember the hash so we can put it back - uncached = s.url.slice( cacheURL.length ); - - // If data is available and should be processed, append data to url - if ( s.data && ( s.processData || typeof s.data === "string" ) ) { - cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data; - - // #9682: remove data so that it's not used in an eventual retry - delete s.data; - } - - // Add or update anti-cache param if needed - if ( s.cache === false ) { - cacheURL = cacheURL.replace( rantiCache, "$1" ); - uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce++ ) + uncached; - } - - // Put hash and anti-cache on the URL that will be requested (gh-1732) - s.url = cacheURL + uncached; - - // Change '%20' to '+' if this is encoded form body content (gh-2658) - } else if ( s.data && s.processData && - ( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) { - s.data = s.data.replace( r20, "+" ); - } - - // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. - if ( s.ifModified ) { - if ( jQuery.lastModified[ cacheURL ] ) { - jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] ); - } - if ( jQuery.etag[ cacheURL ] ) { - jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] ); - } - } - - // Set the correct header, if data is being sent - if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { - jqXHR.setRequestHeader( "Content-Type", s.contentType ); - } - - // Set the Accepts header for the server, depending on the dataType - jqXHR.setRequestHeader( - "Accept", - s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ? - s.accepts[ s.dataTypes[ 0 ] ] + - ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : - s.accepts[ "*" ] - ); - - // Check for headers option - for ( i in s.headers ) { - jqXHR.setRequestHeader( i, s.headers[ i ] ); - } - - // Allow custom headers/mimetypes and early abort - if ( s.beforeSend && - ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) { - - // Abort if not done already and return - return jqXHR.abort(); - } - - // Aborting is no longer a cancellation - strAbort = "abort"; - - // Install callbacks on deferreds - completeDeferred.add( s.complete ); - jqXHR.done( s.success ); - jqXHR.fail( s.error ); - - // Get transport - transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); - - // If no transport, we auto-abort - if ( !transport ) { - done( -1, "No Transport" ); - } else { - jqXHR.readyState = 1; - - // Send global event - if ( fireGlobals ) { - globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); - } - - // If request was aborted inside ajaxSend, stop there - if ( completed ) { - return jqXHR; - } - - // Timeout - if ( s.async && s.timeout > 0 ) { - timeoutTimer = window.setTimeout( function() { - jqXHR.abort( "timeout" ); - }, s.timeout ); - } - - try { - completed = false; - transport.send( requestHeaders, done ); - } catch ( e ) { - - // Rethrow post-completion exceptions - if ( completed ) { - throw e; - } - - // Propagate others as results - done( -1, e ); - } - } - - // Callback for when everything is done - function done( status, nativeStatusText, responses, headers ) { - var isSuccess, success, error, response, modified, - statusText = nativeStatusText; - - // Ignore repeat invocations - if ( completed ) { - return; - } - - completed = true; - - // Clear timeout if it exists - if ( timeoutTimer ) { - window.clearTimeout( timeoutTimer ); - } - - // Dereference transport for early garbage collection - // (no matter how long the jqXHR object will be used) - transport = undefined; - - // Cache response headers - responseHeadersString = headers || ""; - - // Set readyState - jqXHR.readyState = status > 0 ? 4 : 0; - - // Determine if successful - isSuccess = status >= 200 && status < 300 || status === 304; - - // Get response data - if ( responses ) { - response = ajaxHandleResponses( s, jqXHR, responses ); - } - - // Convert no matter what (that way responseXXX fields are always set) - response = ajaxConvert( s, response, jqXHR, isSuccess ); - - // If successful, handle type chaining - if ( isSuccess ) { - - // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. - if ( s.ifModified ) { - modified = jqXHR.getResponseHeader( "Last-Modified" ); - if ( modified ) { - jQuery.lastModified[ cacheURL ] = modified; - } - modified = jqXHR.getResponseHeader( "etag" ); - if ( modified ) { - jQuery.etag[ cacheURL ] = modified; - } - } - - // if no content - if ( status === 204 || s.type === "HEAD" ) { - statusText = "nocontent"; - - // if not modified - } else if ( status === 304 ) { - statusText = "notmodified"; - - // If we have data, let's convert it - } else { - statusText = response.state; - success = response.data; - error = response.error; - isSuccess = !error; - } - } else { - - // Extract error from statusText and normalize for non-aborts - error = statusText; - if ( status || !statusText ) { - statusText = "error"; - if ( status < 0 ) { - status = 0; - } - } - } - - // Set data for the fake xhr object - jqXHR.status = status; - jqXHR.statusText = ( nativeStatusText || statusText ) + ""; - - // Success/Error - if ( isSuccess ) { - deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); - } else { - deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); - } - - // Status-dependent callbacks - jqXHR.statusCode( statusCode ); - statusCode = undefined; - - if ( fireGlobals ) { - globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError", - [ jqXHR, s, isSuccess ? success : error ] ); - } - - // Complete - completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); - - if ( fireGlobals ) { - globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); - - // Handle the global AJAX counter - if ( !( --jQuery.active ) ) { - jQuery.event.trigger( "ajaxStop" ); - } - } - } - - return jqXHR; - }, - - getJSON: function( url, data, callback ) { - return jQuery.get( url, data, callback, "json" ); - }, - - getScript: function( url, callback ) { - return jQuery.get( url, undefined, callback, "script" ); - } -} ); - -jQuery.each( [ "get", "post" ], function( i, method ) { - jQuery[ method ] = function( url, data, callback, type ) { - - // Shift arguments if data argument was omitted - if ( isFunction( data ) ) { - type = type || callback; - callback = data; - data = undefined; - } - - // The url can be an options object (which then must have .url) - return jQuery.ajax( jQuery.extend( { - url: url, - type: method, - dataType: type, - data: data, - success: callback - }, jQuery.isPlainObject( url ) && url ) ); - }; -} ); - - -jQuery._evalUrl = function( url, options ) { - return jQuery.ajax( { - url: url, - - // Make this explicit, since user can override this through ajaxSetup (#11264) - type: "GET", - dataType: "script", - cache: true, - async: false, - global: false, - - // Only evaluate the response if it is successful (gh-4126) - // dataFilter is not invoked for failure responses, so using it instead - // of the default converter is kludgy but it works. - converters: { - "text script": function() {} - }, - dataFilter: function( response ) { - jQuery.globalEval( response, options ); - } - } ); -}; - - -jQuery.fn.extend( { - wrapAll: function( html ) { - var wrap; - - if ( this[ 0 ] ) { - if ( isFunction( html ) ) { - html = html.call( this[ 0 ] ); - } - - // The elements to wrap the target around - wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true ); - - if ( this[ 0 ].parentNode ) { - wrap.insertBefore( this[ 0 ] ); - } - - wrap.map( function() { - var elem = this; - - while ( elem.firstElementChild ) { - elem = elem.firstElementChild; - } - - return elem; - } ).append( this ); - } - - return this; - }, - - wrapInner: function( html ) { - if ( isFunction( html ) ) { - return this.each( function( i ) { - jQuery( this ).wrapInner( html.call( this, i ) ); - } ); - } - - return this.each( function() { - var self = jQuery( this ), - contents = self.contents(); - - if ( contents.length ) { - contents.wrapAll( html ); - - } else { - self.append( html ); - } - } ); - }, - - wrap: function( html ) { - var htmlIsFunction = isFunction( html ); - - return this.each( function( i ) { - jQuery( this ).wrapAll( htmlIsFunction ? html.call( this, i ) : html ); - } ); - }, - - unwrap: function( selector ) { - this.parent( selector ).not( "body" ).each( function() { - jQuery( this ).replaceWith( this.childNodes ); - } ); - return this; - } -} ); - - -jQuery.expr.pseudos.hidden = function( elem ) { - return !jQuery.expr.pseudos.visible( elem ); -}; -jQuery.expr.pseudos.visible = function( elem ) { - return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ); -}; - - - - -jQuery.ajaxSettings.xhr = function() { - try { - return new window.XMLHttpRequest(); - } catch ( e ) {} -}; - -var xhrSuccessStatus = { - - // File protocol always yields status code 0, assume 200 - 0: 200, - - // Support: IE <=9 only - // #1450: sometimes IE returns 1223 when it should be 204 - 1223: 204 - }, - xhrSupported = jQuery.ajaxSettings.xhr(); - -support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported ); -support.ajax = xhrSupported = !!xhrSupported; - -jQuery.ajaxTransport( function( options ) { - var callback, errorCallback; - - // Cross domain only allowed if supported through XMLHttpRequest - if ( support.cors || xhrSupported && !options.crossDomain ) { - return { - send: function( headers, complete ) { - var i, - xhr = options.xhr(); - - xhr.open( - options.type, - options.url, - options.async, - options.username, - options.password - ); - - // Apply custom fields if provided - if ( options.xhrFields ) { - for ( i in options.xhrFields ) { - xhr[ i ] = options.xhrFields[ i ]; - } - } - - // Override mime type if needed - if ( options.mimeType && xhr.overrideMimeType ) { - xhr.overrideMimeType( options.mimeType ); - } - - // X-Requested-With header - // For cross-domain requests, seeing as conditions for a preflight are - // akin to a jigsaw puzzle, we simply never set it to be sure. - // (it can always be set on a per-request basis or even using ajaxSetup) - // For same-domain requests, won't change header if already provided. - if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) { - headers[ "X-Requested-With" ] = "XMLHttpRequest"; - } - - // Set headers - for ( i in headers ) { - xhr.setRequestHeader( i, headers[ i ] ); - } - - // Callback - callback = function( type ) { - return function() { - if ( callback ) { - callback = errorCallback = xhr.onload = - xhr.onerror = xhr.onabort = xhr.ontimeout = - xhr.onreadystatechange = null; - - if ( type === "abort" ) { - xhr.abort(); - } else if ( type === "error" ) { - - // Support: IE <=9 only - // On a manual native abort, IE9 throws - // errors on any property access that is not readyState - if ( typeof xhr.status !== "number" ) { - complete( 0, "error" ); - } else { - complete( - - // File: protocol always yields status 0; see #8605, #14207 - xhr.status, - xhr.statusText - ); - } - } else { - complete( - xhrSuccessStatus[ xhr.status ] || xhr.status, - xhr.statusText, - - // Support: IE <=9 only - // IE9 has no XHR2 but throws on binary (trac-11426) - // For XHR2 non-text, let the caller handle it (gh-2498) - ( xhr.responseType || "text" ) !== "text" || - typeof xhr.responseText !== "string" ? - { binary: xhr.response } : - { text: xhr.responseText }, - xhr.getAllResponseHeaders() - ); - } - } - }; - }; - - // Listen to events - xhr.onload = callback(); - errorCallback = xhr.onerror = xhr.ontimeout = callback( "error" ); - - // Support: IE 9 only - // Use onreadystatechange to replace onabort - // to handle uncaught aborts - if ( xhr.onabort !== undefined ) { - xhr.onabort = errorCallback; - } else { - xhr.onreadystatechange = function() { - - // Check readyState before timeout as it changes - if ( xhr.readyState === 4 ) { - - // Allow onerror to be called first, - // but that will not handle a native abort - // Also, save errorCallback to a variable - // as xhr.onerror cannot be accessed - window.setTimeout( function() { - if ( callback ) { - errorCallback(); - } - } ); - } - }; - } - - // Create the abort callback - callback = callback( "abort" ); - - try { - - // Do send the request (this may raise an exception) - xhr.send( options.hasContent && options.data || null ); - } catch ( e ) { - - // #14683: Only rethrow if this hasn't been notified as an error yet - if ( callback ) { - throw e; - } - } - }, - - abort: function() { - if ( callback ) { - callback(); - } - } - }; - } -} ); - - - - -// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432) -jQuery.ajaxPrefilter( function( s ) { - if ( s.crossDomain ) { - s.contents.script = false; - } -} ); - -// Install script dataType -jQuery.ajaxSetup( { - accepts: { - script: "text/javascript, application/javascript, " + - "application/ecmascript, application/x-ecmascript" - }, - contents: { - script: /\b(?:java|ecma)script\b/ - }, - converters: { - "text script": function( text ) { - jQuery.globalEval( text ); - return text; - } - } -} ); - -// Handle cache's special case and crossDomain -jQuery.ajaxPrefilter( "script", function( s ) { - if ( s.cache === undefined ) { - s.cache = false; - } - if ( s.crossDomain ) { - s.type = "GET"; - } -} ); - -// Bind script tag hack transport -jQuery.ajaxTransport( "script", function( s ) { - - // This transport only deals with cross domain or forced-by-attrs requests - if ( s.crossDomain || s.scriptAttrs ) { - var script, callback; - return { - send: function( _, complete ) { - script = jQuery( "\r\n"; - -// inject VBScript -document.write(IEBinaryToArray_ByteStr_Script); - -global.JSZipUtils._getBinaryFromXHR = function (xhr) { - var binary = xhr.responseBody; - var byteMapping = {}; - for ( var i = 0; i < 256; i++ ) { - for ( var j = 0; j < 256; j++ ) { - byteMapping[ String.fromCharCode( i + (j << 8) ) ] = - String.fromCharCode(i) + String.fromCharCode(j); - } - } - var rawBytes = IEBinaryToArray_ByteStr(binary); - var lastChr = IEBinaryToArray_ByteStr_Last(binary); - return rawBytes.replace(/[\s\S]/g, function( match ) { - return byteMapping[match]; - }) + lastChr; -}; - -// enforcing Stuk's coding style -// vim: set shiftwidth=4 softtabstop=4: - -},{}]},{},[1]) -; diff --git a/boomerangScope-SootUp/target/apidocs/jquery/jszip-utils/dist/jszip-utils-ie.min.js b/boomerangScope-SootUp/target/apidocs/jquery/jszip-utils/dist/jszip-utils-ie.min.js deleted file mode 100644 index 93d8bc8ef..000000000 --- a/boomerangScope-SootUp/target/apidocs/jquery/jszip-utils/dist/jszip-utils-ie.min.js +++ /dev/null @@ -1,10 +0,0 @@ -/*! - -JSZipUtils - A collection of cross-browser utilities to go along with JSZip. - - -(c) 2014 Stuart Knightley, David Duponchel -Dual licenced under the MIT license or GPLv3. See https://raw.github.com/Stuk/jszip-utils/master/LICENSE.markdown. - -*/ -!function a(b,c,d){function e(g,h){if(!c[g]){if(!b[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);throw new Error("Cannot find module '"+g+"'")}var j=c[g]={exports:{}};b[g][0].call(j.exports,function(a){var c=b[g][1][a];return e(c?c:a)},j,j.exports,a,b,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;g\r\n";document.write(b),a.JSZipUtils._getBinaryFromXHR=function(a){for(var b=a.responseBody,c={},d=0;256>d;d++)for(var e=0;256>e;e++)c[String.fromCharCode(d+(e<<8))]=String.fromCharCode(d)+String.fromCharCode(e);var f=IEBinaryToArray_ByteStr(b),g=IEBinaryToArray_ByteStr_Last(b);return f.replace(/[\s\S]/g,function(a){return c[a]})+g}},{}]},{},[1]); diff --git a/boomerangScope-SootUp/target/apidocs/jquery/jszip-utils/dist/jszip-utils.js b/boomerangScope-SootUp/target/apidocs/jquery/jszip-utils/dist/jszip-utils.js deleted file mode 100644 index 775895ec9..000000000 --- a/boomerangScope-SootUp/target/apidocs/jquery/jszip-utils/dist/jszip-utils.js +++ /dev/null @@ -1,118 +0,0 @@ -/*! - -JSZipUtils - A collection of cross-browser utilities to go along with JSZip. - - -(c) 2014 Stuart Knightley, David Duponchel -Dual licenced under the MIT license or GPLv3. See https://raw.github.com/Stuk/jszip-utils/master/LICENSE.markdown. - -*/ -!function(e){"object"==typeof exports?module.exports=e():"function"==typeof define&&define.amd?define(e):"undefined"!=typeof window?window.JSZipUtils=e():"undefined"!=typeof global?global.JSZipUtils=e():"undefined"!=typeof self&&(self.JSZipUtils=e())}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o - -(c) 2014 Stuart Knightley, David Duponchel -Dual licenced under the MIT license or GPLv3. See https://raw.github.com/Stuk/jszip-utils/master/LICENSE.markdown. - -*/ -!function(a){"object"==typeof exports?module.exports=a():"function"==typeof define&&define.amd?define(a):"undefined"!=typeof window?window.JSZipUtils=a():"undefined"!=typeof global?global.JSZipUtils=a():"undefined"!=typeof self&&(self.JSZipUtils=a())}(function(){return function a(b,c,d){function e(g,h){if(!c[g]){if(!b[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);throw new Error("Cannot find module '"+g+"'")}var j=c[g]={exports:{}};b[g][0].call(j.exports,function(a){var c=b[g][1][a];return e(c?c:a)},j,j.exports,a,b,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;g - -(c) 2009-2016 Stuart Knightley -Dual licenced under the MIT license or GPLv3. See https://raw.github.com/Stuk/jszip/master/LICENSE.markdown. - -JSZip uses the library pako released under the MIT license : -https://github.com/nodeca/pako/blob/master/LICENSE -*/ - -(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.JSZip = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o - -(c) 2009-2016 Stuart Knightley -Dual licenced under the MIT license or GPLv3. See https://raw.github.com/Stuk/jszip/master/LICENSE.markdown. - -JSZip uses the library pako released under the MIT license : -https://github.com/nodeca/pako/blob/master/LICENSE -*/ - -!function(t){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{("undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this).JSZip=t()}}(function(){return function s(a,o,h){function u(r,t){if(!o[r]){if(!a[r]){var e="function"==typeof require&&require;if(!t&&e)return e(r,!0);if(l)return l(r,!0);var i=new Error("Cannot find module '"+r+"'");throw i.code="MODULE_NOT_FOUND",i}var n=o[r]={exports:{}};a[r][0].call(n.exports,function(t){var e=a[r][1][t];return u(e||t)},n,n.exports,s,a,o,h)}return o[r].exports}for(var l="function"==typeof require&&require,t=0;t>2,s=(3&e)<<4|r>>4,a=1>6:64,o=2>4,r=(15&n)<<4|(s=p.indexOf(t.charAt(o++)))>>2,i=(3&s)<<6|(a=p.indexOf(t.charAt(o++))),u[h++]=e,64!==s&&(u[h++]=r),64!==a&&(u[h++]=i);return u}},{"./support":30,"./utils":32}],2:[function(t,e,r){"use strict";var i=t("./external"),n=t("./stream/DataWorker"),s=t("./stream/Crc32Probe"),a=t("./stream/DataLengthProbe");function o(t,e,r,i,n){this.compressedSize=t,this.uncompressedSize=e,this.crc32=r,this.compression=i,this.compressedContent=n}o.prototype={getContentWorker:function(){var t=new n(i.Promise.resolve(this.compressedContent)).pipe(this.compression.uncompressWorker()).pipe(new a("data_length")),e=this;return t.on("end",function(){if(this.streamInfo.data_length!==e.uncompressedSize)throw new Error("Bug : uncompressed data size mismatch")}),t},getCompressedWorker:function(){return new n(i.Promise.resolve(this.compressedContent)).withStreamInfo("compressedSize",this.compressedSize).withStreamInfo("uncompressedSize",this.uncompressedSize).withStreamInfo("crc32",this.crc32).withStreamInfo("compression",this.compression)}},o.createWorkerFrom=function(t,e,r){return t.pipe(new s).pipe(new a("uncompressedSize")).pipe(e.compressWorker(r)).pipe(new a("compressedSize")).withStreamInfo("compression",e)},e.exports=o},{"./external":6,"./stream/Crc32Probe":25,"./stream/DataLengthProbe":26,"./stream/DataWorker":27}],3:[function(t,e,r){"use strict";var i=t("./stream/GenericWorker");r.STORE={magic:"\0\0",compressWorker:function(t){return new i("STORE compression")},uncompressWorker:function(){return new i("STORE decompression")}},r.DEFLATE=t("./flate")},{"./flate":7,"./stream/GenericWorker":28}],4:[function(t,e,r){"use strict";var i=t("./utils"),a=function(){for(var t,e=[],r=0;r<256;r++){t=r;for(var i=0;i<8;i++)t=1&t?3988292384^t>>>1:t>>>1;e[r]=t}return e}();e.exports=function(t,e){return void 0!==t&&t.length?"string"!==i.getTypeOf(t)?function(t,e,r){var i=a,n=0+r;t^=-1;for(var s=0;s>>8^i[255&(t^e[s])];return-1^t}(0|e,t,t.length):function(t,e,r){var i=a,n=0+r;t^=-1;for(var s=0;s>>8^i[255&(t^e.charCodeAt(s))];return-1^t}(0|e,t,t.length):0}},{"./utils":32}],5:[function(t,e,r){"use strict";r.base64=!1,r.binary=!1,r.dir=!1,r.createFolders=!0,r.date=null,r.compression=null,r.compressionOptions=null,r.comment=null,r.unixPermissions=null,r.dosPermissions=null},{}],6:[function(t,e,r){"use strict";var i;i="undefined"!=typeof Promise?Promise:t("lie"),e.exports={Promise:i}},{lie:37}],7:[function(t,e,r){"use strict";var i="undefined"!=typeof Uint8Array&&"undefined"!=typeof Uint16Array&&"undefined"!=typeof Uint32Array,n=t("pako"),s=t("./utils"),a=t("./stream/GenericWorker"),o=i?"uint8array":"array";function h(t,e){a.call(this,"FlateWorker/"+t),this._pako=null,this._pakoAction=t,this._pakoOptions=e,this.meta={}}r.magic="\b\0",s.inherits(h,a),h.prototype.processChunk=function(t){this.meta=t.meta,null===this._pako&&this._createPako(),this._pako.push(s.transformTo(o,t.data),!1)},h.prototype.flush=function(){a.prototype.flush.call(this),null===this._pako&&this._createPako(),this._pako.push([],!0)},h.prototype.cleanUp=function(){a.prototype.cleanUp.call(this),this._pako=null},h.prototype._createPako=function(){this._pako=new n[this._pakoAction]({raw:!0,level:this._pakoOptions.level||-1});var e=this;this._pako.onData=function(t){e.push({data:t,meta:e.meta})}},r.compressWorker=function(t){return new h("Deflate",t)},r.uncompressWorker=function(){return new h("Inflate",{})}},{"./stream/GenericWorker":28,"./utils":32,pako:38}],8:[function(t,e,r){"use strict";function O(t,e){var r,i="";for(r=0;r>>=8;return i}function n(t,e,r,i,n,s){var a,o,h=t.file,u=t.compression,l=s!==R.utf8encode,f=B.transformTo("string",s(h.name)),d=B.transformTo("string",R.utf8encode(h.name)),c=h.comment,p=B.transformTo("string",s(c)),m=B.transformTo("string",R.utf8encode(c)),_=d.length!==h.name.length,g=m.length!==c.length,b="",v="",y="",w=h.dir,k=h.date,x={crc32:0,compressedSize:0,uncompressedSize:0};e&&!r||(x.crc32=t.crc32,x.compressedSize=t.compressedSize,x.uncompressedSize=t.uncompressedSize);var S=0;e&&(S|=8),l||!_&&!g||(S|=2048);var z,C,E=0,A=0;w&&(E|=16),"UNIX"===n?(A=798,E|=(z=h.unixPermissions,(C=z)||(C=w?16893:33204),(65535&C)<<16)):(A=20,E|=63&(h.dosPermissions||0)),a=k.getUTCHours(),a<<=6,a|=k.getUTCMinutes(),a<<=5,a|=k.getUTCSeconds()/2,o=k.getUTCFullYear()-1980,o<<=4,o|=k.getUTCMonth()+1,o<<=5,o|=k.getUTCDate(),_&&(b+="up"+O((v=O(1,1)+O(T(f),4)+d).length,2)+v),g&&(b+="uc"+O((y=O(1,1)+O(T(p),4)+m).length,2)+y);var I="";return I+="\n\0",I+=O(S,2),I+=u.magic,I+=O(a,2),I+=O(o,2),I+=O(x.crc32,4),I+=O(x.compressedSize,4),I+=O(x.uncompressedSize,4),I+=O(f.length,2),I+=O(b.length,2),{fileRecord:D.LOCAL_FILE_HEADER+I+f+b,dirRecord:D.CENTRAL_FILE_HEADER+O(A,2)+I+O(p.length,2)+"\0\0\0\0"+O(E,4)+O(i,4)+f+b+p}}var B=t("../utils"),s=t("../stream/GenericWorker"),R=t("../utf8"),T=t("../crc32"),D=t("../signature");function i(t,e,r,i){s.call(this,"ZipFileWorker"),this.bytesWritten=0,this.zipComment=e,this.zipPlatform=r,this.encodeFileName=i,this.streamFiles=t,this.accumulate=!1,this.contentBuffer=[],this.dirRecords=[],this.currentSourceOffset=0,this.entriesCount=0,this.currentFile=null,this._sources=[]}B.inherits(i,s),i.prototype.push=function(t){var e=t.meta.percent||0,r=this.entriesCount,i=this._sources.length;this.accumulate?this.contentBuffer.push(t):(this.bytesWritten+=t.data.length,s.prototype.push.call(this,{data:t.data,meta:{currentFile:this.currentFile,percent:r?(e+100*(r-i-1))/r:100}}))},i.prototype.openedSource=function(t){this.currentSourceOffset=this.bytesWritten,this.currentFile=t.file.name;var e=this.streamFiles&&!t.file.dir;if(e){var r=n(t,e,!1,this.currentSourceOffset,this.zipPlatform,this.encodeFileName);this.push({data:r.fileRecord,meta:{percent:0}})}else this.accumulate=!0},i.prototype.closedSource=function(t){this.accumulate=!1;var e,r=this.streamFiles&&!t.file.dir,i=n(t,r,!0,this.currentSourceOffset,this.zipPlatform,this.encodeFileName);if(this.dirRecords.push(i.dirRecord),r)this.push({data:(e=t,D.DATA_DESCRIPTOR+O(e.crc32,4)+O(e.compressedSize,4)+O(e.uncompressedSize,4)),meta:{percent:100}});else for(this.push({data:i.fileRecord,meta:{percent:0}});this.contentBuffer.length;)this.push(this.contentBuffer.shift());this.currentFile=null},i.prototype.flush=function(){for(var t=this.bytesWritten,e=0;e=this.index;e--)r=(r<<8)+this.byteAt(e);return this.index+=t,r},readString:function(t){return i.transformTo("string",this.readData(t))},readData:function(t){},lastIndexOfSignature:function(t){},readAndCheckSignature:function(t){},readDate:function(){var t=this.readInt(4);return new Date(Date.UTC(1980+(t>>25&127),(t>>21&15)-1,t>>16&31,t>>11&31,t>>5&63,(31&t)<<1))}},e.exports=n},{"../utils":32}],19:[function(t,e,r){"use strict";var i=t("./Uint8ArrayReader");function n(t){i.call(this,t)}t("../utils").inherits(n,i),n.prototype.readData=function(t){this.checkOffset(t);var e=this.data.slice(this.zero+this.index,this.zero+this.index+t);return this.index+=t,e},e.exports=n},{"../utils":32,"./Uint8ArrayReader":21}],20:[function(t,e,r){"use strict";var i=t("./DataReader");function n(t){i.call(this,t)}t("../utils").inherits(n,i),n.prototype.byteAt=function(t){return this.data.charCodeAt(this.zero+t)},n.prototype.lastIndexOfSignature=function(t){return this.data.lastIndexOf(t)-this.zero},n.prototype.readAndCheckSignature=function(t){return t===this.readData(4)},n.prototype.readData=function(t){this.checkOffset(t);var e=this.data.slice(this.zero+this.index,this.zero+this.index+t);return this.index+=t,e},e.exports=n},{"../utils":32,"./DataReader":18}],21:[function(t,e,r){"use strict";var i=t("./ArrayReader");function n(t){i.call(this,t)}t("../utils").inherits(n,i),n.prototype.readData=function(t){if(this.checkOffset(t),0===t)return new Uint8Array(0);var e=this.data.subarray(this.zero+this.index,this.zero+this.index+t);return this.index+=t,e},e.exports=n},{"../utils":32,"./ArrayReader":17}],22:[function(t,e,r){"use strict";var i=t("../utils"),n=t("../support"),s=t("./ArrayReader"),a=t("./StringReader"),o=t("./NodeBufferReader"),h=t("./Uint8ArrayReader");e.exports=function(t){var e=i.getTypeOf(t);return i.checkSupport(e),"string"!==e||n.uint8array?"nodebuffer"===e?new o(t):n.uint8array?new h(i.transformTo("uint8array",t)):new s(i.transformTo("array",t)):new a(t)}},{"../support":30,"../utils":32,"./ArrayReader":17,"./NodeBufferReader":19,"./StringReader":20,"./Uint8ArrayReader":21}],23:[function(t,e,r){"use strict";r.LOCAL_FILE_HEADER="PK",r.CENTRAL_FILE_HEADER="PK",r.CENTRAL_DIRECTORY_END="PK",r.ZIP64_CENTRAL_DIRECTORY_LOCATOR="PK",r.ZIP64_CENTRAL_DIRECTORY_END="PK",r.DATA_DESCRIPTOR="PK\b"},{}],24:[function(t,e,r){"use strict";var i=t("./GenericWorker"),n=t("../utils");function s(t){i.call(this,"ConvertWorker to "+t),this.destType=t}n.inherits(s,i),s.prototype.processChunk=function(t){this.push({data:n.transformTo(this.destType,t.data),meta:t.meta})},e.exports=s},{"../utils":32,"./GenericWorker":28}],25:[function(t,e,r){"use strict";var i=t("./GenericWorker"),n=t("../crc32");function s(){i.call(this,"Crc32Probe"),this.withStreamInfo("crc32",0)}t("../utils").inherits(s,i),s.prototype.processChunk=function(t){this.streamInfo.crc32=n(t.data,this.streamInfo.crc32||0),this.push(t)},e.exports=s},{"../crc32":4,"../utils":32,"./GenericWorker":28}],26:[function(t,e,r){"use strict";var i=t("../utils"),n=t("./GenericWorker");function s(t){n.call(this,"DataLengthProbe for "+t),this.propName=t,this.withStreamInfo(t,0)}i.inherits(s,n),s.prototype.processChunk=function(t){if(t){var e=this.streamInfo[this.propName]||0;this.streamInfo[this.propName]=e+t.data.length}n.prototype.processChunk.call(this,t)},e.exports=s},{"../utils":32,"./GenericWorker":28}],27:[function(t,e,r){"use strict";var i=t("../utils"),n=t("./GenericWorker");function s(t){n.call(this,"DataWorker");var e=this;this.dataIsReady=!1,this.index=0,this.max=0,this.data=null,this.type="",this._tickScheduled=!1,t.then(function(t){e.dataIsReady=!0,e.data=t,e.max=t&&t.length||0,e.type=i.getTypeOf(t),e.isPaused||e._tickAndRepeat()},function(t){e.error(t)})}i.inherits(s,n),s.prototype.cleanUp=function(){n.prototype.cleanUp.call(this),this.data=null},s.prototype.resume=function(){return!!n.prototype.resume.call(this)&&(!this._tickScheduled&&this.dataIsReady&&(this._tickScheduled=!0,i.delay(this._tickAndRepeat,[],this)),!0)},s.prototype._tickAndRepeat=function(){this._tickScheduled=!1,this.isPaused||this.isFinished||(this._tick(),this.isFinished||(i.delay(this._tickAndRepeat,[],this),this._tickScheduled=!0))},s.prototype._tick=function(){if(this.isPaused||this.isFinished)return!1;var t=null,e=Math.min(this.max,this.index+16384);if(this.index>=this.max)return this.end();switch(this.type){case"string":t=this.data.substring(this.index,e);break;case"uint8array":t=this.data.subarray(this.index,e);break;case"array":case"nodebuffer":t=this.data.slice(this.index,e)}return this.index=e,this.push({data:t,meta:{percent:this.max?this.index/this.max*100:0}})},e.exports=s},{"../utils":32,"./GenericWorker":28}],28:[function(t,e,r){"use strict";function i(t){this.name=t||"default",this.streamInfo={},this.generatedError=null,this.extraStreamInfo={},this.isPaused=!0,this.isFinished=!1,this.isLocked=!1,this._listeners={data:[],end:[],error:[]},this.previous=null}i.prototype={push:function(t){this.emit("data",t)},end:function(){if(this.isFinished)return!1;this.flush();try{this.emit("end"),this.cleanUp(),this.isFinished=!0}catch(t){this.emit("error",t)}return!0},error:function(t){return!this.isFinished&&(this.isPaused?this.generatedError=t:(this.isFinished=!0,this.emit("error",t),this.previous&&this.previous.error(t),this.cleanUp()),!0)},on:function(t,e){return this._listeners[t].push(e),this},cleanUp:function(){this.streamInfo=this.generatedError=this.extraStreamInfo=null,this._listeners=[]},emit:function(t,e){if(this._listeners[t])for(var r=0;r "+t:t}},e.exports=i},{}],29:[function(t,e,r){"use strict";var h=t("../utils"),n=t("./ConvertWorker"),s=t("./GenericWorker"),u=t("../base64"),i=t("../support"),a=t("../external"),o=null;if(i.nodestream)try{o=t("../nodejs/NodejsStreamOutputAdapter")}catch(t){}function l(t,e,r){var i=e;switch(e){case"blob":case"arraybuffer":i="uint8array";break;case"base64":i="string"}try{this._internalType=i,this._outputType=e,this._mimeType=r,h.checkSupport(i),this._worker=t.pipe(new n(i)),t.lock()}catch(t){this._worker=new s("error"),this._worker.error(t)}}l.prototype={accumulate:function(t){return function(t,o){return new a.Promise(function(e,r){var i=[],n=t._internalType,s=t._outputType,a=t._mimeType;t.on("data",function(t,e){i.push(t),o&&o(e)}).on("error",function(t){i=[],r(t)}).on("end",function(){try{var t=function(t,e,r){switch(t){case"blob":return h.newBlob(h.transformTo("arraybuffer",e),r);case"base64":return u.encode(e);default:return h.transformTo(t,e)}}(s,function(t,e){var r,i=0,n=null,s=0;for(r=0;r>>6:(r<65536?e[s++]=224|r>>>12:(e[s++]=240|r>>>18,e[s++]=128|r>>>12&63),e[s++]=128|r>>>6&63),e[s++]=128|63&r);return e}(t)},s.utf8decode=function(t){return h.nodebuffer?o.transformTo("nodebuffer",t).toString("utf-8"):function(t){var e,r,i,n,s=t.length,a=new Array(2*s);for(e=r=0;e>10&1023,a[r++]=56320|1023&i)}return a.length!==r&&(a.subarray?a=a.subarray(0,r):a.length=r),o.applyFromCharCode(a)}(t=o.transformTo(h.uint8array?"uint8array":"array",t))},o.inherits(a,i),a.prototype.processChunk=function(t){var e=o.transformTo(h.uint8array?"uint8array":"array",t.data);if(this.leftOver&&this.leftOver.length){if(h.uint8array){var r=e;(e=new Uint8Array(r.length+this.leftOver.length)).set(this.leftOver,0),e.set(r,this.leftOver.length)}else e=this.leftOver.concat(e);this.leftOver=null}var i=function(t,e){var r;for((e=e||t.length)>t.length&&(e=t.length),r=e-1;0<=r&&128==(192&t[r]);)r--;return r<0?e:0===r?e:r+u[t[r]]>e?r:e}(e),n=e;i!==e.length&&(h.uint8array?(n=e.subarray(0,i),this.leftOver=e.subarray(i,e.length)):(n=e.slice(0,i),this.leftOver=e.slice(i,e.length))),this.push({data:s.utf8decode(n),meta:t.meta})},a.prototype.flush=function(){this.leftOver&&this.leftOver.length&&(this.push({data:s.utf8decode(this.leftOver),meta:{}}),this.leftOver=null)},s.Utf8DecodeWorker=a,o.inherits(l,i),l.prototype.processChunk=function(t){this.push({data:s.utf8encode(t.data),meta:t.meta})},s.Utf8EncodeWorker=l},{"./nodejsUtils":14,"./stream/GenericWorker":28,"./support":30,"./utils":32}],32:[function(t,e,o){"use strict";var h=t("./support"),u=t("./base64"),r=t("./nodejsUtils"),i=t("set-immediate-shim"),l=t("./external");function n(t){return t}function f(t,e){for(var r=0;r>8;this.dir=!!(16&this.externalFileAttributes),0==t&&(this.dosPermissions=63&this.externalFileAttributes),3==t&&(this.unixPermissions=this.externalFileAttributes>>16&65535),this.dir||"/"!==this.fileNameStr.slice(-1)||(this.dir=!0)},parseZIP64ExtraField:function(t){if(this.extraFields[1]){var e=i(this.extraFields[1].value);this.uncompressedSize===s.MAX_VALUE_32BITS&&(this.uncompressedSize=e.readInt(8)),this.compressedSize===s.MAX_VALUE_32BITS&&(this.compressedSize=e.readInt(8)),this.localHeaderOffset===s.MAX_VALUE_32BITS&&(this.localHeaderOffset=e.readInt(8)),this.diskNumberStart===s.MAX_VALUE_32BITS&&(this.diskNumberStart=e.readInt(4))}},readExtraFields:function(t){var e,r,i,n=t.index+this.extraFieldsLength;for(this.extraFields||(this.extraFields={});t.index+4>>6:(r<65536?e[s++]=224|r>>>12:(e[s++]=240|r>>>18,e[s++]=128|r>>>12&63),e[s++]=128|r>>>6&63),e[s++]=128|63&r);return e},r.buf2binstring=function(t){return l(t,t.length)},r.binstring2buf=function(t){for(var e=new h.Buf8(t.length),r=0,i=e.length;r>10&1023,o[i++]=56320|1023&n)}return l(o,i)},r.utf8border=function(t,e){var r;for((e=e||t.length)>t.length&&(e=t.length),r=e-1;0<=r&&128==(192&t[r]);)r--;return r<0?e:0===r?e:r+u[t[r]]>e?r:e}},{"./common":41}],43:[function(t,e,r){"use strict";e.exports=function(t,e,r,i){for(var n=65535&t|0,s=t>>>16&65535|0,a=0;0!==r;){for(r-=a=2e3>>1:t>>>1;e[r]=t}return e}();e.exports=function(t,e,r,i){var n=o,s=i+r;t^=-1;for(var a=i;a>>8^n[255&(t^e[a])];return-1^t}},{}],46:[function(t,e,r){"use strict";var h,d=t("../utils/common"),u=t("./trees"),c=t("./adler32"),p=t("./crc32"),i=t("./messages"),l=0,f=0,m=-2,n=2,_=8,s=286,a=30,o=19,g=2*s+1,b=15,v=3,y=258,w=y+v+1,k=42,x=113;function S(t,e){return t.msg=i[e],e}function z(t){return(t<<1)-(4t.avail_out&&(r=t.avail_out),0!==r&&(d.arraySet(t.output,e.pending_buf,e.pending_out,r,t.next_out),t.next_out+=r,e.pending_out+=r,t.total_out+=r,t.avail_out-=r,e.pending-=r,0===e.pending&&(e.pending_out=0))}function A(t,e){u._tr_flush_block(t,0<=t.block_start?t.block_start:-1,t.strstart-t.block_start,e),t.block_start=t.strstart,E(t.strm)}function I(t,e){t.pending_buf[t.pending++]=e}function O(t,e){t.pending_buf[t.pending++]=e>>>8&255,t.pending_buf[t.pending++]=255&e}function B(t,e){var r,i,n=t.max_chain_length,s=t.strstart,a=t.prev_length,o=t.nice_match,h=t.strstart>t.w_size-w?t.strstart-(t.w_size-w):0,u=t.window,l=t.w_mask,f=t.prev,d=t.strstart+y,c=u[s+a-1],p=u[s+a];t.prev_length>=t.good_match&&(n>>=2),o>t.lookahead&&(o=t.lookahead);do{if(u[(r=e)+a]===p&&u[r+a-1]===c&&u[r]===u[s]&&u[++r]===u[s+1]){s+=2,r++;do{}while(u[++s]===u[++r]&&u[++s]===u[++r]&&u[++s]===u[++r]&&u[++s]===u[++r]&&u[++s]===u[++r]&&u[++s]===u[++r]&&u[++s]===u[++r]&&u[++s]===u[++r]&&sh&&0!=--n);return a<=t.lookahead?a:t.lookahead}function R(t){var e,r,i,n,s,a,o,h,u,l,f=t.w_size;do{if(n=t.window_size-t.lookahead-t.strstart,t.strstart>=f+(f-w)){for(d.arraySet(t.window,t.window,f,f,0),t.match_start-=f,t.strstart-=f,t.block_start-=f,e=r=t.hash_size;i=t.head[--e],t.head[e]=f<=i?i-f:0,--r;);for(e=r=f;i=t.prev[--e],t.prev[e]=f<=i?i-f:0,--r;);n+=f}if(0===t.strm.avail_in)break;if(a=t.strm,o=t.window,h=t.strstart+t.lookahead,l=void 0,(u=n)<(l=a.avail_in)&&(l=u),r=0===l?0:(a.avail_in-=l,d.arraySet(o,a.input,a.next_in,l,h),1===a.state.wrap?a.adler=c(a.adler,o,l,h):2===a.state.wrap&&(a.adler=p(a.adler,o,l,h)),a.next_in+=l,a.total_in+=l,l),t.lookahead+=r,t.lookahead+t.insert>=v)for(s=t.strstart-t.insert,t.ins_h=t.window[s],t.ins_h=(t.ins_h<=v&&(t.ins_h=(t.ins_h<=v)if(i=u._tr_tally(t,t.strstart-t.match_start,t.match_length-v),t.lookahead-=t.match_length,t.match_length<=t.max_lazy_match&&t.lookahead>=v){for(t.match_length--;t.strstart++,t.ins_h=(t.ins_h<=v&&(t.ins_h=(t.ins_h<=v&&t.match_length<=t.prev_length){for(n=t.strstart+t.lookahead-v,i=u._tr_tally(t,t.strstart-1-t.prev_match,t.prev_length-v),t.lookahead-=t.prev_length-1,t.prev_length-=2;++t.strstart<=n&&(t.ins_h=(t.ins_h<t.pending_buf_size-5&&(r=t.pending_buf_size-5);;){if(t.lookahead<=1){if(R(t),0===t.lookahead&&e===l)return 1;if(0===t.lookahead)break}t.strstart+=t.lookahead,t.lookahead=0;var i=t.block_start+r;if((0===t.strstart||t.strstart>=i)&&(t.lookahead=t.strstart-i,t.strstart=i,A(t,!1),0===t.strm.avail_out))return 1;if(t.strstart-t.block_start>=t.w_size-w&&(A(t,!1),0===t.strm.avail_out))return 1}return t.insert=0,4===e?(A(t,!0),0===t.strm.avail_out?3:4):(t.strstart>t.block_start&&(A(t,!1),t.strm.avail_out),1)}),new F(4,4,8,4,T),new F(4,5,16,8,T),new F(4,6,32,32,T),new F(4,4,16,16,D),new F(8,16,32,32,D),new F(8,16,128,128,D),new F(8,32,128,256,D),new F(32,128,258,1024,D),new F(32,258,258,4096,D)],r.deflateInit=function(t,e){return L(t,e,_,15,8,0)},r.deflateInit2=L,r.deflateReset=P,r.deflateResetKeep=U,r.deflateSetHeader=function(t,e){return t&&t.state?2!==t.state.wrap?m:(t.state.gzhead=e,f):m},r.deflate=function(t,e){var r,i,n,s;if(!t||!t.state||5>8&255),I(i,i.gzhead.time>>16&255),I(i,i.gzhead.time>>24&255),I(i,9===i.level?2:2<=i.strategy||i.level<2?4:0),I(i,255&i.gzhead.os),i.gzhead.extra&&i.gzhead.extra.length&&(I(i,255&i.gzhead.extra.length),I(i,i.gzhead.extra.length>>8&255)),i.gzhead.hcrc&&(t.adler=p(t.adler,i.pending_buf,i.pending,0)),i.gzindex=0,i.status=69):(I(i,0),I(i,0),I(i,0),I(i,0),I(i,0),I(i,9===i.level?2:2<=i.strategy||i.level<2?4:0),I(i,3),i.status=x);else{var a=_+(i.w_bits-8<<4)<<8;a|=(2<=i.strategy||i.level<2?0:i.level<6?1:6===i.level?2:3)<<6,0!==i.strstart&&(a|=32),a+=31-a%31,i.status=x,O(i,a),0!==i.strstart&&(O(i,t.adler>>>16),O(i,65535&t.adler)),t.adler=1}if(69===i.status)if(i.gzhead.extra){for(n=i.pending;i.gzindex<(65535&i.gzhead.extra.length)&&(i.pending!==i.pending_buf_size||(i.gzhead.hcrc&&i.pending>n&&(t.adler=p(t.adler,i.pending_buf,i.pending-n,n)),E(t),n=i.pending,i.pending!==i.pending_buf_size));)I(i,255&i.gzhead.extra[i.gzindex]),i.gzindex++;i.gzhead.hcrc&&i.pending>n&&(t.adler=p(t.adler,i.pending_buf,i.pending-n,n)),i.gzindex===i.gzhead.extra.length&&(i.gzindex=0,i.status=73)}else i.status=73;if(73===i.status)if(i.gzhead.name){n=i.pending;do{if(i.pending===i.pending_buf_size&&(i.gzhead.hcrc&&i.pending>n&&(t.adler=p(t.adler,i.pending_buf,i.pending-n,n)),E(t),n=i.pending,i.pending===i.pending_buf_size)){s=1;break}s=i.gzindexn&&(t.adler=p(t.adler,i.pending_buf,i.pending-n,n)),0===s&&(i.gzindex=0,i.status=91)}else i.status=91;if(91===i.status)if(i.gzhead.comment){n=i.pending;do{if(i.pending===i.pending_buf_size&&(i.gzhead.hcrc&&i.pending>n&&(t.adler=p(t.adler,i.pending_buf,i.pending-n,n)),E(t),n=i.pending,i.pending===i.pending_buf_size)){s=1;break}s=i.gzindexn&&(t.adler=p(t.adler,i.pending_buf,i.pending-n,n)),0===s&&(i.status=103)}else i.status=103;if(103===i.status&&(i.gzhead.hcrc?(i.pending+2>i.pending_buf_size&&E(t),i.pending+2<=i.pending_buf_size&&(I(i,255&t.adler),I(i,t.adler>>8&255),t.adler=0,i.status=x)):i.status=x),0!==i.pending){if(E(t),0===t.avail_out)return i.last_flush=-1,f}else if(0===t.avail_in&&z(e)<=z(r)&&4!==e)return S(t,-5);if(666===i.status&&0!==t.avail_in)return S(t,-5);if(0!==t.avail_in||0!==i.lookahead||e!==l&&666!==i.status){var o=2===i.strategy?function(t,e){for(var r;;){if(0===t.lookahead&&(R(t),0===t.lookahead)){if(e===l)return 1;break}if(t.match_length=0,r=u._tr_tally(t,0,t.window[t.strstart]),t.lookahead--,t.strstart++,r&&(A(t,!1),0===t.strm.avail_out))return 1}return t.insert=0,4===e?(A(t,!0),0===t.strm.avail_out?3:4):t.last_lit&&(A(t,!1),0===t.strm.avail_out)?1:2}(i,e):3===i.strategy?function(t,e){for(var r,i,n,s,a=t.window;;){if(t.lookahead<=y){if(R(t),t.lookahead<=y&&e===l)return 1;if(0===t.lookahead)break}if(t.match_length=0,t.lookahead>=v&&0t.lookahead&&(t.match_length=t.lookahead)}if(t.match_length>=v?(r=u._tr_tally(t,1,t.match_length-v),t.lookahead-=t.match_length,t.strstart+=t.match_length,t.match_length=0):(r=u._tr_tally(t,0,t.window[t.strstart]),t.lookahead--,t.strstart++),r&&(A(t,!1),0===t.strm.avail_out))return 1}return t.insert=0,4===e?(A(t,!0),0===t.strm.avail_out?3:4):t.last_lit&&(A(t,!1),0===t.strm.avail_out)?1:2}(i,e):h[i.level].func(i,e);if(3!==o&&4!==o||(i.status=666),1===o||3===o)return 0===t.avail_out&&(i.last_flush=-1),f;if(2===o&&(1===e?u._tr_align(i):5!==e&&(u._tr_stored_block(i,0,0,!1),3===e&&(C(i.head),0===i.lookahead&&(i.strstart=0,i.block_start=0,i.insert=0))),E(t),0===t.avail_out))return i.last_flush=-1,f}return 4!==e?f:i.wrap<=0?1:(2===i.wrap?(I(i,255&t.adler),I(i,t.adler>>8&255),I(i,t.adler>>16&255),I(i,t.adler>>24&255),I(i,255&t.total_in),I(i,t.total_in>>8&255),I(i,t.total_in>>16&255),I(i,t.total_in>>24&255)):(O(i,t.adler>>>16),O(i,65535&t.adler)),E(t),0=r.w_size&&(0===s&&(C(r.head),r.strstart=0,r.block_start=0,r.insert=0),u=new d.Buf8(r.w_size),d.arraySet(u,e,l-r.w_size,r.w_size,0),e=u,l=r.w_size),a=t.avail_in,o=t.next_in,h=t.input,t.avail_in=l,t.next_in=0,t.input=e,R(r);r.lookahead>=v;){for(i=r.strstart,n=r.lookahead-(v-1);r.ins_h=(r.ins_h<>>=y=v>>>24,p-=y,0==(y=v>>>16&255))C[s++]=65535&v;else{if(!(16&y)){if(0==(64&y)){v=m[(65535&v)+(c&(1<>>=y,p-=y),p<15&&(c+=z[i++]<>>=y=v>>>24,p-=y,!(16&(y=v>>>16&255))){if(0==(64&y)){v=_[(65535&v)+(c&(1<>>=y,p-=y,(y=s-a)>3,c&=(1<<(p-=w<<3))-1,t.next_in=i,t.next_out=s,t.avail_in=i>>24&255)+(t>>>8&65280)+((65280&t)<<8)+((255&t)<<24)}function s(){this.mode=0,this.last=!1,this.wrap=0,this.havedict=!1,this.flags=0,this.dmax=0,this.check=0,this.total=0,this.head=null,this.wbits=0,this.wsize=0,this.whave=0,this.wnext=0,this.window=null,this.hold=0,this.bits=0,this.length=0,this.offset=0,this.extra=0,this.lencode=null,this.distcode=null,this.lenbits=0,this.distbits=0,this.ncode=0,this.nlen=0,this.ndist=0,this.have=0,this.next=null,this.lens=new I.Buf16(320),this.work=new I.Buf16(288),this.lendyn=null,this.distdyn=null,this.sane=0,this.back=0,this.was=0}function a(t){var e;return t&&t.state?(e=t.state,t.total_in=t.total_out=e.total=0,t.msg="",e.wrap&&(t.adler=1&e.wrap),e.mode=P,e.last=0,e.havedict=0,e.dmax=32768,e.head=null,e.hold=0,e.bits=0,e.lencode=e.lendyn=new I.Buf32(i),e.distcode=e.distdyn=new I.Buf32(n),e.sane=1,e.back=-1,N):U}function o(t){var e;return t&&t.state?((e=t.state).wsize=0,e.whave=0,e.wnext=0,a(t)):U}function h(t,e){var r,i;return t&&t.state?(i=t.state,e<0?(r=0,e=-e):(r=1+(e>>4),e<48&&(e&=15)),e&&(e<8||15=s.wsize?(I.arraySet(s.window,e,r-s.wsize,s.wsize,0),s.wnext=0,s.whave=s.wsize):(i<(n=s.wsize-s.wnext)&&(n=i),I.arraySet(s.window,e,r-i,n,s.wnext),(i-=n)?(I.arraySet(s.window,e,r-i,i,0),s.wnext=i,s.whave=s.wsize):(s.wnext+=n,s.wnext===s.wsize&&(s.wnext=0),s.whave>>8&255,r.check=B(r.check,E,2,0),l=u=0,r.mode=2;break}if(r.flags=0,r.head&&(r.head.done=!1),!(1&r.wrap)||(((255&u)<<8)+(u>>8))%31){t.msg="incorrect header check",r.mode=30;break}if(8!=(15&u)){t.msg="unknown compression method",r.mode=30;break}if(l-=4,k=8+(15&(u>>>=4)),0===r.wbits)r.wbits=k;else if(k>r.wbits){t.msg="invalid window size",r.mode=30;break}r.dmax=1<>8&1),512&r.flags&&(E[0]=255&u,E[1]=u>>>8&255,r.check=B(r.check,E,2,0)),l=u=0,r.mode=3;case 3:for(;l<32;){if(0===o)break t;o--,u+=i[s++]<>>8&255,E[2]=u>>>16&255,E[3]=u>>>24&255,r.check=B(r.check,E,4,0)),l=u=0,r.mode=4;case 4:for(;l<16;){if(0===o)break t;o--,u+=i[s++]<>8),512&r.flags&&(E[0]=255&u,E[1]=u>>>8&255,r.check=B(r.check,E,2,0)),l=u=0,r.mode=5;case 5:if(1024&r.flags){for(;l<16;){if(0===o)break t;o--,u+=i[s++]<>>8&255,r.check=B(r.check,E,2,0)),l=u=0}else r.head&&(r.head.extra=null);r.mode=6;case 6:if(1024&r.flags&&(o<(c=r.length)&&(c=o),c&&(r.head&&(k=r.head.extra_len-r.length,r.head.extra||(r.head.extra=new Array(r.head.extra_len)),I.arraySet(r.head.extra,i,s,c,k)),512&r.flags&&(r.check=B(r.check,i,c,s)),o-=c,s+=c,r.length-=c),r.length))break t;r.length=0,r.mode=7;case 7:if(2048&r.flags){if(0===o)break t;for(c=0;k=i[s+c++],r.head&&k&&r.length<65536&&(r.head.name+=String.fromCharCode(k)),k&&c>9&1,r.head.done=!0),t.adler=r.check=0,r.mode=12;break;case 10:for(;l<32;){if(0===o)break t;o--,u+=i[s++]<>>=7&l,l-=7&l,r.mode=27;break}for(;l<3;){if(0===o)break t;o--,u+=i[s++]<>>=1)){case 0:r.mode=14;break;case 1:if(j(r),r.mode=20,6!==e)break;u>>>=2,l-=2;break t;case 2:r.mode=17;break;case 3:t.msg="invalid block type",r.mode=30}u>>>=2,l-=2;break;case 14:for(u>>>=7&l,l-=7&l;l<32;){if(0===o)break t;o--,u+=i[s++]<>>16^65535)){t.msg="invalid stored block lengths",r.mode=30;break}if(r.length=65535&u,l=u=0,r.mode=15,6===e)break t;case 15:r.mode=16;case 16:if(c=r.length){if(o>>=5,l-=5,r.ndist=1+(31&u),u>>>=5,l-=5,r.ncode=4+(15&u),u>>>=4,l-=4,286>>=3,l-=3}for(;r.have<19;)r.lens[A[r.have++]]=0;if(r.lencode=r.lendyn,r.lenbits=7,S={bits:r.lenbits},x=T(0,r.lens,0,19,r.lencode,0,r.work,S),r.lenbits=S.bits,x){t.msg="invalid code lengths set",r.mode=30;break}r.have=0,r.mode=19;case 19:for(;r.have>>16&255,b=65535&C,!((_=C>>>24)<=l);){if(0===o)break t;o--,u+=i[s++]<>>=_,l-=_,r.lens[r.have++]=b;else{if(16===b){for(z=_+2;l>>=_,l-=_,0===r.have){t.msg="invalid bit length repeat",r.mode=30;break}k=r.lens[r.have-1],c=3+(3&u),u>>>=2,l-=2}else if(17===b){for(z=_+3;l>>=_)),u>>>=3,l-=3}else{for(z=_+7;l>>=_)),u>>>=7,l-=7}if(r.have+c>r.nlen+r.ndist){t.msg="invalid bit length repeat",r.mode=30;break}for(;c--;)r.lens[r.have++]=k}}if(30===r.mode)break;if(0===r.lens[256]){t.msg="invalid code -- missing end-of-block",r.mode=30;break}if(r.lenbits=9,S={bits:r.lenbits},x=T(D,r.lens,0,r.nlen,r.lencode,0,r.work,S),r.lenbits=S.bits,x){t.msg="invalid literal/lengths set",r.mode=30;break}if(r.distbits=6,r.distcode=r.distdyn,S={bits:r.distbits},x=T(F,r.lens,r.nlen,r.ndist,r.distcode,0,r.work,S),r.distbits=S.bits,x){t.msg="invalid distances set",r.mode=30;break}if(r.mode=20,6===e)break t;case 20:r.mode=21;case 21:if(6<=o&&258<=h){t.next_out=a,t.avail_out=h,t.next_in=s,t.avail_in=o,r.hold=u,r.bits=l,R(t,d),a=t.next_out,n=t.output,h=t.avail_out,s=t.next_in,i=t.input,o=t.avail_in,u=r.hold,l=r.bits,12===r.mode&&(r.back=-1);break}for(r.back=0;g=(C=r.lencode[u&(1<>>16&255,b=65535&C,!((_=C>>>24)<=l);){if(0===o)break t;o--,u+=i[s++]<>v)])>>>16&255,b=65535&C,!(v+(_=C>>>24)<=l);){if(0===o)break t;o--,u+=i[s++]<>>=v,l-=v,r.back+=v}if(u>>>=_,l-=_,r.back+=_,r.length=b,0===g){r.mode=26;break}if(32&g){r.back=-1,r.mode=12;break}if(64&g){t.msg="invalid literal/length code",r.mode=30;break}r.extra=15&g,r.mode=22;case 22:if(r.extra){for(z=r.extra;l>>=r.extra,l-=r.extra,r.back+=r.extra}r.was=r.length,r.mode=23;case 23:for(;g=(C=r.distcode[u&(1<>>16&255,b=65535&C,!((_=C>>>24)<=l);){if(0===o)break t;o--,u+=i[s++]<>v)])>>>16&255,b=65535&C,!(v+(_=C>>>24)<=l);){if(0===o)break t;o--,u+=i[s++]<>>=v,l-=v,r.back+=v}if(u>>>=_,l-=_,r.back+=_,64&g){t.msg="invalid distance code",r.mode=30;break}r.offset=b,r.extra=15&g,r.mode=24;case 24:if(r.extra){for(z=r.extra;l>>=r.extra,l-=r.extra,r.back+=r.extra}if(r.offset>r.dmax){t.msg="invalid distance too far back",r.mode=30;break}r.mode=25;case 25:if(0===h)break t;if(c=d-h,r.offset>c){if((c=r.offset-c)>r.whave&&r.sane){t.msg="invalid distance too far back",r.mode=30;break}p=c>r.wnext?(c-=r.wnext,r.wsize-c):r.wnext-c,c>r.length&&(c=r.length),m=r.window}else m=n,p=a-r.offset,c=r.length;for(hc?(m=R[T+a[v]],A[I+a[v]]):(m=96,0),h=1<>S)+(u-=h)]=p<<24|m<<16|_|0,0!==u;);for(h=1<>=1;if(0!==h?(E&=h-1,E+=h):E=0,v++,0==--O[b]){if(b===w)break;b=e[r+a[v]]}if(k>>7)]}function x(t,e){t.pending_buf[t.pending++]=255&e,t.pending_buf[t.pending++]=e>>>8&255}function S(t,e,r){t.bi_valid>n-r?(t.bi_buf|=e<>n-t.bi_valid,t.bi_valid+=r-n):(t.bi_buf|=e<>>=1,r<<=1,0<--e;);return r>>>1}function E(t,e,r){var i,n,s=new Array(_+1),a=0;for(i=1;i<=_;i++)s[i]=a=a+r[i-1]<<1;for(n=0;n<=e;n++){var o=t[2*n+1];0!==o&&(t[2*n]=C(s[o]++,o))}}function A(t){var e;for(e=0;e<286;e++)t.dyn_ltree[2*e]=0;for(e=0;e<30;e++)t.dyn_dtree[2*e]=0;for(e=0;e<19;e++)t.bl_tree[2*e]=0;t.dyn_ltree[512]=1,t.opt_len=t.static_len=0,t.last_lit=t.matches=0}function I(t){8>1;1<=r;r--)B(t,s,r);for(n=h;r=t.heap[1],t.heap[1]=t.heap[t.heap_len--],B(t,s,1),i=t.heap[1],t.heap[--t.heap_max]=r,t.heap[--t.heap_max]=i,s[2*n]=s[2*r]+s[2*i],t.depth[n]=(t.depth[r]>=t.depth[i]?t.depth[r]:t.depth[i])+1,s[2*r+1]=s[2*i+1]=n,t.heap[1]=n++,B(t,s,1),2<=t.heap_len;);t.heap[--t.heap_max]=t.heap[1],function(t,e){var r,i,n,s,a,o,h=e.dyn_tree,u=e.max_code,l=e.stat_desc.static_tree,f=e.stat_desc.has_stree,d=e.stat_desc.extra_bits,c=e.stat_desc.extra_base,p=e.stat_desc.max_length,m=0;for(s=0;s<=_;s++)t.bl_count[s]=0;for(h[2*t.heap[t.heap_max]+1]=0,r=t.heap_max+1;r<573;r++)p<(s=h[2*h[2*(i=t.heap[r])+1]+1]+1)&&(s=p,m++),h[2*i+1]=s,u>=7;i<30;i++)for(y[i]=n<<7,t=0;t<1<>>=1)if(1&r&&0!==t.dyn_ltree[2*e])return 0;if(0!==t.dyn_ltree[18]||0!==t.dyn_ltree[20]||0!==t.dyn_ltree[26])return 1;for(e=32;e<256;e++)if(0!==t.dyn_ltree[2*e])return 1;return 0}(t)),T(t,t.l_desc),T(t,t.d_desc),a=function(t){var e;for(D(t,t.dyn_ltree,t.l_desc.max_code),D(t,t.dyn_dtree,t.d_desc.max_code),T(t,t.bl_desc),e=18;3<=e&&0===t.bl_tree[2*l[e]+1];e--);return t.opt_len+=3*(e+1)+5+5+4,e}(t),n=t.opt_len+3+7>>>3,(s=t.static_len+3+7>>>3)<=n&&(n=s)):n=s=r+5,r+4<=n&&-1!==e?U(t,e,r,i):4===t.strategy||s===n?(S(t,2+(i?1:0),3),R(t,f,d)):(S(t,4+(i?1:0),3),function(t,e,r,i){var n;for(S(t,e-257,5),S(t,r-1,5),S(t,i-4,4),n=0;n>>8&255,t.pending_buf[t.d_buf+2*t.last_lit+1]=255&e,t.pending_buf[t.l_buf+t.last_lit]=255&r,t.last_lit++,0===e?t.dyn_ltree[2*r]++:(t.matches++,e--,t.dyn_ltree[2*(p[r]+256+1)]++,t.dyn_dtree[2*k(e)]++),t.last_lit===t.lit_bufsize-1},r._tr_align=function(t){var e;S(t,2,3),z(t,256,f),16===(e=t).bi_valid?(x(e,e.bi_buf),e.bi_buf=0,e.bi_valid=0):8<=e.bi_valid&&(e.pending_buf[e.pending++]=255&e.bi_buf,e.bi_buf>>=8,e.bi_valid-=8)}},{"../utils/common":41}],53:[function(t,e,r){"use strict";e.exports=function(){this.input=null,this.next_in=0,this.avail_in=0,this.total_in=0,this.output=null,this.next_out=0,this.avail_out=0,this.total_out=0,this.msg="",this.state=null,this.data_type=2,this.adler=0}},{}],54:[function(t,e,r){"use strict";e.exports="function"==typeof setImmediate?setImmediate:function(){var t=[].slice.apply(arguments);t.splice(1,0,0),setTimeout.apply(null,t)}},{}]},{},[10])(10)})}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}]},{},[1])(1)}); -}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{}]},{},[1])(1) -}); \ No newline at end of file diff --git a/boomerangScope-SootUp/target/apidocs/jquery/jszip/dist/jszip.min.js b/boomerangScope-SootUp/target/apidocs/jquery/jszip/dist/jszip.min.js deleted file mode 100644 index c6ae9ad82..000000000 --- a/boomerangScope-SootUp/target/apidocs/jquery/jszip/dist/jszip.min.js +++ /dev/null @@ -1,13 +0,0 @@ -/*! - -JSZip v3.7.1 - A JavaScript class for generating and reading zip files - - -(c) 2009-2016 Stuart Knightley -Dual licenced under the MIT license or GPLv3. See https://raw.github.com/Stuk/jszip/master/LICENSE.markdown. - -JSZip uses the library pako released under the MIT license : -https://github.com/nodeca/pako/blob/master/LICENSE -*/ - -!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{("undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this).JSZip=e()}}(function(){return function s(a,o,h){function u(r,e){if(!o[r]){if(!a[r]){var t="function"==typeof require&&require;if(!e&&t)return t(r,!0);if(l)return l(r,!0);var n=new Error("Cannot find module '"+r+"'");throw n.code="MODULE_NOT_FOUND",n}var i=o[r]={exports:{}};a[r][0].call(i.exports,function(e){var t=a[r][1][e];return u(t||e)},i,i.exports,s,a,o,h)}return o[r].exports}for(var l="function"==typeof require&&require,e=0;e>2,s=(3&t)<<4|r>>4,a=1>6:64,o=2>4,r=(15&i)<<4|(s=p.indexOf(e.charAt(o++)))>>2,n=(3&s)<<6|(a=p.indexOf(e.charAt(o++))),u[h++]=t,64!==s&&(u[h++]=r),64!==a&&(u[h++]=n);return u}},{"./support":30,"./utils":32}],2:[function(e,t,r){"use strict";var n=e("./external"),i=e("./stream/DataWorker"),s=e("./stream/Crc32Probe"),a=e("./stream/DataLengthProbe");function o(e,t,r,n,i){this.compressedSize=e,this.uncompressedSize=t,this.crc32=r,this.compression=n,this.compressedContent=i}o.prototype={getContentWorker:function(){var e=new i(n.Promise.resolve(this.compressedContent)).pipe(this.compression.uncompressWorker()).pipe(new a("data_length")),t=this;return e.on("end",function(){if(this.streamInfo.data_length!==t.uncompressedSize)throw new Error("Bug : uncompressed data size mismatch")}),e},getCompressedWorker:function(){return new i(n.Promise.resolve(this.compressedContent)).withStreamInfo("compressedSize",this.compressedSize).withStreamInfo("uncompressedSize",this.uncompressedSize).withStreamInfo("crc32",this.crc32).withStreamInfo("compression",this.compression)}},o.createWorkerFrom=function(e,t,r){return e.pipe(new s).pipe(new a("uncompressedSize")).pipe(t.compressWorker(r)).pipe(new a("compressedSize")).withStreamInfo("compression",t)},t.exports=o},{"./external":6,"./stream/Crc32Probe":25,"./stream/DataLengthProbe":26,"./stream/DataWorker":27}],3:[function(e,t,r){"use strict";var n=e("./stream/GenericWorker");r.STORE={magic:"\0\0",compressWorker:function(e){return new n("STORE compression")},uncompressWorker:function(){return new n("STORE decompression")}},r.DEFLATE=e("./flate")},{"./flate":7,"./stream/GenericWorker":28}],4:[function(e,t,r){"use strict";var n=e("./utils"),a=function(){for(var e,t=[],r=0;r<256;r++){e=r;for(var n=0;n<8;n++)e=1&e?3988292384^e>>>1:e>>>1;t[r]=e}return t}();t.exports=function(e,t){return void 0!==e&&e.length?"string"!==n.getTypeOf(e)?function(e,t,r){var n=a,i=0+r;e^=-1;for(var s=0;s>>8^n[255&(e^t[s])];return-1^e}(0|t,e,e.length):function(e,t,r){var n=a,i=0+r;e^=-1;for(var s=0;s>>8^n[255&(e^t.charCodeAt(s))];return-1^e}(0|t,e,e.length):0}},{"./utils":32}],5:[function(e,t,r){"use strict";r.base64=!1,r.binary=!1,r.dir=!1,r.createFolders=!0,r.date=null,r.compression=null,r.compressionOptions=null,r.comment=null,r.unixPermissions=null,r.dosPermissions=null},{}],6:[function(e,t,r){"use strict";var n;n="undefined"!=typeof Promise?Promise:e("lie"),t.exports={Promise:n}},{lie:37}],7:[function(e,t,r){"use strict";var n="undefined"!=typeof Uint8Array&&"undefined"!=typeof Uint16Array&&"undefined"!=typeof Uint32Array,i=e("pako"),s=e("./utils"),a=e("./stream/GenericWorker"),o=n?"uint8array":"array";function h(e,t){a.call(this,"FlateWorker/"+e),this._pako=null,this._pakoAction=e,this._pakoOptions=t,this.meta={}}r.magic="\b\0",s.inherits(h,a),h.prototype.processChunk=function(e){this.meta=e.meta,null===this._pako&&this._createPako(),this._pako.push(s.transformTo(o,e.data),!1)},h.prototype.flush=function(){a.prototype.flush.call(this),null===this._pako&&this._createPako(),this._pako.push([],!0)},h.prototype.cleanUp=function(){a.prototype.cleanUp.call(this),this._pako=null},h.prototype._createPako=function(){this._pako=new i[this._pakoAction]({raw:!0,level:this._pakoOptions.level||-1});var t=this;this._pako.onData=function(e){t.push({data:e,meta:t.meta})}},r.compressWorker=function(e){return new h("Deflate",e)},r.uncompressWorker=function(){return new h("Inflate",{})}},{"./stream/GenericWorker":28,"./utils":32,pako:38}],8:[function(e,t,r){"use strict";function I(e,t){var r,n="";for(r=0;r>>=8;return n}function i(e,t,r,n,i,s){var a,o,h=e.file,u=e.compression,l=s!==B.utf8encode,f=O.transformTo("string",s(h.name)),d=O.transformTo("string",B.utf8encode(h.name)),c=h.comment,p=O.transformTo("string",s(c)),m=O.transformTo("string",B.utf8encode(c)),_=d.length!==h.name.length,g=m.length!==c.length,b="",v="",y="",w=h.dir,k=h.date,x={crc32:0,compressedSize:0,uncompressedSize:0};t&&!r||(x.crc32=e.crc32,x.compressedSize=e.compressedSize,x.uncompressedSize=e.uncompressedSize);var S=0;t&&(S|=8),l||!_&&!g||(S|=2048);var z,C=0,E=0;w&&(C|=16),"UNIX"===i?(E=798,C|=((z=h.unixPermissions)||(z=w?16893:33204),(65535&z)<<16)):(E=20,C|=63&(h.dosPermissions||0)),a=k.getUTCHours(),a<<=6,a|=k.getUTCMinutes(),a<<=5,a|=k.getUTCSeconds()/2,o=k.getUTCFullYear()-1980,o<<=4,o|=k.getUTCMonth()+1,o<<=5,o|=k.getUTCDate(),_&&(b+="up"+I((v=I(1,1)+I(R(f),4)+d).length,2)+v),g&&(b+="uc"+I((y=I(1,1)+I(R(p),4)+m).length,2)+y);var A="";return A+="\n\0",A+=I(S,2),A+=u.magic,A+=I(a,2),A+=I(o,2),A+=I(x.crc32,4),A+=I(x.compressedSize,4),A+=I(x.uncompressedSize,4),A+=I(f.length,2),A+=I(b.length,2),{fileRecord:T.LOCAL_FILE_HEADER+A+f+b,dirRecord:T.CENTRAL_FILE_HEADER+I(E,2)+A+I(p.length,2)+"\0\0\0\0"+I(C,4)+I(n,4)+f+b+p}}var O=e("../utils"),s=e("../stream/GenericWorker"),B=e("../utf8"),R=e("../crc32"),T=e("../signature");function n(e,t,r,n){s.call(this,"ZipFileWorker"),this.bytesWritten=0,this.zipComment=t,this.zipPlatform=r,this.encodeFileName=n,this.streamFiles=e,this.accumulate=!1,this.contentBuffer=[],this.dirRecords=[],this.currentSourceOffset=0,this.entriesCount=0,this.currentFile=null,this._sources=[]}O.inherits(n,s),n.prototype.push=function(e){var t=e.meta.percent||0,r=this.entriesCount,n=this._sources.length;this.accumulate?this.contentBuffer.push(e):(this.bytesWritten+=e.data.length,s.prototype.push.call(this,{data:e.data,meta:{currentFile:this.currentFile,percent:r?(t+100*(r-n-1))/r:100}}))},n.prototype.openedSource=function(e){this.currentSourceOffset=this.bytesWritten,this.currentFile=e.file.name;var t=this.streamFiles&&!e.file.dir;if(t){var r=i(e,t,!1,this.currentSourceOffset,this.zipPlatform,this.encodeFileName);this.push({data:r.fileRecord,meta:{percent:0}})}else this.accumulate=!0},n.prototype.closedSource=function(e){this.accumulate=!1;var t,r=this.streamFiles&&!e.file.dir,n=i(e,r,!0,this.currentSourceOffset,this.zipPlatform,this.encodeFileName);if(this.dirRecords.push(n.dirRecord),r)this.push({data:(t=e,T.DATA_DESCRIPTOR+I(t.crc32,4)+I(t.compressedSize,4)+I(t.uncompressedSize,4)),meta:{percent:100}});else for(this.push({data:n.fileRecord,meta:{percent:0}});this.contentBuffer.length;)this.push(this.contentBuffer.shift());this.currentFile=null},n.prototype.flush=function(){for(var e=this.bytesWritten,t=0;t=this.index;t--)r=(r<<8)+this.byteAt(t);return this.index+=e,r},readString:function(e){return n.transformTo("string",this.readData(e))},readData:function(e){},lastIndexOfSignature:function(e){},readAndCheckSignature:function(e){},readDate:function(){var e=this.readInt(4);return new Date(Date.UTC(1980+(e>>25&127),(e>>21&15)-1,e>>16&31,e>>11&31,e>>5&63,(31&e)<<1))}},t.exports=i},{"../utils":32}],19:[function(e,t,r){"use strict";var n=e("./Uint8ArrayReader");function i(e){n.call(this,e)}e("../utils").inherits(i,n),i.prototype.readData=function(e){this.checkOffset(e);var t=this.data.slice(this.zero+this.index,this.zero+this.index+e);return this.index+=e,t},t.exports=i},{"../utils":32,"./Uint8ArrayReader":21}],20:[function(e,t,r){"use strict";var n=e("./DataReader");function i(e){n.call(this,e)}e("../utils").inherits(i,n),i.prototype.byteAt=function(e){return this.data.charCodeAt(this.zero+e)},i.prototype.lastIndexOfSignature=function(e){return this.data.lastIndexOf(e)-this.zero},i.prototype.readAndCheckSignature=function(e){return e===this.readData(4)},i.prototype.readData=function(e){this.checkOffset(e);var t=this.data.slice(this.zero+this.index,this.zero+this.index+e);return this.index+=e,t},t.exports=i},{"../utils":32,"./DataReader":18}],21:[function(e,t,r){"use strict";var n=e("./ArrayReader");function i(e){n.call(this,e)}e("../utils").inherits(i,n),i.prototype.readData=function(e){if(this.checkOffset(e),0===e)return new Uint8Array(0);var t=this.data.subarray(this.zero+this.index,this.zero+this.index+e);return this.index+=e,t},t.exports=i},{"../utils":32,"./ArrayReader":17}],22:[function(e,t,r){"use strict";var n=e("../utils"),i=e("../support"),s=e("./ArrayReader"),a=e("./StringReader"),o=e("./NodeBufferReader"),h=e("./Uint8ArrayReader");t.exports=function(e){var t=n.getTypeOf(e);return n.checkSupport(t),"string"!==t||i.uint8array?"nodebuffer"===t?new o(e):i.uint8array?new h(n.transformTo("uint8array",e)):new s(n.transformTo("array",e)):new a(e)}},{"../support":30,"../utils":32,"./ArrayReader":17,"./NodeBufferReader":19,"./StringReader":20,"./Uint8ArrayReader":21}],23:[function(e,t,r){"use strict";r.LOCAL_FILE_HEADER="PK",r.CENTRAL_FILE_HEADER="PK",r.CENTRAL_DIRECTORY_END="PK",r.ZIP64_CENTRAL_DIRECTORY_LOCATOR="PK",r.ZIP64_CENTRAL_DIRECTORY_END="PK",r.DATA_DESCRIPTOR="PK\b"},{}],24:[function(e,t,r){"use strict";var n=e("./GenericWorker"),i=e("../utils");function s(e){n.call(this,"ConvertWorker to "+e),this.destType=e}i.inherits(s,n),s.prototype.processChunk=function(e){this.push({data:i.transformTo(this.destType,e.data),meta:e.meta})},t.exports=s},{"../utils":32,"./GenericWorker":28}],25:[function(e,t,r){"use strict";var n=e("./GenericWorker"),i=e("../crc32");function s(){n.call(this,"Crc32Probe"),this.withStreamInfo("crc32",0)}e("../utils").inherits(s,n),s.prototype.processChunk=function(e){this.streamInfo.crc32=i(e.data,this.streamInfo.crc32||0),this.push(e)},t.exports=s},{"../crc32":4,"../utils":32,"./GenericWorker":28}],26:[function(e,t,r){"use strict";var n=e("../utils"),i=e("./GenericWorker");function s(e){i.call(this,"DataLengthProbe for "+e),this.propName=e,this.withStreamInfo(e,0)}n.inherits(s,i),s.prototype.processChunk=function(e){if(e){var t=this.streamInfo[this.propName]||0;this.streamInfo[this.propName]=t+e.data.length}i.prototype.processChunk.call(this,e)},t.exports=s},{"../utils":32,"./GenericWorker":28}],27:[function(e,t,r){"use strict";var n=e("../utils"),i=e("./GenericWorker");function s(e){i.call(this,"DataWorker");var t=this;this.dataIsReady=!1,this.index=0,this.max=0,this.data=null,this.type="",this._tickScheduled=!1,e.then(function(e){t.dataIsReady=!0,t.data=e,t.max=e&&e.length||0,t.type=n.getTypeOf(e),t.isPaused||t._tickAndRepeat()},function(e){t.error(e)})}n.inherits(s,i),s.prototype.cleanUp=function(){i.prototype.cleanUp.call(this),this.data=null},s.prototype.resume=function(){return!!i.prototype.resume.call(this)&&(!this._tickScheduled&&this.dataIsReady&&(this._tickScheduled=!0,n.delay(this._tickAndRepeat,[],this)),!0)},s.prototype._tickAndRepeat=function(){this._tickScheduled=!1,this.isPaused||this.isFinished||(this._tick(),this.isFinished||(n.delay(this._tickAndRepeat,[],this),this._tickScheduled=!0))},s.prototype._tick=function(){if(this.isPaused||this.isFinished)return!1;var e=null,t=Math.min(this.max,this.index+16384);if(this.index>=this.max)return this.end();switch(this.type){case"string":e=this.data.substring(this.index,t);break;case"uint8array":e=this.data.subarray(this.index,t);break;case"array":case"nodebuffer":e=this.data.slice(this.index,t)}return this.index=t,this.push({data:e,meta:{percent:this.max?this.index/this.max*100:0}})},t.exports=s},{"../utils":32,"./GenericWorker":28}],28:[function(e,t,r){"use strict";function n(e){this.name=e||"default",this.streamInfo={},this.generatedError=null,this.extraStreamInfo={},this.isPaused=!0,this.isFinished=!1,this.isLocked=!1,this._listeners={data:[],end:[],error:[]},this.previous=null}n.prototype={push:function(e){this.emit("data",e)},end:function(){if(this.isFinished)return!1;this.flush();try{this.emit("end"),this.cleanUp(),this.isFinished=!0}catch(e){this.emit("error",e)}return!0},error:function(e){return!this.isFinished&&(this.isPaused?this.generatedError=e:(this.isFinished=!0,this.emit("error",e),this.previous&&this.previous.error(e),this.cleanUp()),!0)},on:function(e,t){return this._listeners[e].push(t),this},cleanUp:function(){this.streamInfo=this.generatedError=this.extraStreamInfo=null,this._listeners=[]},emit:function(e,t){if(this._listeners[e])for(var r=0;r "+e:e}},t.exports=n},{}],29:[function(e,t,r){"use strict";var u=e("../utils"),i=e("./ConvertWorker"),s=e("./GenericWorker"),l=e("../base64"),n=e("../support"),a=e("../external"),o=null;if(n.nodestream)try{o=e("../nodejs/NodejsStreamOutputAdapter")}catch(e){}function h(e,t,r){var n=t;switch(t){case"blob":case"arraybuffer":n="uint8array";break;case"base64":n="string"}try{this._internalType=n,this._outputType=t,this._mimeType=r,u.checkSupport(n),this._worker=e.pipe(new i(n)),e.lock()}catch(e){this._worker=new s("error"),this._worker.error(e)}}h.prototype={accumulate:function(e){return o=this,h=e,new a.Promise(function(t,r){var n=[],i=o._internalType,s=o._outputType,a=o._mimeType;o.on("data",function(e,t){n.push(e),h&&h(t)}).on("error",function(e){n=[],r(e)}).on("end",function(){try{var e=function(e,t,r){switch(e){case"blob":return u.newBlob(u.transformTo("arraybuffer",t),r);case"base64":return l.encode(t);default:return u.transformTo(e,t)}}(s,function(e,t){var r,n=0,i=null,s=0;for(r=0;r>>6:(r<65536?t[s++]=224|r>>>12:(t[s++]=240|r>>>18,t[s++]=128|r>>>12&63),t[s++]=128|r>>>6&63),t[s++]=128|63&r);return t}(e)},s.utf8decode=function(e){return h.nodebuffer?o.transformTo("nodebuffer",e).toString("utf-8"):function(e){var t,r,n,i,s=e.length,a=new Array(2*s);for(t=r=0;t>10&1023,a[r++]=56320|1023&n)}return a.length!==r&&(a.subarray?a=a.subarray(0,r):a.length=r),o.applyFromCharCode(a)}(e=o.transformTo(h.uint8array?"uint8array":"array",e))},o.inherits(a,n),a.prototype.processChunk=function(e){var t=o.transformTo(h.uint8array?"uint8array":"array",e.data);if(this.leftOver&&this.leftOver.length){if(h.uint8array){var r=t;(t=new Uint8Array(r.length+this.leftOver.length)).set(this.leftOver,0),t.set(r,this.leftOver.length)}else t=this.leftOver.concat(t);this.leftOver=null}var n=function(e,t){var r;for((t=t||e.length)>e.length&&(t=e.length),r=t-1;0<=r&&128==(192&e[r]);)r--;return r<0?t:0===r?t:r+u[e[r]]>t?r:t}(t),i=t;n!==t.length&&(h.uint8array?(i=t.subarray(0,n),this.leftOver=t.subarray(n,t.length)):(i=t.slice(0,n),this.leftOver=t.slice(n,t.length))),this.push({data:s.utf8decode(i),meta:e.meta})},a.prototype.flush=function(){this.leftOver&&this.leftOver.length&&(this.push({data:s.utf8decode(this.leftOver),meta:{}}),this.leftOver=null)},s.Utf8DecodeWorker=a,o.inherits(l,n),l.prototype.processChunk=function(e){this.push({data:s.utf8encode(e.data),meta:e.meta})},s.Utf8EncodeWorker=l},{"./nodejsUtils":14,"./stream/GenericWorker":28,"./support":30,"./utils":32}],32:[function(e,t,o){"use strict";var h=e("./support"),u=e("./base64"),r=e("./nodejsUtils"),n=e("set-immediate-shim"),l=e("./external");function i(e){return e}function f(e,t){for(var r=0;r>8;this.dir=!!(16&this.externalFileAttributes),0==e&&(this.dosPermissions=63&this.externalFileAttributes),3==e&&(this.unixPermissions=this.externalFileAttributes>>16&65535),this.dir||"/"!==this.fileNameStr.slice(-1)||(this.dir=!0)},parseZIP64ExtraField:function(e){if(this.extraFields[1]){var t=n(this.extraFields[1].value);this.uncompressedSize===s.MAX_VALUE_32BITS&&(this.uncompressedSize=t.readInt(8)),this.compressedSize===s.MAX_VALUE_32BITS&&(this.compressedSize=t.readInt(8)),this.localHeaderOffset===s.MAX_VALUE_32BITS&&(this.localHeaderOffset=t.readInt(8)),this.diskNumberStart===s.MAX_VALUE_32BITS&&(this.diskNumberStart=t.readInt(4))}},readExtraFields:function(e){var t,r,n,i=e.index+this.extraFieldsLength;for(this.extraFields||(this.extraFields={});e.index+4>>6:(r<65536?t[s++]=224|r>>>12:(t[s++]=240|r>>>18,t[s++]=128|r>>>12&63),t[s++]=128|r>>>6&63),t[s++]=128|63&r);return t},r.buf2binstring=function(e){return l(e,e.length)},r.binstring2buf=function(e){for(var t=new h.Buf8(e.length),r=0,n=t.length;r>10&1023,o[n++]=56320|1023&i)}return l(o,n)},r.utf8border=function(e,t){var r;for((t=t||e.length)>e.length&&(t=e.length),r=t-1;0<=r&&128==(192&e[r]);)r--;return r<0?t:0===r?t:r+u[e[r]]>t?r:t}},{"./common":41}],43:[function(e,t,r){"use strict";t.exports=function(e,t,r,n){for(var i=65535&e|0,s=e>>>16&65535|0,a=0;0!==r;){for(r-=a=2e3>>1:e>>>1;t[r]=e}return t}();t.exports=function(e,t,r,n){var i=o,s=n+r;e^=-1;for(var a=n;a>>8^i[255&(e^t[a])];return-1^e}},{}],46:[function(e,t,r){"use strict";var h,d=e("../utils/common"),u=e("./trees"),c=e("./adler32"),p=e("./crc32"),n=e("./messages"),l=0,f=0,m=-2,i=2,_=8,s=286,a=30,o=19,g=2*s+1,b=15,v=3,y=258,w=y+v+1,k=42,x=113;function S(e,t){return e.msg=n[t],t}function z(e){return(e<<1)-(4e.avail_out&&(r=e.avail_out),0!==r&&(d.arraySet(e.output,t.pending_buf,t.pending_out,r,e.next_out),e.next_out+=r,t.pending_out+=r,e.total_out+=r,e.avail_out-=r,t.pending-=r,0===t.pending&&(t.pending_out=0))}function A(e,t){u._tr_flush_block(e,0<=e.block_start?e.block_start:-1,e.strstart-e.block_start,t),e.block_start=e.strstart,E(e.strm)}function I(e,t){e.pending_buf[e.pending++]=t}function O(e,t){e.pending_buf[e.pending++]=t>>>8&255,e.pending_buf[e.pending++]=255&t}function B(e,t){var r,n,i=e.max_chain_length,s=e.strstart,a=e.prev_length,o=e.nice_match,h=e.strstart>e.w_size-w?e.strstart-(e.w_size-w):0,u=e.window,l=e.w_mask,f=e.prev,d=e.strstart+y,c=u[s+a-1],p=u[s+a];e.prev_length>=e.good_match&&(i>>=2),o>e.lookahead&&(o=e.lookahead);do{if(u[(r=t)+a]===p&&u[r+a-1]===c&&u[r]===u[s]&&u[++r]===u[s+1]){s+=2,r++;do{}while(u[++s]===u[++r]&&u[++s]===u[++r]&&u[++s]===u[++r]&&u[++s]===u[++r]&&u[++s]===u[++r]&&u[++s]===u[++r]&&u[++s]===u[++r]&&u[++s]===u[++r]&&sh&&0!=--i);return a<=e.lookahead?a:e.lookahead}function R(e){var t,r,n,i,s,a,o,h,u,l,f=e.w_size;do{if(i=e.window_size-e.lookahead-e.strstart,e.strstart>=f+(f-w)){for(d.arraySet(e.window,e.window,f,f,0),e.match_start-=f,e.strstart-=f,e.block_start-=f,t=r=e.hash_size;n=e.head[--t],e.head[t]=f<=n?n-f:0,--r;);for(t=r=f;n=e.prev[--t],e.prev[t]=f<=n?n-f:0,--r;);i+=f}if(0===e.strm.avail_in)break;if(a=e.strm,o=e.window,h=e.strstart+e.lookahead,l=void 0,(u=i)<(l=a.avail_in)&&(l=u),r=0===l?0:(a.avail_in-=l,d.arraySet(o,a.input,a.next_in,l,h),1===a.state.wrap?a.adler=c(a.adler,o,l,h):2===a.state.wrap&&(a.adler=p(a.adler,o,l,h)),a.next_in+=l,a.total_in+=l,l),e.lookahead+=r,e.lookahead+e.insert>=v)for(s=e.strstart-e.insert,e.ins_h=e.window[s],e.ins_h=(e.ins_h<=v&&(e.ins_h=(e.ins_h<=v)if(n=u._tr_tally(e,e.strstart-e.match_start,e.match_length-v),e.lookahead-=e.match_length,e.match_length<=e.max_lazy_match&&e.lookahead>=v){for(e.match_length--;e.strstart++,e.ins_h=(e.ins_h<=v&&(e.ins_h=(e.ins_h<=v&&e.match_length<=e.prev_length){for(i=e.strstart+e.lookahead-v,n=u._tr_tally(e,e.strstart-1-e.prev_match,e.prev_length-v),e.lookahead-=e.prev_length-1,e.prev_length-=2;++e.strstart<=i&&(e.ins_h=(e.ins_h<e.pending_buf_size-5&&(r=e.pending_buf_size-5);;){if(e.lookahead<=1){if(R(e),0===e.lookahead&&t===l)return 1;if(0===e.lookahead)break}e.strstart+=e.lookahead,e.lookahead=0;var n=e.block_start+r;if((0===e.strstart||e.strstart>=n)&&(e.lookahead=e.strstart-n,e.strstart=n,A(e,!1),0===e.strm.avail_out))return 1;if(e.strstart-e.block_start>=e.w_size-w&&(A(e,!1),0===e.strm.avail_out))return 1}return e.insert=0,4===t?(A(e,!0),0===e.strm.avail_out?3:4):(e.strstart>e.block_start&&(A(e,!1),e.strm.avail_out),1)}),new F(4,4,8,4,T),new F(4,5,16,8,T),new F(4,6,32,32,T),new F(4,4,16,16,D),new F(8,16,32,32,D),new F(8,16,128,128,D),new F(8,32,128,256,D),new F(32,128,258,1024,D),new F(32,258,258,4096,D)],r.deflateInit=function(e,t){return L(e,t,_,15,8,0)},r.deflateInit2=L,r.deflateReset=P,r.deflateResetKeep=U,r.deflateSetHeader=function(e,t){return e&&e.state?2!==e.state.wrap?m:(e.state.gzhead=t,f):m},r.deflate=function(e,t){var r,n,i,s;if(!e||!e.state||5>8&255),I(n,n.gzhead.time>>16&255),I(n,n.gzhead.time>>24&255),I(n,9===n.level?2:2<=n.strategy||n.level<2?4:0),I(n,255&n.gzhead.os),n.gzhead.extra&&n.gzhead.extra.length&&(I(n,255&n.gzhead.extra.length),I(n,n.gzhead.extra.length>>8&255)),n.gzhead.hcrc&&(e.adler=p(e.adler,n.pending_buf,n.pending,0)),n.gzindex=0,n.status=69):(I(n,0),I(n,0),I(n,0),I(n,0),I(n,0),I(n,9===n.level?2:2<=n.strategy||n.level<2?4:0),I(n,3),n.status=x);else{var a=_+(n.w_bits-8<<4)<<8;a|=(2<=n.strategy||n.level<2?0:n.level<6?1:6===n.level?2:3)<<6,0!==n.strstart&&(a|=32),a+=31-a%31,n.status=x,O(n,a),0!==n.strstart&&(O(n,e.adler>>>16),O(n,65535&e.adler)),e.adler=1}if(69===n.status)if(n.gzhead.extra){for(i=n.pending;n.gzindex<(65535&n.gzhead.extra.length)&&(n.pending!==n.pending_buf_size||(n.gzhead.hcrc&&n.pending>i&&(e.adler=p(e.adler,n.pending_buf,n.pending-i,i)),E(e),i=n.pending,n.pending!==n.pending_buf_size));)I(n,255&n.gzhead.extra[n.gzindex]),n.gzindex++;n.gzhead.hcrc&&n.pending>i&&(e.adler=p(e.adler,n.pending_buf,n.pending-i,i)),n.gzindex===n.gzhead.extra.length&&(n.gzindex=0,n.status=73)}else n.status=73;if(73===n.status)if(n.gzhead.name){i=n.pending;do{if(n.pending===n.pending_buf_size&&(n.gzhead.hcrc&&n.pending>i&&(e.adler=p(e.adler,n.pending_buf,n.pending-i,i)),E(e),i=n.pending,n.pending===n.pending_buf_size)){s=1;break}s=n.gzindexi&&(e.adler=p(e.adler,n.pending_buf,n.pending-i,i)),0===s&&(n.gzindex=0,n.status=91)}else n.status=91;if(91===n.status)if(n.gzhead.comment){i=n.pending;do{if(n.pending===n.pending_buf_size&&(n.gzhead.hcrc&&n.pending>i&&(e.adler=p(e.adler,n.pending_buf,n.pending-i,i)),E(e),i=n.pending,n.pending===n.pending_buf_size)){s=1;break}s=n.gzindexi&&(e.adler=p(e.adler,n.pending_buf,n.pending-i,i)),0===s&&(n.status=103)}else n.status=103;if(103===n.status&&(n.gzhead.hcrc?(n.pending+2>n.pending_buf_size&&E(e),n.pending+2<=n.pending_buf_size&&(I(n,255&e.adler),I(n,e.adler>>8&255),e.adler=0,n.status=x)):n.status=x),0!==n.pending){if(E(e),0===e.avail_out)return n.last_flush=-1,f}else if(0===e.avail_in&&z(t)<=z(r)&&4!==t)return S(e,-5);if(666===n.status&&0!==e.avail_in)return S(e,-5);if(0!==e.avail_in||0!==n.lookahead||t!==l&&666!==n.status){var o=2===n.strategy?function(e,t){for(var r;;){if(0===e.lookahead&&(R(e),0===e.lookahead)){if(t===l)return 1;break}if(e.match_length=0,r=u._tr_tally(e,0,e.window[e.strstart]),e.lookahead--,e.strstart++,r&&(A(e,!1),0===e.strm.avail_out))return 1}return e.insert=0,4===t?(A(e,!0),0===e.strm.avail_out?3:4):e.last_lit&&(A(e,!1),0===e.strm.avail_out)?1:2}(n,t):3===n.strategy?function(e,t){for(var r,n,i,s,a=e.window;;){if(e.lookahead<=y){if(R(e),e.lookahead<=y&&t===l)return 1;if(0===e.lookahead)break}if(e.match_length=0,e.lookahead>=v&&0e.lookahead&&(e.match_length=e.lookahead)}if(e.match_length>=v?(r=u._tr_tally(e,1,e.match_length-v),e.lookahead-=e.match_length,e.strstart+=e.match_length,e.match_length=0):(r=u._tr_tally(e,0,e.window[e.strstart]),e.lookahead--,e.strstart++),r&&(A(e,!1),0===e.strm.avail_out))return 1}return e.insert=0,4===t?(A(e,!0),0===e.strm.avail_out?3:4):e.last_lit&&(A(e,!1),0===e.strm.avail_out)?1:2}(n,t):h[n.level].func(n,t);if(3!==o&&4!==o||(n.status=666),1===o||3===o)return 0===e.avail_out&&(n.last_flush=-1),f;if(2===o&&(1===t?u._tr_align(n):5!==t&&(u._tr_stored_block(n,0,0,!1),3===t&&(C(n.head),0===n.lookahead&&(n.strstart=0,n.block_start=0,n.insert=0))),E(e),0===e.avail_out))return n.last_flush=-1,f}return 4!==t?f:n.wrap<=0?1:(2===n.wrap?(I(n,255&e.adler),I(n,e.adler>>8&255),I(n,e.adler>>16&255),I(n,e.adler>>24&255),I(n,255&e.total_in),I(n,e.total_in>>8&255),I(n,e.total_in>>16&255),I(n,e.total_in>>24&255)):(O(n,e.adler>>>16),O(n,65535&e.adler)),E(e),0=r.w_size&&(0===s&&(C(r.head),r.strstart=0,r.block_start=0,r.insert=0),u=new d.Buf8(r.w_size),d.arraySet(u,t,l-r.w_size,r.w_size,0),t=u,l=r.w_size),a=e.avail_in,o=e.next_in,h=e.input,e.avail_in=l,e.next_in=0,e.input=t,R(r);r.lookahead>=v;){for(n=r.strstart,i=r.lookahead-(v-1);r.ins_h=(r.ins_h<>>=y=v>>>24,p-=y,0==(y=v>>>16&255))C[s++]=65535&v;else{if(!(16&y)){if(0==(64&y)){v=m[(65535&v)+(c&(1<>>=y,p-=y),p<15&&(c+=z[n++]<>>=y=v>>>24,p-=y,!(16&(y=v>>>16&255))){if(0==(64&y)){v=_[(65535&v)+(c&(1<>>=y,p-=y,(y=s-a)>3,c&=(1<<(p-=w<<3))-1,e.next_in=n,e.next_out=s,e.avail_in=n>>24&255)+(e>>>8&65280)+((65280&e)<<8)+((255&e)<<24)}function s(){this.mode=0,this.last=!1,this.wrap=0,this.havedict=!1,this.flags=0,this.dmax=0,this.check=0,this.total=0,this.head=null,this.wbits=0,this.wsize=0,this.whave=0,this.wnext=0,this.window=null,this.hold=0,this.bits=0,this.length=0,this.offset=0,this.extra=0,this.lencode=null,this.distcode=null,this.lenbits=0,this.distbits=0,this.ncode=0,this.nlen=0,this.ndist=0,this.have=0,this.next=null,this.lens=new I.Buf16(320),this.work=new I.Buf16(288),this.lendyn=null,this.distdyn=null,this.sane=0,this.back=0,this.was=0}function a(e){var t;return e&&e.state?(t=e.state,e.total_in=e.total_out=t.total=0,e.msg="",t.wrap&&(e.adler=1&t.wrap),t.mode=P,t.last=0,t.havedict=0,t.dmax=32768,t.head=null,t.hold=0,t.bits=0,t.lencode=t.lendyn=new I.Buf32(n),t.distcode=t.distdyn=new I.Buf32(i),t.sane=1,t.back=-1,N):U}function o(e){var t;return e&&e.state?((t=e.state).wsize=0,t.whave=0,t.wnext=0,a(e)):U}function h(e,t){var r,n;return e&&e.state?(n=e.state,t<0?(r=0,t=-t):(r=1+(t>>4),t<48&&(t&=15)),t&&(t<8||15=s.wsize?(I.arraySet(s.window,t,r-s.wsize,s.wsize,0),s.wnext=0,s.whave=s.wsize):(n<(i=s.wsize-s.wnext)&&(i=n),I.arraySet(s.window,t,r-n,i,s.wnext),(n-=i)?(I.arraySet(s.window,t,r-n,n,0),s.wnext=n,s.whave=s.wsize):(s.wnext+=i,s.wnext===s.wsize&&(s.wnext=0),s.whave>>8&255,r.check=B(r.check,E,2,0),l=u=0,r.mode=2;break}if(r.flags=0,r.head&&(r.head.done=!1),!(1&r.wrap)||(((255&u)<<8)+(u>>8))%31){e.msg="incorrect header check",r.mode=30;break}if(8!=(15&u)){e.msg="unknown compression method",r.mode=30;break}if(l-=4,k=8+(15&(u>>>=4)),0===r.wbits)r.wbits=k;else if(k>r.wbits){e.msg="invalid window size",r.mode=30;break}r.dmax=1<>8&1),512&r.flags&&(E[0]=255&u,E[1]=u>>>8&255,r.check=B(r.check,E,2,0)),l=u=0,r.mode=3;case 3:for(;l<32;){if(0===o)break e;o--,u+=n[s++]<>>8&255,E[2]=u>>>16&255,E[3]=u>>>24&255,r.check=B(r.check,E,4,0)),l=u=0,r.mode=4;case 4:for(;l<16;){if(0===o)break e;o--,u+=n[s++]<>8),512&r.flags&&(E[0]=255&u,E[1]=u>>>8&255,r.check=B(r.check,E,2,0)),l=u=0,r.mode=5;case 5:if(1024&r.flags){for(;l<16;){if(0===o)break e;o--,u+=n[s++]<>>8&255,r.check=B(r.check,E,2,0)),l=u=0}else r.head&&(r.head.extra=null);r.mode=6;case 6:if(1024&r.flags&&(o<(c=r.length)&&(c=o),c&&(r.head&&(k=r.head.extra_len-r.length,r.head.extra||(r.head.extra=new Array(r.head.extra_len)),I.arraySet(r.head.extra,n,s,c,k)),512&r.flags&&(r.check=B(r.check,n,c,s)),o-=c,s+=c,r.length-=c),r.length))break e;r.length=0,r.mode=7;case 7:if(2048&r.flags){if(0===o)break e;for(c=0;k=n[s+c++],r.head&&k&&r.length<65536&&(r.head.name+=String.fromCharCode(k)),k&&c>9&1,r.head.done=!0),e.adler=r.check=0,r.mode=12;break;case 10:for(;l<32;){if(0===o)break e;o--,u+=n[s++]<>>=7&l,l-=7&l,r.mode=27;break}for(;l<3;){if(0===o)break e;o--,u+=n[s++]<>>=1)){case 0:r.mode=14;break;case 1:if(j(r),r.mode=20,6!==t)break;u>>>=2,l-=2;break e;case 2:r.mode=17;break;case 3:e.msg="invalid block type",r.mode=30}u>>>=2,l-=2;break;case 14:for(u>>>=7&l,l-=7&l;l<32;){if(0===o)break e;o--,u+=n[s++]<>>16^65535)){e.msg="invalid stored block lengths",r.mode=30;break}if(r.length=65535&u,l=u=0,r.mode=15,6===t)break e;case 15:r.mode=16;case 16:if(c=r.length){if(o>>=5,l-=5,r.ndist=1+(31&u),u>>>=5,l-=5,r.ncode=4+(15&u),u>>>=4,l-=4,286>>=3,l-=3}for(;r.have<19;)r.lens[A[r.have++]]=0;if(r.lencode=r.lendyn,r.lenbits=7,S={bits:r.lenbits},x=T(0,r.lens,0,19,r.lencode,0,r.work,S),r.lenbits=S.bits,x){e.msg="invalid code lengths set",r.mode=30;break}r.have=0,r.mode=19;case 19:for(;r.have>>16&255,b=65535&C,!((_=C>>>24)<=l);){if(0===o)break e;o--,u+=n[s++]<>>=_,l-=_,r.lens[r.have++]=b;else{if(16===b){for(z=_+2;l>>=_,l-=_,0===r.have){e.msg="invalid bit length repeat",r.mode=30;break}k=r.lens[r.have-1],c=3+(3&u),u>>>=2,l-=2}else if(17===b){for(z=_+3;l>>=_)),u>>>=3,l-=3}else{for(z=_+7;l>>=_)),u>>>=7,l-=7}if(r.have+c>r.nlen+r.ndist){e.msg="invalid bit length repeat",r.mode=30;break}for(;c--;)r.lens[r.have++]=k}}if(30===r.mode)break;if(0===r.lens[256]){e.msg="invalid code -- missing end-of-block",r.mode=30;break}if(r.lenbits=9,S={bits:r.lenbits},x=T(D,r.lens,0,r.nlen,r.lencode,0,r.work,S),r.lenbits=S.bits,x){e.msg="invalid literal/lengths set",r.mode=30;break}if(r.distbits=6,r.distcode=r.distdyn,S={bits:r.distbits},x=T(F,r.lens,r.nlen,r.ndist,r.distcode,0,r.work,S),r.distbits=S.bits,x){e.msg="invalid distances set",r.mode=30;break}if(r.mode=20,6===t)break e;case 20:r.mode=21;case 21:if(6<=o&&258<=h){e.next_out=a,e.avail_out=h,e.next_in=s,e.avail_in=o,r.hold=u,r.bits=l,R(e,d),a=e.next_out,i=e.output,h=e.avail_out,s=e.next_in,n=e.input,o=e.avail_in,u=r.hold,l=r.bits,12===r.mode&&(r.back=-1);break}for(r.back=0;g=(C=r.lencode[u&(1<>>16&255,b=65535&C,!((_=C>>>24)<=l);){if(0===o)break e;o--,u+=n[s++]<>v)])>>>16&255,b=65535&C,!(v+(_=C>>>24)<=l);){if(0===o)break e;o--,u+=n[s++]<>>=v,l-=v,r.back+=v}if(u>>>=_,l-=_,r.back+=_,r.length=b,0===g){r.mode=26;break}if(32&g){r.back=-1,r.mode=12;break}if(64&g){e.msg="invalid literal/length code",r.mode=30;break}r.extra=15&g,r.mode=22;case 22:if(r.extra){for(z=r.extra;l>>=r.extra,l-=r.extra,r.back+=r.extra}r.was=r.length,r.mode=23;case 23:for(;g=(C=r.distcode[u&(1<>>16&255,b=65535&C,!((_=C>>>24)<=l);){if(0===o)break e;o--,u+=n[s++]<>v)])>>>16&255,b=65535&C,!(v+(_=C>>>24)<=l);){if(0===o)break e;o--,u+=n[s++]<>>=v,l-=v,r.back+=v}if(u>>>=_,l-=_,r.back+=_,64&g){e.msg="invalid distance code",r.mode=30;break}r.offset=b,r.extra=15&g,r.mode=24;case 24:if(r.extra){for(z=r.extra;l>>=r.extra,l-=r.extra,r.back+=r.extra}if(r.offset>r.dmax){e.msg="invalid distance too far back",r.mode=30;break}r.mode=25;case 25:if(0===h)break e;if(c=d-h,r.offset>c){if((c=r.offset-c)>r.whave&&r.sane){e.msg="invalid distance too far back",r.mode=30;break}p=c>r.wnext?(c-=r.wnext,r.wsize-c):r.wnext-c,c>r.length&&(c=r.length),m=r.window}else m=i,p=a-r.offset,c=r.length;for(hc?(m=R[T+a[v]],A[I+a[v]]):(m=96,0),h=1<>S)+(u-=h)]=p<<24|m<<16|_|0,0!==u;);for(h=1<>=1;if(0!==h?(E&=h-1,E+=h):E=0,v++,0==--O[b]){if(b===w)break;b=t[r+a[v]]}if(k>>7)]}function x(e,t){e.pending_buf[e.pending++]=255&t,e.pending_buf[e.pending++]=t>>>8&255}function S(e,t,r){e.bi_valid>i-r?(e.bi_buf|=t<>i-e.bi_valid,e.bi_valid+=r-i):(e.bi_buf|=t<>>=1,r<<=1,0<--t;);return r>>>1}function E(e,t,r){var n,i,s=new Array(_+1),a=0;for(n=1;n<=_;n++)s[n]=a=a+r[n-1]<<1;for(i=0;i<=t;i++){var o=e[2*i+1];0!==o&&(e[2*i]=C(s[o]++,o))}}function A(e){var t;for(t=0;t<286;t++)e.dyn_ltree[2*t]=0;for(t=0;t<30;t++)e.dyn_dtree[2*t]=0;for(t=0;t<19;t++)e.bl_tree[2*t]=0;e.dyn_ltree[512]=1,e.opt_len=e.static_len=0,e.last_lit=e.matches=0}function I(e){8>1;1<=r;r--)B(e,s,r);for(i=h;r=e.heap[1],e.heap[1]=e.heap[e.heap_len--],B(e,s,1),n=e.heap[1],e.heap[--e.heap_max]=r,e.heap[--e.heap_max]=n,s[2*i]=s[2*r]+s[2*n],e.depth[i]=(e.depth[r]>=e.depth[n]?e.depth[r]:e.depth[n])+1,s[2*r+1]=s[2*n+1]=i,e.heap[1]=i++,B(e,s,1),2<=e.heap_len;);e.heap[--e.heap_max]=e.heap[1],function(e,t){var r,n,i,s,a,o,h=t.dyn_tree,u=t.max_code,l=t.stat_desc.static_tree,f=t.stat_desc.has_stree,d=t.stat_desc.extra_bits,c=t.stat_desc.extra_base,p=t.stat_desc.max_length,m=0;for(s=0;s<=_;s++)e.bl_count[s]=0;for(h[2*e.heap[e.heap_max]+1]=0,r=e.heap_max+1;r<573;r++)p<(s=h[2*h[2*(n=e.heap[r])+1]+1]+1)&&(s=p,m++),h[2*n+1]=s,u>=7;n<30;n++)for(y[n]=i<<7,e=0;e<1<>>=1)if(1&r&&0!==e.dyn_ltree[2*t])return 0;if(0!==e.dyn_ltree[18]||0!==e.dyn_ltree[20]||0!==e.dyn_ltree[26])return 1;for(t=32;t<256;t++)if(0!==e.dyn_ltree[2*t])return 1;return 0}(e)),T(e,e.l_desc),T(e,e.d_desc),a=function(e){var t;for(D(e,e.dyn_ltree,e.l_desc.max_code),D(e,e.dyn_dtree,e.d_desc.max_code),T(e,e.bl_desc),t=18;3<=t&&0===e.bl_tree[2*l[t]+1];t--);return e.opt_len+=3*(t+1)+5+5+4,t}(e),i=e.opt_len+3+7>>>3,(s=e.static_len+3+7>>>3)<=i&&(i=s)):i=s=r+5,r+4<=i&&-1!==t?U(e,t,r,n):4===e.strategy||s===i?(S(e,2+(n?1:0),3),R(e,f,d)):(S(e,4+(n?1:0),3),function(e,t,r,n){var i;for(S(e,t-257,5),S(e,r-1,5),S(e,n-4,4),i=0;i>>8&255,e.pending_buf[e.d_buf+2*e.last_lit+1]=255&t,e.pending_buf[e.l_buf+e.last_lit]=255&r,e.last_lit++,0===t?e.dyn_ltree[2*r]++:(e.matches++,t--,e.dyn_ltree[2*(p[r]+256+1)]++,e.dyn_dtree[2*k(t)]++),e.last_lit===e.lit_bufsize-1},r._tr_align=function(e){var t;S(e,2,3),z(e,256,f),16===(t=e).bi_valid?(x(t,t.bi_buf),t.bi_buf=0,t.bi_valid=0):8<=t.bi_valid&&(t.pending_buf[t.pending++]=255&t.bi_buf,t.bi_buf>>=8,t.bi_valid-=8)}},{"../utils/common":41}],53:[function(e,t,r){"use strict";t.exports=function(){this.input=null,this.next_in=0,this.avail_in=0,this.total_in=0,this.output=null,this.next_out=0,this.avail_out=0,this.total_out=0,this.msg="",this.state=null,this.data_type=2,this.adler=0}},{}],54:[function(e,t,r){"use strict";t.exports="function"==typeof setImmediate?setImmediate:function(){var e=[].slice.apply(arguments);e.splice(1,0,0),setTimeout.apply(null,e)}},{}]},{},[10])(10)})}).call(this,void 0!==r?r:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}]},{},[1])(1)})}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}]},{},[1])(1)}); \ No newline at end of file diff --git a/boomerangScope-SootUp/target/apidocs/member-search-index.js b/boomerangScope-SootUp/target/apidocs/member-search-index.js deleted file mode 100644 index 6c60e47b1..000000000 --- a/boomerangScope-SootUp/target/apidocs/member-search-index.js +++ /dev/null @@ -1 +0,0 @@ -memberSearchIndex = [{"p":"boomerang.scene.sootup","c":"JimpleUpStaticFieldVal","l":"asUnbalanced(ControlFlowGraph.Edge)","url":"asUnbalanced(boomerang.scene.ControlFlowGraph.Edge)"},{"p":"boomerang.scene.sootup","c":"JimpleUpVal","l":"asUnbalanced(ControlFlowGraph.Edge)","url":"asUnbalanced(boomerang.scene.ControlFlowGraph.Edge)"},{"p":"boomerang.scene.sootup","c":"BoomerangPreInterceptor","l":"BoomerangPreInterceptor()","url":"%3Cinit%3E()"},{"p":"boomerang.scene.sootup","c":"JimpleUpControlFlowGraph","l":"buildCache()"},{"p":"boomerang.scene.sootup","c":"JimpleUpStatement","l":"containsInvokeExpr()"},{"p":"boomerang.scene.sootup","c":"JimpleUpStatement","l":"containsStaticFieldAccess()"},{"p":"boomerang.scene.sootup","c":"JimpleUpStatement","l":"create(Stmt, JimpleUpMethod)","url":"create(sootup.core.jimple.common.stmt.Stmt,boomerang.scene.sootup.JimpleUpMethod)"},{"p":"boomerang.scene.sootup","c":"JimpleUpType","l":"doesCastFail(Type, Val)","url":"doesCastFail(boomerang.scene.Type,boomerang.scene.Val)"},{"p":"boomerang.scene.sootup","c":"JimpleUpDeclaredMethod","l":"equals(Object)","url":"equals(java.lang.Object)"},{"p":"boomerang.scene.sootup","c":"JimpleUpDoubleVal","l":"equals(Object)","url":"equals(java.lang.Object)"},{"p":"boomerang.scene.sootup","c":"JimpleUpField","l":"equals(Object)","url":"equals(java.lang.Object)"},{"p":"boomerang.scene.sootup","c":"JimpleUpIfStatement","l":"equals(Object)","url":"equals(java.lang.Object)"},{"p":"boomerang.scene.sootup","c":"JimpleUpInstanceFieldRef","l":"equals(Object)","url":"equals(java.lang.Object)"},{"p":"boomerang.scene.sootup","c":"JimpleUpInvokeExpr","l":"equals(Object)","url":"equals(java.lang.Object)"},{"p":"boomerang.scene.sootup","c":"JimpleUpMethod","l":"equals(Object)","url":"equals(java.lang.Object)"},{"p":"boomerang.scene.sootup","c":"JimpleUpStatement","l":"equals(Object)","url":"equals(java.lang.Object)"},{"p":"boomerang.scene.sootup","c":"JimpleUpStaticFieldVal","l":"equals(Object)","url":"equals(java.lang.Object)"},{"p":"boomerang.scene.sootup","c":"JimpleUpVal","l":"equals(Object)","url":"equals(java.lang.Object)"},{"p":"boomerang.scene.sootup","c":"JimpleUpWrappedClass","l":"equals(Object)","url":"equals(java.lang.Object)"},{"p":"boomerang.scene.sootup","c":"JimpleUpIfStatement","l":"evaluate(Val)","url":"evaluate(boomerang.scene.Val)"},{"p":"boomerang.scene.sootup","c":"JimpleUpStaticFieldVal","l":"field()"},{"p":"boomerang.scene.sootup","c":"JimpleUpInvokeExpr","l":"getArg(int)"},{"p":"boomerang.scene.sootup","c":"JimpleUpInvokeExpr","l":"getArgs()"},{"p":"boomerang.scene.sootup","c":"JimpleUpStatement","l":"getArrayBase()"},{"p":"boomerang.scene.sootup","c":"JimpleUpStaticFieldVal","l":"getArrayBase()"},{"p":"boomerang.scene.sootup","c":"JimpleUpVal","l":"getArrayBase()"},{"p":"boomerang.scene.sootup","c":"JimpleUpType","l":"getArrayBaseType()"},{"p":"boomerang.scene.sootup","c":"JimpleUpInstanceFieldRef","l":"getBase()"},{"p":"boomerang.scene.sootup","c":"JimpleUpInvokeExpr","l":"getBase()"},{"p":"boomerang.scene.sootup","c":"JimpleUpDeclaredMethod","l":"getCalledMethod()"},{"p":"boomerang.scene.sootup","c":"JimpleUpStaticFieldVal","l":"getCastOp()"},{"p":"boomerang.scene.sootup","c":"JimpleUpVal","l":"getCastOp()"},{"p":"boomerang.scene.sootup","c":"JimpleUpStaticFieldVal","l":"getClassConstantType()"},{"p":"boomerang.scene.sootup","c":"JimpleUpVal","l":"getClassConstantType()"},{"p":"boomerang.scene.sootup","c":"JimpleUpMethod","l":"getControlFlowGraph()"},{"p":"boomerang.scene.sootup","c":"JimpleUpDeclaredMethod","l":"getDeclaringClass()"},{"p":"boomerang.scene.sootup","c":"JimpleUpMethod","l":"getDeclaringClass()"},{"p":"boomerang.scene.sootup","c":"JimpleUpDeclaredMethod","l":"getDelegate()"},{"p":"boomerang.scene.sootup","c":"JimpleUpField","l":"getDelegate()"},{"p":"boomerang.scene.sootup","c":"JimpleUpMethod","l":"getDelegate()"},{"p":"boomerang.scene.sootup","c":"JimpleUpStatement","l":"getDelegate()"},{"p":"boomerang.scene.sootup","c":"JimpleUpType","l":"getDelegate()"},{"p":"boomerang.scene.sootup","c":"JimpleUpVal","l":"getDelegate()"},{"p":"boomerang.scene.sootup","c":"JimpleUpWrappedClass","l":"getDelegate()"},{"p":"boomerang.scene.sootup","c":"JimpleUpStatement","l":"getEndColumnNumber()"},{"p":"boomerang.scene.sootup","c":"JimpleUpStatement","l":"getEndLineNumber()"},{"p":"boomerang.scene.sootup","c":"JimpleUpControlFlowGraph","l":"getEndPoints()"},{"p":"boomerang.scene.sootup","c":"JimpleUpDoubleVal","l":"getFalseVariable()"},{"p":"boomerang.scene.sootup","c":"JimpleUpInstanceFieldRef","l":"getField()"},{"p":"boomerang.scene.sootup","c":"JimpleUpStatement","l":"getFieldLoad()"},{"p":"boomerang.scene.sootup","c":"JimpleUpStatement","l":"getFieldStore()"},{"p":"boomerang.scene.sootup","c":"JimpleUpWrappedClass","l":"getFullyQualifiedName()"},{"p":"boomerang.scene.sootup","c":"SootUpClient","l":"getIdentifierFactory()"},{"p":"boomerang.scene.sootup","c":"JimpleUpStatement","l":"getIfStmt()"},{"p":"boomerang.scene.sootup","c":"SootUpClient","l":"getInstance()"},{"p":"boomerang.scene.sootup","c":"JimpleUpStaticFieldVal","l":"getInstanceOfOp()"},{"p":"boomerang.scene.sootup","c":"JimpleUpVal","l":"getInstanceOfOp()"},{"p":"boomerang.scene.sootup","c":"JimpleUpStaticFieldVal","l":"getIntValue()"},{"p":"boomerang.scene.sootup","c":"JimpleUpVal","l":"getIntValue()"},{"p":"boomerang.scene.sootup","c":"JimpleUpStatement","l":"getInvokeExpr()"},{"p":"boomerang.scene.sootup","c":"JimpleUpStatement","l":"getLeftOp()"},{"p":"boomerang.scene.sootup","c":"JimpleUpStaticFieldVal","l":"getLengthOp()"},{"p":"boomerang.scene.sootup","c":"JimpleUpVal","l":"getLengthOp()"},{"p":"boomerang.scene.sootup","c":"JimpleUpStatement","l":"getLoadedField()"},{"p":"boomerang.scene.sootup","c":"JimpleUpMethod","l":"getLocals()"},{"p":"boomerang.scene.sootup","c":"JimpleUpStaticFieldVal","l":"getLongValue()"},{"p":"boomerang.scene.sootup","c":"JimpleUpVal","l":"getLongValue()"},{"p":"boomerang.scene.sootup","c":"JimpleUpInvokeExpr","l":"getMethod()"},{"p":"boomerang.scene.sootup","c":"JimpleUpWrappedClass","l":"getMethods()"},{"p":"boomerang.scene.sootup","c":"JimpleUpDeclaredMethod","l":"getName()"},{"p":"boomerang.scene.sootup","c":"JimpleUpMethod","l":"getName()"},{"p":"boomerang.scene.sootup","c":"JimpleUpWrappedClass","l":"getName()"},{"p":"boomerang.scene.sootup","c":"JimpleUpStaticFieldVal","l":"getNewExprType()"},{"p":"boomerang.scene.sootup","c":"JimpleUpVal","l":"getNewExprType()"},{"p":"boomerang.scene.sootup","c":"JimpleUpMethod","l":"getParameterLocals()"},{"p":"boomerang.scene.sootup","c":"JimpleUpMethod","l":"getParameterType(int)"},{"p":"boomerang.scene.sootup","c":"JimpleUpMethod","l":"getParameterTypes()"},{"p":"boomerang.scene.sootup","c":"JimpleUpStatement","l":"getPhiVals()"},{"p":"boomerang.scene.sootup","c":"JimpleUpControlFlowGraph","l":"getPredsOf(Statement)","url":"getPredsOf(boomerang.scene.Statement)"},{"p":"boomerang.scene.sootup","c":"JimpleUpStatement","l":"getReturnOp()"},{"p":"boomerang.scene.sootup","c":"JimpleUpStatement","l":"getRightOp()"},{"p":"boomerang.scene.sootup","c":"JimpleUpDeclaredMethod","l":"getSignature()"},{"p":"boomerang.scene.sootup","c":"SootUpClient","l":"getSootClass(ClassType)","url":"getSootClass(sootup.core.types.ClassType)"},{"p":"boomerang.scene.sootup","c":"SootUpClient","l":"getSootField(FieldSignature)","url":"getSootField(sootup.core.signatures.FieldSignature)"},{"p":"boomerang.scene.sootup","c":"SootUpClient","l":"getSootMethod(MethodSignature)","url":"getSootMethod(sootup.core.signatures.MethodSignature)"},{"p":"boomerang.scene.sootup","c":"JimpleUpStatement","l":"getStartColumnNumber()"},{"p":"boomerang.scene.sootup","c":"JimpleUpStatement","l":"getStartLineNumber()"},{"p":"boomerang.scene.sootup","c":"JimpleUpControlFlowGraph","l":"getStartPoints()"},{"p":"boomerang.scene.sootup","c":"JimpleUpControlFlowGraph","l":"getStatements()"},{"p":"boomerang.scene.sootup","c":"JimpleUpMethod","l":"getStatements()"},{"p":"boomerang.scene.sootup","c":"JimpleUpStatement","l":"getStaticField()"},{"p":"boomerang.scene.sootup","c":"JimpleUpStaticFieldVal","l":"getStringValue()"},{"p":"boomerang.scene.sootup","c":"JimpleUpVal","l":"getStringValue()"},{"p":"boomerang.scene.sootup","c":"JimpleUpDeclaredMethod","l":"getSubSignature()"},{"p":"boomerang.scene.sootup","c":"JimpleUpMethod","l":"getSubSignature()"},{"p":"boomerang.scene.sootup","c":"JimpleUpControlFlowGraph","l":"getSuccsOf(Statement)","url":"getSuccsOf(boomerang.scene.Statement)"},{"p":"boomerang.scene.sootup","c":"JimpleUpWrappedClass","l":"getSuperclass()"},{"p":"boomerang.scene.sootup","c":"JimpleUpIfStatement","l":"getTarget()"},{"p":"boomerang.scene.sootup","c":"JimpleUpMethod","l":"getThisLocal()"},{"p":"boomerang.scene.sootup","c":"JimpleUpStaticFieldVal","l":"getType()"},{"p":"boomerang.scene.sootup","c":"JimpleUpVal","l":"getType()"},{"p":"boomerang.scene.sootup","c":"JimpleUpWrappedClass","l":"getType()"},{"p":"boomerang.scene.sootup","c":"JimpleUpStaticFieldVal","l":"getVariableName()"},{"p":"boomerang.scene.sootup","c":"JimpleUpVal","l":"getVariableName()"},{"p":"boomerang.scene.sootup","c":"SootUpClient","l":"getView()"},{"p":"boomerang.scene.sootup","c":"JimpleUpType","l":"getWrappedClass()"},{"p":"boomerang.scene.sootup","c":"JimpleUpStatement","l":"getWrittenField()"},{"p":"boomerang.scene.sootup","c":"JimpleUpDeclaredMethod","l":"hashCode()"},{"p":"boomerang.scene.sootup","c":"JimpleUpDoubleVal","l":"hashCode()"},{"p":"boomerang.scene.sootup","c":"JimpleUpField","l":"hashCode()"},{"p":"boomerang.scene.sootup","c":"JimpleUpIfStatement","l":"hashCode()"},{"p":"boomerang.scene.sootup","c":"JimpleUpInstanceFieldRef","l":"hashCode()"},{"p":"boomerang.scene.sootup","c":"JimpleUpInvokeExpr","l":"hashCode()"},{"p":"boomerang.scene.sootup","c":"JimpleUpMethod","l":"hashCode()"},{"p":"boomerang.scene.sootup","c":"JimpleUpStatement","l":"hashCode()"},{"p":"boomerang.scene.sootup","c":"JimpleUpStaticFieldVal","l":"hashCode()"},{"p":"boomerang.scene.sootup","c":"JimpleUpVal","l":"hashCode()"},{"p":"boomerang.scene.sootup","c":"JimpleUpWrappedClass","l":"hashCode()"},{"p":"boomerang.scene.sootup","c":"JimpleUpWrappedClass","l":"hasSuperclass()"},{"p":"boomerang.scene.sootup","c":"BoomerangPreInterceptor","l":"interceptBody(Body.BodyBuilder, View)","url":"interceptBody(sootup.core.model.Body.BodyBuilder,sootup.core.views.View)"},{"p":"boomerang.scene.sootup","c":"JimpleUpMethod","l":"INTERNAL_POOL"},{"p":"boomerang.scene.sootup","c":"JimpleUpWrappedClass","l":"isApplicationClass()"},{"p":"boomerang.scene.sootup","c":"JimpleUpStaticFieldVal","l":"isArrayAllocationVal()"},{"p":"boomerang.scene.sootup","c":"JimpleUpVal","l":"isArrayAllocationVal()"},{"p":"boomerang.scene.sootup","c":"JimpleUpStatement","l":"isArrayLoad()"},{"p":"boomerang.scene.sootup","c":"JimpleUpStaticFieldVal","l":"isArrayRef()"},{"p":"boomerang.scene.sootup","c":"JimpleUpVal","l":"isArrayRef()"},{"p":"boomerang.scene.sootup","c":"JimpleUpStatement","l":"isArrayStore()"},{"p":"boomerang.scene.sootup","c":"JimpleUpType","l":"isArrayType()"},{"p":"boomerang.scene.sootup","c":"JimpleUpStatement","l":"isAssign()"},{"p":"boomerang.scene.sootup","c":"JimpleUpType","l":"isBooleanType()"},{"p":"boomerang.scene.sootup","c":"JimpleUpStatement","l":"isCast()"},{"p":"boomerang.scene.sootup","c":"JimpleUpStaticFieldVal","l":"isCast()"},{"p":"boomerang.scene.sootup","c":"JimpleUpVal","l":"isCast()"},{"p":"boomerang.scene.sootup","c":"JimpleUpStatement","l":"isCatchStmt()"},{"p":"boomerang.scene.sootup","c":"JimpleUpStaticFieldVal","l":"isClassConstant()"},{"p":"boomerang.scene.sootup","c":"JimpleUpVal","l":"isClassConstant()"},{"p":"boomerang.scene.sootup","c":"JimpleUpDeclaredMethod","l":"isConstructor()"},{"p":"boomerang.scene.sootup","c":"JimpleUpMethod","l":"isConstructor()"},{"p":"boomerang.scene.sootup","c":"SootUpClient","l":"isConstructor(JavaSootMethod)","url":"isConstructor(sootup.java.core.JavaSootMethod)"},{"p":"boomerang.scene.sootup","c":"JimpleUpStatement","l":"isFieldLoad()"},{"p":"boomerang.scene.sootup","c":"JimpleUpStatement","l":"isFieldLoadWithBase(Val)","url":"isFieldLoadWithBase(boomerang.scene.Val)"},{"p":"boomerang.scene.sootup","c":"JimpleUpStatement","l":"isFieldStore()"},{"p":"boomerang.scene.sootup","c":"JimpleUpStatement","l":"isFieldWriteWithBase(Val)","url":"isFieldWriteWithBase(boomerang.scene.Val)"},{"p":"boomerang.scene.sootup","c":"JimpleUpStatement","l":"isIdentityStmt()"},{"p":"boomerang.scene.sootup","c":"JimpleUpStatement","l":"isIfStmt()"},{"p":"boomerang.scene.sootup","c":"JimpleUpField","l":"isInnerClassField()"},{"p":"boomerang.scene.sootup","c":"JimpleUpInvokeExpr","l":"isInstanceInvokeExpr()"},{"p":"boomerang.scene.sootup","c":"JimpleUpStaticFieldVal","l":"isInstanceOfExpr()"},{"p":"boomerang.scene.sootup","c":"JimpleUpVal","l":"isInstanceOfExpr()"},{"p":"boomerang.scene.sootup","c":"JimpleUpStatement","l":"isInstanceOfStatement(Val)","url":"isInstanceOfStatement(boomerang.scene.Val)"},{"p":"boomerang.scene.sootup","c":"JimpleUpStaticFieldVal","l":"isIntConstant()"},{"p":"boomerang.scene.sootup","c":"JimpleUpVal","l":"isIntConstant()"},{"p":"boomerang.scene.sootup","c":"JimpleUpStaticFieldVal","l":"isLengthExpr()"},{"p":"boomerang.scene.sootup","c":"JimpleUpVal","l":"isLengthExpr()"},{"p":"boomerang.scene.sootup","c":"JimpleUpStaticFieldVal","l":"isLocal()"},{"p":"boomerang.scene.sootup","c":"JimpleUpVal","l":"isLocal()"},{"p":"boomerang.scene.sootup","c":"JimpleUpStaticFieldVal","l":"isLongConstant()"},{"p":"boomerang.scene.sootup","c":"JimpleUpVal","l":"isLongConstant()"},{"p":"boomerang.scene.sootup","c":"JimpleUpStatement","l":"isMultiArrayAllocation()"},{"p":"boomerang.scene.sootup","c":"JimpleUpDeclaredMethod","l":"isNative()"},{"p":"boomerang.scene.sootup","c":"JimpleUpMethod","l":"isNative()"},{"p":"boomerang.scene.sootup","c":"JimpleUpStaticFieldVal","l":"isNewExpr()"},{"p":"boomerang.scene.sootup","c":"JimpleUpVal","l":"isNewExpr()"},{"p":"boomerang.scene.sootup","c":"JimpleUpStaticFieldVal","l":"isNull()"},{"p":"boomerang.scene.sootup","c":"JimpleUpVal","l":"isNull()"},{"p":"boomerang.scene.sootup","c":"JimpleUpType","l":"isNullType()"},{"p":"boomerang.scene.sootup","c":"JimpleUpMethod","l":"isParameterLocal(Val)","url":"isParameterLocal(boomerang.scene.Val)"},{"p":"boomerang.scene.sootup","c":"JimpleUpStatement","l":"isPhiStatement()"},{"p":"boomerang.scene.sootup","c":"JimpleUpMethod","l":"isPublic()"},{"p":"boomerang.scene.sootup","c":"JimpleUpType","l":"isRefType()"},{"p":"boomerang.scene.sootup","c":"JimpleUpStatement","l":"isReturnStmt()"},{"p":"boomerang.scene.sootup","c":"JimpleUpInvokeExpr","l":"isSpecialInvokeExpr()"},{"p":"boomerang.scene.sootup","c":"JimpleUpDeclaredMethod","l":"isStatic()"},{"p":"boomerang.scene.sootup","c":"JimpleUpMethod","l":"isStatic()"},{"p":"boomerang.scene.sootup","c":"JimpleUpStaticFieldVal","l":"isStatic()"},{"p":"boomerang.scene.sootup","c":"JimpleUpVal","l":"isStatic()"},{"p":"boomerang.scene.sootup","c":"JimpleUpStatement","l":"isStaticFieldLoad()"},{"p":"boomerang.scene.sootup","c":"JimpleUpStatement","l":"isStaticFieldStore()"},{"p":"boomerang.scene.sootup","c":"JimpleUpMethod","l":"isStaticInitializer()"},{"p":"boomerang.scene.sootup","c":"SootUpClient","l":"isStaticInitializer(JavaSootMethod)","url":"isStaticInitializer(sootup.java.core.JavaSootMethod)"},{"p":"boomerang.scene.sootup","c":"JimpleUpInvokeExpr","l":"isStaticInvokeExpr()"},{"p":"boomerang.scene.sootup","c":"JimpleUpStatement","l":"isStringAllocation()"},{"p":"boomerang.scene.sootup","c":"JimpleUpStaticFieldVal","l":"isStringBufferOrBuilder()"},{"p":"boomerang.scene.sootup","c":"JimpleUpVal","l":"isStringBufferOrBuilder()"},{"p":"boomerang.scene.sootup","c":"JimpleUpStaticFieldVal","l":"isStringConstant()"},{"p":"boomerang.scene.sootup","c":"JimpleUpVal","l":"isStringConstant()"},{"p":"boomerang.scene.sootup","c":"JimpleUpType","l":"isSubtypeOf(String)","url":"isSubtypeOf(java.lang.String)"},{"p":"boomerang.scene.sootup","c":"JimpleUpMethod","l":"isThisLocal(Val)","url":"isThisLocal(boomerang.scene.Val)"},{"p":"boomerang.scene.sootup","c":"JimpleUpStaticFieldVal","l":"isThrowableAllocationType()"},{"p":"boomerang.scene.sootup","c":"JimpleUpVal","l":"isThrowableAllocationType()"},{"p":"boomerang.scene.sootup","c":"JimpleUpStatement","l":"isThrowStmt()"},{"p":"boomerang.scene.sootup","c":"JimpleUpControlFlowGraph","l":"JimpleUpControlFlowGraph(JimpleUpMethod)","url":"%3Cinit%3E(boomerang.scene.sootup.JimpleUpMethod)"},{"p":"boomerang.scene.sootup","c":"JimpleUpDeclaredMethod","l":"JimpleUpDeclaredMethod(JimpleUpInvokeExpr, JavaSootMethod)","url":"%3Cinit%3E(boomerang.scene.sootup.JimpleUpInvokeExpr,sootup.java.core.JavaSootMethod)"},{"p":"boomerang.scene.sootup","c":"JimpleUpDoubleVal","l":"JimpleUpDoubleVal(Value, JimpleUpMethod, Val)","url":"%3Cinit%3E(sootup.core.jimple.basic.Value,boomerang.scene.sootup.JimpleUpMethod,boomerang.scene.Val)"},{"p":"boomerang.scene.sootup","c":"JimpleUpField","l":"JimpleUpField(JavaSootField)","url":"%3Cinit%3E(sootup.java.core.JavaSootField)"},{"p":"boomerang.scene.sootup","c":"JimpleUpIfStatement","l":"JimpleUpIfStatement(JIfStmt, JimpleUpMethod)","url":"%3Cinit%3E(sootup.core.jimple.common.stmt.JIfStmt,boomerang.scene.sootup.JimpleUpMethod)"},{"p":"boomerang.scene.sootup","c":"JimpleUpInstanceFieldRef","l":"JimpleUpInstanceFieldRef(JInstanceFieldRef, JimpleUpMethod)","url":"%3Cinit%3E(sootup.core.jimple.common.ref.JInstanceFieldRef,boomerang.scene.sootup.JimpleUpMethod)"},{"p":"boomerang.scene.sootup","c":"JimpleUpInvokeExpr","l":"JimpleUpInvokeExpr(AbstractInvokeExpr, JimpleUpMethod)","url":"%3Cinit%3E(sootup.core.jimple.common.expr.AbstractInvokeExpr,boomerang.scene.sootup.JimpleUpMethod)"},{"p":"boomerang.scene.sootup","c":"JimpleUpMethod","l":"JimpleUpMethod(JavaSootMethod)","url":"%3Cinit%3E(sootup.java.core.JavaSootMethod)"},{"p":"boomerang.scene.sootup","c":"JimpleUpStaticFieldVal","l":"JimpleUpStaticFieldVal(JimpleUpField, Method)","url":"%3Cinit%3E(boomerang.scene.sootup.JimpleUpField,boomerang.scene.Method)"},{"p":"boomerang.scene.sootup","c":"JimpleUpType","l":"JimpleUpType(Type)","url":"%3Cinit%3E(sootup.core.types.Type)"},{"p":"boomerang.scene.sootup","c":"JimpleUpVal","l":"JimpleUpVal(Value, JimpleUpMethod, ControlFlowGraph.Edge)","url":"%3Cinit%3E(sootup.core.jimple.basic.Value,boomerang.scene.sootup.JimpleUpMethod,boomerang.scene.ControlFlowGraph.Edge)"},{"p":"boomerang.scene.sootup","c":"JimpleUpVal","l":"JimpleUpVal(Value, JimpleUpMethod)","url":"%3Cinit%3E(sootup.core.jimple.basic.Value,boomerang.scene.sootup.JimpleUpMethod)"},{"p":"boomerang.scene.sootup","c":"JimpleUpWrappedClass","l":"JimpleUpWrappedClass(JavaSootClass)","url":"%3Cinit%3E(sootup.java.core.JavaSootClass)"},{"p":"boomerang.scene.sootup","c":"JimpleUpStatement","l":"killAtIfStmt(Val, Statement)","url":"killAtIfStmt(boomerang.scene.Val,boomerang.scene.Statement)"},{"p":"boomerang.scene.sootup","c":"SootUpDataFlowScope","l":"make()"},{"p":"boomerang.scene.sootup","c":"JimpleUpMethod","l":"of(JavaSootMethod)","url":"of(sootup.java.core.JavaSootMethod)"},{"p":"boomerang.scene.sootup","c":"SootUpClient","l":"setInstance(JavaView, JavaIdentifierFactory)","url":"setInstance(sootup.java.core.views.JavaView,sootup.java.core.JavaIdentifierFactory)"},{"p":"boomerang.scene.sootup","c":"SootUpCallGraph","l":"SootUpCallGraph(CallGraph, Collection)","url":"%3Cinit%3E(sootup.callgraph.CallGraph,java.util.Collection)"},{"p":"boomerang.scene.sootup","c":"SootUpDataFlowScope","l":"SootUpDataFlowScope()","url":"%3Cinit%3E()"},{"p":"boomerang.scene.sootup","c":"JimpleUpDeclaredMethod","l":"toString()"},{"p":"boomerang.scene.sootup","c":"JimpleUpDoubleVal","l":"toString()"},{"p":"boomerang.scene.sootup","c":"JimpleUpField","l":"toString()"},{"p":"boomerang.scene.sootup","c":"JimpleUpIfStatement","l":"toString()"},{"p":"boomerang.scene.sootup","c":"JimpleUpInstanceFieldRef","l":"toString()"},{"p":"boomerang.scene.sootup","c":"JimpleUpInvokeExpr","l":"toString()"},{"p":"boomerang.scene.sootup","c":"JimpleUpMethod","l":"toString()"},{"p":"boomerang.scene.sootup","c":"JimpleUpStatement","l":"toString()"},{"p":"boomerang.scene.sootup","c":"JimpleUpStaticFieldVal","l":"toString()"},{"p":"boomerang.scene.sootup","c":"JimpleUpVal","l":"toString()"},{"p":"boomerang.scene.sootup","c":"JimpleUpWrappedClass","l":"toString()"},{"p":"boomerang.scene.sootup","c":"BoomerangPreInterceptor","l":"TRANSFORM_CONSTANTS"},{"p":"boomerang.scene.sootup","c":"JimpleUpIfStatement","l":"uses(Val)","url":"uses(boomerang.scene.Val)"},{"p":"boomerang.scene.sootup","c":"JimpleUpStaticFieldVal","l":"withNewMethod(Method)","url":"withNewMethod(boomerang.scene.Method)"},{"p":"boomerang.scene.sootup","c":"JimpleUpVal","l":"withNewMethod(Method)","url":"withNewMethod(boomerang.scene.Method)"},{"p":"boomerang.scene.sootup","c":"JimpleUpVal","l":"withSecondVal(Val)","url":"withSecondVal(boomerang.scene.Val)"}] \ No newline at end of file diff --git a/boomerangScope-SootUp/target/apidocs/member-search-index.zip b/boomerangScope-SootUp/target/apidocs/member-search-index.zip deleted file mode 100644 index a924f299a2170644e37298b42eb793bc675a23b8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2286 zcmVbNguOs^!l%Z2t{mZ**HmPo}H&R^qNRnomeBr-boHr;jd_ zS~rq*@@;ro-cBqZA0*B%G~qZ}dGTh#V;3i+l3=k%;+t?`Yj`K+AJ zfvzW<beu&g;}rW2xhk`2jVMFoahiZFp2L ztOrIy#xyLgHwIRi9%^h&I!m{u#8@eDG{20TZnX(U1aAmTC~+Jn5{l}YA}FP!u~3M^ zZ-?!p>vTQIc(G4s#ePN6i$_DeWhsU6JnLnHy~~sb99qlJpkJ2kHzkk2IuolbgZk{&}rq` zm9$D@TXaulA<`fQ^qy^Z0RP~d$P2bji4qPO7U@*8$}2y$CUp9^$#0*ONUbn&>j|U; z#;uqTvTj#T3{$8rMqZcAWBXa8K$QhIfBYg<#XK_gp2n(>N)j^gDyn3jV;xn3VJoSV zP}2akF@=-doml&%Q0{CY^#%++ut9LVrl(j9wm#lrK(J1zNs%OezftFg@*D2hW>Fld zNFW<%{WA@PTN0r@vE9AgvAhgMLa8Y_+=2ky9S$M+npN-FKmt@W$nBOM7=6NRFt)ob zfYJLbn3OaHSv{v|*^zuV$=1W|l(q2&<+L}Np^X0A1(V#{e{h_&PKAPk3|Xj7a?W2U z3{P+vrm(2tPUZBKG*+ivW$Wiif5iIZN?#kJVsxR6PUAbfrQ1>OUbT?Nz31CS9u+E& z4G^wyH?!sS{cL>u41*0xGONRvvSn8T7+&hZ~k=&$o&R z-TU{oSeYqwI{^$&>p-UwEtgqgpmBvIQLa~pC~4GG=9Hvi6GdXK55vtVh~$V*yPOZ?ku=*QE&tIeRXK<90$AxG?8lG_ z5$trch5F3ouDp}exm@Nd5aynlLky5r^RRRXPfxa~TjCszG6%Er89H?>+Mpv@SLCl4 zX-Y*oYe8$9UZkywCYHyYH#&?|b4Uw;h9fx!;>bJZ*$U<=5=O(EJtadJa|FgCm^q`x z4j-K26AQ9Sga&wpNw*k(G=u&9`m8 z!>*-V6QHUx)O|Tk)CZGr&*{})jlC*18!G0a+K9xda{%B;VM9bVI8w&~FN&4E-%%c) zYG_CEj(N>{TXiYSTx!lGE&tbKoNZ;W+==W-pV2kCh&$B`hU`z85)AQap0jdacGMjw z=NszodU3BsJKdx^GwNHb(S^@uzFzDWEv!+sPbqupQF%$jeq-Hw8NAhy_TkFc@|k!= za+bt~^Qz$q@alMb@1&D56eN+Isg7wLRfyO@Jx2qbwyd^cFWal|+vGhT z=+2Bfvw3s@x2XnT7sCE-Mms6$UR?F)fVs9h;Kpj-x3^M!_WFe%pEc^(=i~atG1VKR3&$PBP9cYf?seeMn~P=z`U{antH~nC zj+1InzTwuz*~V+sR8|;c=2$@ItvBg3Q{OW&;b8B@zeb?;Lp{mNeU&52DY=6^qydEU zb}(+GM#ulOP2rp-dL8kTb*ud6lM_%8wxtnhSY-&`byb0Nqgl08mQ-0u%rg00;;O0C-v&SxDk-&`byb0Nqgl02lxO00000 z00000000000001OWo=?*axHUZVRB<=Eop9KWq2-Xb8l`?O9ci1000010096-0001z I2mk;80A?{s<^TWy diff --git a/boomerangScope-SootUp/target/apidocs/overview-tree.html b/boomerangScope-SootUp/target/apidocs/overview-tree.html deleted file mode 100644 index 1663fd467..000000000 --- a/boomerangScope-SootUp/target/apidocs/overview-tree.html +++ /dev/null @@ -1,209 +0,0 @@ - - - - - -Class Hierarchy (boomerangScope-SootUp 3.1.2-Sparse API) - - - - - - - - - - - - - - -
- -
-
-
-

Hierarchy For All Packages

-Package Hierarchies: - -
-
-
-

Class Hierarchy

- -
-
-
-
- -

Copyright © 2024. All rights reserved.

-
- - diff --git a/boomerangScope-SootUp/target/apidocs/package-search-index.js b/boomerangScope-SootUp/target/apidocs/package-search-index.js deleted file mode 100644 index 2cad49d0b..000000000 --- a/boomerangScope-SootUp/target/apidocs/package-search-index.js +++ /dev/null @@ -1 +0,0 @@ -packageSearchIndex = [{"l":"All Packages","url":"allpackages-index.html"},{"l":"boomerang.scene.sootup"}] \ No newline at end of file diff --git a/boomerangScope-SootUp/target/apidocs/package-search-index.zip b/boomerangScope-SootUp/target/apidocs/package-search-index.zip deleted file mode 100644 index 1ddebca71b8e9f28ff18d8956b8afbba596b8fad..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 238 zcmWIWW@Zs#;Nak3sECq^WIzIvKz2c5a&}^Rs%~*=Vo`F2Zf0IeYK2}_aeiL+y0BA$ zn}UkYoDAgf@Hyw_JoRsvExf%rEN>jUL}qZ_~k#FbE+Q;{`;0FZwVNX2n-^JoI; zP;4#$8DIy*Yk-P>VN(DUKmPse7mx+ExD4O|;?E5D0Z5($mjO3`*anwQU^s{ZDK#Lz zj>~{qyaIx5K!t%=G&2IJNzg!ChRpyLkO7}Ry!QaotAHAMpbB3AF(}|_f!G-oI|uK6 z`id_dumai5K%C3Y$;tKS_iqMPHg<*|-@e`liWLAggVM!zAP#@l;=c>S03;{#04Z~5 zN_+ss=Yg6*hTr59mzMwZ@+l~q!+?ft!fF66AXT#wWavHt30bZWFCK%!BNk}LN?0Hg z1VF_nfs`Lm^DjYZ1(1uD0u4CSIr)XAaqW6IT{!St5~1{i=i}zAy76p%_|w8rh@@c0Axr!ns=D-X+|*sY6!@wacG9%)Qn*O zl0sa739kT-&_?#oVxXF6tOnqTD)cZ}2vi$`ZU8RLAlo8=_z#*P3xI~i!lEh+Pdu-L zx{d*wgjtXbnGX_Yf@Tc7Q3YhLhPvc8noGJs2DA~1DySiA&6V{5JzFt ojAY1KXm~va;tU{v7C?Xj0BHw!K;2aXV*mgE07*qoM6N<$f;4TDA^-pY diff --git a/boomerangScope-SootUp/target/apidocs/script.js b/boomerangScope-SootUp/target/apidocs/script.js deleted file mode 100644 index 41215a5ab..000000000 --- a/boomerangScope-SootUp/target/apidocs/script.js +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. - * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - */ - -var moduleSearchIndex; -var packageSearchIndex; -var typeSearchIndex; -var memberSearchIndex; -var tagSearchIndex; -function loadScripts(doc, tag) { - createElem(doc, tag, 'jquery/jszip/dist/jszip.js'); - createElem(doc, tag, 'jquery/jszip-utils/dist/jszip-utils.js'); - if (window.navigator.userAgent.indexOf('MSIE ') > 0 || window.navigator.userAgent.indexOf('Trident/') > 0 || - window.navigator.userAgent.indexOf('Edge/') > 0) { - createElem(doc, tag, 'jquery/jszip-utils/dist/jszip-utils-ie.js'); - } - createElem(doc, tag, 'search.js'); - - $.get(pathtoroot + "module-search-index.zip") - .done(function() { - JSZipUtils.getBinaryContent(pathtoroot + "module-search-index.zip", function(e, data) { - JSZip.loadAsync(data).then(function(zip){ - zip.file("module-search-index.json").async("text").then(function(content){ - moduleSearchIndex = JSON.parse(content); - }); - }); - }); - }); - $.get(pathtoroot + "package-search-index.zip") - .done(function() { - JSZipUtils.getBinaryContent(pathtoroot + "package-search-index.zip", function(e, data) { - JSZip.loadAsync(data).then(function(zip){ - zip.file("package-search-index.json").async("text").then(function(content){ - packageSearchIndex = JSON.parse(content); - }); - }); - }); - }); - $.get(pathtoroot + "type-search-index.zip") - .done(function() { - JSZipUtils.getBinaryContent(pathtoroot + "type-search-index.zip", function(e, data) { - JSZip.loadAsync(data).then(function(zip){ - zip.file("type-search-index.json").async("text").then(function(content){ - typeSearchIndex = JSON.parse(content); - }); - }); - }); - }); - $.get(pathtoroot + "member-search-index.zip") - .done(function() { - JSZipUtils.getBinaryContent(pathtoroot + "member-search-index.zip", function(e, data) { - JSZip.loadAsync(data).then(function(zip){ - zip.file("member-search-index.json").async("text").then(function(content){ - memberSearchIndex = JSON.parse(content); - }); - }); - }); - }); - $.get(pathtoroot + "tag-search-index.zip") - .done(function() { - JSZipUtils.getBinaryContent(pathtoroot + "tag-search-index.zip", function(e, data) { - JSZip.loadAsync(data).then(function(zip){ - zip.file("tag-search-index.json").async("text").then(function(content){ - tagSearchIndex = JSON.parse(content); - }); - }); - }); - }); - if (!moduleSearchIndex) { - createElem(doc, tag, 'module-search-index.js'); - } - if (!packageSearchIndex) { - createElem(doc, tag, 'package-search-index.js'); - } - if (!typeSearchIndex) { - createElem(doc, tag, 'type-search-index.js'); - } - if (!memberSearchIndex) { - createElem(doc, tag, 'member-search-index.js'); - } - if (!tagSearchIndex) { - createElem(doc, tag, 'tag-search-index.js'); - } - $(window).resize(function() { - $('.navPadding').css('padding-top', $('.fixedNav').css("height")); - }); -} - -function createElem(doc, tag, path) { - var script = doc.createElement(tag); - var scriptElement = doc.getElementsByTagName(tag)[0]; - script.src = pathtoroot + path; - scriptElement.parentNode.insertBefore(script, scriptElement); -} - -function show(type) { - count = 0; - for (var key in data) { - var row = document.getElementById(key); - if ((data[key] & type) !== 0) { - row.style.display = ''; - row.className = (count++ % 2) ? rowColor : altColor; - } - else - row.style.display = 'none'; - } - updateTabs(type); -} - -function updateTabs(type) { - for (var value in tabs) { - var sNode = document.getElementById(tabs[value][0]); - var spanNode = sNode.firstChild; - if (value == type) { - sNode.className = activeTableTab; - spanNode.innerHTML = tabs[value][1]; - } - else { - sNode.className = tableTab; - spanNode.innerHTML = "" + tabs[value][1] + ""; - } - } -} - -function updateModuleFrame(pFrame, cFrame) { - top.packageFrame.location = pFrame; - top.classFrame.location = cFrame; -} diff --git a/boomerangScope-SootUp/target/apidocs/search.js b/boomerangScope-SootUp/target/apidocs/search.js deleted file mode 100644 index 38160c2fb..000000000 --- a/boomerangScope-SootUp/target/apidocs/search.js +++ /dev/null @@ -1,326 +0,0 @@ -/* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. - * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - */ - -var noResult = {l: "No results found"}; -var catModules = "Modules"; -var catPackages = "Packages"; -var catTypes = "Types"; -var catMembers = "Members"; -var catSearchTags = "SearchTags"; -var highlight = "$&"; -var camelCaseRegexp = ""; -var secondaryMatcher = ""; -function getHighlightedText(item) { - var ccMatcher = new RegExp(camelCaseRegexp); - var label = item.replace(ccMatcher, highlight); - if (label === item) { - label = item.replace(secondaryMatcher, highlight); - } - return label; -} -function getURLPrefix(ui) { - var urlPrefix=""; - if (useModuleDirectories) { - var slash = "/"; - if (ui.item.category === catModules) { - return ui.item.l + slash; - } else if (ui.item.category === catPackages && ui.item.m) { - return ui.item.m + slash; - } else if ((ui.item.category === catTypes && ui.item.p) || ui.item.category === catMembers) { - $.each(packageSearchIndex, function(index, item) { - if (ui.item.p == item.l) { - urlPrefix = item.m + slash; - } - }); - return urlPrefix; - } else { - return urlPrefix; - } - } - return urlPrefix; -} -var watermark = 'Search'; -$(function() { - $("#search").val(''); - $("#search").prop("disabled", false); - $("#reset").prop("disabled", false); - $("#search").val(watermark).addClass('watermark'); - $("#search").blur(function() { - if ($(this).val().length == 0) { - $(this).val(watermark).addClass('watermark'); - } - }); - $("#search").on('click keydown', function() { - if ($(this).val() == watermark) { - $(this).val('').removeClass('watermark'); - } - }); - $("#reset").click(function() { - $("#search").val(''); - $("#search").focus(); - }); - $("#search").focus(); - $("#search")[0].setSelectionRange(0, 0); -}); -$.widget("custom.catcomplete", $.ui.autocomplete, { - _create: function() { - this._super(); - this.widget().menu("option", "items", "> :not(.ui-autocomplete-category)"); - }, - _renderMenu: function(ul, items) { - var rMenu = this, - currentCategory = ""; - rMenu.menu.bindings = $(); - $.each(items, function(index, item) { - var li; - if (item.l !== noResult.l && item.category !== currentCategory) { - ul.append("
  • " + item.category + "
  • "); - currentCategory = item.category; - } - li = rMenu._renderItemData(ul, item); - if (item.category) { - li.attr("aria-label", item.category + " : " + item.l); - li.attr("class", "resultItem"); - } else { - li.attr("aria-label", item.l); - li.attr("class", "resultItem"); - } - }); - }, - _renderItem: function(ul, item) { - var label = ""; - if (item.category === catModules) { - label = getHighlightedText(item.l); - } else if (item.category === catPackages) { - label = (item.m) - ? getHighlightedText(item.m + "/" + item.l) - : getHighlightedText(item.l); - } else if (item.category === catTypes) { - label = (item.p) - ? getHighlightedText(item.p + "." + item.l) - : getHighlightedText(item.l); - } else if (item.category === catMembers) { - label = getHighlightedText(item.p + "." + (item.c + "." + item.l)); - } else if (item.category === catSearchTags) { - label = getHighlightedText(item.l); - } else { - label = item.l; - } - var li = $("
  • ").appendTo(ul); - var div = $("
    ").appendTo(li); - if (item.category === catSearchTags) { - if (item.d) { - div.html(label + " (" + item.h + ")
    " - + item.d + "
    "); - } else { - div.html(label + " (" + item.h + ")"); - } - } else { - div.html(label); - } - return li; - } -}); -$(function() { - $("#search").catcomplete({ - minLength: 1, - delay: 100, - source: function(request, response) { - var result = new Array(); - var presult = new Array(); - var tresult = new Array(); - var mresult = new Array(); - var tgresult = new Array(); - var secondaryresult = new Array(); - var displayCount = 0; - var exactMatcher = new RegExp("^" + $.ui.autocomplete.escapeRegex(request.term) + "$", "i"); - camelCaseRegexp = ($.ui.autocomplete.escapeRegex(request.term)).split(/(?=[A-Z])/).join("([a-z0-9_$]*?)"); - var camelCaseMatcher = new RegExp("^" + camelCaseRegexp); - secondaryMatcher = new RegExp($.ui.autocomplete.escapeRegex(request.term), "i"); - - // Return the nested innermost name from the specified object - function nestedName(e) { - return e.l.substring(e.l.lastIndexOf(".") + 1); - } - - function concatResults(a1, a2) { - a1 = a1.concat(a2); - a2.length = 0; - return a1; - } - - if (moduleSearchIndex) { - var mdleCount = 0; - $.each(moduleSearchIndex, function(index, item) { - item.category = catModules; - if (exactMatcher.test(item.l)) { - result.push(item); - mdleCount++; - } else if (camelCaseMatcher.test(item.l)) { - result.push(item); - } else if (secondaryMatcher.test(item.l)) { - secondaryresult.push(item); - } - }); - displayCount = mdleCount; - result = concatResults(result, secondaryresult); - } - if (packageSearchIndex) { - var pCount = 0; - var pkg = ""; - $.each(packageSearchIndex, function(index, item) { - item.category = catPackages; - pkg = (item.m) - ? (item.m + "/" + item.l) - : item.l; - if (exactMatcher.test(item.l)) { - presult.push(item); - pCount++; - } else if (camelCaseMatcher.test(pkg)) { - presult.push(item); - } else if (secondaryMatcher.test(pkg)) { - secondaryresult.push(item); - } - }); - result = result.concat(concatResults(presult, secondaryresult)); - displayCount = (pCount > displayCount) ? pCount : displayCount; - } - if (typeSearchIndex) { - var tCount = 0; - $.each(typeSearchIndex, function(index, item) { - item.category = catTypes; - var s = nestedName(item); - if (exactMatcher.test(s)) { - tresult.push(item); - tCount++; - } else if (camelCaseMatcher.test(s)) { - tresult.push(item); - } else if (secondaryMatcher.test(item.p + "." + item.l)) { - secondaryresult.push(item); - } - }); - result = result.concat(concatResults(tresult, secondaryresult)); - displayCount = (tCount > displayCount) ? tCount : displayCount; - } - if (memberSearchIndex) { - var mCount = 0; - $.each(memberSearchIndex, function(index, item) { - item.category = catMembers; - var s = nestedName(item); - if (exactMatcher.test(s)) { - mresult.push(item); - mCount++; - } else if (camelCaseMatcher.test(s)) { - mresult.push(item); - } else if (secondaryMatcher.test(item.c + "." + item.l)) { - secondaryresult.push(item); - } - }); - result = result.concat(concatResults(mresult, secondaryresult)); - displayCount = (mCount > displayCount) ? mCount : displayCount; - } - if (tagSearchIndex) { - var tgCount = 0; - $.each(tagSearchIndex, function(index, item) { - item.category = catSearchTags; - if (exactMatcher.test(item.l)) { - tgresult.push(item); - tgCount++; - } else if (secondaryMatcher.test(item.l)) { - secondaryresult.push(item); - } - }); - result = result.concat(concatResults(tgresult, secondaryresult)); - displayCount = (tgCount > displayCount) ? tgCount : displayCount; - } - displayCount = (displayCount > 500) ? displayCount : 500; - var counter = function() { - var count = {Modules: 0, Packages: 0, Types: 0, Members: 0, SearchTags: 0}; - var f = function(item) { - count[item.category] += 1; - return (count[item.category] <= displayCount); - }; - return f; - }(); - response(result.filter(counter)); - }, - response: function(event, ui) { - if (!ui.content.length) { - ui.content.push(noResult); - } else { - $("#search").empty(); - } - }, - autoFocus: true, - position: { - collision: "flip" - }, - select: function(event, ui) { - if (ui.item.l !== noResult.l) { - var url = getURLPrefix(ui); - if (ui.item.category === catModules) { - if (useModuleDirectories) { - url += "module-summary.html"; - } else { - url = ui.item.l + "-summary.html"; - } - } else if (ui.item.category === catPackages) { - if (ui.item.url) { - url = ui.item.url; - } else { - url += ui.item.l.replace(/\./g, '/') + "/package-summary.html"; - } - } else if (ui.item.category === catTypes) { - if (ui.item.url) { - url = ui.item.url; - } else if (ui.item.p === "") { - url += ui.item.l + ".html"; - } else { - url += ui.item.p.replace(/\./g, '/') + "/" + ui.item.l + ".html"; - } - } else if (ui.item.category === catMembers) { - if (ui.item.p === "") { - url += ui.item.c + ".html" + "#"; - } else { - url += ui.item.p.replace(/\./g, '/') + "/" + ui.item.c + ".html" + "#"; - } - if (ui.item.url) { - url += ui.item.url; - } else { - url += ui.item.l; - } - } else if (ui.item.category === catSearchTags) { - url += ui.item.u; - } - if (top !== window) { - parent.classFrame.location = pathtoroot + url; - } else { - window.location.href = pathtoroot + url; - } - $("#search").focus(); - } - } - }); -}); diff --git a/boomerangScope-SootUp/target/apidocs/stylesheet.css b/boomerangScope-SootUp/target/apidocs/stylesheet.css deleted file mode 100644 index fa246765c..000000000 --- a/boomerangScope-SootUp/target/apidocs/stylesheet.css +++ /dev/null @@ -1,906 +0,0 @@ -/* - * Javadoc style sheet - */ - -@import url('resources/fonts/dejavu.css'); - -/* - * Styles for individual HTML elements. - * - * These are styles that are specific to individual HTML elements. Changing them affects the style of a particular - * HTML element throughout the page. - */ - -body { - background-color:#ffffff; - color:#353833; - font-family:'DejaVu Sans', Arial, Helvetica, sans-serif; - font-size:14px; - margin:0; - padding:0; - height:100%; - width:100%; -} -iframe { - margin:0; - padding:0; - height:100%; - width:100%; - overflow-y:scroll; - border:none; -} -a:link, a:visited { - text-decoration:none; - color:#4A6782; -} -a[href]:hover, a[href]:focus { - text-decoration:none; - color:#bb7a2a; -} -a[name] { - color:#353833; -} -a[name]:before, a[name]:target, a[id]:before, a[id]:target { - content:""; - display:inline-block; - position:relative; - padding-top:129px; - margin-top:-129px; -} -pre { - font-family:'DejaVu Sans Mono', monospace; - font-size:14px; -} -h1 { - font-size:20px; -} -h2 { - font-size:18px; -} -h3 { - font-size:16px; - font-style:italic; -} -h4 { - font-size:13px; -} -h5 { - font-size:12px; -} -h6 { - font-size:11px; -} -ul { - list-style-type:disc; -} -code, tt { - font-family:'DejaVu Sans Mono', monospace; - font-size:14px; - padding-top:4px; - margin-top:8px; - line-height:1.4em; -} -dt code { - font-family:'DejaVu Sans Mono', monospace; - font-size:14px; - padding-top:4px; -} -table tr td dt code { - font-family:'DejaVu Sans Mono', monospace; - font-size:14px; - vertical-align:top; - padding-top:4px; -} -sup { - font-size:8px; -} - -/* - * Styles for HTML generated by javadoc. - * - * These are style classes that are used by the standard doclet to generate HTML documentation. - */ - -/* - * Styles for document title and copyright. - */ -.clear { - clear:both; - height:0px; - overflow:hidden; -} -.aboutLanguage { - float:right; - padding:0px 21px; - font-size:11px; - z-index:200; - margin-top:-9px; -} -.legalCopy { - margin-left:.5em; -} -.bar a, .bar a:link, .bar a:visited, .bar a:active { - color:#FFFFFF; - text-decoration:none; -} -.bar a:hover, .bar a:focus { - color:#bb7a2a; -} -.tab { - background-color:#0066FF; - color:#ffffff; - padding:8px; - width:5em; - font-weight:bold; -} -/* - * Styles for navigation bar. - */ -.bar { - background-color:#4D7A97; - color:#FFFFFF; - padding:.8em .5em .4em .8em; - height:auto;/*height:1.8em;*/ - font-size:11px; - margin:0; -} -.navPadding { - padding-top: 107px; -} -.fixedNav { - position:fixed; - width:100%; - z-index:999; - background-color:#ffffff; -} -.topNav { - background-color:#4D7A97; - color:#FFFFFF; - float:left; - padding:0; - width:100%; - clear:right; - height:2.8em; - padding-top:10px; - overflow:hidden; - font-size:12px; -} -.bottomNav { - margin-top:10px; - background-color:#4D7A97; - color:#FFFFFF; - float:left; - padding:0; - width:100%; - clear:right; - height:2.8em; - padding-top:10px; - overflow:hidden; - font-size:12px; -} -.subNav { - background-color:#dee3e9; - float:left; - width:100%; - overflow:hidden; - font-size:12px; -} -.subNav div { - clear:left; - float:left; - padding:0 0 5px 6px; - text-transform:uppercase; -} -ul.navList, ul.subNavList { - float:left; - margin:0 25px 0 0; - padding:0; -} -ul.navList li{ - list-style:none; - float:left; - padding: 5px 6px; - text-transform:uppercase; -} -ul.navListSearch { - float:right; - margin:0 0 0 0; - padding:0; -} -ul.navListSearch li { - list-style:none; - float:right; - padding: 5px 6px; - text-transform:uppercase; -} -ul.navListSearch li label { - position:relative; - right:-16px; -} -ul.subNavList li { - list-style:none; - float:left; -} -.topNav a:link, .topNav a:active, .topNav a:visited, .bottomNav a:link, .bottomNav a:active, .bottomNav a:visited { - color:#FFFFFF; - text-decoration:none; - text-transform:uppercase; -} -.topNav a:hover, .bottomNav a:hover { - text-decoration:none; - color:#bb7a2a; - text-transform:uppercase; -} -.navBarCell1Rev { - background-color:#F8981D; - color:#253441; - margin: auto 5px; -} -.skipNav { - position:absolute; - top:auto; - left:-9999px; - overflow:hidden; -} -/* - * Styles for page header and footer. - */ -.header, .footer { - clear:both; - margin:0 20px; - padding:5px 0 0 0; -} -.indexNav { - position:relative; - font-size:12px; - background-color:#dee3e9; -} -.indexNav ul { - margin-top:0; - padding:5px; -} -.indexNav ul li { - display:inline; - list-style-type:none; - padding-right:10px; - text-transform:uppercase; -} -.indexNav h1 { - font-size:13px; -} -.title { - color:#2c4557; - margin:10px 0; -} -.subTitle { - margin:5px 0 0 0; -} -.header ul { - margin:0 0 15px 0; - padding:0; -} -.footer ul { - margin:20px 0 5px 0; -} -.header ul li, .footer ul li { - list-style:none; - font-size:13px; -} -/* - * Styles for headings. - */ -div.details ul.blockList ul.blockList ul.blockList li.blockList h4, div.details ul.blockList ul.blockList ul.blockListLast li.blockList h4 { - background-color:#dee3e9; - border:1px solid #d0d9e0; - margin:0 0 6px -8px; - padding:7px 5px; -} -ul.blockList ul.blockList ul.blockList li.blockList h3 { - background-color:#dee3e9; - border:1px solid #d0d9e0; - margin:0 0 6px -8px; - padding:7px 5px; -} -ul.blockList ul.blockList li.blockList h3 { - padding:0; - margin:15px 0; -} -ul.blockList li.blockList h2 { - padding:0px 0 20px 0; -} -/* - * Styles for page layout containers. - */ -.contentContainer, .sourceContainer, .classUseContainer, .serializedFormContainer, .constantValuesContainer, -.allClassesContainer, .allPackagesContainer { - clear:both; - padding:10px 20px; - position:relative; -} -.indexContainer { - margin:10px; - position:relative; - font-size:12px; -} -.indexContainer h2 { - font-size:13px; - padding:0 0 3px 0; -} -.indexContainer ul { - margin:0; - padding:0; -} -.indexContainer ul li { - list-style:none; - padding-top:2px; -} -.contentContainer .description dl dt, .contentContainer .details dl dt, .serializedFormContainer dl dt { - font-size:12px; - font-weight:bold; - margin:10px 0 0 0; - color:#4E4E4E; -} -.contentContainer .description dl dd, .contentContainer .details dl dd, .serializedFormContainer dl dd { - margin:5px 0 10px 0px; - font-size:14px; - font-family:'DejaVu Serif', Georgia, "Times New Roman", Times, serif; -} -.serializedFormContainer dl.nameValue dt { - margin-left:1px; - font-size:1.1em; - display:inline; - font-weight:bold; -} -.serializedFormContainer dl.nameValue dd { - margin:0 0 0 1px; - font-size:1.1em; - display:inline; -} -/* - * Styles for lists. - */ -li.circle { - list-style:circle; -} -ul.horizontal li { - display:inline; - font-size:0.9em; -} -ul.inheritance { - margin:0; - padding:0; -} -ul.inheritance li { - display:inline; - list-style:none; -} -ul.inheritance li ul.inheritance { - margin-left:15px; - padding-left:15px; - padding-top:1px; -} -ul.blockList, ul.blockListLast { - margin:10px 0 10px 0; - padding:0; -} -ul.blockList li.blockList, ul.blockListLast li.blockList { - list-style:none; - margin-bottom:15px; - line-height:1.4; -} -ul.blockList ul.blockList li.blockList, ul.blockList ul.blockListLast li.blockList { - padding:0px 20px 5px 10px; - border:1px solid #ededed; - background-color:#f8f8f8; -} -ul.blockList ul.blockList ul.blockList li.blockList, ul.blockList ul.blockList ul.blockListLast li.blockList { - padding:0 0 5px 8px; - background-color:#ffffff; - border:none; -} -ul.blockList ul.blockList ul.blockList ul.blockList li.blockList { - margin-left:0; - padding-left:0; - padding-bottom:15px; - border:none; -} -ul.blockList ul.blockList ul.blockList ul.blockList li.blockListLast { - list-style:none; - border-bottom:none; - padding-bottom:0; -} -table tr td dl, table tr td dl dt, table tr td dl dd { - margin-top:0; - margin-bottom:1px; -} -/* - * Styles for tables. - */ -.overviewSummary, .memberSummary, .typeSummary, .useSummary, .constantsSummary, .deprecatedSummary, -.requiresSummary, .packagesSummary, .providesSummary, .usesSummary { - width:100%; - border-spacing:0; - border-left:1px solid #EEE; - border-right:1px solid #EEE; - border-bottom:1px solid #EEE; -} -.overviewSummary, .memberSummary, .requiresSummary, .packagesSummary, .providesSummary, .usesSummary { - padding:0px; -} -.overviewSummary caption, .memberSummary caption, .typeSummary caption, -.useSummary caption, .constantsSummary caption, .deprecatedSummary caption, -.requiresSummary caption, .packagesSummary caption, .providesSummary caption, .usesSummary caption { - position:relative; - text-align:left; - background-repeat:no-repeat; - color:#253441; - font-weight:bold; - clear:none; - overflow:hidden; - padding:0px; - padding-top:10px; - padding-left:1px; - margin:0px; - white-space:pre; -} -.overviewSummary caption a:link, .memberSummary caption a:link, .typeSummary caption a:link, -.constantsSummary caption a:link, .deprecatedSummary caption a:link, -.requiresSummary caption a:link, .packagesSummary caption a:link, .providesSummary caption a:link, -.usesSummary caption a:link, -.overviewSummary caption a:hover, .memberSummary caption a:hover, .typeSummary caption a:hover, -.constantsSummary caption a:hover, .deprecatedSummary caption a:hover, -.requiresSummary caption a:hover, .packagesSummary caption a:hover, .providesSummary caption a:hover, -.usesSummary caption a:hover, -.overviewSummary caption a:active, .memberSummary caption a:active, .typeSummary caption a:active, -.constantsSummary caption a:active, .deprecatedSummary caption a:active, -.requiresSummary caption a:active, .packagesSummary caption a:active, .providesSummary caption a:active, -.usesSummary caption a:active, -.overviewSummary caption a:visited, .memberSummary caption a:visited, .typeSummary caption a:visited, -.constantsSummary caption a:visited, .deprecatedSummary caption a:visited, -.requiresSummary caption a:visited, .packagesSummary caption a:visited, .providesSummary caption a:visited, -.usesSummary caption a:visited { - color:#FFFFFF; -} -.useSummary caption a:link, .useSummary caption a:hover, .useSummary caption a:active, -.useSummary caption a:visited { - color:#1f389c; -} -.overviewSummary caption span, .memberSummary caption span, .typeSummary caption span, -.useSummary caption span, .constantsSummary caption span, .deprecatedSummary caption span, -.requiresSummary caption span, .packagesSummary caption span, .providesSummary caption span, -.usesSummary caption span { - white-space:nowrap; - padding-top:5px; - padding-left:12px; - padding-right:12px; - padding-bottom:7px; - display:inline-block; - float:left; - background-color:#F8981D; - border: none; - height:16px; -} -.memberSummary caption span.activeTableTab span, .packagesSummary caption span.activeTableTab span, -.overviewSummary caption span.activeTableTab span, .typeSummary caption span.activeTableTab span { - white-space:nowrap; - padding-top:5px; - padding-left:12px; - padding-right:12px; - margin-right:3px; - display:inline-block; - float:left; - background-color:#F8981D; - height:16px; -} -.memberSummary caption span.tableTab span, .packagesSummary caption span.tableTab span, -.overviewSummary caption span.tableTab span, .typeSummary caption span.tableTab span { - white-space:nowrap; - padding-top:5px; - padding-left:12px; - padding-right:12px; - margin-right:3px; - display:inline-block; - float:left; - background-color:#4D7A97; - height:16px; -} -.memberSummary caption span.tableTab, .memberSummary caption span.activeTableTab, -.packagesSummary caption span.tableTab, .packagesSummary caption span.activeTableTab, -.overviewSummary caption span.tableTab, .overviewSummary caption span.activeTableTab, -.typeSummary caption span.tableTab, .typeSummary caption span.activeTableTab { - padding-top:0px; - padding-left:0px; - padding-right:0px; - background-image:none; - float:none; - display:inline; -} -.overviewSummary .tabEnd, .memberSummary .tabEnd, .typeSummary .tabEnd, -.useSummary .tabEnd, .constantsSummary .tabEnd, .deprecatedSummary .tabEnd, -.requiresSummary .tabEnd, .packagesSummary .tabEnd, .providesSummary .tabEnd, .usesSummary .tabEnd { - display:none; - width:5px; - position:relative; - float:left; - background-color:#F8981D; -} -.memberSummary .activeTableTab .tabEnd, .packagesSummary .activeTableTab .tabEnd, -.overviewSummary .activeTableTab .tabEnd, .typeSummary .activeTableTab .tabEnd { - display:none; - width:5px; - margin-right:3px; - position:relative; - float:left; - background-color:#F8981D; -} -.memberSummary .tableTab .tabEnd, .packagesSummary .tableTab .tabEnd, -.overviewSummary .tableTab .tabEnd, .typeSummary .tableTab .tabEnd { - display:none; - width:5px; - margin-right:3px; - position:relative; - background-color:#4D7A97; - float:left; -} -.rowColor th, .altColor th { - font-weight:normal; -} -.overviewSummary td, .memberSummary td, .typeSummary td, -.useSummary td, .constantsSummary td, .deprecatedSummary td, -.requiresSummary td, .packagesSummary td, .providesSummary td, .usesSummary td { - text-align:left; - padding:0px 0px 12px 10px; -} -th.colFirst, th.colSecond, th.colLast, th.colConstructorName, th.colDeprecatedItemName, .useSummary th, -.constantsSummary th, .packagesSummary th, td.colFirst, td.colSecond, td.colLast, .useSummary td, -.constantsSummary td { - vertical-align:top; - padding-right:0px; - padding-top:8px; - padding-bottom:3px; -} -th.colFirst, th.colSecond, th.colLast, th.colConstructorName, th.colDeprecatedItemName, .constantsSummary th, -.packagesSummary th { - background:#dee3e9; - text-align:left; - padding:8px 3px 3px 7px; -} -td.colFirst, th.colFirst { - font-size:13px; -} -td.colSecond, th.colSecond, td.colLast, th.colConstructorName, th.colDeprecatedItemName, th.colLast { - font-size:13px; -} -.constantsSummary th, .packagesSummary th { - font-size:13px; -} -.providesSummary th.colFirst, .providesSummary th.colLast, .providesSummary td.colFirst, -.providesSummary td.colLast { - white-space:normal; - font-size:13px; -} -.overviewSummary td.colFirst, .overviewSummary th.colFirst, -.requiresSummary td.colFirst, .requiresSummary th.colFirst, -.packagesSummary td.colFirst, .packagesSummary td.colSecond, .packagesSummary th.colFirst, .packagesSummary th, -.usesSummary td.colFirst, .usesSummary th.colFirst, -.providesSummary td.colFirst, .providesSummary th.colFirst, -.memberSummary td.colFirst, .memberSummary th.colFirst, -.memberSummary td.colSecond, .memberSummary th.colSecond, .memberSummary th.colConstructorName, -.typeSummary td.colFirst, .typeSummary th.colFirst { - vertical-align:top; -} -.packagesSummary th.colLast, .packagesSummary td.colLast { - white-space:normal; -} -td.colFirst a:link, td.colFirst a:visited, -td.colSecond a:link, td.colSecond a:visited, -th.colFirst a:link, th.colFirst a:visited, -th.colSecond a:link, th.colSecond a:visited, -th.colConstructorName a:link, th.colConstructorName a:visited, -th.colDeprecatedItemName a:link, th.colDeprecatedItemName a:visited, -.constantValuesContainer td a:link, .constantValuesContainer td a:visited, -.allClassesContainer td a:link, .allClassesContainer td a:visited, -.allPackagesContainer td a:link, .allPackagesContainer td a:visited { - font-weight:bold; -} -.tableSubHeadingColor { - background-color:#EEEEFF; -} -.altColor, .altColor th { - background-color:#FFFFFF; -} -.rowColor, .rowColor th { - background-color:#EEEEEF; -} -/* - * Styles for contents. - */ -.description pre { - margin-top:0; -} -.deprecatedContent { - margin:0; - padding:10px 0; -} -.docSummary { - padding:0; -} -ul.blockList ul.blockList ul.blockList li.blockList h3 { - font-style:normal; -} -div.block { - font-size:14px; - font-family:'DejaVu Serif', Georgia, "Times New Roman", Times, serif; -} -td.colLast div { - padding-top:0px; -} -td.colLast a { - padding-bottom:3px; -} -/* - * Styles for formatting effect. - */ -.sourceLineNo { - color:green; - padding:0 30px 0 0; -} -h1.hidden { - visibility:hidden; - overflow:hidden; - font-size:10px; -} -.block { - display:block; - margin:3px 10px 2px 0px; - color:#474747; -} -.deprecatedLabel, .descfrmTypeLabel, .implementationLabel, .memberNameLabel, .memberNameLink, -.moduleLabelInPackage, .moduleLabelInType, .overrideSpecifyLabel, .packageLabelInType, -.packageHierarchyLabel, .paramLabel, .returnLabel, .seeLabel, .simpleTagLabel, -.throwsLabel, .typeNameLabel, .typeNameLink, .searchTagLink { - font-weight:bold; -} -.deprecationComment, .emphasizedPhrase, .interfaceName { - font-style:italic; -} -.deprecationBlock { - font-size:14px; - font-family:'DejaVu Serif', Georgia, "Times New Roman", Times, serif; - border-style:solid; - border-width:thin; - border-radius:10px; - padding:10px; - margin-bottom:10px; - margin-right:10px; - display:inline-block; -} -div.block div.deprecationComment, div.block div.block span.emphasizedPhrase, -div.block div.block span.interfaceName { - font-style:normal; -} -div.contentContainer ul.blockList li.blockList h2 { - padding-bottom:0px; -} -/* - * Styles for IFRAME. - */ -.mainContainer { - margin:0 auto; - padding:0; - height:100%; - width:100%; - position:fixed; - top:0; - left:0; -} -.leftContainer { - height:100%; - position:fixed; - width:320px; -} -.leftTop { - position:relative; - float:left; - width:315px; - top:0; - left:0; - height:30%; - border-right:6px solid #ccc; - border-bottom:6px solid #ccc; -} -.leftBottom { - position:relative; - float:left; - width:315px; - bottom:0; - left:0; - height:70%; - border-right:6px solid #ccc; - border-top:1px solid #000; -} -.rightContainer { - position:absolute; - left:320px; - top:0; - bottom:0; - height:100%; - right:0; - border-left:1px solid #000; -} -.rightIframe { - margin:0; - padding:0; - height:100%; - right:30px; - width:100%; - overflow:visible; - margin-bottom:30px; -} -/* - * Styles specific to HTML5 elements. - */ -main, nav, header, footer, section { - display:block; -} -/* - * Styles for javadoc search. - */ -.ui-autocomplete-category { - font-weight:bold; - font-size:15px; - padding:7px 0 7px 3px; - background-color:#4D7A97; - color:#FFFFFF; -} -.resultItem { - font-size:13px; -} -.ui-autocomplete { - max-height:85%; - max-width:65%; - overflow-y:scroll; - overflow-x:scroll; - white-space:nowrap; - box-shadow: 0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23); -} -ul.ui-autocomplete { - position:fixed; - z-index:999999; -} -ul.ui-autocomplete li { - float:left; - clear:both; - width:100%; -} -.resultHighlight { - font-weight:bold; -} -#search { - background-image:url('resources/glass.png'); - background-size:13px; - background-repeat:no-repeat; - background-position:2px 3px; - padding-left:20px; - position:relative; - right:-18px; -} -#reset { - background-color: rgb(255,255,255); - background-image:url('resources/x.png'); - background-position:center; - background-repeat:no-repeat; - background-size:12px; - border:0 none; - width:16px; - height:17px; - position:relative; - left:-4px; - top:-4px; - font-size:0px; -} -.watermark { - color:#545454; -} -.searchTagDescResult { - font-style:italic; - font-size:11px; -} -.searchTagHolderResult { - font-style:italic; - font-size:12px; -} -.searchTagResult:before, .searchTagResult:target { - color:red; -} -.moduleGraph span { - display:none; - position:absolute; -} -.moduleGraph:hover span { - display:block; - margin: -100px 0 0 100px; - z-index: 1; -} -.methodSignature { - white-space:normal; -} - -/* - * Styles for user-provided tables. - * - * borderless: - * No borders, vertical margins, styled caption. - * This style is provided for use with existing doc comments. - * In general, borderless tables should not be used for layout purposes. - * - * plain: - * Plain borders around table and cells, vertical margins, styled caption. - * Best for small tables or for complex tables for tables with cells that span - * rows and columns, when the "striped" style does not work well. - * - * striped: - * Borders around the table and vertical borders between cells, striped rows, - * vertical margins, styled caption. - * Best for tables that have a header row, and a body containing a series of simple rows. - */ - -table.borderless, -table.plain, -table.striped { - margin-top: 10px; - margin-bottom: 10px; -} -table.borderless > caption, -table.plain > caption, -table.striped > caption { - font-weight: bold; - font-size: smaller; -} -table.borderless th, table.borderless td, -table.plain th, table.plain td, -table.striped th, table.striped td { - padding: 2px 5px; -} -table.borderless, -table.borderless > thead > tr > th, table.borderless > tbody > tr > th, table.borderless > tr > th, -table.borderless > thead > tr > td, table.borderless > tbody > tr > td, table.borderless > tr > td { - border: none; -} -table.borderless > thead > tr, table.borderless > tbody > tr, table.borderless > tr { - background-color: transparent; -} -table.plain { - border-collapse: collapse; - border: 1px solid black; -} -table.plain > thead > tr, table.plain > tbody tr, table.plain > tr { - background-color: transparent; -} -table.plain > thead > tr > th, table.plain > tbody > tr > th, table.plain > tr > th, -table.plain > thead > tr > td, table.plain > tbody > tr > td, table.plain > tr > td { - border: 1px solid black; -} -table.striped { - border-collapse: collapse; - border: 1px solid black; -} -table.striped > thead { - background-color: #E3E3E3; -} -table.striped > thead > tr > th, table.striped > thead > tr > td { - border: 1px solid black; -} -table.striped > tbody > tr:nth-child(even) { - background-color: #EEE -} -table.striped > tbody > tr:nth-child(odd) { - background-color: #FFF -} -table.striped > tbody > tr > th, table.striped > tbody > tr > td { - border-left: 1px solid black; - border-right: 1px solid black; -} -table.striped > tbody > tr > th { - font-weight: normal; -} diff --git a/boomerangScope-SootUp/target/apidocs/type-search-index.js b/boomerangScope-SootUp/target/apidocs/type-search-index.js deleted file mode 100644 index 6da93b625..000000000 --- a/boomerangScope-SootUp/target/apidocs/type-search-index.js +++ /dev/null @@ -1 +0,0 @@ -typeSearchIndex = [{"l":"All Classes","url":"allclasses-index.html"},{"p":"boomerang.scene.sootup","l":"BoomerangPreInterceptor"},{"p":"boomerang.scene.sootup","l":"JimpleUpControlFlowGraph"},{"p":"boomerang.scene.sootup","l":"JimpleUpDeclaredMethod"},{"p":"boomerang.scene.sootup","l":"JimpleUpDoubleVal"},{"p":"boomerang.scene.sootup","l":"JimpleUpField"},{"p":"boomerang.scene.sootup","l":"JimpleUpIfStatement"},{"p":"boomerang.scene.sootup","l":"JimpleUpInstanceFieldRef"},{"p":"boomerang.scene.sootup","l":"JimpleUpInvokeExpr"},{"p":"boomerang.scene.sootup","l":"JimpleUpMethod"},{"p":"boomerang.scene.sootup","l":"JimpleUpStatement"},{"p":"boomerang.scene.sootup","l":"JimpleUpStaticFieldVal"},{"p":"boomerang.scene.sootup","l":"JimpleUpType"},{"p":"boomerang.scene.sootup","l":"JimpleUpVal"},{"p":"boomerang.scene.sootup","l":"JimpleUpWrappedClass"},{"p":"boomerang.scene.sootup","l":"SootUpCallGraph"},{"p":"boomerang.scene.sootup","l":"SootUpClient"},{"p":"boomerang.scene.sootup","l":"SootUpDataFlowScope"}] \ No newline at end of file diff --git a/boomerangScope-SootUp/target/apidocs/type-search-index.zip b/boomerangScope-SootUp/target/apidocs/type-search-index.zip deleted file mode 100644 index cd10362cc4f3f3b4f6d51f5e67934da903c9ff4e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 392 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�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

    me;PVQ1ku(RM|9#^5YJsYoC#E(RuhWy9e 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 z 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

    wjlhsj!GDjy-~xaCCk2K-%qz>Oh1ujOl)j-8 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 z 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 z zYIsZqSf3sA;AbGN|A}f26V|DV2~2||AxfaL!fvUoXBmq(dR+vQ9-KUM^r*k@ydCN&wba z1q1?CxuXV!IG3J^{o5h|gKu|#=zWI`Ofeu$a~z>z?jWi=9e&!<0Mk&`wT(Uxn9pPg z{QRbY0Jt?eAqO3XjFioZ3j&P2M%3!&b`IFzmj3I2(nCBHA~kv{`-Eix#_cWOPSF4^ zBXiCn!37EC#;M$slRpe??e9S?59ArTVfgq?$3{BM9WeA?Qa+4-o#&c^3*c@SZ4l`C zp+A7%P>A&9Q~3xJJ&Zc-TES5XSUo=h0>N&j4;vJM#&{|fQF@0#&vh;8w*#i4nu0(q zheY5v6oM;qD)iK(o}SfDrz19!wG zfX%;qm`?3f@X=8X@Ha391ROta0OrO6OX=?(me)O%3f#Z{VJghS@)WZ^XMsB!HQ>7P zcOR4)p9no|IfH>S>dY+IfwXZ+7~TgYwx@wlUc@XtsZqrMbK8JxiQh9_=)F^@e_y&_ zk0xdyX=a?j3K<9F3m}q@8WeK*5faGA_8^xzF}fI7IfEVl@Ft8f{?(X~3LuF8L3j*o z>N5u0Ie?9T3v%EvV&L^g2nkMR3m9a8W?+m#K;R!WD5O6W2?Vw}xR^f>hYych0b&nW zp0)rY4p_a88WeIV3<+cgwz6Y1wlzYiRB=|i)ev}`!YhY#P>Fab3x#aN0-N7pXT354 z*DeTUmj_W^y#*edSOPckz`z_eD8wiCA6bNQIbp+zn&LdIx)N^*A~8ObktU z!C*aBHx3pS*fvXeG#ZyCdN*Jo+8=0*oxh>EIQ5JTV4suGL_ulWJqXeFcK?RvJ{^5g zR=ox>I)3jIG?)waIoaxDDHZ4?z!|cCIHY3#Z)je?*I*M?u+hor+`MkTdB7p00GjK! zptyl_2H`N8nVXtf0Y6TRj=-*HJ-{~LUZFS{3+7=rG5H%7_dP~f9$>BFAJ(2@IuXmk z3H$sFi|sNPnhRjn|G?r(orvW*Xn(_s?xdK!L+Au_;}fw)#w-Rb27kkvRVYTW%OHV5 zfE~8KKf2p;I>P=+5sd6ioJ_0;GKAIUWzB2&!1Eg5Il%A9UB3e5Ftq+*IGe*Nu;CK{ zzDo5ppA>Kdbsp(pAOB%|LLr4M2nc^BsSo9@A07g!8AI$>em@3KT|oWQ1lT$G2+UY0 zP19YZ0fAn7{yMqgn9@gc0_9Irx)sy~$AFCe6B7gi9xNU;C}dX-0mRYC!P&^k*#V5m zpaC>AMtm3xxHh3WBEd5GMWw&8PUxU&?e2{*YY@oZ6A1)c3J)6;VySw}gS{*8|K1Xa zV8q3#NJw3*K%i9M%Ha1tvVT6A12gJRf5E@8@YtpaX0)TBJN5mA@F4~Ng0W+4Fvq{f zBDT05?rloP=%3vG3XQ-E@NauKW@ZZgJ0@aV;m?{s<_3tOopACzyer`kh&^VI$|7a} z0R#_$KR@jlBB+Xn;50ROdH7RRj^)jC&`vsI1s(!_7|Jo^`$-T4U4cJ!fb2=HR?dzX*JL`(s(!=23VV(>d@ zj>YEe0I}cp)xgWbS3MlddibCrtbu?hz?TCY6QI6`2nU0O3M5P5IRWr#0&)|rAMBt1 E0~|#3WdHyG diff --git a/boomerangScope-SootUp/target/boomerangScope-SootUp-3.1.2-Sparse-sources.jar b/boomerangScope-SootUp/target/boomerangScope-SootUp-3.1.2-Sparse-sources.jar deleted file mode 100644 index ea7f7b226cbf137e55139dc6e7fbee8705f7ddee..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18931 zcmbt+19YCt_IKP^jqS!}W81cEn~fUVcGB3kZQE9ZM$MO=bI;J-C1-TV%~ z_x5j|x8JvKe>Rikl@b*alvkjZ6#6PTIwB!XMLh*0PDMUGI#DA>JIk=SXGbk2NhvBh zr&#=3x*Gacdbls}2{-v|=@Yj4F12^Ge7zPH0mFU0ig9{jp=?xTl_I#588>qXd8c+T6J{ckLHS z(YsHpa!EGrS;S;k^3hX%1%CETYB=29chBhRl&)l3?5eR2#Htyv!!aBh^!Sm4sRtYr zrX=VzdM)0FbRF5U{q>zsaY&$v0ubUAF0!T9t=Y5~1?V)UZt5|6951ag1~D_3O;O%O z0jy`v8Y8BUqTUun$?#p(4vi|4WQ2B@%Oe#;+LnTY4AZ)y!i5$O-JtUD(4puXetV|K z^zABmIp{S0L;(^L_5{66FXk-c*hz;k)e`UCtgRf#ZDa1sU zSh7kZPS4MD7>qo$Fb^E=j11eK(L@UmX{m$=LztBTcTz8MS;{bGU5VBLZor&C);{m2 z&9PHFHxgmF@{=~r$hbP<_rN7AhG)>CW*n=GsvSL)yN(!CVQ~8}UGYs_xqr_rrUsfm zp4&!Aagv7E5yV%?nHQ>9q?KV)n;4`s1Y!AW3F1K<5-ko)xfPdIB-g8_m!~5Gjz+lk zCXzvMEM~G;eSeOE?U)L$U1Kych1Hgwjg#%?UYdnGtSLh&dbReOMiu;QM)m`bd{sbTP(jg?S;_MJ_>DKm%(ktx-4Rltp$heN@# zG%vK0H8&@Qh0|5hX%aF<@+fZ0eHgQfhY8Lr=;B7W2eK`8imBW#Y*5g;vSB(>1oKbC z34Zi0RAVB}T9+iRPa!u9$jax)4aSsAF&q;V`+Svmdwh$Xk6D=2cGoZb+FCq@Y}8;1 zCS_6O8fgGiH1D#4oYq<~$8X5PpN$+qIDzOp&myI)iw|8;uzQWZ*n>r0G=KB(%@$Hr zl33!!#6%NYKFq(DR&jZ$vKUynhc-#dGqFcNA2QCs9u6x>C(X!yV4A0aP#SOml4D=u zYj=rEc95KTGa)p`o+uuJX}#Yjung7w=PN%ILv&=n#Nl`03#oevLy!lkV_w6(eR^cL z9NGXTFNLK76&nh*$NqtE=}E0;t~Lv%zTaTt?s|rW3&h3gL`t4%&B(~EJQm?sebrtz zStnX7d*gFy@h>+CzYTi&2;%Oh&TuQswwVCkszFMLF}M(74ti=De3n*vMy{$O`X{z^`m$ zUZfNVv%_Ek79`3ItaUmnbTQ7hUhCkIfgrHMhSV|RWqL@H6D{_s8}cfBB=9XzG} z6ELdIq&)HNV?%128|PHcWBl^)^HopGW7CN{nCiQ7dyLOxb~%w>`tIr`wn4i&g*Fac zYSiXtt+gXXPNuCCAKOE=@XM*b>>=4(9WU>=Lwp>aS-<$iRI}1NR-)daxy7N!WKFgU z=^CaXsOTxP(?Ap~$S?qwNUIbS>dr~T&r|}eG^MDCsW7t_7m62&S}^5#U*8}s8$4oH zEdr4{Q|EwRIa?<6DOC>Zee(7%j?0ML06C#m+!b>)_2hY6Y3Mf`Ah zwTg-xC;zu$WDsTZjdpxisAC)}@z2;;Jm*Jc@`I=`}P%@r-_35vd1)+pzMIDd-R08+{)5N@LGbOPO&t25fyVB5#JlGI$xt!XWvrKhIm?i>|95 zia|wrUx-~%^L|o4+K58S2vZHyz^PZ8^}@=6F*#~U7m3%5v!LoEl!e*7`iB7X)D)i& z7(P@q-qW^UTcmjRgv+%tQd9OCCD*XO&y#KY^X%?b-s()bSuS37R_?TbqHHTt=T4Nd zb2pYWNQJk?h6vL#Rxr6igLD<_QnEvr)!QCz|(O; z=6F(7TV7k_IdWrJ9_~p|`7u|s*DL*i^Q0_3@Rl{^aW2tIY7ryIOvemHqt*{)__eud z>gZqsyy=zr>-*ku=M6RM=X>0r8r}~Lfq6r7<|_~Yzz!4u0OS9yA&8k;+E^GW+VERj zIoMfS2w7M=3)|`1nEa+9q${0St>7WOXcu2}N(+~`_~f6|J7vz5C>`Gc^tL-4(yI8# z3(l;2qK45qtLN#l%Q2adP?*_8@r29OTh1RC9~ie<#nrzH z#w0FN+WsOlvB79we}WnvnV?$4y9^lfB}GY05r~v)UTixEK1%&DJ^4(Ng0e!j2IMss z(>wtn65rE5?(63>G)pSfqNNLa;sYm5@*X#3-n>~J3T3=fe#;N}V!YCg%z1k764u^G zD$G{*=ZD+!fF54+wU}M@F;GU(O}CvJW3|@36)ksYc9r)FQ}EL!?L9a#G2$cyGuVq| z^FfV8_t!nh#eSDafkFtKL_@0W0VfGi;_I<75Wox;<;{sxV#>WYkzjDHs4@@} znYBjl_f+a*HqbArw5Cs4jkPS)2zmA|&KBcg-#kE22e(ZM){}uJKt)M0VL*3v!lw7z zPe0GN^V!3Ia|f)}KIoZAud5ytGZ@yatFYlBJlCjOnKT62BJTK8S;sW;Q&eX1^6b60 z*(g`6y2!|B@H_O@bi=)H&SIj$8**%y&B(oI8PW^EtkvD3KuCg^(ov@>WM*SKP1K1N z(zK|v zUA`49{p`U-v|6{dZ!d$%AKbt|qZVUk6^LTh=VTpkom1%|bu-hZRUyRy_F`*S)0rG% zzxq;LBL_P96Zz2LT8s`vJF2Z_edT$go|^$0Ha{nA%lG+#H7|?CEYugIV2{{T0aaOp zXscTzNy;5Pg;;GX-2x2Q;JM3h0$b4-t5^ImxuFk%ew&<$?i5Ylx>Tt)_BmLkUS4hmXB&_~ifMnsgoQp6ZriHQ+q48}UtB8OR7SnIFt0W&_CjrD zLWzi#@Bfc9;c|zxc?{sl{pGR*1{pPe&)llEbbFbu&!{QP1#$_ahMp3hSb>)P^-r!A%NLNF*aj* zAJCAP@Ffn}?_&YQD9&P*2u-94I_X8US9Z%u3?OYgSFz*5MEP8yP}qTnm~JUG1BGMc zBKJ+Inq6Rb3^k+E0yd59Jwq6c+f0P`uxnb9eYTq)U((?1H}~2^854Kz)bZ7$JlW&Z zl$j6+?NIo;4k=aaxm*egWYsknN3m&Yapm)aLc7CFHZ7^m4wtU_6{3_zS5Xp5i=rh; z!*%ccN+Z!Q_qK&O6o#iKI4rZ8fvL72Z}DMCL{gsedfBKl{3~_{lu#QjHk+}auVCAJ zIQU}Yga&7%D`*=CbHJW#(b4;Pi3)9-dsH-MV0G#dLwnywV;lTa9o5)5X0c_8Gr)(~ z%5zwOK1#O%7MsmWVzYl5V}%*h_TF55<^H(>e~57s_3@SxKmY)J5C8zG|6v7MJL*{& zD(PDMw)n#3#>~2T;M<|vdk)F6t7-7~Lh~p2u4K&M@`EI?#+Dsf*3uVIuGU((>15^2 z_(c+uFN~dx#4m9*IIlWR)AscPO5xe99VH770Q!U3-~P$g=Gb z`&c|Hj~m?0Ro@%Pwev7#=(#du2~Agsq5r#n@m>3@b3>*_vo-z4_5(k(EQSe3iUcyOKb>ax+8m9JIvq#*ZaI@hsHTxve6g?EfX28)DlnZ$OW-CSe= z`|a065-+IH5A_os7wT@_$hO%Qj2+1|<&KCUS)28Z3rjAmHX)@W6wm&S)je@q8=H&u zT$+~C<)3gP#4$lZ4hmTxs zm}1ijb8}>vTOCp$8NYAl^18@oyIGF25P|LGoiZOwl(L;Rl=G$myny8PSfFCXY1O&% z3l(9B1VwtU#wQ$Z{Gx+daJ3rZ0|NkDzxkMG{&^lnjpQA49SkiEtsH*azGuoC)^BHr zSH)}0)&oMCu7L7pRa?6M_Z*~uO4S(iU>cMNM?x|QO{D;K*HR!}Bj0T&ZrZ(7IG z`PX!NR<>}j8M5x+DkQeC0s(;}e1xzef{Todw2WTU@kR|^4QVUl_#{1&7EE3$ybV)1 z>G30A;()OCc0+8QNVj1K0tEfhqw!R{^f?3(wcft!wg}?#3B~FpL}Nrv1T7K*@Sd)8-g`sW?;EHohGo;?cx8U{%f-IoD1d+n9m5``egDu9ek zUH9P7Pkb&z4ylFI=nr?da z->3?nwK`<119s<&70a%NNmK*qm-?;T#A&Y1!7~8_g%40+qdmZ4t7d+B;n7dIAQ5#E* z37bto{;*Sj?io0Qp3;#yHzYIThJS(@ES9?Rjah3*D8V*C53p!fL8jrwqCTaZ-QJVJ zHBFM2o9q-B2fu9#hd;ZTP&k-A;ARxG@p;r^Jr zwNYsVs<&&n&1|z^kK&kxFJ$uE@~vjOR+)0nS*mBKSbhrkU?(1$ZGB>re=R;j_YWr z%Z6P_briR6Y0f(^z@8d}l%YC{>lj!w{1C*kAACl1POpx_`hyWGG^V+-h3>=EM`I#* z7cfB~wPW$S4P_(p{eliJGbBvrpaOdG9BMRE%3jy}A~~Gd$xJ-8C}AmAzIj7<>yrw= z<|w7LzPF2|xuZvVSJl!VU^i*Aa_Yc_J9#-@6L(J_J@6jo{2tdO@|@aP@GwSn7xGej zB7Y1Fa&kZ(5eeDAtF3Yk_G-$P!E?1eNM@K&fyU5JLBKUUTlMUDF59Xdgq~T@NN^`1 zfjZd<218Ay-ha`>m*VPZFPwS+Y(@f@_$e5ZjM`_Hf^X(=plK~(J^ir@J=@I2jdip> z_3(p0UfzZGUzf{K9-;NXn{LnX7I~olAB3}&leM{_po`7#-t%-tN$V9_=r+_t?@cRM zHSm@~vIIl++Qmu!NzFiPq*U9uk1-#HR2y<$J>x7@oh%C1{QzWpg|Dyp4aRpqWDr=y zeazaYHzX1IJW6U9>fz;T>xvKCG+iI`&EK}4i9~zqT!9|9Z*3^ot$Sjk31`4#M-~43 zA-bkJB#f$VzoP?OUpT->WO}ZMK(}go@XjF-KOOEJF*@Rh`cHZC#SXnj{}-kybMg)Mro893mIU)2@Y|}v~dXR zyRDo_hI)6X@7zrb7buwMNmZ^OvIr06QpW1(!kRNr(1pTF07tf*FGYw?1)jWVzawpd zf6b-xi5wvmbdX>KgVaYz-Q))&k**>a6Sv1vg{DRct@L zI3?ku7)|15Jw}mLFW-T+T3;82OnWmyCnOY-0qT~VjiSCpU~=zyj&&Y)!&$z=mqn9d zG7u+OK{JbvU-3m6YneuaV&TkhR()ELTf#QGAAGD%W>~gEyBl3Bq6x2(Ps4rk>D{X> zDjio;z8#aOC_|wK{Zi6nGEwPsNpkdr`g2SCh^2|n9u?TW>74xt0089wye0l*=H@G} zSgo+ad%{I|>pT$wgL3QG^RCpkq;{twIXXSbAc0a%(aWbOhz@^Nzu91K6(Mk}O1FaV zL}W{3UaYB#;KbsM$Qn`7}HHU^tyY!MI%^p zyOg)fJzHu>*VaMXI|+kqq_%6NJax483ZA+C48BROreT}o_#u7-hB}{;t?#li8pw;a zu&HaITZXvEEyTj$TZRQhIn2(tcsT{n{8#i9z_<}Iv?RGl=Sy>M_b00TR z#*r(HecKGbw3==IjjkCW6!+wmIP(!VH@P|Sal1Hm$(wPumxk-7U@i=D$nfqHIEqM_ z{5)UiX&}=gu0!Tx4(U0XsoSx&6*!iPeeLy)_3kw!2=|-R0v5?`y5A=#Aaqd7ZJ6W#R-;mP?)zbDPlB#pD;w>rLxdZT<2Z@s7VRdsk(N;TL?l2c|E|{m z1CqH9b@6iW&Z~O+mF~7E>clP#N_y{(<+@L|)1y*vdataZbqBD<)d~xz4M58$+wORx zdA42p@6?xx9AOoZMz{^r4-)-)EHF=nq2=>K@h}DDpwM&#g@6jVF<3FP=_h?PTHK+< zh`D2G@b5lhLD%FKpX4vVwLY~JR849oAMg3a`}yqSkf?M?LBicsMz8N~H9MADZ!(@b z9)U(2Fc=77Djo>oV2$WaZJ-aXcDKjQh+tKl1_2~pEhtx`k@R>QZaZzzA3M3iZD40| z<>H1nWC{br-IuWV?p|{p4b}%Op`6aAva8Nr^}(rY#%7?wQVRAUc&*Eo0@g@;Sv6D|l{ZbNUiYcLGsL!yD@L$Qe|MjARgLl-2`agbiVLj4q6KfENl z&p`o|U;qHfr2mtbKOGT@b@E<4ATq2w&ryGF*!?aUYfoOdNud@?$(4wxO!O5+W!tC@%mt#@pPx@) zB99P}fDnnm1aw|L>hhDZqJ8WP2r-)xbh>!J1x4F6{6nv3G`)dZJ2;ttNs3iAgkfzb8={e{ zm|eAB{f=&j+;iZiV{%UT^F?EYsSd}nDJO<<1CX?2|^BfNF11honHva zL>)Mv1}hr!E{-Ns6fkB^4aY}D`E|yy+#C=!e7UZz?MB7RtkFv*!>X#cAkV@Y-zO^UWNR zh}|lAF!vggEdkm_gKDt}2W3kBV>=KbZaY-M||LZn&2y= z=b}4ucx>5`lCsok>C+exj|IP4g{?LgLk#HaJ1<3xAV?hOOR`aFJgg-7kiFLd9ae)A zHcIvv<`?8(g?56yac_QJ;0|z9c3Mq~$L0)-1zF@uU)(|kURNGT>rR1pn>8m_3)WWS zI0i=aynevI(+NfiQU(Pa2&>LjhZj&a-@$0vq&KZ(- z)&>Bw;?gbH4DA`WH4XM%mubSDFGp3Uq_I1FIe55a+Ty5P3Gi#3{E;1_(>ydUv;YcyCaSLTutgY7n!x9vU{#HN zBSF=&7Zd|+(!Ii=1D0(=`=_M1zb~}!pq`rn2*~J;aTzsVWaGIgP6vb zUtIbA;BxUaUjq={aYEt*)p8TMw37CazHUcI2Qu=$_pGhzxHHvrAX1=07UTkoOrBzA z8VS@u%ZPRBy{l<{_F*MpZ+*AZjDEP#w50-EW2qW7!}h!!@)}A5Op@}=7l}lj+sPnd z5m(!s*TmECf%|%;p{>*pPgatWmurgW`6H)x(a>8q-m6q$pDnKps?~RH=9jA~g{M<{ zT5*eSVP7+tZ?-lj{52^qHJg(=+%(UV;BxT+(S-+mNLc1{2g@vd19IfsEU)kxN6co) z!3%VY9pZw{WH1{G>VWffQ*pGZnIQ#?&P96)&|Fdu4E+pYdcseoVCfAY)PqdYtWajs z=#}DbdN-7$j4LmEzFQ8yb6km{Qf+wpF6AN|=}+jWxKWnmsO2Kot2D<3V%kFEIjpb< zTwM3bOD^xp*jMxVZuiwI+GBov)8#ZRU;xgeoqc($%NmNPT^OP#NB{FTLxb%tJH{k< zjODM@1qZpdzIVX~?*69=a1l|V>8IRB2VT@%b*X3ecdy+Ocj{uOAl{vBxMadXIo|7JBJ92`I%tu*_P9e4K-C zC|?N=5&qI)74O5;_t@ta5ZlACG)Kk?aubk#ZP z$mR7u3i#zj$0VxZcGpUkCRLrH?{Ml0j^}4Nft)lm2#bFY1mh875Ua8@fDe zO$MzHX(b)GiTv@!T4?`fs-DfAgqR9Zcf(yLDu1z&)zJ?`=~TrOP6M~vJ63^TKHmvA zH@B22;%U{x%|H!?$&hbt{1PCD!g|6{ee*H;zxf#dhY;0|qt8_TH=oBJQGzmM@gJsa z`pz%dVrb5^XVxtjOEaXA3zgBtwRciu7t**z&u)2 zpMfO^HlkkhBrFrwG0ap>H8^D2RWHuj0>-9OjtJ9dXc@wSK8Q^jpQ(t{1lJ_>rkP2$ z=aK|H)t;wy#sbpK=T$xHok55qr^*8xbc0Z%z)L|ba0p6GxT{?ds_3)eW$@A4b94G$hDL3qdRCbV%@ngsdSB zNCU)mJ8X^86_rB&nmC0Or>C!yV@_6?<&f8DAa)9-1LZH#wYY%{0vH+tRJe)9ukZ?q zRUo1>2`9euompGO3#$lE!o6Af89l!19B-kL)mv=NY(4Izj8<@+O@z}kmbA%cX~Uqq z5EZg z6F7{6Xv>OZBdNkA10b_JDTe-m$!ki5EN5mY4BMi58%zDg_jh5(38gCxesStPvdi&j zXtKe*B&UcgK^DsMEVM^rz4w-MmLDMZ~#egLk37@LnF%*g! zOQGw%nci`(L3YW~qX*7G5Iv=Tlqo5qV{Ac>^?19#dZZZP0nQeocv_K=tV|_EvhT7> z+hb%S6J|47JCaJ4b~ z%_W(yAS>SU76rgP^TbMKzH-eb8e- z72386kRo-!lmZIH=E~Q9YI8ml6pM%4Nq|3!*0(hmDQN9|;cQM0c_EVN^gH0>8a}vF zeXV5J6U`)+V!(E>?aeD4%!Ao7Xe1H-QFwh)@1hEub#Xb<0lTI|^SyN}xH}&_q zOWxzAdHyUjq|pVpUdT2u(nF2@pk~K$@HbN#X}Gd3$?QZ+ty}>P_MS?2_c=HDq5JUP z&Qw=G0jRXuiK?n9n_QTu-C?WghDMUm>EtWoHQXc4AI0J?*5M>8&n?zp_;S2BFwv~lOt zFn8)UrctxB!SYvo#3b3EIOc7hXV3uvKK%1s{~?L<(cYYj%r`iAufDgUd<=js)Zz{O zk_{lH^o)|!J+QUU77V$9;W^tNmak7ZWU@qtBL&l0JcjKT(p>E^`>)f)QOWS;QMD>Y zim;#t@$eN=>xkKJZyt$Fbw!OODO^Qb2l1MH zNixGs6a0HI@)yLQRUT;(-}-!^#0w?kY&>OJT$&UA8%$Lvx`99yREA;4em2XJW{_kR zdbn(+MEH8V^yb~uQrX!UbNjr-C?Mutdri{%z|aFMu|9!l2@Jyp$9xg|$_Zcm3`Qdi z{xW|05BSg$P*z9+I;f%J(j6OIzHt_?S`H2|QN*M#-qU36orn-62?2C{ZgZ0>r6W<< zR7*r>VR)SstfPI9;~(pQSWfA{D&E1?;*~bbD^#tb&kn1}%x*@BVy}09 z@wURk?_HvB-ms&P>TtTpNCS7Nw~HZCu$eKhL?M&tvL^+ol*yhl__pOv{N^) z*F(+8^trES^vkx_FE|nD&(LnzM<_He;}GP7umC>XS;Cusi5w_EO%RVGX~X>34EB7& zCN?=A-ma|hsVuhXfnL%=nEoCa!v3Qup9@X2dV&5JR|P6mRKs-0X7Y5O|Qs)IDsvtqn1} zQ~LZVdm6#{2$``@jpk%mdJYKzH1i9?*rjw}ZqukT4In(Q+(fPIXZBg|#imxFgl3hb zB5xCUJW*-BYF*;73O1Y?Q1a{OeX+sB{YB`Vz?OsYajMuJ%V{?GiE`Vuo>V)ydYv-D zoQ(wblEUak7<6pyn3YI|7>7brZ&I|w`2>{~;m|rwcYlggEQ|wKYqRiOT-X;|xq2K( zx^ia$cHqf{o&W-WhmcxsM-{%X#ZCV(FFb+sm-h$ln{7xt&4D_FD;`VZhUalM_r;of zcvV(*&|aN_>-Ox!!dqWC>dn8c_>j`QyztISpu@vRBycJ=4}u)@wqH3K0EtLggzZ|1 z(^{de(bi29#zW{&x6j!u?*Oc~*nGoxRKG;^JJkC$(G?KI>VKRFz@_Xv@ug>>U~UU` z(#Q2FqE|sv$LlQBhZ{UEXwBY6oYM#qhppk(iQB!8Hmt--<3M0!MI{{8^kN};cD0uA_mIX9%es{y4^o&qRvq?g zXY`$Gx#g0}418xnR?&A3+6WjA7p=NqHkhb{E#-4%7ns^qM+TZH_bg-P3;@{Hj7G}b^EpoEs6dAbrwPc^1+19HQHfDcR!En6QN?ku983*K|bF9mm zGb7($kw^)5nD26wu`-T~`qJ@=uRUfq1W1Rcba;PQKGlwjQ6Mmi^T{wm3+6~Lf~{c! zOLgUWiqsl|N{tJHZcQtdvFNUZmtg}fBbj}Pz>Hy8ogK2yZ-3l5sMu)dGi$3Sy+$>c zR-^fGp&t`9UbrM{qHqwySpKa#J^oPdYa6VODS&uVN0?|;8p(PIf_Lk!*LrbXcT94l zI?U?}++W3d2odxA=v&CB?RMjiCX*g|5B*Z%28VqPq1AEs|Ge?W@h9 ze2M6Hz>|-3!|)P*5dFQt+g*}Un30Uk^)<4RFBe$sQac*W=e|X9)AkSJ&Q|r?N7n5^ zDq>B%V|arJUFGqE%8t7PR?eEW=Rn?{Y^-EK5M!kK%Ulp`61`eDwfab60K zlT$!C#~cYOH3+zco_%{r4eg~f+@F+ z%CsiF_^m$P%OpHE)%Td7xCl#s(gKV^A%bDqUWkq;a%>b=01ig%IcACgt zqsouS2=XgioTBV03_!CP=@mq`hK2^oOjL@yk{ti^nVL=DS594&n&6yX1(oqJ_GC+U zFir9>W7X-nY9RwVWcY#^)sqHut{!0*)7p6ICr`Jklv-8LYsBCU&3u`sDYH;?`1|6! z(THqkp{QX-lpNKT(D6oXKim4J*D0S$oXOHN_k|z``!?Bnb%#{*hh6pWW#naxo3|TC zoB;;gvOP{s$RJIA5NWr?Y0)xhr1|+wy!<1~rXr^)OGmKYP&}@zS8ZxYeps5+nPU2` z$$Ip+$xKo&1|o^4L3lTP`EYamO& zbPenPDjA0NcqHoVw!F~sG_zx~38Ko~5%&sCah}MxU4zRZLd&_dg>Yd682AfCSbdzr zSvHo05(xT=jA9Cc>rR&n1v+a$JZ1}A{+Mb0K~$J&AuKE8^19F`3POP!n^NlqN^ZO> zbZCJh<%Qe29V5dRy2IlN-`yt7NkK zd6nRq{V=fiZt1;T6;v(~Bu)6ZtUhKxJ2lFnzo~jIwmisvGy-bCX`pyZ@~Ohhk*{WI zK^F_bM$=_KwLPEQK;ypIQJ%h>du=)s(3f?)zPut#C%TqWj8?+(Ae0z}VD2dz38uvG z{q}~&PxxWPsX>+c7kk17dQ-?{`?bmBdXdfFwL}5=Y!C2y&zq~beY`o3hk4gsVVMBZ z<0EJBZDv1|loJp68K7&tri@WrZ$UFt8o)f(%37p%Z!hiLAhTU94U_SaK7&D#PWEm~ zNJ4*s*oAngHXLW0lv&yf$A8sC-vybid!{8@5q!V6l4K8*%f-%$xri{m_=v|E7vRid zq7)MW7mb@zIs+6+-};j9O(8CpQr8AJiy0+^Uqn#ql1&y98OY);BkZ({=XiQ$)J_lq zKp(a0P7odK9Q1BgZo2t{%{TOhYSnK@YtxBRIGu(teWEelD65_fbJe68q;ysCQUgb`IqIGUy~|DMm$#!qL)@1xE!2|BtnvkLwh~O z#5=O2fh$UA83X!11c&+#as}trtlAK-@$6H52$k+oLRK;*&rrVHO3NsGKbTYjUV){A z`KiH>D@;3`R>z%sdYo}Lk6*}=!zhx0P^ZdVi0jOgn~&TfTGdh#%8~$UOtojIzW3eB zE8t(nd4KB-O7GjEU4Ikj|HUHv*P^vB{Ua}{PHE*wPOqo7>1)?^K5yAIpkb&#L6n?h zHn9cnV>SI}z=nP){UEBcyAAgG_X7}sP87)aTO-Lk$qYMmY*OBvRJ`W+cX^#2n8R^4 zh+_B($&pspR@R4Hr~!N%SAaqJIg}c^A&?PEgJ-G^Ng+U#M+y3hC<1{DVk!xLMBYQ#5DiC2c8u-gW`a?9AEn0vs2(2TFrE0lMTF ziemJJ4dnOXtg1Lf2aj8aemwBg6cC6xu;Q%9oOA2NG@ zFGCp_c-Zv{;mYd5-ctyFmup@>WL6!LJK%y-u{~7yZDlrBB$@EawAAyA>*FHY_JvClWCwq@nKDpWoq~t zVedu|J=SB7D&ms7;GxNvu@j!d`ONuPr$PDYayvv(a=;n(#R21GMVQc(AYALYL48Li zJY`#|SV8dtURGGOmzpUvm($-gtJ&816>sD9T4?6^mQ*KQfhXHJxhqnbu#~|vjF4>;2V=*rH0R5@TjgrW zdn3%+%5TgK)|1o-7$BA-$yf2c-L!D^nd@z&u}7BhuWISo6Z5O0l*#phPrzpmgsd?? zc~gYxG$zm^PD+HxZ470}t4zbRG&C(uS+xLv%FbBsh8dDBGH7f{Z@3YZA~wQzYP)!C zblNX=!s)*Mtw!}{!YSKoLK)YaZ^G}*k@#N{6@T9e0=f>mKk7t&D^LARubGSPk^-WG z54<31?QsD{+yV@S=$}ha>6I{5tv(Nxc+8 zX`Xp^YIX*1aFS64Q=J7DHV}A@^<)P(r#l#K`8=`vV@l?Lh{+8RE}2y+$Ao4{hnqvh zZhAlbNA+?|Q(~Sx5XzKls2cyb++ZRjf|g!iBY2vJv;CVZ2IHsFaOqB%DiHa{}%*GVq8maTB;h z`=?MM4M$OJA~n|NdYg*&x096X?Iito0r&5v$^Thx{P*R;HrAHZE|wN^@?BQHrzvrx zwX27uVh8fb(y03aQK596R8mkd)I+Kx5-o|odX?F(?SFn$PSQ>>H1ZQn4+oH6%u?FyTdCiOr(94?z#cCX2)4ZuML1kMr4u@q$4 zI6wMO4Q@zH6SKpzTY4uY<=V0qahky2Kc^QxlX>qfNIJzw68|*|Wc)f^qY2-m5cC`G z5iTgv0h+rqPN&6Y^kwEXKg;|vVk+)CmT&Mz4uRnuz$ozt9Zc23$K$IBtpe3`lf`P* zQ;46batCC3!A|y2{NYTh9^_~-01+%bP}_;vnubFr=kRl1Bu02@7eTb$R(&ei@MjMb zKo-!`L4~dyvgm=Vb zhjw5?=H{x|WbE2THdz`En%0v9`#laD&FVPF*E2S%8pW}p>pc^x)5BM#XAn*go+Y4^ zf@+=PNMcMR#tErr@3N165yEWg^sk^l7srpfb;faC7@xOA5&ZTm`2V*!Z0z2O%k3OY z4een@s~~&u-~lEzFL7b%g-c)p!06-T#DXO1adoy$vA2i%KpyYMo;R7KM+eJuf{xzh zuF#23g~e^v3(}%aHZLr+GuU`9vLwYGTHlQlNsd_JVMoBGs9%X<+?CPD2I3N%b@bC5izZU1eoy`Aw-~rBfe|-G+ ze)yg2cNzAB?AI#|{vgcr{o#T8H`$*qIQTQ;zq_E|cZ45|Q{O)Rd!N0@&YvCrmF~xd z1;0N(=z88h{-pce&--WUzq`QTC-v3eQ2)zI{AZ9~-`QIr=wHu|E|9#*l7A2WkLwM7 z_WxI6{6A;`eh|z5C-Hv@p#RpF9~U0{{``Q8`Cs7v{l0#={@_QSf1X&sUV!iin>^ox zHzxnap!th$o$tR~hw%F-elqyAe)1;+h_|Kse=zvNdH=W7lz-;%cg1BtIY`0$BZt2! zHTyIE-<1yi#GiayBL6S~fxi?I{R;hSfyz(lzPHrDe}Mj3uJSAFuk{i?VZ-15BkZr$ z6TgE0njZcW{0Zfs!T&B<{8tXYW)%PAK>ij7_=mS5`q%v8KV$!0YUWRDPON{#{!^mn zpK<>#bLuDV9o|3U{xy&4SLk0O(?6lF-X!urypF$#Q~!$pYe4NMe#)B*;vew;9bWqt z_1DnNPt?G-`n!KX{Uea`E9kF|!=Ip9=ox-PK?B-~YY4wyO46 zReSBKHRl*}j;$p70~{9Qzi%EoxZ3}5^RE-kKUaBiHDLy61qmjlf5D(Z-2Z{m)SBK| z|MU3QKL`5%4wDyFkd_cvRb!Nwc#xl&mXl>*Tttv%pq-nUZ&qPmVLLc=p_iGPpqFJ3 zfrdIM)kwvp8zA@U%#Be&lT}f5%cHGB$A?2rVN=2ILz`B4K#zTzd5rb$%#~qtl^JLn z{HY8rB)(2ZfoBD=fG8k}X258`2=YH)?f;&^f1j6$qocjKi?M^{|C+-8jYIx7oU5t1 zgZcjt8teZ9?ds_0=I->r20{PF$1E0nNo_y`0qG?J0b&1t4-)yGZ>Z#AF74oE?qX{0 zRP7-=Y_uR{xxsY+MIAmf$TL1`GfUha%+sZ87wxDK{uYfQcP^n`DoE5 zajn*4br%JR&)V69Z*F>aIEvw;GDa1S%bI{H{-;v+0lE8eN0D_(hXbK}_DahgpL|NT z$VH%~g(jUf1w)mPpvB#e!1>O@$9$*HsV0>HxDu0Ya0iOy5338E!f^~qT z@CQpi!cYVg_+r?3F!wK}>hTPAexlI$5}WsFlAX9DP(SraxP5414Drn}1`EJYyq6!IqxX(iJ;W zcsVWvXHhX56pF%@qY@%LEvG6KGtkbGAFG=KL6N4e59X*^J&rzO9Y;0$cks)Bt#|lB zA@eFxZAQus=d$C?gR57=ke{rhtCcV9ifdUWNNz?hJ4ue#905_R&7!@%ViwcgVg|oa z#k$OZ|GkrA)m3S@A6CSs)tx#2Lb>abVX`#KK?XZ3c9P7Y($3v{OvRdQNs$2!WmG9? ze3d!g!f&ZoNM|0>BoW zW?m>$7Pb`W#j56%s-Q6e_O?-h9-FaYdr^C5!D*@IY_n`p8r@lela0eWaJEghi|$T^ zHY6ROSSd%oa&7kT6j3kjgqac#0T*g2BXnhog96?Uf3)Gf8cs6%kaSpm%k*e4_tW0m zcL=zLcsm&i)Rt@#TP2}by6BJ}n?scag(qXheqC9l?dbfr5?^-cTwGQ!TnOLwheGTh z6-HU3f2J3*KDGHL*mY)|*%q7G2-?-m(6$Jwv}ynEZ0s){Av=^dd_ ztSoS2C~c3=IRef$k|t4X+pN`srVNw*RlR5OP>`9Y>k6iI($N!jd1zjG8K-dCd?|@z zckrTE&12FuG21M$S+B*o(O4Wwor8=RPwIBWx-KhIPwZ31YBghSOv^NxoOOe4i&2Y7 zB_4SzN#lewCm4rsCNefA$m-(uZ%?$enhHY80K-r_uo-O1n^;}{&R|qKdc=&1U=+ix z8F)%7r@|BtqXp2=#EoxJ3!oEPtfd|M1@kks2Bsb6D~4LxSiHXt4Zty$VrP?NBMaAz z%`u+trrR&NzF)$+x`bfct)*B#BFKSYwnKZ|cX9Si!>nNe;7afvXGpEwzXBBUk{##y zXo!F4`00f6FwP)R-mu)__5q9Kp5A5+1vC3v_vPx!jvMOe1LB zn7_u{wzw;8)HBqZbTVYJnbcJT>Qur=)G~0ZFzjAhixglg>4xr2K`N$kqb^)p^;E&P zvF$Eh>S|Ykjd~T+yn5*Ld41*JNmXGLvjQ>{T-gHfqU4W>}BT5+d)k<>v~({ z^LjYlzINArDS%;6*6)^`4`b7H?zII$vfV>H>80%2^BaD)19@Uv{y`W_bP@5t^S^H~ zX-zh4W(fB+DRY%NenZ!Ho_x(Zd&vySJl$5w=~Zne@1&rnHt)AoP~NYrW8zoC#gGg% zWI--dCDr7FIB<34QfbO_J5FVJ$1f8vW8N1adet-5+62{v&UKE->CUY%ZEzfyjh^L1 zRc=a=v+}(yRSoV5<_Kq1qB$=tpO+r>!Z&3M?PDUsKPieutGN5Iq^x6y1ap~+3}5RCCBiVLlOx@CB2$T~V$ zcQT-(GGXpxggv>Wji-jO&7$w!GGygIN%8XQN#qow?Q{FV3!&o5~xp;@jmOa15 zApxI_3g5<=3r)GdYRAk@Cr?+$_SB3=l|{j_)3=0=U%pWPe&!^mokMkO7weOrc>U(= z^0CFfiq^u$;@HO2`+Zo?M=@GG;(R zcoZ9)Cs5oeX=1R?LV_ZVl7}g>Z%xhSo_H4^CFsy8H%D=dNw%57%!YwzE(+?E6TCRq zF?rICanYV4&h9L6VK(i!a001NFMc_e6yU>4FNx*=eho$eT}j9IYqSG`VW&II7HMzr zy9eC0&N;!;M6mtg+UE{#fAGpQ@hX{V_#s#R8_y=eQK=0}vnYgaw@8f21Hj-#<&h*J zeR*y@K^OZ|sAF9{OFuI6w`~cX*2$)2q?- z<*0pVPdPQgbhp4XkLYPN%%4n4iqM7Lq+&R_QG+#ln!nAg|Bb^BKc*z8t5FEQP=j+A z_3Mae^c0^aUrc;MXbc4!O2RqpClLI4D99<1e;Dgtwfb=s8CJ2sX`C2xDc)BqCqzSk=HAp<)jR$|5^oZi%l9O4f0>S=%`O92Q3K1ht(TbR`U^XDZYl_CxUO4{O~y>3_CJnR<7XS<2Ge zrOnG|Tiq&hY;Xm;SBB#rF)(P~(>+&xas;D@#UCWTD=R=WXlUDBw{NdDn9_dM z(-`!tqz$ZBZw=B1Sj~<13gYy2>k~b7)4pD27}vU#w5~*@%eEThr;$b>7HKAlm6WCM3nwa# zbDiWKUM&|A;-ztYa2PYp;{}`|%znD7vL84=rAlDs6V#k@X*UlzHgS5O`8$$Xc^uoU z$q3k5u+ceC(b3OsZOz|&6F+s4H=A)^u+sWsS^z_IX8ei z70?fTHsK;o;QC2%9*`}CCdjY}Qf@m-bpdFi4oRdB*<3)7rhj;e3C`SjLnllfd&%XG zp#6c5pK$e(i9c?3!Bw2D!A@UyQVWQ*JfRn)5*luHK_nye8DS$T$%oAas2!DB5*PsN zMq*As0D^z%gxvSVb^{}z{|Kkwkz5g#s+05-)F6L4 zG1YZO*q7!%J|7ACShLZ62dLP#FkeX(<+aA6>-cukozg3MgAkD#^aLjy4U6#;*&`f~ zeJoiy!w5Sh;)Lb35Ony^udEsKzKdpH|Gm+3Bb_#A<&Nk@1QU#>%H3n^pKq7YX6oE+W?1KMW{xaLF>c%n8??cLvcJ(aGc7`3@~NZM zTvcpF4x8ms+T#Ds)-cn$j+Z;fuP_7{UEh__ztX7I4^64u(|!-r3*&I@0J$DcXfVa- z8&p0~uN~&vgqm+W_s_}u!#7iT&+5~_LfWugAT)r&JPst&SWf_g1<2U%HFh5}JkIg{ zC8MIduQ-9qj1gR7bSj=hBb<{+5#ZduHgGAq9EZ_x;LP@Mpu!tIU0^Jv#~ZGTJ@lqO z^TGJxt{^@WLUk)G1#tzP?*hd~p%dpQYolN~Z9H>a17r^NvnL2XBM5IldFVWxu|(2y z-1I z=yqrbZ44SUMQMG&3`Dqlm;R*v{vQ1X{hwO=e+XdFZZ;TwC=d{6R1gr3|F-~^v9@=z zGgo&Kb#!oZakTqKo_I>S7&}@04+Wg2sq2Zhj`0=GU|k9{;sJ+;UH=K)7K@@l+;V^% zYziH3CkkE~1dc5m!Y{T|S%NZB_RJ}r!%i z-?|y~!c&4wJDEY2o~dA3&^OSxp!a#x_wgC;{u^Pyp{KzFO@(9!Ms$>?^wdTtEb77K zDHWfUwrOHAjUu84zprvgLO3j>I2x{l+FG#&-=YgZp{D{g_bY>|0Io9T4z8a7+#&Xr z0P-07L+z)NY{}=^G#`3cb24Mi=3AcRL!PHs-Vpn$0DlN3Xz-?RHv2O0wy_F&I@=8& zMgltWxLg!Et#s9y@v#{@K~wzsgzi{hh!1Psc}2L|7+-wpX-*SHmUO44Ig(CNLu%u4 z*Dlo-grGQCAfn`RlD_=ar1kO7#Tjm}BXSrBNzd5YBv)840pPJ5(o;Z>Yjh4lUN-LoK+@8#w zJWgb=2`=TF|4JWNnif~aK$pjI5pTCPp}YxUSfq*19r#oL=r+ zuABG?Giz)|=BcOF@Muaq8Sc;O`st}$Uvkbfm$Mt+nXKoH!9kw~MFvn}vSRG1$2KY$ z3!|s>z#KxTFa=FxQ2`f9-ukG^;@-4dt?oB)ghPy_@E`&=Ae6{#?m0#S`Tpfa!uUiEhU=hymWEje z3sAt4%9&)0L?5D=!m_$_<~m*q?XTI)8`a&J+I$8=b@uUTjXTofq>!$|tna`z)(*YQ zig$ML#aY$2kohE+IK2=ydEPQEbX!G2_m?zMj3JDkd?qHatu;q2ssY&gIlK6{$F#yG zPh{qzaG0QBl~A=Su>%ATk&Kq<2n=W`mf%ScLi;48BGvv)iNoj>aK*AN&wC|p z=ypdrjmasQ3rqmoek*)=8I_Yoo;EQ)V2!$H2TNZccm4SMuuSv3qz9(?>9t^{VHlhk#jM9G9joa+84QhE|I=|4ha5n>(IFKcrFB`cof?gKgg@*UB%cJbI;M|uA8|SOk?UTXo1QJ zrinB12fsE%y#bNnZxqe{9wN--Wscb9U4ZV)OZ=UE9bU7Ja7+@bG3=UHBPu^A8WVC) z{!-65NHlgx=>Xsux+A&SD|f&qiz|RTWxsmi;x*qGl?HRy3%bWWcZw21wgTRQ9dDmC ziZqViADEO4Kwacve<0V?6FWVf^+QhXxD(VoznEE(_3?=D0yb82h%$ul5|_ZUupfWE zLDCWX`k@$#Z!n4C05wCuX)e>?^~ucFVWk3)PUJiPD1D#=LQoJ3puo%+6DXH{MfQh2 znHy6Sdky_?Ifa2D8;o|68ly&y3_WWsQpE)(zz&V+{#3d~uHVazeS4ul{qfMb*f}u% z!=iae4W3og2m6G2n12N1-puQnh0`>4mis&26wF)h2sQqI2Y>WI3NT3|8bw8P1THv+ z1t8*&$K$49&qX!nr|~#!*+^hB0ka%czBs~8K5{PIk@G^?9a)d$m$5D0kou4w`%0F4 zP~E1z%09V7_(Mp+Acla#FQb##vD@;C-6m=Qami|Yy2Sz=ROgA-KARktZF0JekR^P4 z2h3CN#rhWUY|q?JEC;IUnVg5yh0!&y+U1{JU~rjgk^`3E1*Z!mSHtN{wN`!MU8uHR zMR4%IQmg8Kew~YXMirtsQY((_C;6kW4rb5Vrq3 zUyGUlQ=)b;H(cSc%||mm3>hp1$>6sBj>q?Y)3@Pc zJ}~eD;Q-MMCc~*8i-kWCz|!QWg$h&>!A=nKBNZMo?dzP0z<^OqJifPLN>J~k2Vg0_ z-eg58Qot8co5&CGa+1RzcSg>4j8YO2#=PkLEFEIkP?w`Tu&J-Qwx~(kQ}IZ1)8^9h z39}I2nqg}$*Te*W+)=--?xZe6o==4xd{8YcWw}yDUQbA@Sa&e3W##7Lt4A47nxkvEY5EiQL;;?(3{~Bs65B z5jZ2_ehj9V`;o+&GSt(Rzw8W(X-go}mYQWfy6(fEM2iu8IM9AG9AmQM@KwTP`j_}5 zRng7DVLu1Q>%wGmZzAZW4cGV<%T_^mc&jNIP~_Q7vF%~u3(ycb6cC+uL4zsek%CLs zaW!R6U6ud3^m^VChw-h8sm{ax@g@sOcYbiQmXV8kCSaX~8?3^l+O`j%F(~MO=JF|i zTsPpr?w>sN$!^(}+F(U0jXxqgTT+`cj>yRnfkbRsiBOI2!#GnNb(oqsz_@xWCi8m^bHT`Qi zd93@(;L#WO&}YzNdC1-Oa}urad^9AUY|$V7>}zC!vTQ$$jCYb%mz;_f)4Ud;nFeY> zwm!g!#}%&K{tpsL6JmV$*AT!W@c|2o`AFSn^3-$%2#ha7u6UiSkCbD5`Y}}0yJ8y} z;ydXdTYm8@U|5QXGVS`cj-C6P(BwigbRrs)O+yds^|$c#hVvT}9Q|^K$mnzE5~t#O zjT#w5^ifq!HLHTUIdyiz1WA56TnpBKKHVK53;lOYX5@x{P`Cem3%LKZFUNJCX0w&H z`4`l`2Rk%j0B+Y05D+M65D>=yLa=jmH?cFcj~C$pS?#CD@htnES+A+bc+ww5;ep*P(7N@FT(~WRm2o1KtI4~8j-`#AI6SddG%B`m`M7PqQ1pj=Olwn;tPu1(;}^>K0Qq2{PpP7-Du|1PQXxemRNh} zR%|p}%PD4kTA{FYy_|^KjsvwSy^3E)*MvB#R5Ee$eY5t8IkhdEVI|e4^DvaUIoUCN zqSdn1ZP3`^InjK&(>*y(sj5v?VC(xvnWb`w^rj5jnAuHO+$M{wfGWW`Mq4zrW3T-Y z>aohPl12HMquQWrN{55;AYGk4`{GDfN}G;hC0^@5ct4{fFh-TcZEzU%0W^oK{&mOML_Ru&Wr=>F(4AmDF*!Qe8hLE?5P6DcDh&gli}Iz)k^M(CZyClAI4DO$bY zsW?1!!CUM;iz8!@Q71Se2Es)pWCFT(44=igvG5QlZmh#=`1Dyo1S9VQusH6#e4}gU6U|1wnTTg$HaQ zCB>ztB-ye-lGkVTfuJ7aLabV{W$h>WBsTp`42YF`5Z2+d6_oIJjvUSsMYQ}&uymTl z{gJfL)t0UPN|^Onuf7=qWMHk*zeaJv@abC?IYm0jaE}#YX+vg^c!Mg15f9ej7ZHw7 z5HGScCckeMb58O&2hx7h&ny;P`K79`Aa*MnG7K^MM2BXVx15n3HB0P$;Hg6X;mT6T zyK5kSstH{*kGsH+j8avsRKPc1;T0Q@LS+b338gg+TLa5uI5yp(3a(GgC3~e6xc`Ft z_b9LqO3bne1_ELX0Rlq%pGN@+YjeAQF`YP7eZ^%Z?0~txuC%#0MGSOEybgCM6d~jY zF*Z>!94{6M<%TZjCX8+mkG!bBQQs#>GyQ`!pyz%>7qAr&XylYvsJy%DGE=QgEDdzfzLXJd<^`D4YGS(j)cYD`O z1(RnA=R#I3ob)k#;;N3V{8XaMIlgkdD^D7|q8a#j?6iSvYw|~I*$m#l%8A|jo5pJ# zgw?=rr}8sT5{N}NJg#?)BQx}S-`r#!-_RuVyKi{I)lIQUy2jH8nAE4tyKmKAyAG?| zOpYLu>WPDFVUM`U4!eT!q}Uo`L(L($eh($ySdty42Royq>kWuQ)O5@yz7hpl1HM{J z2d&yuzA{Ace;(;4I?KHf(~W44pcXMj^25Sb{-KikWIh&Pj$(xO zXBV8&ox(&#U;VHR6@9n)LSD>(hI(H8G4kipmm>CqYeKhp+>`vgHv`=#1lc@^_zI;+)IVC7s8#iFCB=xH0wpy>WmWDK~Tq@cRv>NR_N{Z!_YK(ls zGqX@o6o=qS_6xDNFZR=R;yIS^Ha;KNWD)q|-xo+l!)DsE~V`>t2z2fFD_3@<0_Rk#h_j_MM9{WrbZiq?=nGRej3=YZ5)a+HUehw z?0di8_wE1voqg{Z0Oa`P?xi@$|9Db@%lGQkAFO|&z7Vks``5@3^ly>jSO5eR0K|}o z`dAnO!YdLf!psU57DWwNL@OwMct?+$Xqu(a2pKXEFWFg47)O(4n4}L?`QThts2y1y zIb`xF+#LT@@Q4)^{;rX55sF>b65vKDw=9GBE@GkgjDWLv7^!f-Sc&sMQCoR>4UKDz zf`+?-8p3I-m*4eE%2Xvr38XB4j^sA;ECvAL6D;a8fx4$};S`BxvqULcZ;fz;p195G zTi1btXOt-qkCV}&DXntJkpfKYTRq^fo%q=zQD15TL#Uw~qJt6Bs5Rz{K?R76l~m^s zA2;VOI+D&!1*S$<0O3V%*(pY^rN^3S^M@a34F+Q1Wt+%iqBERiMyI()mDuEa7kGdZ ziql@=qZ)Q8!0PCAKvy)Elf;;|pttI%E_X_pZ;ll0-q{ix6{Y?dAMF;PKH8Og{$RE* zS^efG)$k6@RZQ`8{Tp_5c|CFX>UUUiaLURWrsXOq4s0b&YZfeFctP$tS)-8a&=B*!aaw)ck<66&{UNk$l-|&j6&1*b zmNNs&0<)M^o6X9CBabXn<+y(55uk7GAH!*JNRHe*Hmo-q<>@K&QNFRYwJDo)dV9CG z*xdfEVTsn_5I5e6riN*r{{zQ?xT|<4m+fOXDA|Aei4-%ZF|m)~JZO;(YV_l8VZyvg zK+u9}`4fefOi6^rC;4HqWzsWiX8RYaOAkWE!CP*+ixSleIj-fhRDv8BGS!4BDyAC8Sv`OKic zF&rZ>kXXdF$QLy(bAxCeQ}QF^Flkqj*=Ou)^+)^zks1q&67Av9rKDUok`bCTDk73i ztgJ#K-6qzR7p0PNEBDAgsBmco>#EIr#v0$5Yg+%ZpDBBfa`q43>NI-s>OHZKw7xjTKf>WJ zo6iQ*#$*85m}}o1>0gZlNN;V?+WdrqiFw}WPD~*qfnMp8OGr*5GM9;hW?6$g{kd~p z3<*d14Kcg^1j;z-z9UNuXEqpHj(1G8u+5Df#$VU zk)Td>lV${#ye&8YQG#YfwPe&yAjETlYRYB(1NN4o!bN*g<@NtCd2;dzdi4AwBLn`C zk^hArm$ZYco3Vqb`F{{e6?2P!Rn7iUlW3CI0>|6D)07I(++{yIz)|;&WG~_%p^;^5 z*GbS*q=G7bv;F4Mzwhe4miZL6SEoU$Q$tl-iRK~?P*n%c-fV%Jn*BN0%yOK2WwboQ z>wo*c4+QlKLLh(?#1VzmJZY>vtd3U%X2pXGuEPMz^bAs(8`$YD7o7En5eT?`(^s{# z@1#faxo9mqWsvkz*e#v}8Fi>U>2qCp%!FUVxQ^R++6g~+Y`e=T+U2A*9YgI{NBX8W zwi8C*QiQANf-`u=7#Hby?zRCsmf1hUokDSVYN&;-^VA_yQ?JuaA-HhzPY?+JKSEBp zuu@)kD6mnCBEfZ3!96<^6)ap{ zJzwy4DCM%5qlcVKpr!0l=sO8a=Kh9m9tr`K@?d9e%x;928SdJLP>(zPvdl1qJUZn$ z@aNSrX4AjculR~l=ue5zX6o)IuJ$)eI~*2J35UHH4&sP3ys1sa0iD0zRc@zJ$WOn@lXHi-_wtaV=n8c63ia{IG|`8SFHX-vYFR7bwaRpE)~bVMAMxuaO*jDzW^CS5p7578BV*ia5L zbEE{BuosMGQO_V8P4`}&OW9$5iP#}Yzl}U6y_FErmJw^8?m-_W`P$%D)3~)t1ereO zc|$ThrtS@EJ@Guw9tp z{9MmB_VXkjcZG79d34Pk7dbh5mRda(0cw(?b&qC9jd{ZPW>PQRV|7yZ{j^Yj3yhjf zezS_&Pb5ZXkg2Yh#^J0VniDB;&L4w_C6jCev(_b-h0%1r9EhTSRy50U@|L-PzeS(G zBDP0 zhX44!nf?oO*}=on)?D1n>0fs5JPmtSG0ZL_YDJ~0OWm13*nc%ZU^jvxk=0++Ax;De@Z8)Hb7LYe)^-HP+mFL zR?;MLjRbB~Qf$rsAqrR0WYjjN9EnQQGv^@PiWf!(QnDh9?8w^47*aPFNV)htH0P*> zhCk!xFq%&4Beq~WFzF_)(Uai#k=WT5XHAD4<;{Se?74F6+huD8G>eR8A1`i;%q~=} zan_6$IJ;D_PcWP1895smP+w9Od0967$(gV??&-!x0*9Sw_O!f4_{lPb#q(GcihOb< zM>B)Y(oom(Y*)~g`cL~DxGz|5YuI}P}d%kpaT*plj^5tZ0v zR12D6P>z!92#8!bezCBe+G<;!U$$bhN^|*<*~U~Zm)OgSKz8sKQXM^MdAhEtefy$m zx$5v=3lbofrWQAg{r)D8*8ps&5472|p<-9)w^$AN%5oHIV``?US*HmmXGd3!$%fsPnvg&E z|D<1lS!s&lp%4${g8I`^?q!kk+Z&VXokw1QfpcEBR79GpDoc7SBwJ@?WfeZpSM|`1 ze!3@>e)k73b@vopwwGGGHJ8wGTrJ?LF0HpE11f1Tq%v0FCLM@Phz0D54e=5k$zk0a zLSF0?c3dL)gY7uI5ds2i+2R`Rs@FT5B|9dFeP~pS^wJ#jjfB4Ny*N%s5owRL{2BJ9 z>5a{(_o=MEK4FEtF4n_z{KJp>n9Ps<7|oBi&@#kj%>%aKh7GhAkDSk-jN`BUh3X>r z-k%37U}r3gAIY(-UWIMvB@4+hHz}*akvEFrd)gX5(z9(=?yd! zeJNW7)w#UuUw^8Y(+H%iV#%C(L}FYdXeAXfxT5dq5Nnf}^c(4!N(xzr%-hh5f=I<= z!#98f7XICwEO(SYkO1;q%!EQXj+;h>&Ks!Qy5@vS18%DJWHfJ?s@JtR9_fio52;bq z8o@ZUyW23ce=WiZaOg9vn6je*9`Z1_ZYr z!*E+EvMq*7C-;Y}%^l1;wJ;2}f&me2Fz<^!%883tJK>#^W^yszN+1^FeX5s4fAwmR zYGjhyQ6VnwSNy7=XBrgU7UY+gz<=V6>hLBC^Jp+K1TbD%q?7E1Z}TjSIcF$+GkoX~ zl%k&)E*uP8+6Fs4^!Il>Tq7R2Gu1&wEsGe)r<(SsAqa2b{OP$m z=t!VEB$|$T;QdL-erWITcX>*GhrdW@u|w&kZ!P&*2gGG>43TaD%V^^7y1j#MK8hS4p+1Y1%=+oAjxI)3Yg z%HHprfc=!m-arHnv~3PtbQ-{fd7VVxEgXzb8wA{Djw>Y^Wr>NiTsO7U<>4z)-}H76 z_`W^;I#&N2m&$*>FS)9%_xKEN!=Xw*?G2Hf8kS2B1)>ixcupZcg!s=xh7{c^AL~HZ z6^?cOv|Lq)So$IegxM7x2T$k+b8K&otj}>u!svC=9l6t@Ce(#$C3T92}z__ynJ?Yx+q@mxjxILK5#arK0$W^zUVwcm5w10ss8( z1jGRWq5IGC&i~%B&C~QYLSM!C?wzGfnL(76A|_UA3LZ)pZ>NpMK0!tgkuC%;T5R+1 zV59tzlGnjEZLC`tEzr~0S~sfWtA#{QTMTYey|lcx=V`0!TkyBfR^ZLw(ZbS`3Jvvr ze6Htp&$D;mv)BKvY&;*NQH;G>D}?U~c^FDvFPIO*uM(3;17%ba-A^qnxZCT&^rJ&} zP=L1gKJHNPM%7tJu--(7&}b`!Wy4Eq5EMhcBSc+bCN+cw{tzXAzxp6C*cfB{kog|p zI3FcI>UCUenOgTXGXhYcWQE-Ud}_QvbhbT{ZS{(MsiLgQomYgE18_Rc^iJ}t~A z%QVf(s!&aKjon$BWQ$dK&GO#dr8D@;~l`L6mJo5Z2wz3l-jTIGIr zkZ7*QzGBY(!^801Wl4YAQcI%$F7XPDSD>x#%_A@MEOv!g=LvZc4Y_hkZ;i?6N(@qC zTbs&K_gwdHd@GN?)h}}O>A8zF8v(YT<+!|MalxiKRfNMux36ibza=+nb(ap$NCYa7 zaNU;XSi|DXkMbq~aQ`(nWDAj|Te1-OKII+1;_Y6%aJCI`<$R#m9;L(zjGqa(<3b<<8TZUg2y@xuP z*TRgZ%Y=F&U?}Iyj00|2^D=WTm`#^RuNEj@)%eT#NtXZ6V47OFNc0);fJMQuNy*SV zY693Ggs`meOr7*lz-TXi4>(7~|3-Q2spf3RAp~0d?LTN(`5MZ>e7c3O|uf37ZMvpI`f~G5%pNEY(wZAdavO z;MtG5{>OB8s3Z6_y`me6j3TcVRr%8e?DTY1T0^Xr(k4_SBgUoSVH9ktVu$+`qwEk; zS@!c{W5=AL@{n_<@{lrMC-$8E=CH>eUL%t9ihYMvO@1V_Jd!565(@!+=D@nECuxUw z5FE3z;l@ENok9evRYO0$TZAKku`IB#yjNmSe3R3IHNp@()BA3OOVNg`To3ik*q*%B zJ2s=s&!Ad-x^yUSXEiok&2{3S&?2=cdTrJ&U$+oRQFb(ydT8zLXwCkHyk@c1Pn}a| z|6wx<$cO^3nYOn+&QAb0-f!bn<3Ywwr##6iRktYvH1I9Fk>y)Cpo4UK#c;L@LPdor z`Ai$(J5ae`Ft&h*tl9M|M3mQE9=c$sqRMu^%WDZaOV6KGa@0j;B@%TBrB@(g8{NIz z$cByynm^bz@{wuw6W216{TS~c!;<{$F+Hi79!8dJE(;3q8JKT6JDzsO`G^?CB2~3i zFsQEeY{kM;x4r{>@;XaPZ7w|(rZ+G$a?fI{9uRpQ-TiDr&^8^%6y4Xb!G4h5CjWw1 zE_laY1E~zhA41lWHAK<-McK!;&=p11Qo6|f@Vvg9P#*i;i^7I-Iw_YL6WNs0NBU^6 z;DKGt;0>L0!d&ezo~kV7n^TQcayHqfOx@d}?+fjYgl3Dux$KH*bK%V&H7`tXWJQi; zc_=nBF1;bb$55}+gW3B_?{^Lu)^ZogX#hW#Vt(1 z8O(YU0A=MKX`(=f((roPa^ZaPp7@SdA{g0zBj&35(|*|MMkf`2a0OaRSIwp-L(dWw z+H%pSY6aJm!v9gn=zw)eS26vKCKm_7dC5^7!2K1rLBT1_XAtoVVj zwpB9#PIeW0ZcStu?hk4cm0MNQfg#8@LoKuC;HQMWHv zFiBXXq&B{hP#r0r8xZf&QiTTv4@3V(*^Z?MQBe2OseS1X^^NBD$Y|%_4%R>fgLX8@ zgK7i%&DwHHgdU6V0+ zuYs0hf=A6@!2fY4f~KP&+CfMM2(k-JICAM#S*u+S$T@`-dG9?@qPy)$utISpU!h*z zg0m`u8ISF3 zSqpEJISug8wbt%(?+x_zr;{m~NBj3Z`^R7B-gEEqPvMvXkE}uXMp|j(58+_@E=JjC zWdLQc)Gw?^hROi-v_3;sKy5UvpZ*}%%loWM?6EF9&|WY=VbD|U1)z_yKm4q&c0}a; zwiDhsYq4y4^^F7q9>xV95WWGwA4bt_y2m(ic!;f)-G5@C^H30vUnT?v3yM@ggo3q4C$?NyT<^%-gT4@;9w6^o;_ z5znJdkMSYI_0k#?Es1tmER9Ty)+&o$EzaVQThb$2TQHi{Q9H!4#rUl-fVWuk=0#lv zr^jkFc09SF#*D9cF?c+7qNY~ydSb?p$)1ujdBBXY3wD~~<3dV^vcb)bo1l0VrDVr% z75yKApNsTrCrc0+lSP8#PrNy7(PzIy^F~}cESUPg{)Ke;HR$gNeuaB zfLP&wBke7Kg;vCu z3+=IsPh>6~Rzp&50N-RoPLF3po+%5x2Pm-RN(NzmbQ4nhI@Zr3M-Rsn5SiQ*A#}}7 z=f`c>sj-Ta$ZB$$YY-!$@6wZyPpgO4`{{tC*DMv)J`T$a*v>z$b0y&qMxT!4LlC9S z8^&YP&osq~y9tq%O+Xul+|m1O5mEu}YPWi>I-mmc{Arg9UXRy?1xW=^!@s7(6cd2| zGK@q>(S(dUjzKW3t+^m<_(iuLUN{$nITFTAkZ`uL+{D*LlxxOHxnydjk6@FQ$-30 zx47}|btTIawHiwd{JDQ(1#=@V;-}N!@GCsAXX&nX&yU;>h5gr1ye@Hx;Luaxw{q6; zhDz8-_Ac5V7?U&sNzp-l4VpHoUIYmw3&C!7eRjR72nx-3)g$~ojvEu-#s%FOl4=Z# zXX)T%0Xw9XC?oT{CerFfcOArNv-BuYvl4T@XS}4&+k@VeOOqCRQOfFNOl*(H z4Qhn!Vi%UGA*}F<-wr!Mc)Uu;h`zu8$5-7nFxQdj>cZBVmJ0e`ZgZ>USel1(yy9TzMr*b%0=HSPm1%Br(_327CP z7#<7aSzks7|GH{iT=Z;_kO3dL3d9-sR<}g%#e#S`h{C%O7R#=Wg1Y}AOyK%;gv3@S(_-&SM8h zT|xv|I#o2}nW`|~qiLbyquBux1Y|W`J{s|u#@aN`f-fNqBmi64t*_En2%6;8RCW&1 zTH)%#R&xW+*A$T5#Hgg07shFqrjVSe0@~5bvv#P5OdUA{m%G~pTzqL|z7;n+Fgpyh z)HX{4`%dy_1LsDsuUsd0e4t=YS&iAV4?s)|Q)R*JLacLZ%7M)-x|%1nNuG+$T{^O^^PA^C6 zzhsZb=jWBU;^v7gnLT|WHis@ye)6;Bh2*^_D6zf>(sxs(ylIhH8dNVAhf*?MW7;PX zzA)4Ks!MB4^y9+`GRavicb7OA>)i(_+*z?7%c-1ooe5Qj0%K;Qf-&1iu@!7HK7k2C zTkg=EmXlweQci0OXbQYJ%X{H*-$6-&sHSjUUf1fvY}ih`6~tji+1bTXCCs*0-VoC& zVU{q%<^QtM=3GEyE|^ZLt7w`{y3a$kkE&T>1JN&+lfp~ueg5Ihz0=?Y^kyx* zVMY6kzo`kuKdze*9++t5viWw_BT7wyB3>$~9=Fhd&z-IFr}f+OZ_^?NDLs7C=B=hB zL~nxYR?adh#ZBJooYgKfYe2o`Wl5Tp+!AxOWt&ZH7s+NLF`ZAzQI|P{*qE3ns(ZhI z{R}UAsVH=~bG$+>lnOzI8QBO=S4O`tyhBqqy2Z;QEI@M%oc zAh{du5P)(FW+Ur&;{=SAyyK-tRwGs~U}0iL?MX|_P^s(Tnf5N)HK{bi+R#Z8qFe%YjhNeI7V4v1o`H7hkPu5fwo0gl zu+D_&K0q%1oGX^51_d(w#Z_)BiDkl~bs5w%N^5Sm4T@MxMi5`9oD+OjaFf|@Qav;p zsw7=-M6A*jwa^q8M>daY`WY~amw+y6t`+8hxs(T8S<>S^uTO+I6Kv8zBt_~Cg+)01 zmEDjgFq0mS7(Ib2O!cTt)Gtp@tM}Wva!-$aM)^7!u^3-g00ZJtYS1Her33(MA5pWo zU{Q~MCH^MTT+T8Q3!%}zGocH*k^G82F-vriiDr9+T?yKGoR2$ZRIwy4O{CtOtPn1L z-f`8DLvn{Y(1Y^2GYYUC4g2D35YjJ5%`Z(z!oFrSHtC>}e@DndR&sS0x;dv|=cs?% zD19T&#mI^$n$&Ylh2bLpnhs)Yh?3eTjS4C+jh#HZQ5lo}f@}fIsOAirjAX7#Df9i z;@=(1sjV5GD+-tB{W<*-zPTg-vy$BJly-;GC|pbUw_!9duf9?7GZf)2jxwpt6b~X! z@(L+baEE*csGc5=U%P8QxDC(3NfZWJlGXX<8_gN+wGo*S$et3uH^pnUhmlAk<1cg6 zEmuAf<#i{S*d{XW^oNDwzS3_9X?3kU;6T00Vm~!6(+eO>*9C8Fq&KmOo340tjy0?j zCf9nFs%&5cpzU7CM^@&MN#07dSao%%MKy~{|HhWCc3`5uau%&e;Ls1#pju#_IgB?y z_QI+|F>MuTWD?5kQZ$+lq_oq-E^Jtqz({BoVwB$878+IIROoR2W;#3~uA1qZ#g@y` z)0I7x>j4mvU_&U2riXBl>Qz1yUALGA0n3>Y3pmdTtNGDATKG_`gy?< ziNYJFI3Dp0y_lvw_4~N>AZq%?v6_7I?Ue;7+*0e?6Boxiw3^Oup72W#Gw<-5)6OcZ z)9-cX7OG9e@tNN?_G8Z)aEb>K&KVxtwTcGp)7r%(PEA68-m3S|tEY?^IW9997@y;R zPoLGvV0=(0OofZ<#I=`)7&lF%zPs?m?IO-t7j<-h(%ozCX8!%Y%YM0;b@^Vn@@VR~ z;RCl}xf!#Dn=QZ81cK{L?)LN$2P>&vJ?eZZ8{d{qBFb~>aOu0dq5LHIy5RZfy-B#; zX!!M-`uM7iO4ijY_{b-jO#3I2&ZC|?&zoZOO;vr;p$oQ0(E0LgC9O+%I92?VoRL>p z-U&vE!y64Px!_1TuE^WcVEk%Y%zVAj$*IuEia@~ybvUvz4X^Ku(O-QXV8ll}u!o!>5T5z))f)O{xZ+K50X=L3%c%}K` za*tFJH30{b`d!ePJ`xG zWXAK9Eo{z0c_ao``WE>n)4Ln0m0slmXZx@YupS~-0ZwW-U>E}oO1dP#)kMOAR3QRk zjq*(JDU>zpO!~!YLEHw+(bKHjwTp9EaEjf0Fs+QcWxwK$NcSx)r!HVHRkehI1UeyH zRAW~C@268HI(|^WTWZV5?Ibc2JFEBC$86;@L1y+EHaXfP+}EBdi=TB;IioJZu)na4 zMd22Al47%VC(zaQaf;XeE|MQyz-WI-GOc(BWYsaW7Sm8&Y2ZqG7jlY4<;)GEse3e; zJwRoOs8l0u;*2*pI*k!`OV7eck-*UXao8|q>i7i6nwyIao58!@L&9K>3|SPK7i34#8sPx0XDxq;|%-`TCb;!d%}WT2lcIHxby z%08xbn#yrHbC4ZtBH!6?2JOfd+_GG{wkp3hz-m*)LhHATG88z z`U=-}d}}pQgo?K-`t`|ub`(a9NWcswA3T(<@HmuG;CCkYdB2-yda6ZXLU(Z|;_syt zheCn&P*4yFxUv3^rTEj4%-%RF7)Bh zugvB>QzN@mAAf{AO^y4`Cw->%i=+HMr3wCRkZx}H9|2E)rO&ATcKoG+^1i2CZKNKJ z#QJ?Fm}CuLeb$&@Eon}GC2&@mwYqFS!a-v*D%jq&pyqn&{f77b`)&1?>>gX?yMR(Q z-$ot{W#f4z^p+n6I7Q)1Ck#{|O^_fk7*mb}qJHH)iqlFpxq1nLT4!%APsLk^qEDHT zQ;y4MN*$poN}gYJ_hM3%&w5i@diDtjuj(SJ#gDWZQ(GyvbD!(1m(ubz7dkZcQODYw z&Y7{E+4DE(R$7OkQz*rLX3|mhbCT;jFr`U^%mdw8JXq*ksSC83RWm>Y+y)O$GMyS9 zP#qg5I0qk`huhGcM)&6QPc*19YC$}=uTZ^9TPHq2lw>U3M3!D{UPRe=ZFXrA<4v6&*W1y{U;Oy9_< zLa-@`rggNVP!h($vYIcvn}A@@E+AE0EGn9tGIz>us%GLi0!FkCRsb9i2w&P|YS1U{FS8iN1nj#h!cp z1}MH4H;g50&*tXAzbp4p+J?qexapxmsW{!za$Mc1C_T7!^ydUZzjhh>0|{-Tb-&-R zQEN%NQBlnJ)q+95k8jt|*b0L0rYq^P&Won%`Vp4=LSPWa9x;aIdz|%UI@It-q<&jz z-Pl{;8%@;#1HovA50f@BlwBy(xXVl(n1wb374M#=MH;5H5u_NSAtT@xV6rk?TW?)( zI_TDA>FPKBb4~fk(+65L$D)Q3F6~O&b8XwPwO#S@jZW3avCB$mwMYVawNgl=D#kL~ zMg*abOz_41b=%`F-STT;3 z+@zkylY#xt4$S{hPFc9}+5<#>XWe;;8&SzaYy-}P%&M(e$3Ol07}6fDp-#jluI@oy z6@MCS^CC(~<4H>KswG_EW(7Oba28wKXMr&5)@VAWbb&d_CQSXKGmt4$RD1}I=@q_u z^a;V|y*BvpiX5hTo3wylxb`!vGHT1WEdWDH`AQLnw||QG%vN^dyfyY33IdMAV)V7( z4G(l_8-T=MhAGRCp!_|C3a@|>cl7yd*)r_d)J&OBM&)zk$0VZC?Hbv;WlVI)8m856 zk@n8r3R}+S?a-~?3fg^D(a8cx76GhH!WJj}`SphWMROA0=NQL3Ht)1(Jane@O0+2| ztEjiL*NT$5)#a`^yv4Ivlh=0D!wzJ$bxji?G3BP@d~6$y1lY5$B!$^9>RrZ~B6Y8C zJOb)ED{a)U9yrECcT>eCj!>qYX+~Tl($6}qt69y1J5k}jmmnvuD7H0PFg)7fs~;6C zO3%m|7PpWsXTb}nTN3vh-fcg!WF-mxDnY-b3IRK^eEs63F}J+cnW+M1E{zjV6>@AI z&2ysYr0TGXG>clmJKF{ZH>+I8Sp&sj&LdQAg&#tM4)TgJobbAU?f_WtKNJc5jV)e$ zT(wUUZIesN`i`rxw#?~Sp>I@^@)Y&-)XK-xw?ybkJ#bjg^+|$L2E&D@F*=ted4I4W zd;%927TN9A4Oa;QM9?6#dmNB^1AzyP-WGHR3Dy$5ar)DW-$s-JT@W)o7Pmh{pdc(( zMD|4^;~*~8M7H4Bwb-Og+fkt8S!m$BHn!6pYIIa?6LtP^4IVd)pah{W*KgMN)e}_{i6kr342k9QncMJ^QQM04Y5TLzRi))?|?k_KorSL28vmhWI7Yc z!aK4h)Snk0{5_BEDFMQY7Q$MVcv=g=0u{;3TchL|AS}0c3G3I5lH1J)VYL+4BuhG7 z0mYni(&sMMvx-ocEv@IFXy#EBah?UVMhkB3!{v8ACa`u3!K907LE~gj(f+MM7om5obK+Mn>B?-y4tT_tplL!NVEHKvLRzDv-h1+N)C zwWCKP(zD||>jJ!A*TpV%YfOog*7`QE(8((c*maIUFD&84E)9K&5b)oS;DNdXXFVOz z9CvMVS-q%5)7D*3I!i5EPoH|&-Zu8&c6|gtfSRve&N8oT9bT*p#KUn(JasP)ixj(# z-|oV`zJ^s@&hoj%WH%q(?tw1!=9n+8M|yc8=W~!Nw7)>daR}M+NP2Kj_wrIQIOIIY zLXREs65F5btF^-#lsdq&j)1S`KX>6%l3Q44S)hpa9(uzKU4Jht=Xu4n-C;#8p#5E& za)t8ZbyUKa}5#}E^aHQ&!c-?Bfg1HD%e^xcsd6;?l z@N4d3Y7>w5>-e@ZcBLz_AaV@KI7O=Bl~Au|CP{X!pBO**1DYYwq_uAPZSER@C~_<%|rU1}bf_!f~6b*;X zs+BckZM3AoV4<6=z*Lj&?T`(rdXs7mRL=Xd2cnCXea!k+)`b+YMW>s>HSo7ZgF-~! zpGV_G(ouoF0pNs#;X8eExRCb5j;&NR2G0sFh#uoS3^6srs;!dWdKZ8b)-X&sv83jR zrAYf&br>^DU;Ixa`l;H8DTwbD+mB1Y;-`_yb~(~1(FP{Yun{TZzOz<9sZG{0?fyJR zvDX6Quv8^(FndThKgq;+$B^&7m)HRPx!V>NaX4P5yoZ%8CLu}(IhPj~E>lr%CJJ^u zAFdR@pw%uGw~fjg?o9(~iQtDH^(M+TXws$xy{%HBK@1L=UB27{g+g0PPVha-iOx1} z5OuK4;znjW747)0tv`Cni|^*%g|@Frb@T|675h?+1!hfuFDx)D_9$dpNGdF)9MpsT zY+cR^GJfgMo5~)CByE_ib54UFj@pY;80d%^-KDzS?5xNFn8C};`38H|=mcwzR%zrY zw-yD4sfkFS1Kr-e^yGfJ#gC__6R`}@>xF*Ha{Wp3H_r7uM!K#p-+B&*sHF0=qkFt_0wHg));2=S85C>WSbmH2?70)FVT+*D z3vZ8h_X^}2WQW%7Lx69(7CS2jl32?rL;SpYNnuHSF^gokL&>TYJ_vuKN2;^7tg4Lu zC~uHPRFJQ|!(hwr2E~}PhqS1^mhviEu%A&VH<1zUPk+R9W$x>W#ln2~q6hf$h3wzg z!hd$K8`U5@k@rzPd{zMUY0%W2KZw5sMZS;7XXaqvmtKq zhQ=n`#>$6=#`vbyvHWmUF2ukxGt1g0l{E`)kL5+&2f5Q3LCVj-E(Xqa&WwT0>bEz& zhYZ`U$BmEm%Q2!$>@K(-a)WYcI1yv3K>~=!7JIc|C{YQsTh7-O)jltVi(z>T8!owU z9xk%&_Sbz6si)Y$%Q3QHdJIV1;WVjuH&I8W3Hg$=j+Hw(`)Pqw`^UX?IBv@SIBOfL8zywz)gmL&5^5ZVVyUfK0Lr{ zT#8S8Ejq1)YnbjkReqfAJK=Wq>pLq3<<$=?T1i*op;A}nzD>6eW{k0Gj_QrrT14BM z6FkIs^8BwKJHy?^9YM{;6}>)yj{XOB8YuAIa#Ark`JPcO{$zL>Le!uRikmNa1Jp)v zSxQFq!inN}T0J-_L>9VqrI4O&QC58EsfHPL#Lf6PivSW0VY_co>EIv?4@+cZP zwTgIgXt%f1k_cgS>&xlExdBj8_;jBC_E4i4-iSCLV5Z>f?DAZv0GHTWR_}T*U*I4{ zj@aTj{p^8~Z8hd)Bx`Ylm|B!$&(Wwd$C?=897tKiK-0UcRp@!fkO_KFPvbYFz=FWo zt1`#f0`}Bj(SO_qBm7A4Xo z$pzkn+x$%G8@~w;E$MW}p7`nbBT{iF8?>qc{h@hyZ$&N@y# zLqto{oC!eiYIdZi(UAH1r1uxL)LyBqraxv#7^m5w=Q^AJj)m!Jl|5$CA;w29uY3v^E$xtXW{o}d!Q+|@;}Iu&ko!6WriZdNy0GVOA4Ztb3<2rMwEZa zwi%SVifLEd>sHh-cM*@P^uh)n5tu-Z%Z#n0hm$mZZTv1PhOH|Ae3lqYxfPbxeKw29lmCnPrnVs?S0IV!F!>3Cah- zObO$9zDzfZ88f_7v7kNfitA>)gTSY!qtl%xU8;|Gb+^n2xjie6y_pyeV8)WxLu4Po znND_2`0>*!2~r`H%z!8OC&zN>)|X&1isfj@&sXFwq|KnWh2F|}tUL>=d| zuy8f}GGh7s(4ah(-U)*$LR1Jm=_qrK@)U_Y83b>6+AvUIDpbjDo(a}rkTeG0f%4+G zy(e4b6XkKgC3m#5lx!(PvwiIS&hV#9HNa+<0ZEa#Yd<%ItTN!g<;aig)H#u;C15@~ zj~eWR@G7}|u&@9~DG#yo6IMhN{=`az%}kagMT>bzuiBCzY6?ctvaG05w1Y6rxKQ#y zsgFoyP!_5;L-5tC*flN(EK(W(8>Sz~Jrmc;>unbttXx|JuTVImvv0s) zR~SOGqpSc^6=vO5^uAGVqTkTi;9^++%uI9hY0{R@PC#HU zp4x7ImrmIevx%Q{c`YgKTNW0voo+k7ZOo;4S>ahmoKc!=6oxhQ>+dDmC0wX1RiY}N zqjR!6R&$;!7W$F3@eCi3wFTa~)RAsIFXqlQ->v#%gTMd1cFHfZUwX*u7b=M>rm?H1 z7hPiHU|85D1YX1hyCjzdsmpBYB9$Ukg%f0wR&8)ZYT>$c1W9SWH^RBZJ-TZBz8ev# zt&qGR8R0K3!KG-{j7Avf68$I>HXxVxkMq&$sh4#TG7QGc7T|my*Hr#>RG4y)Z$$^= zg#*^C0Vf5~D#w=Pj;UJgqmHCvA%6896?+Bo8h{@zqu(64m$t1k{3IVKl4c{q@4;A27M6)2RM~WI{RO zBKllmZWkM4SV~6RieR0?pjMk4^3L+SElntx0xMv~PDpwlofHRoOw^)}5paoQB)e%U7lGo!?(Om-w#4#HJjND{+FH zl83(dcm<#bv5B1mb);l7yaC-3^hP|+j9O;)yRqR-tB&g)Q6|grWgd+h-E;=apfPlI z>tB;Wp2X;nBD6TWLW;^eb$7qpApgd?2zHVS8Qn3-Pt9Jq(-O;3y-J1Qm z(w5lQ;gg};QeJA!H(1eoB-A(51n(w(UN3aT$c0F+SV&ue+za@Ws9klI=z8l_)PCmm z#^6@s+uZVTk)`ucnxq(S6PCBu=(~1$quCtk;^&MdhYP90|~ z5au@mglP(-Ibz~b6ESGQmkq+z)B3D1gGRX^+bvdQGxCQR?uDPV_Q#wTa79(Uz|k`9 z?EA*cXqvQ?Q+6qI!AN1%XQ#p#!(YzY91)(+4aNsUteZ5gATuH$S3g3{Ip-o$_WCzt zqdpu&UsDe9bw5eQAw*xshGu-kqu(Qj@8I@kKIRHOOvUG>_GdmEJed?fC~vlH$A>!#Cyk222-%F5lQL%~PE zf+(9Ux=mK$hdBF7_0g8Mz)Q~AG@~u)I$Ufrn04EddK={vvKy=5<5X-p%u2cR%I5?_ zW*?&v>I(vv;)(?s1IXw?+eXeXnuEuD=>zU}4d)n+_+n9Q!Q4Ko>Iu`;q?ID>6SGw> zbe7}a<3Q~_4AzR#<|&Tb+DTQV!P0ny8Ms8J+*bW?T|x*c`g7HCPy0yj?$Ogp zR8IHS>H>JgxiJX8hi}0OEY>oMKnx7Ny^b8e}iB1WoJ&1Q(~ zGLP}iR-k2#(o#_JcA36Vh~v5Ta(y_%D~_)h3>(MdxLrstX}&5)QYD$LTtsY^%S`vcRS7wSikAZ^C?oE$<{>Tzd zr*aTo{>&29`wVrY|M#Oh)lW8LJ7XikzX<~UBVqh={RC?P<-H2vVQq|aXr38600|Ik z!v0mnCvi3eAR%$K0+X{^g0NPX#PZl(sG6>tMTcyd7QmYp7^@HBF(dFwh0P*&#+_s7 zHZJnv|45c8x@&h?s-v>DN|mZ|p5l(V^nA>8T>5z5Z1e$Qi|i(u@w+x@FchFk!0gHv z0@@Xq+CBr#>_@^Xxrb@>RP1k#7uy*DKue8vX3md}4NC2>O%6bE1H6U|&~Hu`=ul?%7x~gmpwV8+j42v6&~Mki+aEjV--zB@w2s4^E**n^2J1K?*JA zoKld8U6@7oTI47lvCJpEUsy|fCVXB|3EFX*Y1SI9F@C3X2eK{?`;2Y2(G9fM<;LTo z<{FeBrmLU5^7kD=2Eso_*h(USTfB)ziD*h$q-NwbK{gT? z8(5u{U8Gf?l(K~yP>dwnEjqp5*B@9v zhN=T4%4BYNuTalZ+=RJ`-K@~0*&pYZoNXa01HVj)b~3uki+*bn9sXLN9!?pU0}xn@ z3cfsL3#>MK@{3Nns*A?k35~|nSNma@H9LQ8h&^+Kgj2nxjKe#a8Vy$Xoz}Z(ml+#j zxix-j*Lb)Y@*qr-T`{Y%r)bw{|5*skIct4%IX=^MiH+E*Ku_t0>nK!8`5ouUM%g82cxhab464$Z)AzH; zki9k(eR@KGe$R_ZmZl}gGsinj6$_2tC`6wYhZD~+;*dCt_NFp|X@v;t&)%$*M;~HE z%Wljbm$1bt>MJvbD7djSmy@NvyW00OA%9~R4^~>nZhzt%_!2>v;5q(tcYgm)hyDB= za#wzW|LIg``q(K@VgAe*PXq*NM~ccNDDP6O)M$K+65or);LM(eg+78Vpt4-Ve1Aw? zCc9cxL0~JJZ1PkXlPBKm(G+!HG<#pm>2O?*nC+FHXm~bfsiud3d#BBDpRg6jA@k~m zA?z&cBsMqZ2Zt=C%mz!Rm!G~ZcjOudMcv6lzFL_Jz235O^7=S{*Tm49#tIwV@>HLe z7nt+Oz8Q|*D$WJ88`JP+^+$yww+sIvqbbQ!Kq9mP>aJ~_B}5+OExCb@qWh!6dMMjc z<*U_tu!)r@+~z8fwI_rw=zKyX;ZqD6{A0mXj5#T_tjinDbq4xbTlBy@A|{V;X8bZC zX0-qk`iPcr!d7KX4%`F~Yb^G;&OoqBtvaT&uAeswHNBM1`x&po6@>N>N)7jP%f(h( zg87BP(RxS2!xlmTU1U229~{D+SBow`4~~Gh@5lE6+g!o^ZQzf69lmkZG$7ip*knNp z;veK+I_z@=B=Y0&&X{Y^nCoZBN`x&$N!*S>Drm*vOmT%bWRth}smy?5&G_O5 zpyxs+gno#=KK@!rZlm8k)Q$J;vOh$y18z2ByzrjGSq3EaQmd~@)?$`NE6LfC_#CM@ z-`a)R+AFRB=4OlV{BeGW7uDS7#&Hc!WEHN~4Cr_EbQk~X5@t>rgG~u~PM=s%zYw3) z4&G6!LSc5NzY;ZAjEKX}smSSxoD%Aorf$kx1WZJzv<$OQS|@4)T1(^0kQ-u0;Pd?1 z4{56t6<&=`va9(W$!3YSs-Scmj6)7TRH-`CA~wKeoycUZaZX8D(Yu7^W4$ge@ekMw zE)jL9g-H=63z!$`26Ho?&-95H)e>H8g(XA<9~c+lMr2Io*5<(8ou3qyjN@99NPc5a zQ13qH+#zR{updU_w<> z5m^=fT_icn7~TJ?u&R6tS=$e`ux25?4tT&;_y9`e&;WFMh_Ris2_s|4z`(ES18>r# zX09hIg&@5$1(i`!y!b~YVqQQ}yc1meS)YG}o5aHWIJ?)&&G(!O9@C4B_IoJbVftJ> zqG*bvA;s4d`RNG5BsO0)Vh+1ZT`vY1GVo8%vAJ=_cv5?eVq_(KzFvOlo1+GQQ#+Af zbuP-?On;3`Rk;{6ilf31I;F60@lpr`(6<0$Lm@vuc?>kbH$&34_I4SGlCTvS3CD?T z?tG1LnZm$1k@E9kV^f8*I(HTY}4brGKw|P{o1=^F-z`z>`${u&&y>SUZ_x!J?~)xFY^_de>}XP;HNK@#!A~rW2}}H8{EV zvt%*@yM0)-36T?XS&3JGKy-y)S7J6^RzI8O`evvdhzY222f5dg%=O&>2=F7w^vo~W zCm7uHgkmln)|yo&@jq>%q|yaWmtdTA2*^!4Hd&|`6t*$RB_D^d6=GvRfHO4h8r7|? zvHhgoiGs%vq3n&BYea$5JOLwegsgFLKHWbgOU8i#Sl=Tq{R17G*GyB+trK&8kJ{;jjHd(L7fyhWUUrYpg z9Ja>v_pl;vyu}^6cZ!(uwVo+5ZY!b{2?8Yi`awVwhZ9c@U4Vm z8(ZGcYvdO&$Gj%qevtE}9@KOHv3$PBUm*$#6qn(^Kn;yrYjQ9-3u|Vb$A0Bj@|LPF zb6-|v|EV>;0ZA~wL2yNGV1SNZX{N*uDmuy2f*P?eub)+DRTi@pfk8>IAA|zHbjWJ( zEEuoNWk5RY_@niHptFHB131V+B#Ox;a)l_Bl0AA4`)(9~^B zqe9<})MRf`rRC~ZP#$u4q&4aecF`WP@;Cg zeTgd2LrGR{L>^Ve4#Ak)jB5VS#TC+JMmkNyn_K(n>q*(KJM#wrAsE-dt_*X900$-b z`|5*?*rFN(MB}w$_#?|S5%w&7KRZ24eh8$NQ6lv|>p+dMFnTSXu<$iG68RO(@yUg? zlJo&Vsrde0aV6RDSIp$&-#GqDrZxxaD#7A=+vM{N!RbCC=V^9iR7l$-D$)k`$9VFp z^}*tEYFIt@Y2}=#{wvI2B5A;abm?A=3E;me7J~xj)O1B4FE;SufR_a>b>^qrlTFIy zqnOQlHC|fPL%iRadqH1d!uaGoX%qvi;s(B9UUN5Xqvo{)kh}(;KLK-Ik&3g#7wMA$ zd|)-hNX0bVLv68);%)ISOkNl*{KOeJ$tGRoL>Uj-g;ksdh%kk5V|M6!@Xq^eR&j98 zdv#WGEncI&m?-jj8Dpi?Ro0NyN4S@HhZiKut%bM)Z!jDxv_v{1oiV^(i-B803>gF% zU}qTxDS(2odw65R&TTc=_Do0g`@Fwp1%})NcEou`qA=epE?*&?*gT0362QDjQi|`1 z>()R`&8ZStP#11EmOP>T>k2j+!qdLu=O`=sle+SMS;78C^I>KFPtM9D)nip8Rpbwt zHGsY^JVLXAp)$T7W^>yY1$u!fP&vd}JxxvkaHNz89V35j`TFDPs&M-o$eSM8HMWP$ zX>;~mcWH6)V<$!(>{^Q3?Z&U)?cE-i?T?+$huxx|qp9#5PgfvAoq7CTTyX?6FQ(}F z5n_ZX54!DuP;oq(T@bvNYeJ6>z)mFZSxQ3 z7(R~T%UEd0(>!S?GYZ*DG&Vv5aZ)*`BVp^5U1FiaT>k0b{8 z#i#A;dCE!)WGKFSl~rlH0qxK@k3LnVh?!+(Mq`?XODJkBB*kf&NQ{u|lS}LOGAY!t z(3mQ-xS(2As4pOIDbKkzpGpsgUxOEm{qQbwU7W$tDE5GXkd&E#8M}=ph_f4V<8VeA zT7@vzccyeibXL?Mr$p4J(~y^D85uFX^*hj5-03h7d1?l9K2&|l1jFaEwNTgKTPxE8 zSfWxjFaKsUE!8k`+E9SeUKA^6WFjg!{B{}|;kl`C_u?VEM|KrG*B{PoSpbqrdB3V; z>a;Ry99Bskr>3Ju{iTUa-e&YuuS|JFvpPkLpO1jKzRn7tSRq1O%2Uv z3xJ=%HfTBRmfw9eIl}0`YwIfMT{; zoVk>Sni(a3BY!mAU6H`DD===XD3KuPyz^j3U}Lxj;H1ajN5e&|&-x$-Qk@S%S11GF zF+-#0ksA@SUn0Rcx)qh!w<}0rzaLOvSL&kHOD;SUV3Douu1iN@sZmox3R1jKF>+lU z(L$h)z)IZVuS(nzyadA4>Yf(rD%h9NB78VOu8|)*cI)gqUc}L{-@Asm(c6x=(f=FB zxe7r6jz@0?PvQw2ui7M|cr`#a^{yE4vxNd$T~cL3wAoD#r3H9~aXQW46*3*}U7_u8 zaC}!5pCQ03`Q-~##<|j4(^`MSWPF;$lgwhsATE69R3~V8FSjIes627Ihf$c8kej6` z9XpT4DR}LGC+0a!LGlw$0cX^Fbteeh8lkM?E;Lhqv=j_d3ZXat&ldgh{ev(ssih<;)56%G_CZu^ zXiia6BkoG_16-nGg#KM>yk@@QSQqp4o=YX)3iWx z5$9(82~M98-Sre!`EE64UBF+Rjix<(voM)nmd$&HDV*72jY3V3n97T4$zS0GT28-~ z^{vCny+MININoEr+Z35ncHHewhgKftCH<%jwt*epNM-ly=9UI67jxI$7{@2AAPE^dhkBzV10^A#jJyZ}@DNtmngXNX846^OJXKeywyw%rX?XMx%kr58x zTOFFqZxCJ<>XRC}GXV*$hmE)l&!0xxlZO3HN9q{!4#JP*;8DZJW4(XDFH23dTya?;&T5 zWh5<6dS{qU#O%(%NjVdThRq%=(<1Xw0nILEDb3gRn)^bbJJq03a8t1%`Cv-@eg04F zflAkR0?AL-@#Rmk6^4H|uo2RC(*K(#nxdhtoiTv^9}|FzV+u(8$e({GXu>wR(8jl~ z;sR1ao>Vnd)VM*)0Gd3t{VK*e5SWDH(lm${>Q`SZR+|Q=ZLlZl+DvYT^olJ{&&M@UHH!P4W;n2WSM)(Pb(50T+ zvAwG**?Q>gv3@0u=`aYL+b}tVyI`aH?*uUg8_fYK4pfGqhsyAwW^0G`RA!nyW@HP< z2yoF9wUj{eVM!7i`h_wV)-C-=U5Djx-&KPQj140QsCU<6sy1%|hift~DK-(Rriiwc zg&it7D*HSv+RYcCTQlk~g1M36dgILF^mEG(v!01-rMX6e+BAyN&cK93~oIYG9-KV0CuuZe@*#OmSa}+B^dXzl zq2?IQutm6AGh7D~`W#zB`6uJe+n}wUuGvfoK^-s&TeyDRq%e>Ook(`7eY-Yx?2=vm zsqTy_aRNt(;tOoVHg?lJgvv?1J~l(9mk}vAnWdg1TA{UCXL=9d>&Y$Eh1>(OFr(Pp zP(jr3Jd{a`sk_~y<%J(st0}n0g~Y|mX)86w!pZpOLQ#+~kUB%0@T|BZ9pVbtpHtJ@ zW-%ZPU%z~T`z)US3*YzOJ5B#mH2)F(Cnqi2#|Q5*en?@@p9!u=$6w$C1CzVo&szR5WA8DZeW7xg%a)xsQbAG zH9K-ibWytrmndOGGRvtO!jROZLXji$O3;75C$*P{R$i=MLUNO;9p z!>X(35EC;JwjOn<2UElK8stAatzW)4YhbE>J`Mi4eXb6Ckrr0srxuqHp|#d`Hn#a^ zCdPk1nBc!3Y-CJh;-LTC#?02l*n!5}*!q7lXZ?RMH?Xy}Hg?drG5wEc5%u2-!9PL4 zzmP|vs<)DvYW02=psvrJH_!ifP&->|8dqzp1;t*QH9F`{v?E^hF3s=^oM1kAT1`J7 zYSf<78cIsWCP+<0z>4^XciFD1L!1*19dwDUwwJ_`E#W86exG@cF{4VQW z#eam ztDGA_*2NRV3_LK_CwLR5;3zI&)TG01=DN|7$zRDGLUoPPr5d&~h+)+E!*T}LV|)$E-*nx7`Bt+N%pWCxTf)c!5xI6!;02Pu z6|K~4_)#Wc7NDNn=tEb%hr?athhXPa8y~PP&@95z`=ywZGWL)?znJJyk$V~Pt#qCq zu`qf~9G7z?(eSu>7xPv>qJQ4jp2Tt|SENQLpbT2|+F~BUCwjVDH@G=x>zBoJ!un<| zc_tsa&TlEsM_hK=Uz6W%&)KQ#l_y4S_RVC@jy_agzj1r=tpKGL)#;tY5Mv=TP06(R zRC4%7i?U}ieEhR?|6LK3X_6nt_p?xhe(u8m{|bkl!)J5o;AC#>2s2&_*^dwZWm@|R z50*i+3?>MaAyGjhM5+l-Z^s;GXJqi(%j3lB7PIX5&#JtTW3c=+ddZo{#O)?wI<)Dw zrKK)LJD+9N)P&=LP$^Bf=iYqCv!>TV-wH$;1-2^kmR4L21ZvT&{H#(v%dnGTv09?) zup2uSjkHD7VM>YXPhFv}K*+$KrfB^qgwzYzYrxbO4xpOyEs z!v4=E{5e+s$M!e7lYg;uG&Hs`{$H)p{?qtByrO?T2LAH;cWcMb$=dIB{{`gl1tX8= zDY5!;3xe*g9!ZR<4DfISlq_R*ul`)&dK&4RJwm%uA{ihPn zU)b09{}%hd=;Hi|`=@}&U$}^$G0p$xru;WKkw4M@q+kCFo#B%P^WUNWU&+}2bnz#p z^ItCbKN+6?t&4vpc>WXoPu|YIz*|4r-B|R_EyCFJS^~zR z^e13lU3Bx&dngF=nHoqjAJShzn2uS8g4*8@Ai(hde^Vn;Eevao - - - - - - - - src/main/javadoc - diff --git a/boomerangScope-SootUp/target/javadoc-bundle-options/package-list b/boomerangScope-SootUp/target/javadoc-bundle-options/package-list deleted file mode 100644 index 351c18685..000000000 --- a/boomerangScope-SootUp/target/javadoc-bundle-options/package-list +++ /dev/null @@ -1,217 +0,0 @@ -java.applet -java.awt -java.awt.color -java.awt.datatransfer -java.awt.dnd -java.awt.event -java.awt.font -java.awt.geom -java.awt.im -java.awt.im.spi -java.awt.image -java.awt.image.renderable -java.awt.print -java.beans -java.beans.beancontext -java.io -java.lang -java.lang.annotation -java.lang.instrument -java.lang.invoke -java.lang.management -java.lang.ref -java.lang.reflect -java.math -java.net -java.nio -java.nio.channels -java.nio.channels.spi -java.nio.charset -java.nio.charset.spi -java.nio.file -java.nio.file.attribute -java.nio.file.spi -java.rmi -java.rmi.activation -java.rmi.dgc -java.rmi.registry -java.rmi.server -java.security -java.security.acl -java.security.cert -java.security.interfaces -java.security.spec -java.sql -java.text -java.text.spi -java.time -java.time.chrono -java.time.format -java.time.temporal -java.time.zone -java.util -java.util.concurrent -java.util.concurrent.atomic -java.util.concurrent.locks -java.util.function -java.util.jar -java.util.logging -java.util.prefs -java.util.regex -java.util.spi -java.util.stream -java.util.zip -javax.accessibility -javax.activation -javax.activity -javax.annotation -javax.annotation.processing -javax.crypto -javax.crypto.interfaces -javax.crypto.spec -javax.imageio -javax.imageio.event -javax.imageio.metadata -javax.imageio.plugins.bmp -javax.imageio.plugins.jpeg -javax.imageio.spi -javax.imageio.stream -javax.jws -javax.jws.soap -javax.lang.model -javax.lang.model.element -javax.lang.model.type -javax.lang.model.util -javax.management -javax.management.loading -javax.management.modelmbean -javax.management.monitor -javax.management.openmbean -javax.management.relation -javax.management.remote -javax.management.remote.rmi -javax.management.timer -javax.naming -javax.naming.directory -javax.naming.event -javax.naming.ldap -javax.naming.spi -javax.net -javax.net.ssl -javax.print -javax.print.attribute -javax.print.attribute.standard -javax.print.event -javax.rmi -javax.rmi.CORBA -javax.rmi.ssl -javax.script -javax.security.auth -javax.security.auth.callback -javax.security.auth.kerberos -javax.security.auth.login -javax.security.auth.spi -javax.security.auth.x500 -javax.security.cert -javax.security.sasl -javax.sound.midi -javax.sound.midi.spi -javax.sound.sampled -javax.sound.sampled.spi -javax.sql -javax.sql.rowset -javax.sql.rowset.serial -javax.sql.rowset.spi -javax.swing -javax.swing.border -javax.swing.colorchooser -javax.swing.event -javax.swing.filechooser -javax.swing.plaf -javax.swing.plaf.basic -javax.swing.plaf.metal -javax.swing.plaf.multi -javax.swing.plaf.nimbus -javax.swing.plaf.synth -javax.swing.table -javax.swing.text -javax.swing.text.html -javax.swing.text.html.parser -javax.swing.text.rtf -javax.swing.tree -javax.swing.undo -javax.tools -javax.transaction -javax.transaction.xa -javax.xml -javax.xml.bind -javax.xml.bind.annotation -javax.xml.bind.annotation.adapters -javax.xml.bind.attachment -javax.xml.bind.helpers -javax.xml.bind.util -javax.xml.crypto -javax.xml.crypto.dom -javax.xml.crypto.dsig -javax.xml.crypto.dsig.dom -javax.xml.crypto.dsig.keyinfo -javax.xml.crypto.dsig.spec -javax.xml.datatype -javax.xml.namespace -javax.xml.parsers -javax.xml.soap -javax.xml.stream -javax.xml.stream.events -javax.xml.stream.util -javax.xml.transform -javax.xml.transform.dom -javax.xml.transform.sax -javax.xml.transform.stax -javax.xml.transform.stream -javax.xml.validation -javax.xml.ws -javax.xml.ws.handler -javax.xml.ws.handler.soap -javax.xml.ws.http -javax.xml.ws.soap -javax.xml.ws.spi -javax.xml.ws.spi.http -javax.xml.ws.wsaddressing -javax.xml.xpath -org.ietf.jgss -org.omg.CORBA -org.omg.CORBA.DynAnyPackage -org.omg.CORBA.ORBPackage -org.omg.CORBA.TypeCodePackage -org.omg.CORBA.portable -org.omg.CORBA_2_3 -org.omg.CORBA_2_3.portable -org.omg.CosNaming -org.omg.CosNaming.NamingContextExtPackage -org.omg.CosNaming.NamingContextPackage -org.omg.Dynamic -org.omg.DynamicAny -org.omg.DynamicAny.DynAnyFactoryPackage -org.omg.DynamicAny.DynAnyPackage -org.omg.IOP -org.omg.IOP.CodecFactoryPackage -org.omg.IOP.CodecPackage -org.omg.Messaging -org.omg.PortableInterceptor -org.omg.PortableInterceptor.ORBInitInfoPackage -org.omg.PortableServer -org.omg.PortableServer.CurrentPackage -org.omg.PortableServer.POAManagerPackage -org.omg.PortableServer.POAPackage -org.omg.PortableServer.ServantLocatorPackage -org.omg.PortableServer.portable -org.omg.SendingContext -org.omg.stub.java.rmi -org.w3c.dom -org.w3c.dom.bootstrap -org.w3c.dom.events -org.w3c.dom.ls -org.w3c.dom.views -org.xml.sax -org.xml.sax.ext -org.xml.sax.helpers diff --git a/boomerangScope-SootUp/target/maven-archiver/pom.properties b/boomerangScope-SootUp/target/maven-archiver/pom.properties deleted file mode 100644 index dc504a7b4..000000000 --- a/boomerangScope-SootUp/target/maven-archiver/pom.properties +++ /dev/null @@ -1,5 +0,0 @@ -#Generated by Maven -#Mon Aug 26 11:19:42 CEST 2024 -groupId=de.fraunhofer.iem -artifactId=boomerangScope-SootUp -version=3.1.2-Sparse diff --git a/boomerangScope-SootUp/target/maven-javadoc-plugin-stale-data.txt b/boomerangScope-SootUp/target/maven-javadoc-plugin-stale-data.txt deleted file mode 100644 index b8615cea2..000000000 --- a/boomerangScope-SootUp/target/maven-javadoc-plugin-stale-data.txt +++ /dev/null @@ -1,101 +0,0 @@ --J-Duser.language= --J-Duser.country= -@options -@packages --classpath -'C:/Users/Sven/Documents/GitHub/SparseBoomerang/boomerangScope/target/boomerangScope-3.1.2-Sparse.jar;C:/Users/Sven/.m2/repository/org/soot-oss/soot/4.5.0/soot-4.5.0.jar;C:/Users/Sven/.m2/repository/org/smali/dexlib2/2.5.2/dexlib2-2.5.2.jar;C:/Users/Sven/.m2/repository/org/ow2/asm/asm/9.7/asm-9.7.jar;C:/Users/Sven/.m2/repository/org/ow2/asm/asm-tree/9.7/asm-tree-9.7.jar;C:/Users/Sven/.m2/repository/org/ow2/asm/asm-util/9.7/asm-util-9.7.jar;C:/Users/Sven/.m2/repository/org/ow2/asm/asm-analysis/9.7/asm-analysis-9.7.jar;C:/Users/Sven/.m2/repository/org/ow2/asm/asm-commons/9.7/asm-commons-9.7.jar;C:/Users/Sven/.m2/repository/xmlpull/xmlpull/1.1.3.4d_b4_min/xmlpull-1.1.3.4d_b4_min.jar;C:/Users/Sven/.m2/repository/de/upb/cs/swt/axml/2.1.3/axml-2.1.3.jar;C:/Users/Sven/.m2/repository/ca/mcgill/sable/polyglot/2006/polyglot-2006.jar;C:/Users/Sven/.m2/repository/ca/mcgill/sable/jasmin/3.0.3/jasmin-3.0.3.jar;C:/Users/Sven/.m2/repository/ca/mcgill/sable/java_cup/0.9.2/java_cup-0.9.2.jar;C:/Users/Sven/.m2/repository/jakarta/annotation/jakarta.annotation-api/2.1.1/jakarta.annotation-api-2.1.1.jar;C:/Users/Sven/.m2/repository/jakarta/xml/bind/jakarta.xml.bind-api/3.0.0/jakarta.xml.bind-api-3.0.0.jar;C:/Users/Sven/.m2/repository/com/sun/activation/jakarta.activation/2.0.0/jakarta.activation-2.0.0.jar;C:/Users/Sven/.m2/repository/org/glassfish/jaxb/jaxb-runtime/3.0.0/jaxb-runtime-3.0.0.jar;C:/Users/Sven/.m2/repository/org/glassfish/jaxb/jaxb-core/3.0.0/jaxb-core-3.0.0.jar;C:/Users/Sven/.m2/repository/org/glassfish/jaxb/txw2/3.0.0/txw2-3.0.0.jar;C:/Users/Sven/.m2/repository/com/sun/istack/istack-commons-runtime/4.0.0/istack-commons-runtime-4.0.0.jar;C:/Users/Sven/.m2/repository/com/google/protobuf/protobuf-java/3.21.7/protobuf-java-3.21.7.jar;C:/Users/Sven/.m2/repository/com/google/protobuf/protobuf-java-util/3.21.2/protobuf-java-util-3.21.2.jar;C:/Users/Sven/.m2/repository/com/google/code/gson/gson/2.8.9/gson-2.8.9.jar;C:/Users/Sven/Documents/GitHub/SparseBoomerang/SynchronizedPDS/target/synchronizedPDS-3.1.2-Sparse.jar;C:/Users/Sven/Documents/GitHub/SparseBoomerang/WPDS/target/WPDS-3.1.2-Sparse.jar;C:/Users/Sven/.m2/repository/de/fraunhofer/iem/pathexpression/1.0.2/pathexpression-1.0.2.jar;C:/Users/Sven/.m2/repository/org/apache/logging/log4j/log4j-core/2.17.1/log4j-core-2.17.1.jar;C:/Users/Sven/.m2/repository/org/apache/logging/log4j/log4j-api/2.17.1/log4j-api-2.17.1.jar;C:/Users/Sven/.m2/repository/org/soot-oss/sootup.core/1.3.0/sootup.core-1.3.0.jar;C:/Users/Sven/.m2/repository/org/jgrapht/jgrapht-core/1.3.1/jgrapht-core-1.3.1.jar;C:/Users/Sven/.m2/repository/org/jheaps/jheaps/0.10/jheaps-0.10.jar;C:/Users/Sven/.m2/repository/org/slf4j/slf4j-api/2.0.16/slf4j-api-2.0.16.jar;C:/Users/Sven/.m2/repository/org/apache/commons/commons-lang3/3.16.0/commons-lang3-3.16.0.jar;C:/Users/Sven/.m2/repository/commons-io/commons-io/2.11.0/commons-io-2.11.0.jar;C:/Users/Sven/.m2/repository/com/google/guava/guava/33.3.0-jre/guava-33.3.0-jre.jar;C:/Users/Sven/.m2/repository/com/google/guava/failureaccess/1.0.2/failureaccess-1.0.2.jar;C:/Users/Sven/.m2/repository/com/google/guava/listenablefuture/9999.0-empty-to-avoid-conflict-with-guava/listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar;C:/Users/Sven/.m2/repository/org/checkerframework/checker-qual/3.43.0/checker-qual-3.43.0.jar;C:/Users/Sven/.m2/repository/com/google/errorprone/error_prone_annotations/2.28.0/error_prone_annotations-2.28.0.jar;C:/Users/Sven/.m2/repository/com/google/j2objc/j2objc-annotations/3.0.0/j2objc-annotations-3.0.0.jar;C:/Users/Sven/.m2/repository/com/google/code/findbugs/jsr305/3.0.2/jsr305-3.0.2.jar;C:/Users/Sven/.m2/repository/org/soot-oss/sootup.java.core/1.3.0/sootup.java.core-1.3.0.jar;C:/Users/Sven/.m2/repository/org/soot-oss/sootup.callgraph/1.3.0/sootup.callgraph-1.3.0.jar;C:/Users/Sven/.m2/repository/org/soot-oss/sootup.analysis/1.3.0/sootup.analysis-1.3.0.jar;C:/Users/Sven/.m2/repository/de/upb/cs/swt/heros/1.2.3/heros-1.2.3.jar;C:/Users/Sven/.m2/repository/org/functionaljava/functionaljava/4.2/functionaljava-4.2.jar' --encoding -'UTF-8' --protected --source -'8' --sourcepath -'C:/Users/Sven/Documents/GitHub/SparseBoomerang/boomerangScope-SootUp/src/main/java;C:/Users/Sven/Documents/GitHub/SparseBoomerang/boomerangScope-SootUp/target/generated-sources/annotations' --Xdoclint:none --author --bottom -'Copyright © 2024. All rights reserved.' --charset -'UTF-8' --d -'C:/Users/Sven/Documents/GitHub/SparseBoomerang/boomerangScope-SootUp/target/apidocs' --docencoding -'UTF-8' --doctitle -'boomerangScope-SootUp 3.1.2-Sparse API' --linkoffline -'https://docs.oracle.com/javase/8/docs/api' 'C:/Users/Sven/Documents/GitHub/SparseBoomerang/boomerangScope-SootUp/target/javadoc-bundle-options' --linkoffline -'https://github.com/secure-software-engineering/SparseBoomerang/boomerangScope/apidocs' 'C:/Users/Sven/Documents/GitHub/SparseBoomerang/boomerangScope/target/apidocs' --use --version --windowtitle -'boomerangScope-SootUp 3.1.2-Sparse API' -boomerang.scene.sootup -C:\Users\Sven\Documents\GitHub\SparseBoomerang\boomerangScope\target\boomerangScope-3.1.2-Sparse.jar = 1724663919186 -C:\Users\Sven\.m2\repository\org\soot-oss\soot\4.5.0\soot-4.5.0.jar = 1713974931957 -C:\Users\Sven\.m2\repository\org\smali\dexlib2\2.5.2\dexlib2-2.5.2.jar = 1703708584873 -C:\Users\Sven\.m2\repository\org\ow2\asm\asm\9.7\asm-9.7.jar = 1713974929160 -C:\Users\Sven\.m2\repository\org\ow2\asm\asm-tree\9.7\asm-tree-9.7.jar = 1713974929241 -C:\Users\Sven\.m2\repository\org\ow2\asm\asm-util\9.7\asm-util-9.7.jar = 1713974929421 -C:\Users\Sven\.m2\repository\org\ow2\asm\asm-analysis\9.7\asm-analysis-9.7.jar = 1713974929497 -C:\Users\Sven\.m2\repository\org\ow2\asm\asm-commons\9.7\asm-commons-9.7.jar = 1713974929578 -C:\Users\Sven\.m2\repository\xmlpull\xmlpull\1.1.3.4d_b4_min\xmlpull-1.1.3.4d_b4_min.jar = 1679673563401 -C:\Users\Sven\.m2\repository\de\upb\cs\swt\axml\2.1.3\axml-2.1.3.jar = 1699704152472 -C:\Users\Sven\.m2\repository\ca\mcgill\sable\polyglot\2006\polyglot-2006.jar = 1679673557077 -C:\Users\Sven\.m2\repository\ca\mcgill\sable\jasmin\3.0.3\jasmin-3.0.3.jar = 1703708582768 -C:\Users\Sven\.m2\repository\ca\mcgill\sable\java_cup\0.9.2\java_cup-0.9.2.jar = 1679673556626 -C:\Users\Sven\.m2\repository\jakarta\annotation\jakarta.annotation-api\2.1.1\jakarta.annotation-api-2.1.1.jar = 1713974929285 -C:\Users\Sven\.m2\repository\jakarta\xml\bind\jakarta.xml.bind-api\3.0.0\jakarta.xml.bind-api-3.0.0.jar = 1713974929389 -C:\Users\Sven\.m2\repository\com\sun\activation\jakarta.activation\2.0.0\jakarta.activation-2.0.0.jar = 1713974929477 -C:\Users\Sven\.m2\repository\org\glassfish\jaxb\jaxb-runtime\3.0.0\jaxb-runtime-3.0.0.jar = 1713974931250 -C:\Users\Sven\.m2\repository\org\glassfish\jaxb\jaxb-core\3.0.0\jaxb-core-3.0.0.jar = 1713974931537 -C:\Users\Sven\.m2\repository\org\glassfish\jaxb\txw2\3.0.0\txw2-3.0.0.jar = 1713974929485 -C:\Users\Sven\.m2\repository\com\sun\istack\istack-commons-runtime\4.0.0\istack-commons-runtime-4.0.0.jar = 1713974929561 -C:\Users\Sven\.m2\repository\com\google\protobuf\protobuf-java\3.21.7\protobuf-java-3.21.7.jar = 1703708583123 -C:\Users\Sven\.m2\repository\com\google\protobuf\protobuf-java-util\3.21.2\protobuf-java-util-3.21.2.jar = 1703708583231 -C:\Users\Sven\.m2\repository\com\google\code\gson\gson\2.8.9\gson-2.8.9.jar = 1701266437796 -C:\Users\Sven\Documents\GitHub\SparseBoomerang\SynchronizedPDS\target\synchronizedPDS-3.1.2-Sparse.jar = 1724663900785 -C:\Users\Sven\Documents\GitHub\SparseBoomerang\WPDS\target\WPDS-3.1.2-Sparse.jar = 1724663890939 -C:\Users\Sven\.m2\repository\de\fraunhofer\iem\pathexpression\1.0.2\pathexpression-1.0.2.jar = 1710413283107 -C:\Users\Sven\.m2\repository\org\apache\logging\log4j\log4j-core\2.17.1\log4j-core-2.17.1.jar = 1708206016783 -C:\Users\Sven\.m2\repository\org\apache\logging\log4j\log4j-api\2.17.1\log4j-api-2.17.1.jar = 1708206011406 -C:\Users\Sven\.m2\repository\org\soot-oss\sootup.core\1.3.0\sootup.core-1.3.0.jar = 1723818962590 -C:\Users\Sven\.m2\repository\org\jgrapht\jgrapht-core\1.3.1\jgrapht-core-1.3.1.jar = 1723818962557 -C:\Users\Sven\.m2\repository\org\jheaps\jheaps\0.10\jheaps-0.10.jar = 1723818962476 -C:\Users\Sven\.m2\repository\org\slf4j\slf4j-api\2.0.16\slf4j-api-2.0.16.jar = 1723818651559 -C:\Users\Sven\.m2\repository\org\apache\commons\commons-lang3\3.16.0\commons-lang3-3.16.0.jar = 1723818924217 -C:\Users\Sven\.m2\repository\commons-io\commons-io\2.11.0\commons-io-2.11.0.jar = 1679673488677 -C:\Users\Sven\.m2\repository\com\google\guava\guava\33.3.0-jre\guava-33.3.0-jre.jar = 1724337378976 -C:\Users\Sven\.m2\repository\com\google\guava\failureaccess\1.0.2\failureaccess-1.0.2.jar = 1705141324774 -C:\Users\Sven\.m2\repository\com\google\guava\listenablefuture\9999.0-empty-to-avoid-conflict-with-guava\listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar = 1700319423360 -C:\Users\Sven\.m2\repository\org\checkerframework\checker-qual\3.43.0\checker-qual-3.43.0.jar = 1724337378175 -C:\Users\Sven\.m2\repository\com\google\errorprone\error_prone_annotations\2.28.0\error_prone_annotations-2.28.0.jar = 1724337378156 -C:\Users\Sven\.m2\repository\com\google\j2objc\j2objc-annotations\3.0.0\j2objc-annotations-3.0.0.jar = 1712570923943 -C:\Users\Sven\.m2\repository\com\google\code\findbugs\jsr305\3.0.2\jsr305-3.0.2.jar = 1679671779160 -C:\Users\Sven\.m2\repository\org\soot-oss\sootup.java.core\1.3.0\sootup.java.core-1.3.0.jar = 1723819387895 -C:\Users\Sven\.m2\repository\org\soot-oss\sootup.callgraph\1.3.0\sootup.callgraph-1.3.0.jar = 1724337596950 -C:\Users\Sven\.m2\repository\org\soot-oss\sootup.analysis\1.3.0\sootup.analysis-1.3.0.jar = 1724341280274 -C:\Users\Sven\.m2\repository\de\upb\cs\swt\heros\1.2.3\heros-1.2.3.jar = 1699704152797 -C:\Users\Sven\.m2\repository\org\functionaljava\functionaljava\4.2\functionaljava-4.2.jar = 1679673568182 -C:\Users\Sven\Documents\GitHub\SparseBoomerang\boomerangScope-SootUp\src\main\java = 1724337334069 -C:\Users\Sven\Documents\GitHub\SparseBoomerang\boomerangScope-SootUp\target\generated-sources\annotations = 1724663981669 -C:\Users\Sven\Documents\GitHub\SparseBoomerang\boomerangScope-SootUp\target\apidocs\allclasses-index.html = 1724663988215 -C:\Users\Sven\Documents\GitHub\SparseBoomerang\boomerangScope-SootUp\target\apidocs\allclasses.html = 1724663988227 -C:\Users\Sven\Documents\GitHub\SparseBoomerang\boomerangScope-SootUp\target\apidocs\allpackages-index.html = 1724663988218 -C:\Users\Sven\Documents\GitHub\SparseBoomerang\boomerangScope-SootUp\target\apidocs\constant-values.html = 1724663988042 -C:\Users\Sven\Documents\GitHub\SparseBoomerang\boomerangScope-SootUp\target\apidocs\deprecated-list.html = 1724663988225 -C:\Users\Sven\Documents\GitHub\SparseBoomerang\boomerangScope-SootUp\target\apidocs\element-list = 1724663988016 -C:\Users\Sven\Documents\GitHub\SparseBoomerang\boomerangScope-SootUp\target\apidocs\help-doc.html = 1724663988233 -C:\Users\Sven\Documents\GitHub\SparseBoomerang\boomerangScope-SootUp\target\apidocs\index-all.html = 1724663988209 -C:\Users\Sven\Documents\GitHub\SparseBoomerang\boomerangScope-SootUp\target\apidocs\index.html = 1724663988230 -C:\Users\Sven\Documents\GitHub\SparseBoomerang\boomerangScope-SootUp\target\apidocs\member-search-index.js = 1724663988203 -C:\Users\Sven\Documents\GitHub\SparseBoomerang\boomerangScope-SootUp\target\apidocs\member-search-index.zip = 1724663988205 -C:\Users\Sven\Documents\GitHub\SparseBoomerang\boomerangScope-SootUp\target\apidocs\overview-tree.html = 1724663988147 -C:\Users\Sven\Documents\GitHub\SparseBoomerang\boomerangScope-SootUp\target\apidocs\package-search-index.js = 1724663988194 -C:\Users\Sven\Documents\GitHub\SparseBoomerang\boomerangScope-SootUp\target\apidocs\package-search-index.zip = 1724663988198 -C:\Users\Sven\Documents\GitHub\SparseBoomerang\boomerangScope-SootUp\target\apidocs\script.js = 1724663988238 -C:\Users\Sven\Documents\GitHub\SparseBoomerang\boomerangScope-SootUp\target\apidocs\search.js = 1724663988241 -C:\Users\Sven\Documents\GitHub\SparseBoomerang\boomerangScope-SootUp\target\apidocs\stylesheet.css = 1724663988237 -C:\Users\Sven\Documents\GitHub\SparseBoomerang\boomerangScope-SootUp\target\apidocs\type-search-index.js = 1724663988200 -C:\Users\Sven\Documents\GitHub\SparseBoomerang\boomerangScope-SootUp\target\apidocs\type-search-index.zip = 1724663988202 diff --git a/boomerangScope-SootUp/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst b/boomerangScope-SootUp/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst deleted file mode 100644 index 23eb2171e..000000000 --- a/boomerangScope-SootUp/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst +++ /dev/null @@ -1,18 +0,0 @@ -boomerang\scene\sootup\JimpleUpDeclaredMethod.class -boomerang\scene\sootup\BoomerangPreInterceptor.class -boomerang\scene\sootup\JimpleUpControlFlowGraph.class -boomerang\scene\sootup\JimpleUpField.class -boomerang\scene\sootup\JimpleUpVal.class -boomerang\scene\sootup\SootUpDataFlowScope.class -boomerang\scene\sootup\JimpleUpDoubleVal.class -boomerang\scene\sootup\SootUpClient.class -boomerang\scene\sootup\JimpleUpWrappedClass.class -boomerang\scene\sootup\SootUpDataFlowScope$1.class -boomerang\scene\sootup\JimpleUpStatement.class -boomerang\scene\sootup\JimpleUpMethod.class -boomerang\scene\sootup\JimpleUpInvokeExpr.class -boomerang\scene\sootup\JimpleUpInstanceFieldRef.class -boomerang\scene\sootup\JimpleUpStaticFieldVal.class -boomerang\scene\sootup\JimpleUpIfStatement.class -boomerang\scene\sootup\JimpleUpType.class -boomerang\scene\sootup\SootUpCallGraph.class diff --git a/boomerangScope-SootUp/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst b/boomerangScope-SootUp/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst deleted file mode 100644 index b4e957a00..000000000 --- a/boomerangScope-SootUp/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst +++ /dev/null @@ -1,17 +0,0 @@ -C:\Users\Sven\Documents\GitHub\SparseBoomerang\boomerangScope-SootUp\src\main\java\boomerang\scene\sootup\BoomerangPreInterceptor.java -C:\Users\Sven\Documents\GitHub\SparseBoomerang\boomerangScope-SootUp\src\main\java\boomerang\scene\sootup\JimpleUpControlFlowGraph.java -C:\Users\Sven\Documents\GitHub\SparseBoomerang\boomerangScope-SootUp\src\main\java\boomerang\scene\sootup\JimpleUpDeclaredMethod.java -C:\Users\Sven\Documents\GitHub\SparseBoomerang\boomerangScope-SootUp\src\main\java\boomerang\scene\sootup\JimpleUpDoubleVal.java -C:\Users\Sven\Documents\GitHub\SparseBoomerang\boomerangScope-SootUp\src\main\java\boomerang\scene\sootup\JimpleUpField.java -C:\Users\Sven\Documents\GitHub\SparseBoomerang\boomerangScope-SootUp\src\main\java\boomerang\scene\sootup\JimpleUpIfStatement.java -C:\Users\Sven\Documents\GitHub\SparseBoomerang\boomerangScope-SootUp\src\main\java\boomerang\scene\sootup\JimpleUpInstanceFieldRef.java -C:\Users\Sven\Documents\GitHub\SparseBoomerang\boomerangScope-SootUp\src\main\java\boomerang\scene\sootup\JimpleUpInvokeExpr.java -C:\Users\Sven\Documents\GitHub\SparseBoomerang\boomerangScope-SootUp\src\main\java\boomerang\scene\sootup\JimpleUpMethod.java -C:\Users\Sven\Documents\GitHub\SparseBoomerang\boomerangScope-SootUp\src\main\java\boomerang\scene\sootup\JimpleUpStatement.java -C:\Users\Sven\Documents\GitHub\SparseBoomerang\boomerangScope-SootUp\src\main\java\boomerang\scene\sootup\JimpleUpStaticFieldVal.java -C:\Users\Sven\Documents\GitHub\SparseBoomerang\boomerangScope-SootUp\src\main\java\boomerang\scene\sootup\JimpleUpType.java -C:\Users\Sven\Documents\GitHub\SparseBoomerang\boomerangScope-SootUp\src\main\java\boomerang\scene\sootup\JimpleUpVal.java -C:\Users\Sven\Documents\GitHub\SparseBoomerang\boomerangScope-SootUp\src\main\java\boomerang\scene\sootup\JimpleUpWrappedClass.java -C:\Users\Sven\Documents\GitHub\SparseBoomerang\boomerangScope-SootUp\src\main\java\boomerang\scene\sootup\SootUpCallGraph.java -C:\Users\Sven\Documents\GitHub\SparseBoomerang\boomerangScope-SootUp\src\main\java\boomerang\scene\sootup\SootUpClient.java -C:\Users\Sven\Documents\GitHub\SparseBoomerang\boomerangScope-SootUp\src\main\java\boomerang\scene\sootup\SootUpDataFlowScope.java diff --git a/boomerangScope-SootUp/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/createdFiles.lst b/boomerangScope-SootUp/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/createdFiles.lst deleted file mode 100644 index e69de29bb..000000000 diff --git a/boomerangScope-SootUp/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst b/boomerangScope-SootUp/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst deleted file mode 100644 index e69de29bb..000000000 From c10931c507dbe2503f3ad8e0a80062cc167c812f Mon Sep 17 00:00:00 2001 From: Sven Meyer Date: Fri, 27 Sep 2024 19:54:24 +0200 Subject: [PATCH 02/61] Add first version of Opal Scope --- boomerangScope-Opal/.gitignore | 3 + boomerangScope-Opal/pom.xml | 58 ++++ .../src/main/scala/boomerang/scene/Main.scala | 41 +++ .../boomerang/scene/opal/OpalCallGraph.scala | 50 +++ .../boomerang/scene/opal/OpalClient.scala | 36 +++ .../scene/opal/OpalControlFlowGraph.scala | 78 +++++ .../scene/opal/OpalDeclaredMethod.scala | 37 +++ .../boomerang/scene/opal/OpalDoubleVal.scala | 18 ++ .../boomerang/scene/opal/OpalField.scala | 20 ++ .../scene/opal/OpalIfStatement.scala | 36 +++ .../boomerang/scene/opal/OpalInvokeExpr.scala | 85 ++++++ .../boomerang/scene/opal/OpalMethod.scala | 174 +++++++++++ .../boomerang/scene/opal/OpalStatement.scala | 288 ++++++++++++++++++ .../scene/opal/OpalStaticFieldVal.scala | 64 ++++ .../scala/boomerang/scene/opal/OpalType.scala | 46 +++ .../scala/boomerang/scene/opal/OpalVal.scala | 138 +++++++++ .../scene/opal/OpalWrappedClass.scala | 48 +++ .../scene/jimple/JimpleStaticFieldVal.java | 2 +- pom.xml | 1 + 19 files changed, 1222 insertions(+), 1 deletion(-) create mode 100644 boomerangScope-Opal/.gitignore create mode 100644 boomerangScope-Opal/pom.xml create mode 100644 boomerangScope-Opal/src/main/scala/boomerang/scene/Main.scala create mode 100644 boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalCallGraph.scala create mode 100644 boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalClient.scala create mode 100644 boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalControlFlowGraph.scala create mode 100644 boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalDeclaredMethod.scala create mode 100644 boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalDoubleVal.scala create mode 100644 boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalField.scala create mode 100644 boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalIfStatement.scala create mode 100644 boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalInvokeExpr.scala create mode 100644 boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalMethod.scala create mode 100644 boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalStatement.scala create mode 100644 boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalStaticFieldVal.scala create mode 100644 boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalType.scala create mode 100644 boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalVal.scala create mode 100644 boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalWrappedClass.scala diff --git a/boomerangScope-Opal/.gitignore b/boomerangScope-Opal/.gitignore new file mode 100644 index 000000000..058faa1cd --- /dev/null +++ b/boomerangScope-Opal/.gitignore @@ -0,0 +1,3 @@ +/target/ +.bsp +/project/ diff --git a/boomerangScope-Opal/pom.xml b/boomerangScope-Opal/pom.xml new file mode 100644 index 000000000..25f038c92 --- /dev/null +++ b/boomerangScope-Opal/pom.xml @@ -0,0 +1,58 @@ + + + 4.0.0 + + de.fraunhofer.iem + SPDS + 3.1.2-Sparse + + + boomerangScope-Opal + + + 5.0.0 + + + + + de.fraunhofer.iem + boomerangScope + 3.1.2-Sparse + + + org.scala-lang + scala-library + ${scala.version} + + + de.opal-project + framework_2.13 + ${opal.version} + + + + + src/main/scala + + + net.alchim31.maven + scala-maven-plugin + 4.8.1 + + incremental + ${scala.version} + + + + + compile + + + + + + + + diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scene/Main.scala b/boomerangScope-Opal/src/main/scala/boomerang/scene/Main.scala new file mode 100644 index 000000000..e3eeb7b7d --- /dev/null +++ b/boomerangScope-Opal/src/main/scala/boomerang/scene/Main.scala @@ -0,0 +1,41 @@ +package boomerang.scene + +import boomerang.scene.opal.{OpalCallGraph, OpalClient} +import org.opalj.br.analyses.Project +import org.opalj.br.analyses.cg.InitialEntryPointsKey +import org.opalj.tac.cg.CHACallGraphKey + +import scala.jdk.CollectionConverters._ +import java.io.File + +object Main { + + def main(args: Array[String]): Unit = { + val project = Project(new File("C:\\Users\\Sven\\Documents\\CogniCrypt\\Opal\\IfStmt\\IfStmt.jar")) + val callGraph = project.get(CHACallGraphKey) + val entryPoints = project.get(InitialEntryPointsKey) + + OpalClient.init(project) + + val opalCallGraph = new OpalCallGraph(callGraph, entryPoints.toSet) + + val edges = opalCallGraph.getEdges + edges.forEach(x => { + val start = x.src() + val target = x.tgt() + + if (!target.isStatic) { + //val thisLocal = target.getThisLocal + } + val locals = target.getParameterLocals + + for (stmt <- target.getStatements.asScala) { + if (stmt.isAssign) { + println(stmt.getRightOp.isLengthExpr) + } + + println("--") + } + }) + } +} diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalCallGraph.scala b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalCallGraph.scala new file mode 100644 index 000000000..7565f941f --- /dev/null +++ b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalCallGraph.scala @@ -0,0 +1,50 @@ +package boomerang.scene.opal + +import boomerang.scene.CallGraph.Edge +import org.opalj.br.Method +import org.opalj.tac.cg.CallGraph + +class OpalCallGraph(callGraph: CallGraph, entryPoints: Set[Method]) extends boomerang.scene.CallGraph { + + for (reachableMethod <- callGraph.reachableMethods()) { + if (reachableMethod.method.hasSingleDefinedMethod) { + val method = reachableMethod.method.definedMethod + + if (method.body.isDefined) { + val tacCode = OpalClient.getTacForMethod(method) + val calleeMap = callGraph.calleesOf(reachableMethod.method).toMap + + for (stmt <- tacCode.stmts) { + val srcStatement = new OpalStatement(stmt, new OpalMethod(reachableMethod.method.definedMethod)) + + if (srcStatement.containsInvokeExpr()) { + val callees = calleeMap(stmt.pc) + + for (callee <- callees) { + if (callee.method.hasSingleDefinedMethod) { + val target = callee.method + + if (target.definedMethod.body.isDefined) { + val targetMethod = new OpalMethod(target.definedMethod) + + val edge = new Edge(srcStatement, targetMethod) + addEdge(edge) + // TODO Test for multiple edges + println("Added edge " + srcStatement + " -> " + targetMethod) + } + } + } + } + } + } + } + } + + for (entryPoint <- entryPoints) { + if (entryPoint.body.isDefined) { + val method = new OpalMethod(entryPoint) + + addEntryPoint(method) + } + } +} diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalClient.scala b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalClient.scala new file mode 100644 index 000000000..806df22e9 --- /dev/null +++ b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalClient.scala @@ -0,0 +1,36 @@ +package boomerang.scene.opal + +import org.opalj.br.{ClassFile, ClassHierarchy, DeclaredMethod, Field, Method, MethodDescriptor, ObjectType, ReferenceType} +import org.opalj.br.analyses.{DeclaredMethods, DeclaredMethodsKey, Project} +import org.opalj.tac.{AITACode, ComputeTACAIKey, FieldRead, FieldWriteAccessStmt, TACMethodParameter} +import org.opalj.value.ValueInformation + +object OpalClient { + + private var project: Option[Project[_]] = None + private var declaredMethods: Option[DeclaredMethods] = None + private var tacCodes: Option[Method => AITACode[TACMethodParameter, ValueInformation]] = None + + def init(p: Project[_]): Unit = { + project = Some(p) + declaredMethods = Some(p.get(DeclaredMethodsKey)) + tacCodes = Some(p.get(ComputeTACAIKey)) + } + + def getClassHierarchy: ClassHierarchy = project.get.classHierarchy + + def getClassFileForType(objectType: ObjectType): ClassFile = project.get.classFile(objectType).get + + def isApplicationClass(classFile: ClassFile): Boolean = project.get.allProjectClassFiles.toSet.contains(classFile) + + def getDeclaredMethod(method: Method): DeclaredMethod = declaredMethods.get(method) + + def getTacForMethod(method: Method): AITACode[TACMethodParameter, ValueInformation] = tacCodes.get(method) + + def resolveFieldStore(stmt: FieldWriteAccessStmt[_]): Option[Field] = stmt.resolveField(project.get) + + def resolveFieldLoad(expr: FieldRead[_]): Option[Field] = expr.resolveField(project.get) + + def resolveMethodRef(declaringClass: ReferenceType, name: String, methodDescriptor: MethodDescriptor): Option[Method] = project.get.resolveMethodReference(declaringClass, name, methodDescriptor) + +} diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalControlFlowGraph.scala b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalControlFlowGraph.scala new file mode 100644 index 000000000..d7a608ef3 --- /dev/null +++ b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalControlFlowGraph.scala @@ -0,0 +1,78 @@ +package boomerang.scene.opal + +import boomerang.scene.{ControlFlowGraph, Statement} +import com.google.common.collect.{HashMultimap, Multimap} + +import java.util + +class OpalControlFlowGraph(method: OpalMethod) extends ControlFlowGraph { + + private var cacheBuilt = false + + private val startPointCache: util.List[Statement] = new util.ArrayList[Statement] + private val endPointCache: util.List[Statement] = new util.ArrayList[Statement] + private val predsOfCache: Multimap[Statement, Statement] = HashMultimap.create() + private val succsOfCache: Multimap[Statement, Statement] = HashMultimap.create() + private val statements: util.List[Statement] = new util.ArrayList[Statement]() + + override def getStartPoints: util.Collection[Statement] = { + buildCache() + startPointCache + } + + override def getEndPoints: util.Collection[Statement] = { + buildCache() + endPointCache + } + + override def getSuccsOf(curr: Statement): util.Collection[Statement] = { + buildCache() + succsOfCache.get(curr) + } + + override def getPredsOf(curr: Statement): util.Collection[Statement] = { + buildCache() + predsOfCache.get(curr) + } + + override def getStatements: util.List[Statement] = { + buildCache() + statements + } + + private def buildCache(): Unit = { + if (cacheBuilt) return + + val tac = OpalClient.getTacForMethod(method.getDelegate) + + val headPc = tac.cfg.startBlock.startPC + val head = tac.stmts(headPc) + val headStatement = new OpalStatement(head, method) + startPointCache.add(headStatement) + + // TODO Deal with tails + val tail = tac.cfg.normalReturnNode.predecessors.tail + + for (stmt <- tac.stmts) { + val statement = new OpalStatement(stmt, method) + statements.add(statement) + + val stmtPc = tac.pcToIndex(stmt.pc) + for (successorPc <- tac.cfg.successors(stmtPc)) { + val successor = tac.stmts(successorPc) + val successorStatement = new OpalStatement(successor, method) + + succsOfCache.put(statement, successorStatement) + } + + for (predecessorPc <- tac.cfg.predecessors(stmtPc)) { + val predecessor = tac.stmts(predecessorPc) + val predecessorStatement = new OpalStatement(predecessor, method) + + predsOfCache.put(statement, predecessorStatement) + } + } + + cacheBuilt = true + } +} diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalDeclaredMethod.scala b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalDeclaredMethod.scala new file mode 100644 index 000000000..5e6645242 --- /dev/null +++ b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalDeclaredMethod.scala @@ -0,0 +1,37 @@ +package boomerang.scene.opal + +import boomerang.scene.{DeclaredMethod, InvokeExpr, WrappedClass} +import org.opalj.br.Method +import org.opalj.tac.Var + +class OpalDeclaredMethod[+V <: Var[V]](invokeExpr: InvokeExpr, delegate: Method) extends DeclaredMethod(invokeExpr) { + + override def isNative: Boolean = delegate.isNative + + override def getSubSignature: String = delegate.signature.toString + + override def getName: String = delegate.name + + override def isStatic: Boolean = delegate.isStatic + + override def isConstructor: Boolean = delegate.isStatic + + override def getSignature: String = delegate.fullyQualifiedSignature + + override def getDeclaringClass: WrappedClass = { + val declaredMethod = OpalClient.getDeclaredMethod(delegate) + new OpalWrappedClass(OpalClient.getClassFileForType(declaredMethod.declaringClassType)) + } + + override def hashCode(): Int = 31 * delegate.hashCode() + + override def equals(obj: Any): Boolean = obj match { + case other: OpalDeclaredMethod[_] => this.delegate == other.getDelegate + case _ => false + } + + override def toString: String = delegate.toJava + + def getDelegate: Method = delegate + +} diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalDoubleVal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalDoubleVal.scala new file mode 100644 index 000000000..43f1d65d2 --- /dev/null +++ b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalDoubleVal.scala @@ -0,0 +1,18 @@ +package boomerang.scene.opal + +import boomerang.scene.{Method, Val, ValWithFalseVariable} +import org.opalj.tac.{Expr, Var} + +class OpalDoubleVal[+V <: Var[V]](delegate: Expr[V], method: Method, falseVal: Val) extends OpalVal(delegate, method) with ValWithFalseVariable{ + + override def getFalseVariable: Val = falseVal + + override def hashCode(): Int = 31 * super.hashCode() + 31 * falseVal.hashCode() + + override def equals(obj: Any): Boolean = obj match { + case other: OpalDoubleVal[_] => super.equals(other) && falseVal.equals(other.getFalseVariable) + case _ => false + } + + override def toString: String = "FalseVal: " + falseVal + " from " + super.toString +} diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalField.scala b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalField.scala new file mode 100644 index 000000000..7be9ae328 --- /dev/null +++ b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalField.scala @@ -0,0 +1,20 @@ +package boomerang.scene.opal + +import boomerang.scene.Field + +class OpalField(delegate: org.opalj.br.Field) extends Field { + + override def isInnerClassField: Boolean = delegate.name.contains("$") + + override def hashCode(): Int = 31 * delegate.hashCode() + + override def equals(obj: Any): Boolean = obj match { + case other: OpalField => this.delegate == other.getDelegate + case _ => false + } + + override def toString: String = delegate.toJava + + def getDelegate: org.opalj.br.Field = delegate + +} diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalIfStatement.scala b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalIfStatement.scala new file mode 100644 index 000000000..a9ca928e9 --- /dev/null +++ b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalIfStatement.scala @@ -0,0 +1,36 @@ +package boomerang.scene.opal + +import boomerang.scene.{IfStatement, Statement, Val} +import org.opalj.tac.{DUVar, If, Var} +import org.opalj.value.ValueInformation + +class OpalIfStatement[+V <: Var[V]](delegate: If[V], method: OpalMethod) extends IfStatement { + + override def getTarget: Statement = { + val tac = OpalClient.getTacForMethod(method.getDelegate) + val target = delegate.targetStmt + + new OpalStatement[DUVar[ValueInformation]](tac.stmts(target), method) + } + + override def evaluate(otherVal: Val): IfStatement.Evaluation = IfStatement.Evaluation.UNKOWN + + override def uses(otherVal: Val): Boolean = { + val left = new OpalVal(delegate.left, method) + val right = new OpalVal(delegate.right, method) + + otherVal.equals(left) || otherVal.equals(right) + } + + override def hashCode(): Int = 31 * delegate.hashCode() + + override def equals(obj: Any): Boolean = obj match { + case other: OpalStatement[_] => this.delegate == other.getDelegate + case _ => false + } + + override def toString: String = delegate.toString() + + def getDelegate: If[V] = delegate + +} diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalInvokeExpr.scala b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalInvokeExpr.scala new file mode 100644 index 000000000..cb8639e40 --- /dev/null +++ b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalInvokeExpr.scala @@ -0,0 +1,85 @@ +package boomerang.scene.opal + +import boomerang.scene.{DeclaredMethod, InvokeExpr, Val} +import org.opalj.tac.{FunctionCall, InstanceFunctionCall, InstanceMethodCall, MethodCall, NonVirtualFunctionCall, NonVirtualMethodCall, Var} + +import java.util + +class OpalMethodInvokeExpr[+V <: Var[V]](delegate: MethodCall[V], method: OpalMethod) extends InvokeExpr { + + override def getArg(index: Int): Val = getArgs.get(index) + + override def getArgs: util.List[Val] = { + val result = new util.ArrayList[Val] + + for (param <- delegate.params) { + result.add(new OpalVal[V](param, method)) + } + + result + } + + override def isInstanceInvokeExpr: Boolean = delegate.isInstanceOf[InstanceMethodCall[_]] + + override def getBase: Val = { + if (isInstanceInvokeExpr) { + return new OpalVal[V](delegate.asInstanceMethodCall.receiver, method) + } + + throw new RuntimeException("Method call is not an instance invoke expression") + } + + override def getMethod: DeclaredMethod = { + val resolvedMethod = OpalClient.resolveMethodRef(delegate.declaringClass, delegate.name, delegate.descriptor) + + if (resolvedMethod.isDefined) { + return new OpalDeclaredMethod[V](this, resolvedMethod.get) + } + + throw new RuntimeException("Cannot resolve method " + delegate.name + " from invoke expression") + } + + override def isSpecialInvokeExpr: Boolean = delegate.astID == NonVirtualMethodCall.ASTID + + override def isStaticInvokeExpr: Boolean = delegate.isStaticMethodCall +} + +class OpalFunctionInvokeExpr[+V <: Var[V]](delegate: FunctionCall[V], method: OpalMethod) extends InvokeExpr { + + override def getArg(index: Int): Val = getArgs.get(index) + + override def getArgs: util.List[Val] = { + val result = new util.ArrayList[Val] + + for (param <- delegate.params) { + result.add(new OpalVal[V](param, method)) + } + + result + } + + override def isInstanceInvokeExpr: Boolean = delegate.isInstanceOf[InstanceFunctionCall[_]] + + override def getBase: Val = { + if (isInstanceInvokeExpr) { + return new OpalVal[V](delegate.asInstanceFunctionCall.receiver, method) + } + + throw new RuntimeException("Function call is not an instance invoke expression") + } + + override def getMethod: DeclaredMethod = { + val resolvedMethod = OpalClient.resolveMethodRef(delegate.declaringClass, delegate.name, delegate.descriptor) + + if (resolvedMethod.isDefined) { + new OpalDeclaredMethod[V](this, resolvedMethod.get) + } + + throw new RuntimeException("Cannot resolve method " + delegate.name + " from invoke expression") + } + + override def isSpecialInvokeExpr: Boolean = delegate.astID == NonVirtualFunctionCall.ASTID + + override def isStaticInvokeExpr: Boolean = delegate.isStaticFunctionCall + +} diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalMethod.scala b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalMethod.scala new file mode 100644 index 000000000..ea3c52d5e --- /dev/null +++ b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalMethod.scala @@ -0,0 +1,174 @@ +package boomerang.scene.opal + +import boomerang.scene.{ControlFlowGraph, Method, Statement, Val, WrappedClass} +import org.opalj.tac.{DUVar, InstanceFunctionCall, InstanceMethodCall, UVar} +import org.opalj.value.ValueInformation + +import scala.jdk.CollectionConverters._ +import java.util + +class OpalMethod(delegate: org.opalj.br.Method) extends Method { + + if (delegate.body.isEmpty) { + throw new RuntimeException("Trying to build Opal method without body present") + } + + private var localCache: Option[util.Set[Val]] = None + private var parameterLocalCache: Option[util.List[Val]] = None + + private val cfg = new OpalControlFlowGraph(this) + + override def isStaticInitializer: Boolean = delegate.isStaticInitializer + + override def isParameterLocal(value: Val): Boolean = { + // if (value.isStatic) return false + + val parameterLocals = getParameterLocals + parameterLocals.contains(value) + } + + override def isThisLocal(fact: Val): Boolean = { + if (isStatic) return false + + val thisLocal = isThisLocalDefined + if (thisLocal.isDefined) { + return thisLocal.get.equals(fact) + } + + // TODO This might not be enough + false + } + + override def getThisLocal: Val = { + if (!isStatic) { + val thisLocal = isThisLocalDefined + if (thisLocal.isDefined) { + return thisLocal.get + } + + // TODO Replace corresponding places + throw new RuntimeException("this local is not used in method. Use #isThisLocal for comparisons") + } + + throw new RuntimeException("Static method does not have a 'this' local") + } + + private def isThisLocalDefined: Option[Val] = { + val locals = getLocals + for (local <- locals.asScala) { + val opalVal = local.asInstanceOf[OpalVal[DUVar[ValueInformation]]] + val valDelegate = opalVal.getDelegate + + if (valDelegate.isInstanceOf[UVar[_]]) { + if (valDelegate.asVar.definedBy.head == -1) { + return Some(local) + } + } + } + + None + } + + override def getLocals: util.Set[Val] = { + if (localCache.isEmpty) { + localCache = Some(new util.HashSet[Val]()) + + val tac = OpalClient.getTacForMethod(delegate) + + for (stmt <- tac.stmts) { + if (stmt.isMethodCall) { + // Extract the base + if (stmt.isInstanceOf[InstanceMethodCall[_]]) { + val opalVal = new OpalVal[DUVar[ValueInformation]](stmt.asInstanceMethodCall.receiver, this) + localCache.get.add(opalVal) + } + + // Parameters of method calls + for (param <- stmt.asMethodCall.params) { + if (param.isVar) { + localCache.get.add(new OpalVal[DUVar[ValueInformation]](param.asVar, this)) + } + } + } + + if (stmt.isAssignment) { + // Target variable + val targetVar = stmt.asAssignment.targetVar + localCache.get.add(new OpalVal[DUVar[ValueInformation]](targetVar, this)) + + if (stmt.asAssignment.expr.isFunctionCall) { + // Extract the base + if (stmt.asAssignment.expr.isInstanceOf[InstanceFunctionCall[_]]) { + val opalVal = new OpalVal[DUVar[ValueInformation]](stmt.asAssignment.expr.asInstanceFunctionCall.receiver, this) + localCache.get.add(opalVal) + } + + // Parameters of function call + for (param <- stmt.asAssignment.expr.asFunctionCall.params) { + if (param.isVar) { + localCache.get.add(new OpalVal[DUVar[ValueInformation]](param.asVar, this)) + } + } + } + } + } + } + + localCache.get + } + + override def getParameterLocals: util.List[Val] = { + if (parameterLocalCache.isEmpty) { + parameterLocalCache = Some(new util.ArrayList[Val]()) + + val locals = getLocals + for (local <- locals.asScala) { + if (local.isLocal) { + val opalVal = local.asInstanceOf[OpalVal[DUVar[ValueInformation]]] + val valDelegate = opalVal.getDelegate + + if (valDelegate.isInstanceOf[UVar[_]]) { + if (valDelegate.asVar.definedBy.head < 0) { + parameterLocalCache.get.add(local) + } + } + } + } + } + + parameterLocalCache.get + } + + override def isStatic: Boolean = delegate.isStatic + + override def isNative: Boolean = delegate.isNative + + override def getStatements: util.List[Statement] = cfg.getStatements + + override def getDeclaringClass: WrappedClass = { + val declaredMethod = OpalClient.getDeclaredMethod(delegate) + new OpalWrappedClass(OpalClient.getClassFileForType(declaredMethod.declaringClassType)) + } + + override def getControlFlowGraph: ControlFlowGraph = cfg + + override def getSubSignature: String = delegate.signature.toString + + override def getName: String = delegate.name + + override def isConstructor: Boolean = delegate.isConstructor + + override def isPublic: Boolean = delegate.isPublic + + override def hashCode(): Int = 31 + delegate.hashCode() + + override def equals(obj: Any): Boolean = obj match { + case other: OpalMethod => this.delegate == other.getDelegate + case _ => false + } + + override def toString: String = delegate.toJava + + def getDelegate: org.opalj.br.Method = delegate + +} diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalStatement.scala b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalStatement.scala new file mode 100644 index 000000000..e814229ce --- /dev/null +++ b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalStatement.scala @@ -0,0 +1,288 @@ +package boomerang.scene.opal + +import boomerang.scene.{Field, IfStatement, InvokeExpr, Pair, Statement, StaticFieldVal, Val} +import org.opalj.tac.{PrimitiveTypecastExpr, Stmt, Var} + +import java.util + +class OpalStatement[+V <: Var[V]](delegate: Stmt[V], m: OpalMethod) extends Statement(m) { + + override def containsStaticFieldAccess(): Boolean = isStaticFieldLoad || isStaticFieldStore + + override def containsInvokeExpr(): Boolean = isAssign && delegate.asAssignment.expr.isFunctionCall || delegate.isMethodCall + + override def getWrittenField: Field = { + if (isFieldStore) { + val resolvedField = OpalClient.resolveFieldStore(delegate.asPutField) + return new OpalField(resolvedField.get) + } + + if (isStaticFieldStore) { + val resolvedField = OpalClient.resolveFieldStore(delegate.asPutStatic) + return new OpalField(resolvedField.get) + } + + if (isArrayStore) { + // TODO + //val resolvedField = OpalClient.resolveFieldStore(delegate.asArrayStore) + //return new OpalField(resolvedField.get) + } + + throw new RuntimeException("Statement is not a field store operation") + } + + override def isFieldWriteWithBase(base: Val): Boolean = { + if (isAssign && isFieldStore) { + return getFieldStore.getX.equals(base) + } + + if (isAssign && isArrayStore) { + return getArrayBase.getX.equals(base) + } + + false + } + + override def getLoadedField: Field = { + // TODO Also array? + if (isFieldLoad) { + val resolvedField = OpalClient.resolveFieldLoad(delegate.asAssignment.expr.asFieldRead) + return new OpalField(resolvedField.get) + } + + throw new RuntimeException("Statement is not a field load operation") + } + + override def isFieldLoadWithBase(base: Val): Boolean = { + // TODO Also array? + if (isAssign && isFieldLoad) { + return getFieldLoad.getX.equals(base) + } + + false + } + + override def isAssign: Boolean = delegate.isAssignment + + override def getLeftOp: Val = { + if (isAssign) { + return new OpalVal[V](delegate.asAssignment.targetVar, m) + } + + throw new RuntimeException("Statement is not an assignment") + } + + override def getRightOp: Val = { + if (isAssign) { + return new OpalVal[V](delegate.asAssignment.expr, m) + } + + throw new RuntimeException("Statement is not an assignment") + } + + override def isInstanceOfStatement(fact: Val): Boolean = { + if (isAssign) { + if (getRightOp.isInstanceOfExpr) { + val insOf = getRightOp.getInstanceOfOp + + return insOf.equals(fact) + } + } + + false + } + + override def isCast: Boolean = { + // Primitive type casts + if (isAssign) { + val assignExpr = delegate.asAssignment.expr + + if (assignExpr.astID == PrimitiveTypecastExpr.ASTID) { + return true + } + } + + // Class casts + delegate.isCheckcast + } + + override def isPhiStatement: Boolean = false + + override def getInvokeExpr: InvokeExpr = { + if (containsInvokeExpr()) { + if (isAssign) { + return new OpalFunctionInvokeExpr[V](delegate.asAssignment.expr.asFunctionCall, m) + } else { + return new OpalMethodInvokeExpr[V](delegate.asMethodCall, m) + } + } + + throw new RuntimeException("Statement does not contain an invoke expression") + } + + override def isReturnStmt: Boolean = delegate.isReturnValue + + override def isThrowStmt: Boolean = delegate.isThrow + + override def isIfStmt: Boolean = delegate.isIf + + override def getIfStmt: IfStatement = { + if (isIfStmt) { + return new OpalIfStatement[V](delegate.asIf, m) + } + + throw new RuntimeException("Statement is not an if-statement") + } + + override def getReturnOp: Val = { + if (isReturnStmt) { + return new OpalVal[V](delegate.asReturnValue.expr, m) + } + + throw new RuntimeException("Statement is not a return statement") + } + + override def isMultiArrayAllocation: Boolean = ??? + + override def isStringAllocation: Boolean = { + if (isAssign) { + return delegate.asAssignment.expr.isStringConst + } + + throw new RuntimeException("Statement is not an allocation statement") + } + + override def isFieldStore: Boolean = { + if (!delegate.isPutField) { + return false + } + + val field = OpalClient.resolveFieldStore(delegate.asPutField) + field.isDefined + } + + override def isArrayStore: Boolean = delegate.isArrayStore + + override def isArrayLoad: Boolean = { + if (!isAssign) { + return false + } + + delegate.asAssignment.expr.isArrayLoad + } + + override def isFieldLoad: Boolean = { + if (!delegate.isAssignment) { + return false + } + + if (!delegate.asAssignment.expr.isGetField) { + return false + } + + val field = OpalClient.resolveFieldLoad(delegate.asAssignment.expr.asGetField) + field.isDefined + } + + override def isIdentityStmt: Boolean = false + + override def getFieldStore: Pair[Val, Field] = { + if (isFieldStore) { + val resolvedField = OpalClient.resolveFieldStore(delegate.asPutField).get + val ref = delegate.asPutField.objRef + + return new Pair(new OpalVal[V](ref, m), new OpalField(resolvedField)) + } + + throw new RuntimeException("Statement is not a field store operation") + } + + override def getFieldLoad: Pair[Val, Field] = { + if (isFieldLoad) { + val resolvedField = OpalClient.resolveFieldLoad(delegate.asAssignment.expr.asFieldRead).get + val ref = delegate.asAssignment.expr.asGetField.objRef + + return new Pair(new OpalVal[V](ref, m), new OpalField(resolvedField)) + } + + throw new RuntimeException("Statement is not a field load operation") + } + + override def isStaticFieldLoad: Boolean = { + if (!delegate.isAssignment) { + return false + } + + if (!delegate.asAssignment.expr.isGetStatic) { + return false + } + + val field = OpalClient.resolveFieldLoad(delegate.asAssignment.expr.asGetStatic) + field.isDefined + } + + override def isStaticFieldStore: Boolean = { + if (!delegate.isPutStatic) { + return false + } + + val field = OpalClient.resolveFieldStore(delegate.asPutStatic) + field.isDefined + } + + override def getStaticField: StaticFieldVal = { + if (isStaticFieldLoad) { + val resolvedField = OpalClient.resolveFieldLoad(delegate.asAssignment.expr.asGetStatic) + val staticField = new OpalField(resolvedField.get) + + return new OpalStaticFieldVal(staticField, m) + } + + if (isStaticFieldStore) { + val resolvedField = OpalClient.resolveFieldStore(delegate.asPutStatic) + val staticField = new OpalField(resolvedField.get) + + return new OpalStaticFieldVal(staticField, m) + } + + throw new RuntimeException("Statement is neither a static field load or store operation") + } + + override def killAtIfStmt(fact: Val, successor: Statement): Boolean = false + + override def getPhiVals: util.Collection[Val] = throw new RuntimeException("Not supported") + + override def getArrayBase: Pair[Val, Integer] = { + if (isArrayLoad) { + val rightOp = getRightOp + return rightOp.getArrayBase + } + + if (isArrayLoad) { + // TODO + } + + throw new RuntimeException("Statement has no array base") + } + + override def getStartLineNumber: Int = m.getDelegate.body.get.lineNumber(delegate.pc).getOrElse(-1) + + override def getStartColumnNumber: Int = getStartLineNumber() + + override def getEndLineNumber: Int = getStartLineNumber() + + override def getEndColumnNumber: Int = getStartLineNumber() + + override def isCatchStmt: Boolean = delegate.isCaughtException + + override def hashCode(): Int = 31 + delegate.hashCode() + + override def equals(obj: Any): Boolean = obj match { + case other: OpalStatement[_] => this.delegate == other.getDelegate + case _ => false + } + + override def toString: String = delegate.toString + + def getDelegate: Stmt[V] = delegate +} diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalStaticFieldVal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalStaticFieldVal.scala new file mode 100644 index 000000000..064013108 --- /dev/null +++ b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalStaticFieldVal.scala @@ -0,0 +1,64 @@ +package boomerang.scene.opal + +import boomerang.scene.{ControlFlowGraph, Field, Method, Pair, StaticFieldVal, Type, Val} + +class OpalStaticFieldVal(field: OpalField, method: Method, unbalanced: ControlFlowGraph.Edge = null) extends StaticFieldVal(method, unbalanced) { + + override def field(): Field = field + + override def asUnbalanced(stmt: ControlFlowGraph.Edge): Val = new OpalStaticFieldVal(field, method, stmt) + + override def getType: Type = new OpalType(field.getDelegate.fieldType) + + override def isStatic: Boolean = true + + override def isNewExpr: Boolean = false + + override def getNewExprType: Type = throw new RuntimeException("Static field is not a new expression") + + override def isLocal: Boolean = false + + override def isArrayAllocationVal: Boolean = false + + override def isNull: Boolean = false + + override def isStringConstant: Boolean = false + + override def getStringValue: String = throw new RuntimeException("Static field is not a string constant") + + override def isStringBufferOrBuilder: Boolean = false + + override def isThrowableAllocationType: Boolean = false + + override def isCast: Boolean = false + + override def getCastOp: Val = throw new RuntimeException("Static field is not a cast operation") + + override def isArrayRef: Boolean = false + + override def isInstanceOfExpr: Boolean = false + + override def getInstanceOfOp: Val = throw new RuntimeException("Static field is not an instance of operation") + + override def isLengthExpr: Boolean = false + + override def getLengthOp: Val = throw new RuntimeException("Static field is not a length operation") + + override def isIntConstant: Boolean = false + + override def isClassConstant: Boolean = false + + override def getClassConstantType: Type = throw new RuntimeException("Static field has not a class constant type") + + override def withNewMethod(callee: Method): Val = new OpalStaticFieldVal(field, callee) + + override def isLongConstant: Boolean = false + + override def getIntValue: Int = throw new RuntimeException("Static field is not an int value") + + override def getLongValue: Long = throw new RuntimeException("Static field is not a long value") + + override def getArrayBase: Pair[Val, Integer] = throw new RuntimeException("Static field has no array base") + + override def getVariableName: String = field.toString +} diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalType.scala b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalType.scala new file mode 100644 index 000000000..a30979659 --- /dev/null +++ b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalType.scala @@ -0,0 +1,46 @@ +package boomerang.scene.opal +import boomerang.scene.{AllocVal, Type, Val, WrappedClass} +import org.opalj.br.ObjectType + +class OpalType(delegate: org.opalj.br.Type) extends Type { + + override def isNullType: Boolean = false + + override def isRefType: Boolean = delegate.isReferenceType + + override def isArrayType: Boolean = delegate.isArrayType + + override def getArrayBaseType: Type = new OpalType(delegate.asArrayType) + + override def getWrappedClass: WrappedClass = new OpalWrappedClass(OpalClient.getClassFileForType(delegate.asObjectType)) + + override def doesCastFail(targetValType: Type, target: Val): Boolean = { + if (!isRefType || !targetValType.isRefType) { + return false + } + + val sourceType = delegate.asReferenceType + val targetType = targetValType.asInstanceOf[OpalType].getDelegate.asReferenceType + + target match { + case allocVal: AllocVal if allocVal.getAllocVal.isNewExpr => OpalClient.getClassHierarchy.isSubtypeOf(sourceType, targetType) + + case _ => OpalClient.getClassHierarchy.isSubtypeOf(sourceType, targetType) + } + } + + override def isSubtypeOf(otherType: String): Boolean = OpalClient.getClassHierarchy.isSubtypeOf(delegate.asObjectType, ObjectType(otherType)) + + override def isBooleanType: Boolean = delegate.isBooleanType + + override def hashCode(): Int = 31 * delegate.hashCode() + + override def equals(obj: Any): Boolean = obj match { + case other: OpalType => this.delegate == other.getDelegate + case _ => false + } + + override def toString: String = delegate.toJava + + def getDelegate: org.opalj.br.Type = delegate +} diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalVal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalVal.scala new file mode 100644 index 000000000..03100cd08 --- /dev/null +++ b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalVal.scala @@ -0,0 +1,138 @@ +package boomerang.scene.opal + +import boomerang.scene.{ControlFlowGraph, Method, Pair, Type, Val} +import org.opalj.br.ReferenceType +import org.opalj.tac.{ArrayLength, Expr, InstanceOf, PrimitiveTypecastExpr, Var} + +class OpalVal[+V <: Var[V]](delegate: Expr[V], method: Method, edge: ControlFlowGraph.Edge = null) extends Val(method, edge) { + + override def getType: Type = ??? + + override def isStatic: Boolean = false + + override def isNewExpr: Boolean = delegate.isNew + + override def getNewExprType: Type = { + if (isNewExpr) { + return new OpalType(delegate.asNew.tpe) + } + + throw new RuntimeException("Value is not a new expression") + } + + override def asUnbalanced(stmt: ControlFlowGraph.Edge): Val = new OpalVal[V](delegate, method, stmt) + + override def isLocal: Boolean = delegate.isVar + + override def isArrayAllocationVal: Boolean = delegate.isNewArray + + override def isNull: Boolean = delegate.isNullExpr + + override def isStringConstant: Boolean = delegate.isStringConst + + override def getStringValue: String = { + if (isStringConstant) { + return delegate.asStringConst.value + } + + throw new RuntimeException("Value is not a String constant") + } + + override def isStringBufferOrBuilder: Boolean = { + val thisType = getType + + thisType.toString.equals("java.lang.String") || thisType.toString.equals("java.lang.StringBuilder") || thisType.toString.equals("java.lang.StringBuffer") + } + + override def isThrowableAllocationType: Boolean = { + val thisType = getType + + if (!thisType.isRefType) { + return false + } + + val opalType = thisType.asInstanceOf[OpalType].getDelegate + OpalClient.getClassHierarchy.isSubtypeOf(opalType.asReferenceType, ReferenceType("java/lang/Throwable")) + } + + override def isCast: Boolean = delegate.astID == PrimitiveTypecastExpr.ASTID + + override def getCastOp: Val = { + if (isCast) { + return new OpalVal[V](delegate.asPrimitiveTypeCastExpr.operand, method) + } + + throw new RuntimeException("Expression is not a cast expression") + } + + override def isArrayRef: Boolean = ??? + + override def isInstanceOfExpr: Boolean = delegate.astID == InstanceOf.ASTID + + override def getInstanceOfOp: Val = { + if (isInstanceOfExpr) { + return new OpalVal[V](delegate.asInstanceOf.value, method) + } + + throw new RuntimeException("Expression is not an instanceOf expression") + } + + override def isLengthExpr: Boolean = delegate.astID == ArrayLength.ASTID + + override def getLengthOp: Val = { + if (isLengthExpr) { + return new OpalVal[V](delegate.asArrayLength, method) + } + + throw new RuntimeException("Value is not a length expression") + } + + override def isIntConstant: Boolean = delegate.isIntConst + + override def isClassConstant: Boolean = delegate.isClassConst + + override def getClassConstantType: Type = { + if (isClassConstant) { + return new OpalType(delegate.asClassConst.value) + } + + throw new RuntimeException("Value is not a class constant") + } + + override def withNewMethod(callee: Method): Val = new OpalVal[V](delegate, callee) + + override def withSecondVal(secondVal: Val) = new OpalDoubleVal[V](delegate, method, secondVal) + + override def isLongConstant: Boolean = delegate.isLongConst + + override def getIntValue: Int = { + if (isIntConstant) { + return delegate.asIntConst.value + } + + throw new RuntimeException("Value is not an integer constant") + } + + override def getLongValue: Long = { + if (isLongConstant) { + return delegate.asLongConst.value + } + + throw new RuntimeException("Value is not a long constant") + } + + override def getArrayBase: Pair[Val, Integer] = ??? + + override def getVariableName: String = delegate.toString + + override def hashCode(): Int = 31 * delegate.hashCode() + + override def equals(obj: Any): Boolean = obj match { + case other: OpalVal[_] => this.delegate == other.getDelegate + case _ => false + } + + override def toString: String = delegate.toString + + def getDelegate: Expr[V] = delegate +} diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalWrappedClass.scala b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalWrappedClass.scala new file mode 100644 index 000000000..73814f49c --- /dev/null +++ b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalWrappedClass.scala @@ -0,0 +1,48 @@ +package boomerang.scene.opal + +import boomerang.scene.{Method, Type, WrappedClass} +import org.opalj.br.ClassFile + +import java.util + +class OpalWrappedClass(delegate: ClassFile) extends WrappedClass { + + override def getMethods: util.Set[Method] = { + val methods = new util.HashSet[Method] + + for (method <- delegate.methods) { + if (method.body.isDefined) { + methods.add(new OpalMethod(method)) + } + } + + methods + } + + override def hasSuperclass: Boolean = delegate.superclassType.isDefined + + override def getSuperclass: WrappedClass = { + val superClass = OpalClient.getClassFileForType(delegate.superclassType.get) + + new OpalWrappedClass(superClass) + } + + override def getType: Type = new OpalType(delegate.thisType) + + override def isApplicationClass: Boolean = OpalClient.isApplicationClass(delegate) + + override def getFullyQualifiedName: String = delegate.classSignature.get.toString() + + override def getName: String = delegate.classSignature.get.toString() + + override def hashCode(): Int = 31 * delegate.hashCode() + + override def equals(obj: Any): Boolean = obj match { + case other: OpalWrappedClass => this.delegate == other.getDelegate + case _ => false + } + + override def toString: String = delegate.toString() + + override def getDelegate: AnyRef = delegate +} diff --git a/boomerangScope/src/main/java/boomerang/scene/jimple/JimpleStaticFieldVal.java b/boomerangScope/src/main/java/boomerang/scene/jimple/JimpleStaticFieldVal.java index 4fc6aef2c..b3fb82529 100644 --- a/boomerangScope/src/main/java/boomerang/scene/jimple/JimpleStaticFieldVal.java +++ b/boomerangScope/src/main/java/boomerang/scene/jimple/JimpleStaticFieldVal.java @@ -43,7 +43,7 @@ public String toString() { public Field field() { return field; - }; + } @Override public Val asUnbalanced(Edge stmt) { diff --git a/pom.xml b/pom.xml index 965e3c4a9..a42890a40 100644 --- a/pom.xml +++ b/pom.xml @@ -51,6 +51,7 @@ boomerangScope boomerangScope-WALA SparseBoomerangCorrectness + boomerangScope-Opal UTF-8 From 465e42b350a30fb2b530e36e694ecaeee4d2cf1e Mon Sep 17 00:00:00 2001 From: Sven Meyer Date: Fri, 27 Sep 2024 20:06:44 +0200 Subject: [PATCH 03/61] Remove semicola to avoid wrong formatting --- .../java/sync/pds/solver/OneWeightFunctions.java | 3 ++- .../src/main/java/sync/pds/solver/SyncPDSSolver.java | 12 ++++++------ WPDS/src/main/java/wpds/impl/WeightedPAutomaton.java | 4 ++-- .../main/java/wpds/impl/WeightedPushdownSystem.java | 3 ++- .../src/main/java/boomerang/WeightedBoomerang.java | 2 +- .../main/java/boomerang/WeightedForwardQuery.java | 3 ++- .../java/boomerang/callgraph/BoomerangResolver.java | 6 +++--- .../java/boomerang/debugger/ConsoleDebugger.java | 2 +- .../boomerang/solver/BackwardBoomerangSolver.java | 3 ++- .../src/test/java/test/cases/fields/ReadPOITest.java | 3 ++- .../test/java/test/cases/fields/WritePOITest.java | 2 +- boomerangScope-Opal/pom.xml | 1 + .../src/main/java/typestate/TransitionFunction.java | 2 +- .../impl/statemachines/OutputStreamStateMachine.java | 2 +- .../src/test/java/test/IDEALTestingFramework.java | 2 +- .../src/test/java/typestate/test/helper/File.java | 2 +- pom.xml | 2 +- 17 files changed, 30 insertions(+), 24 deletions(-) diff --git a/SynchronizedPDS/src/main/java/sync/pds/solver/OneWeightFunctions.java b/SynchronizedPDS/src/main/java/sync/pds/solver/OneWeightFunctions.java index 0b7551ed6..d73e270a8 100644 --- a/SynchronizedPDS/src/main/java/sync/pds/solver/OneWeightFunctions.java +++ b/SynchronizedPDS/src/main/java/sync/pds/solver/OneWeightFunctions.java @@ -41,4 +41,5 @@ public W pop(Node curr) { public W getOne() { return one; } -}; + +} diff --git a/SynchronizedPDS/src/main/java/sync/pds/solver/SyncPDSSolver.java b/SynchronizedPDS/src/main/java/sync/pds/solver/SyncPDSSolver.java index 4058d32ad..827728fac 100644 --- a/SynchronizedPDS/src/main/java/sync/pds/solver/SyncPDSSolver.java +++ b/SynchronizedPDS/src/main/java/sync/pds/solver/SyncPDSSolver.java @@ -62,13 +62,13 @@ public enum PDSSystem { new WeightedPushdownSystem, W>() { public String toString() { return "Call " + SyncPDSSolver.this.toString(); - }; + } }; protected final WeightedPushdownSystem>, W> fieldPDS = new WeightedPushdownSystem>, W>() { public String toString() { return "Field " + SyncPDSSolver.this.toString(); - }; + } }; private final Set> reachedStates = Sets.newHashSet(); private final Set> callingContextReachable = Sets.newHashSet(); @@ -112,7 +112,7 @@ public Field epsilon() { @Override public boolean nested() { return useFieldSummaries; - }; + } @Override public W getOne() { @@ -129,7 +129,7 @@ public boolean addWeightForTransition( if (preventFieldTransitionAdd(trans, weight)) return false; logger.trace("Adding field transition {} with weight {}", trans, weight); return super.addWeightForTransition(trans, weight); - }; + } @Override public boolean isGeneratedState(INode> d) { @@ -152,7 +152,7 @@ public Stmt epsilon() { @Override public boolean nested() { return useCallSummaries; - }; + } @Override public W getOne() { @@ -163,7 +163,7 @@ public boolean addWeightForTransition(Transition> trans, W wei if (preventCallTransitionAdd(trans, weight)) return false; logger.trace("Adding call transition {} with weight {}", trans, weight); return super.addWeightForTransition(trans, weight); - }; + } @Override public boolean isGeneratedState(INode d) { diff --git a/WPDS/src/main/java/wpds/impl/WeightedPAutomaton.java b/WPDS/src/main/java/wpds/impl/WeightedPAutomaton.java index 6b3709802..6c16a79df 100644 --- a/WPDS/src/main/java/wpds/impl/WeightedPAutomaton.java +++ b/WPDS/src/main/java/wpds/impl/WeightedPAutomaton.java @@ -283,11 +283,11 @@ public Set> getEdges() { } } return trans; - }; + } public Set getNodes() { return getStates(); - }; + } public boolean addWeightForTransition(Transition trans, W weight) { if (weight == null) throw new IllegalArgumentException("Weight must not be null!"); diff --git a/WPDS/src/main/java/wpds/impl/WeightedPushdownSystem.java b/WPDS/src/main/java/wpds/impl/WeightedPushdownSystem.java index 6494a3db7..741ebe2a5 100644 --- a/WPDS/src/main/java/wpds/impl/WeightedPushdownSystem.java +++ b/WPDS/src/main/java/wpds/impl/WeightedPushdownSystem.java @@ -144,7 +144,8 @@ public void putSummaryAutomaton(D target, WeightedPAutomaton aut) { @Override public WeightedPAutomaton getSummaryAutomaton(D target) { return summaries.getSummaryAutomaton(target); - }; + } + }.poststar(this, initialAutomaton); } diff --git a/boomerangPDS/src/main/java/boomerang/WeightedBoomerang.java b/boomerangPDS/src/main/java/boomerang/WeightedBoomerang.java index 02f1c616b..d79b25b26 100644 --- a/boomerangPDS/src/main/java/boomerang/WeightedBoomerang.java +++ b/boomerangPDS/src/main/java/boomerang/WeightedBoomerang.java @@ -1238,7 +1238,7 @@ public void execute(final ForwardQuery baseAllocation, final Query flowAllocatio new ExecuteImportFieldStmtPOI(baseSolver, flowSolver, FieldWritePOI.this) { public void activate(INode> start) { activateAllPois(new SolverPair(flowSolver, baseSolver), start); - }; + } }; registerActivationListener(new SolverPair(flowSolver, baseSolver), exec); exec.solve(); diff --git a/boomerangPDS/src/main/java/boomerang/WeightedForwardQuery.java b/boomerangPDS/src/main/java/boomerang/WeightedForwardQuery.java index 8e3970a22..0c5e8e47a 100644 --- a/boomerangPDS/src/main/java/boomerang/WeightedForwardQuery.java +++ b/boomerangPDS/src/main/java/boomerang/WeightedForwardQuery.java @@ -26,5 +26,6 @@ public WeightedForwardQuery(Edge stmt, Val variable, W weight) { public W weight() { return weight; - }; + } + } diff --git a/boomerangPDS/src/main/java/boomerang/callgraph/BoomerangResolver.java b/boomerangPDS/src/main/java/boomerang/callgraph/BoomerangResolver.java index bda09b737..7d1b93740 100644 --- a/boomerangPDS/src/main/java/boomerang/callgraph/BoomerangResolver.java +++ b/boomerangPDS/src/main/java/boomerang/callgraph/BoomerangResolver.java @@ -41,7 +41,7 @@ public class BoomerangResolver implements ICallerCalleeResolutionStrategy { public enum NoCalleeFoundFallbackOptions { PRECOMPUTED, BYPASS - }; + } private static final String THREAD_CLASS = "java.lang.Thread"; private static final String THREAD_START_SIGNATURE = ""; @@ -53,7 +53,7 @@ public enum NoCalleeFoundFallbackOptions { private CallGraph precomputedCallGraph; private WeightedBoomerang solver; private Set queriedInvokeExprAndAllocationSitesFound = Sets.newHashSet(); - private Set queriedInvokeExpr = Sets.newHashSet();; + private Set queriedInvokeExpr = Sets.newHashSet(); public BoomerangResolver(CallGraph cg, DataFlowScope scope) { this.solver = new Boomerang(cg, scope); @@ -241,7 +241,7 @@ protected void allocationSiteFound( } } } - }; + } }); } } diff --git a/boomerangPDS/src/main/java/boomerang/debugger/ConsoleDebugger.java b/boomerangPDS/src/main/java/boomerang/debugger/ConsoleDebugger.java index 042aca4ba..290d91dc8 100644 --- a/boomerangPDS/src/main/java/boomerang/debugger/ConsoleDebugger.java +++ b/boomerangPDS/src/main/java/boomerang/debugger/ConsoleDebugger.java @@ -27,5 +27,5 @@ public void done( // } queryToSolvers.get(q).debugOutput(); } - }; + } } diff --git a/boomerangPDS/src/main/java/boomerang/solver/BackwardBoomerangSolver.java b/boomerangPDS/src/main/java/boomerang/solver/BackwardBoomerangSolver.java index f6d5fdcec..d8dd1ef62 100644 --- a/boomerangPDS/src/main/java/boomerang/solver/BackwardBoomerangSolver.java +++ b/boomerangPDS/src/main/java/boomerang/solver/BackwardBoomerangSolver.java @@ -140,7 +140,8 @@ private void byPassFlowAtCallsite(Method caller, Node curr) { .getPredsOf(curr.stmt().getStart())) { Set res = - flowFunction.callToReturnFlow(new Edge(returnSite, curr.stmt().getStart()), curr.fact()) + flowFunction + .callToReturnFlow(new Edge(returnSite, curr.stmt().getStart()), curr.fact()) .stream() .collect(Collectors.toSet()); for (State s : res) { diff --git a/boomerangPDS/src/test/java/test/cases/fields/ReadPOITest.java b/boomerangPDS/src/test/java/test/cases/fields/ReadPOITest.java index 47968786a..3d2e946f7 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/ReadPOITest.java +++ b/boomerangPDS/src/test/java/test/cases/fields/ReadPOITest.java @@ -141,5 +141,6 @@ private static class Node { private static class AllocNode extends Node implements AllocatedObject {} - private static class Alloc implements AllocatedObject {}; + private static class Alloc implements AllocatedObject {} + } diff --git a/boomerangPDS/src/test/java/test/cases/fields/WritePOITest.java b/boomerangPDS/src/test/java/test/cases/fields/WritePOITest.java index 30720a3cc..87a8de17f 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/WritePOITest.java +++ b/boomerangPDS/src/test/java/test/cases/fields/WritePOITest.java @@ -273,7 +273,7 @@ public static class ObjectWithField { Object field = null; } - public static class Alloc implements AllocatedObject {}; + public static class Alloc implements AllocatedObject {} private static class A1 { B1 b = new B1(); diff --git a/boomerangScope-Opal/pom.xml b/boomerangScope-Opal/pom.xml index 25f038c92..7f1473d68 100644 --- a/boomerangScope-Opal/pom.xml +++ b/boomerangScope-Opal/pom.xml @@ -13,6 +13,7 @@ 5.0.0 + 2.13.14 diff --git a/idealPDS/src/main/java/typestate/TransitionFunction.java b/idealPDS/src/main/java/typestate/TransitionFunction.java index dd4857990..8b0537f4e 100644 --- a/idealPDS/src/main/java/typestate/TransitionFunction.java +++ b/idealPDS/src/main/java/typestate/TransitionFunction.java @@ -112,7 +112,7 @@ public Weight combineWith(Weight other) { HashSet newStateChangeStmts = Sets.newHashSet(stateChangeStatements); newStateChangeStmts.addAll(func.stateChangeStatements); return new TransitionFunction(transitions, newStateChangeStmts); - }; + } public static TransitionFunction one() { if (one == null) one = new TransitionFunction("ONE"); diff --git a/idealPDS/src/main/java/typestate/impl/statemachines/OutputStreamStateMachine.java b/idealPDS/src/main/java/typestate/impl/statemachines/OutputStreamStateMachine.java index 8b60c62c0..ea177075b 100644 --- a/idealPDS/src/main/java/typestate/impl/statemachines/OutputStreamStateMachine.java +++ b/idealPDS/src/main/java/typestate/impl/statemachines/OutputStreamStateMachine.java @@ -25,7 +25,7 @@ public class OutputStreamStateMachine extends TypeStateMachineWeightFunctions { private static final String CLOSE_METHODS = ".* close.*"; private static final String WRITE_METHODS = ".* write.*"; - private static final String TYPE = "java.io.OutputStream";; + private static final String TYPE = "java.io.OutputStream"; public static enum States implements State { NONE, diff --git a/idealPDS/src/test/java/test/IDEALTestingFramework.java b/idealPDS/src/test/java/test/IDEALTestingFramework.java index 3ecf61e5c..a0391850e 100644 --- a/idealPDS/src/test/java/test/IDEALTestingFramework.java +++ b/idealPDS/src/test/java/test/IDEALTestingFramework.java @@ -101,7 +101,7 @@ public boolean onTheFlyCallGraph() { public StaticFieldStrategy getStaticFieldStrategy() { return StaticFieldStrategy.FLOW_SENSITIVE; - }; + } @Override public boolean allowMultipleQueries() { diff --git a/idealPDS/src/test/java/typestate/test/helper/File.java b/idealPDS/src/test/java/typestate/test/helper/File.java index f9393c2d1..099b13cf3 100644 --- a/idealPDS/src/test/java/typestate/test/helper/File.java +++ b/idealPDS/src/test/java/typestate/test/helper/File.java @@ -18,7 +18,7 @@ public File open() { public File close() { return this; - }; + } public int hashCode() { return 9; diff --git a/pom.xml b/pom.xml index a42890a40..80b46ecbb 100644 --- a/pom.xml +++ b/pom.xml @@ -55,7 +55,7 @@ UTF-8 - 4.3.0-SNAPSHOT + 4.5.0 2.13 1.11.2 3.6.1 From 12bc45bf3ea5f0228ea0669942ab886556ee1883 Mon Sep 17 00:00:00 2001 From: Sven Meyer Date: Sun, 29 Sep 2024 12:54:59 +0200 Subject: [PATCH 04/61] Add missing functions --- .../sync/pds/solver/OneWeightFunctions.java | 1 - .../java/boomerang/WeightedForwardQuery.java | 1 - .../java/test/cases/fields/ReadPOITest.java | 1 - .../scene/opal/OpalDeclaredMethod.scala | 3 ++ .../boomerang/scene/opal/OpalMethod.scala | 14 +++++- .../boomerang/scene/sootup/JimpleUpType.java | 47 +++++++++---------- 6 files changed, 38 insertions(+), 29 deletions(-) diff --git a/SynchronizedPDS/src/main/java/sync/pds/solver/OneWeightFunctions.java b/SynchronizedPDS/src/main/java/sync/pds/solver/OneWeightFunctions.java index d73e270a8..09471078a 100644 --- a/SynchronizedPDS/src/main/java/sync/pds/solver/OneWeightFunctions.java +++ b/SynchronizedPDS/src/main/java/sync/pds/solver/OneWeightFunctions.java @@ -41,5 +41,4 @@ public W pop(Node curr) { public W getOne() { return one; } - } diff --git a/boomerangPDS/src/main/java/boomerang/WeightedForwardQuery.java b/boomerangPDS/src/main/java/boomerang/WeightedForwardQuery.java index 0c5e8e47a..318f403f7 100644 --- a/boomerangPDS/src/main/java/boomerang/WeightedForwardQuery.java +++ b/boomerangPDS/src/main/java/boomerang/WeightedForwardQuery.java @@ -27,5 +27,4 @@ public WeightedForwardQuery(Edge stmt, Val variable, W weight) { public W weight() { return weight; } - } diff --git a/boomerangPDS/src/test/java/test/cases/fields/ReadPOITest.java b/boomerangPDS/src/test/java/test/cases/fields/ReadPOITest.java index 3d2e946f7..b685b0504 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/ReadPOITest.java +++ b/boomerangPDS/src/test/java/test/cases/fields/ReadPOITest.java @@ -142,5 +142,4 @@ private static class Node { private static class AllocNode extends Node implements AllocatedObject {} private static class Alloc implements AllocatedObject {} - } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalDeclaredMethod.scala b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalDeclaredMethod.scala index 5e6645242..db4cc2d79 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalDeclaredMethod.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalDeclaredMethod.scala @@ -1,5 +1,6 @@ package boomerang.scene.opal +import boomerang.scene import boomerang.scene.{DeclaredMethod, InvokeExpr, WrappedClass} import org.opalj.br.Method import org.opalj.tac.Var @@ -23,6 +24,8 @@ class OpalDeclaredMethod[+V <: Var[V]](invokeExpr: InvokeExpr, delegate: Method) new OpalWrappedClass(OpalClient.getClassFileForType(declaredMethod.declaringClassType)) } + override def getCalledMethod: scene.Method = new OpalMethod(delegate) + override def hashCode(): Int = 31 * delegate.hashCode() override def equals(obj: Any): Boolean = obj match { diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalMethod.scala b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalMethod.scala index ea3c52d5e..4488af3cd 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalMethod.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalMethod.scala @@ -1,6 +1,6 @@ package boomerang.scene.opal -import boomerang.scene.{ControlFlowGraph, Method, Statement, Val, WrappedClass} +import boomerang.scene.{ControlFlowGraph, Method, Statement, Type, Val, WrappedClass} import org.opalj.tac.{DUVar, InstanceFunctionCall, InstanceMethodCall, UVar} import org.opalj.value.ValueInformation @@ -27,6 +27,18 @@ class OpalMethod(delegate: org.opalj.br.Method) extends Method { parameterLocals.contains(value) } + override def getParameterTypes: util.List[Type] = { + val result = new util.ArrayList[Type]() + + for (parameterType <- delegate.parameterTypes) { + result.add(new OpalType(parameterType)) + } + + result + } + + override def getParameterType(index: Int): Type = getParameterTypes.get(index) + override def isThisLocal(fact: Val): Boolean = { if (isStatic) return false diff --git a/boomerangScope-SootUp/src/main/java/boomerang/scene/sootup/JimpleUpType.java b/boomerangScope-SootUp/src/main/java/boomerang/scene/sootup/JimpleUpType.java index 988f1fba3..cd14674c4 100644 --- a/boomerangScope-SootUp/src/main/java/boomerang/scene/sootup/JimpleUpType.java +++ b/boomerangScope-SootUp/src/main/java/boomerang/scene/sootup/JimpleUpType.java @@ -4,6 +4,7 @@ import boomerang.scene.Type; import boomerang.scene.Val; import boomerang.scene.WrappedClass; +import java.util.stream.Collectors; import sootup.core.types.ArrayType; import sootup.core.types.ClassType; import sootup.core.types.NullType; @@ -12,8 +13,6 @@ import sootup.java.core.JavaSootClass; import sootup.java.core.types.JavaClassType; -import java.util.stream.Collectors; - public class JimpleUpType implements Type { private final sootup.core.types.Type delegate; @@ -56,14 +55,12 @@ public boolean doesCastFail(Type targetVal, Val target) { return true; } JavaClassType sourceType = (JavaClassType) this.getDelegate(); - JavaSootClass targetClass = - SootUpClient.getInstance().getSootClass(targetType); - JavaSootClass sourceClass = - SootUpClient.getInstance().getSootClass(sourceType); + JavaSootClass targetClass = SootUpClient.getInstance().getSootClass(targetType); + JavaSootClass sourceClass = SootUpClient.getInstance().getSootClass(sourceType); // if (targetClass.isPhantomClass() || sourceClass.isPhantomClass()) return false; if (target instanceof AllocVal && ((AllocVal) target).getAllocVal().isNewExpr()) { boolean castFails = - SootUpClient.getInstance().getView().getTypeHierarchy().isSubtype(targetType, sourceType); + SootUpClient.getInstance().getView().getTypeHierarchy().isSubtype(targetType, sourceType); return !castFails; } // TODO this line is necessary as canStoreType does not properly work for @@ -72,11 +69,11 @@ public boolean doesCastFail(Type targetVal, Val target) { return false; } boolean castFails = - SootUpClient.getInstance().getView().getTypeHierarchy().isSubtype(targetType, sourceType) - || SootUpClient.getInstance() - .getView() - .getTypeHierarchy() - .isSubtype(sourceType, targetType); + SootUpClient.getInstance().getView().getTypeHierarchy().isSubtype(targetType, sourceType) + || SootUpClient.getInstance() + .getView() + .getTypeHierarchy() + .isSubtype(sourceType, targetType); return !castFails; } @@ -97,25 +94,25 @@ public boolean isSubtypeOf(String type) { JavaSootClass sootClass = SootUpClient.getInstance().getSootClass(allocatedType); if (!superClass.isInterface()) { return SootUpClient.getInstance() - .getView() - .getTypeHierarchy() - .isSubtype(sootClass.getType(), superClass.getType()); + .getView() + .getTypeHierarchy() + .isSubtype(sootClass.getType(), superClass.getType()); } if (SootUpClient.getInstance() - .getView() - .getTypeHierarchy() - .subclassesOf(superClass.getType()) - .collect(Collectors.toSet()) - .contains(allocatedType)) { + .getView() + .getTypeHierarchy() + .subclassesOf(superClass.getType()) + .collect(Collectors.toSet()) + .contains(allocatedType)) { return true; } return SootUpClient.getInstance() - .getView() - .getTypeHierarchy() - .implementersOf(superClass.getType()) - .collect(Collectors.toSet()) - .contains(allocatedType); + .getView() + .getTypeHierarchy() + .implementersOf(superClass.getType()) + .collect(Collectors.toSet()) + .contains(allocatedType); } @Override From 1cb2d83245b90965256754422f7390d07a22c4dd Mon Sep 17 00:00:00 2001 From: Sven Meyer Date: Fri, 25 Oct 2024 10:13:29 +0200 Subject: [PATCH 05/61] First complete version of Opal scope --- .../java/boomerang/WeightedBoomerang.java | 44 +++--- .../solver/BackwardBoomerangSolver.java | 3 +- .../solver/ForwardBoomerangSolver.java | 1 + boomerangScope-Opal/pom.xml | 3 +- .../src/main/scala/boomerang/scene/Main.scala | 53 ++++--- .../boomerang/scene/opal/OpalCallGraph.scala | 66 ++++---- .../boomerang/scene/opal/OpalClient.scala | 20 ++- .../scene/opal/OpalControlFlowGraph.scala | 48 +++--- .../scene/opal/OpalDeclaredMethod.scala | 76 +++++++--- .../boomerang/scene/opal/OpalDoubleVal.scala | 18 ++- .../boomerang/scene/opal/OpalField.scala | 12 +- .../scene/opal/OpalIfStatement.scala | 17 +-- .../boomerang/scene/opal/OpalInvokeExpr.scala | 57 ++++--- .../boomerang/scene/opal/OpalMethod.scala | 88 +++++++---- .../boomerang/scene/opal/OpalStatement.scala | 101 ++++++++----- .../scene/opal/OpalStaticFieldVal.scala | 4 +- .../scala/boomerang/scene/opal/OpalType.scala | 45 ++++-- .../scala/boomerang/scene/opal/OpalVal.scala | 141 +++++++++++++++--- .../scene/opal/OpalWrappedClass.scala | 57 ++++--- boomerangScope-SootUp/pom.xml | 2 +- .../scene/sootup/JimpleUpDeclaredMethod.java | 25 +++- .../scene/sootup/JimpleUpStaticFieldVal.java | 5 + .../boomerang/scene/sootup/JimpleUpType.java | 5 + .../boomerang/scene/sootup/JimpleUpVal.java | 11 ++ .../scene/wala/WALADeclaredMethod.java | 14 +- .../scene/wala/WALAStaticFieldVal.java | 5 + .../java/boomerang/scene/wala/WALAType.java | 4 + .../java/boomerang/scene/wala/WALAVal.java | 5 + .../main/java/boomerang/scene/AllocVal.java | 4 + .../java/boomerang/scene/DeclaredMethod.java | 10 +- .../src/main/java/boomerang/scene/Type.java | 2 + .../src/main/java/boomerang/scene/Val.java | 34 +---- .../scene/jimple/JimpleDeclaredMethod.java | 22 ++- .../scene/jimple/JimpleStaticFieldVal.java | 5 + .../boomerang/scene/jimple/JimpleType.java | 84 ++++++++++- .../boomerang/scene/jimple/JimpleVal.java | 10 ++ pom.xml | 8 + 37 files changed, 783 insertions(+), 326 deletions(-) diff --git a/boomerangPDS/src/main/java/boomerang/WeightedBoomerang.java b/boomerangPDS/src/main/java/boomerang/WeightedBoomerang.java index d79b25b26..cb3e4a816 100644 --- a/boomerangPDS/src/main/java/boomerang/WeightedBoomerang.java +++ b/boomerangPDS/src/main/java/boomerang/WeightedBoomerang.java @@ -1142,28 +1142,28 @@ private AbstractBoomerangSolver forwardSolve(ForwardQuery query) { solver.getFieldAutomaton(), new Transition<>(genState, Field.empty(), fieldTarget)); } } - if (stmt.isStringAllocation()) { - // Scene.v().forceResolve("java.lang.String", - // SootClass.BODIES); - // throw new RuntimeException("Not properly implemented String allocation site"); - // SootClass stringClass = Scene.v().getSootClass("java.lang.String"); - // if (stringClass.declaresField("char[] value")) { - // SootField valueField = stringClass.getField("char[] value"); - // SingleNode> s = new SingleNode>(query.asNode()); - // INode> irState = - // solver.getFieldAutomaton().createState(s, - // new Field(valueField)); - // insertTransition(solver.getFieldAutomaton(), new Transition>>( - // new SingleNode>(query.asNode()), new - // Field(valueField), irState)); - // insertTransition(solver.getFieldAutomaton(), new Transition>>( - // irState, Field.empty(), - // solver.getFieldAutomaton().getInitialState())); - // } - } + // if (stmt.isStringAllocation()) { + // Scene.v().forceResolve("java.lang.String", + // SootClass.BODIES); + // throw new RuntimeException("Not properly implemented String allocation site"); + // SootClass stringClass = Scene.v().getSootClass("java.lang.String"); + // if (stringClass.declaresField("char[] value")) { + // SootField valueField = stringClass.getField("char[] value"); + // SingleNode> s = new SingleNode>(query.asNode()); + // INode> irState = + // solver.getFieldAutomaton().createState(s, + // new Field(valueField)); + // insertTransition(solver.getFieldAutomaton(), new Transition>>( + // new SingleNode>(query.asNode()), new + // Field(valueField), irState)); + // insertTransition(solver.getFieldAutomaton(), new Transition>>( + // irState, Field.empty(), + // solver.getFieldAutomaton().getInitialState())); + // } + // } Val var; Field field; if (stmt.isFieldStore()) { diff --git a/boomerangPDS/src/main/java/boomerang/solver/BackwardBoomerangSolver.java b/boomerangPDS/src/main/java/boomerang/solver/BackwardBoomerangSolver.java index d8dd1ef62..768bc1825 100644 --- a/boomerangPDS/src/main/java/boomerang/solver/BackwardBoomerangSolver.java +++ b/boomerangPDS/src/main/java/boomerang/solver/BackwardBoomerangSolver.java @@ -124,11 +124,12 @@ protected Collection computeReturnFlow( } protected void callFlow(Method caller, Node curr, Statement callSite) { - icfg.addCalleeListener(new CallSiteCalleeListener(curr, caller)); InvokeExpr invokeExpr = callSite.getInvokeExpr(); if (dataFlowScope.isExcluded(invokeExpr.getMethod())) { byPassFlowAtCallsite(caller, curr); + return; } + icfg.addCalleeListener(new CallSiteCalleeListener(curr, caller)); } private void byPassFlowAtCallsite(Method caller, Node curr) { diff --git a/boomerangPDS/src/main/java/boomerang/solver/ForwardBoomerangSolver.java b/boomerangPDS/src/main/java/boomerang/solver/ForwardBoomerangSolver.java index 94b3e8611..b3f736194 100644 --- a/boomerangPDS/src/main/java/boomerang/solver/ForwardBoomerangSolver.java +++ b/boomerangPDS/src/main/java/boomerang/solver/ForwardBoomerangSolver.java @@ -436,6 +436,7 @@ public void callFlow( assert icfg.isCallStmt(callSiteEdge.getStart()); if (dataFlowScope.isExcluded(invokeExpr.getMethod())) { byPassFlowAtCallSite(caller, currNode, callSiteEdge.getStart()); + return; } icfg.addCalleeListener(new CallSiteCalleeListener(caller, callSiteEdge, currNode, invokeExpr)); diff --git a/boomerangScope-Opal/pom.xml b/boomerangScope-Opal/pom.xml index 7f1473d68..cacef835f 100644 --- a/boomerangScope-Opal/pom.xml +++ b/boomerangScope-Opal/pom.xml @@ -6,7 +6,7 @@ de.fraunhofer.iem SPDS - 3.1.2-Sparse + 3.2.1 boomerangScope-Opal @@ -20,7 +20,6 @@ de.fraunhofer.iem boomerangScope - 3.1.2-Sparse org.scala-lang diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scene/Main.scala b/boomerangScope-Opal/src/main/scala/boomerang/scene/Main.scala index e3eeb7b7d..becadc7cf 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scene/Main.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scene/Main.scala @@ -1,41 +1,54 @@ package boomerang.scene import boomerang.scene.opal.{OpalCallGraph, OpalClient} +import com.typesafe.config.ConfigValueFactory import org.opalj.br.analyses.Project import org.opalj.br.analyses.cg.InitialEntryPointsKey +import org.opalj.log.{DevNullLogger, GlobalLogContext, OPALLogger} import org.opalj.tac.cg.CHACallGraphKey -import scala.jdk.CollectionConverters._ import java.io.File object Main { def main(args: Array[String]): Unit = { - val project = Project(new File("C:\\Users\\Sven\\Documents\\CogniCrypt\\Opal\\IfStmt\\IfStmt.jar")) - val callGraph = project.get(CHACallGraphKey) - val entryPoints = project.get(InitialEntryPointsKey) + OPALLogger.updateLogger(GlobalLogContext, DevNullLogger) - OpalClient.init(project) + val project = Project(new File("C:\\Users\\Sven\\Documents\\CogniCrypt\\Opal\\MultipleCalls\\Main.jar")) + var config = project.config - val opalCallGraph = new OpalCallGraph(callGraph, entryPoints.toSet) + val key = s"${InitialEntryPointsKey.ConfigKeyPrefix}entryPoints" + val currentValues = project.config.getList(key).unwrapped() + val allMethods = project.allMethodsWithBody + + allMethods.foreach(method => { + val configValue = new java.util.HashMap[String, String] + configValue.put("declaringClass", method.classFile.thisType.toJava) + configValue.put("name", method.name) - val edges = opalCallGraph.getEdges - edges.forEach(x => { - val start = x.src() - val target = x.tgt() + currentValues.add(ConfigValueFactory.fromMap(configValue)) + config = config.withValue(key, ConfigValueFactory.fromIterable(currentValues)) + }) - if (!target.isStatic) { - //val thisLocal = target.getThisLocal - } - val locals = target.getParameterLocals + config = config.withValue( + s"${InitialEntryPointsKey.ConfigKeyPrefix}analysis", + ConfigValueFactory.fromAnyRef("org.opalj.br.analyses.cg.ConfigurationEntryPointsFinder") + ) - for (stmt <- target.getStatements.asScala) { - if (stmt.isAssign) { - println(stmt.getRightOp.isLengthExpr) - } + val newProject = Project.recreate(project, config) + val callGraph = newProject.get(CHACallGraphKey) + val entryPoints = newProject.get(InitialEntryPointsKey) + println("Entry Points: " + entryPoints.size) - println("--") - } + callGraph.reachableMethods().foreach(method => { + println(method.method) + }) + + OpalClient.init(newProject) + + val opalCallGraph = new OpalCallGraph(callGraph, entryPoints.toSet) + opalCallGraph.getEdges.forEach(edge => { + println(edge) }) } } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalCallGraph.scala b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalCallGraph.scala index 7565f941f..e7442cfd4 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalCallGraph.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalCallGraph.scala @@ -1,50 +1,56 @@ package boomerang.scene.opal import boomerang.scene.CallGraph.Edge -import org.opalj.br.Method +import org.opalj.br.{DefinedMethod, Method, MultipleDefinedMethods, VirtualDeclaredMethod} import org.opalj.tac.cg.CallGraph class OpalCallGraph(callGraph: CallGraph, entryPoints: Set[Method]) extends boomerang.scene.CallGraph { - for (reachableMethod <- callGraph.reachableMethods()) { - if (reachableMethod.method.hasSingleDefinedMethod) { - val method = reachableMethod.method.definedMethod + callGraph.reachableMethods().foreach(method => { + method.method match { + case definedMethod: DefinedMethod => addEdgesFromMethod(definedMethod) + // TODO Should this case be considered? + // case definedMethods: MultipleDefinedMethods => + // definedMethods.foreachDefinedMethod(m => addEdgesFromMethod(m)) + case _ => + } + }) + + private def addEdgesFromMethod(method: DefinedMethod): Unit = { + // TODO move TAC to parameters or use method wrappers with TAC + val tacCode = OpalClient.getTacForMethod(method.definedMethod) - if (method.body.isDefined) { - val tacCode = OpalClient.getTacForMethod(method) - val calleeMap = callGraph.calleesOf(reachableMethod.method).toMap + tacCode.stmts.foreach(stmt => { + val srcStatement = new OpalStatement(stmt, OpalMethod(method.definedMethod)) - for (stmt <- tacCode.stmts) { - val srcStatement = new OpalStatement(stmt, new OpalMethod(reachableMethod.method.definedMethod)) + if (srcStatement.containsInvokeExpr()) { + val callees = callGraph.directCalleesOf(method, stmt.pc) - if (srcStatement.containsInvokeExpr()) { - val callees = calleeMap(stmt.pc) + callees.foreach(callee => { + callee.method match { + case definedMethod: DefinedMethod => + val targetMethod = OpalMethod(definedMethod.definedMethod) - for (callee <- callees) { - if (callee.method.hasSingleDefinedMethod) { - val target = callee.method + addEdge(new Edge(srcStatement, targetMethod)) + case virtualMethod: VirtualDeclaredMethod => + val targetMethod = OpalPhantomMethod(virtualMethod.declaringClassType, virtualMethod.name, virtualMethod.descriptor, srcStatement.getInvokeExpr.isStaticInvokeExpr) - if (target.definedMethod.body.isDefined) { - val targetMethod = new OpalMethod(target.definedMethod) + addEdge(new Edge(srcStatement, targetMethod)) + case definedMethods: MultipleDefinedMethods => + definedMethods.foreachDefinedMethod(method => { + val targetMethod = OpalMethod(method) - val edge = new Edge(srcStatement, targetMethod) - addEdge(edge) - // TODO Test for multiple edges - println("Added edge " + srcStatement + " -> " + targetMethod) - } - } - } + addEdge(new Edge(srcStatement, targetMethod)) + }) } - } + }) } - } + }) } - for (entryPoint <- entryPoints) { + entryPoints.foreach(entryPoint => { if (entryPoint.body.isDefined) { - val method = new OpalMethod(entryPoint) - - addEntryPoint(method) + addEntryPoint(OpalMethod(entryPoint)) } - } + }) } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalClient.scala b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalClient.scala index 806df22e9..f38e59ada 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalClient.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalClient.scala @@ -1,6 +1,6 @@ package boomerang.scene.opal -import org.opalj.br.{ClassFile, ClassHierarchy, DeclaredMethod, Field, Method, MethodDescriptor, ObjectType, ReferenceType} +import org.opalj.br.{ClassFile, ClassHierarchy, DeclaredMethod, DefinedMethod, Field, Method, MethodDescriptor, ObjectType, ReferenceType} import org.opalj.br.analyses.{DeclaredMethods, DeclaredMethodsKey, Project} import org.opalj.tac.{AITACode, ComputeTACAIKey, FieldRead, FieldWriteAccessStmt, TACMethodParameter} import org.opalj.value.ValueInformation @@ -17,20 +17,30 @@ object OpalClient { tacCodes = Some(p.get(ComputeTACAIKey)) } + def getDeclaredMethod(method: Method): DeclaredMethod = declaredMethods.get(method) + def getClassHierarchy: ClassHierarchy = project.get.classHierarchy - def getClassFileForType(objectType: ObjectType): ClassFile = project.get.classFile(objectType).get + def getClassFileForType(objectType: ObjectType): Option[ClassFile] = project.get.classFile(objectType) def isApplicationClass(classFile: ClassFile): Boolean = project.get.allProjectClassFiles.toSet.contains(classFile) - def getDeclaredMethod(method: Method): DeclaredMethod = declaredMethods.get(method) - def getTacForMethod(method: Method): AITACode[TACMethodParameter, ValueInformation] = tacCodes.get(method) def resolveFieldStore(stmt: FieldWriteAccessStmt[_]): Option[Field] = stmt.resolveField(project.get) def resolveFieldLoad(expr: FieldRead[_]): Option[Field] = expr.resolveField(project.get) - def resolveMethodRef(declaringClass: ReferenceType, name: String, methodDescriptor: MethodDescriptor): Option[Method] = project.get.resolveMethodReference(declaringClass, name, methodDescriptor) + def resolveMethodRef(declaringClass: ReferenceType, name: String, methodDescriptor: MethodDescriptor): Option[DefinedMethod] = { + val method = project.get.resolveMethodReference(declaringClass, name, methodDescriptor, forceLookupInSuperinterfacesOnFailure = true) + + if (method.isDefined) { + val declaredMethod = declaredMethods.get(method.get) + + return Some(declaredMethod) + } + + None + } } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalControlFlowGraph.scala b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalControlFlowGraph.scala index d7a608ef3..14a107374 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalControlFlowGraph.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalControlFlowGraph.scala @@ -43,35 +43,45 @@ class OpalControlFlowGraph(method: OpalMethod) extends ControlFlowGraph { private def buildCache(): Unit = { if (cacheBuilt) return - val tac = OpalClient.getTacForMethod(method.getDelegate) + val tac = OpalClient.getTacForMethod(method.delegate) - val headPc = tac.cfg.startBlock.startPC - val head = tac.stmts(headPc) - val headStatement = new OpalStatement(head, method) - startPointCache.add(headStatement) + // val entryPoint = tac.stmts(tac.cfg.startBlock.startPC) + // startPointCache.add(new OpalStatement(entryPoint, method)) - // TODO Deal with tails - val tail = tac.cfg.normalReturnNode.predecessors.tail - - for (stmt <- tac.stmts) { + tac.stmts.foreach(stmt => { val statement = new OpalStatement(stmt, method) statements.add(statement) val stmtPc = tac.pcToIndex(stmt.pc) - for (successorPc <- tac.cfg.successors(stmtPc)) { - val successor = tac.stmts(successorPc) - val successorStatement = new OpalStatement(successor, method) - succsOfCache.put(statement, successorStatement) + val predecessors = tac.cfg.predecessors(stmtPc) + if (predecessors.isEmpty) { + // No predecessors => Head statement + val headStatement = new OpalStatement(stmt, method) + startPointCache.add(headStatement) + } else { + predecessors.foreach(predecessorPc => { + val predecessor = tac.stmts(predecessorPc) + val predecessorStatement = new OpalStatement(predecessor, method) + + predsOfCache.put(statement, predecessorStatement) + }) } - for (predecessorPc <- tac.cfg.predecessors(stmtPc)) { - val predecessor = tac.stmts(predecessorPc) - val predecessorStatement = new OpalStatement(predecessor, method) - - predsOfCache.put(statement, predecessorStatement) + val successors = tac.cfg.successors(stmtPc) + if (successors.isEmpty) { + // No successors => Tail statement + val tailStmt = new OpalStatement(stmt, method) + endPointCache.add(tailStmt) + } else { + successors.foreach(successorPc => { + val successor = tac.stmts(successorPc) + val successorStatement = new OpalStatement(successor, method) + + succsOfCache.put(statement, successorStatement) + }) } - } + }) cacheBuilt = true } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalDeclaredMethod.scala b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalDeclaredMethod.scala index db4cc2d79..e84bc18da 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalDeclaredMethod.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalDeclaredMethod.scala @@ -1,40 +1,76 @@ package boomerang.scene.opal -import boomerang.scene -import boomerang.scene.{DeclaredMethod, InvokeExpr, WrappedClass} -import org.opalj.br.Method -import org.opalj.tac.Var +import boomerang.scene.{DeclaredMethod, InvokeExpr, Type, WrappedClass} +import org.opalj.br.{DefinedMethod, MethodDescriptor, MethodSignature, ReferenceType} -class OpalDeclaredMethod[+V <: Var[V]](invokeExpr: InvokeExpr, delegate: Method) extends DeclaredMethod(invokeExpr) { +import java.util - override def isNative: Boolean = delegate.isNative +case class OpalDeclaredMethod(invokeExpr: InvokeExpr, delegate: DefinedMethod) extends DeclaredMethod(invokeExpr) { - override def getSubSignature: String = delegate.signature.toString + override def isNative: Boolean = delegate.definedMethod.isNative + + override def getSubSignature: String = delegate.definedMethod.signature.toString override def getName: String = delegate.name - override def isStatic: Boolean = delegate.isStatic + override def isStatic: Boolean = delegate.definedMethod.isStatic - override def isConstructor: Boolean = delegate.isStatic + override def isConstructor: Boolean = delegate.definedMethod.isConstructor - override def getSignature: String = delegate.fullyQualifiedSignature + override def getSignature: String = delegate.definedMethod.fullyQualifiedSignature - override def getDeclaringClass: WrappedClass = { - val declaredMethod = OpalClient.getDeclaredMethod(delegate) - new OpalWrappedClass(OpalClient.getClassFileForType(declaredMethod.declaringClassType)) + override def getDeclaringClass: WrappedClass = OpalWrappedClass(delegate.definedMethod.classFile) + + override def getParameterTypes: util.List[Type] = { + val result = new util.ArrayList[Type]() + + delegate.definedMethod.parameterTypes.foreach(paramType => { + result.add(OpalType(paramType)) + }) + + result } - override def getCalledMethod: scene.Method = new OpalMethod(delegate) + override def getParameterType(index: Int): Type = getParameterTypes.get(index) + + override def toString: String = getSignature +} + +case class OpalPhantomDeclaredMethod(invokeExpr: InvokeExpr, declaringClass: ReferenceType, name: String, descriptor: MethodDescriptor, static: Boolean) extends DeclaredMethod(invokeExpr) { + + override def isNative: Boolean = false - override def hashCode(): Int = 31 * delegate.hashCode() + override def getSubSignature: String = MethodSignature(name, descriptor).toJava - override def equals(obj: Any): Boolean = obj match { - case other: OpalDeclaredMethod[_] => this.delegate == other.getDelegate - case _ => false + override def getName: String = name + + override def isStatic: Boolean = static + + override def isConstructor: Boolean = name == "" + + override def getSignature: String = descriptor.toJava(s"${declaringClass.toJava}.$name") + + override def getDeclaringClass: WrappedClass = { + val decClass = OpalClient.getClassFileForType(declaringClass.asObjectType) + + if (decClass.isDefined) { + OpalWrappedClass(decClass.get) + } else { + OpalPhantomWrappedClass(declaringClass) + } } - override def toString: String = delegate.toJava + override def getParameterTypes: util.List[Type] = { + val result = new util.ArrayList[Type]() + + descriptor.parameterTypes.foreach(paramType => { + result.add(OpalType(paramType)) + }) + + result + } - def getDelegate: Method = delegate + override def getParameterType(index: Int): Type = getParameterTypes.get(index) + override def toString: String = getSignature } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalDoubleVal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalDoubleVal.scala index 43f1d65d2..f3771bf36 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalDoubleVal.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalDoubleVal.scala @@ -1,16 +1,24 @@ package boomerang.scene.opal -import boomerang.scene.{Method, Val, ValWithFalseVariable} -import org.opalj.tac.{Expr, Var} +import boomerang.scene.{Val, ValWithFalseVariable} +import org.opalj.tac.{DUVar, Expr} +import org.opalj.value.ValueInformation -class OpalDoubleVal[+V <: Var[V]](delegate: Expr[V], method: Method, falseVal: Val) extends OpalVal(delegate, method) with ValWithFalseVariable{ +class OpalDoubleVal(delegate: Expr[DUVar[ValueInformation]], method: OpalMethod, falseVal: Val) extends OpalVal(delegate, method) with ValWithFalseVariable { override def getFalseVariable: Val = falseVal - override def hashCode(): Int = 31 * super.hashCode() + 31 * falseVal.hashCode() + override def hashCode(): Int = { + var result = 31 + super.hashCode() + result = result * 31 + falseVal.hashCode() + result + } + + private def canEqual(a: Any): Boolean = a.isInstanceOf[OpalDoubleVal] override def equals(obj: Any): Boolean = obj match { - case other: OpalDoubleVal[_] => super.equals(other) && falseVal.equals(other.getFalseVariable) + case other: OpalDoubleVal => + other.canEqual(this) && super.equals(other) && falseVal.equals(other.getFalseVariable) case _ => false } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalField.scala b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalField.scala index 7be9ae328..c87792d02 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalField.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalField.scala @@ -2,19 +2,9 @@ package boomerang.scene.opal import boomerang.scene.Field -class OpalField(delegate: org.opalj.br.Field) extends Field { +case class OpalField(delegate: org.opalj.br.Field) extends Field { override def isInnerClassField: Boolean = delegate.name.contains("$") - override def hashCode(): Int = 31 * delegate.hashCode() - - override def equals(obj: Any): Boolean = obj match { - case other: OpalField => this.delegate == other.getDelegate - case _ => false - } - override def toString: String = delegate.toJava - - def getDelegate: org.opalj.br.Field = delegate - } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalIfStatement.scala b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalIfStatement.scala index a9ca928e9..5b568dfd3 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalIfStatement.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalIfStatement.scala @@ -1,16 +1,16 @@ package boomerang.scene.opal import boomerang.scene.{IfStatement, Statement, Val} -import org.opalj.tac.{DUVar, If, Var} +import org.opalj.tac.{DUVar, If} import org.opalj.value.ValueInformation -class OpalIfStatement[+V <: Var[V]](delegate: If[V], method: OpalMethod) extends IfStatement { +class OpalIfStatement(val delegate: If[DUVar[ValueInformation]], method: OpalMethod) extends IfStatement { override def getTarget: Statement = { - val tac = OpalClient.getTacForMethod(method.getDelegate) + val tac = OpalClient.getTacForMethod(method.delegate) val target = delegate.targetStmt - new OpalStatement[DUVar[ValueInformation]](tac.stmts(target), method) + new OpalStatement(tac.stmts(target), method) } override def evaluate(otherVal: Val): IfStatement.Evaluation = IfStatement.Evaluation.UNKOWN @@ -22,15 +22,14 @@ class OpalIfStatement[+V <: Var[V]](delegate: If[V], method: OpalMethod) extends otherVal.equals(left) || otherVal.equals(right) } - override def hashCode(): Int = 31 * delegate.hashCode() + override def hashCode(): Int = 31 + delegate.hashCode() + + private def canEqual(a: Any): Boolean = a.isInstanceOf[OpalIfStatement] override def equals(obj: Any): Boolean = obj match { - case other: OpalStatement[_] => this.delegate == other.getDelegate + case other: OpalIfStatement => other.canEqual(this) && this.delegate.pc == other.delegate.pc case _ => false } override def toString: String = delegate.toString() - - def getDelegate: If[V] = delegate - } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalInvokeExpr.scala b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalInvokeExpr.scala index cb8639e40..861cae8ef 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalInvokeExpr.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalInvokeExpr.scala @@ -1,20 +1,22 @@ package boomerang.scene.opal import boomerang.scene.{DeclaredMethod, InvokeExpr, Val} -import org.opalj.tac.{FunctionCall, InstanceFunctionCall, InstanceMethodCall, MethodCall, NonVirtualFunctionCall, NonVirtualMethodCall, Var} +import org.opalj.UShort +import org.opalj.tac.{DUVar, FunctionCall, InstanceFunctionCall, InstanceMethodCall, MethodCall, NonVirtualFunctionCall, NonVirtualMethodCall} +import org.opalj.value.ValueInformation import java.util -class OpalMethodInvokeExpr[+V <: Var[V]](delegate: MethodCall[V], method: OpalMethod) extends InvokeExpr { +class OpalMethodInvokeExpr(val delegate: MethodCall[DUVar[ValueInformation]], method: OpalMethod, pc: UShort) extends InvokeExpr { override def getArg(index: Int): Val = getArgs.get(index) override def getArgs: util.List[Val] = { val result = new util.ArrayList[Val] - for (param <- delegate.params) { - result.add(new OpalVal[V](param, method)) - } + delegate.params.foreach(param => { + result.add(new OpalVal(param, method)) + }) result } @@ -23,7 +25,7 @@ class OpalMethodInvokeExpr[+V <: Var[V]](delegate: MethodCall[V], method: OpalMe override def getBase: Val = { if (isInstanceInvokeExpr) { - return new OpalVal[V](delegate.asInstanceMethodCall.receiver, method) + return new OpalVal(delegate.asInstanceMethodCall.receiver, method) } throw new RuntimeException("Method call is not an instance invoke expression") @@ -33,27 +35,38 @@ class OpalMethodInvokeExpr[+V <: Var[V]](delegate: MethodCall[V], method: OpalMe val resolvedMethod = OpalClient.resolveMethodRef(delegate.declaringClass, delegate.name, delegate.descriptor) if (resolvedMethod.isDefined) { - return new OpalDeclaredMethod[V](this, resolvedMethod.get) + OpalDeclaredMethod(this, resolvedMethod.get) + } else { + OpalPhantomDeclaredMethod(this, delegate.declaringClass, delegate.name, delegate.descriptor, delegate.isStaticMethodCall) } - - throw new RuntimeException("Cannot resolve method " + delegate.name + " from invoke expression") } override def isSpecialInvokeExpr: Boolean = delegate.astID == NonVirtualMethodCall.ASTID override def isStaticInvokeExpr: Boolean = delegate.isStaticMethodCall + + override def hashCode(): Int = 31 + delegate.hashCode() + + private def canEqual(a: Any): Boolean = a.isInstanceOf[OpalMethodInvokeExpr] + + override def equals(obj: Any): Boolean = obj match { + case other: OpalMethodInvokeExpr => other.canEqual(this) && this.delegate == other.delegate + case _ => false + } + + override def toString: String = delegate.toString } -class OpalFunctionInvokeExpr[+V <: Var[V]](delegate: FunctionCall[V], method: OpalMethod) extends InvokeExpr { +class OpalFunctionInvokeExpr(val delegate: FunctionCall[DUVar[ValueInformation]], method: OpalMethod, pc: UShort) extends InvokeExpr { override def getArg(index: Int): Val = getArgs.get(index) override def getArgs: util.List[Val] = { val result = new util.ArrayList[Val] - for (param <- delegate.params) { - result.add(new OpalVal[V](param, method)) - } + delegate.params.foreach(param => { + result.add(new OpalVal(param, method)) + }) result } @@ -62,7 +75,7 @@ class OpalFunctionInvokeExpr[+V <: Var[V]](delegate: FunctionCall[V], method: Op override def getBase: Val = { if (isInstanceInvokeExpr) { - return new OpalVal[V](delegate.asInstanceFunctionCall.receiver, method) + return new OpalVal(delegate.asInstanceFunctionCall.receiver, method) } throw new RuntimeException("Function call is not an instance invoke expression") @@ -72,14 +85,24 @@ class OpalFunctionInvokeExpr[+V <: Var[V]](delegate: FunctionCall[V], method: Op val resolvedMethod = OpalClient.resolveMethodRef(delegate.declaringClass, delegate.name, delegate.descriptor) if (resolvedMethod.isDefined) { - new OpalDeclaredMethod[V](this, resolvedMethod.get) + OpalDeclaredMethod(this, resolvedMethod.get) + } else { + OpalPhantomDeclaredMethod(this, delegate.declaringClass, delegate.name, delegate.descriptor, delegate.isStaticFunctionCall) } - - throw new RuntimeException("Cannot resolve method " + delegate.name + " from invoke expression") } override def isSpecialInvokeExpr: Boolean = delegate.astID == NonVirtualFunctionCall.ASTID override def isStaticInvokeExpr: Boolean = delegate.isStaticFunctionCall + override def hashCode(): Int = 31 + delegate.hashCode() + + private def canEqual(a: Any): Boolean = a.isInstanceOf[OpalFunctionInvokeExpr] + + override def equals(obj: Any): Boolean = obj match { + case other: OpalFunctionInvokeExpr => other.canEqual(this) && this.delegate == other.delegate + case _ => false + } + + override def toString: String = delegate.toString } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalMethod.scala b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalMethod.scala index 4488af3cd..9bd5635e1 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalMethod.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalMethod.scala @@ -1,17 +1,13 @@ package boomerang.scene.opal import boomerang.scene.{ControlFlowGraph, Method, Statement, Type, Val, WrappedClass} -import org.opalj.tac.{DUVar, InstanceFunctionCall, InstanceMethodCall, UVar} -import org.opalj.value.ValueInformation +import org.opalj.br.{MethodDescriptor, MethodSignature, ObjectType} +import org.opalj.tac.{InstanceFunctionCall, InstanceMethodCall, UVar} import scala.jdk.CollectionConverters._ import java.util -class OpalMethod(delegate: org.opalj.br.Method) extends Method { - - if (delegate.body.isEmpty) { - throw new RuntimeException("Trying to build Opal method without body present") - } +case class OpalMethod(delegate: org.opalj.br.Method) extends Method { private var localCache: Option[util.Set[Val]] = None private var parameterLocalCache: Option[util.List[Val]] = None @@ -30,9 +26,9 @@ class OpalMethod(delegate: org.opalj.br.Method) extends Method { override def getParameterTypes: util.List[Type] = { val result = new util.ArrayList[Type]() - for (parameterType <- delegate.parameterTypes) { - result.add(new OpalType(parameterType)) - } + delegate.parameterTypes.foreach(paramType => { + result.add(OpalType(paramType)) + }) result } @@ -68,8 +64,8 @@ class OpalMethod(delegate: org.opalj.br.Method) extends Method { private def isThisLocalDefined: Option[Val] = { val locals = getLocals for (local <- locals.asScala) { - val opalVal = local.asInstanceOf[OpalVal[DUVar[ValueInformation]]] - val valDelegate = opalVal.getDelegate + val opalVal = local.asInstanceOf[OpalVal] + val valDelegate = opalVal.delegate if (valDelegate.isInstanceOf[UVar[_]]) { if (valDelegate.asVar.definedBy.head == -1) { @@ -91,14 +87,14 @@ class OpalMethod(delegate: org.opalj.br.Method) extends Method { if (stmt.isMethodCall) { // Extract the base if (stmt.isInstanceOf[InstanceMethodCall[_]]) { - val opalVal = new OpalVal[DUVar[ValueInformation]](stmt.asInstanceMethodCall.receiver, this) + val opalVal = new OpalVal(stmt.asInstanceMethodCall.receiver, this) localCache.get.add(opalVal) } // Parameters of method calls for (param <- stmt.asMethodCall.params) { if (param.isVar) { - localCache.get.add(new OpalVal[DUVar[ValueInformation]](param.asVar, this)) + localCache.get.add(new OpalVal(param.asVar, this)) } } } @@ -106,19 +102,19 @@ class OpalMethod(delegate: org.opalj.br.Method) extends Method { if (stmt.isAssignment) { // Target variable val targetVar = stmt.asAssignment.targetVar - localCache.get.add(new OpalVal[DUVar[ValueInformation]](targetVar, this)) + localCache.get.add(new OpalVal(targetVar, this)) if (stmt.asAssignment.expr.isFunctionCall) { // Extract the base if (stmt.asAssignment.expr.isInstanceOf[InstanceFunctionCall[_]]) { - val opalVal = new OpalVal[DUVar[ValueInformation]](stmt.asAssignment.expr.asInstanceFunctionCall.receiver, this) + val opalVal = new OpalVal(stmt.asAssignment.expr.asInstanceFunctionCall.receiver, this) localCache.get.add(opalVal) } // Parameters of function call for (param <- stmt.asAssignment.expr.asFunctionCall.params) { if (param.isVar) { - localCache.get.add(new OpalVal[DUVar[ValueInformation]](param.asVar, this)) + localCache.get.add(new OpalVal(param.asVar, this)) } } } @@ -136,8 +132,8 @@ class OpalMethod(delegate: org.opalj.br.Method) extends Method { val locals = getLocals for (local <- locals.asScala) { if (local.isLocal) { - val opalVal = local.asInstanceOf[OpalVal[DUVar[ValueInformation]]] - val valDelegate = opalVal.getDelegate + val opalVal = local.asInstanceOf[OpalVal] + val valDelegate = opalVal.delegate if (valDelegate.isInstanceOf[UVar[_]]) { if (valDelegate.asVar.definedBy.head < 0) { @@ -157,14 +153,11 @@ class OpalMethod(delegate: org.opalj.br.Method) extends Method { override def getStatements: util.List[Statement] = cfg.getStatements - override def getDeclaringClass: WrappedClass = { - val declaredMethod = OpalClient.getDeclaredMethod(delegate) - new OpalWrappedClass(OpalClient.getClassFileForType(declaredMethod.declaringClassType)) - } + override def getDeclaringClass: WrappedClass = OpalWrappedClass(delegate.classFile) override def getControlFlowGraph: ControlFlowGraph = cfg - override def getSubSignature: String = delegate.signature.toString + override def getSubSignature: String = delegate.signature.toJava override def getName: String = delegate.name @@ -172,15 +165,50 @@ class OpalMethod(delegate: org.opalj.br.Method) extends Method { override def isPublic: Boolean = delegate.isPublic - override def hashCode(): Int = 31 + delegate.hashCode() + override def toString: String = delegate.toJava +} + +case class OpalPhantomMethod(declaringClassType: ObjectType, name: String, descriptor: MethodDescriptor, isStatic: Boolean) extends Method { + + override def isStaticInitializer: Boolean = name == "" + + override def isParameterLocal(value: Val): Boolean = false + + override def getParameterTypes: util.List[Type] = { + val result = new util.ArrayList[Type]() + + descriptor.parameterTypes.foreach(paramType => { + result.add(OpalType(paramType)) + }) - override def equals(obj: Any): Boolean = obj match { - case other: OpalMethod => this.delegate == other.getDelegate - case _ => false + result } - override def toString: String = delegate.toJava + override def getParameterType(index: Int): Type = OpalType(descriptor.parameterType(index)) + + override def isThisLocal(value: Val): Boolean = false + + override def getLocals: util.Set[Val] = throw new RuntimeException("Locals of phantom method are not available") + + override def getThisLocal: Val = throw new RuntimeException("this local of phantom method is not available") + + override def getParameterLocals: util.List[Val] = throw new RuntimeException("Parameter locals of phantom method are not available") + + override def isNative: Boolean = false + + override def getStatements: util.List[Statement] = new util.ArrayList[Statement]() + + override def getDeclaringClass: WrappedClass = OpalPhantomWrappedClass(declaringClassType) + + override def getControlFlowGraph: ControlFlowGraph = throw new RuntimeException("CFG of phantom method is not available") + + override def getSubSignature: String = MethodSignature(name, descriptor).toJava + + override def getName: String = name + + override def isConstructor: Boolean = name == "" - def getDelegate: org.opalj.br.Method = delegate + override def isPublic: Boolean = true + override def toString: String = "PHANTOM: " + getSubSignature } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalStatement.scala b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalStatement.scala index e814229ce..e420ac1f9 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalStatement.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalStatement.scala @@ -1,25 +1,45 @@ package boomerang.scene.opal import boomerang.scene.{Field, IfStatement, InvokeExpr, Pair, Statement, StaticFieldVal, Val} -import org.opalj.tac.{PrimitiveTypecastExpr, Stmt, Var} +import com.google.common.base.Joiner +import org.opalj.tac.{DUVar, PrimitiveTypecastExpr, Stmt} +import org.opalj.value.ValueInformation import java.util -class OpalStatement[+V <: Var[V]](delegate: Stmt[V], m: OpalMethod) extends Statement(m) { +class OpalStatement(val delegate: Stmt[DUVar[ValueInformation]], m: OpalMethod) extends Statement(m) { override def containsStaticFieldAccess(): Boolean = isStaticFieldLoad || isStaticFieldStore - override def containsInvokeExpr(): Boolean = isAssign && delegate.asAssignment.expr.isFunctionCall || delegate.isMethodCall + override def containsInvokeExpr(): Boolean = { + if (delegate.isMethodCall) return true + if (isAssign && delegate.asAssignment.expr.isFunctionCall) return true + if (delegate.isExprStmt && delegate.asExprStmt.isMethodCall) return true + if (delegate.isExprStmt && delegate.asExprStmt.expr.isFunctionCall) return true + + false + } + + override def getInvokeExpr: InvokeExpr = { + if (containsInvokeExpr()) { + if (delegate.isMethodCall) return new OpalMethodInvokeExpr(delegate.asMethodCall, m, delegate.pc) + if (isAssign && delegate.asAssignment.expr.isFunctionCall) return new OpalFunctionInvokeExpr(delegate.asAssignment.expr.asFunctionCall, m, delegate.pc) + if (delegate.isExprStmt && delegate.asExprStmt.isMethodCall) return new OpalMethodInvokeExpr(delegate.asExprStmt.asMethodCall, m, delegate.pc) + if (delegate.isExprStmt && delegate.asExprStmt.expr.isFunctionCall) return new OpalFunctionInvokeExpr(delegate.asExprStmt.expr.asFunctionCall, m, delegate.pc) + } + + throw new RuntimeException("Statement does not contain an invoke expression") + } override def getWrittenField: Field = { if (isFieldStore) { val resolvedField = OpalClient.resolveFieldStore(delegate.asPutField) - return new OpalField(resolvedField.get) + return OpalField(resolvedField.get) } if (isStaticFieldStore) { val resolvedField = OpalClient.resolveFieldStore(delegate.asPutStatic) - return new OpalField(resolvedField.get) + return OpalField(resolvedField.get) } if (isArrayStore) { @@ -47,7 +67,7 @@ class OpalStatement[+V <: Var[V]](delegate: Stmt[V], m: OpalMethod) extends Stat // TODO Also array? if (isFieldLoad) { val resolvedField = OpalClient.resolveFieldLoad(delegate.asAssignment.expr.asFieldRead) - return new OpalField(resolvedField.get) + return OpalField(resolvedField.get) } throw new RuntimeException("Statement is not a field load operation") @@ -66,7 +86,7 @@ class OpalStatement[+V <: Var[V]](delegate: Stmt[V], m: OpalMethod) extends Stat override def getLeftOp: Val = { if (isAssign) { - return new OpalVal[V](delegate.asAssignment.targetVar, m) + return new OpalVal(delegate.asAssignment.targetVar, m) } throw new RuntimeException("Statement is not an assignment") @@ -74,7 +94,7 @@ class OpalStatement[+V <: Var[V]](delegate: Stmt[V], m: OpalMethod) extends Stat override def getRightOp: Val = { if (isAssign) { - return new OpalVal[V](delegate.asAssignment.expr, m) + return new OpalVal(delegate.asAssignment.expr, m) } throw new RuntimeException("Statement is not an assignment") @@ -108,18 +128,6 @@ class OpalStatement[+V <: Var[V]](delegate: Stmt[V], m: OpalMethod) extends Stat override def isPhiStatement: Boolean = false - override def getInvokeExpr: InvokeExpr = { - if (containsInvokeExpr()) { - if (isAssign) { - return new OpalFunctionInvokeExpr[V](delegate.asAssignment.expr.asFunctionCall, m) - } else { - return new OpalMethodInvokeExpr[V](delegate.asMethodCall, m) - } - } - - throw new RuntimeException("Statement does not contain an invoke expression") - } - override def isReturnStmt: Boolean = delegate.isReturnValue override def isThrowStmt: Boolean = delegate.isThrow @@ -128,7 +136,7 @@ class OpalStatement[+V <: Var[V]](delegate: Stmt[V], m: OpalMethod) extends Stat override def getIfStmt: IfStatement = { if (isIfStmt) { - return new OpalIfStatement[V](delegate.asIf, m) + return new OpalIfStatement(delegate.asIf, m) } throw new RuntimeException("Statement is not an if-statement") @@ -136,13 +144,13 @@ class OpalStatement[+V <: Var[V]](delegate: Stmt[V], m: OpalMethod) extends Stat override def getReturnOp: Val = { if (isReturnStmt) { - return new OpalVal[V](delegate.asReturnValue.expr, m) + return new OpalVal(delegate.asReturnValue.expr, m) } throw new RuntimeException("Statement is not a return statement") } - override def isMultiArrayAllocation: Boolean = ??? + override def isMultiArrayAllocation: Boolean = false override def isStringAllocation: Boolean = { if (isAssign) { @@ -191,7 +199,7 @@ class OpalStatement[+V <: Var[V]](delegate: Stmt[V], m: OpalMethod) extends Stat val resolvedField = OpalClient.resolveFieldStore(delegate.asPutField).get val ref = delegate.asPutField.objRef - return new Pair(new OpalVal[V](ref, m), new OpalField(resolvedField)) + return new Pair(new OpalVal(ref, m), OpalField(resolvedField)) } throw new RuntimeException("Statement is not a field store operation") @@ -202,7 +210,7 @@ class OpalStatement[+V <: Var[V]](delegate: Stmt[V], m: OpalMethod) extends Stat val resolvedField = OpalClient.resolveFieldLoad(delegate.asAssignment.expr.asFieldRead).get val ref = delegate.asAssignment.expr.asGetField.objRef - return new Pair(new OpalVal[V](ref, m), new OpalField(resolvedField)) + return new Pair(new OpalVal(ref, m), OpalField(resolvedField)) } throw new RuntimeException("Statement is not a field load operation") @@ -233,19 +241,19 @@ class OpalStatement[+V <: Var[V]](delegate: Stmt[V], m: OpalMethod) extends Stat override def getStaticField: StaticFieldVal = { if (isStaticFieldLoad) { val resolvedField = OpalClient.resolveFieldLoad(delegate.asAssignment.expr.asGetStatic) - val staticField = new OpalField(resolvedField.get) + val staticField = OpalField(resolvedField.get) return new OpalStaticFieldVal(staticField, m) } if (isStaticFieldStore) { val resolvedField = OpalClient.resolveFieldStore(delegate.asPutStatic) - val staticField = new OpalField(resolvedField.get) + val staticField = OpalField(resolvedField.get) return new OpalStaticFieldVal(staticField, m) } - throw new RuntimeException("Statement is neither a static field load or store operation") + throw new RuntimeException("Statement is neither a static field load nor store operation") } override def killAtIfStmt(fact: Val, successor: Statement): Boolean = false @@ -265,24 +273,47 @@ class OpalStatement[+V <: Var[V]](delegate: Stmt[V], m: OpalMethod) extends Stat throw new RuntimeException("Statement has no array base") } - override def getStartLineNumber: Int = m.getDelegate.body.get.lineNumber(delegate.pc).getOrElse(-1) + override def getStartLineNumber: Int = m.delegate.body.get.lineNumber(delegate.pc).getOrElse(-1) - override def getStartColumnNumber: Int = getStartLineNumber() + override def getStartColumnNumber: Int = -1 - override def getEndLineNumber: Int = getStartLineNumber() + override def getEndLineNumber: Int = -1 - override def getEndColumnNumber: Int = getStartLineNumber() + override def getEndColumnNumber: Int = -1 override def isCatchStmt: Boolean = delegate.isCaughtException override def hashCode(): Int = 31 + delegate.hashCode() + private def canEqual(a: Any): Boolean = a.isInstanceOf[OpalStatement] + override def equals(obj: Any): Boolean = obj match { - case other: OpalStatement[_] => this.delegate == other.getDelegate + case other: OpalStatement => other.canEqual(this) && this.delegate.pc == other.delegate.pc case _ => false } - override def toString: String = delegate.toString + override def toString: String = { + if (containsInvokeExpr()) { + var base = "" + if (getInvokeExpr.isInstanceInvokeExpr) { + base = getInvokeExpr.getBase.toString + "." + } + var assign = "" + if (isAssign) { + assign = getLeftOp.toString + " = " + } + + return assign + base + getInvokeExpr.getMethod.getName + "(" + Joiner.on(",").join(getInvokeExpr.getArgs) + ")" + } + + if (isAssign) { + if (getRightOp.isNewExpr) { + return getLeftOp.toString + " = new " + getRightOp.getNewExprType.toString + } else { + return getLeftOp.toString + " = " + getRightOp.toString + } + } - def getDelegate: Stmt[V] = delegate + delegate.toString + } } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalStaticFieldVal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalStaticFieldVal.scala index 064013108..047a56a31 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalStaticFieldVal.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalStaticFieldVal.scala @@ -8,7 +8,7 @@ class OpalStaticFieldVal(field: OpalField, method: Method, unbalanced: ControlFl override def asUnbalanced(stmt: ControlFlowGraph.Edge): Val = new OpalStaticFieldVal(field, method, stmt) - override def getType: Type = new OpalType(field.getDelegate.fieldType) + override def getType: Type = OpalType(field.delegate.fieldType) override def isStatic: Boolean = true @@ -20,6 +20,8 @@ class OpalStaticFieldVal(field: OpalField, method: Method, unbalanced: ControlFl override def isArrayAllocationVal: Boolean = false + override def getArrayAllocationSize: Val = throw new RuntimeException("Static field is not an array allocation expression") + override def isNull: Boolean = false override def isStringConstant: Boolean = false diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalType.scala b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalType.scala index a30979659..409111be9 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalType.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalType.scala @@ -2,17 +2,29 @@ package boomerang.scene.opal import boomerang.scene.{AllocVal, Type, Val, WrappedClass} import org.opalj.br.ObjectType -class OpalType(delegate: org.opalj.br.Type) extends Type { +case class OpalType(delegate: org.opalj.br.Type, isNull: Boolean = false) extends Type { - override def isNullType: Boolean = false + override def isNullType: Boolean = isNull - override def isRefType: Boolean = delegate.isReferenceType + override def isRefType: Boolean = delegate.isObjectType override def isArrayType: Boolean = delegate.isArrayType - override def getArrayBaseType: Type = new OpalType(delegate.asArrayType) + override def getArrayBaseType: Type = OpalType(delegate.asArrayType) - override def getWrappedClass: WrappedClass = new OpalWrappedClass(OpalClient.getClassFileForType(delegate.asObjectType)) + override def getWrappedClass: WrappedClass = { + if (isRefType) { + val declaringClass = OpalClient.getClassFileForType(delegate.asObjectType) + + if (declaringClass.isDefined) { + OpalWrappedClass(declaringClass.get) + } else { + OpalPhantomWrappedClass(delegate.asReferenceType) + } + } + + throw new RuntimeException("Cannot compute declaring class because type is not a RefType") + } override def doesCastFail(targetValType: Type, target: Val): Boolean = { if (!isRefType || !targetValType.isRefType) { @@ -20,7 +32,7 @@ class OpalType(delegate: org.opalj.br.Type) extends Type { } val sourceType = delegate.asReferenceType - val targetType = targetValType.asInstanceOf[OpalType].getDelegate.asReferenceType + val targetType = targetValType.asInstanceOf[OpalType].delegate.asReferenceType target match { case allocVal: AllocVal if allocVal.getAllocVal.isNewExpr => OpalClient.getClassHierarchy.isSubtypeOf(sourceType, targetType) @@ -29,18 +41,23 @@ class OpalType(delegate: org.opalj.br.Type) extends Type { } } - override def isSubtypeOf(otherType: String): Boolean = OpalClient.getClassHierarchy.isSubtypeOf(delegate.asObjectType, ObjectType(otherType)) + override def isSubtypeOf(otherType: String): Boolean = { + if (!delegate.isObjectType) { + return false + } - override def isBooleanType: Boolean = delegate.isBooleanType + OpalClient.getClassHierarchy.isSubtypeOf(delegate.asObjectType, ObjectType(otherType)) + } - override def hashCode(): Int = 31 * delegate.hashCode() + override def isSupertypeOf(subType: String): Boolean = { + if (!delegate.isObjectType) { + return false + } - override def equals(obj: Any): Boolean = obj match { - case other: OpalType => this.delegate == other.getDelegate - case _ => false + OpalClient.getClassHierarchy.isSubtypeOf(ObjectType(subType), delegate.asObjectType) } - override def toString: String = delegate.toJava + override def isBooleanType: Boolean = delegate.isBooleanType - def getDelegate: org.opalj.br.Type = delegate + override def toString: String = delegate.toJava } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalVal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalVal.scala index 03100cd08..7abff2bbb 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalVal.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalVal.scala @@ -1,12 +1,42 @@ package boomerang.scene.opal import boomerang.scene.{ControlFlowGraph, Method, Pair, Type, Val} -import org.opalj.br.ReferenceType -import org.opalj.tac.{ArrayLength, Expr, InstanceOf, PrimitiveTypecastExpr, Var} +import org.opalj.br.{ObjectType, ReferenceType} +import org.opalj.tac.{ArrayLength, Const, DUVar, DVar, DefSites, Expr, FunctionCall, InstanceOf, IntConst, LongConst, New, PrimitiveTypecastExpr, StringConst, UVar} +import org.opalj.value.ValueInformation -class OpalVal[+V <: Var[V]](delegate: Expr[V], method: Method, edge: ControlFlowGraph.Edge = null) extends Val(method, edge) { +class OpalVal(val delegate: Expr[DUVar[ValueInformation]], method: OpalMethod, unbalanced: ControlFlowGraph.Edge = null) extends Val(method, unbalanced) { - override def getType: Type = ??? + override def getType: Type = delegate match { + case local : UVar[ValueInformation] => + if (local.value.isReferenceValue) { + OpalType(local.value.asReferenceValue.asReferenceType, local.value.asReferenceValue.isNull.isYes) + } else if (local.value.isPrimitiveValue) { + OpalType(local.value.asPrimitiveValue.primitiveType) + } else if (local.value.isVoid) { + OpalType(ObjectType.Void) + } else if (local.value.isArrayValue.isYes) { + OpalType(ObjectType.Array) + } else { + throw new RuntimeException("Could not determine type " + local.value) + } + case local: DUVar[ValueInformation] => + if (local.value.isReferenceValue) { + OpalType(local.value.asReferenceValue.asReferenceType, local.value.asReferenceValue.isNull.isYes) + } else if (local.value.isPrimitiveValue) { + OpalType(local.value.asPrimitiveValue.primitiveType) + } else if (local.value.isVoid) { + OpalType(ObjectType.Void) + } else if (local.value.isArrayValue.isYes) { + OpalType(ObjectType.Array) + } else { + throw new RuntimeException("Could not determine type " + local.value) + } + case const: Const => OpalType(const.tpe) + case newExpr: New => OpalType(newExpr.tpe) + case functionCall: FunctionCall[_] => OpalType(functionCall.descriptor.returnType) + case _ => throw new RuntimeException("Type not implemented yet") + } override def isStatic: Boolean = false @@ -14,18 +44,27 @@ class OpalVal[+V <: Var[V]](delegate: Expr[V], method: Method, edge: ControlFlow override def getNewExprType: Type = { if (isNewExpr) { - return new OpalType(delegate.asNew.tpe) + return OpalType(delegate.asNew.tpe) } throw new RuntimeException("Value is not a new expression") } - override def asUnbalanced(stmt: ControlFlowGraph.Edge): Val = new OpalVal[V](delegate, method, stmt) + override def asUnbalanced(stmt: ControlFlowGraph.Edge): Val = new OpalVal(delegate, method, stmt) override def isLocal: Boolean = delegate.isVar override def isArrayAllocationVal: Boolean = delegate.isNewArray + // TODO Deal with multiple arrays + override def getArrayAllocationSize: Val = { + if (isArrayAllocationVal) { + return new OpalVal(delegate.asNewArray.counts.head, method) + } + + throw new RuntimeException("Value is not an array allocation expression") + } + override def isNull: Boolean = delegate.isNullExpr override def isStringConstant: Boolean = delegate.isStringConst @@ -41,7 +80,7 @@ class OpalVal[+V <: Var[V]](delegate: Expr[V], method: Method, edge: ControlFlow override def isStringBufferOrBuilder: Boolean = { val thisType = getType - thisType.toString.equals("java.lang.String") || thisType.toString.equals("java.lang.StringBuilder") || thisType.toString.equals("java.lang.StringBuffer") + thisType.toString.equals("java/lang/String") || thisType.toString.equals("java/lang/StringBuilder") || thisType.toString.equals("java/lang/StringBuffer") } override def isThrowableAllocationType: Boolean = { @@ -51,7 +90,7 @@ class OpalVal[+V <: Var[V]](delegate: Expr[V], method: Method, edge: ControlFlow return false } - val opalType = thisType.asInstanceOf[OpalType].getDelegate + val opalType = thisType.asInstanceOf[OpalType].delegate OpalClient.getClassHierarchy.isSubtypeOf(opalType.asReferenceType, ReferenceType("java/lang/Throwable")) } @@ -59,19 +98,22 @@ class OpalVal[+V <: Var[V]](delegate: Expr[V], method: Method, edge: ControlFlow override def getCastOp: Val = { if (isCast) { - return new OpalVal[V](delegate.asPrimitiveTypeCastExpr.operand, method) + return new OpalVal(delegate.asPrimitiveTypeCastExpr.operand, method) } throw new RuntimeException("Expression is not a cast expression") } - override def isArrayRef: Boolean = ??? + override def isArrayRef: Boolean = delegate match { + case ref: UVar[ValueInformation] => ref.value.isArrayValue.isYes + case _ => false + } override def isInstanceOfExpr: Boolean = delegate.astID == InstanceOf.ASTID override def getInstanceOfOp: Val = { if (isInstanceOfExpr) { - return new OpalVal[V](delegate.asInstanceOf.value, method) + return new OpalVal(delegate.asInstanceOf.value, method) } throw new RuntimeException("Expression is not an instanceOf expression") @@ -81,7 +123,7 @@ class OpalVal[+V <: Var[V]](delegate: Expr[V], method: Method, edge: ControlFlow override def getLengthOp: Val = { if (isLengthExpr) { - return new OpalVal[V](delegate.asArrayLength, method) + return new OpalVal(delegate.asArrayLength, method) } throw new RuntimeException("Value is not a length expression") @@ -93,15 +135,15 @@ class OpalVal[+V <: Var[V]](delegate: Expr[V], method: Method, edge: ControlFlow override def getClassConstantType: Type = { if (isClassConstant) { - return new OpalType(delegate.asClassConst.value) + return OpalType(delegate.asClassConst.value) } throw new RuntimeException("Value is not a class constant") } - override def withNewMethod(callee: Method): Val = new OpalVal[V](delegate, callee) + override def withNewMethod(callee: Method): Val = new OpalVal(delegate, callee.asInstanceOf[OpalMethod]) - override def withSecondVal(secondVal: Val) = new OpalDoubleVal[V](delegate, method, secondVal) + override def withSecondVal(secondVal: Val) = new OpalDoubleVal(delegate, method, secondVal) override def isLongConstant: Boolean = delegate.isLongConst @@ -121,18 +163,75 @@ class OpalVal[+V <: Var[V]](delegate: Expr[V], method: Method, edge: ControlFlow throw new RuntimeException("Value is not a long constant") } - override def getArrayBase: Pair[Val, Integer] = ??? + override def getArrayBase: Pair[Val, Integer] = { + if (isArrayRef) { + // TODO + } + + throw new RuntimeException("Value is not an array ref") + } override def getVariableName: String = delegate.toString - override def hashCode(): Int = 31 * delegate.hashCode() + override def hashCode(): Int = delegate match { + case uVar: UVar[_] => + // UVars should reference their DVar to keep the comparisons consistent + val tac = OpalClient.getTacForMethod(method.delegate) + val defStmt = tac.stmts(uVar.definedBy.head) + + if (!defStmt.isAssignment) { + return 31 * super.hashCode() + delegate.hashCode() + } + + val targetVar = defStmt.asAssignment.targetVar + 31 * super.hashCode() + targetVar.hashCode() + case _ => 31 * super.hashCode() + delegate.hashCode() + } + + private def canEqual(a: Any): Boolean = a.isInstanceOf[OpalVal] override def equals(obj: Any): Boolean = obj match { - case other: OpalVal[_] => this.delegate == other.getDelegate + case other: OpalVal => + // DVar does not implement a proper equals() method, so we have to compare the hash codes + this.delegate match { + case _: DVar[_] if other.delegate.isInstanceOf[DVar[_]] => + super.equals(other) && this.delegate.hashCode() == other.delegate.hashCode() + case uVar: UVar[_] if other.delegate.isInstanceOf[DVar[_]] => + val tac = OpalClient.getTacForMethod(method.delegate) + val defStmt = tac.stmts(uVar.definedBy.head) + + if (!defStmt.isAssignment) { + return false + } + + val targetVar = defStmt.asAssignment.targetVar + val otherVar = other.delegate.asInstanceOf[DVar[ValueInformation]] + super.equals(other) && targetVar.hashCode() == otherVar.hashCode() + case dVar: DVar[_] if other.delegate.isInstanceOf[UVar[_]] => + val otherVar = other.delegate.asInstanceOf[UVar[ValueInformation]] + val tac = OpalClient.getTacForMethod(method.delegate) + val defStmt = tac.stmts(otherVar.definedBy.head) + + if (!defStmt.isAssignment) { + return false + } + + val targetVar = defStmt.asAssignment.targetVar + super.equals(other) && dVar.hashCode() == targetVar.hashCode() + case _ => + other.canEqual(this) && super.equals(other) && this.delegate == other.delegate + } case _ => false } - override def toString: String = delegate.toString - - def getDelegate: Expr[V] = delegate + override def toString: String = { + delegate match { + case _: DVar[_] => "var" // TODO Add origin + case uVar: UVar[_] => "var" + uVar.definedBy.head + case stringConst: StringConst => "\"" + stringConst.value + "\"" + case intConst: IntConst => intConst.value.toString + case longConst: LongConst => longConst.value.toString + case _ => delegate.toString + } + } } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalWrappedClass.scala b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalWrappedClass.scala index 73814f49c..6329e02c1 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalWrappedClass.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalWrappedClass.scala @@ -1,20 +1,18 @@ package boomerang.scene.opal import boomerang.scene.{Method, Type, WrappedClass} -import org.opalj.br.ClassFile +import org.opalj.br.{ClassFile, ReferenceType} import java.util -class OpalWrappedClass(delegate: ClassFile) extends WrappedClass { +case class OpalWrappedClass(delegate: ClassFile) extends WrappedClass { override def getMethods: util.Set[Method] = { val methods = new util.HashSet[Method] - for (method <- delegate.methods) { - if (method.body.isDefined) { - methods.add(new OpalMethod(method)) - } - } + delegate.methods.foreach(method => { + methods.add(OpalMethod(method)) + }) methods } @@ -22,27 +20,50 @@ class OpalWrappedClass(delegate: ClassFile) extends WrappedClass { override def hasSuperclass: Boolean = delegate.superclassType.isDefined override def getSuperclass: WrappedClass = { - val superClass = OpalClient.getClassFileForType(delegate.superclassType.get) + if (hasSuperclass) { + val superClass = OpalClient.getClassFileForType(delegate.superclassType.get) + + if (superClass.isDefined) { + return OpalWrappedClass(superClass.get) + } else { + return OpalPhantomWrappedClass(delegate.superclassType.get) + } + } - new OpalWrappedClass(superClass) + throw new RuntimeException("Class " + delegate.thisType.toJava + " has no super class") } - override def getType: Type = new OpalType(delegate.thisType) + override def getType: Type = OpalType(delegate.thisType) override def isApplicationClass: Boolean = OpalClient.isApplicationClass(delegate) - override def getFullyQualifiedName: String = delegate.classSignature.get.toString() + override def getFullyQualifiedName: String = delegate.fqn - override def getName: String = delegate.classSignature.get.toString() + override def getName: String = delegate.thisType.toJava - override def hashCode(): Int = 31 * delegate.hashCode() + override def toString: String = delegate.toString() - override def equals(obj: Any): Boolean = obj match { - case other: OpalWrappedClass => this.delegate == other.getDelegate - case _ => false - } + override def getDelegate: AnyRef = delegate +} - override def toString: String = delegate.toString() +case class OpalPhantomWrappedClass(delegate: ReferenceType) extends WrappedClass { + + override def getMethods: util.Set[Method] = throw new RuntimeException("Methods of class " + delegate.toString + " are not available") + + override def hasSuperclass: Boolean = false + + override def getSuperclass: WrappedClass = throw new RuntimeException("Super class of " + delegate.toString + " is not available") + + override def getType: Type = OpalType(delegate) + + override def isApplicationClass: Boolean = false + + override def getFullyQualifiedName: String = delegate.toJava + + override def getName: String = delegate.toJava override def getDelegate: AnyRef = delegate + + override def toString: String = delegate.toString + } diff --git a/boomerangScope-SootUp/pom.xml b/boomerangScope-SootUp/pom.xml index 1d1869247..dd1cab3af 100644 --- a/boomerangScope-SootUp/pom.xml +++ b/boomerangScope-SootUp/pom.xml @@ -6,7 +6,7 @@ de.fraunhofer.iem SPDS - 3.1.2-Sparse + 3.2.1 ../pom.xml diff --git a/boomerangScope-SootUp/src/main/java/boomerang/scene/sootup/JimpleUpDeclaredMethod.java b/boomerangScope-SootUp/src/main/java/boomerang/scene/sootup/JimpleUpDeclaredMethod.java index 68b52647c..95bb91334 100644 --- a/boomerangScope-SootUp/src/main/java/boomerang/scene/sootup/JimpleUpDeclaredMethod.java +++ b/boomerangScope-SootUp/src/main/java/boomerang/scene/sootup/JimpleUpDeclaredMethod.java @@ -1,9 +1,11 @@ package boomerang.scene.sootup; import boomerang.scene.DeclaredMethod; -import boomerang.scene.Method; +import boomerang.scene.Type; import boomerang.scene.WrappedClass; +import java.util.ArrayList; import java.util.Arrays; +import java.util.List; import sootup.java.core.JavaSootClass; import sootup.java.core.JavaSootMethod; @@ -51,11 +53,6 @@ public String getSignature() { return delegate.getSignature().toString(); } - @Override - public Method getCalledMethod() { - return JimpleUpMethod.of(delegate); - } - @Override public WrappedClass getDeclaringClass() { JavaSootClass sootClass = @@ -63,6 +60,22 @@ public WrappedClass getDeclaringClass() { return new JimpleUpWrappedClass(sootClass); } + @Override + public List getParameterTypes() { + List result = new ArrayList<>(); + + for (sootup.core.types.Type type : delegate.getParameterTypes()) { + result.add(new JimpleUpType(type)); + } + + return result; + } + + @Override + public Type getParameterType(int index) { + return new JimpleUpType(delegate.getParameterType(index)); + } + @Override public int hashCode() { return Arrays.hashCode(new Object[] {delegate}); diff --git a/boomerangScope-SootUp/src/main/java/boomerang/scene/sootup/JimpleUpStaticFieldVal.java b/boomerangScope-SootUp/src/main/java/boomerang/scene/sootup/JimpleUpStaticFieldVal.java index dd0f8ff5e..244e08669 100644 --- a/boomerangScope-SootUp/src/main/java/boomerang/scene/sootup/JimpleUpStaticFieldVal.java +++ b/boomerangScope-SootUp/src/main/java/boomerang/scene/sootup/JimpleUpStaticFieldVal.java @@ -64,6 +64,11 @@ public boolean isArrayAllocationVal() { return false; } + @Override + public Val getArrayAllocationSize() { + throw new RuntimeException("Static field val is not an array allocation expression"); + } + @Override public boolean isNull() { return false; diff --git a/boomerangScope-SootUp/src/main/java/boomerang/scene/sootup/JimpleUpType.java b/boomerangScope-SootUp/src/main/java/boomerang/scene/sootup/JimpleUpType.java index cd14674c4..f31ac5e1b 100644 --- a/boomerangScope-SootUp/src/main/java/boomerang/scene/sootup/JimpleUpType.java +++ b/boomerangScope-SootUp/src/main/java/boomerang/scene/sootup/JimpleUpType.java @@ -77,6 +77,11 @@ public boolean doesCastFail(Type targetVal, Val target) { return !castFails; } + @Override + public boolean isSupertypeOf(String subType) { + throw new RuntimeException("Not implemented"); + } + @Override public boolean isSubtypeOf(String type) { if (delegate.toString().equals(type)) return true; diff --git a/boomerangScope-SootUp/src/main/java/boomerang/scene/sootup/JimpleUpVal.java b/boomerangScope-SootUp/src/main/java/boomerang/scene/sootup/JimpleUpVal.java index 6afb356b6..b501cf6cb 100644 --- a/boomerangScope-SootUp/src/main/java/boomerang/scene/sootup/JimpleUpVal.java +++ b/boomerangScope-SootUp/src/main/java/boomerang/scene/sootup/JimpleUpVal.java @@ -81,6 +81,17 @@ public boolean isArrayAllocationVal() { return delegate instanceof JNewArrayExpr || delegate instanceof JNewMultiArrayExpr; } + @Override + public Val getArrayAllocationSize() { + if (delegate instanceof JNewArrayExpr) { + JNewArrayExpr expr = (JNewArrayExpr) delegate; + + return new JimpleUpVal(expr.getSize(), method); + } + + throw new RuntimeException("Val is not an array allocation expression"); + } + @Override public boolean isNull() { return delegate instanceof NullConstant; diff --git a/boomerangScope-WALA/src/main/java/boomerang/scene/wala/WALADeclaredMethod.java b/boomerangScope-WALA/src/main/java/boomerang/scene/wala/WALADeclaredMethod.java index d459f1d2e..b075cf150 100644 --- a/boomerangScope-WALA/src/main/java/boomerang/scene/wala/WALADeclaredMethod.java +++ b/boomerangScope-WALA/src/main/java/boomerang/scene/wala/WALADeclaredMethod.java @@ -13,9 +13,10 @@ import boomerang.scene.DeclaredMethod; import boomerang.scene.InvokeExpr; -import boomerang.scene.Method; +import boomerang.scene.Type; import boomerang.scene.WrappedClass; import com.ibm.wala.types.MethodReference; +import java.util.List; public class WALADeclaredMethod extends DeclaredMethod { @@ -59,13 +60,18 @@ public String getSignature() { } @Override - public Method getCalledMethod() { + public WrappedClass getDeclaringClass() { + return new WALAClass(delegate.getDeclaringClass()); + } + + @Override + public List getParameterTypes() { throw new RuntimeException("Not implemented"); } @Override - public WrappedClass getDeclaringClass() { - return new WALAClass(delegate.getDeclaringClass()); + public Type getParameterType(int index) { + throw new RuntimeException("Not implemented"); } @Override diff --git a/boomerangScope-WALA/src/main/java/boomerang/scene/wala/WALAStaticFieldVal.java b/boomerangScope-WALA/src/main/java/boomerang/scene/wala/WALAStaticFieldVal.java index f2ce73127..c02d62539 100644 --- a/boomerangScope-WALA/src/main/java/boomerang/scene/wala/WALAStaticFieldVal.java +++ b/boomerangScope-WALA/src/main/java/boomerang/scene/wala/WALAStaticFieldVal.java @@ -72,6 +72,11 @@ public boolean isArrayAllocationVal() { return false; } + @Override + public Val getArrayAllocationSize() { + throw new RuntimeException("Fault!"); + } + @Override public boolean isNull() { return false; diff --git a/boomerangScope-WALA/src/main/java/boomerang/scene/wala/WALAType.java b/boomerangScope-WALA/src/main/java/boomerang/scene/wala/WALAType.java index 3a031c128..1f71c2c14 100644 --- a/boomerangScope-WALA/src/main/java/boomerang/scene/wala/WALAType.java +++ b/boomerangScope-WALA/src/main/java/boomerang/scene/wala/WALAType.java @@ -80,6 +80,10 @@ private boolean isSubclassOf(WALAType targetType) { return meet.equals(typeAbstraction); } + public boolean isSupertypeOf(String subType) { + throw new RuntimeException("Not implemented"); + } + private TypeAbstraction getDelegate() { return typeAbstraction; } diff --git a/boomerangScope-WALA/src/main/java/boomerang/scene/wala/WALAVal.java b/boomerangScope-WALA/src/main/java/boomerang/scene/wala/WALAVal.java index 6857be8aa..1dae6869c 100644 --- a/boomerangScope-WALA/src/main/java/boomerang/scene/wala/WALAVal.java +++ b/boomerangScope-WALA/src/main/java/boomerang/scene/wala/WALAVal.java @@ -146,6 +146,11 @@ public boolean isArrayAllocationVal() { return false; } + @Override + public Val getArrayAllocationSize() { + throw new RuntimeException("Not implemented"); + } + @Override public boolean isNull() { return symbolTable != null diff --git a/boomerangScope/src/main/java/boomerang/scene/AllocVal.java b/boomerangScope/src/main/java/boomerang/scene/AllocVal.java index 6dd4bec01..9047590c4 100644 --- a/boomerangScope/src/main/java/boomerang/scene/AllocVal.java +++ b/boomerangScope/src/main/java/boomerang/scene/AllocVal.java @@ -64,6 +64,10 @@ public boolean isArrayAllocationVal() { return delegate.isArrayAllocationVal(); } + public Val getArrayAllocationSize() { + return delegate.getArrayAllocationSize(); + } + public boolean isNull() { return allocationVal.isNull(); } diff --git a/boomerangScope/src/main/java/boomerang/scene/DeclaredMethod.java b/boomerangScope/src/main/java/boomerang/scene/DeclaredMethod.java index 3d2646551..e88a7a8d1 100644 --- a/boomerangScope/src/main/java/boomerang/scene/DeclaredMethod.java +++ b/boomerangScope/src/main/java/boomerang/scene/DeclaredMethod.java @@ -1,8 +1,10 @@ package boomerang.scene; +import java.util.List; + public abstract class DeclaredMethod { - private InvokeExpr inv; + private final InvokeExpr inv; public DeclaredMethod(InvokeExpr inv) { this.inv = inv; @@ -20,10 +22,12 @@ public DeclaredMethod(InvokeExpr inv) { public abstract String getSignature(); - public abstract Method getCalledMethod(); - public abstract WrappedClass getDeclaringClass(); + public abstract List getParameterTypes(); + + public abstract Type getParameterType(int index); + public InvokeExpr getInvokeExpr() { return inv; } diff --git a/boomerangScope/src/main/java/boomerang/scene/Type.java b/boomerangScope/src/main/java/boomerang/scene/Type.java index 38d15e86d..5f1059b53 100644 --- a/boomerangScope/src/main/java/boomerang/scene/Type.java +++ b/boomerangScope/src/main/java/boomerang/scene/Type.java @@ -16,5 +16,7 @@ public interface Type { boolean isSubtypeOf(String type); + boolean isSupertypeOf(String subType); + boolean isBooleanType(); } diff --git a/boomerangScope/src/main/java/boomerang/scene/Val.java b/boomerangScope/src/main/java/boomerang/scene/Val.java index 0d30553df..1cd206f5c 100644 --- a/boomerangScope/src/main/java/boomerang/scene/Val.java +++ b/boomerangScope/src/main/java/boomerang/scene/Val.java @@ -60,133 +60,116 @@ public static Val zero() { @Override public Type getType() { - // TODO Auto-generated method stub return null; } @Override public boolean isStatic() { - // TODO Auto-generated method stub return false; } @Override public boolean isNewExpr() { - // TODO Auto-generated method stub return false; } @Override public Type getNewExprType() { - // TODO Auto-generated method stub return null; } @Override public Val asUnbalanced(ControlFlowGraph.Edge stmt) { - // TODO Auto-generated method stub return null; } @Override public boolean isLocal() { - // TODO Auto-generated method stub return false; } @Override public boolean isArrayAllocationVal() { - // TODO Auto-generated method stub return false; } + @Override + public Val getArrayAllocationSize() { + return null; + } + @Override public boolean isNull() { - // TODO Auto-generated method stub return false; } @Override public boolean isStringConstant() { - // TODO Auto-generated method stub return false; } @Override public String getStringValue() { - // TODO Auto-generated method stub return null; } @Override public boolean isStringBufferOrBuilder() { - // TODO Auto-generated method stub return false; } @Override public boolean isThrowableAllocationType() { - // TODO Auto-generated method stub return false; } @Override public boolean isCast() { - // TODO Auto-generated method stub return false; } @Override public Val getCastOp() { - // TODO Auto-generated method stub return null; } @Override public boolean isArrayRef() { - // TODO Auto-generated method stub return false; } @Override public boolean isInstanceOfExpr() { - // TODO Auto-generated method stub return false; } @Override public Val getInstanceOfOp() { - // TODO Auto-generated method stub return null; } @Override public boolean isLengthExpr() { - // TODO Auto-generated method stub return false; } @Override public Val getLengthOp() { - // TODO Auto-generated method stub return null; } @Override public boolean isIntConstant() { - // TODO Auto-generated method stub return false; } @Override public boolean isClassConstant() { - // TODO Auto-generated method stub return false; } @Override public Type getClassConstantType() { - // TODO Auto-generated method stub return null; } @@ -197,25 +180,21 @@ public Val withNewMethod(Method callee) { @Override public boolean isLongConstant() { - // TODO Auto-generated method stub return false; } @Override public int getIntValue() { - // TODO Auto-generated method stub return 0; } @Override public long getLongValue() { - // TODO Auto-generated method stub return 0; } @Override public Pair getArrayBase() { - // TODO Auto-generated method stub return null; } @@ -241,8 +220,11 @@ public boolean isUnbalanced() { public abstract boolean isLocal(); + // TODO Distinguish between single arrays and multi arrays public abstract boolean isArrayAllocationVal(); + public abstract Val getArrayAllocationSize(); + public abstract boolean isNull(); public abstract boolean isStringConstant(); diff --git a/boomerangScope/src/main/java/boomerang/scene/jimple/JimpleDeclaredMethod.java b/boomerangScope/src/main/java/boomerang/scene/jimple/JimpleDeclaredMethod.java index 90188b49b..8396d9ea2 100644 --- a/boomerangScope/src/main/java/boomerang/scene/jimple/JimpleDeclaredMethod.java +++ b/boomerangScope/src/main/java/boomerang/scene/jimple/JimpleDeclaredMethod.java @@ -2,8 +2,10 @@ import boomerang.scene.DeclaredMethod; import boomerang.scene.InvokeExpr; -import boomerang.scene.Method; +import boomerang.scene.Type; import boomerang.scene.WrappedClass; +import java.util.ArrayList; +import java.util.List; import soot.SootMethod; public class JimpleDeclaredMethod extends DeclaredMethod { @@ -71,13 +73,23 @@ public String getSignature() { } @Override - public Method getCalledMethod() { - return JimpleMethod.of(delegate); + public WrappedClass getDeclaringClass() { + return new JimpleWrappedClass(delegate.getDeclaringClass()); } @Override - public WrappedClass getDeclaringClass() { - return new JimpleWrappedClass(delegate.getDeclaringClass()); + public List getParameterTypes() { + List types = new ArrayList<>(); + + for (soot.Type type : delegate.getParameterTypes()) { + types.add(new JimpleType(type)); + } + return types; + } + + @Override + public Type getParameterType(int index) { + return new JimpleType(delegate.getParameterType(index)); } public Object getDelegate() { diff --git a/boomerangScope/src/main/java/boomerang/scene/jimple/JimpleStaticFieldVal.java b/boomerangScope/src/main/java/boomerang/scene/jimple/JimpleStaticFieldVal.java index b3fb82529..f9dfcc521 100644 --- a/boomerangScope/src/main/java/boomerang/scene/jimple/JimpleStaticFieldVal.java +++ b/boomerangScope/src/main/java/boomerang/scene/jimple/JimpleStaticFieldVal.java @@ -75,6 +75,11 @@ public boolean isArrayAllocationVal() { return false; } + @Override + public Val getArrayAllocationSize() { + throw new RuntimeException("Fault!"); + } + @Override public boolean isNull() { return false; diff --git a/boomerangScope/src/main/java/boomerang/scene/jimple/JimpleType.java b/boomerangScope/src/main/java/boomerang/scene/jimple/JimpleType.java index c98a0b16b..363a3004e 100644 --- a/boomerangScope/src/main/java/boomerang/scene/jimple/JimpleType.java +++ b/boomerangScope/src/main/java/boomerang/scene/jimple/JimpleType.java @@ -4,6 +4,9 @@ import boomerang.scene.Type; import boomerang.scene.Val; import boomerang.scene.WrappedClass; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; import soot.ArrayType; import soot.BooleanType; import soot.NullType; @@ -14,7 +17,7 @@ public class JimpleType implements Type { - private soot.Type delegate; + private final soot.Type delegate; public JimpleType(soot.Type type) { this.delegate = type; @@ -97,6 +100,48 @@ public boolean isSubtypeOf(String type) { .contains(allocatedType.getSootClass()); } + @Override + public boolean isSupertypeOf(String subType) { + if (!(delegate instanceof RefType)) { + if (delegate instanceof PrimType) { + return subType.equals(delegate.toString()); + } + return false; + } + + if (!Scene.v().containsClass(subType)) { + return false; + } + + RefType thisType = (RefType) delegate; + if (!thisType.hasSootClass()) { + return false; + } + + SootClass thisClass = thisType.getSootClass(); + SootClass subClass = Scene.v().getSootClass(subType); + + Collection hierarchy = getFullHierarchy(subClass, new HashSet<>()); + return hierarchy.contains(thisClass); + + /*if (thisClass.equals(subClass)) { + return true; + } + + if (thisClass.isInterface()) { + if (subClass.isInterface()) { + return Scene.v().getActiveHierarchy().getSuperinterfacesOfIncluding(subClass).contains(thisClass); + } else { + return Scene.v().getActiveHierarchy().getSubinterfacesOfIncluding(thisClass).contains(thisClass); + } + } else { + return Scene.v() + .getActiveHierarchy() + .getSuperclassesOfIncluding(subClass) + .contains(thisClass); + }*/ + } + @Override public int hashCode() { final int prime = 31; @@ -121,4 +166,41 @@ public boolean equals(Object obj) { public String toString() { return delegate.toString(); } + + private Collection getFullHierarchy(SootClass sourceClass, Set visited) { + Set result = new HashSet<>(); + + if (visited.contains(sourceClass)) { + return result; + } + + result.add(sourceClass); + visited.add(sourceClass); + + // Super interfaces + Collection interfaces = sourceClass.getInterfaces(); + for (SootClass intFace : interfaces) { + result.addAll(getFullHierarchy(intFace, visited)); + } + + if (sourceClass.isInterface()) { + // Super interfaces + Collection superInterfaces = + Scene.v().getActiveHierarchy().getSuperinterfacesOf(sourceClass); + + for (SootClass superInterface : superInterfaces) { + result.addAll(getFullHierarchy(superInterface, visited)); + } + } else { + // Super classes + Collection superClasses = + Scene.v().getActiveHierarchy().getSuperclassesOf(sourceClass); + + for (SootClass superClass : superClasses) { + result.addAll(getFullHierarchy(superClass, visited)); + } + } + + return result; + } } diff --git a/boomerangScope/src/main/java/boomerang/scene/jimple/JimpleVal.java b/boomerangScope/src/main/java/boomerang/scene/jimple/JimpleVal.java index eb8413263..9acde4378 100644 --- a/boomerangScope/src/main/java/boomerang/scene/jimple/JimpleVal.java +++ b/boomerangScope/src/main/java/boomerang/scene/jimple/JimpleVal.java @@ -99,6 +99,16 @@ public boolean isArrayAllocationVal() { return false; } + public Val getArrayAllocationSize() { + if (v instanceof NewArrayExpr) { + NewArrayExpr expr = (NewArrayExpr) v; + + return new JimpleVal(expr.getSize(), m); + } + + throw new RuntimeException("Val is not an array allocation expression"); + } + public boolean isNull() { return v instanceof NullConstant; } diff --git a/pom.xml b/pom.xml index 91e10e734..34a82990c 100644 --- a/pom.xml +++ b/pom.xml @@ -215,6 +215,14 @@ + + + org.scala-lang + scala-library + 2.13.14 + + + ossrh From db362bdb44508aaeea86fce3626957959e63bce0 Mon Sep 17 00:00:00 2001 From: Sven Meyer Date: Fri, 1 Nov 2024 17:30:05 +0100 Subject: [PATCH 06/61] Split Val into Local and ArrayRef --- .../src/main/scala/boomerang/scene/Main.scala | 20 ++- .../boomerang/scene/opal/OpalArrayRef.scala | 88 ++++++++++ .../boomerang/scene/opal/OpalClient.scala | 4 +- .../scene/opal/OpalIfStatement.scala | 4 + .../boomerang/scene/opal/OpalInvokeExpr.scala | 13 +- .../boomerang/scene/opal/OpalLocal.scala | 157 ++++++++++++++++++ .../boomerang/scene/opal/OpalMethod.scala | 26 +-- .../boomerang/scene/opal/OpalStatement.scala | 104 +++++++++--- .../scene/opal/OpalStaticFieldVal.scala | 6 + .../scala/boomerang/scene/opal/OpalVal.scala | 114 +++---------- 10 files changed, 391 insertions(+), 145 deletions(-) create mode 100644 boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalArrayRef.scala create mode 100644 boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalLocal.scala diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scene/Main.scala b/boomerangScope-Opal/src/main/scala/boomerang/scene/Main.scala index becadc7cf..7cb23692a 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scene/Main.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scene/Main.scala @@ -1,6 +1,6 @@ package boomerang.scene -import boomerang.scene.opal.{OpalCallGraph, OpalClient} +import boomerang.scene.opal.{OpalCallGraph, OpalClient, OpalMethod} import com.typesafe.config.ConfigValueFactory import org.opalj.br.analyses.Project import org.opalj.br.analyses.cg.InitialEntryPointsKey @@ -14,10 +14,11 @@ object Main { def main(args: Array[String]): Unit = { OPALLogger.updateLogger(GlobalLogContext, DevNullLogger) - val project = Project(new File("C:\\Users\\Sven\\Documents\\CogniCrypt\\Opal\\MultipleCalls\\Main.jar")) + val project = Project(new File("C:\\Users\\Sven\\Documents\\CogniCrypt\\Opal\\Array\\Array.jar")) var config = project.config val key = s"${InitialEntryPointsKey.ConfigKeyPrefix}entryPoints" + println("InitialEntryPoints " + key) val currentValues = project.config.getList(key).unwrapped() val allMethods = project.allMethodsWithBody @@ -40,15 +41,18 @@ object Main { val entryPoints = newProject.get(InitialEntryPointsKey) println("Entry Points: " + entryPoints.size) - callGraph.reachableMethods().foreach(method => { - println(method.method) - }) - OpalClient.init(newProject) val opalCallGraph = new OpalCallGraph(callGraph, entryPoints.toSet) - opalCallGraph.getEdges.forEach(edge => { - println(edge) + opalCallGraph.getReachableMethods.forEach(method => { + if (method.isInstanceOf[OpalMethod]) { + val locals = method.getLocals + println("Locals in " + method + ": " + locals) + } + + method.getStatements.forEach(statement => { + + }) }) } } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalArrayRef.scala b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalArrayRef.scala new file mode 100644 index 000000000..a8a62dcc6 --- /dev/null +++ b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalArrayRef.scala @@ -0,0 +1,88 @@ +package boomerang.scene.opal + +import boomerang.scene.{ControlFlowGraph, Method, Pair, Type, Val} +import org.opalj.br.ObjectType +import org.opalj.tac.{DUVar, DVar, Expr, UVar} +import org.opalj.value.ValueInformation + +class OpalArrayRef(val arrayRef: Expr[DUVar[ValueInformation]], val index: Int, method: OpalMethod, unbalanced: ControlFlowGraph.Edge = null) extends Val(method, unbalanced) { + + if (!arrayRef.isVar) { + throw new RuntimeException("Array Ref has to be a variable") + } + + // TODO Type + override def getType: Type = OpalType(ObjectType.Array) + + override def isStatic: Boolean = false + + override def isNewExpr: Boolean = false + + override def getNewExprType: Type = throw new RuntimeException("Array Value is not a new expression") + + override def asUnbalanced(stmt: ControlFlowGraph.Edge): Val = new OpalArrayRef(arrayRef, index, method, stmt) + + override def isLocal: Boolean = true + + override def isArrayAllocationVal: Boolean = false + + override def getArrayAllocationSize: Val = throw new RuntimeException("Array Value has no allocation size") + + override def isNull: Boolean = false + + override def isStringConstant: Boolean = false + + override def getStringValue: String = throw new RuntimeException("Array Value is not a String constant") + + override def isStringBufferOrBuilder: Boolean = false + + override def isThrowableAllocationType: Boolean = false + + override def isCast: Boolean = false + + override def getCastOp: Val = throw new RuntimeException("Array Value is not a cast operation") + + override def isArrayRef: Boolean = true + + override def isInstanceOfExpr: Boolean = false + + override def getInstanceOfOp: Val = throw new RuntimeException("Array Value is not an instance of operation") + + override def isLengthExpr: Boolean = false + + override def getLengthOp: Val = throw new RuntimeException("Array Value is not a length operation") + + override def isIntConstant: Boolean = false + + override def isClassConstant: Boolean = false + + override def getClassConstantType: Type = throw new RuntimeException("Array Value is not a class constant") + + override def withNewMethod(callee: Method): Val = new OpalArrayRef(arrayRef, index, callee.asInstanceOf[OpalMethod]) + + override def isLongConstant: Boolean = false + + override def getIntValue: Int = throw new RuntimeException("Array Value is not an integer constant") + + override def getLongValue: Long = throw new RuntimeException("Array Value is not a long constant") + + override def getArrayBase: Pair[Val, Integer] = { + val base = new OpalLocal(arrayRef, method) + + new Pair[Val, Integer](base, index) + } + + override def getVariableName: String = { + arrayRef match { + case dVar: DVar[_] => s"var${}[$index]" // TODO insert origin + case uVar: UVar[_] => s"var${uVar.definedBy.head}[$index]" + case _ => arrayRef.toString + } + } + + override def hashCode(): Int = ??? + + override def equals(obj: Any): Boolean = ??? + + override def toString: String = getVariableName +} diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalClient.scala b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalClient.scala index f38e59ada..31efa6b9c 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalClient.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalClient.scala @@ -1,6 +1,6 @@ package boomerang.scene.opal -import org.opalj.br.{ClassFile, ClassHierarchy, DeclaredMethod, DefinedMethod, Field, Method, MethodDescriptor, ObjectType, ReferenceType} +import org.opalj.br.{ClassFile, ClassHierarchy, DefinedMethod, Field, Method, MethodDescriptor, ObjectType, ReferenceType} import org.opalj.br.analyses.{DeclaredMethods, DeclaredMethodsKey, Project} import org.opalj.tac.{AITACode, ComputeTACAIKey, FieldRead, FieldWriteAccessStmt, TACMethodParameter} import org.opalj.value.ValueInformation @@ -17,8 +17,6 @@ object OpalClient { tacCodes = Some(p.get(ComputeTACAIKey)) } - def getDeclaredMethod(method: Method): DeclaredMethod = declaredMethods.get(method) - def getClassHierarchy: ClassHierarchy = project.get.classHierarchy def getClassFileForType(objectType: ObjectType): Option[ClassFile] = project.get.classFile(objectType) diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalIfStatement.scala b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalIfStatement.scala index 5b568dfd3..6d41fd9f6 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalIfStatement.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalIfStatement.scala @@ -16,6 +16,10 @@ class OpalIfStatement(val delegate: If[DUVar[ValueInformation]], method: OpalMet override def evaluate(otherVal: Val): IfStatement.Evaluation = IfStatement.Evaluation.UNKOWN override def uses(otherVal: Val): Boolean = { + // TODO + if (otherVal.isInstanceOf[OpalVal]) {} + if (otherVal.isInstanceOf[OpalLocal]) {} + if (otherVal.isInstanceOf[OpalArrayRef]) {} val left = new OpalVal(delegate.left, method) val right = new OpalVal(delegate.right, method) diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalInvokeExpr.scala b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalInvokeExpr.scala index 861cae8ef..0f4a521f1 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalInvokeExpr.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalInvokeExpr.scala @@ -1,13 +1,12 @@ package boomerang.scene.opal import boomerang.scene.{DeclaredMethod, InvokeExpr, Val} -import org.opalj.UShort import org.opalj.tac.{DUVar, FunctionCall, InstanceFunctionCall, InstanceMethodCall, MethodCall, NonVirtualFunctionCall, NonVirtualMethodCall} import org.opalj.value.ValueInformation import java.util -class OpalMethodInvokeExpr(val delegate: MethodCall[DUVar[ValueInformation]], method: OpalMethod, pc: UShort) extends InvokeExpr { +class OpalMethodInvokeExpr(val delegate: MethodCall[DUVar[ValueInformation]], method: OpalMethod) extends InvokeExpr { override def getArg(index: Int): Val = getArgs.get(index) @@ -15,7 +14,7 @@ class OpalMethodInvokeExpr(val delegate: MethodCall[DUVar[ValueInformation]], me val result = new util.ArrayList[Val] delegate.params.foreach(param => { - result.add(new OpalVal(param, method)) + result.add(new OpalLocal(param, method)) }) result @@ -25,7 +24,7 @@ class OpalMethodInvokeExpr(val delegate: MethodCall[DUVar[ValueInformation]], me override def getBase: Val = { if (isInstanceInvokeExpr) { - return new OpalVal(delegate.asInstanceMethodCall.receiver, method) + return new OpalLocal(delegate.asInstanceMethodCall.receiver, method) } throw new RuntimeException("Method call is not an instance invoke expression") @@ -57,7 +56,7 @@ class OpalMethodInvokeExpr(val delegate: MethodCall[DUVar[ValueInformation]], me override def toString: String = delegate.toString } -class OpalFunctionInvokeExpr(val delegate: FunctionCall[DUVar[ValueInformation]], method: OpalMethod, pc: UShort) extends InvokeExpr { +class OpalFunctionInvokeExpr(val delegate: FunctionCall[DUVar[ValueInformation]], method: OpalMethod) extends InvokeExpr { override def getArg(index: Int): Val = getArgs.get(index) @@ -65,7 +64,7 @@ class OpalFunctionInvokeExpr(val delegate: FunctionCall[DUVar[ValueInformation]] val result = new util.ArrayList[Val] delegate.params.foreach(param => { - result.add(new OpalVal(param, method)) + result.add(new OpalLocal(param, method)) }) result @@ -75,7 +74,7 @@ class OpalFunctionInvokeExpr(val delegate: FunctionCall[DUVar[ValueInformation]] override def getBase: Val = { if (isInstanceInvokeExpr) { - return new OpalVal(delegate.asInstanceFunctionCall.receiver, method) + return new OpalLocal(delegate.asInstanceFunctionCall.receiver, method) } throw new RuntimeException("Function call is not an instance invoke expression") diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalLocal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalLocal.scala new file mode 100644 index 000000000..e9cb37a9d --- /dev/null +++ b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalLocal.scala @@ -0,0 +1,157 @@ +package boomerang.scene.opal + +import boomerang.scene.{ControlFlowGraph, Method, Pair, Type, Val} +import org.opalj.br.ObjectType +import org.opalj.tac.{DUVar, DVar, Expr, UVar} +import org.opalj.value.ValueInformation + +class OpalLocal(val delegate: Expr[DUVar[ValueInformation]], method: OpalMethod, unbalanced: ControlFlowGraph.Edge = null) extends Val(method, unbalanced) { + + if (!delegate.isVar) { + throw new RuntimeException("OpalLocal can hold only variables") + } + + override def getType: Type = delegate match { + case local: DUVar[ValueInformation] => + if (local.value.isReferenceValue) { + OpalType(local.value.asReferenceValue.asReferenceType, local.value.asReferenceValue.isNull.isYes) + } else if (local.value.isPrimitiveValue) { + OpalType(local.value.asPrimitiveValue.primitiveType) + } else if (local.value.isVoid) { + OpalType(ObjectType.Void) + } else if (local.value.isArrayValue.isYes) { + OpalType(ObjectType.Array) + } else { + throw new RuntimeException("Could not determine type " + local.value) + } + case _ => throw new RuntimeException("Cannot compute type of expression that is not a variable") + } + + override def isStatic: Boolean = false + + override def isNewExpr: Boolean = false + + override def getNewExprType: Type = throw new RuntimeException("Opal local is not a new expression") + + override def asUnbalanced(stmt: ControlFlowGraph.Edge): Val = new OpalLocal(delegate, method, stmt) + + override def isLocal: Boolean = true + + override def isArrayAllocationVal: Boolean = false + + override def getArrayAllocationSize: Val = throw new RuntimeException("Opal local is not an array allocation expression") + + override def isNull: Boolean = { + if (!delegate.asVar.value.isReferenceValue) { + delegate.asVar.value.asReferenceValue.isNull.isYes + } + + false + } + + override def isStringConstant: Boolean = false + + override def getStringValue: String = throw new RuntimeException("Opal local is not a String constant") + + override def isStringBufferOrBuilder: Boolean = false + + override def isThrowableAllocationType: Boolean = false + + override def isCast: Boolean = false + + override def getCastOp: Val = throw new RuntimeException("Opal local is not a cast operation") + + override def isArrayRef: Boolean = false + + override def isInstanceOfExpr: Boolean = false + + override def getInstanceOfOp: Val = throw new RuntimeException("Opal local is not an instance of operation") + + override def isLengthExpr: Boolean = false + + override def getLengthOp: Val = throw new RuntimeException("Opal local is not a length operation") + + override def isIntConstant: Boolean = false + + override def isClassConstant: Boolean = false + + override def getClassConstantType: Type = throw new RuntimeException("Opal local is not a class constant") + + override def withNewMethod(callee: Method): Val = new OpalLocal(delegate, callee.asInstanceOf[OpalMethod]) + + override def isLongConstant: Boolean = false + + override def getIntValue: Int = throw new RuntimeException("Opal local is not an int constant") + + override def getLongValue: Long = throw new RuntimeException("Opal local is not a long constant") + + override def getArrayBase: Pair[Val, Integer] = throw new RuntimeException("Opal local is not array reference") + + override def getVariableName: String = delegate match { + case dVar: DVar[_] => s"var${}" // TODO Add origin + case uVar: UVar[_] => s"var${uVar.definedBy.head}" + case _ => delegate.toString + } + + override def hashCode(): Int = delegate match { + case uVar: UVar[_] => + if (uVar.definedBy.head < 0) { + // Parameters have no real definition statement + return 31 * super.hashCode() + delegate.hashCode() + } + + // UVars should reference their DVar to keep the comparisons consistent + val tac = OpalClient.getTacForMethod(method.delegate) + val defStmt = tac.stmts(uVar.definedBy.head) + + if (!defStmt.isAssignment) { + return 31 * super.hashCode() + delegate.hashCode() + } + + val targetVar = defStmt.asAssignment.targetVar + 31 * super.hashCode() + targetVar.hashCode() + case dVar: DVar[_] => 31 * super.hashCode() + dVar.hashCode() + case _ => throw new RuntimeException("Cannot compute hashCode for non variables") + } + + override def equals(obj: Any): Boolean = obj match { + case other: OpalLocal => + // DVar does not implement a proper equals() method, so we have to compare the hash codes + this.delegate match { + case _: DVar[_] if other.delegate.isInstanceOf[DVar[_]] => + super.equals(other) && this.delegate.hashCode() == other.delegate.hashCode() + case uVar: UVar[_] if other.delegate.isInstanceOf[DVar[_]] => + val tac = OpalClient.getTacForMethod(method.delegate) + val defStmt = tac.stmts(uVar.definedBy.head) + + if (!defStmt.isAssignment) { + return false + } + + val targetVar = defStmt.asAssignment.targetVar + val otherVar = other.delegate.asInstanceOf[DVar[ValueInformation]] + super.equals(other) && targetVar.hashCode() == otherVar.hashCode() + case dVar: DVar[_] if other.delegate.isInstanceOf[UVar[_]] => + val otherVar = other.delegate.asInstanceOf[UVar[ValueInformation]] + + // Parameter vars have no corresponding DVar + if (otherVar.definedBy.head < 0) { + return false + } + + val tac = OpalClient.getTacForMethod(method.delegate) + val defStmt = tac.stmts(otherVar.definedBy.head) + + if (!defStmt.isAssignment) { + return false + } + + val targetVar = defStmt.asAssignment.targetVar + super.equals(other) && dVar.hashCode() == targetVar.hashCode() + case _ => throw new RuntimeException("Cannot compare a variable with a non variable") + } + case _ => false + } + + override def toString: String = getVariableName +} diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalMethod.scala b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalMethod.scala index 9bd5635e1..68e3fb60b 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalMethod.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalMethod.scala @@ -9,6 +9,10 @@ import java.util case class OpalMethod(delegate: org.opalj.br.Method) extends Method { + if (delegate.body.isEmpty) { + throw new RuntimeException("Cannot build OpalMethod without existing body") + } + private var localCache: Option[util.Set[Val]] = None private var parameterLocalCache: Option[util.List[Val]] = None @@ -87,36 +91,36 @@ case class OpalMethod(delegate: org.opalj.br.Method) extends Method { if (stmt.isMethodCall) { // Extract the base if (stmt.isInstanceOf[InstanceMethodCall[_]]) { - val opalVal = new OpalVal(stmt.asInstanceMethodCall.receiver, this) - localCache.get.add(opalVal) + val base = new OpalLocal(stmt.asInstanceMethodCall.receiver, this) + localCache.get.add(base) } // Parameters of method calls - for (param <- stmt.asMethodCall.params) { + stmt.asMethodCall.params.foreach(param => { if (param.isVar) { - localCache.get.add(new OpalVal(param.asVar, this)) + localCache.get.add(new OpalLocal(param, this)) } - } + }) } if (stmt.isAssignment) { // Target variable val targetVar = stmt.asAssignment.targetVar - localCache.get.add(new OpalVal(targetVar, this)) + localCache.get.add(new OpalLocal(targetVar, this)) if (stmt.asAssignment.expr.isFunctionCall) { // Extract the base if (stmt.asAssignment.expr.isInstanceOf[InstanceFunctionCall[_]]) { - val opalVal = new OpalVal(stmt.asAssignment.expr.asInstanceFunctionCall.receiver, this) - localCache.get.add(opalVal) + val base = new OpalLocal(stmt.asAssignment.expr.asInstanceFunctionCall.receiver, this) + localCache.get.add(base) } // Parameters of function call - for (param <- stmt.asAssignment.expr.asFunctionCall.params) { + stmt.asAssignment.expr.asFunctionCall.params.foreach(param => { if (param.isVar) { - localCache.get.add(new OpalVal(param.asVar, this)) + localCache.get.add(new OpalLocal(param, this)) } - } + }) } } } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalStatement.scala b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalStatement.scala index e420ac1f9..0353f90ae 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalStatement.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalStatement.scala @@ -13,7 +13,7 @@ class OpalStatement(val delegate: Stmt[DUVar[ValueInformation]], m: OpalMethod) override def containsInvokeExpr(): Boolean = { if (delegate.isMethodCall) return true - if (isAssign && delegate.asAssignment.expr.isFunctionCall) return true + if (delegate.isAssignment && delegate.asAssignment.expr.isFunctionCall) return true if (delegate.isExprStmt && delegate.asExprStmt.isMethodCall) return true if (delegate.isExprStmt && delegate.asExprStmt.expr.isFunctionCall) return true @@ -22,10 +22,10 @@ class OpalStatement(val delegate: Stmt[DUVar[ValueInformation]], m: OpalMethod) override def getInvokeExpr: InvokeExpr = { if (containsInvokeExpr()) { - if (delegate.isMethodCall) return new OpalMethodInvokeExpr(delegate.asMethodCall, m, delegate.pc) - if (isAssign && delegate.asAssignment.expr.isFunctionCall) return new OpalFunctionInvokeExpr(delegate.asAssignment.expr.asFunctionCall, m, delegate.pc) - if (delegate.isExprStmt && delegate.asExprStmt.isMethodCall) return new OpalMethodInvokeExpr(delegate.asExprStmt.asMethodCall, m, delegate.pc) - if (delegate.isExprStmt && delegate.asExprStmt.expr.isFunctionCall) return new OpalFunctionInvokeExpr(delegate.asExprStmt.expr.asFunctionCall, m, delegate.pc) + if (delegate.isMethodCall) return new OpalMethodInvokeExpr(delegate.asMethodCall, m) + if (delegate.isAssignment && delegate.asAssignment.expr.isFunctionCall) return new OpalFunctionInvokeExpr(delegate.asAssignment.expr.asFunctionCall, m) + if (delegate.isExprStmt && delegate.asExprStmt.isMethodCall) return new OpalMethodInvokeExpr(delegate.asExprStmt.asMethodCall, m) + if (delegate.isExprStmt && delegate.asExprStmt.expr.isFunctionCall) return new OpalFunctionInvokeExpr(delegate.asExprStmt.expr.asFunctionCall, m) } throw new RuntimeException("Statement does not contain an invoke expression") @@ -52,11 +52,11 @@ class OpalStatement(val delegate: Stmt[DUVar[ValueInformation]], m: OpalMethod) } override def isFieldWriteWithBase(base: Val): Boolean = { - if (isAssign && isFieldStore) { + if (delegate.isAssignment && isFieldStore) { return getFieldStore.getX.equals(base) } - if (isAssign && isArrayStore) { + if (delegate.isAssignment && isArrayStore) { return getArrayBase.getX.equals(base) } @@ -75,18 +75,37 @@ class OpalStatement(val delegate: Stmt[DUVar[ValueInformation]], m: OpalMethod) override def isFieldLoadWithBase(base: Val): Boolean = { // TODO Also array? - if (isAssign && isFieldLoad) { + if (delegate.isAssignment && isFieldLoad) { return getFieldLoad.getX.equals(base) } false } - override def isAssign: Boolean = delegate.isAssignment + override def isAssign: Boolean = delegate.isAssignment || isFieldStore || isArrayStore override def getLeftOp: Val = { if (isAssign) { - return new OpalVal(delegate.asAssignment.targetVar, m) + if (delegate.isAssignment) { + // TODO Change to variable + return new OpalVal(delegate.asAssignment.targetVar, m) + } + + if (isFieldStore) { + // TODO Is it correct? + return new OpalVal(delegate.asPutField.objRef, m) + } + + if (isArrayStore) { + val base = delegate.asArrayStore.arrayRef + val indexValue = delegate.asArrayStore.index + + if (!indexValue.isVar) return new OpalArrayRef(base, -1, m) + if (!indexValue.asVar.value.isPrimitiveValue) return new OpalArrayRef(base, -1, m) + + val index = indexValue.asVar.value.asPrimitiveValue.asConstantInteger.intValue() + return new OpalArrayRef(base, index, m) + } } throw new RuntimeException("Statement is not an assignment") @@ -94,14 +113,42 @@ class OpalStatement(val delegate: Stmt[DUVar[ValueInformation]], m: OpalMethod) override def getRightOp: Val = { if (isAssign) { - return new OpalVal(delegate.asAssignment.expr, m) + if (delegate.isAssignment) { + val rightExpr = delegate.asAssignment.expr + + // TODO + if (rightExpr.isGetField) {} + + if (rightExpr.isArrayLoad) { + val base = rightExpr.asArrayLoad.arrayRef + val indexValue = rightExpr.asArrayLoad.index + + if (!indexValue.isVar) return new OpalArrayRef(base, -1, m) + if (!indexValue.asVar.value.isPrimitiveValue) return new OpalArrayRef(base, -1, m) + + val index = indexValue.asVar.value.asPrimitiveValue.asConstantInteger.intValue() + return new OpalArrayRef(base, index, m) + } + + return new OpalVal(delegate.asAssignment.expr, m) + } + + if (isFieldStore) { + // TODO Distinguish between constant and variable + return new OpalVal(delegate.asPutField.value, m) + } + + if (isArrayStore) { + // TODO Distinguish between constant and variable + return new OpalVal(delegate.asArrayStore.value, m) + } } throw new RuntimeException("Statement is not an assignment") } override def isInstanceOfStatement(fact: Val): Boolean = { - if (isAssign) { + if (delegate.isAssignment) { if (getRightOp.isInstanceOfExpr) { val insOf = getRightOp.getInstanceOfOp @@ -114,7 +161,7 @@ class OpalStatement(val delegate: Stmt[DUVar[ValueInformation]], m: OpalMethod) override def isCast: Boolean = { // Primitive type casts - if (isAssign) { + if (delegate.isAssignment) { val assignExpr = delegate.asAssignment.expr if (assignExpr.astID == PrimitiveTypecastExpr.ASTID) { @@ -153,7 +200,7 @@ class OpalStatement(val delegate: Stmt[DUVar[ValueInformation]], m: OpalMethod) override def isMultiArrayAllocation: Boolean = false override def isStringAllocation: Boolean = { - if (isAssign) { + if (delegate.isAssignment) { return delegate.asAssignment.expr.isStringConst } @@ -172,7 +219,7 @@ class OpalStatement(val delegate: Stmt[DUVar[ValueInformation]], m: OpalMethod) override def isArrayStore: Boolean = delegate.isArrayStore override def isArrayLoad: Boolean = { - if (!isAssign) { + if (!delegate.isAssignment) { return false } @@ -199,6 +246,7 @@ class OpalStatement(val delegate: Stmt[DUVar[ValueInformation]], m: OpalMethod) val resolvedField = OpalClient.resolveFieldStore(delegate.asPutField).get val ref = delegate.asPutField.objRef + // TODO return new Pair(new OpalVal(ref, m), OpalField(resolvedField)) } @@ -210,6 +258,7 @@ class OpalStatement(val delegate: Stmt[DUVar[ValueInformation]], m: OpalMethod) val resolvedField = OpalClient.resolveFieldLoad(delegate.asAssignment.expr.asFieldRead).get val ref = delegate.asAssignment.expr.asGetField.objRef + // TODO return new Pair(new OpalVal(ref, m), OpalField(resolvedField)) } @@ -266,11 +315,12 @@ class OpalStatement(val delegate: Stmt[DUVar[ValueInformation]], m: OpalMethod) return rightOp.getArrayBase } - if (isArrayLoad) { - // TODO + if (isArrayStore) { + val leftOp = getLeftOp + return leftOp.getArrayBase } - throw new RuntimeException("Statement has no array base") + throw new RuntimeException("Statement is not an array load or array store operation") } override def getStartLineNumber: Int = m.delegate.body.get.lineNumber(delegate.pc).getOrElse(-1) @@ -300,17 +350,25 @@ class OpalStatement(val delegate: Stmt[DUVar[ValueInformation]], m: OpalMethod) } var assign = "" if (isAssign) { - assign = getLeftOp.toString + " = " + assign = getLeftOp + " = " } return assign + base + getInvokeExpr.getMethod.getName + "(" + Joiner.on(",").join(getInvokeExpr.getArgs) + ")" } if (isAssign) { - if (getRightOp.isNewExpr) { - return getLeftOp.toString + " = new " + getRightOp.getNewExprType.toString - } else { - return getLeftOp.toString + " = " + getRightOp.toString + if (delegate.isAssignment) { + if (getRightOp.isNewExpr) { + return s"$getLeftOp = new + ${getRightOp.getNewExprType}" + } else { + // TODO Array load + return getLeftOp + " = " + getRightOp + } + } else if (isFieldStore) { + return s"$getLeftOp = $getWrittenField" + } else if (isArrayStore) { + val base = getArrayBase + return s"${base.getX.getVariableName}[${base.getY}] = $getRightOp" } } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalStaticFieldVal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalStaticFieldVal.scala index 047a56a31..a18cf0864 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalStaticFieldVal.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalStaticFieldVal.scala @@ -63,4 +63,10 @@ class OpalStaticFieldVal(field: OpalField, method: Method, unbalanced: ControlFl override def getArrayBase: Pair[Val, Integer] = throw new RuntimeException("Static field has no array base") override def getVariableName: String = field.toString + + override def hashCode(): Int = ??? + + override def equals(obj: Any): Boolean = ??? + + override def toString: String = ??? } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalVal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalVal.scala index 7abff2bbb..6da61f9d8 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalVal.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalVal.scala @@ -1,44 +1,25 @@ package boomerang.scene.opal import boomerang.scene.{ControlFlowGraph, Method, Pair, Type, Val} -import org.opalj.br.{ObjectType, ReferenceType} -import org.opalj.tac.{ArrayLength, Const, DUVar, DVar, DefSites, Expr, FunctionCall, InstanceOf, IntConst, LongConst, New, PrimitiveTypecastExpr, StringConst, UVar} +import org.opalj.br.ReferenceType +import org.opalj.tac.{ArrayLength, Const, DUVar, Expr, FunctionCall, InstanceOf, IntConst, LongConst, New, PrimitiveTypecastExpr, StringConst} import org.opalj.value.ValueInformation class OpalVal(val delegate: Expr[DUVar[ValueInformation]], method: OpalMethod, unbalanced: ControlFlowGraph.Edge = null) extends Val(method, unbalanced) { + if (delegate.isVar) { + throw new RuntimeException("OpalVal cannot hold a variable (use OpalLocal)") + } + override def getType: Type = delegate match { - case local : UVar[ValueInformation] => - if (local.value.isReferenceValue) { - OpalType(local.value.asReferenceValue.asReferenceType, local.value.asReferenceValue.isNull.isYes) - } else if (local.value.isPrimitiveValue) { - OpalType(local.value.asPrimitiveValue.primitiveType) - } else if (local.value.isVoid) { - OpalType(ObjectType.Void) - } else if (local.value.isArrayValue.isYes) { - OpalType(ObjectType.Array) - } else { - throw new RuntimeException("Could not determine type " + local.value) - } - case local: DUVar[ValueInformation] => - if (local.value.isReferenceValue) { - OpalType(local.value.asReferenceValue.asReferenceType, local.value.asReferenceValue.isNull.isYes) - } else if (local.value.isPrimitiveValue) { - OpalType(local.value.asPrimitiveValue.primitiveType) - } else if (local.value.isVoid) { - OpalType(ObjectType.Void) - } else if (local.value.isArrayValue.isYes) { - OpalType(ObjectType.Array) - } else { - throw new RuntimeException("Could not determine type " + local.value) - } case const: Const => OpalType(const.tpe) case newExpr: New => OpalType(newExpr.tpe) case functionCall: FunctionCall[_] => OpalType(functionCall.descriptor.returnType) case _ => throw new RuntimeException("Type not implemented yet") } - override def isStatic: Boolean = false + // TODO + override def isStatic: Boolean = ??? override def isNewExpr: Boolean = delegate.isNew @@ -52,7 +33,7 @@ class OpalVal(val delegate: Expr[DUVar[ValueInformation]], method: OpalMethod, u override def asUnbalanced(stmt: ControlFlowGraph.Edge): Val = new OpalVal(delegate, method, stmt) - override def isLocal: Boolean = delegate.isVar + override def isLocal: Boolean = false override def isArrayAllocationVal: Boolean = delegate.isNewArray @@ -104,10 +85,7 @@ class OpalVal(val delegate: Expr[DUVar[ValueInformation]], method: OpalMethod, u throw new RuntimeException("Expression is not a cast expression") } - override def isArrayRef: Boolean = delegate match { - case ref: UVar[ValueInformation] => ref.value.isArrayValue.isYes - case _ => false - } + override def isArrayRef: Boolean = false override def isInstanceOfExpr: Boolean = delegate.astID == InstanceOf.ASTID @@ -163,75 +141,25 @@ class OpalVal(val delegate: Expr[DUVar[ValueInformation]], method: OpalMethod, u throw new RuntimeException("Value is not a long constant") } - override def getArrayBase: Pair[Val, Integer] = { - if (isArrayRef) { - // TODO - } + override def getArrayBase: Pair[Val, Integer] = throw new RuntimeException("Value is not an array ref") - throw new RuntimeException("Value is not an array ref") + override def getVariableName: String = { + delegate match { + case stringConst: StringConst => "\"" + stringConst.value + "\"" + case intConst: IntConst => intConst.value.toString + case longConst: LongConst => longConst.value.toString + case _ => delegate.toString + } } - override def getVariableName: String = delegate.toString - - override def hashCode(): Int = delegate match { - case uVar: UVar[_] => - // UVars should reference their DVar to keep the comparisons consistent - val tac = OpalClient.getTacForMethod(method.delegate) - val defStmt = tac.stmts(uVar.definedBy.head) - - if (!defStmt.isAssignment) { - return 31 * super.hashCode() + delegate.hashCode() - } - - val targetVar = defStmt.asAssignment.targetVar - 31 * super.hashCode() + targetVar.hashCode() - case _ => 31 * super.hashCode() + delegate.hashCode() - } + override def hashCode(): Int = 31 * super.hashCode() + delegate.hashCode() private def canEqual(a: Any): Boolean = a.isInstanceOf[OpalVal] override def equals(obj: Any): Boolean = obj match { - case other: OpalVal => - // DVar does not implement a proper equals() method, so we have to compare the hash codes - this.delegate match { - case _: DVar[_] if other.delegate.isInstanceOf[DVar[_]] => - super.equals(other) && this.delegate.hashCode() == other.delegate.hashCode() - case uVar: UVar[_] if other.delegate.isInstanceOf[DVar[_]] => - val tac = OpalClient.getTacForMethod(method.delegate) - val defStmt = tac.stmts(uVar.definedBy.head) - - if (!defStmt.isAssignment) { - return false - } - - val targetVar = defStmt.asAssignment.targetVar - val otherVar = other.delegate.asInstanceOf[DVar[ValueInformation]] - super.equals(other) && targetVar.hashCode() == otherVar.hashCode() - case dVar: DVar[_] if other.delegate.isInstanceOf[UVar[_]] => - val otherVar = other.delegate.asInstanceOf[UVar[ValueInformation]] - val tac = OpalClient.getTacForMethod(method.delegate) - val defStmt = tac.stmts(otherVar.definedBy.head) - - if (!defStmt.isAssignment) { - return false - } - - val targetVar = defStmt.asAssignment.targetVar - super.equals(other) && dVar.hashCode() == targetVar.hashCode() - case _ => - other.canEqual(this) && super.equals(other) && this.delegate == other.delegate - } + case other: OpalVal => other.canEqual(this) && super.equals(other) && this.delegate == other.delegate case _ => false } - override def toString: String = { - delegate match { - case _: DVar[_] => "var" // TODO Add origin - case uVar: UVar[_] => "var" + uVar.definedBy.head - case stringConst: StringConst => "\"" + stringConst.value + "\"" - case intConst: IntConst => intConst.value.toString - case longConst: LongConst => longConst.value.toString - case _ => delegate.toString - } - } + override def toString: String = getVariableName } From f47df3fcb93e25f0cda3ee8a8efd3bf5bfe22d79 Mon Sep 17 00:00:00 2001 From: Sven Meyer Date: Fri, 7 Mar 2025 18:19:25 +0100 Subject: [PATCH 07/61] Consistent renaming --- .../java/aliasing/SparseAliasManager.java | 4 ++-- .../java/test/aliasing/AliasingTestSetUp.java | 2 +- boomerangScope-Opal/pom.xml | 2 +- .../boomerang/{scene => scope}/Main.scala | 5 ++-- .../{scene => scope}/opal/OpalCallGraph.scala | 9 ++++---- .../{scene => scope}/opal/OpalClient.scala | 2 +- .../scope/opal/OpalFrameworkScope.scala | 23 +++++++++++++++++++ .../opal/tac}/OpalArrayRef.scala | 4 ++-- .../opal/tac}/OpalControlFlowGraph.scala | 5 ++-- .../opal/tac}/OpalDeclaredMethod.scala | 5 ++-- .../opal/tac}/OpalDoubleVal.scala | 4 ++-- .../opal => scope/opal/tac}/OpalField.scala | 4 ++-- .../opal/tac}/OpalIfStatement.scala | 5 ++-- .../opal/tac}/OpalInvokeExpr.scala | 7 +++--- .../opal => scope/opal/tac}/OpalLocal.scala | 5 ++-- .../opal => scope/opal/tac}/OpalMethod.scala | 7 +++--- .../opal/tac}/OpalStatement.scala | 5 ++-- .../opal/tac}/OpalStaticFieldVal.scala | 4 ++-- .../opal => scope/opal/tac}/OpalType.scala | 6 +++-- .../opal => scope/opal/tac}/OpalVal.scala | 7 +++--- .../opal/tac}/OpalWrappedClass.scala | 5 ++-- pom.xml | 6 +++++ testCore/pom.xml | 6 ++++- .../main/scala/test/setup/OpalTestSetup.scala | 13 +++++++++++ 24 files changed, 102 insertions(+), 43 deletions(-) rename boomerangScope-Opal/src/main/scala/boomerang/{scene => scope}/Main.scala (93%) rename boomerangScope-Opal/src/main/scala/boomerang/{scene => scope}/opal/OpalCallGraph.scala (86%) rename boomerangScope-Opal/src/main/scala/boomerang/{scene => scope}/opal/OpalClient.scala (98%) create mode 100644 boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalFrameworkScope.scala rename boomerangScope-Opal/src/main/scala/boomerang/{scene/opal => scope/opal/tac}/OpalArrayRef.scala (96%) rename boomerangScope-Opal/src/main/scala/boomerang/{scene/opal => scope/opal/tac}/OpalControlFlowGraph.scala (95%) rename boomerangScope-Opal/src/main/scala/boomerang/{scene/opal => scope/opal/tac}/OpalDeclaredMethod.scala (94%) rename boomerangScope-Opal/src/main/scala/boomerang/{scene/opal => scope/opal/tac}/OpalDoubleVal.scala (90%) rename boomerangScope-Opal/src/main/scala/boomerang/{scene/opal => scope/opal/tac}/OpalField.scala (75%) rename boomerangScope-Opal/src/main/scala/boomerang/{scene/opal => scope/opal/tac}/OpalIfStatement.scala (90%) rename boomerangScope-Opal/src/main/scala/boomerang/{scene/opal => scope/opal/tac}/OpalInvokeExpr.scala (93%) rename boomerangScope-Opal/src/main/scala/boomerang/{scene/opal => scope/opal/tac}/OpalLocal.scala (98%) rename boomerangScope-Opal/src/main/scala/boomerang/{scene/opal => scope/opal/tac}/OpalMethod.scala (98%) rename boomerangScope-Opal/src/main/scala/boomerang/{scene/opal => scope/opal/tac}/OpalStatement.scala (98%) rename boomerangScope-Opal/src/main/scala/boomerang/{scene/opal => scope/opal/tac}/OpalStaticFieldVal.scala (95%) rename boomerangScope-Opal/src/main/scala/boomerang/{scene/opal => scope/opal/tac}/OpalType.scala (93%) rename boomerangScope-Opal/src/main/scala/boomerang/{scene/opal => scope/opal/tac}/OpalVal.scala (95%) rename boomerangScope-Opal/src/main/scala/boomerang/{scene/opal => scope/opal/tac}/OpalWrappedClass.scala (93%) create mode 100644 testCore/src/main/scala/test/setup/OpalTestSetup.scala diff --git a/SparseBoomerangCorrectness/src/main/java/aliasing/SparseAliasManager.java b/SparseBoomerangCorrectness/src/main/java/aliasing/SparseAliasManager.java index a3940d544..b1ed44112 100644 --- a/SparseBoomerangCorrectness/src/main/java/aliasing/SparseAliasManager.java +++ b/SparseBoomerangCorrectness/src/main/java/aliasing/SparseAliasManager.java @@ -4,8 +4,8 @@ import boomerang.Boomerang; import boomerang.DefaultBoomerangOptions; import boomerang.results.BackwardBoomerangResults; -import boomerang.scene.*; -import boomerang.scene.jimple.*; +import boomerang.scope.*; +import boomerang.scope.jimple.*; import boomerang.sparse.SparsificationStrategy; import boomerang.util.AccessPath; import com.google.common.base.Stopwatch; diff --git a/SparseBoomerangCorrectness/src/test/java/test/aliasing/AliasingTestSetUp.java b/SparseBoomerangCorrectness/src/test/java/test/aliasing/AliasingTestSetUp.java index 3697f2a65..142836cbf 100644 --- a/SparseBoomerangCorrectness/src/test/java/test/aliasing/AliasingTestSetUp.java +++ b/SparseBoomerangCorrectness/src/test/java/test/aliasing/AliasingTestSetUp.java @@ -3,7 +3,7 @@ import static org.junit.Assert.assertTrue; import aliasing.SparseAliasManager; -import boomerang.scene.jimple.BoomerangPretransformer; +import boomerang.scope.jimple.BoomerangPretransformer; import boomerang.util.AccessPath; import com.google.common.base.Predicate; import java.io.File; diff --git a/boomerangScope-Opal/pom.xml b/boomerangScope-Opal/pom.xml index cacef835f..07ba5fac9 100644 --- a/boomerangScope-Opal/pom.xml +++ b/boomerangScope-Opal/pom.xml @@ -6,7 +6,7 @@ de.fraunhofer.iem SPDS - 3.2.1 + 3.2.4-SNAPSHOT boomerangScope-Opal diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scene/Main.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/Main.scala similarity index 93% rename from boomerangScope-Opal/src/main/scala/boomerang/scene/Main.scala rename to boomerangScope-Opal/src/main/scala/boomerang/scope/Main.scala index 7cb23692a..c59eb6c52 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scene/Main.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/Main.scala @@ -1,6 +1,7 @@ -package boomerang.scene +package boomerang.scope -import boomerang.scene.opal.{OpalCallGraph, OpalClient, OpalMethod} +import boomerang.scope.opal.tac.OpalMethod +import boomerang.scope.opal.{OpalCallGraph, OpalClient} import com.typesafe.config.ConfigValueFactory import org.opalj.br.analyses.Project import org.opalj.br.analyses.cg.InitialEntryPointsKey diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalCallGraph.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalCallGraph.scala similarity index 86% rename from boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalCallGraph.scala rename to boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalCallGraph.scala index e7442cfd4..77dbc8fd5 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalCallGraph.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalCallGraph.scala @@ -1,10 +1,11 @@ -package boomerang.scene.opal +package boomerang.scope.opal -import boomerang.scene.CallGraph.Edge +import boomerang.scope.CallGraph +import boomerang.scope.CallGraph.Edge +import boomerang.scope.opal.tac.{OpalMethod, OpalPhantomMethod, OpalStatement} import org.opalj.br.{DefinedMethod, Method, MultipleDefinedMethods, VirtualDeclaredMethod} -import org.opalj.tac.cg.CallGraph -class OpalCallGraph(callGraph: CallGraph, entryPoints: Set[Method]) extends boomerang.scene.CallGraph { +class OpalCallGraph(callGraph: org.opalj.tac.cg.CallGraph, entryPoints: Set[Method]) extends CallGraph { callGraph.reachableMethods().foreach(method => { method.method match { diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalClient.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalClient.scala similarity index 98% rename from boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalClient.scala rename to boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalClient.scala index 31efa6b9c..220513ddc 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalClient.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalClient.scala @@ -1,4 +1,4 @@ -package boomerang.scene.opal +package boomerang.scope.opal import org.opalj.br.{ClassFile, ClassHierarchy, DefinedMethod, Field, Method, MethodDescriptor, ObjectType, ReferenceType} import org.opalj.br.analyses.{DeclaredMethods, DeclaredMethodsKey, Project} diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalFrameworkScope.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalFrameworkScope.scala new file mode 100644 index 000000000..b91400f25 --- /dev/null +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalFrameworkScope.scala @@ -0,0 +1,23 @@ +package boomerang.scope.opal + +import boomerang.scope.{CallGraph, DataFlowScope, Field, FrameworkScope, Method, StaticFieldVal, Val} +import org.opalj.br.analyses.Project + +import java.util.stream + +class OpalFrameworkScope(project: Project[_], callGraph: org.opalj.tac.cg.CallGraph, entryPoints: Set[org.opalj.br.Method], dataFlowScope: DataFlowScope) extends FrameworkScope { + + val opalCallGraph = new OpalCallGraph(callGraph, entryPoints) + + override def getCallGraph: CallGraph = opalCallGraph + + override def getDataFlowScope: DataFlowScope = dataFlowScope + + override def getTrueValue(m: Method): Val = ??? + + override def getFalseValue(m: Method): Val = ??? + + override def handleStaticFieldInitializers(fact: Val): stream.Stream[Method] = ??? + + override def newStaticFieldVal(field: Field, m: Method): StaticFieldVal = ??? +} diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalArrayRef.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalArrayRef.scala similarity index 96% rename from boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalArrayRef.scala rename to boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalArrayRef.scala index a8a62dcc6..3ac422d2e 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalArrayRef.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalArrayRef.scala @@ -1,6 +1,6 @@ -package boomerang.scene.opal +package boomerang.scope.opal.tac -import boomerang.scene.{ControlFlowGraph, Method, Pair, Type, Val} +import boomerang.scope._ import org.opalj.br.ObjectType import org.opalj.tac.{DUVar, DVar, Expr, UVar} import org.opalj.value.ValueInformation diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalControlFlowGraph.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalControlFlowGraph.scala similarity index 95% rename from boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalControlFlowGraph.scala rename to boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalControlFlowGraph.scala index 14a107374..36213dac0 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalControlFlowGraph.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalControlFlowGraph.scala @@ -1,6 +1,7 @@ -package boomerang.scene.opal +package boomerang.scope.opal.tac -import boomerang.scene.{ControlFlowGraph, Statement} +import boomerang.scope.opal.OpalClient +import boomerang.scope.{ControlFlowGraph, Statement} import com.google.common.collect.{HashMultimap, Multimap} import java.util diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalDeclaredMethod.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalDeclaredMethod.scala similarity index 94% rename from boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalDeclaredMethod.scala rename to boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalDeclaredMethod.scala index e84bc18da..21cfe5ffa 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalDeclaredMethod.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalDeclaredMethod.scala @@ -1,6 +1,7 @@ -package boomerang.scene.opal +package boomerang.scope.opal.tac -import boomerang.scene.{DeclaredMethod, InvokeExpr, Type, WrappedClass} +import boomerang.scope.opal.OpalClient +import boomerang.scope.{DeclaredMethod, InvokeExpr, Type, WrappedClass} import org.opalj.br.{DefinedMethod, MethodDescriptor, MethodSignature, ReferenceType} import java.util diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalDoubleVal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalDoubleVal.scala similarity index 90% rename from boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalDoubleVal.scala rename to boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalDoubleVal.scala index f3771bf36..bbe0995ad 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalDoubleVal.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalDoubleVal.scala @@ -1,6 +1,6 @@ -package boomerang.scene.opal +package boomerang.scope.opal.tac -import boomerang.scene.{Val, ValWithFalseVariable} +import boomerang.scope.{Val, ValWithFalseVariable} import org.opalj.tac.{DUVar, Expr} import org.opalj.value.ValueInformation diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalField.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalField.scala similarity index 75% rename from boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalField.scala rename to boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalField.scala index c87792d02..3e94a3b82 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalField.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalField.scala @@ -1,6 +1,6 @@ -package boomerang.scene.opal +package boomerang.scope.opal.tac -import boomerang.scene.Field +import boomerang.scope.Field case class OpalField(delegate: org.opalj.br.Field) extends Field { diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalIfStatement.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalIfStatement.scala similarity index 90% rename from boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalIfStatement.scala rename to boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalIfStatement.scala index 6d41fd9f6..d9688c099 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalIfStatement.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalIfStatement.scala @@ -1,6 +1,7 @@ -package boomerang.scene.opal +package boomerang.scope.opal.tac -import boomerang.scene.{IfStatement, Statement, Val} +import boomerang.scope.opal.OpalClient +import boomerang.scope.{IfStatement, Statement, Val} import org.opalj.tac.{DUVar, If} import org.opalj.value.ValueInformation diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalInvokeExpr.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalInvokeExpr.scala similarity index 93% rename from boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalInvokeExpr.scala rename to boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalInvokeExpr.scala index 0f4a521f1..4da7337ce 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalInvokeExpr.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalInvokeExpr.scala @@ -1,7 +1,8 @@ -package boomerang.scene.opal +package boomerang.scope.opal.tac -import boomerang.scene.{DeclaredMethod, InvokeExpr, Val} -import org.opalj.tac.{DUVar, FunctionCall, InstanceFunctionCall, InstanceMethodCall, MethodCall, NonVirtualFunctionCall, NonVirtualMethodCall} +import boomerang.scope.opal.OpalClient +import boomerang.scope.{DeclaredMethod, InvokeExpr, Val} +import org.opalj.tac._ import org.opalj.value.ValueInformation import java.util diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalLocal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalLocal.scala similarity index 98% rename from boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalLocal.scala rename to boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalLocal.scala index e9cb37a9d..1d6adbbae 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalLocal.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalLocal.scala @@ -1,6 +1,7 @@ -package boomerang.scene.opal +package boomerang.scope.opal.tac -import boomerang.scene.{ControlFlowGraph, Method, Pair, Type, Val} +import boomerang.scope.opal.OpalClient +import boomerang.scope._ import org.opalj.br.ObjectType import org.opalj.tac.{DUVar, DVar, Expr, UVar} import org.opalj.value.ValueInformation diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalMethod.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalMethod.scala similarity index 98% rename from boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalMethod.scala rename to boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalMethod.scala index 68e3fb60b..89dd9b58c 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalMethod.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalMethod.scala @@ -1,11 +1,12 @@ -package boomerang.scene.opal +package boomerang.scope.opal.tac -import boomerang.scene.{ControlFlowGraph, Method, Statement, Type, Val, WrappedClass} +import boomerang.scope._ +import boomerang.scope.opal.OpalClient import org.opalj.br.{MethodDescriptor, MethodSignature, ObjectType} import org.opalj.tac.{InstanceFunctionCall, InstanceMethodCall, UVar} -import scala.jdk.CollectionConverters._ import java.util +import scala.jdk.CollectionConverters._ case class OpalMethod(delegate: org.opalj.br.Method) extends Method { diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalStatement.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala similarity index 98% rename from boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalStatement.scala rename to boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala index 0353f90ae..cd704ed42 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalStatement.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala @@ -1,6 +1,7 @@ -package boomerang.scene.opal +package boomerang.scope.opal.tac -import boomerang.scene.{Field, IfStatement, InvokeExpr, Pair, Statement, StaticFieldVal, Val} +import boomerang.scope.opal.OpalClient +import boomerang.scope._ import com.google.common.base.Joiner import org.opalj.tac.{DUVar, PrimitiveTypecastExpr, Stmt} import org.opalj.value.ValueInformation diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalStaticFieldVal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStaticFieldVal.scala similarity index 95% rename from boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalStaticFieldVal.scala rename to boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStaticFieldVal.scala index a18cf0864..42583cfa7 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalStaticFieldVal.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStaticFieldVal.scala @@ -1,6 +1,6 @@ -package boomerang.scene.opal +package boomerang.scope.opal.tac -import boomerang.scene.{ControlFlowGraph, Field, Method, Pair, StaticFieldVal, Type, Val} +import boomerang.scope._ class OpalStaticFieldVal(field: OpalField, method: Method, unbalanced: ControlFlowGraph.Edge = null) extends StaticFieldVal(method, unbalanced) { diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalType.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalType.scala similarity index 93% rename from boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalType.scala rename to boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalType.scala index 409111be9..289b13933 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalType.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalType.scala @@ -1,5 +1,7 @@ -package boomerang.scene.opal -import boomerang.scene.{AllocVal, Type, Val, WrappedClass} +package boomerang.scope.opal.tac + +import boomerang.scope.opal.OpalClient +import boomerang.scope.{AllocVal, Type, Val, WrappedClass} import org.opalj.br.ObjectType case class OpalType(delegate: org.opalj.br.Type, isNull: Boolean = false) extends Type { diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalVal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalVal.scala similarity index 95% rename from boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalVal.scala rename to boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalVal.scala index 6da61f9d8..c95d288f7 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalVal.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalVal.scala @@ -1,8 +1,9 @@ -package boomerang.scene.opal +package boomerang.scope.opal.tac -import boomerang.scene.{ControlFlowGraph, Method, Pair, Type, Val} +import boomerang.scope.opal.OpalClient +import boomerang.scope._ import org.opalj.br.ReferenceType -import org.opalj.tac.{ArrayLength, Const, DUVar, Expr, FunctionCall, InstanceOf, IntConst, LongConst, New, PrimitiveTypecastExpr, StringConst} +import org.opalj.tac._ import org.opalj.value.ValueInformation class OpalVal(val delegate: Expr[DUVar[ValueInformation]], method: OpalMethod, unbalanced: ControlFlowGraph.Edge = null) extends Val(method, unbalanced) { diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalWrappedClass.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalWrappedClass.scala similarity index 93% rename from boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalWrappedClass.scala rename to boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalWrappedClass.scala index 6329e02c1..5d3304dd7 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scene/opal/OpalWrappedClass.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalWrappedClass.scala @@ -1,6 +1,7 @@ -package boomerang.scene.opal +package boomerang.scope.opal.tac -import boomerang.scene.{Method, Type, WrappedClass} +import boomerang.scope.opal.OpalClient +import boomerang.scope.{Method, Type, WrappedClass} import org.opalj.br.{ClassFile, ReferenceType} import java.util diff --git a/pom.xml b/pom.xml index 2942f81fa..9c84f1817 100644 --- a/pom.xml +++ b/pom.xml @@ -54,6 +54,7 @@ boomerangScope boomerangScope-Soot boomerangScope-SootUp + boomerangScope-Opal boomerangScope-WALA @@ -238,6 +239,11 @@ boomerangScope-SootUp ${project.version} + + de.fraunhofer.iem + boomerangScope-Opal + ${project.version} + de.fraunhofer.iem boomerangScope-WALA diff --git a/testCore/pom.xml b/testCore/pom.xml index b2d85c59f..7ead0ad09 100644 --- a/testCore/pom.xml +++ b/testCore/pom.xml @@ -33,13 +33,17 @@ boomerangScope + + de.fraunhofer.iem + boomerangScope-Soot + de.fraunhofer.iem boomerangScope-SootUp de.fraunhofer.iem - boomerangScope-Soot + boomerangScope-Opal \ No newline at end of file diff --git a/testCore/src/main/scala/test/setup/OpalTestSetup.scala b/testCore/src/main/scala/test/setup/OpalTestSetup.scala new file mode 100644 index 000000000..b0ddb8c11 --- /dev/null +++ b/testCore/src/main/scala/test/setup/OpalTestSetup.scala @@ -0,0 +1,13 @@ +package test.setup +import boomerang.scope.{DataFlowScope, FrameworkScope, Method} + +import java.util + +class OpalTestSetup extends TestSetup { + + override def initialize(classPath: String, testMethod: MethodWrapper, includedPackages: util.List[String], excludedPackages: util.List[String]): Unit = ??? + + override def getTestMethod: Method = ??? + + override def createFrameworkScope(dataFlowScope: DataFlowScope): FrameworkScope = ??? +} From c31d83b4ff8ff4dd9d64b39c8ae577e0a913760f Mon Sep 17 00:00:00 2001 From: Sven Meyer Date: Sat, 8 Mar 2025 13:06:21 +0100 Subject: [PATCH 08/61] Clean up Opal scope --- .../boomerang/scope/opal/OpalCallGraph.scala | 2 +- .../scope/opal/OpalFrameworkScope.scala | 5 ++ .../scope/opal/tac/OpalDeclaredMethod.scala | 59 +++++-------------- .../scope/opal/tac/OpalIfStatement.scala | 2 +- .../scope/opal/tac/OpalInvokeExpr.scala | 21 +------ .../boomerang/scope/opal/tac/OpalMethod.scala | 54 ++--------------- .../scope/opal/tac/OpalPhantomMethod.scala | 57 ++++++++++++++++++ .../opal/tac/OpalPhantomWrappedClass.scala | 25 ++++++++ .../scope/opal/tac/OpalStatement.scala | 18 ++---- .../scope/opal/tac/OpalWrappedClass.scala | 26 +------- .../scope/soot/jimple/JimpleType.java | 37 ------------ .../java/boomerang/scope/wala/WALAType.java | 6 +- 12 files changed, 117 insertions(+), 195 deletions(-) create mode 100644 boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalPhantomMethod.scala create mode 100644 boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalPhantomWrappedClass.scala diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalCallGraph.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalCallGraph.scala index 77dbc8fd5..effd4ed40 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalCallGraph.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalCallGraph.scala @@ -34,7 +34,7 @@ class OpalCallGraph(callGraph: org.opalj.tac.cg.CallGraph, entryPoints: Set[Meth addEdge(new Edge(srcStatement, targetMethod)) case virtualMethod: VirtualDeclaredMethod => - val targetMethod = OpalPhantomMethod(virtualMethod.declaringClassType, virtualMethod.name, virtualMethod.descriptor, srcStatement.getInvokeExpr.isStaticInvokeExpr) + val targetMethod = OpalPhantomMethod(virtualMethod, srcStatement.getInvokeExpr.isStaticInvokeExpr) addEdge(new Edge(srcStatement, targetMethod)) case definedMethods: MultipleDefinedMethods => diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalFrameworkScope.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalFrameworkScope.scala index b91400f25..5af488f58 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalFrameworkScope.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalFrameworkScope.scala @@ -21,3 +21,8 @@ class OpalFrameworkScope(project: Project[_], callGraph: org.opalj.tac.cg.CallGr override def newStaticFieldVal(field: Field, m: Method): StaticFieldVal = ??? } + +object OpalFrameworkScope { + final val STATIC_INITIALIZER: String = "" + final val CONSTRUCTOR: String = "" +} diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalDeclaredMethod.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalDeclaredMethod.scala index 21cfe5ffa..ee0329393 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalDeclaredMethod.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalDeclaredMethod.scala @@ -1,70 +1,37 @@ package boomerang.scope.opal.tac -import boomerang.scope.opal.OpalClient +import boomerang.scope.opal.{OpalClient, OpalFrameworkScope} import boomerang.scope.{DeclaredMethod, InvokeExpr, Type, WrappedClass} -import org.opalj.br.{DefinedMethod, MethodDescriptor, MethodSignature, ReferenceType} +import org.opalj.br.MethodSignature +import org.opalj.tac.{Call, DUVar} +import org.opalj.value.ValueInformation import java.util -case class OpalDeclaredMethod(invokeExpr: InvokeExpr, delegate: DefinedMethod) extends DeclaredMethod(invokeExpr) { +case class OpalDeclaredMethod(invokeExpr: InvokeExpr, delegate: Call[DUVar[ValueInformation]]) extends DeclaredMethod(invokeExpr) { - override def isNative: Boolean = delegate.definedMethod.isNative - - override def getSubSignature: String = delegate.definedMethod.signature.toString + override def getSubSignature: String = MethodSignature(delegate.name, delegate.descriptor).toJava override def getName: String = delegate.name - override def isStatic: Boolean = delegate.definedMethod.isStatic - - override def isConstructor: Boolean = delegate.definedMethod.isConstructor - - override def getSignature: String = delegate.definedMethod.fullyQualifiedSignature - - override def getDeclaringClass: WrappedClass = OpalWrappedClass(delegate.definedMethod.classFile) - - override def getParameterTypes: util.List[Type] = { - val result = new util.ArrayList[Type]() - - delegate.definedMethod.parameterTypes.foreach(paramType => { - result.add(OpalType(paramType)) - }) - - result - } - - override def getParameterType(index: Int): Type = getParameterTypes.get(index) - - override def toString: String = getSignature -} - -case class OpalPhantomDeclaredMethod(invokeExpr: InvokeExpr, declaringClass: ReferenceType, name: String, descriptor: MethodDescriptor, static: Boolean) extends DeclaredMethod(invokeExpr) { + override def isConstructor: Boolean = delegate.name == OpalFrameworkScope.CONSTRUCTOR - override def isNative: Boolean = false - - override def getSubSignature: String = MethodSignature(name, descriptor).toJava - - override def getName: String = name - - override def isStatic: Boolean = static - - override def isConstructor: Boolean = name == "" - - override def getSignature: String = descriptor.toJava(s"${declaringClass.toJava}.$name") + override def getSignature: String = delegate.descriptor.toJava(s"${delegate.declaringClass.toJava}.${delegate.name}") override def getDeclaringClass: WrappedClass = { - val decClass = OpalClient.getClassFileForType(declaringClass.asObjectType) + val decClass = OpalClient.getClassFileForType(delegate.declaringClass.asObjectType) if (decClass.isDefined) { OpalWrappedClass(decClass.get) } else { - OpalPhantomWrappedClass(declaringClass) + OpalPhantomWrappedClass(delegate.declaringClass) } } override def getParameterTypes: util.List[Type] = { val result = new util.ArrayList[Type]() - descriptor.parameterTypes.foreach(paramType => { + delegate.descriptor.parameterTypes.foreach(paramType => { result.add(OpalType(paramType)) }) @@ -73,5 +40,7 @@ case class OpalPhantomDeclaredMethod(invokeExpr: InvokeExpr, declaringClass: Ref override def getParameterType(index: Int): Type = getParameterTypes.get(index) - override def toString: String = getSignature + override def getReturnType: Type = OpalType(delegate.descriptor.returnType) + + override def toString: String = delegate.descriptor.toJava } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalIfStatement.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalIfStatement.scala index d9688c099..f297e3037 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalIfStatement.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalIfStatement.scala @@ -14,7 +14,7 @@ class OpalIfStatement(val delegate: If[DUVar[ValueInformation]], method: OpalMet new OpalStatement(tac.stmts(target), method) } - override def evaluate(otherVal: Val): IfStatement.Evaluation = IfStatement.Evaluation.UNKOWN + override def evaluate(otherVal: Val): IfStatement.Evaluation = IfStatement.Evaluation.UNKNOWN override def uses(otherVal: Val): Boolean = { // TODO diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalInvokeExpr.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalInvokeExpr.scala index 4da7337ce..60cbb4b1c 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalInvokeExpr.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalInvokeExpr.scala @@ -1,6 +1,5 @@ package boomerang.scope.opal.tac -import boomerang.scope.opal.OpalClient import boomerang.scope.{DeclaredMethod, InvokeExpr, Val} import org.opalj.tac._ import org.opalj.value.ValueInformation @@ -31,15 +30,7 @@ class OpalMethodInvokeExpr(val delegate: MethodCall[DUVar[ValueInformation]], me throw new RuntimeException("Method call is not an instance invoke expression") } - override def getMethod: DeclaredMethod = { - val resolvedMethod = OpalClient.resolveMethodRef(delegate.declaringClass, delegate.name, delegate.descriptor) - - if (resolvedMethod.isDefined) { - OpalDeclaredMethod(this, resolvedMethod.get) - } else { - OpalPhantomDeclaredMethod(this, delegate.declaringClass, delegate.name, delegate.descriptor, delegate.isStaticMethodCall) - } - } + override def getMethod: DeclaredMethod = OpalDeclaredMethod(this, delegate) override def isSpecialInvokeExpr: Boolean = delegate.astID == NonVirtualMethodCall.ASTID @@ -81,15 +72,7 @@ class OpalFunctionInvokeExpr(val delegate: FunctionCall[DUVar[ValueInformation]] throw new RuntimeException("Function call is not an instance invoke expression") } - override def getMethod: DeclaredMethod = { - val resolvedMethod = OpalClient.resolveMethodRef(delegate.declaringClass, delegate.name, delegate.descriptor) - - if (resolvedMethod.isDefined) { - OpalDeclaredMethod(this, resolvedMethod.get) - } else { - OpalPhantomDeclaredMethod(this, delegate.declaringClass, delegate.name, delegate.descriptor, delegate.isStaticFunctionCall) - } - } + override def getMethod: DeclaredMethod = OpalDeclaredMethod(this, delegate) override def isSpecialInvokeExpr: Boolean = delegate.astID == NonVirtualFunctionCall.ASTID diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalMethod.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalMethod.scala index 89dd9b58c..904ff35e6 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalMethod.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalMethod.scala @@ -2,7 +2,6 @@ package boomerang.scope.opal.tac import boomerang.scope._ import boomerang.scope.opal.OpalClient -import org.opalj.br.{MethodDescriptor, MethodSignature, ObjectType} import org.opalj.tac.{InstanceFunctionCall, InstanceMethodCall, UVar} import java.util @@ -40,6 +39,8 @@ case class OpalMethod(delegate: org.opalj.br.Method) extends Method { override def getParameterType(index: Int): Type = getParameterTypes.get(index) + override def getReturnType: Type = OpalType(delegate.descriptor.returnType) + override def isThisLocal(fact: Val): Boolean = { if (isStatic) return false @@ -154,7 +155,9 @@ case class OpalMethod(delegate: org.opalj.br.Method) extends Method { override def isStatic: Boolean = delegate.isStatic - override def isNative: Boolean = delegate.isNative + override def isDefined: Boolean = true + + override def isPhantom: Boolean = false override def getStatements: util.List[Statement] = cfg.getStatements @@ -168,52 +171,5 @@ case class OpalMethod(delegate: org.opalj.br.Method) extends Method { override def isConstructor: Boolean = delegate.isConstructor - override def isPublic: Boolean = delegate.isPublic - override def toString: String = delegate.toJava } - -case class OpalPhantomMethod(declaringClassType: ObjectType, name: String, descriptor: MethodDescriptor, isStatic: Boolean) extends Method { - - override def isStaticInitializer: Boolean = name == "" - - override def isParameterLocal(value: Val): Boolean = false - - override def getParameterTypes: util.List[Type] = { - val result = new util.ArrayList[Type]() - - descriptor.parameterTypes.foreach(paramType => { - result.add(OpalType(paramType)) - }) - - result - } - - override def getParameterType(index: Int): Type = OpalType(descriptor.parameterType(index)) - - override def isThisLocal(value: Val): Boolean = false - - override def getLocals: util.Set[Val] = throw new RuntimeException("Locals of phantom method are not available") - - override def getThisLocal: Val = throw new RuntimeException("this local of phantom method is not available") - - override def getParameterLocals: util.List[Val] = throw new RuntimeException("Parameter locals of phantom method are not available") - - override def isNative: Boolean = false - - override def getStatements: util.List[Statement] = new util.ArrayList[Statement]() - - override def getDeclaringClass: WrappedClass = OpalPhantomWrappedClass(declaringClassType) - - override def getControlFlowGraph: ControlFlowGraph = throw new RuntimeException("CFG of phantom method is not available") - - override def getSubSignature: String = MethodSignature(name, descriptor).toJava - - override def getName: String = name - - override def isConstructor: Boolean = name == "" - - override def isPublic: Boolean = true - - override def toString: String = "PHANTOM: " + getSubSignature -} diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalPhantomMethod.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalPhantomMethod.scala new file mode 100644 index 000000000..66beba5e3 --- /dev/null +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalPhantomMethod.scala @@ -0,0 +1,57 @@ +package boomerang.scope.opal.tac + +import boomerang.scope.opal.OpalFrameworkScope +import boomerang.scope.{ControlFlowGraph, Method, Statement, Type, Val, WrappedClass} +import org.opalj.br.{MethodSignature, VirtualDeclaredMethod} + +import java.util + +case class OpalPhantomMethod(delegate: VirtualDeclaredMethod, static: Boolean) extends Method { + + override def isStaticInitializer: Boolean = delegate.name == OpalFrameworkScope.STATIC_INITIALIZER + + override def isParameterLocal(value: Val): Boolean = false + + override def getParameterTypes: util.List[Type] = { + val result = new util.ArrayList[Type]() + + delegate.descriptor.parameterTypes.foreach(paramType => { + result.add(OpalType(paramType)) + }) + + result + } + + override def getParameterType(index: Int): Type = OpalType(delegate.descriptor.parameterType(index)) + + override def getReturnType: Type = OpalType(delegate.descriptor.returnType) + + override def isThisLocal(value: Val): Boolean = false + + override def getLocals: util.Collection[Val] = throw new RuntimeException("Locals of phantom method are not available") + + override def getThisLocal: Val = throw new RuntimeException("this local of phantom method is not available") + + override def getParameterLocals: util.List[Val] = throw new RuntimeException("Parameter locals of phantom method are not available") + + override def isStatic: Boolean = static + + override def isDefined: Boolean = false + + override def isPhantom: Boolean = true + + override def getStatements: util.List[Statement] = throw new RuntimeException("Statements of phantom method are not available") + + // TODO + override def getDeclaringClass: WrappedClass = OpalPhantomWrappedClass(delegate.declaringClassType) + + override def getControlFlowGraph: ControlFlowGraph = throw new RuntimeException("CFG of phantom method is not available") + + override def getSubSignature: String = MethodSignature(delegate.name, delegate.descriptor).toJava + + override def getName: String = delegate.name + + override def isConstructor: Boolean = delegate.name == OpalFrameworkScope.CONSTRUCTOR + + override def toString: String = "PHANTOM: " + delegate.toJava +} diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalPhantomWrappedClass.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalPhantomWrappedClass.scala new file mode 100644 index 000000000..198e5ec56 --- /dev/null +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalPhantomWrappedClass.scala @@ -0,0 +1,25 @@ +package boomerang.scope.opal.tac + +import boomerang.scope.{Method, Type, WrappedClass} +import org.opalj.br.ReferenceType + +import java.util + +case class OpalPhantomWrappedClass(delegate: ReferenceType) extends WrappedClass { + + override def getMethods: util.Set[Method] = throw new RuntimeException("Methods of class " + delegate.toString + " are not available") + + override def hasSuperclass: Boolean = false + + override def getSuperclass: WrappedClass = throw new RuntimeException("Super class of " + delegate.toString + " is not available") + + override def getType: Type = OpalType(delegate) + + override def isApplicationClass: Boolean = false + + override def getFullyQualifiedName: String = delegate.toJava + + override def isPhantom: Boolean = true + + override def toString: String = delegate.toString +} diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala index cd704ed42..71f51f80b 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala @@ -83,10 +83,10 @@ class OpalStatement(val delegate: Stmt[DUVar[ValueInformation]], m: OpalMethod) false } - override def isAssign: Boolean = delegate.isAssignment || isFieldStore || isArrayStore + override def isAssignStmt: Boolean = delegate.isAssignment || isFieldStore || isArrayStore override def getLeftOp: Val = { - if (isAssign) { + if (isAssignStmt) { if (delegate.isAssignment) { // TODO Change to variable return new OpalVal(delegate.asAssignment.targetVar, m) @@ -113,7 +113,7 @@ class OpalStatement(val delegate: Stmt[DUVar[ValueInformation]], m: OpalMethod) } override def getRightOp: Val = { - if (isAssign) { + if (isAssignStmt) { if (delegate.isAssignment) { val rightExpr = delegate.asAssignment.expr @@ -200,14 +200,6 @@ class OpalStatement(val delegate: Stmt[DUVar[ValueInformation]], m: OpalMethod) override def isMultiArrayAllocation: Boolean = false - override def isStringAllocation: Boolean = { - if (delegate.isAssignment) { - return delegate.asAssignment.expr.isStringConst - } - - throw new RuntimeException("Statement is not an allocation statement") - } - override def isFieldStore: Boolean = { if (!delegate.isPutField) { return false @@ -350,14 +342,14 @@ class OpalStatement(val delegate: Stmt[DUVar[ValueInformation]], m: OpalMethod) base = getInvokeExpr.getBase.toString + "." } var assign = "" - if (isAssign) { + if (isAssignStmt) { assign = getLeftOp + " = " } return assign + base + getInvokeExpr.getMethod.getName + "(" + Joiner.on(",").join(getInvokeExpr.getArgs) + ")" } - if (isAssign) { + if (isAssignStmt) { if (delegate.isAssignment) { if (getRightOp.isNewExpr) { return s"$getLeftOp = new + ${getRightOp.getNewExprType}" diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalWrappedClass.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalWrappedClass.scala index 5d3304dd7..a94373e63 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalWrappedClass.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalWrappedClass.scala @@ -40,31 +40,7 @@ case class OpalWrappedClass(delegate: ClassFile) extends WrappedClass { override def getFullyQualifiedName: String = delegate.fqn - override def getName: String = delegate.thisType.toJava + override def isPhantom: Boolean = false override def toString: String = delegate.toString() - - override def getDelegate: AnyRef = delegate -} - -case class OpalPhantomWrappedClass(delegate: ReferenceType) extends WrappedClass { - - override def getMethods: util.Set[Method] = throw new RuntimeException("Methods of class " + delegate.toString + " are not available") - - override def hasSuperclass: Boolean = false - - override def getSuperclass: WrappedClass = throw new RuntimeException("Super class of " + delegate.toString + " is not available") - - override def getType: Type = OpalType(delegate) - - override def isApplicationClass: Boolean = false - - override def getFullyQualifiedName: String = delegate.toJava - - override def getName: String = delegate.toJava - - override def getDelegate: AnyRef = delegate - - override def toString: String = delegate.toString - } diff --git a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleType.java b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleType.java index 2798f5ea9..a61dbf342 100644 --- a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleType.java +++ b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleType.java @@ -187,41 +187,4 @@ public int hashCode() { public String toString() { return delegate.toString(); } - - private Collection getFullHierarchy(SootClass sourceClass, Set visited) { - Set result = new HashSet<>(); - - if (visited.contains(sourceClass)) { - return result; - } - - result.add(sourceClass); - visited.add(sourceClass); - - // Super interfaces - Collection interfaces = sourceClass.getInterfaces(); - for (SootClass intFace : interfaces) { - result.addAll(getFullHierarchy(intFace, visited)); - } - - if (sourceClass.isInterface()) { - // Super interfaces - Collection superInterfaces = - Scene.v().getActiveHierarchy().getSuperinterfacesOf(sourceClass); - - for (SootClass superInterface : superInterfaces) { - result.addAll(getFullHierarchy(superInterface, visited)); - } - } else { - // Super classes - Collection superClasses = - Scene.v().getActiveHierarchy().getSuperclassesOf(sourceClass); - - for (SootClass superClass : superClasses) { - result.addAll(getFullHierarchy(superClass, visited)); - } - } - - return result; - } } diff --git a/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALAType.java b/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALAType.java index 7750d397f..55caf7f69 100644 --- a/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALAType.java +++ b/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALAType.java @@ -80,6 +80,7 @@ private boolean isSubclassOf(WALAType targetType) { return meet.equals(typeAbstraction); } + @Override public boolean isSupertypeOf(String subType) { throw new RuntimeException("Not implemented"); } @@ -117,11 +118,6 @@ public boolean isSubtypeOf(String type) { return typeAbstraction.equals(TypeAbstraction.TOP); } - @Override - public boolean isSupertypeOf(String subType) { - throw new UnsupportedOperationException("Not implemented yet"); - } - private boolean hasClassInterface(IClass next, String t) { if (next.getName().toString().equals(t)) { return true; From 8ff6fce89cde24aaaedba16a5da666ab9292805c Mon Sep 17 00:00:00 2001 From: Sven Meyer Date: Mon, 10 Mar 2025 10:44:42 +0100 Subject: [PATCH 09/61] First version of OpalTestSetup --- .../scope/opal/OpalFrameworkScope.scala | 1 + .../boomerang/scope/opal/tac/OpalLocal.scala | 2 + .../scope/opal/tac/OpalStatement.scala | 4 +- .../boomerang/scope/opal/tac/OpalType.scala | 2 +- .../src/main/java/test/TestingFramework.java | 4 +- .../main/java/test/setup/OpalTestSetup.java | 82 +++++++++++++++++++ .../src/main/java/test/setup/TestSetup.java | 2 +- .../main/scala/test/setup/OpalTestSetup.scala | 13 --- 8 files changed, 91 insertions(+), 19 deletions(-) create mode 100644 testCore/src/main/java/test/setup/OpalTestSetup.java delete mode 100644 testCore/src/main/scala/test/setup/OpalTestSetup.scala diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalFrameworkScope.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalFrameworkScope.scala index 5af488f58..a048ed5e5 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalFrameworkScope.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalFrameworkScope.scala @@ -7,6 +7,7 @@ import java.util.stream class OpalFrameworkScope(project: Project[_], callGraph: org.opalj.tac.cg.CallGraph, entryPoints: Set[org.opalj.br.Method], dataFlowScope: DataFlowScope) extends FrameworkScope { + OpalClient.init(project) val opalCallGraph = new OpalCallGraph(callGraph, entryPoints) override def getCallGraph: CallGraph = opalCallGraph diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalLocal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalLocal.scala index 1d6adbbae..fe3fa3b52 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalLocal.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalLocal.scala @@ -149,6 +149,8 @@ class OpalLocal(val delegate: Expr[DUVar[ValueInformation]], method: OpalMethod, val targetVar = defStmt.asAssignment.targetVar super.equals(other) && dVar.hashCode() == targetVar.hashCode() + case _: UVar[_] if other.delegate.isInstanceOf[UVar[_]] => + super.equals(other) && this.delegate.hashCode() == other.delegate.hashCode() case _ => throw new RuntimeException("Cannot compare a variable with a non variable") } case _ => false diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala index 71f51f80b..d51e3ca32 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala @@ -89,7 +89,7 @@ class OpalStatement(val delegate: Stmt[DUVar[ValueInformation]], m: OpalMethod) if (isAssignStmt) { if (delegate.isAssignment) { // TODO Change to variable - return new OpalVal(delegate.asAssignment.targetVar, m) + return new OpalLocal(delegate.asAssignment.targetVar, m) } if (isFieldStore) { @@ -352,7 +352,7 @@ class OpalStatement(val delegate: Stmt[DUVar[ValueInformation]], m: OpalMethod) if (isAssignStmt) { if (delegate.isAssignment) { if (getRightOp.isNewExpr) { - return s"$getLeftOp = new + ${getRightOp.getNewExprType}" + return s"$getLeftOp = new ${getRightOp.getNewExprType}" } else { // TODO Array load return getLeftOp + " = " + getRightOp diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalType.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalType.scala index 289b13933..356088ab7 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalType.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalType.scala @@ -48,7 +48,7 @@ case class OpalType(delegate: org.opalj.br.Type, isNull: Boolean = false) extend return false } - OpalClient.getClassHierarchy.isSubtypeOf(delegate.asObjectType, ObjectType(otherType)) + OpalClient.getClassHierarchy.isSubtypeOf(delegate.asObjectType, ObjectType(otherType.replace(".", "/"))) } override def isSupertypeOf(subType: String): Boolean = { diff --git a/testCore/src/main/java/test/TestingFramework.java b/testCore/src/main/java/test/TestingFramework.java index be61fa16a..7c38fdd11 100644 --- a/testCore/src/main/java/test/TestingFramework.java +++ b/testCore/src/main/java/test/TestingFramework.java @@ -10,7 +10,7 @@ import java.util.stream.Collectors; import org.junit.Assert; import test.setup.MethodWrapper; -import test.setup.SootTestSetup; +import test.setup.OpalTestSetup; import test.setup.TestSetup; public class TestingFramework { @@ -19,7 +19,7 @@ public class TestingFramework { public TestingFramework() { // TODO Parameterize - this.testSetup = new SootTestSetup(); + this.testSetup = new OpalTestSetup(); } public FrameworkScope getFrameworkScope(MethodWrapper methodWrapper) { diff --git a/testCore/src/main/java/test/setup/OpalTestSetup.java b/testCore/src/main/java/test/setup/OpalTestSetup.java new file mode 100644 index 000000000..ea3f09a9c --- /dev/null +++ b/testCore/src/main/java/test/setup/OpalTestSetup.java @@ -0,0 +1,82 @@ +package test.setup; + +import boomerang.scope.DataFlowScope; +import boomerang.scope.FrameworkScope; +import boomerang.scope.Method; +import boomerang.scope.opal.OpalFrameworkScope; +import boomerang.scope.opal.tac.OpalMethod; +import java.io.File; +import java.net.URL; +import java.util.List; +import java.util.Set; +import org.opalj.br.ClassFile; +import org.opalj.br.MethodDescriptor$; +import org.opalj.br.ObjectType; +import org.opalj.br.analyses.Project; +import org.opalj.log.DevNullLogger$; +import org.opalj.log.GlobalLogContext$; +import org.opalj.log.OPALLogger; +import org.opalj.tac.cg.CHACallGraphKey$; +import org.opalj.tac.cg.CallGraph; +import scala.Option; +import scala.jdk.javaapi.CollectionConverters; + +public class OpalTestSetup implements TestSetup { + + private Project project; + private org.opalj.br.Method testMethod; + + @Override + public void initialize( + String classPath, + MethodWrapper methodWrapper, + List includedPackages, + List excludedPackages) { + OPALLogger.updateLogger(GlobalLogContext$.MODULE$, DevNullLogger$.MODULE$); + + project = Project.apply(new File(classPath)); + + Option testClass = + project.classFile(ObjectType.apply(methodWrapper.getDeclaringClass().replace(".", "/"))); + if (testClass.isEmpty()) { + throw new RuntimeException("Could not find class " + methodWrapper.getDeclaringClass()); + } + + // Opal resolves 'void' with 'Void' TODO Add parameters + String signature = + "()" + + ((methodWrapper.getReturnType().equals(MethodWrapper.VOID)) + ? "Void" + : methodWrapper.getReturnType()); + Option method = + testClass + .get() + .findMethod(methodWrapper.getMethodName(), MethodDescriptor$.MODULE$.apply(signature)); + if (method.isEmpty()) { + throw new RuntimeException( + "Could not find method " + + methodWrapper.getMethodName() + + " in class " + + methodWrapper.getDeclaringClass()); + } + + testMethod = method.get(); + } + + @Override + public Method getTestMethod() { + return new OpalMethod(testMethod); + } + + @Override + public FrameworkScope createFrameworkScope(DataFlowScope dataFlowScope) { + // TODO Shrink to application and included classes only + CallGraph callGraph = project.get(CHACallGraphKey$.MODULE$); + + return new OpalFrameworkScope( + project, + callGraph, + CollectionConverters.asScala(Set.of(testMethod)).toSet(), + dataFlowScope); + } +} diff --git a/testCore/src/main/java/test/setup/TestSetup.java b/testCore/src/main/java/test/setup/TestSetup.java index 9f3e4a0cd..bac33ffa3 100644 --- a/testCore/src/main/java/test/setup/TestSetup.java +++ b/testCore/src/main/java/test/setup/TestSetup.java @@ -9,7 +9,7 @@ public interface TestSetup { void initialize( String classPath, - MethodWrapper testMethod, + MethodWrapper methodWrapper, List includedPackages, List excludedPackages); diff --git a/testCore/src/main/scala/test/setup/OpalTestSetup.scala b/testCore/src/main/scala/test/setup/OpalTestSetup.scala deleted file mode 100644 index b0ddb8c11..000000000 --- a/testCore/src/main/scala/test/setup/OpalTestSetup.scala +++ /dev/null @@ -1,13 +0,0 @@ -package test.setup -import boomerang.scope.{DataFlowScope, FrameworkScope, Method} - -import java.util - -class OpalTestSetup extends TestSetup { - - override def initialize(classPath: String, testMethod: MethodWrapper, includedPackages: util.List[String], excludedPackages: util.List[String]): Unit = ??? - - override def getTestMethod: Method = ??? - - override def createFrameworkScope(dataFlowScope: DataFlowScope): FrameworkScope = ??? -} From 8df3fcbd1fcbb0deca1566a097d210a71683e6ff Mon Sep 17 00:00:00 2001 From: Sven Meyer Date: Tue, 11 Mar 2025 09:51:26 +0100 Subject: [PATCH 10/61] Small fix --- .../src/main/java/boomerang/solver/BackwardBoomerangSolver.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boomerangPDS/src/main/java/boomerang/solver/BackwardBoomerangSolver.java b/boomerangPDS/src/main/java/boomerang/solver/BackwardBoomerangSolver.java index e65e7f514..904c29526 100644 --- a/boomerangPDS/src/main/java/boomerang/solver/BackwardBoomerangSolver.java +++ b/boomerangPDS/src/main/java/boomerang/solver/BackwardBoomerangSolver.java @@ -79,7 +79,7 @@ private boolean notUsedInMethod(Method m, Statement curr, Val value) { if (value.isStatic()) { return false; } - return m.getLocals().stream().noneMatch(local -> local.toString().equals(value.toString())); + return m.getLocals().stream().noneMatch(local -> local.equals(value)); } public INode> generateFieldState( From 0e2c62782e7d93e00324a06f2f9b02a4bfdd05c5 Mon Sep 17 00:00:00 2001 From: Sven Meyer Date: Tue, 11 Mar 2025 10:11:12 +0100 Subject: [PATCH 11/61] Some pom updates --- boomerangScope-Opal/pom.xml | 8 ++++---- testCore/pom.xml | 4 ++++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/boomerangScope-Opal/pom.xml b/boomerangScope-Opal/pom.xml index 07ba5fac9..e285e28b9 100644 --- a/boomerangScope-Opal/pom.xml +++ b/boomerangScope-Opal/pom.xml @@ -5,7 +5,7 @@ 4.0.0 de.fraunhofer.iem - SPDS + Boomerang-Parent 3.2.4-SNAPSHOT @@ -13,7 +13,8 @@ 5.0.0 - 2.13.14 + 2.13.16 + ${project.parent.basedir} @@ -39,7 +40,7 @@ net.alchim31.maven scala-maven-plugin - 4.8.1 + 4.9.2 incremental ${scala.version} @@ -54,5 +55,4 @@ - diff --git a/testCore/pom.xml b/testCore/pom.xml index c13daa8e4..288ee5ab9 100644 --- a/testCore/pom.xml +++ b/testCore/pom.xml @@ -37,6 +37,10 @@ de.fraunhofer.iem boomerangScope-SootUp + + de.fraunhofer.iem + boomerangScope-Opal + junit junit From 945f736407c62adb7b35ccfe33020cef456095eb Mon Sep 17 00:00:00 2001 From: Sven Meyer Date: Tue, 11 Mar 2025 12:30:57 +0100 Subject: [PATCH 12/61] Use explicit parameter local --- boomerangScope-Opal/pom.xml | 20 +++--- .../src/main/scala/boomerang/scope/Main.scala | 20 ++++-- .../boomerang/scope/opal/tac/OpalMethod.scala | 9 +++ .../scope/opal/tac/OpalParameterLocal.scala | 65 +++++++++++++++++++ .../scope/opal/tac/OpalStatement.scala | 6 +- pom.xml | 9 ++- .../main/java/test/setup/OpalTestSetup.java | 11 ++++ 7 files changed, 119 insertions(+), 21 deletions(-) create mode 100644 boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalParameterLocal.scala diff --git a/boomerangScope-Opal/pom.xml b/boomerangScope-Opal/pom.xml index e285e28b9..23b48123f 100644 --- a/boomerangScope-Opal/pom.xml +++ b/boomerangScope-Opal/pom.xml @@ -1,7 +1,6 @@ - + 4.0.0 de.fraunhofer.iem @@ -13,7 +12,6 @@ 5.0.0 - 2.13.16 ${project.parent.basedir} @@ -22,11 +20,6 @@ de.fraunhofer.iem boomerangScope - - org.scala-lang - scala-library - ${scala.version} - de.opal-project framework_2.13 @@ -35,24 +28,27 @@ - src/main/scala net.alchim31.maven scala-maven-plugin 4.9.2 - incremental - ${scala.version} + all + + -deprecation + + add-source compile + src/main/scala diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/Main.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/Main.scala index c59eb6c52..dbe680105 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/Main.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/Main.scala @@ -1,8 +1,6 @@ package boomerang.scope -import boomerang.scope.opal.tac.OpalMethod import boomerang.scope.opal.{OpalCallGraph, OpalClient} -import com.typesafe.config.ConfigValueFactory import org.opalj.br.analyses.Project import org.opalj.br.analyses.cg.InitialEntryPointsKey import org.opalj.log.{DevNullLogger, GlobalLogContext, OPALLogger} @@ -15,8 +13,20 @@ object Main { def main(args: Array[String]): Unit = { OPALLogger.updateLogger(GlobalLogContext, DevNullLogger) - val project = Project(new File("C:\\Users\\Sven\\Documents\\CogniCrypt\\Opal\\Array\\Array.jar")) - var config = project.config + val project = Project(new File("C:\\Users\\Sven\\Documents\\CogniCrypt\\Opal\\Parameter\\Parameter.jar")) + OpalClient.init(project) + + val callGraph = project.get(CHACallGraphKey) + val entryPoints = project.get(InitialEntryPointsKey) + val opalCallGraph = new OpalCallGraph(callGraph, entryPoints.toSet) + + opalCallGraph.getReachableMethods.forEach(method => { + if (method.isDefined) { + print(method.getParameterLocals) + } + }) + + /*var config = project.config val key = s"${InitialEntryPointsKey.ConfigKeyPrefix}entryPoints" println("InitialEntryPoints " + key) @@ -54,6 +64,6 @@ object Main { method.getStatements.forEach(statement => { }) - }) + })*/ } } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalMethod.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalMethod.scala index 904ff35e6..633bb59f4 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalMethod.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalMethod.scala @@ -132,6 +132,15 @@ case class OpalMethod(delegate: org.opalj.br.Method) extends Method { } override def getParameterLocals: util.List[Val] = { + if (parameterLocalCache.isEmpty) { + parameterLocalCache = Some(new util.ArrayList[Val]()) + + delegate.parameterTypes.foreach(param => { + val parameterLocal = new OpalParameterLocal(param, this) + parameterLocalCache.get.add(parameterLocal) + }) + } + if (parameterLocalCache.isEmpty) { parameterLocalCache = Some(new util.ArrayList[Val]()) diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalParameterLocal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalParameterLocal.scala new file mode 100644 index 000000000..b4b9e7a56 --- /dev/null +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalParameterLocal.scala @@ -0,0 +1,65 @@ +package boomerang.scope.opal.tac + +import boomerang.scope.{ControlFlowGraph, Method, Pair, Type, Val} +import org.opalj.br.FieldType + +class OpalParameterLocal(parameterType: FieldType, method: OpalMethod, unbalanced: ControlFlowGraph.Edge = null) extends Val(method, unbalanced) { + + override def getType: Type = OpalType(parameterType) + + override def isStatic: Boolean = false + + override def isNewExpr: Boolean = false + + override def getNewExprType: Type = throw new RuntimeException("Parameter local is not a new expression") + + override def asUnbalanced(stmt: ControlFlowGraph.Edge): Val = new OpalParameterLocal(parameterType, method, stmt) + + override def isLocal: Boolean = true + + override def isArrayAllocationVal: Boolean = false + + override def getArrayAllocationSize: Val = throw new RuntimeException("Parameter local is not an array allocation val") + + override def isNull: Boolean = false + + override def isStringConstant: Boolean = false + + override def getStringValue: String = throw new RuntimeException("Parameter local is not a string constant") + + override def isStringBufferOrBuilder: Boolean = false + + override def isThrowableAllocationType: Boolean = false + + override def isCast: Boolean = false + + override def getCastOp: Val = throw new RuntimeException("Parameter local is not a cast expression") + + override def isArrayRef: Boolean = ??? + + override def isInstanceOfExpr: Boolean = false + + override def getInstanceOfOp: Val = throw new RuntimeException("Parameter local is not an instanceOf expression") + + override def isLengthExpr: Boolean = false + + override def getLengthOp: Val = throw new RuntimeException("Parameter local is not a length expression") + + override def isIntConstant: Boolean = false + + override def isClassConstant: Boolean = false + + override def getClassConstantType: Type = throw new RuntimeException("Parameter local is not a class constant") + + override def withNewMethod(callee: Method): Val = new OpalParameterLocal(parameterType, callee.asInstanceOf[OpalMethod]) + + override def isLongConstant: Boolean = false + + override def getIntValue: Int = throw new RuntimeException("Parameter local is not an int constant") + + override def getLongValue: Long = throw new RuntimeException("Parameter local is not a long constant") + + override def getArrayBase: Pair[Val, Integer] = throw new RuntimeException("Parameter local is not an array ref") + + override def getVariableName: String = ??? +} diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala index d51e3ca32..b1ae249d7 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala @@ -339,11 +339,11 @@ class OpalStatement(val delegate: Stmt[DUVar[ValueInformation]], m: OpalMethod) if (containsInvokeExpr()) { var base = "" if (getInvokeExpr.isInstanceInvokeExpr) { - base = getInvokeExpr.getBase.toString + "." + base = s"${getInvokeExpr.getBase}." } var assign = "" if (isAssignStmt) { - assign = getLeftOp + " = " + assign = s"$getLeftOp = " } return assign + base + getInvokeExpr.getMethod.getName + "(" + Joiner.on(",").join(getInvokeExpr.getArgs) + ")" @@ -355,7 +355,7 @@ class OpalStatement(val delegate: Stmt[DUVar[ValueInformation]], m: OpalMethod) return s"$getLeftOp = new ${getRightOp.getNewExprType}" } else { // TODO Array load - return getLeftOp + " = " + getRightOp + return s"$getLeftOp = $getRightOp" } } else if (isFieldStore) { return s"$getLeftOp = $getWrittenField" diff --git a/pom.xml b/pom.xml index 774e430d3..36aebfbc7 100644 --- a/pom.xml +++ b/pom.xml @@ -75,6 +75,7 @@ UTF-8 11 + 2.13.16 3.6.1 ${project.basedir} @@ -162,8 +163,14 @@ guava 33.4.0-jre + + + org.scala-lang + scala-library + ${scala.version} + - + diff --git a/testCore/src/main/java/test/setup/OpalTestSetup.java b/testCore/src/main/java/test/setup/OpalTestSetup.java index ea3f09a9c..03d2a9098 100644 --- a/testCore/src/main/java/test/setup/OpalTestSetup.java +++ b/testCore/src/main/java/test/setup/OpalTestSetup.java @@ -1,3 +1,14 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ package test.setup; import boomerang.scope.DataFlowScope; From 061ce5cc94d8e3505d5727ecedd401e6e85fffb5 Mon Sep 17 00:00:00 2001 From: Sven Meyer Date: Tue, 11 Mar 2025 14:12:12 +0100 Subject: [PATCH 13/61] Create test setup for scopes --- boomerangScope-Soot/pom.xml | 11 +++ .../test/java/scope/soot/SootScopeTest.java | 51 +++++++++++++ .../src/test/java/scope/soot/SootSetup.java | 58 +++++++++++++++ boomerangScope/pom.xml | 21 ++++++ .../scope/test/BoomerangScopeTests.java | 7 ++ .../boomerang/scope/test/MethodSignature.java | 72 +++++++++++++++++++ .../boomerang/scope/test/TargetClassPath.java | 8 +++ .../java/boomerang/scope/test/targets/A.java | 4 ++ .../scope/test/targets/ParameterLocals.java | 20 ++++++ 9 files changed, 252 insertions(+) create mode 100644 boomerangScope-Soot/src/test/java/scope/soot/SootScopeTest.java create mode 100644 boomerangScope-Soot/src/test/java/scope/soot/SootSetup.java create mode 100644 boomerangScope/src/test/java/boomerang/scope/test/BoomerangScopeTests.java create mode 100644 boomerangScope/src/test/java/boomerang/scope/test/MethodSignature.java create mode 100644 boomerangScope/src/test/java/boomerang/scope/test/TargetClassPath.java create mode 100644 boomerangScope/src/test/java/boomerang/scope/test/targets/A.java create mode 100644 boomerangScope/src/test/java/boomerang/scope/test/targets/ParameterLocals.java diff --git a/boomerangScope-Soot/pom.xml b/boomerangScope-Soot/pom.xml index 57efa7e4b..0af325789 100644 --- a/boomerangScope-Soot/pom.xml +++ b/boomerangScope-Soot/pom.xml @@ -31,10 +31,21 @@ de.fraunhofer.iem boomerangScope + + de.fraunhofer.iem + boomerangScope + ${project.version} + test-jar + test + org.soot-oss soot ${soot.version} + + junit + junit + diff --git a/boomerangScope-Soot/src/test/java/scope/soot/SootScopeTest.java b/boomerangScope-Soot/src/test/java/scope/soot/SootScopeTest.java new file mode 100644 index 000000000..411c9ebc1 --- /dev/null +++ b/boomerangScope-Soot/src/test/java/scope/soot/SootScopeTest.java @@ -0,0 +1,51 @@ +package scope.soot; + +import boomerang.scope.Method; +import boomerang.scope.soot.jimple.JimpleMethod; +import boomerang.scope.test.BoomerangScopeTests; +import boomerang.scope.test.MethodSignature; +import boomerang.scope.test.targets.A; +import boomerang.scope.test.targets.ParameterLocals; +import org.junit.Assert; +import org.junit.Test; +import soot.SootMethod; + +import java.util.List; + +public class SootScopeTest implements BoomerangScopeTests { + + private static MethodSignature mainMethod(String className) { + return new MethodSignature(className, "main", "void", List.of("java.lang.String[]")); + } + + @Test + @Override + public void parameterLocalTest() { + SootSetup sootSetup = new SootSetup(); + sootSetup.setupSoot(ParameterLocals.class.getName()); + + // No parameters + MethodSignature noArgsSignature = new MethodSignature(ParameterLocals.class.getName(), "noParameters"); + SootMethod noArgs = sootSetup.resolveMethod(noArgsSignature); + Method noArgsMethod = JimpleMethod.of(noArgs); + + Assert.assertTrue(noArgsMethod.getParameterLocals().isEmpty()); + + // One parameter (primitive type) + MethodSignature oneArgSignature = new MethodSignature(ParameterLocals.class.getName(), "oneParameter", List.of("int")); + SootMethod oneArg = sootSetup.resolveMethod(oneArgSignature); + Method oneArgMethod = JimpleMethod.of(oneArg); + + Assert.assertEquals(1, oneArgMethod.getParameterLocals().size()); + Assert.assertEquals("int", oneArgMethod.getParameterLocal(0).getType().toString()); + + // Two parameters (primitive type + RefType) + MethodSignature twoArgSignature = new MethodSignature(ParameterLocals.class.getName(), "twoParameters", List.of("int", A.class.getName())); + SootMethod twoArgs = sootSetup.resolveMethod(twoArgSignature); + Method twoArgsMethod = JimpleMethod.of(twoArgs); + + Assert.assertEquals(2, twoArgsMethod.getParameterLocals().size()); + Assert.assertEquals("int", twoArgsMethod.getParameterLocal(0).getType().toString()); + Assert.assertEquals(A.class.getName(), twoArgsMethod.getParameterLocal(1).getType().toString()); + } +} diff --git a/boomerangScope-Soot/src/test/java/scope/soot/SootSetup.java b/boomerangScope-Soot/src/test/java/scope/soot/SootSetup.java new file mode 100644 index 000000000..eb8fa4a01 --- /dev/null +++ b/boomerangScope-Soot/src/test/java/scope/soot/SootSetup.java @@ -0,0 +1,58 @@ +package scope.soot; + +import boomerang.scope.test.MethodSignature; +import boomerang.scope.test.TargetClassPath; +import soot.EntryPoints; +import soot.G; +import soot.PackManager; +import soot.Scene; +import soot.SootClass; +import soot.SootMethod; +import soot.options.Options; + +import java.io.File; +import java.util.List; + +public class SootSetup { + + private SootClass targetClass; + + public void setupSoot(String targetClassName) { + G.reset(); + + Options.v().set_whole_program(true); + Options.v().set_output_format(Options.output_format_none); + Options.v().set_no_bodies_for_excluded(true); + Options.v().set_allow_phantom_refs(true); + Options.v().set_keep_line_number(true); + + Options.v().set_soot_classpath("VIRTUAL_FS_FOR_JDK" + File.pathSeparator + TargetClassPath.TARGET_CLASS_PATH); + + Options.v().setPhaseOption("jb.sils", "enabled:false"); + Options.v().setPhaseOption("jb", "use-original-names:true"); + + Options.v().set_include(List.of(targetClassName)); + Options.v().setPhaseOption("cg.cha", "on"); + Options.v().setPhaseOption("cg.cha", "all-reachable:true"); + + targetClass = Scene.v().forceResolve(targetClassName, SootClass.BODIES); + targetClass.setApplicationClass(); + + Scene.v().loadNecessaryClasses(); + Scene.v().setEntryPoints(EntryPoints.v().application()); + + PackManager.v().getPack("cg").apply(); + } + + public SootMethod resolveMethod(MethodSignature methodSignature) { + String signature = + methodSignature.getReturnType() + + " " + + methodSignature.getMethodName() + + "(" + + String.join(",", methodSignature.getParameters()) + + ")"; + + return targetClass.getMethod(signature); + } +} diff --git a/boomerangScope/pom.xml b/boomerangScope/pom.xml index bd3d99544..b9def7892 100644 --- a/boomerangScope/pom.xml +++ b/boomerangScope/pom.xml @@ -29,5 +29,26 @@ de.fraunhofer.iem PDS + + junit + junit + + + + + + org.apache.maven.plugins + maven-jar-plugin + 3.4.2 + + + + test-jar + + + + + + diff --git a/boomerangScope/src/test/java/boomerang/scope/test/BoomerangScopeTests.java b/boomerangScope/src/test/java/boomerang/scope/test/BoomerangScopeTests.java new file mode 100644 index 000000000..948dafecb --- /dev/null +++ b/boomerangScope/src/test/java/boomerang/scope/test/BoomerangScopeTests.java @@ -0,0 +1,7 @@ +package boomerang.scope.test; + +@SuppressWarnings("unused") +public interface BoomerangScopeTests { + + void parameterLocalTest(); +} diff --git a/boomerangScope/src/test/java/boomerang/scope/test/MethodSignature.java b/boomerangScope/src/test/java/boomerang/scope/test/MethodSignature.java new file mode 100644 index 000000000..af925e56b --- /dev/null +++ b/boomerangScope/src/test/java/boomerang/scope/test/MethodSignature.java @@ -0,0 +1,72 @@ +package boomerang.scope.test; + +import java.util.Collections; +import java.util.List; +import java.util.Objects; + +public class MethodSignature { + + private final String declaringClass; + private final String methodName; + private final String returnType; + private final List parameters; + + public static final String VOID = "void"; + + public MethodSignature(String declaringClass, String methodName) { + this(declaringClass, methodName, VOID); + } + + public MethodSignature(String declaringClass, String methodName, String returnType) { + this(declaringClass, methodName, returnType, Collections.emptyList()); + } + + public MethodSignature(String declaringClass, String methodName, List parameters) { + this(declaringClass, methodName, VOID, parameters); + } + + public MethodSignature( + String declaringClass, String methodName, String returnType, List parameters) { + this.declaringClass = declaringClass; + this.methodName = methodName; + this.returnType = returnType; + this.parameters = parameters; + } + + public String getDeclaringClass() { + return declaringClass; + } + + public String getMethodName() { + return methodName; + } + + public String getReturnType() { + return returnType; + } + + public List getParameters() { + return parameters; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + MethodSignature that = (MethodSignature) o; + return Objects.equals(declaringClass, that.declaringClass) + && Objects.equals(methodName, that.methodName) + && Objects.equals(returnType, that.returnType) + && Objects.equals(parameters, that.parameters); + } + + @Override + public int hashCode() { + return Objects.hash(declaringClass, methodName, returnType, parameters); + } + + @Override + public String toString() { + return declaringClass + " " + returnType + " " + methodName + " " + parameters; + } +} diff --git a/boomerangScope/src/test/java/boomerang/scope/test/TargetClassPath.java b/boomerangScope/src/test/java/boomerang/scope/test/TargetClassPath.java new file mode 100644 index 000000000..2b93ac8f4 --- /dev/null +++ b/boomerangScope/src/test/java/boomerang/scope/test/TargetClassPath.java @@ -0,0 +1,8 @@ +package boomerang.scope.test; + +import java.io.File; + +public class TargetClassPath { + + public static final String TARGET_CLASS_PATH = System.getProperty("user.dir") + File.separator + ".." + File.separator + "boomerangScope" + File.separator + "target" + File.separator + "test-classes"; +} diff --git a/boomerangScope/src/test/java/boomerang/scope/test/targets/A.java b/boomerangScope/src/test/java/boomerang/scope/test/targets/A.java new file mode 100644 index 000000000..c3e262692 --- /dev/null +++ b/boomerangScope/src/test/java/boomerang/scope/test/targets/A.java @@ -0,0 +1,4 @@ +package boomerang.scope.test.targets; + +public class A { +} diff --git a/boomerangScope/src/test/java/boomerang/scope/test/targets/ParameterLocals.java b/boomerangScope/src/test/java/boomerang/scope/test/targets/ParameterLocals.java new file mode 100644 index 000000000..eb86a8f1f --- /dev/null +++ b/boomerangScope/src/test/java/boomerang/scope/test/targets/ParameterLocals.java @@ -0,0 +1,20 @@ +package boomerang.scope.test.targets; + +public class ParameterLocals { + + public static void main(String[] args) { + ParameterLocals parameterLocals = new ParameterLocals(); + + parameterLocals.noParameters(); + parameterLocals.oneParameter(10); + + A a = new A(); + parameterLocals.twoParameters(20, a); + } + + public void noParameters() {} + + public void oneParameter(@SuppressWarnings("unused") int i) {} + + public void twoParameters(@SuppressWarnings("unused")int i, @SuppressWarnings("unused") A a) {} +} From 5ec7bd75aa3f5bcb23448a9d8e2b86cc55784a65 Mon Sep 17 00:00:00 2001 From: Sven Meyer Date: Tue, 11 Mar 2025 16:33:04 +0100 Subject: [PATCH 14/61] Add test setup for Opal scope --- boomerangScope-Opal/pom.xml | 14 +++++- .../test/scala/scope/opal/OpalScopeTest.scala | 46 +++++++++++++++++++ .../src/test/scala/scope/opal/OpalSetup.scala | 36 +++++++++++++++ .../test/java/scope/soot/SootScopeTest.java | 4 -- 4 files changed, 95 insertions(+), 5 deletions(-) create mode 100644 boomerangScope-Opal/src/test/scala/scope/opal/OpalScopeTest.scala create mode 100644 boomerangScope-Opal/src/test/scala/scope/opal/OpalSetup.scala diff --git a/boomerangScope-Opal/pom.xml b/boomerangScope-Opal/pom.xml index 23b48123f..d9a755ceb 100644 --- a/boomerangScope-Opal/pom.xml +++ b/boomerangScope-Opal/pom.xml @@ -20,14 +20,26 @@ de.fraunhofer.iem boomerangScope + + de.fraunhofer.iem + boomerangScope + test-jar + test + de.opal-project framework_2.13 ${opal.version} + + junit + junit + + src/main/scala + src/test/scala net.alchim31.maven @@ -44,11 +56,11 @@ add-source compile + testCompile - src/main/scala diff --git a/boomerangScope-Opal/src/test/scala/scope/opal/OpalScopeTest.scala b/boomerangScope-Opal/src/test/scala/scope/opal/OpalScopeTest.scala new file mode 100644 index 000000000..e88ce921b --- /dev/null +++ b/boomerangScope-Opal/src/test/scala/scope/opal/OpalScopeTest.scala @@ -0,0 +1,46 @@ +package scope.opal + +import boomerang.scope.Method +import boomerang.scope.opal.tac.OpalMethod +import boomerang.scope.test.{BoomerangScopeTests, MethodSignature} +import boomerang.scope.test.targets.{A, ParameterLocals} +import org.junit.{Assert, Test} +import org.opalj.br.IntegerType + +import java.util +import java.util.List + +class OpalScopeTest extends BoomerangScopeTests { + + private val integerType = IntegerType.toJVMTypeName + + @Test + override def parameterLocalTest(): Unit = { + val opalSetup = new OpalSetup() + opalSetup.setupOpal(classOf[ParameterLocals].getName) + + // No parameters + val noArgsSignature = new MethodSignature(classOf[ParameterLocals].getName, "noParameters", "Void") + val noArgs = opalSetup.resolveMethod(noArgsSignature) + val noArgsMethod = OpalMethod(noArgs) + + Assert.assertTrue(noArgsMethod.getParameterLocals.isEmpty) + + // One parameter (primitive type) + val oneArgSignature = new MethodSignature(classOf[ParameterLocals].getName, "oneParameter", "Void", util.List.of(integerType)) + val oneArg = opalSetup.resolveMethod(oneArgSignature) + val oneArgMethod = OpalMethod(oneArg) + + Assert.assertEquals(1, oneArgMethod.getParameterLocals.size) + Assert.assertEquals("int", oneArgMethod.getParameterLocal(0).getType.toString) + + // Two parameters (primitive type + RefType) + val twoArgSignature = new MethodSignature(classOf[ParameterLocals].getName, "twoParameters", "Void", util.List.of(integerType, s"L${classOf[A].getName}L")) + val twoArgs = opalSetup.resolveMethod(twoArgSignature) + val twoArgsMethod = OpalMethod(twoArgs) + + Assert.assertEquals(2, twoArgsMethod.getParameterLocals.size) + Assert.assertEquals("int", twoArgsMethod.getParameterLocal(0).getType.toString) + Assert.assertEquals(classOf[A].getName, twoArgsMethod.getParameterLocal(1).getType.toString) + } +} diff --git a/boomerangScope-Opal/src/test/scala/scope/opal/OpalSetup.scala b/boomerangScope-Opal/src/test/scala/scope/opal/OpalSetup.scala new file mode 100644 index 000000000..427c6d51e --- /dev/null +++ b/boomerangScope-Opal/src/test/scala/scope/opal/OpalSetup.scala @@ -0,0 +1,36 @@ +package scope.opal + +import boomerang.scope.test.{MethodSignature, TargetClassPath} +import org.opalj.br.analyses.Project +import org.opalj.br._ +import org.opalj.log.{DevNullLogger, GlobalLogContext, OPALLogger} + +import java.io.File +import scala.collection.immutable.ArraySeq + +class OpalSetup { + + var targetClass: Option[ClassFile] = None + + def setupOpal(targetClassName: String): Unit = { + OPALLogger.updateLogger(GlobalLogContext, DevNullLogger) + val project = Project(new File(TargetClassPath.TARGET_CLASS_PATH)) + + targetClass = project.classFile(ObjectType(targetClassName.replace(".", "/"))) + } + + def resolveMethod(methodSignature: MethodSignature): Method = { + val parameterFields = ArraySeq.from(methodSignature.getParameters.toArray.collect({ + case p: String => FieldType(p.replace(".", "/")) + case _ => throw new IllegalArgumentException("No String") + })) + val returnType = ReturnType(methodSignature.getReturnType) + + val method = targetClass.get.findMethod(methodSignature.getMethodName, MethodDescriptor(parameterFields, returnType)) + if (method.isEmpty) { + throw new RuntimeException("Could not find method " + methodSignature.getMethodName + " in class " + methodSignature.getDeclaringClass) + } + + method.get + } +} diff --git a/boomerangScope-Soot/src/test/java/scope/soot/SootScopeTest.java b/boomerangScope-Soot/src/test/java/scope/soot/SootScopeTest.java index 411c9ebc1..1fc3cf294 100644 --- a/boomerangScope-Soot/src/test/java/scope/soot/SootScopeTest.java +++ b/boomerangScope-Soot/src/test/java/scope/soot/SootScopeTest.java @@ -14,10 +14,6 @@ public class SootScopeTest implements BoomerangScopeTests { - private static MethodSignature mainMethod(String className) { - return new MethodSignature(className, "main", "void", List.of("java.lang.String[]")); - } - @Test @Override public void parameterLocalTest() { From 691b8bdc926e805eaed1d16029858a69cca76282 Mon Sep 17 00:00:00 2001 From: Sven Meyer Date: Tue, 11 Mar 2025 18:20:06 +0100 Subject: [PATCH 15/61] Style --- boomerangScope-Opal/pom.xml | 5 +- .../src/main/scala/boomerang/scope/Main.scala | 69 ----------- .../scope/opal/OpalScopeTest.scala | 6 +- .../scope/opal/OpalSetup.scala | 2 +- .../boomerang/scope/soot/SootScopeTest.java | 61 ++++++++++ .../java/boomerang/scope/soot/SootSetup.java | 70 +++++++++++ .../test/java/scope/soot/SootScopeTest.java | 47 -------- .../src/test/java/scope/soot/SootSetup.java | 58 --------- .../scope/test/BoomerangScopeTests.java | 13 +- .../boomerang/scope/test/MethodSignature.java | 113 ++++++++++-------- .../boomerang/scope/test/TargetClassPath.java | 22 +++- .../java/boomerang/scope/test/targets/A.java | 14 ++- .../scope/test/targets/ParameterLocals.java | 31 +++-- .../src/main/java/test/TestingFramework.java | 4 +- 14 files changed, 267 insertions(+), 248 deletions(-) delete mode 100644 boomerangScope-Opal/src/main/scala/boomerang/scope/Main.scala rename boomerangScope-Opal/src/test/scala/{ => boomerang}/scope/opal/OpalScopeTest.scala (96%) rename boomerangScope-Opal/src/test/scala/{ => boomerang}/scope/opal/OpalSetup.scala (97%) create mode 100644 boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootScopeTest.java create mode 100644 boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootSetup.java delete mode 100644 boomerangScope-Soot/src/test/java/scope/soot/SootScopeTest.java delete mode 100644 boomerangScope-Soot/src/test/java/scope/soot/SootSetup.java diff --git a/boomerangScope-Opal/pom.xml b/boomerangScope-Opal/pom.xml index d9a755ceb..60409c69c 100644 --- a/boomerangScope-Opal/pom.xml +++ b/boomerangScope-Opal/pom.xml @@ -23,6 +23,7 @@ de.fraunhofer.iem boomerangScope + ${project.version} test-jar test @@ -38,8 +39,6 @@ - src/main/scala - src/test/scala net.alchim31.maven @@ -62,5 +61,7 @@ + src/main/scala + src/test/scala diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/Main.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/Main.scala deleted file mode 100644 index dbe680105..000000000 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/Main.scala +++ /dev/null @@ -1,69 +0,0 @@ -package boomerang.scope - -import boomerang.scope.opal.{OpalCallGraph, OpalClient} -import org.opalj.br.analyses.Project -import org.opalj.br.analyses.cg.InitialEntryPointsKey -import org.opalj.log.{DevNullLogger, GlobalLogContext, OPALLogger} -import org.opalj.tac.cg.CHACallGraphKey - -import java.io.File - -object Main { - - def main(args: Array[String]): Unit = { - OPALLogger.updateLogger(GlobalLogContext, DevNullLogger) - - val project = Project(new File("C:\\Users\\Sven\\Documents\\CogniCrypt\\Opal\\Parameter\\Parameter.jar")) - OpalClient.init(project) - - val callGraph = project.get(CHACallGraphKey) - val entryPoints = project.get(InitialEntryPointsKey) - val opalCallGraph = new OpalCallGraph(callGraph, entryPoints.toSet) - - opalCallGraph.getReachableMethods.forEach(method => { - if (method.isDefined) { - print(method.getParameterLocals) - } - }) - - /*var config = project.config - - val key = s"${InitialEntryPointsKey.ConfigKeyPrefix}entryPoints" - println("InitialEntryPoints " + key) - val currentValues = project.config.getList(key).unwrapped() - val allMethods = project.allMethodsWithBody - - allMethods.foreach(method => { - val configValue = new java.util.HashMap[String, String] - configValue.put("declaringClass", method.classFile.thisType.toJava) - configValue.put("name", method.name) - - currentValues.add(ConfigValueFactory.fromMap(configValue)) - config = config.withValue(key, ConfigValueFactory.fromIterable(currentValues)) - }) - - config = config.withValue( - s"${InitialEntryPointsKey.ConfigKeyPrefix}analysis", - ConfigValueFactory.fromAnyRef("org.opalj.br.analyses.cg.ConfigurationEntryPointsFinder") - ) - - val newProject = Project.recreate(project, config) - val callGraph = newProject.get(CHACallGraphKey) - val entryPoints = newProject.get(InitialEntryPointsKey) - println("Entry Points: " + entryPoints.size) - - OpalClient.init(newProject) - - val opalCallGraph = new OpalCallGraph(callGraph, entryPoints.toSet) - opalCallGraph.getReachableMethods.forEach(method => { - if (method.isInstanceOf[OpalMethod]) { - val locals = method.getLocals - println("Locals in " + method + ": " + locals) - } - - method.getStatements.forEach(statement => { - - }) - })*/ - } -} diff --git a/boomerangScope-Opal/src/test/scala/scope/opal/OpalScopeTest.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalScopeTest.scala similarity index 96% rename from boomerangScope-Opal/src/test/scala/scope/opal/OpalScopeTest.scala rename to boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalScopeTest.scala index e88ce921b..29a83c6f3 100644 --- a/boomerangScope-Opal/src/test/scala/scope/opal/OpalScopeTest.scala +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalScopeTest.scala @@ -1,14 +1,12 @@ -package scope.opal +package boomerang.scope.opal -import boomerang.scope.Method import boomerang.scope.opal.tac.OpalMethod -import boomerang.scope.test.{BoomerangScopeTests, MethodSignature} import boomerang.scope.test.targets.{A, ParameterLocals} +import boomerang.scope.test.{BoomerangScopeTests, MethodSignature} import org.junit.{Assert, Test} import org.opalj.br.IntegerType import java.util -import java.util.List class OpalScopeTest extends BoomerangScopeTests { diff --git a/boomerangScope-Opal/src/test/scala/scope/opal/OpalSetup.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalSetup.scala similarity index 97% rename from boomerangScope-Opal/src/test/scala/scope/opal/OpalSetup.scala rename to boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalSetup.scala index 427c6d51e..87d3687cc 100644 --- a/boomerangScope-Opal/src/test/scala/scope/opal/OpalSetup.scala +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalSetup.scala @@ -1,4 +1,4 @@ -package scope.opal +package boomerang.scope.opal import boomerang.scope.test.{MethodSignature, TargetClassPath} import org.opalj.br.analyses.Project diff --git a/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootScopeTest.java b/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootScopeTest.java new file mode 100644 index 000000000..f1d9d5434 --- /dev/null +++ b/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootScopeTest.java @@ -0,0 +1,61 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ +package boomerang.scope.soot; + +import boomerang.scope.Method; +import boomerang.scope.soot.jimple.JimpleMethod; +import boomerang.scope.test.BoomerangScopeTests; +import boomerang.scope.test.MethodSignature; +import boomerang.scope.test.targets.A; +import boomerang.scope.test.targets.ParameterLocals; +import java.util.List; +import org.junit.Assert; +import org.junit.Test; +import soot.SootMethod; + +public class SootScopeTest implements BoomerangScopeTests { + + @Test + @Override + public void parameterLocalTest() { + SootSetup sootSetup = new SootSetup(); + sootSetup.setupSoot(ParameterLocals.class.getName()); + + // No parameters + MethodSignature noArgsSignature = + new MethodSignature(ParameterLocals.class.getName(), "noParameters"); + SootMethod noArgs = sootSetup.resolveMethod(noArgsSignature); + Method noArgsMethod = JimpleMethod.of(noArgs); + + Assert.assertTrue(noArgsMethod.getParameterLocals().isEmpty()); + + // One parameter (primitive type) + MethodSignature oneArgSignature = + new MethodSignature(ParameterLocals.class.getName(), "oneParameter", List.of("int")); + SootMethod oneArg = sootSetup.resolveMethod(oneArgSignature); + Method oneArgMethod = JimpleMethod.of(oneArg); + + Assert.assertEquals(1, oneArgMethod.getParameterLocals().size()); + Assert.assertEquals("int", oneArgMethod.getParameterLocal(0).getType().toString()); + + // Two parameters (primitive type + RefType) + MethodSignature twoArgSignature = + new MethodSignature( + ParameterLocals.class.getName(), "twoParameters", List.of("int", A.class.getName())); + SootMethod twoArgs = sootSetup.resolveMethod(twoArgSignature); + Method twoArgsMethod = JimpleMethod.of(twoArgs); + + Assert.assertEquals(2, twoArgsMethod.getParameterLocals().size()); + Assert.assertEquals("int", twoArgsMethod.getParameterLocal(0).getType().toString()); + Assert.assertEquals(A.class.getName(), twoArgsMethod.getParameterLocal(1).getType().toString()); + } +} diff --git a/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootSetup.java b/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootSetup.java new file mode 100644 index 000000000..eb02f9a3d --- /dev/null +++ b/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootSetup.java @@ -0,0 +1,70 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ +package boomerang.scope.soot; + +import boomerang.scope.test.MethodSignature; +import boomerang.scope.test.TargetClassPath; +import java.io.File; +import java.util.List; +import soot.EntryPoints; +import soot.G; +import soot.PackManager; +import soot.Scene; +import soot.SootClass; +import soot.SootMethod; +import soot.options.Options; + +public class SootSetup { + + private SootClass targetClass; + + public void setupSoot(String targetClassName) { + G.reset(); + + Options.v().set_whole_program(true); + Options.v().set_output_format(Options.output_format_none); + Options.v().set_no_bodies_for_excluded(true); + Options.v().set_allow_phantom_refs(true); + Options.v().set_keep_line_number(true); + + Options.v() + .set_soot_classpath( + "VIRTUAL_FS_FOR_JDK" + File.pathSeparator + TargetClassPath.TARGET_CLASS_PATH); + + Options.v().setPhaseOption("jb.sils", "enabled:false"); + Options.v().setPhaseOption("jb", "use-original-names:true"); + + Options.v().set_include(List.of(targetClassName)); + Options.v().setPhaseOption("cg.cha", "on"); + Options.v().setPhaseOption("cg.cha", "all-reachable:true"); + + targetClass = Scene.v().forceResolve(targetClassName, SootClass.BODIES); + targetClass.setApplicationClass(); + + Scene.v().loadNecessaryClasses(); + Scene.v().setEntryPoints(EntryPoints.v().application()); + + PackManager.v().getPack("cg").apply(); + } + + public SootMethod resolveMethod(MethodSignature methodSignature) { + String signature = + methodSignature.getReturnType() + + " " + + methodSignature.getMethodName() + + "(" + + String.join(",", methodSignature.getParameters()) + + ")"; + + return targetClass.getMethod(signature); + } +} diff --git a/boomerangScope-Soot/src/test/java/scope/soot/SootScopeTest.java b/boomerangScope-Soot/src/test/java/scope/soot/SootScopeTest.java deleted file mode 100644 index 1fc3cf294..000000000 --- a/boomerangScope-Soot/src/test/java/scope/soot/SootScopeTest.java +++ /dev/null @@ -1,47 +0,0 @@ -package scope.soot; - -import boomerang.scope.Method; -import boomerang.scope.soot.jimple.JimpleMethod; -import boomerang.scope.test.BoomerangScopeTests; -import boomerang.scope.test.MethodSignature; -import boomerang.scope.test.targets.A; -import boomerang.scope.test.targets.ParameterLocals; -import org.junit.Assert; -import org.junit.Test; -import soot.SootMethod; - -import java.util.List; - -public class SootScopeTest implements BoomerangScopeTests { - - @Test - @Override - public void parameterLocalTest() { - SootSetup sootSetup = new SootSetup(); - sootSetup.setupSoot(ParameterLocals.class.getName()); - - // No parameters - MethodSignature noArgsSignature = new MethodSignature(ParameterLocals.class.getName(), "noParameters"); - SootMethod noArgs = sootSetup.resolveMethod(noArgsSignature); - Method noArgsMethod = JimpleMethod.of(noArgs); - - Assert.assertTrue(noArgsMethod.getParameterLocals().isEmpty()); - - // One parameter (primitive type) - MethodSignature oneArgSignature = new MethodSignature(ParameterLocals.class.getName(), "oneParameter", List.of("int")); - SootMethod oneArg = sootSetup.resolveMethod(oneArgSignature); - Method oneArgMethod = JimpleMethod.of(oneArg); - - Assert.assertEquals(1, oneArgMethod.getParameterLocals().size()); - Assert.assertEquals("int", oneArgMethod.getParameterLocal(0).getType().toString()); - - // Two parameters (primitive type + RefType) - MethodSignature twoArgSignature = new MethodSignature(ParameterLocals.class.getName(), "twoParameters", List.of("int", A.class.getName())); - SootMethod twoArgs = sootSetup.resolveMethod(twoArgSignature); - Method twoArgsMethod = JimpleMethod.of(twoArgs); - - Assert.assertEquals(2, twoArgsMethod.getParameterLocals().size()); - Assert.assertEquals("int", twoArgsMethod.getParameterLocal(0).getType().toString()); - Assert.assertEquals(A.class.getName(), twoArgsMethod.getParameterLocal(1).getType().toString()); - } -} diff --git a/boomerangScope-Soot/src/test/java/scope/soot/SootSetup.java b/boomerangScope-Soot/src/test/java/scope/soot/SootSetup.java deleted file mode 100644 index eb8fa4a01..000000000 --- a/boomerangScope-Soot/src/test/java/scope/soot/SootSetup.java +++ /dev/null @@ -1,58 +0,0 @@ -package scope.soot; - -import boomerang.scope.test.MethodSignature; -import boomerang.scope.test.TargetClassPath; -import soot.EntryPoints; -import soot.G; -import soot.PackManager; -import soot.Scene; -import soot.SootClass; -import soot.SootMethod; -import soot.options.Options; - -import java.io.File; -import java.util.List; - -public class SootSetup { - - private SootClass targetClass; - - public void setupSoot(String targetClassName) { - G.reset(); - - Options.v().set_whole_program(true); - Options.v().set_output_format(Options.output_format_none); - Options.v().set_no_bodies_for_excluded(true); - Options.v().set_allow_phantom_refs(true); - Options.v().set_keep_line_number(true); - - Options.v().set_soot_classpath("VIRTUAL_FS_FOR_JDK" + File.pathSeparator + TargetClassPath.TARGET_CLASS_PATH); - - Options.v().setPhaseOption("jb.sils", "enabled:false"); - Options.v().setPhaseOption("jb", "use-original-names:true"); - - Options.v().set_include(List.of(targetClassName)); - Options.v().setPhaseOption("cg.cha", "on"); - Options.v().setPhaseOption("cg.cha", "all-reachable:true"); - - targetClass = Scene.v().forceResolve(targetClassName, SootClass.BODIES); - targetClass.setApplicationClass(); - - Scene.v().loadNecessaryClasses(); - Scene.v().setEntryPoints(EntryPoints.v().application()); - - PackManager.v().getPack("cg").apply(); - } - - public SootMethod resolveMethod(MethodSignature methodSignature) { - String signature = - methodSignature.getReturnType() - + " " - + methodSignature.getMethodName() - + "(" - + String.join(",", methodSignature.getParameters()) - + ")"; - - return targetClass.getMethod(signature); - } -} diff --git a/boomerangScope/src/test/java/boomerang/scope/test/BoomerangScopeTests.java b/boomerangScope/src/test/java/boomerang/scope/test/BoomerangScopeTests.java index 948dafecb..329a8ca46 100644 --- a/boomerangScope/src/test/java/boomerang/scope/test/BoomerangScopeTests.java +++ b/boomerangScope/src/test/java/boomerang/scope/test/BoomerangScopeTests.java @@ -1,7 +1,18 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ package boomerang.scope.test; @SuppressWarnings("unused") public interface BoomerangScopeTests { - void parameterLocalTest(); + void parameterLocalTest(); } diff --git a/boomerangScope/src/test/java/boomerang/scope/test/MethodSignature.java b/boomerangScope/src/test/java/boomerang/scope/test/MethodSignature.java index af925e56b..f154e974a 100644 --- a/boomerangScope/src/test/java/boomerang/scope/test/MethodSignature.java +++ b/boomerangScope/src/test/java/boomerang/scope/test/MethodSignature.java @@ -1,3 +1,14 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ package boomerang.scope.test; import java.util.Collections; @@ -6,67 +17,67 @@ public class MethodSignature { - private final String declaringClass; - private final String methodName; - private final String returnType; - private final List parameters; + private final String declaringClass; + private final String methodName; + private final String returnType; + private final List parameters; - public static final String VOID = "void"; + public static final String VOID = "void"; - public MethodSignature(String declaringClass, String methodName) { - this(declaringClass, methodName, VOID); - } + public MethodSignature(String declaringClass, String methodName) { + this(declaringClass, methodName, VOID); + } - public MethodSignature(String declaringClass, String methodName, String returnType) { - this(declaringClass, methodName, returnType, Collections.emptyList()); - } + public MethodSignature(String declaringClass, String methodName, String returnType) { + this(declaringClass, methodName, returnType, Collections.emptyList()); + } - public MethodSignature(String declaringClass, String methodName, List parameters) { - this(declaringClass, methodName, VOID, parameters); - } + public MethodSignature(String declaringClass, String methodName, List parameters) { + this(declaringClass, methodName, VOID, parameters); + } - public MethodSignature( - String declaringClass, String methodName, String returnType, List parameters) { - this.declaringClass = declaringClass; - this.methodName = methodName; - this.returnType = returnType; - this.parameters = parameters; - } + public MethodSignature( + String declaringClass, String methodName, String returnType, List parameters) { + this.declaringClass = declaringClass; + this.methodName = methodName; + this.returnType = returnType; + this.parameters = parameters; + } - public String getDeclaringClass() { - return declaringClass; - } + public String getDeclaringClass() { + return declaringClass; + } - public String getMethodName() { - return methodName; - } + public String getMethodName() { + return methodName; + } - public String getReturnType() { - return returnType; - } + public String getReturnType() { + return returnType; + } - public List getParameters() { - return parameters; - } + public List getParameters() { + return parameters; + } - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - MethodSignature that = (MethodSignature) o; - return Objects.equals(declaringClass, that.declaringClass) - && Objects.equals(methodName, that.methodName) - && Objects.equals(returnType, that.returnType) - && Objects.equals(parameters, that.parameters); - } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + MethodSignature that = (MethodSignature) o; + return Objects.equals(declaringClass, that.declaringClass) + && Objects.equals(methodName, that.methodName) + && Objects.equals(returnType, that.returnType) + && Objects.equals(parameters, that.parameters); + } - @Override - public int hashCode() { - return Objects.hash(declaringClass, methodName, returnType, parameters); - } + @Override + public int hashCode() { + return Objects.hash(declaringClass, methodName, returnType, parameters); + } - @Override - public String toString() { - return declaringClass + " " + returnType + " " + methodName + " " + parameters; - } + @Override + public String toString() { + return declaringClass + " " + returnType + " " + methodName + " " + parameters; + } } diff --git a/boomerangScope/src/test/java/boomerang/scope/test/TargetClassPath.java b/boomerangScope/src/test/java/boomerang/scope/test/TargetClassPath.java index 2b93ac8f4..34fcaa487 100644 --- a/boomerangScope/src/test/java/boomerang/scope/test/TargetClassPath.java +++ b/boomerangScope/src/test/java/boomerang/scope/test/TargetClassPath.java @@ -1,8 +1,28 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ package boomerang.scope.test; import java.io.File; public class TargetClassPath { - public static final String TARGET_CLASS_PATH = System.getProperty("user.dir") + File.separator + ".." + File.separator + "boomerangScope" + File.separator + "target" + File.separator + "test-classes"; + public static final String TARGET_CLASS_PATH = + System.getProperty("user.dir") + + File.separator + + ".." + + File.separator + + "boomerangScope" + + File.separator + + "target" + + File.separator + + "test-classes"; } diff --git a/boomerangScope/src/test/java/boomerang/scope/test/targets/A.java b/boomerangScope/src/test/java/boomerang/scope/test/targets/A.java index c3e262692..a7d0ffccc 100644 --- a/boomerangScope/src/test/java/boomerang/scope/test/targets/A.java +++ b/boomerangScope/src/test/java/boomerang/scope/test/targets/A.java @@ -1,4 +1,14 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ package boomerang.scope.test.targets; -public class A { -} +public class A {} diff --git a/boomerangScope/src/test/java/boomerang/scope/test/targets/ParameterLocals.java b/boomerangScope/src/test/java/boomerang/scope/test/targets/ParameterLocals.java index eb86a8f1f..04772393f 100644 --- a/boomerangScope/src/test/java/boomerang/scope/test/targets/ParameterLocals.java +++ b/boomerangScope/src/test/java/boomerang/scope/test/targets/ParameterLocals.java @@ -1,20 +1,31 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ package boomerang.scope.test.targets; public class ParameterLocals { - public static void main(String[] args) { - ParameterLocals parameterLocals = new ParameterLocals(); + public static void main(String[] args) { + ParameterLocals parameterLocals = new ParameterLocals(); - parameterLocals.noParameters(); - parameterLocals.oneParameter(10); + parameterLocals.noParameters(); + parameterLocals.oneParameter(10); - A a = new A(); - parameterLocals.twoParameters(20, a); - } + A a = new A(); + parameterLocals.twoParameters(20, a); + } - public void noParameters() {} + public void noParameters() {} - public void oneParameter(@SuppressWarnings("unused") int i) {} + public void oneParameter(@SuppressWarnings("unused") int i) {} - public void twoParameters(@SuppressWarnings("unused")int i, @SuppressWarnings("unused") A a) {} + public void twoParameters(@SuppressWarnings("unused") int i, @SuppressWarnings("unused") A a) {} } diff --git a/testCore/src/main/java/test/TestingFramework.java b/testCore/src/main/java/test/TestingFramework.java index a39ab8a48..b2e7ed592 100644 --- a/testCore/src/main/java/test/TestingFramework.java +++ b/testCore/src/main/java/test/TestingFramework.java @@ -21,7 +21,7 @@ import java.util.stream.Collectors; import org.junit.Assert; import test.setup.MethodWrapper; -import test.setup.OpalTestSetup; +import test.setup.SootTestSetup; import test.setup.TestSetup; public class TestingFramework { @@ -30,7 +30,7 @@ public class TestingFramework { public TestingFramework() { // TODO Parameterize - this.testSetup = new OpalTestSetup(); + this.testSetup = new SootTestSetup(); } public FrameworkScope getFrameworkScope(MethodWrapper methodWrapper) { From 46af946e340884ffd46e591330276509e79ecddd Mon Sep 17 00:00:00 2001 From: Sven Meyer Date: Wed, 12 Mar 2025 11:45:06 +0100 Subject: [PATCH 16/61] Add correct logic and tests for locals --- .../scope/opal/tac/OpalArrayRef.scala | 4 +- .../boomerang/scope/opal/tac/OpalLocal.scala | 24 ++-- .../boomerang/scope/opal/tac/OpalMethod.scala | 63 ++------- .../scope/opal/tac/OpalParameterLocal.scala | 25 +++- .../boomerang/scope/opal/tac/OpalVal.scala | 1 + .../boomerang/scope/opal/OpalScopeTest.scala | 121 +++++++++++++++++- .../boomerang/scope/opal/OpalSetup.scala | 1 + .../boomerang/scope/soot/SootScopeTest.java | 93 +++++++++++++- .../main/java/boomerang/scope/AllocVal.java | 8 +- .../scope/test/BoomerangScopeTests.java | 4 + .../java/boomerang/scope/test/targets/A.java | 5 +- .../targets/HashCodeEqualsLocalTarget.java | 40 ++++++ ...Locals.java => ParameterLocalsTarget.java} | 10 +- .../scope/test/targets/ThisLocalTarget.java | 30 +++++ .../src/main/java/test/TestingFramework.java | 4 +- 15 files changed, 348 insertions(+), 85 deletions(-) create mode 100644 boomerangScope/src/test/java/boomerang/scope/test/targets/HashCodeEqualsLocalTarget.java rename boomerangScope/src/test/java/boomerang/scope/test/targets/{ParameterLocals.java => ParameterLocalsTarget.java} (76%) create mode 100644 boomerangScope/src/test/java/boomerang/scope/test/targets/ThisLocalTarget.java diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalArrayRef.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalArrayRef.scala index 3ac422d2e..7c5a07a7c 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalArrayRef.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalArrayRef.scala @@ -74,8 +74,8 @@ class OpalArrayRef(val arrayRef: Expr[DUVar[ValueInformation]], val index: Int, override def getVariableName: String = { arrayRef match { - case dVar: DVar[_] => s"var${}[$index]" // TODO insert origin - case uVar: UVar[_] => s"var${uVar.definedBy.head}[$index]" + case dVar: DVar[_] => s"var(D)[$index]" // TODO insert origin + case uVar: UVar[_] => s"var(${uVar.definedBy.head})[$index]" case _ => arrayRef.toString } } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalLocal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalLocal.scala index fe3fa3b52..8b3156359 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalLocal.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalLocal.scala @@ -6,6 +6,8 @@ import org.opalj.br.ObjectType import org.opalj.tac.{DUVar, DVar, Expr, UVar} import org.opalj.value.ValueInformation +import java.util.Objects + class OpalLocal(val delegate: Expr[DUVar[ValueInformation]], method: OpalMethod, unbalanced: ControlFlowGraph.Edge = null) extends Val(method, unbalanced) { if (!delegate.isVar) { @@ -89,16 +91,16 @@ class OpalLocal(val delegate: Expr[DUVar[ValueInformation]], method: OpalMethod, override def getArrayBase: Pair[Val, Integer] = throw new RuntimeException("Opal local is not array reference") override def getVariableName: String = delegate match { - case dVar: DVar[_] => s"var${}" // TODO Add origin - case uVar: UVar[_] => s"var${uVar.definedBy.head}" + case dVar: DVar[_] => s"var(D)" // TODO Add origin + case uVar: UVar[_] => s"var(${uVar.definedBy.head})" case _ => delegate.toString } - override def hashCode(): Int = delegate match { + override def hashCode: Int = delegate match { case uVar: UVar[_] => if (uVar.definedBy.head < 0) { - // Parameters have no real definition statement - return 31 * super.hashCode() + delegate.hashCode() + // Parameters have no real definition statement, so we just use their definition site index + return Objects.hash(super.hashCode(), uVar.definedBy.head) } // UVars should reference their DVar to keep the comparisons consistent @@ -106,12 +108,12 @@ class OpalLocal(val delegate: Expr[DUVar[ValueInformation]], method: OpalMethod, val defStmt = tac.stmts(uVar.definedBy.head) if (!defStmt.isAssignment) { - return 31 * super.hashCode() + delegate.hashCode() + return Objects.hash(super.hashCode(), delegate.hashCode()) } val targetVar = defStmt.asAssignment.targetVar - 31 * super.hashCode() + targetVar.hashCode() - case dVar: DVar[_] => 31 * super.hashCode() + dVar.hashCode() + Objects.hash(super.hashCode(), targetVar.hashCode()) + case dVar: DVar[_] => Objects.hash(super.hashCode(), dVar.hashCode()) case _ => throw new RuntimeException("Cannot compute hashCode for non variables") } @@ -153,6 +155,12 @@ class OpalLocal(val delegate: Expr[DUVar[ValueInformation]], method: OpalMethod, super.equals(other) && this.delegate.hashCode() == other.delegate.hashCode() case _ => throw new RuntimeException("Cannot compare a variable with a non variable") } + case other: OpalParameterLocal => + this.delegate match { + case uVar: UVar[_] => + Objects.equals(m, other.m) && uVar.definedBy.head == other.index; + case _ => false + } case _ => false } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalMethod.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalMethod.scala index 633bb59f4..2f66d080a 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalMethod.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalMethod.scala @@ -44,45 +44,18 @@ case class OpalMethod(delegate: org.opalj.br.Method) extends Method { override def isThisLocal(fact: Val): Boolean = { if (isStatic) return false - val thisLocal = isThisLocalDefined - if (thisLocal.isDefined) { - return thisLocal.get.equals(fact) - } - - // TODO This might not be enough - false + val thisLocal = getThisLocal + thisLocal.equals(fact) } override def getThisLocal: Val = { if (!isStatic) { - val thisLocal = isThisLocalDefined - if (thisLocal.isDefined) { - return thisLocal.get - } - - // TODO Replace corresponding places - throw new RuntimeException("this local is not used in method. Use #isThisLocal for comparisons") + return new OpalParameterLocal(delegate.classFile.thisType, -1, this) } throw new RuntimeException("Static method does not have a 'this' local") } - private def isThisLocalDefined: Option[Val] = { - val locals = getLocals - for (local <- locals.asScala) { - val opalVal = local.asInstanceOf[OpalVal] - val valDelegate = opalVal.delegate - - if (valDelegate.isInstanceOf[UVar[_]]) { - if (valDelegate.asVar.definedBy.head == -1) { - return Some(local) - } - } - } - - None - } - override def getLocals: util.Set[Val] = { if (localCache.isEmpty) { localCache = Some(new util.HashSet[Val]()) @@ -135,28 +108,20 @@ case class OpalMethod(delegate: org.opalj.br.Method) extends Method { if (parameterLocalCache.isEmpty) { parameterLocalCache = Some(new util.ArrayList[Val]()) - delegate.parameterTypes.foreach(param => { - val parameterLocal = new OpalParameterLocal(param, this) - parameterLocalCache.get.add(parameterLocal) - }) - } + val tac = OpalClient.getTacForMethod(delegate) - if (parameterLocalCache.isEmpty) { - parameterLocalCache = Some(new util.ArrayList[Val]()) + delegate.parameterTypes.indices.foreach(i => { + val paramType = delegate.parameterTypes(i) + val index = tac.params.parameters(i + 1).origin - val locals = getLocals - for (local <- locals.asScala) { - if (local.isLocal) { - val opalVal = local.asInstanceOf[OpalVal] - val valDelegate = opalVal.delegate + val parameterLocal = new OpalParameterLocal(paramType, index, this) + parameterLocalCache.get.add(parameterLocal) + }) - if (valDelegate.isInstanceOf[UVar[_]]) { - if (valDelegate.asVar.definedBy.head < 0) { - parameterLocalCache.get.add(local) - } - } - } - } + /*delegate.parameterTypes.foreach(param => { + val parameterLocal = new OpalParameterLocal(param, this) + parameterLocalCache.get.add(parameterLocal) + })*/ } parameterLocalCache.get diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalParameterLocal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalParameterLocal.scala index b4b9e7a56..22ce52f13 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalParameterLocal.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalParameterLocal.scala @@ -2,8 +2,11 @@ package boomerang.scope.opal.tac import boomerang.scope.{ControlFlowGraph, Method, Pair, Type, Val} import org.opalj.br.FieldType +import org.opalj.tac.UVar -class OpalParameterLocal(parameterType: FieldType, method: OpalMethod, unbalanced: ControlFlowGraph.Edge = null) extends Val(method, unbalanced) { +import java.util.Objects + +class OpalParameterLocal(val parameterType: FieldType, val index: Int, method: OpalMethod, unbalanced: ControlFlowGraph.Edge = null) extends Val(method, unbalanced) { override def getType: Type = OpalType(parameterType) @@ -13,7 +16,7 @@ class OpalParameterLocal(parameterType: FieldType, method: OpalMethod, unbalance override def getNewExprType: Type = throw new RuntimeException("Parameter local is not a new expression") - override def asUnbalanced(stmt: ControlFlowGraph.Edge): Val = new OpalParameterLocal(parameterType, method, stmt) + override def asUnbalanced(stmt: ControlFlowGraph.Edge): Val = new OpalParameterLocal(parameterType, index, method, stmt) override def isLocal: Boolean = true @@ -51,7 +54,7 @@ class OpalParameterLocal(parameterType: FieldType, method: OpalMethod, unbalance override def getClassConstantType: Type = throw new RuntimeException("Parameter local is not a class constant") - override def withNewMethod(callee: Method): Val = new OpalParameterLocal(parameterType, callee.asInstanceOf[OpalMethod]) + override def withNewMethod(callee: Method): Val = new OpalParameterLocal(parameterType, index, callee.asInstanceOf[OpalMethod]) override def isLongConstant: Boolean = false @@ -61,5 +64,19 @@ class OpalParameterLocal(parameterType: FieldType, method: OpalMethod, unbalance override def getArrayBase: Pair[Val, Integer] = throw new RuntimeException("Parameter local is not an array ref") - override def getVariableName: String = ??? + override def getVariableName: String = s"var($index)" + + override def hashCode: Int = Objects.hash(super.hashCode(), index) + + override def equals(obj: Any): Boolean = obj match { + case other: OpalParameterLocal => Objects.equals(m, other.m) && index == other.index + case local: OpalLocal => + local.delegate match { + case uVar: UVar[_] => Objects.equals(m, local.m) && index == uVar.definedBy.head + case _ => false + } + case _ => false + } + + override def toString: String = getVariableName } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalVal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalVal.scala index c95d288f7..b0b9fab49 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalVal.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalVal.scala @@ -149,6 +149,7 @@ class OpalVal(val delegate: Expr[DUVar[ValueInformation]], method: OpalMethod, u case stringConst: StringConst => "\"" + stringConst.value + "\"" case intConst: IntConst => intConst.value.toString case longConst: LongConst => longConst.value.toString + case newExpr: New => s"new ${newExpr.tpe.toJava}" case _ => delegate.toString } } diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalScopeTest.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalScopeTest.scala index 29a83c6f3..77dd481d9 100644 --- a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalScopeTest.scala +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalScopeTest.scala @@ -1,7 +1,8 @@ package boomerang.scope.opal +import boomerang.scope.Statement import boomerang.scope.opal.tac.OpalMethod -import boomerang.scope.test.targets.{A, ParameterLocals} +import boomerang.scope.test.targets.{A, HashCodeEqualsLocalTarget, ParameterLocalsTarget, ThisLocalTarget} import boomerang.scope.test.{BoomerangScopeTests, MethodSignature} import org.junit.{Assert, Test} import org.opalj.br.IntegerType @@ -12,20 +13,48 @@ class OpalScopeTest extends BoomerangScopeTests { private val integerType = IntegerType.toJVMTypeName + @Test + override def thisLocalTest(): Unit = { + val opalSetup = new OpalSetup() + opalSetup.setupOpal(classOf[ThisLocalTarget].getName) + + val signature = new MethodSignature(classOf[ThisLocalTarget].getName, "call", "Void") + val method = opalSetup.resolveMethod(signature) + val opalMethod = OpalMethod(method) + + var checked = false + opalMethod.getStatements.forEach(stmt => { + if (stmt.containsInvokeExpr() && stmt.getInvokeExpr.getMethod.getName.equals("callWithThis")) { + val invokeExpr = stmt.getInvokeExpr + val base = invokeExpr.getBase + + Assert.assertTrue(opalMethod.getThisLocal.equals(base)) + Assert.assertTrue(base.equals(opalMethod.getThisLocal)) + Assert.assertTrue(opalMethod.isThisLocal(base)) + + checked = true + } + }) + + if (!checked) { + Assert.fail("Did not check this local") + } + } + @Test override def parameterLocalTest(): Unit = { val opalSetup = new OpalSetup() - opalSetup.setupOpal(classOf[ParameterLocals].getName) + opalSetup.setupOpal(classOf[ParameterLocalsTarget].getName) // No parameters - val noArgsSignature = new MethodSignature(classOf[ParameterLocals].getName, "noParameters", "Void") + val noArgsSignature = new MethodSignature(classOf[ParameterLocalsTarget].getName, "noParameters", "Void") val noArgs = opalSetup.resolveMethod(noArgsSignature) val noArgsMethod = OpalMethod(noArgs) Assert.assertTrue(noArgsMethod.getParameterLocals.isEmpty) // One parameter (primitive type) - val oneArgSignature = new MethodSignature(classOf[ParameterLocals].getName, "oneParameter", "Void", util.List.of(integerType)) + val oneArgSignature = new MethodSignature(classOf[ParameterLocalsTarget].getName, "oneParameter", "Void", util.List.of(integerType)) val oneArg = opalSetup.resolveMethod(oneArgSignature) val oneArgMethod = OpalMethod(oneArg) @@ -33,7 +62,7 @@ class OpalScopeTest extends BoomerangScopeTests { Assert.assertEquals("int", oneArgMethod.getParameterLocal(0).getType.toString) // Two parameters (primitive type + RefType) - val twoArgSignature = new MethodSignature(classOf[ParameterLocals].getName, "twoParameters", "Void", util.List.of(integerType, s"L${classOf[A].getName}L")) + val twoArgSignature = new MethodSignature(classOf[ParameterLocalsTarget].getName, "twoParameters", "Void", util.List.of(integerType, s"L${classOf[A].getName}L")) val twoArgs = opalSetup.resolveMethod(twoArgSignature) val twoArgsMethod = OpalMethod(twoArgs) @@ -41,4 +70,86 @@ class OpalScopeTest extends BoomerangScopeTests { Assert.assertEquals("int", twoArgsMethod.getParameterLocal(0).getType.toString) Assert.assertEquals(classOf[A].getName, twoArgsMethod.getParameterLocal(1).getType.toString) } + + @Test + override def hashCodeEqualsLocalTest(): Unit = { + val opalSetup = new OpalSetup() + opalSetup.setupOpal(classOf[HashCodeEqualsLocalTarget].getName) + + // Parameter locals + val signature = new MethodSignature(classOf[HashCodeEqualsLocalTarget].getName, "parameterCall", "Void", util.List.of(s"L${classOf[A].getName}L", integerType)) + val method = opalSetup.resolveMethod(signature) + val opalMethod = OpalMethod(method) + + val firstArg = opalMethod.getParameterLocal(0) + val secondArg = opalMethod.getParameterLocal(1) + + var checked = false + opalMethod.getStatements.forEach(stmt => { + if (stmt.containsInvokeExpr() && stmt.getInvokeExpr.getMethod.getName.equals("methodCall")) { + val invokeExpr = stmt.getInvokeExpr + val base = invokeExpr.getBase + val arg = invokeExpr.getArg(0) + + // equals in both directions + Assert.assertTrue(base.equals(firstArg)) + Assert.assertTrue(firstArg.equals(base)) + + Assert.assertTrue(arg.equals(secondArg)) + Assert.assertTrue(secondArg.equals(arg)) + + // hash codes + Assert.assertEquals(base.hashCode, firstArg.hashCode) + Assert.assertEquals(arg.hashCode, secondArg.hashCode) + + checked = true + } + }) + + if (!checked) { + Assert.fail("Did not checked equals and hashCode methods") + } + + // Defined locals + val signature2 = new MethodSignature(classOf[ParameterLocalsTarget].getName, "definedCall", "Void") + val method2 = opalSetup.resolveMethod(signature2) + val jimpleMethod2 = OpalMethod(method2) + + // Find the definition sites + val refDefStmt = jimpleMethod2.getStatements.stream.filter((stmt: Statement) => stmt.isAssignStmt && stmt.getRightOp.isNewExpr).findFirst + val primDefStmt= jimpleMethod2.getStatements.stream.filter((stmt: Statement) => stmt.isAssignStmt && stmt.getRightOp.isIntConstant).findFirst + + if (refDefStmt.isEmpty || primDefStmt.isEmpty) { + Assert.fail("Could not find def statement") + } + + val refDefLocal = refDefStmt.get.getLeftOp + val primDefLocal = primDefStmt.get.getLeftOp + + var checked2: Boolean = false + jimpleMethod2.getStatements.forEach(stmt => { + if (stmt.containsInvokeExpr && stmt.getInvokeExpr.getMethod.getName == "methodCall") { + val invokeExpr = stmt.getInvokeExpr + val base = invokeExpr.getBase + val arg = invokeExpr.getArg(0) + + // equals in both directions + Assert.assertEquals(base, refDefLocal) + Assert.assertEquals(refDefLocal, base) + + Assert.assertEquals(arg, primDefLocal) + Assert.assertEquals(primDefLocal, arg) + + // hash codes + Assert.assertEquals(base.hashCode, refDefLocal.hashCode) + Assert.assertEquals(arg.hashCode, primDefLocal.hashCode) + + checked2 = true + } + }) + + if (!checked2) { + Assert.fail("Did not check equals and hashCode methods for defined locals") + } + } } diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalSetup.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalSetup.scala index 87d3687cc..ecb0a6885 100644 --- a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalSetup.scala +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalSetup.scala @@ -16,6 +16,7 @@ class OpalSetup { OPALLogger.updateLogger(GlobalLogContext, DevNullLogger) val project = Project(new File(TargetClassPath.TARGET_CLASS_PATH)) + OpalClient.init(project) targetClass = project.classFile(ObjectType(targetClassName.replace(".", "/"))) } diff --git a/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootScopeTest.java b/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootScopeTest.java index f1d9d5434..f2dfa3348 100644 --- a/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootScopeTest.java +++ b/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootScopeTest.java @@ -11,12 +11,17 @@ */ package boomerang.scope.soot; +import boomerang.scope.InvokeExpr; import boomerang.scope.Method; +import boomerang.scope.Statement; +import boomerang.scope.Val; import boomerang.scope.soot.jimple.JimpleMethod; import boomerang.scope.test.BoomerangScopeTests; import boomerang.scope.test.MethodSignature; import boomerang.scope.test.targets.A; -import boomerang.scope.test.targets.ParameterLocals; +import boomerang.scope.test.targets.HashCodeEqualsLocalTarget; +import boomerang.scope.test.targets.ParameterLocalsTarget; +import boomerang.scope.test.targets.ThisLocalTarget; import java.util.List; import org.junit.Assert; import org.junit.Test; @@ -24,15 +29,45 @@ public class SootScopeTest implements BoomerangScopeTests { + @Test + @Override + public void thisLocalTest() { + SootSetup sootSetup = new SootSetup(); + sootSetup.setupSoot(ThisLocalTarget.class.getName()); + + MethodSignature signature = new MethodSignature(ThisLocalTarget.class.getName(), "call"); + SootMethod method = sootSetup.resolveMethod(signature); + Method jimpleMethod = JimpleMethod.of(method); + + boolean checked = false; + for (Statement stmt : jimpleMethod.getStatements()) { + if (stmt.containsInvokeExpr() + && stmt.getInvokeExpr().getMethod().getName().equals("callWithThis")) { + InvokeExpr invokeExpr = stmt.getInvokeExpr(); + Val base = invokeExpr.getBase(); + + Assert.assertEquals(jimpleMethod.getThisLocal(), base); + Assert.assertEquals(base, jimpleMethod.getThisLocal()); + Assert.assertTrue(jimpleMethod.isThisLocal(base)); + + checked = true; + } + } + + if (!checked) { + Assert.fail("Did not check this local"); + } + } + @Test @Override public void parameterLocalTest() { SootSetup sootSetup = new SootSetup(); - sootSetup.setupSoot(ParameterLocals.class.getName()); + sootSetup.setupSoot(ParameterLocalsTarget.class.getName()); // No parameters MethodSignature noArgsSignature = - new MethodSignature(ParameterLocals.class.getName(), "noParameters"); + new MethodSignature(ParameterLocalsTarget.class.getName(), "noParameters"); SootMethod noArgs = sootSetup.resolveMethod(noArgsSignature); Method noArgsMethod = JimpleMethod.of(noArgs); @@ -40,7 +75,7 @@ public void parameterLocalTest() { // One parameter (primitive type) MethodSignature oneArgSignature = - new MethodSignature(ParameterLocals.class.getName(), "oneParameter", List.of("int")); + new MethodSignature(ParameterLocalsTarget.class.getName(), "oneParameter", List.of("int")); SootMethod oneArg = sootSetup.resolveMethod(oneArgSignature); Method oneArgMethod = JimpleMethod.of(oneArg); @@ -50,7 +85,9 @@ public void parameterLocalTest() { // Two parameters (primitive type + RefType) MethodSignature twoArgSignature = new MethodSignature( - ParameterLocals.class.getName(), "twoParameters", List.of("int", A.class.getName())); + ParameterLocalsTarget.class.getName(), + "twoParameters", + List.of("int", A.class.getName())); SootMethod twoArgs = sootSetup.resolveMethod(twoArgSignature); Method twoArgsMethod = JimpleMethod.of(twoArgs); @@ -58,4 +95,50 @@ public void parameterLocalTest() { Assert.assertEquals("int", twoArgsMethod.getParameterLocal(0).getType().toString()); Assert.assertEquals(A.class.getName(), twoArgsMethod.getParameterLocal(1).getType().toString()); } + + @Test + @Override + public void hashCodeEqualsLocalTest() { + SootSetup sootSetup = new SootSetup(); + sootSetup.setupSoot(HashCodeEqualsLocalTarget.class.getName()); + + // Parameter locals + MethodSignature signature = + new MethodSignature( + ParameterLocalsTarget.class.getName(), + "parameterCall", + List.of(A.class.getName(), "int")); + SootMethod method = sootSetup.resolveMethod(signature); + Method jimpleMethod = JimpleMethod.of(method); + + Val firstArg = jimpleMethod.getParameterLocal(0); + Val secondArg = jimpleMethod.getParameterLocal(1); + + boolean checked = false; + for (Statement stmt : jimpleMethod.getStatements()) { + if (stmt.containsInvokeExpr() + && stmt.getInvokeExpr().getMethod().getName().equals("methodCall")) { + InvokeExpr invokeExpr = stmt.getInvokeExpr(); + Val base = invokeExpr.getBase(); + Val arg = invokeExpr.getArg(0); + + // equals in both directions + Assert.assertEquals(base, firstArg); + Assert.assertEquals(firstArg, base); + + Assert.assertEquals(arg, secondArg); + Assert.assertEquals(secondArg, arg); + + // hash codes + Assert.assertEquals(base.hashCode(), firstArg.hashCode()); + Assert.assertEquals(arg.hashCode(), secondArg.hashCode()); + + checked = true; + } + } + + if (!checked) { + Assert.fail("Did not check equals and hashCode methods for parameter locals"); + } + } } diff --git a/boomerangScope/src/main/java/boomerang/scope/AllocVal.java b/boomerangScope/src/main/java/boomerang/scope/AllocVal.java index cb9ada7c2..ac95960f2 100644 --- a/boomerangScope/src/main/java/boomerang/scope/AllocVal.java +++ b/boomerangScope/src/main/java/boomerang/scope/AllocVal.java @@ -217,12 +217,12 @@ public int hashCode() { @Override public String toString() { return "AllocVal{" - + "delegate=" + + "delegate: " + delegate - + ", allocStatement=" + + ", allocStatement: " + allocStatement - + ", allocationVal=" + + ", allocationVal: " + allocationVal - + '}'; + + "}"; } } diff --git a/boomerangScope/src/test/java/boomerang/scope/test/BoomerangScopeTests.java b/boomerangScope/src/test/java/boomerang/scope/test/BoomerangScopeTests.java index 329a8ca46..ff3492ca6 100644 --- a/boomerangScope/src/test/java/boomerang/scope/test/BoomerangScopeTests.java +++ b/boomerangScope/src/test/java/boomerang/scope/test/BoomerangScopeTests.java @@ -14,5 +14,9 @@ @SuppressWarnings("unused") public interface BoomerangScopeTests { + void thisLocalTest(); + void parameterLocalTest(); + + void hashCodeEqualsLocalTest(); } diff --git a/boomerangScope/src/test/java/boomerang/scope/test/targets/A.java b/boomerangScope/src/test/java/boomerang/scope/test/targets/A.java index a7d0ffccc..27cc9766b 100644 --- a/boomerangScope/src/test/java/boomerang/scope/test/targets/A.java +++ b/boomerangScope/src/test/java/boomerang/scope/test/targets/A.java @@ -11,4 +11,7 @@ */ package boomerang.scope.test.targets; -public class A {} +public class A { + + public void methodCall(@SuppressWarnings("unused") int i) {} +} diff --git a/boomerangScope/src/test/java/boomerang/scope/test/targets/HashCodeEqualsLocalTarget.java b/boomerangScope/src/test/java/boomerang/scope/test/targets/HashCodeEqualsLocalTarget.java new file mode 100644 index 000000000..f912d2ff5 --- /dev/null +++ b/boomerangScope/src/test/java/boomerang/scope/test/targets/HashCodeEqualsLocalTarget.java @@ -0,0 +1,40 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ +package boomerang.scope.test.targets; + +public class HashCodeEqualsLocalTarget { + + public static void main(String[] args) { + HashCodeEqualsLocalTarget hashCodeEqualsLocalTarget = new HashCodeEqualsLocalTarget(); + + A a = new A(); + hashCodeEqualsLocalTarget.parameterCall(a, 10); + hashCodeEqualsLocalTarget.definedCall(); + } + + /** + * Method to test whether parameter locals and used locals are equal + * + * @param a parameter local with reference type + * @param i parameter local with primitive type + */ + public void parameterCall(A a, int i) { + a.methodCall(i); + } + + /** Method to test whether defined locals and used locals are equal */ + public void definedCall() { + A a = new A(); + int i = 10; + a.methodCall(i); + } +} diff --git a/boomerangScope/src/test/java/boomerang/scope/test/targets/ParameterLocals.java b/boomerangScope/src/test/java/boomerang/scope/test/targets/ParameterLocalsTarget.java similarity index 76% rename from boomerangScope/src/test/java/boomerang/scope/test/targets/ParameterLocals.java rename to boomerangScope/src/test/java/boomerang/scope/test/targets/ParameterLocalsTarget.java index 04772393f..c15eebb81 100644 --- a/boomerangScope/src/test/java/boomerang/scope/test/targets/ParameterLocals.java +++ b/boomerangScope/src/test/java/boomerang/scope/test/targets/ParameterLocalsTarget.java @@ -11,16 +11,16 @@ */ package boomerang.scope.test.targets; -public class ParameterLocals { +public class ParameterLocalsTarget { public static void main(String[] args) { - ParameterLocals parameterLocals = new ParameterLocals(); + ParameterLocalsTarget parameterLocalsTarget = new ParameterLocalsTarget(); - parameterLocals.noParameters(); - parameterLocals.oneParameter(10); + parameterLocalsTarget.noParameters(); + parameterLocalsTarget.oneParameter(10); A a = new A(); - parameterLocals.twoParameters(20, a); + parameterLocalsTarget.twoParameters(20, a); } public void noParameters() {} diff --git a/boomerangScope/src/test/java/boomerang/scope/test/targets/ThisLocalTarget.java b/boomerangScope/src/test/java/boomerang/scope/test/targets/ThisLocalTarget.java new file mode 100644 index 000000000..b81ccfe9f --- /dev/null +++ b/boomerangScope/src/test/java/boomerang/scope/test/targets/ThisLocalTarget.java @@ -0,0 +1,30 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ +package boomerang.scope.test.targets; + +public class ThisLocalTarget { + + public static void main(String[] args) { + ThisLocalTarget thisLocalTarget = new ThisLocalTarget(); + thisLocalTarget.call(); + } + + /** + * Method to test the 'this' local. The call to {@link #callWithThis()} is resolved to + * 'this.callWithThis()'. + */ + public void call() { + callWithThis(); + } + + public void callWithThis() {} +} diff --git a/testCore/src/main/java/test/TestingFramework.java b/testCore/src/main/java/test/TestingFramework.java index b2e7ed592..a39ab8a48 100644 --- a/testCore/src/main/java/test/TestingFramework.java +++ b/testCore/src/main/java/test/TestingFramework.java @@ -21,7 +21,7 @@ import java.util.stream.Collectors; import org.junit.Assert; import test.setup.MethodWrapper; -import test.setup.SootTestSetup; +import test.setup.OpalTestSetup; import test.setup.TestSetup; public class TestingFramework { @@ -30,7 +30,7 @@ public class TestingFramework { public TestingFramework() { // TODO Parameterize - this.testSetup = new SootTestSetup(); + this.testSetup = new OpalTestSetup(); } public FrameworkScope getFrameworkScope(MethodWrapper methodWrapper) { From cf4c1a5aa876345ba4af33ac798d2c3e39fa5ec7 Mon Sep 17 00:00:00 2001 From: Sven Meyer Date: Tue, 18 Mar 2025 14:04:19 +0100 Subject: [PATCH 17/61] Extend equals method for OpalMethod --- .../java/test/core/AbstractBoomerangTest.java | 12 +++----- boomerangScope-Opal/pom.xml | 2 +- .../boomerang/scope/opal/tac/OpalLocal.scala | 30 ++++++++++--------- .../boomerang/scope/opal/tac/OpalMethod.scala | 3 +- 4 files changed, 22 insertions(+), 25 deletions(-) diff --git a/boomerangPDS/src/test/java/test/core/AbstractBoomerangTest.java b/boomerangPDS/src/test/java/test/core/AbstractBoomerangTest.java index e27152cf9..31ab50f8e 100644 --- a/boomerangPDS/src/test/java/test/core/AbstractBoomerangTest.java +++ b/boomerangPDS/src/test/java/test/core/AbstractBoomerangTest.java @@ -239,7 +239,7 @@ private void compareIntegerResults(Set> backwardResults, Analysi InvokeExpr ie = stmt.getStart().getInvokeExpr(); Val arg = ie.getArg(1); Collection expectedResults = parse(arg); - LOGGER.info("Expected results: {}", expectedResults); + LOGGER.info("Expected results: {}", String.join("\n - ", expectedResults)); boolean imprecise = false; for (Node v : backwardResults) { if (v.fact() instanceof AllocVal) { @@ -308,10 +308,10 @@ private void compareQuery( Collection expectedResults, Collection> results, AnalysisMode analysis) { - LOGGER.info("Boomerang Results: {}", results); + LOGGER.info("Boomerang Results:\n - {}", results.stream().map(r -> r.fact().toString()).collect(Collectors.joining("\n - "))); LOGGER.info( - "Expected Results: {}", - expectedResults.stream().map(Query::var).collect(Collectors.toList())); + "Expected Results:\n - {}", + expectedResults.stream().map(r -> r.var().toString()).collect(Collectors.joining("\n - "))); Collection> falseNegativeAllocationSites = new HashSet<>(); for (Query res : expectedResults) { if (!results.contains(res.asNode())) falseNegativeAllocationSites.add(res.asNode()); @@ -350,8 +350,4 @@ private void checkContainsAllExpectedAccessPath(Set allAliases) { Assert.fail("Did not find all access path! " + expected); } } - - protected DataFlowScope getDataFlowScope() { - return null; - } } diff --git a/boomerangScope-Opal/pom.xml b/boomerangScope-Opal/pom.xml index 60409c69c..d623801d5 100644 --- a/boomerangScope-Opal/pom.xml +++ b/boomerangScope-Opal/pom.xml @@ -5,7 +5,7 @@ de.fraunhofer.iem Boomerang-Parent - 3.2.4-SNAPSHOT + 4.0.1-SNAPSHOT boomerangScope-Opal diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalLocal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalLocal.scala index 8b3156359..1d5423ca0 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalLocal.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalLocal.scala @@ -137,20 +137,22 @@ class OpalLocal(val delegate: Expr[DUVar[ValueInformation]], method: OpalMethod, case dVar: DVar[_] if other.delegate.isInstanceOf[UVar[_]] => val otherVar = other.delegate.asInstanceOf[UVar[ValueInformation]] - // Parameter vars have no corresponding DVar - if (otherVar.definedBy.head < 0) { - return false - } - - val tac = OpalClient.getTacForMethod(method.delegate) - val defStmt = tac.stmts(otherVar.definedBy.head) - - if (!defStmt.isAssignment) { - return false - } - - val targetVar = defStmt.asAssignment.targetVar - super.equals(other) && dVar.hashCode() == targetVar.hashCode() + otherVar.definedBy.foreach(defSite => { + // Consider only non-parameter DVars + if (defSite >= 0) { + val tac = OpalClient.getTacForMethod(method.delegate) + val defStmt = tac.stmts(defSite) + + if (defStmt.isAssignment) { + val targetVar = defStmt.asAssignment.targetVar + if (super.equals(other) && dVar.hashCode() == targetVar.hashCode()) { + return true + } + } + } + }) + + false case _: UVar[_] if other.delegate.isInstanceOf[UVar[_]] => super.equals(other) && this.delegate.hashCode() == other.delegate.hashCode() case _ => throw new RuntimeException("Cannot compare a variable with a non variable") diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalMethod.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalMethod.scala index 2f66d080a..b91f9454b 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalMethod.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalMethod.scala @@ -2,10 +2,9 @@ package boomerang.scope.opal.tac import boomerang.scope._ import boomerang.scope.opal.OpalClient -import org.opalj.tac.{InstanceFunctionCall, InstanceMethodCall, UVar} +import org.opalj.tac.{InstanceFunctionCall, InstanceMethodCall} import java.util -import scala.jdk.CollectionConverters._ case class OpalMethod(delegate: org.opalj.br.Method) extends Method { From 3ea64e81c0f5cf3021513521ea32112c3bcd84de Mon Sep 17 00:00:00 2001 From: Sven Meyer Date: Wed, 19 Mar 2025 13:43:44 +0100 Subject: [PATCH 18/61] Add correct logic for fields --- .../java/test/core/AbstractBoomerangTest.java | 4 +- .../boomerang/scope/opal/OpalClient.scala | 16 -- .../scope/opal/tac/OpalControlFlowGraph.scala | 20 +- .../boomerang/scope/opal/tac/OpalField.scala | 13 +- .../boomerang/scope/opal/tac/OpalMethod.scala | 51 ++--- .../scope/opal/tac/OpalStatement.scala | 94 ++++------ .../scope/opal/tac/OpalStaticFieldVal.scala | 65 +------ .../boomerang/scope/opal/tac/OpalVal.scala | 2 +- .../boomerang/scope/opal/OpalFieldTest.scala | 175 ++++++++++++++++++ ...palScopeTest.scala => OpalLocalTest.scala} | 34 +++- .../scope/opal/OpalStatementTest.scala | 28 +++ .../scope/soot/jimple/JimpleField.java | 11 ++ .../soot/jimple/JimpleStaticFieldVal.java | 126 ------------- .../scope/sootup/jimple/JimpleUpField.java | 11 ++ .../java/boomerang/scope/wala/WALAField.java | 11 ++ .../src/main/java/boomerang/scope/Field.java | 8 + .../java/boomerang/scope/StaticFieldVal.java | 125 +++++++++++++ .../test/targets/ControlFlowGraphTarget.java | 30 +++ .../scope/test/targets/FieldClass.java | 37 ++++ .../scope/test/targets/FieldTarget.java | 70 +++++++ .../scope/test/targets/LocalCountTarget.java | 47 +++++ 21 files changed, 658 insertions(+), 320 deletions(-) create mode 100644 boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalFieldTest.scala rename boomerangScope-Opal/src/test/scala/boomerang/scope/opal/{OpalScopeTest.scala => OpalLocalTest.scala} (82%) create mode 100644 boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalStatementTest.scala create mode 100644 boomerangScope/src/test/java/boomerang/scope/test/targets/ControlFlowGraphTarget.java create mode 100644 boomerangScope/src/test/java/boomerang/scope/test/targets/FieldClass.java create mode 100644 boomerangScope/src/test/java/boomerang/scope/test/targets/FieldTarget.java create mode 100644 boomerangScope/src/test/java/boomerang/scope/test/targets/LocalCountTarget.java diff --git a/boomerangPDS/src/test/java/test/core/AbstractBoomerangTest.java b/boomerangPDS/src/test/java/test/core/AbstractBoomerangTest.java index 31ab50f8e..a462bc93b 100644 --- a/boomerangPDS/src/test/java/test/core/AbstractBoomerangTest.java +++ b/boomerangPDS/src/test/java/test/core/AbstractBoomerangTest.java @@ -308,7 +308,9 @@ private void compareQuery( Collection expectedResults, Collection> results, AnalysisMode analysis) { - LOGGER.info("Boomerang Results:\n - {}", results.stream().map(r -> r.fact().toString()).collect(Collectors.joining("\n - "))); + LOGGER.info( + "Boomerang Results:\n - {}", + results.stream().map(r -> r.fact().toString()).collect(Collectors.joining("\n - "))); LOGGER.info( "Expected Results:\n - {}", expectedResults.stream().map(r -> r.var().toString()).collect(Collectors.joining("\n - "))); diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalClient.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalClient.scala index 220513ddc..1609ebc2a 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalClient.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalClient.scala @@ -25,20 +25,4 @@ object OpalClient { def getTacForMethod(method: Method): AITACode[TACMethodParameter, ValueInformation] = tacCodes.get(method) - def resolveFieldStore(stmt: FieldWriteAccessStmt[_]): Option[Field] = stmt.resolveField(project.get) - - def resolveFieldLoad(expr: FieldRead[_]): Option[Field] = expr.resolveField(project.get) - - def resolveMethodRef(declaringClass: ReferenceType, name: String, methodDescriptor: MethodDescriptor): Option[DefinedMethod] = { - val method = project.get.resolveMethodReference(declaringClass, name, methodDescriptor, forceLookupInSuperinterfacesOnFailure = true) - - if (method.isDefined) { - val declaredMethod = declaredMethods.get(method.get) - - return Some(declaredMethod) - } - - None - } - } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalControlFlowGraph.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalControlFlowGraph.scala index 36213dac0..f071dc4c8 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalControlFlowGraph.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalControlFlowGraph.scala @@ -3,10 +3,12 @@ package boomerang.scope.opal.tac import boomerang.scope.opal.OpalClient import boomerang.scope.{ControlFlowGraph, Statement} import com.google.common.collect.{HashMultimap, Multimap} +import org.opalj.br.Method +import org.opalj.br.cfg.CFGFactory import java.util -class OpalControlFlowGraph(method: OpalMethod) extends ControlFlowGraph { +class OpalControlFlowGraph(method: Method) extends ControlFlowGraph { private var cacheBuilt = false @@ -44,13 +46,11 @@ class OpalControlFlowGraph(method: OpalMethod) extends ControlFlowGraph { private def buildCache(): Unit = { if (cacheBuilt) return - val tac = OpalClient.getTacForMethod(method.delegate) - - // val entryPoint = tac.stmts(tac.cfg.startBlock.startPC) - // startPointCache.add(new OpalStatement(entryPoint, method)) + val opalMethod = OpalMethod(method) + val tac = OpalClient.getTacForMethod(method) tac.stmts.foreach(stmt => { - val statement = new OpalStatement(stmt, method) + val statement = new OpalStatement(stmt, opalMethod) statements.add(statement) val stmtPc = tac.pcToIndex(stmt.pc) @@ -58,12 +58,12 @@ class OpalControlFlowGraph(method: OpalMethod) extends ControlFlowGraph { val predecessors = tac.cfg.predecessors(stmtPc) if (predecessors.isEmpty) { // No predecessors => Head statement - val headStatement = new OpalStatement(stmt, method) + val headStatement = new OpalStatement(stmt, opalMethod) startPointCache.add(headStatement) } else { predecessors.foreach(predecessorPc => { val predecessor = tac.stmts(predecessorPc) - val predecessorStatement = new OpalStatement(predecessor, method) + val predecessorStatement = new OpalStatement(predecessor, opalMethod) predsOfCache.put(statement, predecessorStatement) }) @@ -72,12 +72,12 @@ class OpalControlFlowGraph(method: OpalMethod) extends ControlFlowGraph { val successors = tac.cfg.successors(stmtPc) if (successors.isEmpty) { // No successors => Tail statement - val tailStmt = new OpalStatement(stmt, method) + val tailStmt = new OpalStatement(stmt, opalMethod) endPointCache.add(tailStmt) } else { successors.foreach(successorPc => { val successor = tac.stmts(successorPc) - val successorStatement = new OpalStatement(successor, method) + val successorStatement = new OpalStatement(successor, opalMethod) succsOfCache.put(statement, successorStatement) }) diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalField.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalField.scala index 3e94a3b82..67477f215 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalField.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalField.scala @@ -1,10 +1,15 @@ package boomerang.scope.opal.tac -import boomerang.scope.Field +import boomerang.scope.{Field, Type} +import org.opalj.br.{FieldType, ObjectType} -case class OpalField(delegate: org.opalj.br.Field) extends Field { +case class OpalField(declaringClass: ObjectType, fieldType: FieldType, name: String) extends Field { - override def isInnerClassField: Boolean = delegate.name.contains("$") + override def isPredefinedField: Boolean = false - override def toString: String = delegate.toJava + override def isInnerClassField: Boolean = declaringClass.fqn.contains("$") + + override def getType: Type = OpalType(fieldType) + + override def toString: String = s"<${declaringClass.fqn}>.${fieldType.toJava} $name" } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalMethod.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalMethod.scala index b91f9454b..1e4d8e1f5 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalMethod.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalMethod.scala @@ -15,7 +15,7 @@ case class OpalMethod(delegate: org.opalj.br.Method) extends Method { private var localCache: Option[util.Set[Val]] = None private var parameterLocalCache: Option[util.List[Val]] = None - private val cfg = new OpalControlFlowGraph(this) + private val cfg = new OpalControlFlowGraph(delegate) override def isStaticInitializer: Boolean = delegate.isStaticInitializer @@ -59,45 +59,23 @@ case class OpalMethod(delegate: org.opalj.br.Method) extends Method { if (localCache.isEmpty) { localCache = Some(new util.HashSet[Val]()) - val tac = OpalClient.getTacForMethod(delegate) + // 'this' local + if (!isStatic) { + localCache.get.add(getThisLocal) + } - for (stmt <- tac.stmts) { - if (stmt.isMethodCall) { - // Extract the base - if (stmt.isInstanceOf[InstanceMethodCall[_]]) { - val base = new OpalLocal(stmt.asInstanceMethodCall.receiver, this) - localCache.get.add(base) - } - - // Parameters of method calls - stmt.asMethodCall.params.foreach(param => { - if (param.isVar) { - localCache.get.add(new OpalLocal(param, this)) - } - }) - } + // Parameter locals + localCache.get.addAll(getParameterLocals) + + val tac = OpalClient.getTacForMethod(delegate) + tac.stmts.foreach(stmt => { + // Locals are always defined as DVar if (stmt.isAssignment) { - // Target variable val targetVar = stmt.asAssignment.targetVar localCache.get.add(new OpalLocal(targetVar, this)) - - if (stmt.asAssignment.expr.isFunctionCall) { - // Extract the base - if (stmt.asAssignment.expr.isInstanceOf[InstanceFunctionCall[_]]) { - val base = new OpalLocal(stmt.asAssignment.expr.asInstanceFunctionCall.receiver, this) - localCache.get.add(base) - } - - // Parameters of function call - stmt.asAssignment.expr.asFunctionCall.params.foreach(param => { - if (param.isVar) { - localCache.get.add(new OpalLocal(param, this)) - } - }) - } } - } + }) } localCache.get @@ -116,11 +94,6 @@ case class OpalMethod(delegate: org.opalj.br.Method) extends Method { val parameterLocal = new OpalParameterLocal(paramType, index, this) parameterLocalCache.get.add(parameterLocal) }) - - /*delegate.parameterTypes.foreach(param => { - val parameterLocal = new OpalParameterLocal(param, this) - parameterLocalCache.get.add(parameterLocal) - })*/ } parameterLocalCache.get diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala index b1ae249d7..acbffae88 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala @@ -34,17 +34,20 @@ class OpalStatement(val delegate: Stmt[DUVar[ValueInformation]], m: OpalMethod) override def getWrittenField: Field = { if (isFieldStore) { - val resolvedField = OpalClient.resolveFieldStore(delegate.asPutField) - return OpalField(resolvedField.get) + val fieldStore = delegate.asPutField + + return OpalField(fieldStore.declaringClass, fieldStore.declaredFieldType, fieldStore.name) } if (isStaticFieldStore) { - val resolvedField = OpalClient.resolveFieldStore(delegate.asPutStatic) - return OpalField(resolvedField.get) + val fieldStore = delegate.asPutStatic + + return OpalField(fieldStore.declaringClass, fieldStore.declaredFieldType, fieldStore.name) } if (isArrayStore) { // TODO + val arrayStore = delegate.asArrayStore //val resolvedField = OpalClient.resolveFieldStore(delegate.asArrayStore) //return new OpalField(resolvedField.get) } @@ -67,8 +70,9 @@ class OpalStatement(val delegate: Stmt[DUVar[ValueInformation]], m: OpalMethod) override def getLoadedField: Field = { // TODO Also array? if (isFieldLoad) { - val resolvedField = OpalClient.resolveFieldLoad(delegate.asAssignment.expr.asFieldRead) - return OpalField(resolvedField.get) + val fieldLoad = delegate.asAssignment.expr.asGetField + + return OpalField(fieldLoad.declaringClass, fieldLoad.declaredFieldType, fieldLoad.name) } throw new RuntimeException("Statement is not a field load operation") @@ -76,7 +80,7 @@ class OpalStatement(val delegate: Stmt[DUVar[ValueInformation]], m: OpalMethod) override def isFieldLoadWithBase(base: Val): Boolean = { // TODO Also array? - if (delegate.isAssignment && isFieldLoad) { + if (isFieldLoad) { return getFieldLoad.getX.equals(base) } @@ -200,47 +204,30 @@ class OpalStatement(val delegate: Stmt[DUVar[ValueInformation]], m: OpalMethod) override def isMultiArrayAllocation: Boolean = false - override def isFieldStore: Boolean = { - if (!delegate.isPutField) { - return false - } - - val field = OpalClient.resolveFieldStore(delegate.asPutField) - field.isDefined - } + override def isFieldStore: Boolean = delegate.isPutField override def isArrayStore: Boolean = delegate.isArrayStore override def isArrayLoad: Boolean = { - if (!delegate.isAssignment) { - return false + if (delegate.isAssignment) { + delegate.asAssignment.expr.isArrayLoad } - delegate.asAssignment.expr.isArrayLoad + false } - override def isFieldLoad: Boolean = { - if (!delegate.isAssignment) { - return false - } - - if (!delegate.asAssignment.expr.isGetField) { - return false - } - - val field = OpalClient.resolveFieldLoad(delegate.asAssignment.expr.asGetField) - field.isDefined - } + override def isFieldLoad: Boolean = delegate.isAssignment && delegate.asAssignment.expr.isGetField override def isIdentityStmt: Boolean = false override def getFieldStore: Pair[Val, Field] = { if (isFieldStore) { - val resolvedField = OpalClient.resolveFieldStore(delegate.asPutField).get - val ref = delegate.asPutField.objRef + val fieldStore = delegate.asPutField - // TODO - return new Pair(new OpalVal(ref, m), OpalField(resolvedField)) + val local = new OpalLocal(fieldStore.objRef, m) + val field = OpalField(fieldStore.declaringClass, fieldStore.declaredFieldType, fieldStore.name) + + return new Pair(local, field) } throw new RuntimeException("Statement is not a field store operation") @@ -248,50 +235,33 @@ class OpalStatement(val delegate: Stmt[DUVar[ValueInformation]], m: OpalMethod) override def getFieldLoad: Pair[Val, Field] = { if (isFieldLoad) { - val resolvedField = OpalClient.resolveFieldLoad(delegate.asAssignment.expr.asFieldRead).get - val ref = delegate.asAssignment.expr.asGetField.objRef + val fieldLoad = delegate.asAssignment.expr.asGetField - // TODO - return new Pair(new OpalVal(ref, m), OpalField(resolvedField)) - } + val local = new OpalLocal(fieldLoad.objRef, m) + val field = OpalField(fieldLoad.declaringClass, fieldLoad.declaredFieldType, fieldLoad.name) - throw new RuntimeException("Statement is not a field load operation") - } - - override def isStaticFieldLoad: Boolean = { - if (!delegate.isAssignment) { - return false - } - - if (!delegate.asAssignment.expr.isGetStatic) { - return false + return new Pair(local, field) } - val field = OpalClient.resolveFieldLoad(delegate.asAssignment.expr.asGetStatic) - field.isDefined + throw new RuntimeException("Statement is not a field load operation") } - override def isStaticFieldStore: Boolean = { - if (!delegate.isPutStatic) { - return false - } + override def isStaticFieldLoad: Boolean = delegate.isAssignment && delegate.asAssignment.expr.isGetStatic - val field = OpalClient.resolveFieldStore(delegate.asPutStatic) - field.isDefined - } + override def isStaticFieldStore: Boolean = delegate.isPutStatic override def getStaticField: StaticFieldVal = { if (isStaticFieldLoad) { - val resolvedField = OpalClient.resolveFieldLoad(delegate.asAssignment.expr.asGetStatic) - val staticField = OpalField(resolvedField.get) + val staticFieldLoad = delegate.asAssignment.expr.asGetStatic + val staticField = OpalField(staticFieldLoad.declaringClass, staticFieldLoad.declaredFieldType, staticFieldLoad.name) return new OpalStaticFieldVal(staticField, m) } if (isStaticFieldStore) { - val resolvedField = OpalClient.resolveFieldStore(delegate.asPutStatic) - val staticField = OpalField(resolvedField.get) + val staticFieldStore = delegate.asPutStatic + val staticField = OpalField(staticFieldStore.declaringClass, staticFieldStore.declaredFieldType, staticFieldStore.name) return new OpalStaticFieldVal(staticField, m) } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStaticFieldVal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStaticFieldVal.scala index 42583cfa7..2d9ca64e0 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStaticFieldVal.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStaticFieldVal.scala @@ -2,71 +2,26 @@ package boomerang.scope.opal.tac import boomerang.scope._ +import java.util.Objects + class OpalStaticFieldVal(field: OpalField, method: Method, unbalanced: ControlFlowGraph.Edge = null) extends StaticFieldVal(method, unbalanced) { - override def field(): Field = field + override def field: Field = field override def asUnbalanced(stmt: ControlFlowGraph.Edge): Val = new OpalStaticFieldVal(field, method, stmt) - override def getType: Type = OpalType(field.delegate.fieldType) - - override def isStatic: Boolean = true - - override def isNewExpr: Boolean = false - - override def getNewExprType: Type = throw new RuntimeException("Static field is not a new expression") - - override def isLocal: Boolean = false - - override def isArrayAllocationVal: Boolean = false - - override def getArrayAllocationSize: Val = throw new RuntimeException("Static field is not an array allocation expression") - - override def isNull: Boolean = false - - override def isStringConstant: Boolean = false - - override def getStringValue: String = throw new RuntimeException("Static field is not a string constant") - - override def isStringBufferOrBuilder: Boolean = false - - override def isThrowableAllocationType: Boolean = false - - override def isCast: Boolean = false - - override def getCastOp: Val = throw new RuntimeException("Static field is not a cast operation") - - override def isArrayRef: Boolean = false - - override def isInstanceOfExpr: Boolean = false - - override def getInstanceOfOp: Val = throw new RuntimeException("Static field is not an instance of operation") - - override def isLengthExpr: Boolean = false - - override def getLengthOp: Val = throw new RuntimeException("Static field is not a length operation") - - override def isIntConstant: Boolean = false - - override def isClassConstant: Boolean = false - - override def getClassConstantType: Type = throw new RuntimeException("Static field has not a class constant type") + override def getType: Type = OpalType(field.fieldType) override def withNewMethod(callee: Method): Val = new OpalStaticFieldVal(field, callee) - override def isLongConstant: Boolean = false - - override def getIntValue: Int = throw new RuntimeException("Static field is not an int value") - - override def getLongValue: Long = throw new RuntimeException("Static field is not a long value") - - override def getArrayBase: Pair[Val, Integer] = throw new RuntimeException("Static field has no array base") - override def getVariableName: String = field.toString - override def hashCode(): Int = ??? + override def hashCode: Int = Objects.hash(super.hashCode(), field) - override def equals(obj: Any): Boolean = ??? + override def equals(other: Any): Boolean = other match { + case that: OpalStaticFieldVal => super.equals(that) && this.field.equals(that.field) + case _ => false + } - override def toString: String = ??? + override def toString: String = s"StaticField: $field" } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalVal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalVal.scala index b0b9fab49..cd6fd3512 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalVal.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalVal.scala @@ -20,7 +20,7 @@ class OpalVal(val delegate: Expr[DUVar[ValueInformation]], method: OpalMethod, u } // TODO - override def isStatic: Boolean = ??? + override def isStatic: Boolean = false override def isNewExpr: Boolean = delegate.isNew diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalFieldTest.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalFieldTest.scala new file mode 100644 index 000000000..8186e2222 --- /dev/null +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalFieldTest.scala @@ -0,0 +1,175 @@ +package boomerang.scope.opal + +import boomerang.scope.opal.tac.OpalMethod +import boomerang.scope.test.MethodSignature +import boomerang.scope.test.targets.{A, FieldClass, FieldTarget} +import org.junit.{Assert, Test} + +class OpalFieldTest { + + @Test + def fieldLoadTest(): Unit = { + val opalSetup = new OpalSetup() + opalSetup.setupOpal(classOf[FieldTarget].getName) + + val signature = new MethodSignature(classOf[FieldTarget].getName, "fieldLoad", "Void") + val method = opalSetup.resolveMethod(signature) + val opalMethod = OpalMethod(method) + + var fieldLoadCount = 0 + opalMethod.getStatements.forEach(stmt => { + if (stmt.isFieldLoad) { + fieldLoadCount += 1 + + val field = stmt.getLoadedField + Assert.assertFalse(field.isPredefinedField) + Assert.assertFalse(field.isInnerClassField) + + val fieldLoad = stmt.getFieldLoad + Assert.assertTrue(fieldLoad.getX.getType.toString.equals(classOf[FieldClass].getName)) + + val fieldType = fieldLoad.getY.getType.toString + Assert.assertFalse(fieldLoad.getY.isPredefinedField) + Assert.assertTrue(fieldType.equals("int") || fieldType.equals(classOf[A].getName)) + } + }) + + Assert.assertEquals(2, fieldLoadCount) + } + + @Test + def fieldStoreTest(): Unit = { + val opalSetup = new OpalSetup() + opalSetup.setupOpal(classOf[FieldTarget].getName) + + val signature = new MethodSignature(classOf[FieldTarget].getName, "fieldStore", "Void") + val method = opalSetup.resolveMethod(signature) + val opalMethod = OpalMethod(method) + + var fieldStoreCount = 0 + opalMethod.getStatements.forEach(stmt => { + if (stmt.isFieldStore) { + fieldStoreCount += 1 + + val fieldStore = stmt.getFieldStore + Assert.assertTrue(fieldStore.getX.getType.toString.equals(classOf[FieldClass].getName)) + + val fieldType = fieldStore.getY.getType.toString + Assert.assertFalse(fieldStore.getY.isPredefinedField) + Assert.assertFalse(fieldStore.getY.isInnerClassField) + Assert.assertTrue(fieldType.equals("int") || fieldType.equals(classOf[A].getName)) + } + }) + + Assert.assertEquals(2, fieldStoreCount) + } + + @Test + def staticFieldLoadTest(): Unit = { + val opalSetup = new OpalSetup() + opalSetup.setupOpal(classOf[FieldTarget].getName) + + val signature = new MethodSignature(classOf[FieldTarget].getName, "staticFieldLoad", "Void") + val method = opalSetup.resolveMethod(signature) + val opalMethod = OpalMethod(method) + + var staticFieldLoadCount = 0 + opalMethod.getStatements.forEach(stmt => { + if (stmt.isStaticFieldLoad) { + staticFieldLoadCount += 1 + + val staticField = stmt.getStaticField + Assert.assertFalse(staticField.field().isPredefinedField) + Assert.assertFalse(staticField.field().isInnerClassField) + + val typeName = staticField.getType.toString + Assert.assertTrue(typeName.equals("int") || typeName.equals(classOf[A].getName)) + } + }) + + Assert.assertEquals(2, staticFieldLoadCount) + } + + @Test + def staticFieldStoreTest(): Unit = { + val opalSetup = new OpalSetup() + opalSetup.setupOpal(classOf[FieldTarget].getName) + + val signature = new MethodSignature(classOf[FieldTarget].getName, "staticFieldStore", "Void") + val method = opalSetup.resolveMethod(signature) + val opalMethod = OpalMethod(method) + + var staticFieldStoreCount = 0 + opalMethod.getStatements.forEach(stmt => { + if (stmt.isStaticFieldStore) { + staticFieldStoreCount += 1 + + val staticField = stmt.getStaticField + Assert.assertFalse(staticField.field().isPredefinedField) + Assert.assertFalse(staticField.field().isInnerClassField) + + val typeName = staticField.getType.toString + Assert.assertTrue(typeName.equals("int") || typeName.equals(classOf[A].getName)) + } + }) + + Assert.assertEquals(2, staticFieldStoreCount) + } + + @Test + def innerFieldLoadTest(): Unit = { + val opalSetup = new OpalSetup() + opalSetup.setupOpal(classOf[FieldTarget].getName) + + val signature = new MethodSignature(classOf[FieldTarget].getName, "innerFieldLoad", "Void") + val method = opalSetup.resolveMethod(signature) + val opalMethod = OpalMethod(method) + + var fieldLoadCount = 0 + opalMethod.getStatements.forEach(stmt => { + if (stmt.isFieldLoad) { + fieldLoadCount += 1 + + val field = stmt.getLoadedField + Assert.assertFalse(field.isPredefinedField) + Assert.assertTrue(field.isInnerClassField) + + val fieldLoad = stmt.getFieldLoad + Assert.assertTrue(fieldLoad.getX.getType.toString.equals(classOf[FieldClass.InnerFieldClass].getName)) + + val fieldType = fieldLoad.getY.getType.toString + Assert.assertFalse(fieldLoad.getY.isPredefinedField) + Assert.assertTrue(fieldType.equals("int") || fieldType.equals(classOf[A].getName)) + } + }) + + Assert.assertEquals(2, fieldLoadCount) + } + + @Test + def innerFieldStoreTest(): Unit = { + val opalSetup = new OpalSetup() + opalSetup.setupOpal(classOf[FieldTarget].getName) + + val signature = new MethodSignature(classOf[FieldTarget].getName, "innerFieldStore", "Void") + val method = opalSetup.resolveMethod(signature) + val opalMethod = OpalMethod(method) + + var fieldStoreCount = 0 + opalMethod.getStatements.forEach(stmt => { + if (stmt.isFieldStore) { + fieldStoreCount += 1 + + val fieldStore = stmt.getFieldStore + Assert.assertTrue(fieldStore.getX.getType.toString.equals(classOf[FieldClass.InnerFieldClass].getName)) + + val fieldType = fieldStore.getY.getType.toString + Assert.assertFalse(fieldStore.getY.isPredefinedField) + Assert.assertTrue(fieldStore.getY.isInnerClassField) + Assert.assertTrue(fieldType.equals("int") || fieldType.equals(classOf[A].getName)) + } + }) + + Assert.assertEquals(2, fieldStoreCount) + } +} diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalScopeTest.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalLocalTest.scala similarity index 82% rename from boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalScopeTest.scala rename to boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalLocalTest.scala index 77dd481d9..7b4cc115b 100644 --- a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalScopeTest.scala +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalLocalTest.scala @@ -2,19 +2,19 @@ package boomerang.scope.opal import boomerang.scope.Statement import boomerang.scope.opal.tac.OpalMethod -import boomerang.scope.test.targets.{A, HashCodeEqualsLocalTarget, ParameterLocalsTarget, ThisLocalTarget} -import boomerang.scope.test.{BoomerangScopeTests, MethodSignature} +import boomerang.scope.test.targets.{A, HashCodeEqualsLocalTarget, LocalCountTarget, ParameterLocalsTarget, ThisLocalTarget} +import boomerang.scope.test.MethodSignature import org.junit.{Assert, Test} import org.opalj.br.IntegerType import java.util -class OpalScopeTest extends BoomerangScopeTests { +class OpalLocalTest { private val integerType = IntegerType.toJVMTypeName @Test - override def thisLocalTest(): Unit = { + def thisLocalTest(): Unit = { val opalSetup = new OpalSetup() opalSetup.setupOpal(classOf[ThisLocalTarget].getName) @@ -42,7 +42,29 @@ class OpalScopeTest extends BoomerangScopeTests { } @Test - override def parameterLocalTest(): Unit = { + def localCountTest(): Unit = { + val opalSetup = new OpalSetup() + opalSetup.setupOpal(classOf[LocalCountTarget].getName) + + // Virtual + val virtualSignature = new MethodSignature(classOf[LocalCountTarget].getName, "virtualLocalCount", "Void", util.List.of(integerType, s"L${classOf[A].getName}L")) + val virtualMethod = opalSetup.resolveMethod(virtualSignature) + val virtualOpalMethod = OpalMethod(virtualMethod) + + val locals = virtualOpalMethod.getLocals + Assert.assertEquals(5, locals.size()) + + // Static + val staticSignature = new MethodSignature(classOf[LocalCountTarget].getName, "staticLocalCount", "Void", util.List.of(integerType, s"L${classOf[A].getName}L")) + val staticMethod = opalSetup.resolveMethod(staticSignature) + val staticOpalMethod = OpalMethod(staticMethod) + + val locals2 = staticOpalMethod.getLocals + Assert.assertEquals(4, locals2.size()) + } + + @Test + def parameterLocalTest(): Unit = { val opalSetup = new OpalSetup() opalSetup.setupOpal(classOf[ParameterLocalsTarget].getName) @@ -72,7 +94,7 @@ class OpalScopeTest extends BoomerangScopeTests { } @Test - override def hashCodeEqualsLocalTest(): Unit = { + def hashCodeEqualsLocalTest(): Unit = { val opalSetup = new OpalSetup() opalSetup.setupOpal(classOf[HashCodeEqualsLocalTarget].getName) diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalStatementTest.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalStatementTest.scala new file mode 100644 index 000000000..0e23d5a5b --- /dev/null +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalStatementTest.scala @@ -0,0 +1,28 @@ +package boomerang.scope.opal + +import boomerang.scope.opal.tac.OpalMethod +import boomerang.scope.test.MethodSignature +import boomerang.scope.test.targets.ControlFlowGraphTarget +import org.junit.{Assert, Test} +import org.opalj.br.IntegerType + +class OpalStatementTest { + + private val integerType = IntegerType.toJVMTypeName + + @Test + def controlFlowGraphTest(): Unit = { + val opalSetup = new OpalSetup() + opalSetup.setupOpal(classOf[ControlFlowGraphTarget].getName) + + val signature = new MethodSignature(classOf[ControlFlowGraphTarget].getName, "compute", integerType) + val method = opalSetup.resolveMethod(signature) + val opalMethod = OpalMethod(method) + + val cfg = opalMethod.getControlFlowGraph + Assert.assertTrue(cfg.getStatements.size() > 0) + Assert.assertEquals(1, cfg.getStartPoints.size()) + Assert.assertEquals(2, cfg.getEndPoints.size()) + } + +} diff --git a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleField.java b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleField.java index 711b184c7..2517e31b3 100644 --- a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleField.java +++ b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleField.java @@ -12,6 +12,7 @@ package boomerang.scope.soot.jimple; import boomerang.scope.Field; +import boomerang.scope.Type; import java.util.Objects; import soot.SootField; @@ -23,11 +24,21 @@ public JimpleField(SootField delegate) { this.delegate = delegate; } + @Override + public boolean isPredefinedField() { + return false; + } + @Override public boolean isInnerClassField() { return this.delegate.getName().contains("$"); } + @Override + public Type getType() { + return new JimpleType(delegate.getType()); + } + public SootField getDelegate() { return this.delegate; } diff --git a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleStaticFieldVal.java b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleStaticFieldVal.java index eac1de123..5aa14675d 100644 --- a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleStaticFieldVal.java +++ b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleStaticFieldVal.java @@ -14,7 +14,6 @@ import boomerang.scope.ControlFlowGraph; import boomerang.scope.Field; import boomerang.scope.Method; -import boomerang.scope.Pair; import boomerang.scope.StaticFieldVal; import boomerang.scope.Type; import boomerang.scope.Val; @@ -33,11 +32,6 @@ private JimpleStaticFieldVal(JimpleField field, Method m, ControlFlowGraph.Edge this.field = field; } - @Override - public boolean isStatic() { - return true; - } - public Field field() { return field; } @@ -52,131 +46,11 @@ public Type getType() { return new JimpleType(field.getDelegate().getType()); } - @Override - public boolean isNewExpr() { - return false; - } - - @Override - public Type getNewExprType() { - throw new RuntimeException("Fault!"); - } - - @Override - public boolean isLocal() { - return false; - } - - @Override - public boolean isArrayAllocationVal() { - return false; - } - - @Override - public Val getArrayAllocationSize() { - throw new RuntimeException("Static Val is not an array allocation val"); - } - - @Override - public boolean isNull() { - return false; - } - - @Override - public boolean isStringConstant() { - return false; - } - - @Override - public String getStringValue() { - throw new RuntimeException("Fault!"); - } - - @Override - public boolean isStringBufferOrBuilder() { - return false; - } - - @Override - public boolean isThrowableAllocationType() { - return false; - } - - @Override - public boolean isCast() { - return false; - } - - @Override - public Val getCastOp() { - throw new RuntimeException("Fault!"); - } - - @Override - public boolean isArrayRef() { - return false; - } - - @Override - public boolean isInstanceOfExpr() { - return false; - } - - @Override - public Val getInstanceOfOp() { - throw new RuntimeException("Fault!"); - } - - @Override - public boolean isLengthExpr() { - return false; - } - - @Override - public Val getLengthOp() { - throw new RuntimeException("Fault!"); - } - - @Override - public boolean isIntConstant() { - return false; - } - - @Override - public boolean isClassConstant() { - return false; - } - - @Override - public Type getClassConstantType() { - throw new RuntimeException("Fault!"); - } - @Override public Val withNewMethod(Method callee) { return new JimpleStaticFieldVal(field, callee); } - @Override - public boolean isLongConstant() { - return false; - } - - @Override - public int getIntValue() { - return -1; - } - - @Override - public long getLongValue() { - return -1; - } - - @Override - public Pair getArrayBase() { - return null; - } - @Override public String getVariableName() { return toString(); diff --git a/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpField.java b/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpField.java index 6331dbcdf..5f2f3ecc6 100644 --- a/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpField.java +++ b/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpField.java @@ -12,6 +12,7 @@ package boomerang.scope.sootup.jimple; import boomerang.scope.Field; +import boomerang.scope.Type; import java.util.Arrays; import sootup.java.core.JavaSootField; @@ -27,11 +28,21 @@ public JavaSootField getDelegate() { return delegate; } + @Override + public boolean isPredefinedField() { + return false; + } + @Override public boolean isInnerClassField() { return delegate.getName().contains("$"); } + @Override + public Type getType() { + return new JimpleUpType(delegate.getType()); + } + @Override public int hashCode() { return Arrays.hashCode(new Object[] {delegate}); diff --git a/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALAField.java b/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALAField.java index 4d43e5a60..cb25f92ac 100644 --- a/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALAField.java +++ b/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALAField.java @@ -12,6 +12,7 @@ package boomerang.scope.wala; import boomerang.scope.Field; +import boomerang.scope.Type; import com.ibm.wala.types.FieldReference; public class WALAField extends Field { @@ -46,8 +47,18 @@ public String toString() { return fieldRef.toString(); } + @Override + public boolean isPredefinedField() { + return false; + } + @Override public boolean isInnerClassField() { throw new RuntimeException("Not yet implemented"); } + + @Override + public Type getType() { + throw new RuntimeException("Not yet implemented"); + } } diff --git a/boomerangScope/src/main/java/boomerang/scope/Field.java b/boomerangScope/src/main/java/boomerang/scope/Field.java index cb1ddb8ec..413171cfb 100644 --- a/boomerangScope/src/main/java/boomerang/scope/Field.java +++ b/boomerangScope/src/main/java/boomerang/scope/Field.java @@ -170,7 +170,15 @@ public boolean accepts(Location other) { return this.equals(other); } + public boolean isPredefinedField() { + return true; + } + public boolean isInnerClassField() { return false; } + + public Type getType() { + return null; + } } diff --git a/boomerangScope/src/main/java/boomerang/scope/StaticFieldVal.java b/boomerangScope/src/main/java/boomerang/scope/StaticFieldVal.java index ad16c888e..f5405c58a 100644 --- a/boomerangScope/src/main/java/boomerang/scope/StaticFieldVal.java +++ b/boomerangScope/src/main/java/boomerang/scope/StaticFieldVal.java @@ -26,4 +26,129 @@ protected StaticFieldVal(Method m, Edge unbalanced) { public abstract Field field(); public abstract Val asUnbalanced(Edge stmt); + + @Override + public boolean isStatic() { + return true; + } + + @Override + public boolean isNewExpr() { + return false; + } + + @Override + public Type getNewExprType() { + throw new RuntimeException("Static field val is not a new expression"); + } + + @Override + public boolean isLocal() { + return false; + } + + @Override + public boolean isArrayAllocationVal() { + return false; + } + + @Override + public Val getArrayAllocationSize() { + throw new RuntimeException("Static field val is not an array allocation val"); + } + + @Override + public boolean isNull() { + return false; + } + + @Override + public boolean isStringConstant() { + return false; + } + + @Override + public String getStringValue() { + throw new RuntimeException("Static field val is not a String constant"); + } + + @Override + public boolean isStringBufferOrBuilder() { + return false; + } + + @Override + public boolean isThrowableAllocationType() { + return false; + } + + @Override + public boolean isCast() { + return false; + } + + @Override + public Val getCastOp() { + throw new RuntimeException("Static field val is not a cast expression"); + } + + @Override + public boolean isArrayRef() { + return false; + } + + @Override + public boolean isInstanceOfExpr() { + return false; + } + + @Override + public Val getInstanceOfOp() { + throw new RuntimeException("Static field val is not an instance of expression"); + } + + @Override + public boolean isLengthExpr() { + return false; + } + + @Override + public Val getLengthOp() { + throw new RuntimeException("Static field val is not a length expression"); + } + + @Override + public boolean isIntConstant() { + return false; + } + + @Override + public boolean isClassConstant() { + return false; + } + + @Override + public Type getClassConstantType() { + throw new RuntimeException("Static field val is not a class constant"); + } + + @Override + public boolean isLongConstant() { + return false; + } + + @Override + public int getIntValue() { + throw new RuntimeException("Static field val is not an int constant"); + } + + @Override + public long getLongValue() { + throw new RuntimeException("Static field val is not a long constant"); + } + + @Override + public Pair getArrayBase() { + throw new RuntimeException("Static field val has no array base"); + } } diff --git a/boomerangScope/src/test/java/boomerang/scope/test/targets/ControlFlowGraphTarget.java b/boomerangScope/src/test/java/boomerang/scope/test/targets/ControlFlowGraphTarget.java new file mode 100644 index 000000000..ee89368c9 --- /dev/null +++ b/boomerangScope/src/test/java/boomerang/scope/test/targets/ControlFlowGraphTarget.java @@ -0,0 +1,30 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ +package boomerang.scope.test.targets; + +public class ControlFlowGraphTarget { + + public static void main(String[] args) { + ControlFlowGraphTarget target = new ControlFlowGraphTarget(); + int i = target.compute(); + + System.out.println(i); + } + + public int compute() { + if (Math.random() > 0.5) { + return 1; + } else { + return -1; + } + } +} diff --git a/boomerangScope/src/test/java/boomerang/scope/test/targets/FieldClass.java b/boomerangScope/src/test/java/boomerang/scope/test/targets/FieldClass.java new file mode 100644 index 000000000..ae6902870 --- /dev/null +++ b/boomerangScope/src/test/java/boomerang/scope/test/targets/FieldClass.java @@ -0,0 +1,37 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ +package boomerang.scope.test.targets; + +public class FieldClass { + + public int i; + public A a; + + public static int si = 20; + public static A sa = new A(); + + public FieldClass() { + i = 10; + a = new A(); + } + + public static class InnerFieldClass { + + public int innerI; + public A innerA; + + public InnerFieldClass() { + innerI = 30; + innerA = new A(); + } + } +} diff --git a/boomerangScope/src/test/java/boomerang/scope/test/targets/FieldTarget.java b/boomerangScope/src/test/java/boomerang/scope/test/targets/FieldTarget.java new file mode 100644 index 000000000..c4620da13 --- /dev/null +++ b/boomerangScope/src/test/java/boomerang/scope/test/targets/FieldTarget.java @@ -0,0 +1,70 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ +package boomerang.scope.test.targets; + +public class FieldTarget { + + public static void main(String[] args) { + fieldLoad(); + fieldStore(); + + staticFieldLoad(); + staticFieldStore(); + + innerFieldLoad(); + innerFieldStore(); + } + + public static void fieldLoad() { + FieldClass fieldClass = new FieldClass(); + int i = fieldClass.i; + A a = fieldClass.a; + + System.out.println(i + " " + a); + } + + public static void fieldStore() { + FieldClass fieldClass = new FieldClass(); + fieldClass.i = 100; + fieldClass.a = new A(); + + System.out.println(fieldClass); + } + + public static void staticFieldLoad() { + int i = FieldClass.si; + A a = FieldClass.sa; + + a.methodCall(i); + } + + public static void staticFieldStore() { + FieldClass.si = 200; + FieldClass.sa = new A(); + } + + public static void innerFieldLoad() { + FieldClass.InnerFieldClass inner = new FieldClass.InnerFieldClass(); + int i = inner.innerI; + A a = inner.innerA; + + System.out.println(i + " " + a); + } + + public static void innerFieldStore() { + FieldClass.InnerFieldClass inner = new FieldClass.InnerFieldClass(); + inner.innerI = 300; + inner.innerA = new A(); + + System.out.println(inner); + } +} diff --git a/boomerangScope/src/test/java/boomerang/scope/test/targets/LocalCountTarget.java b/boomerangScope/src/test/java/boomerang/scope/test/targets/LocalCountTarget.java new file mode 100644 index 000000000..46d0082c7 --- /dev/null +++ b/boomerangScope/src/test/java/boomerang/scope/test/targets/LocalCountTarget.java @@ -0,0 +1,47 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ +package boomerang.scope.test.targets; + +public class LocalCountTarget { + + public static void main(String[] args) { + LocalCountTarget target = new LocalCountTarget(); + target.virtualLocalCount(10, new A()); + staticLocalCount(10, new A()); + } + + /** + * Virtual method with (at least) 5 locals (2 parameter + 2 defined + 'this' local) + * + * @param i primitive parameter + * @param a ref parameter + */ + public void virtualLocalCount(int i, A a) { + int i2 = 10; + a.methodCall(i2); + A b = new A(); + b.methodCall(i); + } + + /** + * Static method with (at least) 4 locals (2 parameter + 2 defined locals) + * + * @param i primitive parameter + * @param a ref parameter + */ + public static void staticLocalCount(int i, A a) { + int i2 = 10; + a.methodCall(i2); + A b = new A(); + b.methodCall(i); + } +} From 53e138e1151a3e385e095a101aceaa7c43f6eae9 Mon Sep 17 00:00:00 2001 From: Sven Meyer Date: Thu, 20 Mar 2025 09:42:27 +0100 Subject: [PATCH 19/61] Fix array handling --- .../scope/opal/OpalFrameworkScope.scala | 4 +- .../scope/opal/tac/OpalArrayRef.scala | 9 ++- .../boomerang/scope/opal/tac/OpalMethod.scala | 2 +- .../scope/opal/tac/OpalStatement.scala | 30 +++---- .../boomerang/scope/opal/tac/OpalVal.scala | 4 +- .../boomerang/scope/opal/OpalArrayTest.scala | 69 ++++++++++++++++ .../scope/opal/OpalAssignmentTest.scala | 81 +++++++++++++++++++ ...t.scala => OpalControlFlowGraphTest.scala} | 2 +- .../boomerang/scope/soot/SootArrayTest.java | 42 ++++++++++ .../boomerang/scope/soot/SootScopeTest.java | 5 +- .../scope/test/targets/ArrayTarget.java | 33 ++++++++ .../scope/test/targets/AssignmentTarget.java | 25 ++++++ .../main/java/test/setup/OpalTestSetup.java | 11 +++ 13 files changed, 287 insertions(+), 30 deletions(-) create mode 100644 boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalArrayTest.scala create mode 100644 boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalAssignmentTest.scala rename boomerangScope-Opal/src/test/scala/boomerang/scope/opal/{OpalStatementTest.scala => OpalControlFlowGraphTest.scala} (96%) create mode 100644 boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootArrayTest.java create mode 100644 boomerangScope/src/test/java/boomerang/scope/test/targets/ArrayTarget.java create mode 100644 boomerangScope/src/test/java/boomerang/scope/test/targets/AssignmentTarget.java diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalFrameworkScope.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalFrameworkScope.scala index a048ed5e5..afffa6c4d 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalFrameworkScope.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalFrameworkScope.scala @@ -1,14 +1,16 @@ package boomerang.scope.opal import boomerang.scope.{CallGraph, DataFlowScope, Field, FrameworkScope, Method, StaticFieldVal, Val} +import org.opalj.ai.domain import org.opalj.br.analyses.Project +import org.opalj.tac.ComputeTACAIKey import java.util.stream class OpalFrameworkScope(project: Project[_], callGraph: org.opalj.tac.cg.CallGraph, entryPoints: Set[org.opalj.br.Method], dataFlowScope: DataFlowScope) extends FrameworkScope { OpalClient.init(project) - val opalCallGraph = new OpalCallGraph(callGraph, entryPoints) + private val opalCallGraph = new OpalCallGraph(callGraph, entryPoints) override def getCallGraph: CallGraph = opalCallGraph diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalArrayRef.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalArrayRef.scala index 7c5a07a7c..5c5cb33ee 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalArrayRef.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalArrayRef.scala @@ -5,6 +5,8 @@ import org.opalj.br.ObjectType import org.opalj.tac.{DUVar, DVar, Expr, UVar} import org.opalj.value.ValueInformation +import java.util.Objects + class OpalArrayRef(val arrayRef: Expr[DUVar[ValueInformation]], val index: Int, method: OpalMethod, unbalanced: ControlFlowGraph.Edge = null) extends Val(method, unbalanced) { if (!arrayRef.isVar) { @@ -80,9 +82,12 @@ class OpalArrayRef(val arrayRef: Expr[DUVar[ValueInformation]], val index: Int, } } - override def hashCode(): Int = ??? + override def hashCode: Int = Objects.hash(super.hashCode(), arrayRef, index) - override def equals(obj: Any): Boolean = ??? + override def equals(other: Any): Boolean = other match { + case that: OpalArrayRef => super.equals(that) && this.arrayRef == that.arrayRef && this.index == that.index + case _ => false + } override def toString: String = getVariableName } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalMethod.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalMethod.scala index 1e4d8e1f5..36ad6eee7 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalMethod.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalMethod.scala @@ -2,7 +2,7 @@ package boomerang.scope.opal.tac import boomerang.scope._ import boomerang.scope.opal.OpalClient -import org.opalj.tac.{InstanceFunctionCall, InstanceMethodCall} +import org.opalj.tac.{InstanceFunctionCall, InstanceMethodCall, Stmt} import java.util diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala index acbffae88..a85f1bd5e 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala @@ -1,12 +1,12 @@ package boomerang.scope.opal.tac -import boomerang.scope.opal.OpalClient import boomerang.scope._ import com.google.common.base.Joiner import org.opalj.tac.{DUVar, PrimitiveTypecastExpr, Stmt} import org.opalj.value.ValueInformation import java.util +import java.util.Objects class OpalStatement(val delegate: Stmt[DUVar[ValueInformation]], m: OpalMethod) extends Statement(m) { @@ -48,8 +48,6 @@ class OpalStatement(val delegate: Stmt[DUVar[ValueInformation]], m: OpalMethod) if (isArrayStore) { // TODO val arrayStore = delegate.asArrayStore - //val resolvedField = OpalClient.resolveFieldStore(delegate.asArrayStore) - //return new OpalField(resolvedField.get) } throw new RuntimeException("Statement is not a field store operation") @@ -145,7 +143,8 @@ class OpalStatement(val delegate: Stmt[DUVar[ValueInformation]], m: OpalMethod) if (isArrayStore) { // TODO Distinguish between constant and variable - return new OpalVal(delegate.asArrayStore.value, m) + val arrayStore = delegate.asArrayStore + return new OpalLocal(arrayStore.arrayRef, m) } } @@ -208,13 +207,7 @@ class OpalStatement(val delegate: Stmt[DUVar[ValueInformation]], m: OpalMethod) override def isArrayStore: Boolean = delegate.isArrayStore - override def isArrayLoad: Boolean = { - if (delegate.isAssignment) { - delegate.asAssignment.expr.isArrayLoad - } - - false - } + override def isArrayLoad: Boolean = delegate.isAssignment && delegate.asAssignment.expr.isArrayLoad override def isFieldLoad: Boolean = delegate.isAssignment && delegate.asAssignment.expr.isGetField @@ -296,7 +289,7 @@ class OpalStatement(val delegate: Stmt[DUVar[ValueInformation]], m: OpalMethod) override def isCatchStmt: Boolean = delegate.isCaughtException - override def hashCode(): Int = 31 + delegate.hashCode() + override def hashCode: Int = Objects.hash(delegate) private def canEqual(a: Any): Boolean = a.isInstanceOf[OpalStatement] @@ -321,17 +314,14 @@ class OpalStatement(val delegate: Stmt[DUVar[ValueInformation]], m: OpalMethod) if (isAssignStmt) { if (delegate.isAssignment) { - if (getRightOp.isNewExpr) { - return s"$getLeftOp = new ${getRightOp.getNewExprType}" + if (isFieldStore) { + return s"$getLeftOp = ${getFieldStore.getX}.${getFieldStore.getY}" + } else if (isArrayStore) { + val base = getArrayBase + return s"${base.getX.getVariableName}[${base.getY}] = $getRightOp" } else { - // TODO Array load return s"$getLeftOp = $getRightOp" } - } else if (isFieldStore) { - return s"$getLeftOp = $getWrittenField" - } else if (isArrayStore) { - val base = getArrayBase - return s"${base.getX.getVariableName}[${base.getY}] = $getRightOp" } } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalVal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalVal.scala index cd6fd3512..1c043b021 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalVal.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalVal.scala @@ -15,6 +15,7 @@ class OpalVal(val delegate: Expr[DUVar[ValueInformation]], method: OpalMethod, u override def getType: Type = delegate match { case const: Const => OpalType(const.tpe) case newExpr: New => OpalType(newExpr.tpe) + case newArrayExpr: NewArray[_] => OpalType(newArrayExpr.tpe) case functionCall: FunctionCall[_] => OpalType(functionCall.descriptor.returnType) case _ => throw new RuntimeException("Type not implemented yet") } @@ -41,7 +42,7 @@ class OpalVal(val delegate: Expr[DUVar[ValueInformation]], method: OpalMethod, u // TODO Deal with multiple arrays override def getArrayAllocationSize: Val = { if (isArrayAllocationVal) { - return new OpalVal(delegate.asNewArray.counts.head, method) + return new OpalLocal(delegate.asNewArray.counts.head, method) } throw new RuntimeException("Value is not an array allocation expression") @@ -150,6 +151,7 @@ class OpalVal(val delegate: Expr[DUVar[ValueInformation]], method: OpalMethod, u case intConst: IntConst => intConst.value.toString case longConst: LongConst => longConst.value.toString case newExpr: New => s"new ${newExpr.tpe.toJava}" + case newArrayExpr: NewArray[_] => s"new ${newArrayExpr.tpe.toJava}" case _ => delegate.toString } } diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalArrayTest.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalArrayTest.scala new file mode 100644 index 000000000..b4e0c6499 --- /dev/null +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalArrayTest.scala @@ -0,0 +1,69 @@ +package boomerang.scope.opal + +import boomerang.scope.opal.tac.OpalMethod +import boomerang.scope.test.MethodSignature +import boomerang.scope.test.targets.ArrayTarget +import org.junit.{Assert, Test} +import org.opalj.br.IntegerType + +import java.util + +class OpalArrayTest { + + private val integerType = IntegerType.toJVMTypeName + + @Test + def singleArrayLoadTest(): Unit = { + val opalSetup = new OpalSetup() + opalSetup.setupOpal(classOf[ArrayTarget].getName) + + val signature = new MethodSignature(classOf[ArrayTarget].getName, "singleArrayLoad", "Void", util.List.of("[" + integerType)) + val method = opalSetup.resolveMethod(signature) + val opalMethod = OpalMethod(method) + + var arrayLoadCount = 0 + opalMethod.getStatements.forEach(stmt => { + if (stmt.isArrayLoad) { + arrayLoadCount += 1 + + val arrayBase = stmt.getArrayBase + Assert.assertFalse(arrayBase.getX.isArrayRef) + Assert.assertTrue(arrayBase.getX.isLocal) + Assert.assertEquals(1, arrayBase.getY) + + val rightOp = stmt.getRightOp + Assert.assertTrue(rightOp.isArrayRef) + } + }) + + Assert.assertEquals(1, arrayLoadCount) + } + + @Test + def singleArrayWriteTest(): Unit = { + val opalSetup = new OpalSetup() + opalSetup.setupOpal(classOf[ArrayTarget].getName) + + val signature = new MethodSignature(classOf[ArrayTarget].getName, "singleArrayStore", "Void") + val method = opalSetup.resolveMethod(signature) + val opalMethod = OpalMethod(method) + + var arrayStoreCount = 0 + opalMethod.getStatements.forEach(stmt => { + if (stmt.isArrayStore) { + arrayStoreCount += 1 + + val arrayBase = stmt.getArrayBase + Assert.assertFalse(arrayBase.getX.isArrayRef) + Assert.assertTrue(arrayBase.getX.isLocal) + Assert.assertEquals(0, arrayBase.getY) + + val leftOp = stmt.getLeftOp + Assert.assertTrue(leftOp.isArrayRef) + } + }) + + Assert.assertEquals(1, arrayStoreCount) + } + +} diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalAssignmentTest.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalAssignmentTest.scala new file mode 100644 index 000000000..e7af00a19 --- /dev/null +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalAssignmentTest.scala @@ -0,0 +1,81 @@ +package boomerang.scope.opal + +import boomerang.scope.opal.tac.OpalMethod +import boomerang.scope.test.MethodSignature +import boomerang.scope.test.targets.AssignmentTarget +import org.junit.{Assert, Test} + +class OpalAssignmentTest { + + @Test + def arrayAllocationTest(): Unit = { + val opalSetup = new OpalSetup() + opalSetup.setupOpal(classOf[AssignmentTarget].getName) + + val signature = new MethodSignature(classOf[AssignmentTarget].getName, "arrayAllocation", "Void") + val method = opalSetup.resolveMethod(signature) + val opalMethod = OpalMethod(method) + + var arrayAllocationCount = 0 + opalMethod.getStatements.forEach(stmt => { + if (stmt.isAssignStmt) { + val rightOp = stmt.getRightOp + + if (rightOp.isArrayAllocationVal) { + arrayAllocationCount += 1 + + val leftOp = stmt.getLeftOp + Assert.assertTrue(leftOp.isLocal) + + Assert.assertTrue(rightOp.getArrayAllocationSize.isLocal) + Assert.assertTrue(rightOp.getType.isArrayType) + } + } + }) + + Assert.assertEquals(1, arrayAllocationCount) + } + + @Test + def constantAssignmentTest(): Unit = { + val opalSetup = new OpalSetup() + opalSetup.setupOpal(classOf[AssignmentTarget].getName) + + val signature = new MethodSignature(classOf[AssignmentTarget].getName, "constantAssignment", "Void") + val method = opalSetup.resolveMethod(signature) + val opalMethod = OpalMethod(method) + + var constantCount = 0 + opalMethod.getStatements.forEach(stmt => { + if (stmt.isAssignStmt) { + val leftOp = stmt.getLeftOp + val rightOp = stmt.getRightOp + + Assert.assertTrue(leftOp.isLocal) + + if (rightOp.isIntConstant) { + constantCount += 1 + + Assert.assertEquals(10, rightOp.getIntValue) + Assert.assertTrue(rightOp.getType.toString.equals("int")) + } + + if (rightOp.isLongConstant) { + constantCount += 1 + + Assert.assertEquals(1000, rightOp.getLongValue) + Assert.assertTrue(rightOp.getType.toString.equals("long")) + } + + if (rightOp.isStringConstant) { + constantCount += 1 + + Assert.assertTrue(rightOp.getStringValue.equals("test")) + Assert.assertTrue(rightOp.getType.toString.equals("java.lang.String")) + } + } + }) + + Assert.assertEquals(3, constantCount) + } +} diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalStatementTest.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalControlFlowGraphTest.scala similarity index 96% rename from boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalStatementTest.scala rename to boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalControlFlowGraphTest.scala index 0e23d5a5b..8e2b11082 100644 --- a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalStatementTest.scala +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalControlFlowGraphTest.scala @@ -6,7 +6,7 @@ import boomerang.scope.test.targets.ControlFlowGraphTarget import org.junit.{Assert, Test} import org.opalj.br.IntegerType -class OpalStatementTest { +class OpalControlFlowGraphTest { private val integerType = IntegerType.toJVMTypeName diff --git a/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootArrayTest.java b/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootArrayTest.java new file mode 100644 index 000000000..17a0359c9 --- /dev/null +++ b/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootArrayTest.java @@ -0,0 +1,42 @@ +package boomerang.scope.soot; + +import boomerang.scope.Method; +import boomerang.scope.Pair; +import boomerang.scope.Statement; +import boomerang.scope.Val; +import boomerang.scope.soot.jimple.JimpleMethod; +import boomerang.scope.test.MethodSignature; +import boomerang.scope.test.targets.ArrayTarget; +import org.junit.Assert; +import org.junit.Test; +import soot.SootMethod; + +public class SootArrayTest { + + @Test + public void singleArrayStoreConstantTest() { + SootSetup sootSetup = new SootSetup(); + sootSetup.setupSoot(ArrayTarget.class.getName()); + + MethodSignature signature = new MethodSignature(ArrayTarget.class.getName(), "singleArrayStore"); + SootMethod method = sootSetup.resolveMethod(signature); + Method jimpleMethod = JimpleMethod.of(method); + + int arrayStoreCount = 0; + for (Statement stmt : jimpleMethod.getStatements()) { + if (stmt.isArrayStore()) { + arrayStoreCount++; + + Pair arrayBase = stmt.getArrayBase(); + Assert.assertFalse(arrayBase.getX().isArrayRef()); + Assert.assertTrue(arrayBase.getX().isLocal()); + Assert.assertEquals(0, arrayBase.getY().intValue()); + + Val leftOp = stmt.getLeftOp(); + Assert.assertTrue(leftOp.isArrayRef()); + } + } + + Assert.assertEquals(1, arrayStoreCount); + } +} diff --git a/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootScopeTest.java b/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootScopeTest.java index f2dfa3348..2ddeaba30 100644 --- a/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootScopeTest.java +++ b/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootScopeTest.java @@ -27,10 +27,9 @@ import org.junit.Test; import soot.SootMethod; -public class SootScopeTest implements BoomerangScopeTests { +public class SootScopeTest { @Test - @Override public void thisLocalTest() { SootSetup sootSetup = new SootSetup(); sootSetup.setupSoot(ThisLocalTarget.class.getName()); @@ -60,7 +59,6 @@ public void thisLocalTest() { } @Test - @Override public void parameterLocalTest() { SootSetup sootSetup = new SootSetup(); sootSetup.setupSoot(ParameterLocalsTarget.class.getName()); @@ -97,7 +95,6 @@ public void parameterLocalTest() { } @Test - @Override public void hashCodeEqualsLocalTest() { SootSetup sootSetup = new SootSetup(); sootSetup.setupSoot(HashCodeEqualsLocalTarget.class.getName()); diff --git a/boomerangScope/src/test/java/boomerang/scope/test/targets/ArrayTarget.java b/boomerangScope/src/test/java/boomerang/scope/test/targets/ArrayTarget.java new file mode 100644 index 000000000..1e09b89ad --- /dev/null +++ b/boomerangScope/src/test/java/boomerang/scope/test/targets/ArrayTarget.java @@ -0,0 +1,33 @@ +package boomerang.scope.test.targets; + +import java.util.Arrays; + +public class ArrayTarget { + + public static void main(String[] args) { + singleArrayLoad(new int[]{1, 2}); + singleArrayStore(); + + multiArrayStore(); + } + + public static void singleArrayLoad(int[] arr) { + int i = arr[1]; + + System.out.println(i); + } + + public static void singleArrayStore() { + int[] arr = new int[2]; + arr[0] = 1; + + System.out.println(Arrays.toString(arr)); + } + + public static void multiArrayStore() { + int[][] arr = new int[2][2]; + arr[0][0] = 1; + + System.out.println(Arrays.deepToString(arr)); + } +} diff --git a/boomerangScope/src/test/java/boomerang/scope/test/targets/AssignmentTarget.java b/boomerangScope/src/test/java/boomerang/scope/test/targets/AssignmentTarget.java new file mode 100644 index 000000000..23decc5fb --- /dev/null +++ b/boomerangScope/src/test/java/boomerang/scope/test/targets/AssignmentTarget.java @@ -0,0 +1,25 @@ +package boomerang.scope.test.targets; + +import java.util.Arrays; + +public class AssignmentTarget { + + public static void main(String[] args) { + arrayAllocation(); + constantAssignment(); + } + + public static void arrayAllocation() { + int[] arr = new int[]{1, 2}; + + System.out.println(Arrays.toString(arr)); + } + + public static void constantAssignment() { + int i = 10; + long l = 1000; + String s = "test"; + + System.out.println(i + l + " " + s); + } +} diff --git a/testCore/src/main/java/test/setup/OpalTestSetup.java b/testCore/src/main/java/test/setup/OpalTestSetup.java index 03d2a9098..6e7ccab45 100644 --- a/testCore/src/main/java/test/setup/OpalTestSetup.java +++ b/testCore/src/main/java/test/setup/OpalTestSetup.java @@ -20,6 +20,14 @@ import java.net.URL; import java.util.List; import java.util.Set; + +import org.opalj.ai.AIResult; +import org.opalj.ai.AIResultBuilder; +import org.opalj.ai.BaseAI; +import org.opalj.ai.BaseAI$; +import org.opalj.ai.domain.l0.PrimitiveTACAIDomain; +import org.opalj.ai.fpcf.properties.AIDomainFactoryKey; +import org.opalj.ai.fpcf.properties.AIDomainFactoryKey$; import org.opalj.br.ClassFile; import org.opalj.br.MethodDescriptor$; import org.opalj.br.ObjectType; @@ -27,6 +35,9 @@ import org.opalj.log.DevNullLogger$; import org.opalj.log.GlobalLogContext$; import org.opalj.log.OPALLogger; +import org.opalj.tac.ComputeTACAIKey; +import org.opalj.tac.LazyDetachedTACAIKey; +import org.opalj.tac.TACAI; import org.opalj.tac.cg.CHACallGraphKey$; import org.opalj.tac.cg.CallGraph; import scala.Option; From 4b62f6ee4429d1184441a81898e010bc2e0cd8af Mon Sep 17 00:00:00 2001 From: Sven Meyer Date: Fri, 21 Mar 2025 12:30:36 +0100 Subject: [PATCH 20/61] WIP: Prepare for TacTransformer --- .../boomerang/scope/opal/OpalCallGraph.scala | 6 +- .../boomerang/scope/opal/OpalClient.scala | 10 +- .../scope/opal/tac/OpalArrayRef.scala | 6 +- .../scope/opal/tac/OpalControlFlowGraph.scala | 82 +++++++------- .../scope/opal/tac/OpalDeclaredMethod.scala | 4 +- .../scope/opal/tac/OpalDoubleVal.scala | 12 +-- .../scope/opal/tac/OpalIfStatement.scala | 13 ++- .../scope/opal/tac/OpalInvokeExpr.scala | 18 ++-- .../boomerang/scope/opal/tac/OpalLocal.scala | 95 ++--------------- .../boomerang/scope/opal/tac/OpalMethod.scala | 100 ++++++++++++++---- .../scope/opal/tac/OpalParameterLocal.scala | 82 -------------- .../scope/opal/tac/OpalStatement.scala | 50 +++++---- .../boomerang/scope/opal/tac/OpalVal.scala | 9 +- .../scope/opal/OpalControlFlowGraphTest.scala | 2 + .../scope/opal/OpalInvokeExprTest.scala | 78 ++++++++++++++ .../scope/test/targets/InvokeExprTarget.java | 26 +++++ .../test/targets/ParameterLocalsTarget.java | 4 +- .../main/java/test/setup/OpalTestSetup.java | 2 +- 18 files changed, 306 insertions(+), 293 deletions(-) delete mode 100644 boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalParameterLocal.scala create mode 100644 boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala create mode 100644 boomerangScope/src/test/java/boomerang/scope/test/targets/InvokeExprTarget.java diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalCallGraph.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalCallGraph.scala index effd4ed40..52828ee2c 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalCallGraph.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalCallGraph.scala @@ -4,6 +4,7 @@ import boomerang.scope.CallGraph import boomerang.scope.CallGraph.Edge import boomerang.scope.opal.tac.{OpalMethod, OpalPhantomMethod, OpalStatement} import org.opalj.br.{DefinedMethod, Method, MultipleDefinedMethods, VirtualDeclaredMethod} +import org.opalj.tac.TACNaive class OpalCallGraph(callGraph: org.opalj.tac.cg.CallGraph, entryPoints: Set[Method]) extends CallGraph { @@ -18,11 +19,10 @@ class OpalCallGraph(callGraph: org.opalj.tac.cg.CallGraph, entryPoints: Set[Meth }) private def addEdgesFromMethod(method: DefinedMethod): Unit = { - // TODO move TAC to parameters or use method wrappers with TAC - val tacCode = OpalClient.getTacForMethod(method.definedMethod) + val tacCode = TACNaive(method.definedMethod, OpalClient.getClassHierarchy) tacCode.stmts.foreach(stmt => { - val srcStatement = new OpalStatement(stmt, OpalMethod(method.definedMethod)) + val srcStatement = new OpalStatement(stmt, OpalMethod(method.definedMethod, tacCode)) if (srcStatement.containsInvokeExpr()) { val callees = callGraph.directCalleesOf(method, stmt.pc) diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalClient.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalClient.scala index 1609ebc2a..a5b1f0e29 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalClient.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalClient.scala @@ -2,19 +2,13 @@ package boomerang.scope.opal import org.opalj.br.{ClassFile, ClassHierarchy, DefinedMethod, Field, Method, MethodDescriptor, ObjectType, ReferenceType} import org.opalj.br.analyses.{DeclaredMethods, DeclaredMethodsKey, Project} -import org.opalj.tac.{AITACode, ComputeTACAIKey, FieldRead, FieldWriteAccessStmt, TACMethodParameter} -import org.opalj.value.ValueInformation object OpalClient { - private var project: Option[Project[_]] = None - private var declaredMethods: Option[DeclaredMethods] = None - private var tacCodes: Option[Method => AITACode[TACMethodParameter, ValueInformation]] = None + var project: Option[Project[_]] = None def init(p: Project[_]): Unit = { project = Some(p) - declaredMethods = Some(p.get(DeclaredMethodsKey)) - tacCodes = Some(p.get(ComputeTACAIKey)) } def getClassHierarchy: ClassHierarchy = project.get.classHierarchy @@ -23,6 +17,4 @@ object OpalClient { def isApplicationClass(classFile: ClassFile): Boolean = project.get.allProjectClassFiles.toSet.contains(classFile) - def getTacForMethod(method: Method): AITACode[TACMethodParameter, ValueInformation] = tacCodes.get(method) - } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalArrayRef.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalArrayRef.scala index 5c5cb33ee..bca3ee83f 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalArrayRef.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalArrayRef.scala @@ -2,12 +2,12 @@ package boomerang.scope.opal.tac import boomerang.scope._ import org.opalj.br.ObjectType -import org.opalj.tac.{DUVar, DVar, Expr, UVar} +import org.opalj.tac.{DUVar, DVar, Expr, IdBasedVar, UVar, Var} import org.opalj.value.ValueInformation import java.util.Objects -class OpalArrayRef(val arrayRef: Expr[DUVar[ValueInformation]], val index: Int, method: OpalMethod, unbalanced: ControlFlowGraph.Edge = null) extends Val(method, unbalanced) { +class OpalArrayRef(val arrayRef: Expr[IdBasedVar], val index: Int, method: OpalMethod, unbalanced: ControlFlowGraph.Edge = null) extends Val(method, unbalanced) { if (!arrayRef.isVar) { throw new RuntimeException("Array Ref has to be a variable") @@ -69,7 +69,7 @@ class OpalArrayRef(val arrayRef: Expr[DUVar[ValueInformation]], val index: Int, override def getLongValue: Long = throw new RuntimeException("Array Value is not a long constant") override def getArrayBase: Pair[Val, Integer] = { - val base = new OpalLocal(arrayRef, method) + val base = new OpalLocal(arrayRef.asVar, method) new Pair[Val, Integer](base, index) } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalControlFlowGraph.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalControlFlowGraph.scala index f071dc4c8..3b765aa25 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalControlFlowGraph.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalControlFlowGraph.scala @@ -1,14 +1,11 @@ package boomerang.scope.opal.tac -import boomerang.scope.opal.OpalClient import boomerang.scope.{ControlFlowGraph, Statement} import com.google.common.collect.{HashMultimap, Multimap} -import org.opalj.br.Method -import org.opalj.br.cfg.CFGFactory import java.util -class OpalControlFlowGraph(method: Method) extends ControlFlowGraph { +class OpalControlFlowGraph(method: OpalMethod) extends ControlFlowGraph { private var cacheBuilt = false @@ -18,6 +15,12 @@ class OpalControlFlowGraph(method: Method) extends ControlFlowGraph { private val succsOfCache: Multimap[Statement, Statement] = HashMultimap.create() private val statements: util.List[Statement] = new util.ArrayList[Statement]() + def get(): OpalControlFlowGraph = { + buildCache() + + this + } + override def getStartPoints: util.Collection[Statement] = { buildCache() startPointCache @@ -46,41 +49,42 @@ class OpalControlFlowGraph(method: Method) extends ControlFlowGraph { private def buildCache(): Unit = { if (cacheBuilt) return - val opalMethod = OpalMethod(method) - val tac = OpalClient.getTacForMethod(method) - - tac.stmts.foreach(stmt => { - val statement = new OpalStatement(stmt, opalMethod) - statements.add(statement) - - val stmtPc = tac.pcToIndex(stmt.pc) - - val predecessors = tac.cfg.predecessors(stmtPc) - if (predecessors.isEmpty) { - // No predecessors => Head statement - val headStatement = new OpalStatement(stmt, opalMethod) - startPointCache.add(headStatement) - } else { - predecessors.foreach(predecessorPc => { - val predecessor = tac.stmts(predecessorPc) - val predecessorStatement = new OpalStatement(predecessor, opalMethod) - - predsOfCache.put(statement, predecessorStatement) - }) - } - - val successors = tac.cfg.successors(stmtPc) - if (successors.isEmpty) { - // No successors => Tail statement - val tailStmt = new OpalStatement(stmt, opalMethod) - endPointCache.add(tailStmt) - } else { - successors.foreach(successorPc => { - val successor = tac.stmts(successorPc) - val successorStatement = new OpalStatement(successor, opalMethod) - - succsOfCache.put(statement, successorStatement) - }) + var headFound = false + method.tacCode.stmts.foreach(stmt => { + // Definition of parameter locals have implicit PC of -1, so they are not part of the actual CFG + if (stmt.pc != -1) { + val statement = new OpalStatement(stmt, method) + statements.add(statement) + + val stmtPc = method.tacCode.pcToIndex(stmt.pc) + + // The first statement after the parameter local definitions is the head + if (!headFound) { + startPointCache.add(statement) + headFound = true + } else { + val predecessors = method.tacCode.cfg.predecessors(stmtPc) + predecessors.foreach(predecessorPc => { + val predecessor = method.tacCode.stmts(predecessorPc) + val predecessorStatement = new OpalStatement(predecessor, method) + + predsOfCache.put(statement, predecessorStatement) + }) + } + + val successors = method.tacCode.cfg.successors(stmtPc) + if (successors.isEmpty) { + // No successors => Tail statement + val tailStmt = new OpalStatement(stmt, method) + endPointCache.add(tailStmt) + } else { + successors.foreach(successorPc => { + val successor = method.tacCode.stmts(successorPc) + val successorStatement = new OpalStatement(successor, method) + + succsOfCache.put(statement, successorStatement) + }) + } } }) diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalDeclaredMethod.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalDeclaredMethod.scala index ee0329393..a99bc2756 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalDeclaredMethod.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalDeclaredMethod.scala @@ -3,12 +3,12 @@ package boomerang.scope.opal.tac import boomerang.scope.opal.{OpalClient, OpalFrameworkScope} import boomerang.scope.{DeclaredMethod, InvokeExpr, Type, WrappedClass} import org.opalj.br.MethodSignature -import org.opalj.tac.{Call, DUVar} +import org.opalj.tac.{Call, DUVar, Var} import org.opalj.value.ValueInformation import java.util -case class OpalDeclaredMethod(invokeExpr: InvokeExpr, delegate: Call[DUVar[ValueInformation]]) extends DeclaredMethod(invokeExpr) { +case class OpalDeclaredMethod[+V <: Var[V]](invokeExpr: InvokeExpr, delegate: Call[V]) extends DeclaredMethod(invokeExpr) { override def getSubSignature: String = MethodSignature(delegate.name, delegate.descriptor).toJava diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalDoubleVal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalDoubleVal.scala index bbe0995ad..c52e95bd5 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalDoubleVal.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalDoubleVal.scala @@ -1,18 +1,16 @@ package boomerang.scope.opal.tac import boomerang.scope.{Val, ValWithFalseVariable} -import org.opalj.tac.{DUVar, Expr} +import org.opalj.tac.{DUVar, Expr, IdBasedVar, Var} import org.opalj.value.ValueInformation -class OpalDoubleVal(delegate: Expr[DUVar[ValueInformation]], method: OpalMethod, falseVal: Val) extends OpalVal(delegate, method) with ValWithFalseVariable { +import java.util.Objects + +class OpalDoubleVal(delegate: Expr[IdBasedVar], method: OpalMethod, falseVal: Val) extends OpalVal(delegate, method) with ValWithFalseVariable { override def getFalseVariable: Val = falseVal - override def hashCode(): Int = { - var result = 31 + super.hashCode() - result = result * 31 + falseVal.hashCode() - result - } + override def hashCode: Int = Objects.hash(super.hashCode, falseVal) private def canEqual(a: Any): Boolean = a.isInstanceOf[OpalDoubleVal] diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalIfStatement.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalIfStatement.scala index f297e3037..1dffdcb64 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalIfStatement.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalIfStatement.scala @@ -2,16 +2,19 @@ package boomerang.scope.opal.tac import boomerang.scope.opal.OpalClient import boomerang.scope.{IfStatement, Statement, Val} -import org.opalj.tac.{DUVar, If} +import org.opalj.tac.{DUVar, IdBasedVar, If, Var} import org.opalj.value.ValueInformation -class OpalIfStatement(val delegate: If[DUVar[ValueInformation]], method: OpalMethod) extends IfStatement { +import java.util.Objects + +class OpalIfStatement(val delegate: If[IdBasedVar], method: OpalMethod) extends IfStatement { override def getTarget: Statement = { - val tac = OpalClient.getTacForMethod(method.delegate) + /*val tac = OpalClient.getTacForMethod(method.delegate) val target = delegate.targetStmt - new OpalStatement(tac.stmts(target), method) + new OpalStatement(tac.stmts(target), method)*/ + ??? } override def evaluate(otherVal: Val): IfStatement.Evaluation = IfStatement.Evaluation.UNKNOWN @@ -27,7 +30,7 @@ class OpalIfStatement(val delegate: If[DUVar[ValueInformation]], method: OpalMet otherVal.equals(left) || otherVal.equals(right) } - override def hashCode(): Int = 31 + delegate.hashCode() + override def hashCode: Int = Objects.hash(delegate) private def canEqual(a: Any): Boolean = a.isInstanceOf[OpalIfStatement] diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalInvokeExpr.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalInvokeExpr.scala index 60cbb4b1c..ee74a75ef 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalInvokeExpr.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalInvokeExpr.scala @@ -2,11 +2,11 @@ package boomerang.scope.opal.tac import boomerang.scope.{DeclaredMethod, InvokeExpr, Val} import org.opalj.tac._ -import org.opalj.value.ValueInformation import java.util +import java.util.Objects -class OpalMethodInvokeExpr(val delegate: MethodCall[DUVar[ValueInformation]], method: OpalMethod) extends InvokeExpr { +class OpalMethodInvokeExpr(val delegate: MethodCall[IdBasedVar], method: OpalMethod) extends InvokeExpr { override def getArg(index: Int): Val = getArgs.get(index) @@ -14,7 +14,7 @@ class OpalMethodInvokeExpr(val delegate: MethodCall[DUVar[ValueInformation]], me val result = new util.ArrayList[Val] delegate.params.foreach(param => { - result.add(new OpalLocal(param, method)) + result.add(new OpalLocal(param.asVar, method)) }) result @@ -24,7 +24,7 @@ class OpalMethodInvokeExpr(val delegate: MethodCall[DUVar[ValueInformation]], me override def getBase: Val = { if (isInstanceInvokeExpr) { - return new OpalLocal(delegate.asInstanceMethodCall.receiver, method) + return new OpalLocal(delegate.asInstanceMethodCall.receiver.asVar, method) } throw new RuntimeException("Method call is not an instance invoke expression") @@ -36,7 +36,7 @@ class OpalMethodInvokeExpr(val delegate: MethodCall[DUVar[ValueInformation]], me override def isStaticInvokeExpr: Boolean = delegate.isStaticMethodCall - override def hashCode(): Int = 31 + delegate.hashCode() + override def hashCode: Int = Objects.hash(delegate) private def canEqual(a: Any): Boolean = a.isInstanceOf[OpalMethodInvokeExpr] @@ -48,7 +48,7 @@ class OpalMethodInvokeExpr(val delegate: MethodCall[DUVar[ValueInformation]], me override def toString: String = delegate.toString } -class OpalFunctionInvokeExpr(val delegate: FunctionCall[DUVar[ValueInformation]], method: OpalMethod) extends InvokeExpr { +class OpalFunctionInvokeExpr(val delegate: FunctionCall[IdBasedVar], method: OpalMethod) extends InvokeExpr { override def getArg(index: Int): Val = getArgs.get(index) @@ -56,7 +56,7 @@ class OpalFunctionInvokeExpr(val delegate: FunctionCall[DUVar[ValueInformation]] val result = new util.ArrayList[Val] delegate.params.foreach(param => { - result.add(new OpalLocal(param, method)) + result.add(new OpalLocal(param.asVar, method)) }) result @@ -66,7 +66,7 @@ class OpalFunctionInvokeExpr(val delegate: FunctionCall[DUVar[ValueInformation]] override def getBase: Val = { if (isInstanceInvokeExpr) { - return new OpalLocal(delegate.asInstanceFunctionCall.receiver, method) + return new OpalLocal(delegate.asInstanceFunctionCall.receiver.asVar, method) } throw new RuntimeException("Function call is not an instance invoke expression") @@ -78,7 +78,7 @@ class OpalFunctionInvokeExpr(val delegate: FunctionCall[DUVar[ValueInformation]] override def isStaticInvokeExpr: Boolean = delegate.isStaticFunctionCall - override def hashCode(): Int = 31 + delegate.hashCode() + override def hashCode: Int = Objects.hash(delegate) private def canEqual(a: Any): Boolean = a.isInstanceOf[OpalFunctionInvokeExpr] diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalLocal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalLocal.scala index 1d5423ca0..568e88261 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalLocal.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalLocal.scala @@ -1,21 +1,16 @@ package boomerang.scope.opal.tac -import boomerang.scope.opal.OpalClient import boomerang.scope._ import org.opalj.br.ObjectType -import org.opalj.tac.{DUVar, DVar, Expr, UVar} +import org.opalj.tac.{DUVar, DVar, Expr, IdBasedVar, SimpleVar, UVar, Var} import org.opalj.value.ValueInformation import java.util.Objects -class OpalLocal(val delegate: Expr[DUVar[ValueInformation]], method: OpalMethod, unbalanced: ControlFlowGraph.Edge = null) extends Val(method, unbalanced) { - - if (!delegate.isVar) { - throw new RuntimeException("OpalLocal can hold only variables") - } +class OpalLocal(val delegate: Var[IdBasedVar], method: OpalMethod, unbalanced: ControlFlowGraph.Edge = null) extends Val(method, unbalanced) { override def getType: Type = delegate match { - case local: DUVar[ValueInformation] => + /*case local: SimpleVar => if (local.value.isReferenceValue) { OpalType(local.value.asReferenceValue.asReferenceType, local.value.asReferenceValue.isNull.isYes) } else if (local.value.isPrimitiveValue) { @@ -26,8 +21,9 @@ class OpalLocal(val delegate: Expr[DUVar[ValueInformation]], method: OpalMethod, OpalType(ObjectType.Array) } else { throw new RuntimeException("Could not determine type " + local.value) - } + }*/ case _ => throw new RuntimeException("Cannot compute type of expression that is not a variable") + } override def isStatic: Boolean = false @@ -45,11 +41,7 @@ class OpalLocal(val delegate: Expr[DUVar[ValueInformation]], method: OpalMethod, override def getArrayAllocationSize: Val = throw new RuntimeException("Opal local is not an array allocation expression") override def isNull: Boolean = { - if (!delegate.asVar.value.isReferenceValue) { - delegate.asVar.value.asReferenceValue.isNull.isYes - } - - false + ??? } override def isStringConstant: Boolean = false @@ -90,79 +82,12 @@ class OpalLocal(val delegate: Expr[DUVar[ValueInformation]], method: OpalMethod, override def getArrayBase: Pair[Val, Integer] = throw new RuntimeException("Opal local is not array reference") - override def getVariableName: String = delegate match { - case dVar: DVar[_] => s"var(D)" // TODO Add origin - case uVar: UVar[_] => s"var(${uVar.definedBy.head})" - case _ => delegate.toString - } + override def getVariableName: String = delegate.asVar.name - override def hashCode: Int = delegate match { - case uVar: UVar[_] => - if (uVar.definedBy.head < 0) { - // Parameters have no real definition statement, so we just use their definition site index - return Objects.hash(super.hashCode(), uVar.definedBy.head) - } - - // UVars should reference their DVar to keep the comparisons consistent - val tac = OpalClient.getTacForMethod(method.delegate) - val defStmt = tac.stmts(uVar.definedBy.head) - - if (!defStmt.isAssignment) { - return Objects.hash(super.hashCode(), delegate.hashCode()) - } - - val targetVar = defStmt.asAssignment.targetVar - Objects.hash(super.hashCode(), targetVar.hashCode()) - case dVar: DVar[_] => Objects.hash(super.hashCode(), dVar.hashCode()) - case _ => throw new RuntimeException("Cannot compute hashCode for non variables") - } + override def hashCode: Int = Objects.hash(delegate.asVar.id) - override def equals(obj: Any): Boolean = obj match { - case other: OpalLocal => - // DVar does not implement a proper equals() method, so we have to compare the hash codes - this.delegate match { - case _: DVar[_] if other.delegate.isInstanceOf[DVar[_]] => - super.equals(other) && this.delegate.hashCode() == other.delegate.hashCode() - case uVar: UVar[_] if other.delegate.isInstanceOf[DVar[_]] => - val tac = OpalClient.getTacForMethod(method.delegate) - val defStmt = tac.stmts(uVar.definedBy.head) - - if (!defStmt.isAssignment) { - return false - } - - val targetVar = defStmt.asAssignment.targetVar - val otherVar = other.delegate.asInstanceOf[DVar[ValueInformation]] - super.equals(other) && targetVar.hashCode() == otherVar.hashCode() - case dVar: DVar[_] if other.delegate.isInstanceOf[UVar[_]] => - val otherVar = other.delegate.asInstanceOf[UVar[ValueInformation]] - - otherVar.definedBy.foreach(defSite => { - // Consider only non-parameter DVars - if (defSite >= 0) { - val tac = OpalClient.getTacForMethod(method.delegate) - val defStmt = tac.stmts(defSite) - - if (defStmt.isAssignment) { - val targetVar = defStmt.asAssignment.targetVar - if (super.equals(other) && dVar.hashCode() == targetVar.hashCode()) { - return true - } - } - } - }) - - false - case _: UVar[_] if other.delegate.isInstanceOf[UVar[_]] => - super.equals(other) && this.delegate.hashCode() == other.delegate.hashCode() - case _ => throw new RuntimeException("Cannot compare a variable with a non variable") - } - case other: OpalParameterLocal => - this.delegate match { - case uVar: UVar[_] => - Objects.equals(m, other.m) && uVar.definedBy.head == other.index; - case _ => false - } + override def equals(other: Any): Boolean = other match { + case that: OpalLocal => super.equals(that) && this.delegate.asVar.id == that.delegate.asVar.id case _ => false } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalMethod.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalMethod.scala index 36ad6eee7..e6b93410e 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalMethod.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalMethod.scala @@ -2,29 +2,27 @@ package boomerang.scope.opal.tac import boomerang.scope._ import boomerang.scope.opal.OpalClient -import org.opalj.tac.{InstanceFunctionCall, InstanceMethodCall, Stmt} +import org.opalj.ai.domain.l0.PrimitiveTACAIDomain +import org.opalj.ai.domain.l1.DefaultDomainWithCFGAndDefUse +import org.opalj.tac.{InstanceFunctionCall, InstanceMethodCall, NaiveTACode, SimplePropagation, Stmt, TACAI, TACNaive, TACode} import java.util +import java.util.Objects -case class OpalMethod(delegate: org.opalj.br.Method) extends Method { +class OpalMethod private(val delegate: org.opalj.br.Method, val tacCode: NaiveTACode[_]) extends Method { if (delegate.body.isEmpty) { throw new RuntimeException("Cannot build OpalMethod without existing body") } + private val cfg = new OpalControlFlowGraph(this) + private var localCache: Option[util.Set[Val]] = None private var parameterLocalCache: Option[util.List[Val]] = None - private val cfg = new OpalControlFlowGraph(delegate) - override def isStaticInitializer: Boolean = delegate.isStaticInitializer - override def isParameterLocal(value: Val): Boolean = { - // if (value.isStatic) return false - - val parameterLocals = getParameterLocals - parameterLocals.contains(value) - } + override def isParameterLocal(value: Val): Boolean = getParameterLocals.contains(value) override def getParameterTypes: util.List[Type] = { val result = new util.ArrayList[Type]() @@ -49,7 +47,26 @@ case class OpalMethod(delegate: org.opalj.br.Method) extends Method { override def getThisLocal: Val = { if (!isStatic) { - return new OpalParameterLocal(delegate.classFile.thisType, -1, this) + /* The 'this' local is implicitly defined as parameter local with id -1. If the 'this' local + * is not used within the method, it stays at -1. However, if it is used, there is an additional + * assignment to an actual variable. Therefore, we have to check first for the usage. + */ + tacCode.stmts.foreach(stmt => { + if (stmt.isAssignment && stmt.asAssignment.expr.isVar) { + if (stmt.asAssignment.expr.asVar.id == -1) { + return new OpalLocal(stmt.asAssignment.targetVar, this) + } + } + }) + + // 'this' local is not used; return just the parameter local + tacCode.stmts.foreach(stmt => { + if (stmt.isAssignment && stmt.asAssignment.targetVar.id == -1) { + return new OpalLocal(stmt.asAssignment.targetVar, this) + } + }) + + throw new RuntimeException("Could not determine 'this' local in method " + delegate.name) } throw new RuntimeException("Static method does not have a 'this' local") @@ -67,13 +84,14 @@ case class OpalMethod(delegate: org.opalj.br.Method) extends Method { // Parameter locals localCache.get.addAll(getParameterLocals) - val tac = OpalClient.getTacForMethod(delegate) - - tac.stmts.foreach(stmt => { - // Locals are always defined as DVar + tacCode.stmts.foreach(stmt => { if (stmt.isAssignment) { val targetVar = stmt.asAssignment.targetVar - localCache.get.add(new OpalLocal(targetVar, this)) + + // Parameters have been covered above + if (targetVar.id >= 0) { + localCache.get.add(new OpalLocal(targetVar, this)) + } } }) } @@ -85,14 +103,36 @@ case class OpalMethod(delegate: org.opalj.br.Method) extends Method { if (parameterLocalCache.isEmpty) { parameterLocalCache = Some(new util.ArrayList[Val]()) - val tac = OpalClient.getTacForMethod(delegate) + val indices = new util.HashSet[Integer]() + + tacCode.stmts.foreach(stmt => { + if (stmt.isAssignment && stmt.asAssignment.expr.isVar) { + val param = stmt.asAssignment.expr.asVar - delegate.parameterTypes.indices.foreach(i => { - val paramType = delegate.parameterTypes(i) - val index = tac.params.parameters(i + 1).origin + // Exclude the 'this' local + if (param.id < 0 && param.id != -1) { + val paramLocal = new OpalLocal(stmt.asAssignment.targetVar, this) - val parameterLocal = new OpalParameterLocal(paramType, index, this) - parameterLocalCache.get.add(parameterLocal) + parameterLocalCache.get.add(paramLocal) + indices.add(param.id) + } + } + }) + + // Collect all unused parameter locals + tacCode.stmts.foreach(stmt => { + if (stmt.isAssignment) { + val target = stmt.asAssignment.targetVar + + // Exclude 'this' local + if (target.id < 0 && target.id != -1) { + if (!indices.contains(target.id)) { + val paramLocal = new OpalLocal(target, this) + + parameterLocalCache.get.add(paramLocal) + } + } + } }) } @@ -109,7 +149,7 @@ case class OpalMethod(delegate: org.opalj.br.Method) extends Method { override def getDeclaringClass: WrappedClass = OpalWrappedClass(delegate.classFile) - override def getControlFlowGraph: ControlFlowGraph = cfg + override def getControlFlowGraph: ControlFlowGraph = cfg.get() override def getSubSignature: String = delegate.signature.toJava @@ -117,5 +157,19 @@ case class OpalMethod(delegate: org.opalj.br.Method) extends Method { override def isConstructor: Boolean = delegate.isConstructor + override def hashCode: Int = Objects.hash(delegate) + + override def equals(other: Any): Boolean = other match { + case that: OpalMethod => this.delegate == that.delegate + case _ => false + } + override def toString: String = delegate.toJava } + +object OpalMethod { + + def apply(delegate: org.opalj.br.Method): OpalMethod = new OpalMethod(delegate, TACNaive(delegate, OpalClient.getClassHierarchy)) + + def apply(delegate: org.opalj.br.Method, tacCode: NaiveTACode[_]): OpalMethod = new OpalMethod(delegate, tacCode) +} diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalParameterLocal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalParameterLocal.scala deleted file mode 100644 index 22ce52f13..000000000 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalParameterLocal.scala +++ /dev/null @@ -1,82 +0,0 @@ -package boomerang.scope.opal.tac - -import boomerang.scope.{ControlFlowGraph, Method, Pair, Type, Val} -import org.opalj.br.FieldType -import org.opalj.tac.UVar - -import java.util.Objects - -class OpalParameterLocal(val parameterType: FieldType, val index: Int, method: OpalMethod, unbalanced: ControlFlowGraph.Edge = null) extends Val(method, unbalanced) { - - override def getType: Type = OpalType(parameterType) - - override def isStatic: Boolean = false - - override def isNewExpr: Boolean = false - - override def getNewExprType: Type = throw new RuntimeException("Parameter local is not a new expression") - - override def asUnbalanced(stmt: ControlFlowGraph.Edge): Val = new OpalParameterLocal(parameterType, index, method, stmt) - - override def isLocal: Boolean = true - - override def isArrayAllocationVal: Boolean = false - - override def getArrayAllocationSize: Val = throw new RuntimeException("Parameter local is not an array allocation val") - - override def isNull: Boolean = false - - override def isStringConstant: Boolean = false - - override def getStringValue: String = throw new RuntimeException("Parameter local is not a string constant") - - override def isStringBufferOrBuilder: Boolean = false - - override def isThrowableAllocationType: Boolean = false - - override def isCast: Boolean = false - - override def getCastOp: Val = throw new RuntimeException("Parameter local is not a cast expression") - - override def isArrayRef: Boolean = ??? - - override def isInstanceOfExpr: Boolean = false - - override def getInstanceOfOp: Val = throw new RuntimeException("Parameter local is not an instanceOf expression") - - override def isLengthExpr: Boolean = false - - override def getLengthOp: Val = throw new RuntimeException("Parameter local is not a length expression") - - override def isIntConstant: Boolean = false - - override def isClassConstant: Boolean = false - - override def getClassConstantType: Type = throw new RuntimeException("Parameter local is not a class constant") - - override def withNewMethod(callee: Method): Val = new OpalParameterLocal(parameterType, index, callee.asInstanceOf[OpalMethod]) - - override def isLongConstant: Boolean = false - - override def getIntValue: Int = throw new RuntimeException("Parameter local is not an int constant") - - override def getLongValue: Long = throw new RuntimeException("Parameter local is not a long constant") - - override def getArrayBase: Pair[Val, Integer] = throw new RuntimeException("Parameter local is not an array ref") - - override def getVariableName: String = s"var($index)" - - override def hashCode: Int = Objects.hash(super.hashCode(), index) - - override def equals(obj: Any): Boolean = obj match { - case other: OpalParameterLocal => Objects.equals(m, other.m) && index == other.index - case local: OpalLocal => - local.delegate match { - case uVar: UVar[_] => Objects.equals(m, local.m) && index == uVar.definedBy.head - case _ => false - } - case _ => false - } - - override def toString: String = getVariableName -} diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala index a85f1bd5e..9aa7a98f8 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala @@ -2,20 +2,19 @@ package boomerang.scope.opal.tac import boomerang.scope._ import com.google.common.base.Joiner -import org.opalj.tac.{DUVar, PrimitiveTypecastExpr, Stmt} +import org.opalj.tac.{DUVar, IdBasedVar, PrimitiveTypecastExpr, Stmt, Var} import org.opalj.value.ValueInformation import java.util import java.util.Objects -class OpalStatement(val delegate: Stmt[DUVar[ValueInformation]], m: OpalMethod) extends Statement(m) { +class OpalStatement(val delegate: Stmt[IdBasedVar], m: OpalMethod) extends Statement(m) { override def containsStaticFieldAccess(): Boolean = isStaticFieldLoad || isStaticFieldStore override def containsInvokeExpr(): Boolean = { if (delegate.isMethodCall) return true if (delegate.isAssignment && delegate.asAssignment.expr.isFunctionCall) return true - if (delegate.isExprStmt && delegate.asExprStmt.isMethodCall) return true if (delegate.isExprStmt && delegate.asExprStmt.expr.isFunctionCall) return true false @@ -23,10 +22,17 @@ class OpalStatement(val delegate: Stmt[DUVar[ValueInformation]], m: OpalMethod) override def getInvokeExpr: InvokeExpr = { if (containsInvokeExpr()) { - if (delegate.isMethodCall) return new OpalMethodInvokeExpr(delegate.asMethodCall, m) - if (delegate.isAssignment && delegate.asAssignment.expr.isFunctionCall) return new OpalFunctionInvokeExpr(delegate.asAssignment.expr.asFunctionCall, m) - if (delegate.isExprStmt && delegate.asExprStmt.isMethodCall) return new OpalMethodInvokeExpr(delegate.asExprStmt.asMethodCall, m) - if (delegate.isExprStmt && delegate.asExprStmt.expr.isFunctionCall) return new OpalFunctionInvokeExpr(delegate.asExprStmt.expr.asFunctionCall, m) + if (delegate.isMethodCall) { + return new OpalMethodInvokeExpr(delegate.asMethodCall, m) + } + + if (delegate.isAssignment && delegate.asAssignment.expr.isFunctionCall) { + return new OpalFunctionInvokeExpr(delegate.asAssignment.expr.asFunctionCall, m) + } + + if (delegate.isExprStmt && delegate.asExprStmt.expr.isFunctionCall) { + return new OpalFunctionInvokeExpr(delegate.asExprStmt.expr.asFunctionCall, m) + } } throw new RuntimeException("Statement does not contain an invoke expression") @@ -104,10 +110,10 @@ class OpalStatement(val delegate: Stmt[DUVar[ValueInformation]], m: OpalMethod) val indexValue = delegate.asArrayStore.index if (!indexValue.isVar) return new OpalArrayRef(base, -1, m) - if (!indexValue.asVar.value.isPrimitiveValue) return new OpalArrayRef(base, -1, m) + //if (!indexValue.asVar.value.isPrimitiveValue) return new OpalArrayRef(base, -1, m) - val index = indexValue.asVar.value.asPrimitiveValue.asConstantInteger.intValue() - return new OpalArrayRef(base, index, m) + //val index = indexValue.asVar.value.asPrimitiveValue.asConstantInteger.intValue() + return new OpalArrayRef(base, -1, m) } } @@ -127,10 +133,14 @@ class OpalStatement(val delegate: Stmt[DUVar[ValueInformation]], m: OpalMethod) val indexValue = rightExpr.asArrayLoad.index if (!indexValue.isVar) return new OpalArrayRef(base, -1, m) - if (!indexValue.asVar.value.isPrimitiveValue) return new OpalArrayRef(base, -1, m) + //if (!indexValue.asVar.value.isPrimitiveValue) return new OpalArrayRef(base, -1, m) + + //val index = indexValue.asVar.value.asPrimitiveValue.asConstantInteger.intValue() + return new OpalArrayRef(base, -1, m) + } - val index = indexValue.asVar.value.asPrimitiveValue.asConstantInteger.intValue() - return new OpalArrayRef(base, index, m) + if (rightExpr.isVar) { + return new OpalLocal(delegate.asAssignment.expr.asVar, m) } return new OpalVal(delegate.asAssignment.expr, m) @@ -144,7 +154,7 @@ class OpalStatement(val delegate: Stmt[DUVar[ValueInformation]], m: OpalMethod) if (isArrayStore) { // TODO Distinguish between constant and variable val arrayStore = delegate.asArrayStore - return new OpalLocal(arrayStore.arrayRef, m) + return new OpalLocal(arrayStore.arrayRef.asVar, m) } } @@ -217,7 +227,7 @@ class OpalStatement(val delegate: Stmt[DUVar[ValueInformation]], m: OpalMethod) if (isFieldStore) { val fieldStore = delegate.asPutField - val local = new OpalLocal(fieldStore.objRef, m) + val local = new OpalLocal(fieldStore.objRef.asVar, m) val field = OpalField(fieldStore.declaringClass, fieldStore.declaredFieldType, fieldStore.name) return new Pair(local, field) @@ -230,7 +240,7 @@ class OpalStatement(val delegate: Stmt[DUVar[ValueInformation]], m: OpalMethod) if (isFieldLoad) { val fieldLoad = delegate.asAssignment.expr.asGetField - val local = new OpalLocal(fieldLoad.objRef, m) + val local = new OpalLocal(fieldLoad.objRef.asVar, m) val field = OpalField(fieldLoad.declaringClass, fieldLoad.declaredFieldType, fieldLoad.name) return new Pair(local, field) @@ -309,18 +319,18 @@ class OpalStatement(val delegate: Stmt[DUVar[ValueInformation]], m: OpalMethod) assign = s"$getLeftOp = " } - return assign + base + getInvokeExpr.getMethod.getName + "(" + Joiner.on(",").join(getInvokeExpr.getArgs) + ")" + return s"${delegate.pc}: $assign$base${getInvokeExpr.getMethod.getName}(${Joiner.on(",").join(getInvokeExpr.getArgs)})" } if (isAssignStmt) { if (delegate.isAssignment) { if (isFieldStore) { - return s"$getLeftOp = ${getFieldStore.getX}.${getFieldStore.getY}" + return s"${delegate.pc}: $getLeftOp = ${getFieldStore.getX}.${getFieldStore.getY}" } else if (isArrayStore) { val base = getArrayBase - return s"${base.getX.getVariableName}[${base.getY}] = $getRightOp" + return s"${delegate.pc}: ${base.getX.getVariableName}[${base.getY}] = $getRightOp" } else { - return s"$getLeftOp = $getRightOp" + return s"${delegate.pc}: $getLeftOp = $getRightOp" } } } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalVal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalVal.scala index 1c043b021..a919520bd 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalVal.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalVal.scala @@ -4,9 +4,10 @@ import boomerang.scope.opal.OpalClient import boomerang.scope._ import org.opalj.br.ReferenceType import org.opalj.tac._ -import org.opalj.value.ValueInformation -class OpalVal(val delegate: Expr[DUVar[ValueInformation]], method: OpalMethod, unbalanced: ControlFlowGraph.Edge = null) extends Val(method, unbalanced) { +import java.util.Objects + +class OpalVal(val delegate: Expr[IdBasedVar], method: OpalMethod, unbalanced: ControlFlowGraph.Edge = null) extends Val(method, unbalanced) { if (delegate.isVar) { throw new RuntimeException("OpalVal cannot hold a variable (use OpalLocal)") @@ -42,7 +43,7 @@ class OpalVal(val delegate: Expr[DUVar[ValueInformation]], method: OpalMethod, u // TODO Deal with multiple arrays override def getArrayAllocationSize: Val = { if (isArrayAllocationVal) { - return new OpalLocal(delegate.asNewArray.counts.head, method) + return new OpalLocal(delegate.asNewArray.counts.head.asVar, method) } throw new RuntimeException("Value is not an array allocation expression") @@ -156,7 +157,7 @@ class OpalVal(val delegate: Expr[DUVar[ValueInformation]], method: OpalMethod, u } } - override def hashCode(): Int = 31 * super.hashCode() + delegate.hashCode() + override def hashCode: Int = Objects.hash(super.hashCode(), delegate.hashCode()) private def canEqual(a: Any): Boolean = a.isInstanceOf[OpalVal] diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalControlFlowGraphTest.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalControlFlowGraphTest.scala index 8e2b11082..cb7ec359d 100644 --- a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalControlFlowGraphTest.scala +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalControlFlowGraphTest.scala @@ -4,7 +4,9 @@ import boomerang.scope.opal.tac.OpalMethod import boomerang.scope.test.MethodSignature import boomerang.scope.test.targets.ControlFlowGraphTarget import org.junit.{Assert, Test} +import org.opalj.ai.domain.l1.DefaultDomainWithCFGAndDefUse import org.opalj.br.IntegerType +import org.opalj.tac.TACAI class OpalControlFlowGraphTest { diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala new file mode 100644 index 000000000..e5a434007 --- /dev/null +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala @@ -0,0 +1,78 @@ +package boomerang.scope.opal + +import boomerang.scope.InvokeExpr +import boomerang.scope.opal.tac.{OpalLocal, OpalMethod, OpalStatement} +import boomerang.scope.test.MethodSignature +import boomerang.scope.test.targets.{InvokeExprTarget, ThisLocalTarget} +import org.junit.Test +import org.opalj.ai.{AIResult, Domain, InterruptableAI} +import org.opalj.ai.domain.l0.{BaseDomainWithDefUse, PrimitiveTACAIDomain} +import org.opalj.br.cfg.CFGFactory +import org.opalj.tac.TACAI + +class OpalInvokeExprTest { + + @Test + def instanceInvokeExprTest(): Unit = { + val opalSetup = new OpalSetup() + opalSetup.setupOpal(classOf[InvokeExprTarget].getName) + + val signature = new MethodSignature(classOf[InvokeExprTarget].getName, "alias", "Void") + val method = opalSetup.resolveMethod(signature) + val opalMethod = OpalMethod(method) + + val domain = new BaseDomainWithDefUse(OpalClient.project.get, method) + val ai = new InterruptableAI[Domain] + val result = ai(method, domain) + + opalMethod.getStatements.forEach(stmt => { + println("\n" + stmt + ":") + if (stmt.containsInvokeExpr()) { + val invokeExpr = stmt.getInvokeExpr + + if (invokeExpr.isInstanceInvokeExpr) { + val base = invokeExpr.getBase + + val baseId = base.asInstanceOf[OpalLocal].delegate.asVar.id + val base1 = result.domain.operandOrigin(stmt.asInstanceOf[OpalStatement].delegate.pc, baseId) + println("Base " + base1) + + if (invokeExpr.getArgs.size() > 0) { + val arg = invokeExpr.getArg(0) + val argId = arg.asInstanceOf[OpalLocal].delegate.asVar.id + val arg1 = result.domain.operandOrigin(stmt.asInstanceOf[OpalStatement].delegate.pc, argId) + println("Arg " + arg1) + } + } + } + + if (stmt.isAssignStmt) { + val leftOp = stmt.getLeftOp + val rightOp = stmt.getRightOp + + if (leftOp.isLocal && rightOp.isLocal) { + val rightId = rightOp.asInstanceOf[OpalLocal].delegate.asVar.id + if (rightId >= 0) { + val right1 = result.domain.operandOrigin(stmt.asInstanceOf[OpalStatement].delegate.pc, rightId) + println("r1: "+ right1) + } else { + val right2 = result.domain.localOrigin(stmt.asInstanceOf[OpalStatement].delegate.pc, rightId) + println("r2: " + right2) + } + } + + if (leftOp.isLocal && rightOp.isIntConstant) { + val leftId = leftOp.asInstanceOf[OpalLocal].delegate.asVar.id + if (leftId >= 0) { + //val left1 = result.domain.operandOrigin(stmt.asInstanceOf[OpalStatement].delegate.pc, leftId) + println("l1: ")// + left1) + } else { + val left2 = result.domain.localOrigin(stmt.asInstanceOf[OpalStatement].delegate.pc, leftId) + println("l2: " + left2) + } + } + } + }) + } + +} diff --git a/boomerangScope/src/test/java/boomerang/scope/test/targets/InvokeExprTarget.java b/boomerangScope/src/test/java/boomerang/scope/test/targets/InvokeExprTarget.java new file mode 100644 index 000000000..60eb7873c --- /dev/null +++ b/boomerangScope/src/test/java/boomerang/scope/test/targets/InvokeExprTarget.java @@ -0,0 +1,26 @@ +package boomerang.scope.test.targets; + +public class InvokeExprTarget { + + public static void main(String[] args) { + instanceInvokeExpr(); + } + + public static void instanceInvokeExpr() { + int i = 10; + A a = new A(); + + a.methodCall(i); + } + + public static void alias() { + int i = 10; + A a = new A(); + + if (Math.random() > 0.5) { + i = 10000; + } + + a.methodCall(i); + } +} diff --git a/boomerangScope/src/test/java/boomerang/scope/test/targets/ParameterLocalsTarget.java b/boomerangScope/src/test/java/boomerang/scope/test/targets/ParameterLocalsTarget.java index c15eebb81..9975b919d 100644 --- a/boomerangScope/src/test/java/boomerang/scope/test/targets/ParameterLocalsTarget.java +++ b/boomerangScope/src/test/java/boomerang/scope/test/targets/ParameterLocalsTarget.java @@ -27,5 +27,7 @@ public void noParameters() {} public void oneParameter(@SuppressWarnings("unused") int i) {} - public void twoParameters(@SuppressWarnings("unused") int i, @SuppressWarnings("unused") A a) {} + public void twoParameters(@SuppressWarnings("unused") int i, @SuppressWarnings("unused") A a) { + a.methodCall(i); + } } diff --git a/testCore/src/main/java/test/setup/OpalTestSetup.java b/testCore/src/main/java/test/setup/OpalTestSetup.java index 6e7ccab45..139547f28 100644 --- a/testCore/src/main/java/test/setup/OpalTestSetup.java +++ b/testCore/src/main/java/test/setup/OpalTestSetup.java @@ -87,7 +87,7 @@ public void initialize( @Override public Method getTestMethod() { - return new OpalMethod(testMethod); + return OpalMethod.apply(testMethod); } @Override From a7419a9281e2086b155d52cb456f6deb54b14745 Mon Sep 17 00:00:00 2001 From: Sven Meyer Date: Fri, 21 Mar 2025 18:56:23 +0100 Subject: [PATCH 21/61] Add transformer for TACode --- .../opal/transformer/BoomerangTACode.scala | 13 + .../scope/opal/transformer/TacLocal.scala | 70 ++++ .../opal/transformer/TacTransformer.scala | 362 ++++++++++++++++++ .../scope/opal/OpalInvokeExprTest.scala | 64 +--- .../boomerang/scope/soot/SootArrayTest.java | 62 +-- .../boomerang/scope/soot/SootScopeTest.java | 1 - .../scope/test/targets/ArrayTarget.java | 49 ++- .../scope/test/targets/AssignmentTarget.java | 39 +- .../scope/test/targets/InvokeExprTarget.java | 47 ++- .../main/java/test/setup/OpalTestSetup.java | 11 - 10 files changed, 574 insertions(+), 144 deletions(-) create mode 100644 boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/BoomerangTACode.scala create mode 100644 boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacLocal.scala create mode 100644 boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacTransformer.scala diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/BoomerangTACode.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/BoomerangTACode.scala new file mode 100644 index 000000000..9f9c38ce6 --- /dev/null +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/BoomerangTACode.scala @@ -0,0 +1,13 @@ +package boomerang.scope.opal.transformer + +import org.opalj.br.ExceptionHandlers +import org.opalj.br.cfg.CFG +import org.opalj.tac.{Param, Parameters, Stmt, TACStmts} + +class BoomerangTACode( + val params: Parameters[Param], + val statements: Array[Stmt[TacLocal]], + val pcToIndex: Array[Int], + val cfg: CFG[Stmt[TacLocal], TACStmts[TacLocal]], + val exceptionHandlers: ExceptionHandlers + ) {} diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacLocal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacLocal.scala new file mode 100644 index 000000000..d9f0e67f0 --- /dev/null +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacLocal.scala @@ -0,0 +1,70 @@ +package boomerang.scope.opal.transformer + +import org.opalj.br.ComputationalType +import org.opalj.tac.{DUVar, Var} +import org.opalj.value.ValueInformation + +import java.util.Objects + +sealed trait TacLocal extends Var[TacLocal] { + + def id: Int + + def isStackLocal: Boolean + + def isRegisterLocal: Boolean + + final def isSideEffectFree: Boolean = true + + override def toCanonicalForm(implicit ev: TacLocal <:< DUVar[ValueInformation]): Nothing = { + throw new IncompatibleClassChangeError( + "TacLocal objects are not expected to inherit from DUVar" + ) + } +} + +class StackLocal(identifier: Int, computationalType: ComputationalType) extends TacLocal { + + override def id: Int = identifier + + override def isStackLocal: Boolean = true + + override def isRegisterLocal: Boolean = false + + override def name: String = s"$$s$identifier" + + override def cTpe: ComputationalType = computationalType + + override def hashCode: Int = Objects.hash(identifier) + + override def equals(other: Any): Boolean = other match { + case that: StackLocal => this.id == that.id + case _ => false + } + + override def toString: String = name +} + +class RegisterLocal(identifier: Int, computationalType: ComputationalType) extends TacLocal { + + override def id: Int = identifier + + override def isStackLocal: Boolean = false + + override def isRegisterLocal: Boolean = true + + override def name: String = s"r${-identifier - 1}" + + override def cTpe: ComputationalType = computationalType + + override def hashCode: Int = Objects.hash(identifier) + + override def equals(other: Any): Boolean = other match { + case that: RegisterLocal => this.id == that.id + case _ => false + } + + override def toString: String = name +} + + diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacTransformer.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacTransformer.scala new file mode 100644 index 000000000..c8ca417fd --- /dev/null +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacTransformer.scala @@ -0,0 +1,362 @@ +package boomerang.scope.opal.transformer + +import org.opalj.br.{ClassHierarchy, Method} +import org.opalj.br.cfg.CFGFactory +import org.opalj.collection.immutable.IntIntPair +import org.opalj.tac.{ArrayLength, ArrayLoad, ArrayStore, Assignment, BinaryExpr, CaughtException, Checkcast, ClassConst, Compare, DoubleConst, DynamicConst, Expr, ExprStmt, FloatConst, GetField, GetStatic, Goto, IdBasedVar, If, IntConst, InvokedynamicFunctionCall, InvokedynamicMethodCall, JSR, LongConst, MethodHandleConst, MethodTypeConst, MonitorEnter, MonitorExit, NaiveTACode, New, NewArray, NonVirtualFunctionCall, NonVirtualMethodCall, Nop, NullExpr, Param, PrefixExpr, PrimitiveTypecastExpr, PutField, PutStatic, Ret, Return, ReturnValue, StaticFunctionCall, StaticMethodCall, Stmt, StringConst, Switch, TACNaive, TACOptimization, TACStmts, Throw, VirtualFunctionCall, VirtualMethodCall} + +import scala.collection.mutable + +object TacTransformer { + + private var stackCounter = 0 + private var currentStack = mutable.Map.empty[Int, TacLocal] + + def apply(tacCode: NaiveTACode[_]): Array[Stmt[TacLocal]] = { + stackCounter = 0 + currentStack = mutable.Map.empty[Int, TacLocal] + + val updatedTacCode = tacCode.stmts.map(stmt => transformStatement(stmt)) + + updatedTacCode + } + + def apply(method: Method, classHierarchy: ClassHierarchy, optimizations: List[TACOptimization[Param, IdBasedVar, NaiveTACode[Param]]] = List.empty): BoomerangTACode = { + val tacNaive = TACNaive(method, classHierarchy, optimizations) + + val transformedTac: Array[Stmt[TacLocal]] = tacNaive.stmts.map(stmt => transformStatement(stmt)) + + // Update the CFG + val cfg = CFGFactory(method, classHierarchy) + if (cfg.isEmpty) { + throw new RuntimeException("Could not compute CFG for method " + method.name) + } + + val tacCfg = cfg.get.mapPCsToIndexes[Stmt[TacLocal], TACStmts[TacLocal]](TACStmts(transformedTac), tacNaive.pcToIndex, i => i, transformedTac.length) + + new BoomerangTACode(tacNaive.params, transformedTac, tacNaive.pcToIndex, tacCfg, tacNaive.exceptionHandlers) + } + + private def transformStatement(stmt: Stmt[IdBasedVar]): Stmt[TacLocal] = { + if (stmt.astID == If.ASTID) { + val ifStmt = stmt.asIf + + val left = transformExpr(ifStmt.left) + val right = transformExpr(ifStmt.right) + + return If(ifStmt.pc, left, ifStmt.condition, right, ifStmt.targetStmt) + } + + if (stmt.astID == Goto.ASTID) { + return stmt.asGoto + } + + if (stmt.astID == Ret.ASTID) { + return stmt.asRet + } + + if (stmt.astID == JSR.ASTID) { + return stmt.asJSR + } + + if (stmt.astID == Switch.ASTID) { + val switchStmt = stmt.asSwitch + val index = transformExpr(switchStmt.index) + + // Inserting -1 as it is only used in previous remapping steps + return Switch(switchStmt.pc, switchStmt.defaultStmt, index, switchStmt.caseStmts.map(p => IntIntPair(-1, p))) + } + + if (stmt.astID == Assignment.ASTID) { + val target = createNewLocal(stmt.asAssignment.targetVar) + val transformedExpr = transformExpr(stmt.asAssignment.expr) + + // Store the current stack and register locals on our own 'stack' + currentStack(stmt.asAssignment.targetVar.id) = target + + return new Assignment[TacLocal](stmt.pc, target, transformedExpr) + } + + if (stmt.astID == ReturnValue.ASTID) { + val returnStmt = stmt.asReturnValue + val returnValue = transformExpr(returnStmt.expr) + + return ReturnValue(returnStmt.pc, returnValue) + } + + if (stmt.astID == Return.ASTID) { + return stmt.asReturn + } + + if (stmt.astID == Nop.ASTID) { + return stmt.asNop + } + + if (stmt.astID == MonitorEnter.ASTID) { + val monitorEnter = stmt.asMonitorEnter + val objRef = transformExpr(monitorEnter.objRef) + + return MonitorEnter(monitorEnter.pc, objRef) + } + + if (stmt.astID == MonitorExit.ASTID) { + val monitorExit = stmt.asMonitorExit + val objRef = transformExpr(monitorExit.objRef) + + return MonitorExit(monitorExit.pc, objRef) + } + + if (stmt.astID == ArrayStore.ASTID) { + val arrayStore = stmt.asArrayStore + + val arrayRef = transformExpr(arrayStore.arrayRef) + val index = transformExpr(arrayStore.index) + val value = transformExpr(arrayStore.index) + + return ArrayStore(arrayStore.pc, arrayRef, index, value) + } + + if (stmt.astID == Throw.ASTID) { + val throwStmt = stmt.asThrow + val exception = transformExpr(throwStmt.exception) + + return Throw(throwStmt.pc, exception) + } + + if (stmt.astID == PutStatic.ASTID) { + val putStatic = stmt.asPutStatic + val value = transformExpr(putStatic.value) + + return PutStatic(putStatic.pc, putStatic.declaringClass, putStatic.name, putStatic.declaredFieldType, value) + } + + if (stmt.astID == PutField.ASTID) { + val putField = stmt.asPutField + + val objRef = transformExpr(putField.objRef) + val value = transformExpr(putField.value) + + return PutField(putField.pc, putField.declaringClass, putField.name, putField.declaredFieldType, objRef, value) + } + + if (stmt.astID == NonVirtualMethodCall.ASTID) { + val methodCall = stmt.asNonVirtualMethodCall + + val baseLocal = transformExpr(methodCall.receiver) + val paramLocals = methodCall.params.map(p => transformExpr(p)) + + return NonVirtualMethodCall(methodCall.pc, methodCall.declaringClass, methodCall.isInterface, methodCall.name, methodCall.descriptor, baseLocal, paramLocals) + } + + if (stmt.astID == VirtualMethodCall.ASTID) { + val methodCall = stmt.asVirtualMethodCall + + val baseLocal = transformExpr(methodCall.receiver) + val paramLocals = methodCall.params.map(p => transformExpr(p)) + + return VirtualMethodCall(methodCall.pc, methodCall.declaringClass, methodCall.isInterface, methodCall.name, methodCall.descriptor, baseLocal, paramLocals) + } + + if (stmt.astID == StaticMethodCall.ASTID) { + val methodCall = stmt.asStaticMethodCall + val params = methodCall.params.map(p => transformExpr(p)) + + return StaticMethodCall(methodCall.pc, methodCall.declaringClass, methodCall.isInterface, methodCall.name, methodCall.descriptor, params) + } + + if (stmt.astID == InvokedynamicMethodCall.ASTID) { + val methodCall = stmt.asInvokedynamicMethodCall + val params = methodCall.params.map(p => transformExpr(p)) + + return InvokedynamicMethodCall(methodCall.pc, methodCall.bootstrapMethod, methodCall.name, methodCall.descriptor, params) + } + + if (stmt.astID == ExprStmt.ASTID) { + val expr = transformExpr(stmt.asExprStmt.expr) + + return ExprStmt(stmt.pc, expr) + } + + if (stmt.astID == CaughtException.ASTID) { + val caughtException = stmt.asCaughtException + + return CaughtException(caughtException.pc, caughtException.exceptionType, caughtException.origins) + } + + if (stmt.astID == Checkcast.ASTID) { + val castExpr = stmt.asCheckcast + val value = transformExpr(castExpr.value) + + return Checkcast(castExpr.pc, value, castExpr.cmpTpe) + } + + throw new RuntimeException("Could not transform statement: " + stmt) + } + + private def createNewLocal(idBasedVar: IdBasedVar): TacLocal = { + if (idBasedVar.id >= 0) { + val stackLocal = new StackLocal(stackCounter, idBasedVar.cTpe) + stackCounter += 1 + + stackLocal + } else { + new RegisterLocal(idBasedVar.id, idBasedVar.cTpe) + } + } + + private def transformExpr(expr: Expr[IdBasedVar]): Expr[TacLocal] = { + if (expr.isVar) { + return currentStack.getOrElse(expr.asVar.id, throw new RuntimeException("No local on stack")) + } + + if (expr.astID == Compare.ASTID) { + val compareExpr = expr.asCompare + + val leftLocal = transformExpr(compareExpr.left) + val rightLocal = transformExpr(compareExpr.right) + + return Compare(compareExpr.pc, leftLocal, compareExpr.condition, rightLocal) + } + + if (expr.astID == Param.ASTID) { + return expr.asParam + } + + if (expr.astID == MethodTypeConst.ASTID) { + return expr.asMethodTypeConst + } + + if (expr.astID == MethodHandleConst.ASTID) { + return expr.asMethodHandleConst + } + + if (expr.astID == IntConst.ASTID) { + return expr.asIntConst + } + + if (expr.astID == LongConst.ASTID) { + return expr.asFloatConst + } + + if (expr.astID == FloatConst.ASTID) { + return expr.asFloatConst + } + + if (expr.astID == DoubleConst.ASTID) { + return expr.asDoubleConst + } + + if (expr.astID == StringConst.ASTID) { + return expr.asStringConst + } + + if (expr.astID == ClassConst.ASTID) { + return expr.asClassConst + } + + if (expr.astID == DynamicConst.ASTID) { + return expr.asDynamicConst + } + + if (expr.astID == NullExpr.ASTID) { + return expr.asNullExpr + } + + if (expr.astID == BinaryExpr.ASTID) { + val binaryExpr = expr.asBinaryExpr + + val left = transformExpr(binaryExpr.left) + val right = transformExpr(binaryExpr.right) + + return BinaryExpr(binaryExpr.pc, binaryExpr.cTpe, binaryExpr.op, left, right) + } + + if (expr.astID == PrefixExpr.ASTID) { + val prefixExpr = expr.asPrefixExpr + val operand = transformExpr(prefixExpr.operand) + + return PrefixExpr(prefixExpr.pc, prefixExpr.cTpe, prefixExpr.op, operand) + } + + if (expr.astID == PrimitiveTypecastExpr.ASTID) { + val primitiveTypecastExpr = expr.asPrimitiveTypeCastExpr + val operand = transformExpr(primitiveTypecastExpr) + + return PrimitiveTypecastExpr(primitiveTypecastExpr.pc, primitiveTypecastExpr.targetTpe, operand) + } + + if (expr.astID == New.ASTID) { + return expr.asNew + } + + if (expr.astID == NewArray.ASTID) { + val newArray = expr.asNewArray + val counts = newArray.counts.map(c => transformExpr(c)) + + return NewArray(newArray.pc, counts, newArray.tpe) + } + + if (expr.astID == ArrayLoad.ASTID) { + val arrayLoad = expr.asArrayLoad + + val index = transformExpr(arrayLoad.index) + val arrayRef = transformExpr(arrayLoad.arrayRef) + + return ArrayLoad(arrayLoad.pc, index, arrayRef) + } + + if (expr.astID == ArrayLength.ASTID) { + val arrayLength = expr.asArrayLength + val arrayRef = transformExpr(arrayLength.arrayRef) + + return ArrayLength(arrayLength.pc, arrayRef) + } + + if (expr.astID == GetField.ASTID) { + val getField = expr.asGetField + val objRef = transformExpr(getField.objRef) + + return GetField(getField.pc, getField.declaringClass, getField.name, getField.declaredFieldType, objRef) + } + + if (expr.astID == GetStatic.ASTID) { + return expr.asGetStatic + } + + if (expr.astID == InvokedynamicFunctionCall.ASTID) { + val functionCall = expr.asInvokedynamicFunctionCall + val params = functionCall.params.map(p => transformExpr(p)) + + return InvokedynamicFunctionCall(functionCall.pc, functionCall.bootstrapMethod, functionCall.name, functionCall.descriptor, params) + } + + if (expr.astID == NonVirtualFunctionCall.ASTID) { + val functionCall = expr.asNonVirtualFunctionCall + + val base = transformExpr(functionCall.receiver) + val params = functionCall.params.map(p => transformExpr(p)) + + return NonVirtualFunctionCall(functionCall.pc, functionCall.declaringClass, functionCall.isInterface, functionCall.name, functionCall.descriptor, base, params) + } + + if (expr.astID == VirtualFunctionCall.ASTID) { + val functionCall = expr.asVirtualFunctionCall + + val base = transformExpr(functionCall.receiver) + val params = functionCall.params.map(p => transformExpr(p)) + + return VirtualFunctionCall(functionCall.pc, functionCall.declaringClass, functionCall.isInterface, functionCall.name, functionCall.descriptor, base, params) + } + + if (expr.astID == StaticFunctionCall.ASTID) { + val functionCall = expr.asStaticFunctionCall + + val params = functionCall.params + val paramLocals = params.map(p => transformExpr(p)) + + return StaticFunctionCall(functionCall.pc, functionCall.declaringClass, functionCall.isInterface, functionCall.name, functionCall.descriptor, paramLocals) + } + + throw new RuntimeException("Could not transform expression: " + expr) + } +} diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala index e5a434007..f5136b5fc 100644 --- a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala @@ -1,14 +1,10 @@ package boomerang.scope.opal -import boomerang.scope.InvokeExpr -import boomerang.scope.opal.tac.{OpalLocal, OpalMethod, OpalStatement} +import boomerang.scope.opal.tac.OpalMethod +import boomerang.scope.opal.transformer.TacTransformer import boomerang.scope.test.MethodSignature -import boomerang.scope.test.targets.{InvokeExprTarget, ThisLocalTarget} +import boomerang.scope.test.targets.InvokeExprTarget import org.junit.Test -import org.opalj.ai.{AIResult, Domain, InterruptableAI} -import org.opalj.ai.domain.l0.{BaseDomainWithDefUse, PrimitiveTACAIDomain} -import org.opalj.br.cfg.CFGFactory -import org.opalj.tac.TACAI class OpalInvokeExprTest { @@ -21,58 +17,8 @@ class OpalInvokeExprTest { val method = opalSetup.resolveMethod(signature) val opalMethod = OpalMethod(method) - val domain = new BaseDomainWithDefUse(OpalClient.project.get, method) - val ai = new InterruptableAI[Domain] - val result = ai(method, domain) - - opalMethod.getStatements.forEach(stmt => { - println("\n" + stmt + ":") - if (stmt.containsInvokeExpr()) { - val invokeExpr = stmt.getInvokeExpr - - if (invokeExpr.isInstanceInvokeExpr) { - val base = invokeExpr.getBase - - val baseId = base.asInstanceOf[OpalLocal].delegate.asVar.id - val base1 = result.domain.operandOrigin(stmt.asInstanceOf[OpalStatement].delegate.pc, baseId) - println("Base " + base1) - - if (invokeExpr.getArgs.size() > 0) { - val arg = invokeExpr.getArg(0) - val argId = arg.asInstanceOf[OpalLocal].delegate.asVar.id - val arg1 = result.domain.operandOrigin(stmt.asInstanceOf[OpalStatement].delegate.pc, argId) - println("Arg " + arg1) - } - } - } - - if (stmt.isAssignStmt) { - val leftOp = stmt.getLeftOp - val rightOp = stmt.getRightOp - - if (leftOp.isLocal && rightOp.isLocal) { - val rightId = rightOp.asInstanceOf[OpalLocal].delegate.asVar.id - if (rightId >= 0) { - val right1 = result.domain.operandOrigin(stmt.asInstanceOf[OpalStatement].delegate.pc, rightId) - println("r1: "+ right1) - } else { - val right2 = result.domain.localOrigin(stmt.asInstanceOf[OpalStatement].delegate.pc, rightId) - println("r2: " + right2) - } - } - - if (leftOp.isLocal && rightOp.isIntConstant) { - val leftId = leftOp.asInstanceOf[OpalLocal].delegate.asVar.id - if (leftId >= 0) { - //val left1 = result.domain.operandOrigin(stmt.asInstanceOf[OpalStatement].delegate.pc, leftId) - println("l1: ")// + left1) - } else { - val left2 = result.domain.localOrigin(stmt.asInstanceOf[OpalStatement].delegate.pc, leftId) - println("l2: " + left2) - } - } - } - }) + val transformedTac = TacTransformer(opalMethod.tacCode) + println(transformedTac.mkString("Array(", "\n", ")")) } } diff --git a/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootArrayTest.java b/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootArrayTest.java index 17a0359c9..8aec91052 100644 --- a/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootArrayTest.java +++ b/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootArrayTest.java @@ -1,3 +1,14 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ package boomerang.scope.soot; import boomerang.scope.Method; @@ -13,30 +24,31 @@ public class SootArrayTest { - @Test - public void singleArrayStoreConstantTest() { - SootSetup sootSetup = new SootSetup(); - sootSetup.setupSoot(ArrayTarget.class.getName()); - - MethodSignature signature = new MethodSignature(ArrayTarget.class.getName(), "singleArrayStore"); - SootMethod method = sootSetup.resolveMethod(signature); - Method jimpleMethod = JimpleMethod.of(method); - - int arrayStoreCount = 0; - for (Statement stmt : jimpleMethod.getStatements()) { - if (stmt.isArrayStore()) { - arrayStoreCount++; - - Pair arrayBase = stmt.getArrayBase(); - Assert.assertFalse(arrayBase.getX().isArrayRef()); - Assert.assertTrue(arrayBase.getX().isLocal()); - Assert.assertEquals(0, arrayBase.getY().intValue()); - - Val leftOp = stmt.getLeftOp(); - Assert.assertTrue(leftOp.isArrayRef()); - } - } - - Assert.assertEquals(1, arrayStoreCount); + @Test + public void singleArrayStoreConstantTest() { + SootSetup sootSetup = new SootSetup(); + sootSetup.setupSoot(ArrayTarget.class.getName()); + + MethodSignature signature = + new MethodSignature(ArrayTarget.class.getName(), "singleArrayStore"); + SootMethod method = sootSetup.resolveMethod(signature); + Method jimpleMethod = JimpleMethod.of(method); + + int arrayStoreCount = 0; + for (Statement stmt : jimpleMethod.getStatements()) { + if (stmt.isArrayStore()) { + arrayStoreCount++; + + Pair arrayBase = stmt.getArrayBase(); + Assert.assertFalse(arrayBase.getX().isArrayRef()); + Assert.assertTrue(arrayBase.getX().isLocal()); + Assert.assertEquals(0, arrayBase.getY().intValue()); + + Val leftOp = stmt.getLeftOp(); + Assert.assertTrue(leftOp.isArrayRef()); + } } + + Assert.assertEquals(1, arrayStoreCount); + } } diff --git a/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootScopeTest.java b/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootScopeTest.java index 2ddeaba30..9f7dea357 100644 --- a/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootScopeTest.java +++ b/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootScopeTest.java @@ -16,7 +16,6 @@ import boomerang.scope.Statement; import boomerang.scope.Val; import boomerang.scope.soot.jimple.JimpleMethod; -import boomerang.scope.test.BoomerangScopeTests; import boomerang.scope.test.MethodSignature; import boomerang.scope.test.targets.A; import boomerang.scope.test.targets.HashCodeEqualsLocalTarget; diff --git a/boomerangScope/src/test/java/boomerang/scope/test/targets/ArrayTarget.java b/boomerangScope/src/test/java/boomerang/scope/test/targets/ArrayTarget.java index 1e09b89ad..25be86d90 100644 --- a/boomerangScope/src/test/java/boomerang/scope/test/targets/ArrayTarget.java +++ b/boomerangScope/src/test/java/boomerang/scope/test/targets/ArrayTarget.java @@ -1,33 +1,44 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ package boomerang.scope.test.targets; import java.util.Arrays; public class ArrayTarget { - public static void main(String[] args) { - singleArrayLoad(new int[]{1, 2}); - singleArrayStore(); + public static void main(String[] args) { + singleArrayLoad(new int[] {1, 2}); + singleArrayStore(); - multiArrayStore(); - } + multiArrayStore(); + } - public static void singleArrayLoad(int[] arr) { - int i = arr[1]; + public static void singleArrayLoad(int[] arr) { + int i = arr[1]; - System.out.println(i); - } + System.out.println(i); + } - public static void singleArrayStore() { - int[] arr = new int[2]; - arr[0] = 1; + public static void singleArrayStore() { + int[] arr = new int[2]; + arr[0] = 1; - System.out.println(Arrays.toString(arr)); - } + System.out.println(Arrays.toString(arr)); + } - public static void multiArrayStore() { - int[][] arr = new int[2][2]; - arr[0][0] = 1; + public static void multiArrayStore() { + int[][] arr = new int[2][2]; + arr[0][0] = 1; - System.out.println(Arrays.deepToString(arr)); - } + System.out.println(Arrays.deepToString(arr)); + } } diff --git a/boomerangScope/src/test/java/boomerang/scope/test/targets/AssignmentTarget.java b/boomerangScope/src/test/java/boomerang/scope/test/targets/AssignmentTarget.java index 23decc5fb..e497603e0 100644 --- a/boomerangScope/src/test/java/boomerang/scope/test/targets/AssignmentTarget.java +++ b/boomerangScope/src/test/java/boomerang/scope/test/targets/AssignmentTarget.java @@ -1,25 +1,36 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ package boomerang.scope.test.targets; import java.util.Arrays; public class AssignmentTarget { - public static void main(String[] args) { - arrayAllocation(); - constantAssignment(); - } + public static void main(String[] args) { + arrayAllocation(); + constantAssignment(); + } - public static void arrayAllocation() { - int[] arr = new int[]{1, 2}; + public static void arrayAllocation() { + int[] arr = new int[] {1, 2}; - System.out.println(Arrays.toString(arr)); - } + System.out.println(Arrays.toString(arr)); + } - public static void constantAssignment() { - int i = 10; - long l = 1000; - String s = "test"; + public static void constantAssignment() { + int i = 10; + long l = 1000; + String s = "test"; - System.out.println(i + l + " " + s); - } + System.out.println(i + l + " " + s); + } } diff --git a/boomerangScope/src/test/java/boomerang/scope/test/targets/InvokeExprTarget.java b/boomerangScope/src/test/java/boomerang/scope/test/targets/InvokeExprTarget.java index 60eb7873c..6d6188e27 100644 --- a/boomerangScope/src/test/java/boomerang/scope/test/targets/InvokeExprTarget.java +++ b/boomerangScope/src/test/java/boomerang/scope/test/targets/InvokeExprTarget.java @@ -1,26 +1,43 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ package boomerang.scope.test.targets; public class InvokeExprTarget { - public static void main(String[] args) { - instanceInvokeExpr(); - } + public static void main(String[] args) { + constructorCall(); + instanceInvokeExpr(); + alias(); + } - public static void instanceInvokeExpr() { - int i = 10; - A a = new A(); + public static void constructorCall() { + A a = new A(); + } - a.methodCall(i); - } + public static void instanceInvokeExpr() { + int i = 10; + A a = new A(); - public static void alias() { - int i = 10; - A a = new A(); + a.methodCall(i); + } - if (Math.random() > 0.5) { - i = 10000; - } + public static void alias() { + int i = 10; + A a = new A(); - a.methodCall(i); + if (Math.random() > 0.5) { + i = 10000; } + + a.methodCall(i); + } } diff --git a/testCore/src/main/java/test/setup/OpalTestSetup.java b/testCore/src/main/java/test/setup/OpalTestSetup.java index 139547f28..caa192d81 100644 --- a/testCore/src/main/java/test/setup/OpalTestSetup.java +++ b/testCore/src/main/java/test/setup/OpalTestSetup.java @@ -20,14 +20,6 @@ import java.net.URL; import java.util.List; import java.util.Set; - -import org.opalj.ai.AIResult; -import org.opalj.ai.AIResultBuilder; -import org.opalj.ai.BaseAI; -import org.opalj.ai.BaseAI$; -import org.opalj.ai.domain.l0.PrimitiveTACAIDomain; -import org.opalj.ai.fpcf.properties.AIDomainFactoryKey; -import org.opalj.ai.fpcf.properties.AIDomainFactoryKey$; import org.opalj.br.ClassFile; import org.opalj.br.MethodDescriptor$; import org.opalj.br.ObjectType; @@ -35,9 +27,6 @@ import org.opalj.log.DevNullLogger$; import org.opalj.log.GlobalLogContext$; import org.opalj.log.OPALLogger; -import org.opalj.tac.ComputeTACAIKey; -import org.opalj.tac.LazyDetachedTACAIKey; -import org.opalj.tac.TACAI; import org.opalj.tac.cg.CHACallGraphKey$; import org.opalj.tac.cg.CallGraph; import scala.Option; From 54579412a912840cdc88c4871185082df76f48fa Mon Sep 17 00:00:00 2001 From: Sven Meyer Date: Mon, 24 Mar 2025 13:27:29 +0100 Subject: [PATCH 22/61] Prepare for type propagation --- .../boomerang/scope/opal/OpalCallGraph.scala | 6 +-- .../scope/opal/tac/OpalArrayRef.scala | 3 +- .../scope/opal/tac/OpalControlFlowGraph.scala | 20 +++---- .../scope/opal/tac/OpalDoubleVal.scala | 3 +- .../scope/opal/tac/OpalIfStatement.scala | 3 +- .../scope/opal/tac/OpalInvokeExpr.scala | 5 +- .../boomerang/scope/opal/tac/OpalLocal.scala | 27 ++-------- .../boomerang/scope/opal/tac/OpalMethod.scala | 25 ++++----- .../scope/opal/tac/OpalStatement.scala | 36 ++----------- .../opal/tac/OpalStatementFormatter.scala | 52 +++++++++++++++++++ .../boomerang/scope/opal/tac/OpalVal.scala | 4 +- .../scope/opal/transformer/TacLocal.scala | 8 +-- .../opal/transformer/TacTransformer.scala | 44 ++++++++-------- .../scope/opal/OpalControlFlowGraphTest.scala | 6 ++- .../boomerang/scope/opal/OpalFieldTest.scala | 14 ++--- .../scope/opal/OpalInvokeExprTest.scala | 5 +- .../boomerang/scope/opal/OpalLocalTest.scala | 6 +-- 17 files changed, 139 insertions(+), 128 deletions(-) create mode 100644 boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatementFormatter.scala diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalCallGraph.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalCallGraph.scala index 52828ee2c..2689b73c5 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalCallGraph.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalCallGraph.scala @@ -3,8 +3,8 @@ package boomerang.scope.opal import boomerang.scope.CallGraph import boomerang.scope.CallGraph.Edge import boomerang.scope.opal.tac.{OpalMethod, OpalPhantomMethod, OpalStatement} +import boomerang.scope.opal.transformer.{BoomerangTACode, TacTransformer} import org.opalj.br.{DefinedMethod, Method, MultipleDefinedMethods, VirtualDeclaredMethod} -import org.opalj.tac.TACNaive class OpalCallGraph(callGraph: org.opalj.tac.cg.CallGraph, entryPoints: Set[Method]) extends CallGraph { @@ -19,9 +19,9 @@ class OpalCallGraph(callGraph: org.opalj.tac.cg.CallGraph, entryPoints: Set[Meth }) private def addEdgesFromMethod(method: DefinedMethod): Unit = { - val tacCode = TACNaive(method.definedMethod, OpalClient.getClassHierarchy) + val tacCode = TacTransformer(method.definedMethod, OpalClient.getClassHierarchy) - tacCode.stmts.foreach(stmt => { + tacCode.statements.foreach(stmt => { val srcStatement = new OpalStatement(stmt, OpalMethod(method.definedMethod, tacCode)) if (srcStatement.containsInvokeExpr()) { diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalArrayRef.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalArrayRef.scala index bca3ee83f..a6b4d258c 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalArrayRef.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalArrayRef.scala @@ -1,13 +1,14 @@ package boomerang.scope.opal.tac import boomerang.scope._ +import boomerang.scope.opal.transformer.TacLocal import org.opalj.br.ObjectType import org.opalj.tac.{DUVar, DVar, Expr, IdBasedVar, UVar, Var} import org.opalj.value.ValueInformation import java.util.Objects -class OpalArrayRef(val arrayRef: Expr[IdBasedVar], val index: Int, method: OpalMethod, unbalanced: ControlFlowGraph.Edge = null) extends Val(method, unbalanced) { +class OpalArrayRef(val arrayRef: Expr[TacLocal], val index: Int, method: OpalMethod, unbalanced: ControlFlowGraph.Edge = null) extends Val(method, unbalanced) { if (!arrayRef.isVar) { throw new RuntimeException("Array Ref has to be a variable") diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalControlFlowGraph.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalControlFlowGraph.scala index 3b765aa25..e0b1a5f33 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalControlFlowGraph.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalControlFlowGraph.scala @@ -50,36 +50,38 @@ class OpalControlFlowGraph(method: OpalMethod) extends ControlFlowGraph { if (cacheBuilt) return var headFound = false - method.tacCode.stmts.foreach(stmt => { + method.tac.statements.foreach(stmt => { // Definition of parameter locals have implicit PC of -1, so they are not part of the actual CFG if (stmt.pc != -1) { val statement = new OpalStatement(stmt, method) statements.add(statement) - val stmtPc = method.tacCode.pcToIndex(stmt.pc) + val stmtPc = method.tac.pcToIndex(stmt.pc) // The first statement after the parameter local definitions is the head if (!headFound) { - startPointCache.add(statement) headFound = true + + startPointCache.add(statement) + predsOfCache.putAll(statement, util.Collections.emptySet()) } else { - val predecessors = method.tacCode.cfg.predecessors(stmtPc) + val predecessors = method.tac.cfg.predecessors(stmtPc) predecessors.foreach(predecessorPc => { - val predecessor = method.tacCode.stmts(predecessorPc) + val predecessor = method.tac.statements(predecessorPc) val predecessorStatement = new OpalStatement(predecessor, method) predsOfCache.put(statement, predecessorStatement) }) } - val successors = method.tacCode.cfg.successors(stmtPc) + val successors = method.tac.cfg.successors(stmtPc) if (successors.isEmpty) { // No successors => Tail statement - val tailStmt = new OpalStatement(stmt, method) - endPointCache.add(tailStmt) + endPointCache.add(statement) + succsOfCache.putAll(statement, util.Collections.emptySet()) } else { successors.foreach(successorPc => { - val successor = method.tacCode.stmts(successorPc) + val successor = method.tac.statements(successorPc) val successorStatement = new OpalStatement(successor, method) succsOfCache.put(statement, successorStatement) diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalDoubleVal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalDoubleVal.scala index c52e95bd5..fcd10405f 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalDoubleVal.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalDoubleVal.scala @@ -1,12 +1,13 @@ package boomerang.scope.opal.tac +import boomerang.scope.opal.transformer.TacLocal import boomerang.scope.{Val, ValWithFalseVariable} import org.opalj.tac.{DUVar, Expr, IdBasedVar, Var} import org.opalj.value.ValueInformation import java.util.Objects -class OpalDoubleVal(delegate: Expr[IdBasedVar], method: OpalMethod, falseVal: Val) extends OpalVal(delegate, method) with ValWithFalseVariable { +class OpalDoubleVal(delegate: Expr[TacLocal], method: OpalMethod, falseVal: Val) extends OpalVal(delegate, method) with ValWithFalseVariable { override def getFalseVariable: Val = falseVal diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalIfStatement.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalIfStatement.scala index 1dffdcb64..47d568ae2 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalIfStatement.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalIfStatement.scala @@ -1,13 +1,14 @@ package boomerang.scope.opal.tac import boomerang.scope.opal.OpalClient +import boomerang.scope.opal.transformer.TacLocal import boomerang.scope.{IfStatement, Statement, Val} import org.opalj.tac.{DUVar, IdBasedVar, If, Var} import org.opalj.value.ValueInformation import java.util.Objects -class OpalIfStatement(val delegate: If[IdBasedVar], method: OpalMethod) extends IfStatement { +class OpalIfStatement(val delegate: If[TacLocal], method: OpalMethod) extends IfStatement { override def getTarget: Statement = { /*val tac = OpalClient.getTacForMethod(method.delegate) diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalInvokeExpr.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalInvokeExpr.scala index ee74a75ef..96fc60994 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalInvokeExpr.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalInvokeExpr.scala @@ -1,12 +1,13 @@ package boomerang.scope.opal.tac +import boomerang.scope.opal.transformer.TacLocal import boomerang.scope.{DeclaredMethod, InvokeExpr, Val} import org.opalj.tac._ import java.util import java.util.Objects -class OpalMethodInvokeExpr(val delegate: MethodCall[IdBasedVar], method: OpalMethod) extends InvokeExpr { +class OpalMethodInvokeExpr(val delegate: MethodCall[TacLocal], method: OpalMethod) extends InvokeExpr { override def getArg(index: Int): Val = getArgs.get(index) @@ -48,7 +49,7 @@ class OpalMethodInvokeExpr(val delegate: MethodCall[IdBasedVar], method: OpalMet override def toString: String = delegate.toString } -class OpalFunctionInvokeExpr(val delegate: FunctionCall[IdBasedVar], method: OpalMethod) extends InvokeExpr { +class OpalFunctionInvokeExpr(val delegate: FunctionCall[TacLocal], method: OpalMethod) extends InvokeExpr { override def getArg(index: Int): Val = getArgs.get(index) diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalLocal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalLocal.scala index 568e88261..e949d5cf2 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalLocal.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalLocal.scala @@ -1,30 +1,15 @@ package boomerang.scope.opal.tac import boomerang.scope._ +import boomerang.scope.opal.transformer.TacLocal import org.opalj.br.ObjectType -import org.opalj.tac.{DUVar, DVar, Expr, IdBasedVar, SimpleVar, UVar, Var} -import org.opalj.value.ValueInformation +import org.opalj.tac.Var import java.util.Objects -class OpalLocal(val delegate: Var[IdBasedVar], method: OpalMethod, unbalanced: ControlFlowGraph.Edge = null) extends Val(method, unbalanced) { - - override def getType: Type = delegate match { - /*case local: SimpleVar => - if (local.value.isReferenceValue) { - OpalType(local.value.asReferenceValue.asReferenceType, local.value.asReferenceValue.isNull.isYes) - } else if (local.value.isPrimitiveValue) { - OpalType(local.value.asPrimitiveValue.primitiveType) - } else if (local.value.isVoid) { - OpalType(ObjectType.Void) - } else if (local.value.isArrayValue.isYes) { - OpalType(ObjectType.Array) - } else { - throw new RuntimeException("Could not determine type " + local.value) - }*/ - case _ => throw new RuntimeException("Cannot compute type of expression that is not a variable") +class OpalLocal(val delegate: Var[TacLocal], method: OpalMethod, unbalanced: ControlFlowGraph.Edge = null) extends Val(method, unbalanced) { - } + override def getType: Type = OpalType(ObjectType("java/lang/Object")) override def isStatic: Boolean = false @@ -40,9 +25,7 @@ class OpalLocal(val delegate: Var[IdBasedVar], method: OpalMethod, unbalanced: C override def getArrayAllocationSize: Val = throw new RuntimeException("Opal local is not an array allocation expression") - override def isNull: Boolean = { - ??? - } + override def isNull: Boolean = false override def isStringConstant: Boolean = false diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalMethod.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalMethod.scala index e6b93410e..aee89a31f 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalMethod.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalMethod.scala @@ -2,14 +2,12 @@ package boomerang.scope.opal.tac import boomerang.scope._ import boomerang.scope.opal.OpalClient -import org.opalj.ai.domain.l0.PrimitiveTACAIDomain -import org.opalj.ai.domain.l1.DefaultDomainWithCFGAndDefUse -import org.opalj.tac.{InstanceFunctionCall, InstanceMethodCall, NaiveTACode, SimplePropagation, Stmt, TACAI, TACNaive, TACode} +import boomerang.scope.opal.transformer.{BoomerangTACode, TacTransformer} import java.util import java.util.Objects -class OpalMethod private(val delegate: org.opalj.br.Method, val tacCode: NaiveTACode[_]) extends Method { +class OpalMethod private(val delegate: org.opalj.br.Method, val tac: BoomerangTACode) extends Method { if (delegate.body.isEmpty) { throw new RuntimeException("Cannot build OpalMethod without existing body") @@ -51,7 +49,7 @@ class OpalMethod private(val delegate: org.opalj.br.Method, val tacCode: NaiveTA * is not used within the method, it stays at -1. However, if it is used, there is an additional * assignment to an actual variable. Therefore, we have to check first for the usage. */ - tacCode.stmts.foreach(stmt => { + tac.statements.foreach(stmt => { if (stmt.isAssignment && stmt.asAssignment.expr.isVar) { if (stmt.asAssignment.expr.asVar.id == -1) { return new OpalLocal(stmt.asAssignment.targetVar, this) @@ -60,7 +58,7 @@ class OpalMethod private(val delegate: org.opalj.br.Method, val tacCode: NaiveTA }) // 'this' local is not used; return just the parameter local - tacCode.stmts.foreach(stmt => { + tac.statements.foreach(stmt => { if (stmt.isAssignment && stmt.asAssignment.targetVar.id == -1) { return new OpalLocal(stmt.asAssignment.targetVar, this) } @@ -84,14 +82,11 @@ class OpalMethod private(val delegate: org.opalj.br.Method, val tacCode: NaiveTA // Parameter locals localCache.get.addAll(getParameterLocals) - tacCode.stmts.foreach(stmt => { + tac.statements.foreach(stmt => { if (stmt.isAssignment) { val targetVar = stmt.asAssignment.targetVar - // Parameters have been covered above - if (targetVar.id >= 0) { - localCache.get.add(new OpalLocal(targetVar, this)) - } + localCache.get.add(new OpalLocal(targetVar, this)) } }) } @@ -105,7 +100,7 @@ class OpalMethod private(val delegate: org.opalj.br.Method, val tacCode: NaiveTA val indices = new util.HashSet[Integer]() - tacCode.stmts.foreach(stmt => { + tac.statements.foreach(stmt => { if (stmt.isAssignment && stmt.asAssignment.expr.isVar) { val param = stmt.asAssignment.expr.asVar @@ -120,7 +115,7 @@ class OpalMethod private(val delegate: org.opalj.br.Method, val tacCode: NaiveTA }) // Collect all unused parameter locals - tacCode.stmts.foreach(stmt => { + tac.statements.foreach(stmt => { if (stmt.isAssignment) { val target = stmt.asAssignment.targetVar @@ -169,7 +164,7 @@ class OpalMethod private(val delegate: org.opalj.br.Method, val tacCode: NaiveTA object OpalMethod { - def apply(delegate: org.opalj.br.Method): OpalMethod = new OpalMethod(delegate, TACNaive(delegate, OpalClient.getClassHierarchy)) + def apply(delegate: org.opalj.br.Method): OpalMethod = new OpalMethod(delegate, TacTransformer(delegate, OpalClient.getClassHierarchy)) - def apply(delegate: org.opalj.br.Method, tacCode: NaiveTACode[_]): OpalMethod = new OpalMethod(delegate, tacCode) + def apply(delegate: org.opalj.br.Method, tac: BoomerangTACode): OpalMethod = new OpalMethod(delegate, tac) } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala index 9aa7a98f8..fe3595eac 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala @@ -1,6 +1,7 @@ package boomerang.scope.opal.tac import boomerang.scope._ +import boomerang.scope.opal.transformer.TacLocal import com.google.common.base.Joiner import org.opalj.tac.{DUVar, IdBasedVar, PrimitiveTypecastExpr, Stmt, Var} import org.opalj.value.ValueInformation @@ -8,7 +9,7 @@ import org.opalj.value.ValueInformation import java.util import java.util.Objects -class OpalStatement(val delegate: Stmt[IdBasedVar], m: OpalMethod) extends Statement(m) { +class OpalStatement(val delegate: Stmt[TacLocal], m: OpalMethod) extends Statement(m) { override def containsStaticFieldAccess(): Boolean = isStaticFieldLoad || isStaticFieldStore @@ -96,7 +97,6 @@ class OpalStatement(val delegate: Stmt[IdBasedVar], m: OpalMethod) extends State override def getLeftOp: Val = { if (isAssignStmt) { if (delegate.isAssignment) { - // TODO Change to variable return new OpalLocal(delegate.asAssignment.targetVar, m) } @@ -140,7 +140,7 @@ class OpalStatement(val delegate: Stmt[IdBasedVar], m: OpalMethod) extends State } if (rightExpr.isVar) { - return new OpalLocal(delegate.asAssignment.expr.asVar, m) + return new OpalLocal(rightExpr.asVar, m) } return new OpalVal(delegate.asAssignment.expr, m) @@ -308,33 +308,5 @@ class OpalStatement(val delegate: Stmt[IdBasedVar], m: OpalMethod) extends State case _ => false } - override def toString: String = { - if (containsInvokeExpr()) { - var base = "" - if (getInvokeExpr.isInstanceInvokeExpr) { - base = s"${getInvokeExpr.getBase}." - } - var assign = "" - if (isAssignStmt) { - assign = s"$getLeftOp = " - } - - return s"${delegate.pc}: $assign$base${getInvokeExpr.getMethod.getName}(${Joiner.on(",").join(getInvokeExpr.getArgs)})" - } - - if (isAssignStmt) { - if (delegate.isAssignment) { - if (isFieldStore) { - return s"${delegate.pc}: $getLeftOp = ${getFieldStore.getX}.${getFieldStore.getY}" - } else if (isArrayStore) { - val base = getArrayBase - return s"${delegate.pc}: ${base.getX.getVariableName}[${base.getY}] = $getRightOp" - } else { - return s"${delegate.pc}: $getLeftOp = $getRightOp" - } - } - } - - delegate.toString - } + override def toString: String = OpalStatementFormatter(this) } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatementFormatter.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatementFormatter.scala new file mode 100644 index 000000000..cc0a04b82 --- /dev/null +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatementFormatter.scala @@ -0,0 +1,52 @@ +package boomerang.scope.opal.tac + +import com.google.common.base.Joiner +import org.opalj.tac.{Nop, Return} + +object OpalStatementFormatter { + + def apply(stmt: OpalStatement): String = { + val delegate = stmt.delegate + + if (stmt.containsInvokeExpr()) { + var base = "" + if (stmt.getInvokeExpr.isInstanceInvokeExpr) { + base = s"${stmt.getInvokeExpr.getBase}." + } + var assign = "" + if (stmt.isAssignStmt) { + assign = s"${stmt.getLeftOp} = " + } + + return s"${delegate.pc}: $assign$base${stmt.getInvokeExpr.getMethod.getName}(${Joiner.on(",").join(stmt.getInvokeExpr.getArgs)})" + } + + if (stmt.isAssignStmt) { + if (delegate.isAssignment) { + if (stmt.isFieldStore) { + return s"${delegate.pc}: ${stmt.getLeftOp} = ${stmt.getFieldStore.getX}.${stmt.getFieldStore.getY}" + } else if (stmt.isArrayStore) { + val base = stmt.getArrayBase + return s"${delegate.pc}: ${base.getX.getVariableName}[${base.getY}] = ${stmt.getRightOp}" + } else { + return s"${delegate.pc}: ${stmt.getLeftOp} = ${stmt.getRightOp}" + } + } + } + + if (delegate.astID == Nop.ASTID) { + return s"${delegate.pc}: nop" + } + + if (delegate.astID == Return.ASTID) { + return s"${delegate.pc}: return" + } + + if (stmt.isReturnStmt) { + return s"${delegate.pc}: return ${stmt.getReturnOp}" + } + + delegate.toString + } + +} diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalVal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalVal.scala index a919520bd..01e0a677e 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalVal.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalVal.scala @@ -2,12 +2,13 @@ package boomerang.scope.opal.tac import boomerang.scope.opal.OpalClient import boomerang.scope._ +import boomerang.scope.opal.transformer.TacLocal import org.opalj.br.ReferenceType import org.opalj.tac._ import java.util.Objects -class OpalVal(val delegate: Expr[IdBasedVar], method: OpalMethod, unbalanced: ControlFlowGraph.Edge = null) extends Val(method, unbalanced) { +class OpalVal(val delegate: Expr[TacLocal], method: OpalMethod, unbalanced: ControlFlowGraph.Edge = null) extends Val(method, unbalanced) { if (delegate.isVar) { throw new RuntimeException("OpalVal cannot hold a variable (use OpalLocal)") @@ -17,6 +18,7 @@ class OpalVal(val delegate: Expr[IdBasedVar], method: OpalMethod, unbalanced: Co case const: Const => OpalType(const.tpe) case newExpr: New => OpalType(newExpr.tpe) case newArrayExpr: NewArray[_] => OpalType(newArrayExpr.tpe) + case nullExpr: NullExpr => OpalType(nullExpr.tpe) case functionCall: FunctionCall[_] => OpalType(functionCall.descriptor.returnType) case _ => throw new RuntimeException("Type not implemented yet") } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacLocal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacLocal.scala index d9f0e67f0..16706ee07 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacLocal.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacLocal.scala @@ -6,7 +6,7 @@ import org.opalj.value.ValueInformation import java.util.Objects -sealed trait TacLocal extends Var[TacLocal] { +trait TacLocal extends Var[TacLocal] { def id: Int @@ -14,6 +14,8 @@ sealed trait TacLocal extends Var[TacLocal] { def isRegisterLocal: Boolean + def cTpe: ComputationalType + final def isSideEffectFree: Boolean = true override def toCanonicalForm(implicit ev: TacLocal <:< DUVar[ValueInformation]): Nothing = { @@ -35,7 +37,7 @@ class StackLocal(identifier: Int, computationalType: ComputationalType) extends override def cTpe: ComputationalType = computationalType - override def hashCode: Int = Objects.hash(identifier) + override def hashCode: Int = Objects.hash(id) override def equals(other: Any): Boolean = other match { case that: StackLocal => this.id == that.id @@ -57,7 +59,7 @@ class RegisterLocal(identifier: Int, computationalType: ComputationalType) exten override def cTpe: ComputationalType = computationalType - override def hashCode: Int = Objects.hash(identifier) + override def hashCode: Int = Objects.hash(id) override def equals(other: Any): Boolean = other match { case that: RegisterLocal => this.id == that.id diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacTransformer.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacTransformer.scala index c8ca417fd..6e2ba0c29 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacTransformer.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacTransformer.scala @@ -12,20 +12,18 @@ object TacTransformer { private var stackCounter = 0 private var currentStack = mutable.Map.empty[Int, TacLocal] - def apply(tacCode: NaiveTACode[_]): Array[Stmt[TacLocal]] = { + def apply(method: Method, classHierarchy: ClassHierarchy, optimizations: List[TACOptimization[Param, IdBasedVar, NaiveTACode[Param]]] = List.empty): BoomerangTACode = { stackCounter = 0 currentStack = mutable.Map.empty[Int, TacLocal] - val updatedTacCode = tacCode.stmts.map(stmt => transformStatement(stmt)) - - updatedTacCode - } - - def apply(method: Method, classHierarchy: ClassHierarchy, optimizations: List[TACOptimization[Param, IdBasedVar, NaiveTACode[Param]]] = List.empty): BoomerangTACode = { val tacNaive = TACNaive(method, classHierarchy, optimizations) - val transformedTac: Array[Stmt[TacLocal]] = tacNaive.stmts.map(stmt => transformStatement(stmt)) + tacNaive.stmts.foreach(stmt => { + val locals = method.body.get.localVariablesAt(stmt.pc) + println(locals) + }) + // Update the CFG val cfg = CFGFactory(method, classHierarchy) if (cfg.isEmpty) { @@ -85,11 +83,11 @@ object TacTransformer { } if (stmt.astID == Return.ASTID) { - return stmt.asReturn + return Return(stmt.asReturn.pc) } if (stmt.astID == Nop.ASTID) { - return stmt.asNop + return Nop(stmt.asNop.pc) } if (stmt.astID == MonitorEnter.ASTID) { @@ -219,47 +217,47 @@ object TacTransformer { } if (expr.astID == Param.ASTID) { - return expr.asParam + return Param(expr.asParam.cTpe, expr.asParam.name) } if (expr.astID == MethodTypeConst.ASTID) { - return expr.asMethodTypeConst + return MethodTypeConst(expr.asMethodTypeConst.pc, expr.asMethodTypeConst.value) } if (expr.astID == MethodHandleConst.ASTID) { - return expr.asMethodHandleConst + return MethodHandleConst(expr.asMethodHandleConst.pc, expr.asMethodHandleConst.value) } if (expr.astID == IntConst.ASTID) { - return expr.asIntConst + return IntConst(expr.asIntConst.pc, expr.asIntConst.value) } if (expr.astID == LongConst.ASTID) { - return expr.asFloatConst + return LongConst(expr.asLongConst.pc, expr.asLongConst.value) } if (expr.astID == FloatConst.ASTID) { - return expr.asFloatConst + return FloatConst(expr.asFloatConst.pc, expr.asFloatConst.value) } if (expr.astID == DoubleConst.ASTID) { - return expr.asDoubleConst + return DoubleConst(expr.asDoubleConst.pc, expr.asDoubleConst.value) } if (expr.astID == StringConst.ASTID) { - return expr.asStringConst + return StringConst(expr.asStringConst.pc, expr.asStringConst.value) } if (expr.astID == ClassConst.ASTID) { - return expr.asClassConst + return ClassConst(expr.asClassConst.pc, expr.asClassConst.value) } if (expr.astID == DynamicConst.ASTID) { - return expr.asDynamicConst + return DynamicConst(expr.asDynamicConst.pc, expr.asDynamicConst.bootstrapMethod, expr.asDynamicConst.name, expr.asDynamicConst.descriptor) } if (expr.astID == NullExpr.ASTID) { - return expr.asNullExpr + return NullExpr(expr.asNullExpr.pc) } if (expr.astID == BinaryExpr.ASTID) { @@ -286,7 +284,7 @@ object TacTransformer { } if (expr.astID == New.ASTID) { - return expr.asNew + return New(expr.asNew.pc, expr.asNew.tpe) } if (expr.astID == NewArray.ASTID) { @@ -320,7 +318,7 @@ object TacTransformer { } if (expr.astID == GetStatic.ASTID) { - return expr.asGetStatic + return GetStatic(expr.asGetStatic.pc, expr.asGetStatic.declaringClass, expr.asGetStatic.name, expr.asGetStatic.declaredFieldType) } if (expr.astID == InvokedynamicFunctionCall.ASTID) { diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalControlFlowGraphTest.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalControlFlowGraphTest.scala index cb7ec359d..2e828c9fd 100644 --- a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalControlFlowGraphTest.scala +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalControlFlowGraphTest.scala @@ -4,9 +4,7 @@ import boomerang.scope.opal.tac.OpalMethod import boomerang.scope.test.MethodSignature import boomerang.scope.test.targets.ControlFlowGraphTarget import org.junit.{Assert, Test} -import org.opalj.ai.domain.l1.DefaultDomainWithCFGAndDefUse import org.opalj.br.IntegerType -import org.opalj.tac.TACAI class OpalControlFlowGraphTest { @@ -25,6 +23,10 @@ class OpalControlFlowGraphTest { Assert.assertTrue(cfg.getStatements.size() > 0) Assert.assertEquals(1, cfg.getStartPoints.size()) Assert.assertEquals(2, cfg.getEndPoints.size()) + + cfg.getEndPoints.forEach(stmt => { + Assert.assertTrue(stmt.isReturnStmt) + }) } } diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalFieldTest.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalFieldTest.scala index 8186e2222..dce566083 100644 --- a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalFieldTest.scala +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalFieldTest.scala @@ -26,11 +26,11 @@ class OpalFieldTest { Assert.assertFalse(field.isInnerClassField) val fieldLoad = stmt.getFieldLoad - Assert.assertTrue(fieldLoad.getX.getType.toString.equals(classOf[FieldClass].getName)) + //Assert.assertTrue(fieldLoad.getX.getType.toString.equals(classOf[FieldClass].getName)) val fieldType = fieldLoad.getY.getType.toString Assert.assertFalse(fieldLoad.getY.isPredefinedField) - Assert.assertTrue(fieldType.equals("int") || fieldType.equals(classOf[A].getName)) + //Assert.assertTrue(fieldType.equals("int") || fieldType.equals(classOf[A].getName)) } }) @@ -57,7 +57,7 @@ class OpalFieldTest { val fieldType = fieldStore.getY.getType.toString Assert.assertFalse(fieldStore.getY.isPredefinedField) Assert.assertFalse(fieldStore.getY.isInnerClassField) - Assert.assertTrue(fieldType.equals("int") || fieldType.equals(classOf[A].getName)) + //Assert.assertTrue(fieldType.equals("int") || fieldType.equals(classOf[A].getName)) } }) @@ -83,7 +83,7 @@ class OpalFieldTest { Assert.assertFalse(staticField.field().isInnerClassField) val typeName = staticField.getType.toString - Assert.assertTrue(typeName.equals("int") || typeName.equals(classOf[A].getName)) + //Assert.assertTrue(typeName.equals("int") || typeName.equals(classOf[A].getName)) } }) @@ -109,7 +109,7 @@ class OpalFieldTest { Assert.assertFalse(staticField.field().isInnerClassField) val typeName = staticField.getType.toString - Assert.assertTrue(typeName.equals("int") || typeName.equals(classOf[A].getName)) + //Assert.assertTrue(typeName.equals("int") || typeName.equals(classOf[A].getName)) } }) @@ -139,7 +139,7 @@ class OpalFieldTest { val fieldType = fieldLoad.getY.getType.toString Assert.assertFalse(fieldLoad.getY.isPredefinedField) - Assert.assertTrue(fieldType.equals("int") || fieldType.equals(classOf[A].getName)) + //Assert.assertTrue(fieldType.equals("int") || fieldType.equals(classOf[A].getName)) } }) @@ -166,7 +166,7 @@ class OpalFieldTest { val fieldType = fieldStore.getY.getType.toString Assert.assertFalse(fieldStore.getY.isPredefinedField) Assert.assertTrue(fieldStore.getY.isInnerClassField) - Assert.assertTrue(fieldType.equals("int") || fieldType.equals(classOf[A].getName)) + //Assert.assertTrue(fieldType.equals("int") || fieldType.equals(classOf[A].getName)) } }) diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala index f5136b5fc..eb8acb78e 100644 --- a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala @@ -1,7 +1,6 @@ package boomerang.scope.opal import boomerang.scope.opal.tac.OpalMethod -import boomerang.scope.opal.transformer.TacTransformer import boomerang.scope.test.MethodSignature import boomerang.scope.test.targets.InvokeExprTarget import org.junit.Test @@ -16,9 +15,9 @@ class OpalInvokeExprTest { val signature = new MethodSignature(classOf[InvokeExprTarget].getName, "alias", "Void") val method = opalSetup.resolveMethod(signature) val opalMethod = OpalMethod(method) + opalMethod.getControlFlowGraph - val transformedTac = TacTransformer(opalMethod.tacCode) - println(transformedTac.mkString("Array(", "\n", ")")) + println(opalMethod.tac.statements.mkString("Array(\n\t", "\n\t", "\n)")) } } diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalLocalTest.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalLocalTest.scala index 7b4cc115b..22cc2ad89 100644 --- a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalLocalTest.scala +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalLocalTest.scala @@ -81,7 +81,7 @@ class OpalLocalTest { val oneArgMethod = OpalMethod(oneArg) Assert.assertEquals(1, oneArgMethod.getParameterLocals.size) - Assert.assertEquals("int", oneArgMethod.getParameterLocal(0).getType.toString) + //Assert.assertEquals("int", oneArgMethod.getParameterLocal(0).getType.toString) // Two parameters (primitive type + RefType) val twoArgSignature = new MethodSignature(classOf[ParameterLocalsTarget].getName, "twoParameters", "Void", util.List.of(integerType, s"L${classOf[A].getName}L")) @@ -89,8 +89,8 @@ class OpalLocalTest { val twoArgsMethod = OpalMethod(twoArgs) Assert.assertEquals(2, twoArgsMethod.getParameterLocals.size) - Assert.assertEquals("int", twoArgsMethod.getParameterLocal(0).getType.toString) - Assert.assertEquals(classOf[A].getName, twoArgsMethod.getParameterLocal(1).getType.toString) + //Assert.assertEquals("int", twoArgsMethod.getParameterLocal(0).getType.toString) + //Assert.assertEquals(classOf[A].getName, twoArgsMethod.getParameterLocal(1).getType.toString) } @Test From da9c729b8af267c22544068b81bae7a72c11dbb8 Mon Sep 17 00:00:00 2001 From: Sven Meyer Date: Tue, 25 Mar 2025 10:26:06 +0100 Subject: [PATCH 23/61] Add type information to locals --- .../solver/AbstractBoomerangSolver.java | 1 + .../scope/opal/tac/OpalControlFlowGraph.scala | 6 +- .../boomerang/scope/opal/tac/OpalLocal.scala | 11 +- .../boomerang/scope/opal/tac/OpalMethod.scala | 59 +-- .../boomerang/scope/opal/tac/OpalType.scala | 4 +- .../boomerang/scope/opal/tac/OpalVal.scala | 2 +- .../opal/transformer/BoomerangTACode.scala | 9 +- .../scope/opal/transformer/TacLocal.scala | 46 +- .../opal/transformer/TacTransformer.scala | 499 +++++++++--------- .../boomerang/scope/opal/OpalLocalTest.scala | 6 +- .../scope/test/targets/InvokeExprTarget.java | 10 + .../test/targets/ParameterLocalsTarget.java | 2 +- 12 files changed, 347 insertions(+), 308 deletions(-) diff --git a/boomerangPDS/src/main/java/boomerang/solver/AbstractBoomerangSolver.java b/boomerangPDS/src/main/java/boomerang/solver/AbstractBoomerangSolver.java index 58dfcbb1d..5ba2f911f 100644 --- a/boomerangPDS/src/main/java/boomerang/solver/AbstractBoomerangSolver.java +++ b/boomerangPDS/src/main/java/boomerang/solver/AbstractBoomerangSolver.java @@ -522,6 +522,7 @@ protected boolean preventFieldTransitionAdd( } if (!(targetVal.isRefType()) || !(sourceVal.isRefType())) { // A null pointer cannot be cast to any object + // TODO This should be more target.isNull return options.killNullAtCast() && targetVal.isNullType() && isCastNode( diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalControlFlowGraph.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalControlFlowGraph.scala index e0b1a5f33..0dcd0152b 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalControlFlowGraph.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalControlFlowGraph.scala @@ -51,11 +51,11 @@ class OpalControlFlowGraph(method: OpalMethod) extends ControlFlowGraph { var headFound = false method.tac.statements.foreach(stmt => { + val statement = new OpalStatement(stmt, method) + statements.add(statement) + // Definition of parameter locals have implicit PC of -1, so they are not part of the actual CFG if (stmt.pc != -1) { - val statement = new OpalStatement(stmt, method) - statements.add(statement) - val stmtPc = method.tac.pcToIndex(stmt.pc) // The first statement after the parameter local definitions is the head diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalLocal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalLocal.scala index e949d5cf2..ffc611425 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalLocal.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalLocal.scala @@ -9,7 +9,16 @@ import java.util.Objects class OpalLocal(val delegate: Var[TacLocal], method: OpalMethod, unbalanced: ControlFlowGraph.Edge = null) extends Val(method, unbalanced) { - override def getType: Type = OpalType(ObjectType("java/lang/Object")) + override def getType: Type = { + val value = delegate.asVar.value + + if (value.isPrimitiveValue) return OpalType(value.asPrimitiveValue.primitiveType) + if (value.isReferenceValue) return OpalType(value.asReferenceValue.asReferenceType) + if (value.isVoid) return OpalType(ObjectType.Void) + + // TODO Array and illegal types + throw new RuntimeException("Type not implemented yet") + } override def isStatic: Boolean = false diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalMethod.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalMethod.scala index aee89a31f..b41769637 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalMethod.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalMethod.scala @@ -45,22 +45,13 @@ class OpalMethod private(val delegate: org.opalj.br.Method, val tac: BoomerangTA override def getThisLocal: Val = { if (!isStatic) { - /* The 'this' local is implicitly defined as parameter local with id -1. If the 'this' local - * is not used within the method, it stays at -1. However, if it is used, there is an additional - * assignment to an actual variable. Therefore, we have to check first for the usage. - */ tac.statements.foreach(stmt => { - if (stmt.isAssignment && stmt.asAssignment.expr.isVar) { - if (stmt.asAssignment.expr.asVar.id == -1) { - return new OpalLocal(stmt.asAssignment.targetVar, this) - } - } - }) + if (stmt.pc == -1) { + val targetVar = stmt.asAssignment.targetVar - // 'this' local is not used; return just the parameter local - tac.statements.foreach(stmt => { - if (stmt.isAssignment && stmt.asAssignment.targetVar.id == -1) { - return new OpalLocal(stmt.asAssignment.targetVar, this) + if (targetVar.id == -1) { + return new OpalLocal(targetVar, this) + } } }) @@ -74,7 +65,8 @@ class OpalMethod private(val delegate: org.opalj.br.Method, val tac: BoomerangTA if (localCache.isEmpty) { localCache = Some(new util.HashSet[Val]()) - // 'this' local + tac.getLocals.foreach(l => localCache.get.add(new OpalLocal(l, this))) + /*// 'this' local if (!isStatic) { localCache.get.add(getThisLocal) } @@ -88,7 +80,7 @@ class OpalMethod private(val delegate: org.opalj.br.Method, val tac: BoomerangTA localCache.get.add(new OpalLocal(targetVar, this)) } - }) + })*/ } localCache.get @@ -98,35 +90,12 @@ class OpalMethod private(val delegate: org.opalj.br.Method, val tac: BoomerangTA if (parameterLocalCache.isEmpty) { parameterLocalCache = Some(new util.ArrayList[Val]()) - val indices = new util.HashSet[Integer]() - - tac.statements.foreach(stmt => { - if (stmt.isAssignment && stmt.asAssignment.expr.isVar) { - val param = stmt.asAssignment.expr.asVar - - // Exclude the 'this' local - if (param.id < 0 && param.id != -1) { - val paramLocal = new OpalLocal(stmt.asAssignment.targetVar, this) - - parameterLocalCache.get.add(paramLocal) - indices.add(param.id) - } - } - }) - - // Collect all unused parameter locals - tac.statements.foreach(stmt => { - if (stmt.isAssignment) { - val target = stmt.asAssignment.targetVar - - // Exclude 'this' local - if (target.id < 0 && target.id != -1) { - if (!indices.contains(target.id)) { - val paramLocal = new OpalLocal(target, this) - - parameterLocalCache.get.add(paramLocal) - } - } + tac.getParameterLocals.foreach(l => { + // Exclude the 'this' local from the parameters if this is an instance method + if (isStatic) { + parameterLocalCache.get.add(new OpalLocal(l, this)) + } else if (l.id != -1) { + parameterLocalCache.get.add(new OpalLocal(l, this)) } }) } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalType.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalType.scala index 356088ab7..597ebdad0 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalType.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalType.scala @@ -4,9 +4,9 @@ import boomerang.scope.opal.OpalClient import boomerang.scope.{AllocVal, Type, Val, WrappedClass} import org.opalj.br.ObjectType -case class OpalType(delegate: org.opalj.br.Type, isNull: Boolean = false) extends Type { +case class OpalType(delegate: org.opalj.br.Type) extends Type { - override def isNullType: Boolean = isNull + override def isNullType: Boolean = false override def isRefType: Boolean = delegate.isObjectType diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalVal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalVal.scala index 01e0a677e..d450b9c84 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalVal.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalVal.scala @@ -15,10 +15,10 @@ class OpalVal(val delegate: Expr[TacLocal], method: OpalMethod, unbalanced: Cont } override def getType: Type = delegate match { + case nullExpr: NullExpr => OpalType(nullExpr.tpe) case const: Const => OpalType(const.tpe) case newExpr: New => OpalType(newExpr.tpe) case newArrayExpr: NewArray[_] => OpalType(newArrayExpr.tpe) - case nullExpr: NullExpr => OpalType(nullExpr.tpe) case functionCall: FunctionCall[_] => OpalType(functionCall.descriptor.returnType) case _ => throw new RuntimeException("Type not implemented yet") } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/BoomerangTACode.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/BoomerangTACode.scala index 9f9c38ce6..e719e0728 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/BoomerangTACode.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/BoomerangTACode.scala @@ -2,7 +2,7 @@ package boomerang.scope.opal.transformer import org.opalj.br.ExceptionHandlers import org.opalj.br.cfg.CFG -import org.opalj.tac.{Param, Parameters, Stmt, TACStmts} +import org.opalj.tac.{Assignment, Param, Parameters, Stmt, TACStmts} class BoomerangTACode( val params: Parameters[Param], @@ -10,4 +10,9 @@ class BoomerangTACode( val pcToIndex: Array[Int], val cfg: CFG[Stmt[TacLocal], TACStmts[TacLocal]], val exceptionHandlers: ExceptionHandlers - ) {} + ) { + + def getLocals: Set[TacLocal] = statements.filter(stmt => stmt.astID == Assignment.ASTID).map(stmt => stmt.asAssignment.targetVar).toSet + + def getParameterLocals: List[TacLocal] = statements.filter(stmt => stmt.pc == -1).map(stmt => stmt.asAssignment.targetVar).toList +} diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacLocal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacLocal.scala index 16706ee07..4869721c5 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacLocal.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacLocal.scala @@ -14,8 +14,12 @@ trait TacLocal extends Var[TacLocal] { def isRegisterLocal: Boolean + def isParameterLocal: Boolean + def cTpe: ComputationalType + def value: ValueInformation + final def isSideEffectFree: Boolean = true override def toCanonicalForm(implicit ev: TacLocal <:< DUVar[ValueInformation]): Nothing = { @@ -23,9 +27,11 @@ trait TacLocal extends Var[TacLocal] { "TacLocal objects are not expected to inherit from DUVar" ) } + + override def toString: String = name } -class StackLocal(identifier: Int, computationalType: ComputationalType) extends TacLocal { +class StackLocal(identifier: Int, computationalType: ComputationalType, valueInfo: ValueInformation) extends TacLocal { override def id: Int = identifier @@ -33,21 +39,23 @@ class StackLocal(identifier: Int, computationalType: ComputationalType) extends override def isRegisterLocal: Boolean = false + override def isParameterLocal: Boolean = false + override def name: String = s"$$s$identifier" override def cTpe: ComputationalType = computationalType + override def value: ValueInformation = valueInfo + override def hashCode: Int = Objects.hash(id) override def equals(other: Any): Boolean = other match { case that: StackLocal => this.id == that.id case _ => false } - - override def toString: String = name } -class RegisterLocal(identifier: Int, computationalType: ComputationalType) extends TacLocal { +class RegisterLocal(identifier: Int, computationalType: ComputationalType, valueInfo: ValueInformation) extends TacLocal { override def id: Int = identifier @@ -55,18 +63,44 @@ class RegisterLocal(identifier: Int, computationalType: ComputationalType) exten override def isRegisterLocal: Boolean = true + override def isParameterLocal: Boolean = false + override def name: String = s"r${-identifier - 1}" override def cTpe: ComputationalType = computationalType + override def value: ValueInformation = valueInfo + override def hashCode: Int = Objects.hash(id) override def equals(other: Any): Boolean = other match { case that: RegisterLocal => this.id == that.id case _ => false } - - override def toString: String = name } +class ParameterLocal(identifier: Int, computationalType: ComputationalType, paramName: String) extends TacLocal { + + override def id: Int = identifier + + override def isStackLocal: Boolean = false + + override def isRegisterLocal: Boolean = false + + override def isParameterLocal: Boolean = true + + override def cTpe: ComputationalType = computationalType + + override def value: ValueInformation = throw new UnsupportedOperationException("No value information available for parameter local") + + override def name: String = paramName + + override def hashCode: Int = Objects.hash(id) + + override def equals(other: Any): Boolean = other match { + case that: ParameterLocal => this.id == that.id + case _ => false + } +} +// TODO Consider TempLocal in SWAP diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacTransformer.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacTransformer.scala index 6e2ba0c29..920f0a1d9 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacTransformer.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacTransformer.scala @@ -1,5 +1,8 @@ package boomerang.scope.opal.transformer +import boomerang.scope.opal.OpalClient +import org.opalj.ai.domain.l0.PrimitiveTACAIDomain +import org.opalj.ai.{AIResult, BaseAI} import org.opalj.br.{ClassHierarchy, Method} import org.opalj.br.cfg.CFGFactory import org.opalj.collection.immutable.IntIntPair @@ -9,352 +12,360 @@ import scala.collection.mutable object TacTransformer { - private var stackCounter = 0 - private var currentStack = mutable.Map.empty[Int, TacLocal] - def apply(method: Method, classHierarchy: ClassHierarchy, optimizations: List[TACOptimization[Param, IdBasedVar, NaiveTACode[Param]]] = List.empty): BoomerangTACode = { - stackCounter = 0 - currentStack = mutable.Map.empty[Int, TacLocal] + var paramCounter = -1 + var stackCounter = -1 + val currentStack = mutable.Map.empty[Int, TacLocal] + + val aiResult: AIResult = BaseAI(method, new PrimitiveTACAIDomain(OpalClient.getClassHierarchy, method)) + val operandsArray: aiResult.domain.OperandsArray = aiResult.operandsArray + val localArray = aiResult.localsArray val tacNaive = TACNaive(method, classHierarchy, optimizations) - val transformedTac: Array[Stmt[TacLocal]] = tacNaive.stmts.map(stmt => transformStatement(stmt)) - tacNaive.stmts.foreach(stmt => { - val locals = method.body.get.localVariablesAt(stmt.pc) - println(locals) - }) + def transformStatement(stmt: Stmt[IdBasedVar]): Stmt[TacLocal] = { + if (stmt.astID == If.ASTID) { + val ifStmt = stmt.asIf - // Update the CFG - val cfg = CFGFactory(method, classHierarchy) - if (cfg.isEmpty) { - throw new RuntimeException("Could not compute CFG for method " + method.name) - } + val left = transformExpr(ifStmt.left) + val right = transformExpr(ifStmt.right) - val tacCfg = cfg.get.mapPCsToIndexes[Stmt[TacLocal], TACStmts[TacLocal]](TACStmts(transformedTac), tacNaive.pcToIndex, i => i, transformedTac.length) + return If(ifStmt.pc, left, ifStmt.condition, right, ifStmt.targetStmt) + } - new BoomerangTACode(tacNaive.params, transformedTac, tacNaive.pcToIndex, tacCfg, tacNaive.exceptionHandlers) - } + if (stmt.astID == Goto.ASTID) { + return stmt.asGoto + } - private def transformStatement(stmt: Stmt[IdBasedVar]): Stmt[TacLocal] = { - if (stmt.astID == If.ASTID) { - val ifStmt = stmt.asIf + if (stmt.astID == Ret.ASTID) { + return stmt.asRet + } - val left = transformExpr(ifStmt.left) - val right = transformExpr(ifStmt.right) + if (stmt.astID == JSR.ASTID) { + return stmt.asJSR + } - return If(ifStmt.pc, left, ifStmt.condition, right, ifStmt.targetStmt) - } + if (stmt.astID == Switch.ASTID) { + val switchStmt = stmt.asSwitch + val index = transformExpr(switchStmt.index) - if (stmt.astID == Goto.ASTID) { - return stmt.asGoto - } + // Inserting -1 as it is only used in previous remapping steps + return Switch(switchStmt.pc, switchStmt.defaultStmt, index, switchStmt.caseStmts.map(p => IntIntPair(-1, p))) + } - if (stmt.astID == Ret.ASTID) { - return stmt.asRet - } + if (stmt.astID == Assignment.ASTID) { + val target = createNewLocal(stmt.pc, stmt.asAssignment.targetVar) + val transformedExpr = transformExpr(stmt.asAssignment.expr) - if (stmt.astID == JSR.ASTID) { - return stmt.asJSR - } + // Store the current stack and register locals on our own 'stack' + currentStack(stmt.asAssignment.targetVar.id) = target - if (stmt.astID == Switch.ASTID) { - val switchStmt = stmt.asSwitch - val index = transformExpr(switchStmt.index) + return new Assignment[TacLocal](stmt.pc, target, transformedExpr) + } - // Inserting -1 as it is only used in previous remapping steps - return Switch(switchStmt.pc, switchStmt.defaultStmt, index, switchStmt.caseStmts.map(p => IntIntPair(-1, p))) - } + if (stmt.astID == ReturnValue.ASTID) { + val returnStmt = stmt.asReturnValue + val returnValue = transformExpr(returnStmt.expr) - if (stmt.astID == Assignment.ASTID) { - val target = createNewLocal(stmt.asAssignment.targetVar) - val transformedExpr = transformExpr(stmt.asAssignment.expr) + return ReturnValue(returnStmt.pc, returnValue) + } - // Store the current stack and register locals on our own 'stack' - currentStack(stmt.asAssignment.targetVar.id) = target + if (stmt.astID == Return.ASTID) { + return Return(stmt.asReturn.pc) + } - return new Assignment[TacLocal](stmt.pc, target, transformedExpr) - } + if (stmt.astID == Nop.ASTID) { + return Nop(stmt.asNop.pc) + } - if (stmt.astID == ReturnValue.ASTID) { - val returnStmt = stmt.asReturnValue - val returnValue = transformExpr(returnStmt.expr) + if (stmt.astID == MonitorEnter.ASTID) { + val monitorEnter = stmt.asMonitorEnter + val objRef = transformExpr(monitorEnter.objRef) - return ReturnValue(returnStmt.pc, returnValue) - } + return MonitorEnter(monitorEnter.pc, objRef) + } - if (stmt.astID == Return.ASTID) { - return Return(stmt.asReturn.pc) - } + if (stmt.astID == MonitorExit.ASTID) { + val monitorExit = stmt.asMonitorExit + val objRef = transformExpr(monitorExit.objRef) - if (stmt.astID == Nop.ASTID) { - return Nop(stmt.asNop.pc) - } + return MonitorExit(monitorExit.pc, objRef) + } - if (stmt.astID == MonitorEnter.ASTID) { - val monitorEnter = stmt.asMonitorEnter - val objRef = transformExpr(monitorEnter.objRef) + if (stmt.astID == ArrayStore.ASTID) { + val arrayStore = stmt.asArrayStore - return MonitorEnter(monitorEnter.pc, objRef) - } + val arrayRef = transformExpr(arrayStore.arrayRef) + val index = transformExpr(arrayStore.index) + val value = transformExpr(arrayStore.index) - if (stmt.astID == MonitorExit.ASTID) { - val monitorExit = stmt.asMonitorExit - val objRef = transformExpr(monitorExit.objRef) + return ArrayStore(arrayStore.pc, arrayRef, index, value) + } - return MonitorExit(monitorExit.pc, objRef) - } + if (stmt.astID == Throw.ASTID) { + val throwStmt = stmt.asThrow + val exception = transformExpr(throwStmt.exception) - if (stmt.astID == ArrayStore.ASTID) { - val arrayStore = stmt.asArrayStore + return Throw(throwStmt.pc, exception) + } - val arrayRef = transformExpr(arrayStore.arrayRef) - val index = transformExpr(arrayStore.index) - val value = transformExpr(arrayStore.index) + if (stmt.astID == PutStatic.ASTID) { + val putStatic = stmt.asPutStatic + val value = transformExpr(putStatic.value) - return ArrayStore(arrayStore.pc, arrayRef, index, value) - } + return PutStatic(putStatic.pc, putStatic.declaringClass, putStatic.name, putStatic.declaredFieldType, value) + } - if (stmt.astID == Throw.ASTID) { - val throwStmt = stmt.asThrow - val exception = transformExpr(throwStmt.exception) + if (stmt.astID == PutField.ASTID) { + val putField = stmt.asPutField - return Throw(throwStmt.pc, exception) - } + val objRef = transformExpr(putField.objRef) + val value = transformExpr(putField.value) - if (stmt.astID == PutStatic.ASTID) { - val putStatic = stmt.asPutStatic - val value = transformExpr(putStatic.value) + return PutField(putField.pc, putField.declaringClass, putField.name, putField.declaredFieldType, objRef, value) + } - return PutStatic(putStatic.pc, putStatic.declaringClass, putStatic.name, putStatic.declaredFieldType, value) - } + if (stmt.astID == NonVirtualMethodCall.ASTID) { + val methodCall = stmt.asNonVirtualMethodCall - if (stmt.astID == PutField.ASTID) { - val putField = stmt.asPutField + val baseLocal = transformExpr(methodCall.receiver) + val paramLocals = methodCall.params.map(p => transformExpr(p)) - val objRef = transformExpr(putField.objRef) - val value = transformExpr(putField.value) + return NonVirtualMethodCall(methodCall.pc, methodCall.declaringClass, methodCall.isInterface, methodCall.name, methodCall.descriptor, baseLocal, paramLocals) + } - return PutField(putField.pc, putField.declaringClass, putField.name, putField.declaredFieldType, objRef, value) - } + if (stmt.astID == VirtualMethodCall.ASTID) { + val methodCall = stmt.asVirtualMethodCall - if (stmt.astID == NonVirtualMethodCall.ASTID) { - val methodCall = stmt.asNonVirtualMethodCall + val baseLocal = transformExpr(methodCall.receiver) + val paramLocals = methodCall.params.map(p => transformExpr(p)) - val baseLocal = transformExpr(methodCall.receiver) - val paramLocals = methodCall.params.map(p => transformExpr(p)) + return VirtualMethodCall(methodCall.pc, methodCall.declaringClass, methodCall.isInterface, methodCall.name, methodCall.descriptor, baseLocal, paramLocals) + } - return NonVirtualMethodCall(methodCall.pc, methodCall.declaringClass, methodCall.isInterface, methodCall.name, methodCall.descriptor, baseLocal, paramLocals) - } + if (stmt.astID == StaticMethodCall.ASTID) { + val methodCall = stmt.asStaticMethodCall + val params = methodCall.params.map(p => transformExpr(p)) - if (stmt.astID == VirtualMethodCall.ASTID) { - val methodCall = stmt.asVirtualMethodCall + return StaticMethodCall(methodCall.pc, methodCall.declaringClass, methodCall.isInterface, methodCall.name, methodCall.descriptor, params) + } - val baseLocal = transformExpr(methodCall.receiver) - val paramLocals = methodCall.params.map(p => transformExpr(p)) + if (stmt.astID == InvokedynamicMethodCall.ASTID) { + val methodCall = stmt.asInvokedynamicMethodCall + val params = methodCall.params.map(p => transformExpr(p)) - return VirtualMethodCall(methodCall.pc, methodCall.declaringClass, methodCall.isInterface, methodCall.name, methodCall.descriptor, baseLocal, paramLocals) - } + return InvokedynamicMethodCall(methodCall.pc, methodCall.bootstrapMethod, methodCall.name, methodCall.descriptor, params) + } - if (stmt.astID == StaticMethodCall.ASTID) { - val methodCall = stmt.asStaticMethodCall - val params = methodCall.params.map(p => transformExpr(p)) + if (stmt.astID == ExprStmt.ASTID) { + val expr = transformExpr(stmt.asExprStmt.expr) - return StaticMethodCall(methodCall.pc, methodCall.declaringClass, methodCall.isInterface, methodCall.name, methodCall.descriptor, params) - } + return ExprStmt(stmt.pc, expr) + } - if (stmt.astID == InvokedynamicMethodCall.ASTID) { - val methodCall = stmt.asInvokedynamicMethodCall - val params = methodCall.params.map(p => transformExpr(p)) + if (stmt.astID == CaughtException.ASTID) { + val caughtException = stmt.asCaughtException - return InvokedynamicMethodCall(methodCall.pc, methodCall.bootstrapMethod, methodCall.name, methodCall.descriptor, params) - } + return CaughtException(caughtException.pc, caughtException.exceptionType, caughtException.origins) + } + + if (stmt.astID == Checkcast.ASTID) { + val castExpr = stmt.asCheckcast + val value = transformExpr(castExpr.value) - if (stmt.astID == ExprStmt.ASTID) { - val expr = transformExpr(stmt.asExprStmt.expr) + return Checkcast(castExpr.pc, value, castExpr.cmpTpe) + } - return ExprStmt(stmt.pc, expr) + throw new RuntimeException("Could not transform statement: " + stmt) } - if (stmt.astID == CaughtException.ASTID) { - val caughtException = stmt.asCaughtException + def createNewLocal(pc: Int, idBasedVar: IdBasedVar): TacLocal = { + if (pc == -1) { + val local = localArray(0) - return CaughtException(caughtException.pc, caughtException.exceptionType, caughtException.origins) - } + return new RegisterLocal(idBasedVar.id, idBasedVar.cTpe, local(-idBasedVar.id - 1)) + } + + val nextPc = tacNaive.stmts(tacNaive.pcToIndex(pc) + 1).pc - if (stmt.astID == Checkcast.ASTID) { - val castExpr = stmt.asCheckcast - val value = transformExpr(castExpr.value) + if (idBasedVar.id >= 0) { + stackCounter += 1 - return Checkcast(castExpr.pc, value, castExpr.cmpTpe) + val value = operandsArray(nextPc).head + new StackLocal(stackCounter, idBasedVar.cTpe, value) + } else { + val local = localArray(nextPc) + new RegisterLocal(idBasedVar.id, idBasedVar.cTpe, local(-idBasedVar.id - 1)) + } } - throw new RuntimeException("Could not transform statement: " + stmt) - } + def transformExpr(expr: Expr[IdBasedVar]): Expr[TacLocal] = { + if (expr.isVar) { + return currentStack.getOrElse(expr.asVar.id, throw new RuntimeException("No local on stack")) + } - private def createNewLocal(idBasedVar: IdBasedVar): TacLocal = { - if (idBasedVar.id >= 0) { - val stackLocal = new StackLocal(stackCounter, idBasedVar.cTpe) - stackCounter += 1 + if (expr.astID == Compare.ASTID) { + val compareExpr = expr.asCompare - stackLocal - } else { - new RegisterLocal(idBasedVar.id, idBasedVar.cTpe) - } - } + val leftLocal = transformExpr(compareExpr.left) + val rightLocal = transformExpr(compareExpr.right) - private def transformExpr(expr: Expr[IdBasedVar]): Expr[TacLocal] = { - if (expr.isVar) { - return currentStack.getOrElse(expr.asVar.id, throw new RuntimeException("No local on stack")) - } + return Compare(compareExpr.pc, leftLocal, compareExpr.condition, rightLocal) + } - if (expr.astID == Compare.ASTID) { - val compareExpr = expr.asCompare + if (expr.astID == Param.ASTID) { + paramCounter += 1 + return new ParameterLocal(paramCounter, expr.asParam.cTpe, expr.asParam.name) + } - val leftLocal = transformExpr(compareExpr.left) - val rightLocal = transformExpr(compareExpr.right) + if (expr.astID == MethodTypeConst.ASTID) { + return MethodTypeConst(expr.asMethodTypeConst.pc, expr.asMethodTypeConst.value) + } - return Compare(compareExpr.pc, leftLocal, compareExpr.condition, rightLocal) - } + if (expr.astID == MethodHandleConst.ASTID) { + return MethodHandleConst(expr.asMethodHandleConst.pc, expr.asMethodHandleConst.value) + } - if (expr.astID == Param.ASTID) { - return Param(expr.asParam.cTpe, expr.asParam.name) - } + if (expr.astID == IntConst.ASTID) { + return IntConst(expr.asIntConst.pc, expr.asIntConst.value) + } - if (expr.astID == MethodTypeConst.ASTID) { - return MethodTypeConst(expr.asMethodTypeConst.pc, expr.asMethodTypeConst.value) - } + if (expr.astID == LongConst.ASTID) { + return LongConst(expr.asLongConst.pc, expr.asLongConst.value) + } - if (expr.astID == MethodHandleConst.ASTID) { - return MethodHandleConst(expr.asMethodHandleConst.pc, expr.asMethodHandleConst.value) - } + if (expr.astID == FloatConst.ASTID) { + return FloatConst(expr.asFloatConst.pc, expr.asFloatConst.value) + } - if (expr.astID == IntConst.ASTID) { - return IntConst(expr.asIntConst.pc, expr.asIntConst.value) - } + if (expr.astID == DoubleConst.ASTID) { + return DoubleConst(expr.asDoubleConst.pc, expr.asDoubleConst.value) + } - if (expr.astID == LongConst.ASTID) { - return LongConst(expr.asLongConst.pc, expr.asLongConst.value) - } + if (expr.astID == StringConst.ASTID) { + return StringConst(expr.asStringConst.pc, expr.asStringConst.value) + } - if (expr.astID == FloatConst.ASTID) { - return FloatConst(expr.asFloatConst.pc, expr.asFloatConst.value) - } + if (expr.astID == ClassConst.ASTID) { + return ClassConst(expr.asClassConst.pc, expr.asClassConst.value) + } - if (expr.astID == DoubleConst.ASTID) { - return DoubleConst(expr.asDoubleConst.pc, expr.asDoubleConst.value) - } + if (expr.astID == DynamicConst.ASTID) { + return DynamicConst(expr.asDynamicConst.pc, expr.asDynamicConst.bootstrapMethod, expr.asDynamicConst.name, expr.asDynamicConst.descriptor) + } - if (expr.astID == StringConst.ASTID) { - return StringConst(expr.asStringConst.pc, expr.asStringConst.value) - } + if (expr.astID == NullExpr.ASTID) { + return NullExpr(expr.asNullExpr.pc) + } - if (expr.astID == ClassConst.ASTID) { - return ClassConst(expr.asClassConst.pc, expr.asClassConst.value) - } + if (expr.astID == BinaryExpr.ASTID) { + val binaryExpr = expr.asBinaryExpr - if (expr.astID == DynamicConst.ASTID) { - return DynamicConst(expr.asDynamicConst.pc, expr.asDynamicConst.bootstrapMethod, expr.asDynamicConst.name, expr.asDynamicConst.descriptor) - } + val left = transformExpr(binaryExpr.left) + val right = transformExpr(binaryExpr.right) - if (expr.astID == NullExpr.ASTID) { - return NullExpr(expr.asNullExpr.pc) - } + return BinaryExpr(binaryExpr.pc, binaryExpr.cTpe, binaryExpr.op, left, right) + } - if (expr.astID == BinaryExpr.ASTID) { - val binaryExpr = expr.asBinaryExpr + if (expr.astID == PrefixExpr.ASTID) { + val prefixExpr = expr.asPrefixExpr + val operand = transformExpr(prefixExpr.operand) - val left = transformExpr(binaryExpr.left) - val right = transformExpr(binaryExpr.right) + return PrefixExpr(prefixExpr.pc, prefixExpr.cTpe, prefixExpr.op, operand) + } - return BinaryExpr(binaryExpr.pc, binaryExpr.cTpe, binaryExpr.op, left, right) - } + if (expr.astID == PrimitiveTypecastExpr.ASTID) { + val primitiveTypecastExpr = expr.asPrimitiveTypeCastExpr + val operand = transformExpr(primitiveTypecastExpr) - if (expr.astID == PrefixExpr.ASTID) { - val prefixExpr = expr.asPrefixExpr - val operand = transformExpr(prefixExpr.operand) + return PrimitiveTypecastExpr(primitiveTypecastExpr.pc, primitiveTypecastExpr.targetTpe, operand) + } - return PrefixExpr(prefixExpr.pc, prefixExpr.cTpe, prefixExpr.op, operand) - } + if (expr.astID == New.ASTID) { + return New(expr.asNew.pc, expr.asNew.tpe) + } - if (expr.astID == PrimitiveTypecastExpr.ASTID) { - val primitiveTypecastExpr = expr.asPrimitiveTypeCastExpr - val operand = transformExpr(primitiveTypecastExpr) + if (expr.astID == NewArray.ASTID) { + val newArray = expr.asNewArray + val counts = newArray.counts.map(c => transformExpr(c)) - return PrimitiveTypecastExpr(primitiveTypecastExpr.pc, primitiveTypecastExpr.targetTpe, operand) - } + return NewArray(newArray.pc, counts, newArray.tpe) + } - if (expr.astID == New.ASTID) { - return New(expr.asNew.pc, expr.asNew.tpe) - } + if (expr.astID == ArrayLoad.ASTID) { + val arrayLoad = expr.asArrayLoad - if (expr.astID == NewArray.ASTID) { - val newArray = expr.asNewArray - val counts = newArray.counts.map(c => transformExpr(c)) + val index = transformExpr(arrayLoad.index) + val arrayRef = transformExpr(arrayLoad.arrayRef) - return NewArray(newArray.pc, counts, newArray.tpe) - } + return ArrayLoad(arrayLoad.pc, index, arrayRef) + } - if (expr.astID == ArrayLoad.ASTID) { - val arrayLoad = expr.asArrayLoad + if (expr.astID == ArrayLength.ASTID) { + val arrayLength = expr.asArrayLength + val arrayRef = transformExpr(arrayLength.arrayRef) - val index = transformExpr(arrayLoad.index) - val arrayRef = transformExpr(arrayLoad.arrayRef) + return ArrayLength(arrayLength.pc, arrayRef) + } - return ArrayLoad(arrayLoad.pc, index, arrayRef) - } + if (expr.astID == GetField.ASTID) { + val getField = expr.asGetField + val objRef = transformExpr(getField.objRef) - if (expr.astID == ArrayLength.ASTID) { - val arrayLength = expr.asArrayLength - val arrayRef = transformExpr(arrayLength.arrayRef) + return GetField(getField.pc, getField.declaringClass, getField.name, getField.declaredFieldType, objRef) + } - return ArrayLength(arrayLength.pc, arrayRef) - } + if (expr.astID == GetStatic.ASTID) { + return GetStatic(expr.asGetStatic.pc, expr.asGetStatic.declaringClass, expr.asGetStatic.name, expr.asGetStatic.declaredFieldType) + } - if (expr.astID == GetField.ASTID) { - val getField = expr.asGetField - val objRef = transformExpr(getField.objRef) + if (expr.astID == InvokedynamicFunctionCall.ASTID) { + val functionCall = expr.asInvokedynamicFunctionCall + val params = functionCall.params.map(p => transformExpr(p)) - return GetField(getField.pc, getField.declaringClass, getField.name, getField.declaredFieldType, objRef) - } + return InvokedynamicFunctionCall(functionCall.pc, functionCall.bootstrapMethod, functionCall.name, functionCall.descriptor, params) + } - if (expr.astID == GetStatic.ASTID) { - return GetStatic(expr.asGetStatic.pc, expr.asGetStatic.declaringClass, expr.asGetStatic.name, expr.asGetStatic.declaredFieldType) - } + if (expr.astID == NonVirtualFunctionCall.ASTID) { + val functionCall = expr.asNonVirtualFunctionCall - if (expr.astID == InvokedynamicFunctionCall.ASTID) { - val functionCall = expr.asInvokedynamicFunctionCall - val params = functionCall.params.map(p => transformExpr(p)) + val base = transformExpr(functionCall.receiver) + val params = functionCall.params.map(p => transformExpr(p)) - return InvokedynamicFunctionCall(functionCall.pc, functionCall.bootstrapMethod, functionCall.name, functionCall.descriptor, params) - } + return NonVirtualFunctionCall(functionCall.pc, functionCall.declaringClass, functionCall.isInterface, functionCall.name, functionCall.descriptor, base, params) + } - if (expr.astID == NonVirtualFunctionCall.ASTID) { - val functionCall = expr.asNonVirtualFunctionCall + if (expr.astID == VirtualFunctionCall.ASTID) { + val functionCall = expr.asVirtualFunctionCall - val base = transformExpr(functionCall.receiver) - val params = functionCall.params.map(p => transformExpr(p)) + val base = transformExpr(functionCall.receiver) + val params = functionCall.params.map(p => transformExpr(p)) - return NonVirtualFunctionCall(functionCall.pc, functionCall.declaringClass, functionCall.isInterface, functionCall.name, functionCall.descriptor, base, params) - } + return VirtualFunctionCall(functionCall.pc, functionCall.declaringClass, functionCall.isInterface, functionCall.name, functionCall.descriptor, base, params) + } - if (expr.astID == VirtualFunctionCall.ASTID) { - val functionCall = expr.asVirtualFunctionCall + if (expr.astID == StaticFunctionCall.ASTID) { + val functionCall = expr.asStaticFunctionCall - val base = transformExpr(functionCall.receiver) - val params = functionCall.params.map(p => transformExpr(p)) + val params = functionCall.params + val paramLocals = params.map(p => transformExpr(p)) - return VirtualFunctionCall(functionCall.pc, functionCall.declaringClass, functionCall.isInterface, functionCall.name, functionCall.descriptor, base, params) - } + return StaticFunctionCall(functionCall.pc, functionCall.declaringClass, functionCall.isInterface, functionCall.name, functionCall.descriptor, paramLocals) + } - if (expr.astID == StaticFunctionCall.ASTID) { - val functionCall = expr.asStaticFunctionCall + throw new RuntimeException("Could not transform expression: " + expr) + } - val params = functionCall.params - val paramLocals = params.map(p => transformExpr(p)) + val transformedTac: Array[Stmt[TacLocal]] = tacNaive.stmts.map(stmt => transformStatement(stmt)) - return StaticFunctionCall(functionCall.pc, functionCall.declaringClass, functionCall.isInterface, functionCall.name, functionCall.descriptor, paramLocals) + // Update the CFG + val cfg = CFGFactory(method, classHierarchy) + if (cfg.isEmpty) { + throw new RuntimeException("Could not compute CFG for method " + method.name) } - throw new RuntimeException("Could not transform expression: " + expr) + val tacCfg = cfg.get.mapPCsToIndexes[Stmt[TacLocal], TACStmts[TacLocal]](TACStmts(transformedTac), tacNaive.pcToIndex, i => i, transformedTac.length) + + new BoomerangTACode(tacNaive.params, transformedTac, tacNaive.pcToIndex, tacCfg, tacNaive.exceptionHandlers) } } diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalLocalTest.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalLocalTest.scala index 22cc2ad89..7b4cc115b 100644 --- a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalLocalTest.scala +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalLocalTest.scala @@ -81,7 +81,7 @@ class OpalLocalTest { val oneArgMethod = OpalMethod(oneArg) Assert.assertEquals(1, oneArgMethod.getParameterLocals.size) - //Assert.assertEquals("int", oneArgMethod.getParameterLocal(0).getType.toString) + Assert.assertEquals("int", oneArgMethod.getParameterLocal(0).getType.toString) // Two parameters (primitive type + RefType) val twoArgSignature = new MethodSignature(classOf[ParameterLocalsTarget].getName, "twoParameters", "Void", util.List.of(integerType, s"L${classOf[A].getName}L")) @@ -89,8 +89,8 @@ class OpalLocalTest { val twoArgsMethod = OpalMethod(twoArgs) Assert.assertEquals(2, twoArgsMethod.getParameterLocals.size) - //Assert.assertEquals("int", twoArgsMethod.getParameterLocal(0).getType.toString) - //Assert.assertEquals(classOf[A].getName, twoArgsMethod.getParameterLocal(1).getType.toString) + Assert.assertEquals("int", twoArgsMethod.getParameterLocal(0).getType.toString) + Assert.assertEquals(classOf[A].getName, twoArgsMethod.getParameterLocal(1).getType.toString) } @Test diff --git a/boomerangScope/src/test/java/boomerang/scope/test/targets/InvokeExprTarget.java b/boomerangScope/src/test/java/boomerang/scope/test/targets/InvokeExprTarget.java index 6d6188e27..3c34ea4d7 100644 --- a/boomerangScope/src/test/java/boomerang/scope/test/targets/InvokeExprTarget.java +++ b/boomerangScope/src/test/java/boomerang/scope/test/targets/InvokeExprTarget.java @@ -40,4 +40,14 @@ public static void alias() { a.methodCall(i); } + + public static void alias2() { + A alias2 = new A(); + if (Math.random() > 0.5) { + Object alias1 = alias2; + alias2 = new A(); + } + + System.out.println(alias2); + } } diff --git a/boomerangScope/src/test/java/boomerang/scope/test/targets/ParameterLocalsTarget.java b/boomerangScope/src/test/java/boomerang/scope/test/targets/ParameterLocalsTarget.java index 9975b919d..acb808398 100644 --- a/boomerangScope/src/test/java/boomerang/scope/test/targets/ParameterLocalsTarget.java +++ b/boomerangScope/src/test/java/boomerang/scope/test/targets/ParameterLocalsTarget.java @@ -27,7 +27,7 @@ public void noParameters() {} public void oneParameter(@SuppressWarnings("unused") int i) {} - public void twoParameters(@SuppressWarnings("unused") int i, @SuppressWarnings("unused") A a) { + public void twoParameters(int i, A a) { a.methodCall(i); } } From 79fb04558a74679b1a8422e0e8accf94244af65f Mon Sep 17 00:00:00 2001 From: Sven Meyer Date: Tue, 25 Mar 2025 14:25:06 +0100 Subject: [PATCH 24/61] Add basic propagation optimizer --- .../boomerang/scope/opal/tac/OpalType.scala | 8 +- .../opal/transformer/BasicPropagation.scala | 85 +++++++++++++++++++ .../scope/opal/transformer/TacLocal.scala | 8 +- .../opal/transformer/TacTransformer.scala | 28 +++--- .../boomerang/scope/opal/OpalArrayTest.scala | 16 +++- .../scope/opal/OpalInvokeExprTest.scala | 17 +++- .../scope/test/targets/ArrayTarget.java | 2 +- .../scope/test/targets/SingleTarget.java | 30 +++++++ 8 files changed, 175 insertions(+), 19 deletions(-) create mode 100644 boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/BasicPropagation.scala create mode 100644 boomerangScope/src/test/java/boomerang/scope/test/targets/SingleTarget.java diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalType.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalType.scala index 597ebdad0..91d85285c 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalType.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalType.scala @@ -36,11 +36,13 @@ case class OpalType(delegate: org.opalj.br.Type) extends Type { val sourceType = delegate.asReferenceType val targetType = targetValType.asInstanceOf[OpalType].delegate.asReferenceType - target match { + false + + /*target match { case allocVal: AllocVal if allocVal.getAllocVal.isNewExpr => OpalClient.getClassHierarchy.isSubtypeOf(sourceType, targetType) - case _ => OpalClient.getClassHierarchy.isSubtypeOf(sourceType, targetType) - } + case _ => OpalClient.getClassHierarchy.isSubtypeOf(sourceType, targetType) || OpalClient.getClassHierarchy.isSubtypeOf(targetType, sourceType) + }*/ } override def isSubtypeOf(otherType: String): Boolean = { diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/BasicPropagation.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/BasicPropagation.scala new file mode 100644 index 000000000..4c1ba9935 --- /dev/null +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/BasicPropagation.scala @@ -0,0 +1,85 @@ +package boomerang.scope.opal.transformer + +import org.opalj.tac.{Assignment, Expr, NewArray, Nop, SimpleValueConst, Stmt} + +object BasicPropagation { + + def apply(tacStatements: Array[Stmt[TacLocal]]): Array[Stmt[TacLocal]] = { + val statements = tacStatements.map(identity) + + Range(0, tacStatements.length - 1).foreach(i => { + tacStatements(i) match { + /* Transform constant assignments: + * $s = + * r = $s + * + * becomes + * + * Nop + * r = + */ + case Assignment(pc, targetVar, c @ (_: SimpleValueConst)) => + tacStatements(i + 1) match { + // Case: r = $s + case Assignment(nextPc, nextTargetVar, `targetVar`) => + statements(i) = Nop(pc) + statements(i + 1) = Assignment(nextPc, nextTargetVar, c) + case _ => + } + + /* Transform array assignments and try to find their counts: + * $s0 = 0 + * $s1 = 1 + * $s2 = NewArray(counts($s1, $s0)) + * r = $s2 + * + * becomes + * + * Nop + * Nop + * Nop + * r = NewArray(counts(1, 0)) + */ + case Assignment(pc, targetVar, NewArray(exprPc, counts, tpe)) => + val newCounts = counts.map(c => { + val allocSite = propagateBackward(i, c) + + if (allocSite.isDefined) { + val allocStmt = statements(allocSite.get) + statements(allocSite.get) = Nop(allocStmt.pc) + + allocStmt.asAssignment.expr + } else { + c + } + }) + + val newArray = NewArray(exprPc, newCounts, tpe) + tacStatements(i + 1) match { + case Assignment(nextPc, nextTargetVar, `targetVar`) => + statements(i) = Nop(pc) + statements(i + 1) = Assignment(nextPc, nextTargetVar, newArray) + case _ => + } + case _ => + } + }) + + def propagateBackward(i: Int, local: Expr[TacLocal]): Option[Int] = { + Range.inclusive(i - 1, 0, -1).foreach(j => { + val currStmt = statements(j) + + if (currStmt.astID == Assignment.ASTID) { + if (currStmt.asAssignment.targetVar == local && currStmt.asAssignment.expr.isConst) { + return Option(j) + } + } + }) + + Option.empty + } + + statements + } + +} diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacLocal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacLocal.scala index 4869721c5..60a7da174 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacLocal.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacLocal.scala @@ -41,7 +41,13 @@ class StackLocal(identifier: Int, computationalType: ComputationalType, valueInf override def isParameterLocal: Boolean = false - override def name: String = s"$$s$identifier" + override def name: String = { + if (identifier == -1) { + "this" + } else { + s"$$s$identifier" + } + } override def cTpe: ComputationalType = computationalType diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacTransformer.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacTransformer.scala index 920f0a1d9..1d9ee7dbb 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacTransformer.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacTransformer.scala @@ -54,8 +54,10 @@ object TacTransformer { } if (stmt.astID == Assignment.ASTID) { - val target = createNewLocal(stmt.pc, stmt.asAssignment.targetVar) val transformedExpr = transformExpr(stmt.asAssignment.expr) + val isThisAssignment = !method.isStatic && transformedExpr.isVar && transformedExpr.asVar.id == -1 + + val target = createNewLocal(stmt.pc, stmt.asAssignment.targetVar, isThisAssignment) // Store the current stack and register locals on our own 'stack' currentStack(stmt.asAssignment.targetVar.id) = target @@ -97,7 +99,7 @@ object TacTransformer { val arrayRef = transformExpr(arrayStore.arrayRef) val index = transformExpr(arrayStore.index) - val value = transformExpr(arrayStore.index) + val value = transformExpr(arrayStore.value) return ArrayStore(arrayStore.pc, arrayRef, index, value) } @@ -179,7 +181,7 @@ object TacTransformer { throw new RuntimeException("Could not transform statement: " + stmt) } - def createNewLocal(pc: Int, idBasedVar: IdBasedVar): TacLocal = { + def createNewLocal(pc: Int, idBasedVar: IdBasedVar, isThis: Boolean = false): TacLocal = { if (pc == -1) { val local = localArray(0) @@ -189,10 +191,15 @@ object TacTransformer { val nextPc = tacNaive.stmts(tacNaive.pcToIndex(pc) + 1).pc if (idBasedVar.id >= 0) { - stackCounter += 1 - - val value = operandsArray(nextPc).head - new StackLocal(stackCounter, idBasedVar.cTpe, value) + if (isThis) { + val value = operandsArray(nextPc).head + new StackLocal(-1, idBasedVar.cTpe, value) + } else { + stackCounter += 1 + + val value = operandsArray(nextPc).head + new StackLocal(stackCounter, idBasedVar.cTpe, value) + } } else { val local = localArray(nextPc) new RegisterLocal(idBasedVar.id, idBasedVar.cTpe, local(-idBasedVar.id - 1)) @@ -276,7 +283,7 @@ object TacTransformer { if (expr.astID == PrimitiveTypecastExpr.ASTID) { val primitiveTypecastExpr = expr.asPrimitiveTypeCastExpr - val operand = transformExpr(primitiveTypecastExpr) + val operand = transformExpr(primitiveTypecastExpr.operand) return PrimitiveTypecastExpr(primitiveTypecastExpr.pc, primitiveTypecastExpr.targetTpe, operand) } @@ -357,6 +364,7 @@ object TacTransformer { } val transformedTac: Array[Stmt[TacLocal]] = tacNaive.stmts.map(stmt => transformStatement(stmt)) + val optimizedTac: Array[Stmt[TacLocal]] = BasicPropagation(transformedTac) // Update the CFG val cfg = CFGFactory(method, classHierarchy) @@ -364,8 +372,8 @@ object TacTransformer { throw new RuntimeException("Could not compute CFG for method " + method.name) } - val tacCfg = cfg.get.mapPCsToIndexes[Stmt[TacLocal], TACStmts[TacLocal]](TACStmts(transformedTac), tacNaive.pcToIndex, i => i, transformedTac.length) + val tacCfg = cfg.get.mapPCsToIndexes[Stmt[TacLocal], TACStmts[TacLocal]](TACStmts(optimizedTac), tacNaive.pcToIndex, i => i, optimizedTac.length) - new BoomerangTACode(tacNaive.params, transformedTac, tacNaive.pcToIndex, tacCfg, tacNaive.exceptionHandlers) + new BoomerangTACode(tacNaive.params, optimizedTac, tacNaive.pcToIndex, tacCfg, tacNaive.exceptionHandlers) } } diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalArrayTest.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalArrayTest.scala index b4e0c6499..d8352467d 100644 --- a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalArrayTest.scala +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalArrayTest.scala @@ -1,10 +1,12 @@ package boomerang.scope.opal import boomerang.scope.opal.tac.OpalMethod +import boomerang.scope.opal.transformer.{BasicPropagation, TacLocal} import boomerang.scope.test.MethodSignature import boomerang.scope.test.targets.ArrayTarget import org.junit.{Assert, Test} import org.opalj.br.IntegerType +import org.opalj.tac.Stmt import java.util @@ -40,7 +42,7 @@ class OpalArrayTest { } @Test - def singleArrayWriteTest(): Unit = { + def singleArrayStoreTest(): Unit = { val opalSetup = new OpalSetup() opalSetup.setupOpal(classOf[ArrayTarget].getName) @@ -66,4 +68,16 @@ class OpalArrayTest { Assert.assertEquals(1, arrayStoreCount) } + @Test + def multiArrayStore(): Unit = { + val opalSetup = new OpalSetup() + opalSetup.setupOpal(classOf[ArrayTarget].getName) + + val signature = new MethodSignature(classOf[ArrayTarget].getName, "multiArrayStore", "Void") + val method = opalSetup.resolveMethod(signature) + val opalMethod = OpalMethod(method) + + println(opalMethod.tac.statements.mkString("Array(\n\t", "\n\t", "\n)")) + } + } diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala index eb8acb78e..afb1a2461 100644 --- a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala @@ -1,22 +1,33 @@ package boomerang.scope.opal +import boomerang.scope.DataFlowScope import boomerang.scope.opal.tac.OpalMethod import boomerang.scope.test.MethodSignature -import boomerang.scope.test.targets.InvokeExprTarget +import boomerang.scope.test.targets.{InvokeExprTarget, SingleTarget} import org.junit.Test +import org.opalj.tac.cg.{CHACallGraphKey, CallGraph} + +import java.util +import java.util.Set +import scala.jdk.javaapi.CollectionConverters class OpalInvokeExprTest { @Test def instanceInvokeExprTest(): Unit = { val opalSetup = new OpalSetup() - opalSetup.setupOpal(classOf[InvokeExprTarget].getName) + opalSetup.setupOpal(classOf[SingleTarget].getName) - val signature = new MethodSignature(classOf[InvokeExprTarget].getName, "alias", "Void") + val signature = new MethodSignature(classOf[SingleTarget].getName, "identityTest", "Void") val method = opalSetup.resolveMethod(signature) val opalMethod = OpalMethod(method) opalMethod.getControlFlowGraph + + val callGraph: CallGraph = OpalClient.project.get.get(CHACallGraphKey) + + val scope = new OpalFrameworkScope(OpalClient.project.get, callGraph, CollectionConverters.asScala(util.Set.of(method)).toSet, DataFlowScope.EXCLUDE_PHANTOM_CLASSES) + println(opalMethod.tac.statements.mkString("Array(\n\t", "\n\t", "\n)")) } diff --git a/boomerangScope/src/test/java/boomerang/scope/test/targets/ArrayTarget.java b/boomerangScope/src/test/java/boomerang/scope/test/targets/ArrayTarget.java index 25be86d90..697ace632 100644 --- a/boomerangScope/src/test/java/boomerang/scope/test/targets/ArrayTarget.java +++ b/boomerangScope/src/test/java/boomerang/scope/test/targets/ArrayTarget.java @@ -36,7 +36,7 @@ public static void singleArrayStore() { } public static void multiArrayStore() { - int[][] arr = new int[2][2]; + int[][] arr = new int[2][3]; arr[0][0] = 1; System.out.println(Arrays.deepToString(arr)); diff --git a/boomerangScope/src/test/java/boomerang/scope/test/targets/SingleTarget.java b/boomerangScope/src/test/java/boomerang/scope/test/targets/SingleTarget.java new file mode 100644 index 000000000..adb7c7374 --- /dev/null +++ b/boomerangScope/src/test/java/boomerang/scope/test/targets/SingleTarget.java @@ -0,0 +1,30 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ +package boomerang.scope.test.targets; + +public class SingleTarget { + + public static void main(String[] args) { + identityTest(); + } + + public static void identityTest() { + A alias1 = new A(); + A alias2 = identity(alias1); + System.out.println(alias2); + } + + private static A identity(A param) { + A mapped = param; + return mapped; + } +} From 476bda95c5af7a4b032dc5246890b4e445b123ee Mon Sep 17 00:00:00 2001 From: Sven Meyer Date: Wed, 26 Mar 2025 14:34:20 +0100 Subject: [PATCH 25/61] Update opal test setup --- .../cases/bugfixes/issue5/Issue5Test.java | 2 +- .../java/test/cases/fields/SummaryTarget.java | 1 + .../scope/opal/tac/OpalControlFlowGraph.scala | 77 +++++++++-------- .../scope/opal/tac/OpalInstanceFieldRef.scala | 67 +++++++++++++++ .../boomerang/scope/opal/tac/OpalLocal.scala | 25 +++++- .../scope/opal/tac/OpalNullType.scala | 24 ++++++ .../scope/opal/tac/OpalStatement.scala | 23 +++-- .../opal/tac/OpalStatementFormatter.scala | 18 ++-- .../scope/opal/tac/OpalWrappedClass.scala | 4 +- .../scope/opal/transformer/TacLocal.scala | 6 +- .../scope/opal/OpalAssignmentTest.scala | 21 +++++ .../boomerang/scope/opal/OpalFieldTest.scala | 6 +- .../boomerang/scope/soot/SootScopeTest.java | 24 ++++++ .../scope/test/targets/AssignmentTarget.java | 8 ++ .../main/java/test/setup/OpalTestSetup.java | 86 +++++++++++++++++-- 15 files changed, 323 insertions(+), 69 deletions(-) create mode 100644 boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalInstanceFieldRef.scala create mode 100644 boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalNullType.scala diff --git a/boomerangPDS/src/test/java/test/cases/bugfixes/issue5/Issue5Test.java b/boomerangPDS/src/test/java/test/cases/bugfixes/issue5/Issue5Test.java index 72339aa37..9787ed73b 100644 --- a/boomerangPDS/src/test/java/test/cases/bugfixes/issue5/Issue5Test.java +++ b/boomerangPDS/src/test/java/test/cases/bugfixes/issue5/Issue5Test.java @@ -119,7 +119,7 @@ private void assertResults( methodCalledOnFoo.add(methodWrapper); } - Assert.assertEquals(methodCalledOnFoo, Set.of(expectedCalledMethodsOnFoo)); + Assert.assertEquals(Set.of(expectedCalledMethodsOnFoo), methodCalledOnFoo); } private static Collection getMethodsInvokedFromInstanceInStatement( diff --git a/boomerangPDS/src/test/java/test/cases/fields/SummaryTarget.java b/boomerangPDS/src/test/java/test/cases/fields/SummaryTarget.java index d22498caa..cf436e61e 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/SummaryTarget.java +++ b/boomerangPDS/src/test/java/test/cases/fields/SummaryTarget.java @@ -15,6 +15,7 @@ import test.core.QueryMethods; import test.core.selfrunning.AllocatedObject; +@SuppressWarnings("unused") public class SummaryTarget { @TestMethod diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalControlFlowGraph.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalControlFlowGraph.scala index 0dcd0152b..755e8e9ac 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalControlFlowGraph.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalControlFlowGraph.scala @@ -2,6 +2,7 @@ package boomerang.scope.opal.tac import boomerang.scope.{ControlFlowGraph, Statement} import com.google.common.collect.{HashMultimap, Multimap} +import org.opalj.tac.Nop import java.util @@ -49,44 +50,50 @@ class OpalControlFlowGraph(method: OpalMethod) extends ControlFlowGraph { private def buildCache(): Unit = { if (cacheBuilt) return - var headFound = false - method.tac.statements.foreach(stmt => { + // Definition of parameter locals + method.tac.statements.filter(stmt => stmt.pc == -1).foreach(stmt => { val statement = new OpalStatement(stmt, method) statements.add(statement) + }) + + val head = new OpalStatement(Nop(-1), method) + statements.add(head) + startPointCache.add(head) + + var headAdded = false + method.tac.statements.filter(stmt => stmt.pc >= 0).foreach(stmt => { + val statement = new OpalStatement(stmt, method) + statements.add(statement) + + val stmtPc = method.tac.pcToIndex(stmt.pc) + + if (!headAdded) { + headAdded = true + + predsOfCache.put(statement, head) + succsOfCache.put(head, statement) + } else { + val predecessors = method.tac.cfg.predecessors(stmtPc) + predecessors.foreach(predecessorPc => { + val predecessor = method.tac.statements(predecessorPc) + val predecessorStatement = new OpalStatement(predecessor, method) + + predsOfCache.put(statement, predecessorStatement) + }) + } - // Definition of parameter locals have implicit PC of -1, so they are not part of the actual CFG - if (stmt.pc != -1) { - val stmtPc = method.tac.pcToIndex(stmt.pc) - - // The first statement after the parameter local definitions is the head - if (!headFound) { - headFound = true - - startPointCache.add(statement) - predsOfCache.putAll(statement, util.Collections.emptySet()) - } else { - val predecessors = method.tac.cfg.predecessors(stmtPc) - predecessors.foreach(predecessorPc => { - val predecessor = method.tac.statements(predecessorPc) - val predecessorStatement = new OpalStatement(predecessor, method) - - predsOfCache.put(statement, predecessorStatement) - }) - } - - val successors = method.tac.cfg.successors(stmtPc) - if (successors.isEmpty) { - // No successors => Tail statement - endPointCache.add(statement) - succsOfCache.putAll(statement, util.Collections.emptySet()) - } else { - successors.foreach(successorPc => { - val successor = method.tac.statements(successorPc) - val successorStatement = new OpalStatement(successor, method) - - succsOfCache.put(statement, successorStatement) - }) - } + val successors = method.tac.cfg.successors(stmtPc) + if (successors.isEmpty) { + // No successors => Tail statement + endPointCache.add(statement) + succsOfCache.putAll(statement, util.Collections.emptySet()) + } else { + successors.foreach(successorPc => { + val successor = method.tac.statements(successorPc) + val successorStatement = new OpalStatement(successor, method) + + succsOfCache.put(statement, successorStatement) + }) } }) diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalInstanceFieldRef.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalInstanceFieldRef.scala new file mode 100644 index 000000000..1f0f7d152 --- /dev/null +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalInstanceFieldRef.scala @@ -0,0 +1,67 @@ +package boomerang.scope.opal.tac + +import boomerang.scope.{ControlFlowGraph, Method, Pair, Type, Val} +import boomerang.scope.opal.transformer.TacLocal + +case class OpalInstanceFieldRef(base: TacLocal, fieldType: org.opalj.br.Type, fieldName: String, method: OpalMethod, unbalanced: ControlFlowGraph.Edge = null) extends Val(method, unbalanced) { + + override def getType: Type = OpalType(fieldType) + + override def isStatic: Boolean = false + + override def isNewExpr: Boolean = false + + override def getNewExprType: Type = throw new RuntimeException("Instance field ref is not a new expression") + + override def asUnbalanced(stmt: ControlFlowGraph.Edge): Val = OpalInstanceFieldRef(base, fieldType, fieldName, method, stmt) + + override def isLocal: Boolean = false + + override def isArrayAllocationVal: Boolean = false + + override def getArrayAllocationSize: Val = throw new RuntimeException("Instance field ref is not an array allocation val") + + override def isNull: Boolean = false + + override def isStringConstant: Boolean = false + + override def getStringValue: String = throw new RuntimeException("Instance field ref is not a String constant") + + override def isStringBufferOrBuilder: Boolean = false + + override def isThrowableAllocationType: Boolean = false + + override def isCast: Boolean = false + + override def getCastOp: Val = throw new RuntimeException("Instance field ref is not a cast expression") + + override def isArrayRef: Boolean = false + + override def isInstanceOfExpr: Boolean = false + + override def getInstanceOfOp: Val = throw new RuntimeException("Instance field ref is not an instanceOf expression") + + override def isLengthExpr: Boolean = false + + override def getLengthOp: Val = throw new RuntimeException("Instance field ref is not a length expression") + + override def isIntConstant: Boolean = false + + override def isClassConstant: Boolean = false + + override def getClassConstantType: Type = throw new RuntimeException("Instance field ref is not a class constant") + + override def withNewMethod(callee: Method): Val = OpalInstanceFieldRef(base, fieldType, fieldName, callee.asInstanceOf[OpalMethod]) + + override def isLongConstant: Boolean = false + + override def getIntValue: Int = throw new RuntimeException("Instance field ref is not an int constant") + + override def getLongValue: Long = throw new RuntimeException("Instance field ref is not a long constant") + + override def getArrayBase: Pair[Val, Integer] = throw new RuntimeException("Instance field ref has no array base") + + override def getVariableName: String = s"$base.$fieldName" + + override def toString: String = getVariableName +} diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalLocal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalLocal.scala index ffc611425..37e4a3add 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalLocal.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalLocal.scala @@ -12,9 +12,26 @@ class OpalLocal(val delegate: Var[TacLocal], method: OpalMethod, unbalanced: Con override def getType: Type = { val value = delegate.asVar.value - if (value.isPrimitiveValue) return OpalType(value.asPrimitiveValue.primitiveType) - if (value.isReferenceValue) return OpalType(value.asReferenceValue.asReferenceType) - if (value.isVoid) return OpalType(ObjectType.Void) + if (value.isPrimitiveValue) { + return OpalType(value.asPrimitiveValue.primitiveType) + } + + if (value.isReferenceValue) { + if (value.asReferenceValue.isPrecise) { + if (value.asReferenceValue.isNull.isYes) { + return OpalNullType + } else { + return OpalType(value.asReferenceValue.asReferenceType) + } + } + + // Over approximation: Same behavior as in Soot + return OpalType(ObjectType("java/lang/Object")) + } + + if (value.isVoid) { + return OpalType(ObjectType.Void) + } // TODO Array and illegal types throw new RuntimeException("Type not implemented yet") @@ -79,7 +96,7 @@ class OpalLocal(val delegate: Var[TacLocal], method: OpalMethod, unbalanced: Con override def hashCode: Int = Objects.hash(delegate.asVar.id) override def equals(other: Any): Boolean = other match { - case that: OpalLocal => super.equals(that) && this.delegate.asVar.id == that.delegate.asVar.id + case that: OpalLocal => super.equals(that) && this.delegate == that.delegate case _ => false } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalNullType.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalNullType.scala new file mode 100644 index 000000000..632fc546f --- /dev/null +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalNullType.scala @@ -0,0 +1,24 @@ +package boomerang.scope.opal.tac + +import boomerang.scope.{Type, Val, WrappedClass} + +object OpalNullType extends Type { + + override def isNullType: Boolean = true + + override def isRefType: Boolean = false + + override def isArrayType: Boolean = false + + override def getArrayBaseType: Type = throw new RuntimeException("Null type has no array base type") + + override def getWrappedClass: WrappedClass = throw new RuntimeException("Null type has no declaring class") + + override def doesCastFail(targetVal: Type, target: Val): Boolean = true + + override def isSubtypeOf(superType: String): Boolean = false + + override def isSupertypeOf(subType: String): Boolean = false + + override def isBooleanType: Boolean = false +} diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala index fe3595eac..d671d7f90 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala @@ -101,8 +101,9 @@ class OpalStatement(val delegate: Stmt[TacLocal], m: OpalMethod) extends Stateme } if (isFieldStore) { - // TODO Is it correct? - return new OpalVal(delegate.asPutField.objRef, m) + val fieldStore = delegate.asPutField + + return OpalInstanceFieldRef(fieldStore.objRef.asVar, fieldStore.declaredFieldType, fieldStore.name, m) } if (isArrayStore) { @@ -125,8 +126,11 @@ class OpalStatement(val delegate: Stmt[TacLocal], m: OpalMethod) extends Stateme if (delegate.isAssignment) { val rightExpr = delegate.asAssignment.expr - // TODO - if (rightExpr.isGetField) {} + if (rightExpr.isGetField) { + val getField = rightExpr.asGetField + + return OpalInstanceFieldRef(getField.objRef.asVar, getField.declaredFieldType, getField.name, m) + } if (rightExpr.isArrayLoad) { val base = rightExpr.asArrayLoad.arrayRef @@ -147,8 +151,13 @@ class OpalStatement(val delegate: Stmt[TacLocal], m: OpalMethod) extends Stateme } if (isFieldStore) { - // TODO Distinguish between constant and variable - return new OpalVal(delegate.asPutField.value, m) + val fieldStore = delegate.asPutField + + if (fieldStore.value.isVar) { + return new OpalLocal(delegate.asPutField.value.asVar, m) + } else { + return new OpalVal(delegate.asPutField.value, m) + } } if (isArrayStore) { @@ -205,7 +214,7 @@ class OpalStatement(val delegate: Stmt[TacLocal], m: OpalMethod) extends Stateme override def getReturnOp: Val = { if (isReturnStmt) { - return new OpalVal(delegate.asReturnValue.expr, m) + return new OpalLocal(delegate.asReturnValue.expr.asVar, m) } throw new RuntimeException("Statement is not a return statement") diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatementFormatter.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatementFormatter.scala index cc0a04b82..e327d9edb 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatementFormatter.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatementFormatter.scala @@ -1,7 +1,7 @@ package boomerang.scope.opal.tac import com.google.common.base.Joiner -import org.opalj.tac.{Nop, Return} +import org.opalj.tac.{Nop, PutField, Return} object OpalStatementFormatter { @@ -18,28 +18,32 @@ object OpalStatementFormatter { assign = s"${stmt.getLeftOp} = " } - return s"${delegate.pc}: $assign$base${stmt.getInvokeExpr.getMethod.getName}(${Joiner.on(",").join(stmt.getInvokeExpr.getArgs)})" + return s"$assign$base${stmt.getInvokeExpr.getMethod.getName}(${Joiner.on(",").join(stmt.getInvokeExpr.getArgs)})" } if (stmt.isAssignStmt) { if (delegate.isAssignment) { if (stmt.isFieldStore) { - return s"${delegate.pc}: ${stmt.getLeftOp} = ${stmt.getFieldStore.getX}.${stmt.getFieldStore.getY}" + return s"${stmt.getLeftOp} = ${stmt.getFieldStore.getX}.${stmt.getFieldStore.getY}" } else if (stmt.isArrayStore) { val base = stmt.getArrayBase - return s"${delegate.pc}: ${base.getX.getVariableName}[${base.getY}] = ${stmt.getRightOp}" + return s"${base.getX.getVariableName}[${base.getY}] = ${stmt.getRightOp}" } else { - return s"${delegate.pc}: ${stmt.getLeftOp} = ${stmt.getRightOp}" + return s"${stmt.getLeftOp} = ${stmt.getRightOp}" } } } + if (delegate.astID == PutField.ASTID) { + return s"${stmt.getLeftOp} = ${stmt.getRightOp}" + } + if (delegate.astID == Nop.ASTID) { - return s"${delegate.pc}: nop" + return "nop" } if (delegate.astID == Return.ASTID) { - return s"${delegate.pc}: return" + return "return" } if (stmt.isReturnStmt) { diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalWrappedClass.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalWrappedClass.scala index a94373e63..2e0a43caa 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalWrappedClass.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalWrappedClass.scala @@ -2,7 +2,7 @@ package boomerang.scope.opal.tac import boomerang.scope.opal.OpalClient import boomerang.scope.{Method, Type, WrappedClass} -import org.opalj.br.{ClassFile, ReferenceType} +import org.opalj.br.ClassFile import java.util @@ -38,7 +38,7 @@ case class OpalWrappedClass(delegate: ClassFile) extends WrappedClass { override def isApplicationClass: Boolean = OpalClient.isApplicationClass(delegate) - override def getFullyQualifiedName: String = delegate.fqn + override def getFullyQualifiedName: String = delegate.fqn.replace("/", ".") override def isPhantom: Boolean = false diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacLocal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacLocal.scala index 60a7da174..19bdbd458 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacLocal.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacLocal.scala @@ -53,7 +53,7 @@ class StackLocal(identifier: Int, computationalType: ComputationalType, valueInf override def value: ValueInformation = valueInfo - override def hashCode: Int = Objects.hash(id) + override def hashCode: Int = Objects.hash(id, isStackLocal, isRegisterLocal, isParameterLocal) override def equals(other: Any): Boolean = other match { case that: StackLocal => this.id == that.id @@ -77,7 +77,7 @@ class RegisterLocal(identifier: Int, computationalType: ComputationalType, value override def value: ValueInformation = valueInfo - override def hashCode: Int = Objects.hash(id) + override def hashCode: Int = Objects.hash(id, isStackLocal, isRegisterLocal, isParameterLocal) override def equals(other: Any): Boolean = other match { case that: RegisterLocal => this.id == that.id @@ -101,7 +101,7 @@ class ParameterLocal(identifier: Int, computationalType: ComputationalType, para override def name: String = paramName - override def hashCode: Int = Objects.hash(id) + override def hashCode: Int = Objects.hash(id, isStackLocal, isRegisterLocal, isParameterLocal) override def equals(other: Any): Boolean = other match { case that: ParameterLocal => this.id == that.id diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalAssignmentTest.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalAssignmentTest.scala index e7af00a19..42ace91d0 100644 --- a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalAssignmentTest.scala +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalAssignmentTest.scala @@ -78,4 +78,25 @@ class OpalAssignmentTest { Assert.assertEquals(3, constantCount) } + + @Test + def fieldStoreAssignmentTest(): Unit = { + val opalSetup = new OpalSetup() + opalSetup.setupOpal(classOf[AssignmentTarget].getName) + + val signature = new MethodSignature(classOf[AssignmentTarget].getName, "fieldStoreAssignment", "Void") + val method = opalSetup.resolveMethod(signature) + val opalMethod = OpalMethod(method) + + opalMethod.getStatements.forEach(stmt => { + if (stmt.isFieldStore) { + Assert.assertTrue(stmt.isAssignStmt) + + val leftOp = stmt.getLeftOp + val rightOp = stmt.getRightOp + + println() + } + }) + } } diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalFieldTest.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalFieldTest.scala index dce566083..4014f9d65 100644 --- a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalFieldTest.scala +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalFieldTest.scala @@ -26,11 +26,11 @@ class OpalFieldTest { Assert.assertFalse(field.isInnerClassField) val fieldLoad = stmt.getFieldLoad - //Assert.assertTrue(fieldLoad.getX.getType.toString.equals(classOf[FieldClass].getName)) + Assert.assertTrue(fieldLoad.getX.getType.toString.equals(classOf[FieldClass].getName)) val fieldType = fieldLoad.getY.getType.toString Assert.assertFalse(fieldLoad.getY.isPredefinedField) - //Assert.assertTrue(fieldType.equals("int") || fieldType.equals(classOf[A].getName)) + Assert.assertTrue(fieldType.equals("int") || fieldType.equals(classOf[A].getName)) } }) @@ -57,7 +57,7 @@ class OpalFieldTest { val fieldType = fieldStore.getY.getType.toString Assert.assertFalse(fieldStore.getY.isPredefinedField) Assert.assertFalse(fieldStore.getY.isInnerClassField) - //Assert.assertTrue(fieldType.equals("int") || fieldType.equals(classOf[A].getName)) + Assert.assertTrue(fieldType.equals("int") || fieldType.equals(classOf[A].getName)) } }) diff --git a/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootScopeTest.java b/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootScopeTest.java index 9f7dea357..ca26d9404 100644 --- a/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootScopeTest.java +++ b/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootScopeTest.java @@ -18,6 +18,7 @@ import boomerang.scope.soot.jimple.JimpleMethod; import boomerang.scope.test.MethodSignature; import boomerang.scope.test.targets.A; +import boomerang.scope.test.targets.AssignmentTarget; import boomerang.scope.test.targets.HashCodeEqualsLocalTarget; import boomerang.scope.test.targets.ParameterLocalsTarget; import boomerang.scope.test.targets.ThisLocalTarget; @@ -137,4 +138,27 @@ public void hashCodeEqualsLocalTest() { Assert.fail("Did not check equals and hashCode methods for parameter locals"); } } + + @Test + public void fieldStoreAssignmentTest() { + SootSetup sootSetup = new SootSetup(); + sootSetup.setupSoot(AssignmentTarget.class.getName()); + + // Parameter locals + MethodSignature signature = + new MethodSignature(AssignmentTarget.class.getName(), "fieldStoreAssignment"); + SootMethod method = sootSetup.resolveMethod(signature); + Method jimpleMethod = JimpleMethod.of(method); + + for (Statement stmt : jimpleMethod.getStatements()) { + if (stmt.isFieldStore()) { + Assert.assertTrue(stmt.isAssignStmt()); + + Val leftOp = stmt.getLeftOp(); + Val rightOp = stmt.getRightOp(); + + System.out.println(); + } + } + } } diff --git a/boomerangScope/src/test/java/boomerang/scope/test/targets/AssignmentTarget.java b/boomerangScope/src/test/java/boomerang/scope/test/targets/AssignmentTarget.java index e497603e0..15cbcb14d 100644 --- a/boomerangScope/src/test/java/boomerang/scope/test/targets/AssignmentTarget.java +++ b/boomerangScope/src/test/java/boomerang/scope/test/targets/AssignmentTarget.java @@ -18,6 +18,7 @@ public class AssignmentTarget { public static void main(String[] args) { arrayAllocation(); constantAssignment(); + fieldStoreAssignment(); } public static void arrayAllocation() { @@ -33,4 +34,11 @@ public static void constantAssignment() { System.out.println(i + l + " " + s); } + + public static void fieldStoreAssignment() { + FieldClass fieldClass = new FieldClass(); + fieldClass.i = 10; + + System.out.println(fieldClass.i); + } } diff --git a/testCore/src/main/java/test/setup/OpalTestSetup.java b/testCore/src/main/java/test/setup/OpalTestSetup.java index caa192d81..e11a50db9 100644 --- a/testCore/src/main/java/test/setup/OpalTestSetup.java +++ b/testCore/src/main/java/test/setup/OpalTestSetup.java @@ -16,21 +16,42 @@ import boomerang.scope.Method; import boomerang.scope.opal.OpalFrameworkScope; import boomerang.scope.opal.tac.OpalMethod; +import com.typesafe.config.Config; +import com.typesafe.config.ConfigValueFactory; import java.io.File; import java.net.URL; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; +import org.opalj.br.BooleanType$; +import org.opalj.br.ByteType$; +import org.opalj.br.CharType$; import org.opalj.br.ClassFile; +import org.opalj.br.DoubleType$; +import org.opalj.br.FieldType; +import org.opalj.br.FloatType$; +import org.opalj.br.IntegerType$; +import org.opalj.br.LongType$; import org.opalj.br.MethodDescriptor$; import org.opalj.br.ObjectType; +import org.opalj.br.ReturnType; +import org.opalj.br.ShortType$; +import org.opalj.br.Type; +import org.opalj.br.VoidType$; import org.opalj.br.analyses.Project; +import org.opalj.br.analyses.Project$; +import org.opalj.br.analyses.cg.InitialEntryPointsKey; import org.opalj.log.DevNullLogger$; import org.opalj.log.GlobalLogContext$; import org.opalj.log.OPALLogger; import org.opalj.tac.cg.CHACallGraphKey$; import org.opalj.tac.cg.CallGraph; import scala.Option; +import scala.collection.immutable.ArraySeq; import scala.jdk.javaapi.CollectionConverters; +import scala.reflect.ClassTag$; public class OpalTestSetup implements TestSetup { @@ -47,22 +68,33 @@ public void initialize( project = Project.apply(new File(classPath)); + // Load the class that contains the test method Option testClass = project.classFile(ObjectType.apply(methodWrapper.getDeclaringClass().replace(".", "/"))); if (testClass.isEmpty()) { throw new RuntimeException("Could not find class " + methodWrapper.getDeclaringClass()); } - // Opal resolves 'void' with 'Void' TODO Add parameters - String signature = - "()" - + ((methodWrapper.getReturnType().equals(MethodWrapper.VOID)) - ? "Void" - : methodWrapper.getReturnType()); + // To resolve the test method, we use Opal's MethodDescriptor that is identified by the + // parameter fields and the return type + List parameterFields = + methodWrapper.getParameters().stream() + .map(p -> FieldType.apply(convertType(p))) + .collect(Collectors.toList()); + Type returnType = ReturnType.apply(convertType(methodWrapper.getReturnType())); + + ArraySeq convertedParamFields = + ArraySeq.from( + CollectionConverters.asScala(parameterFields), + ClassTag$.MODULE$.apply(FieldType.class)); + + // Search the test method in the test class Option method = testClass .get() - .findMethod(methodWrapper.getMethodName(), MethodDescriptor$.MODULE$.apply(signature)); + .findMethod( + methodWrapper.getMethodName(), + MethodDescriptor$.MODULE$.apply(convertedParamFields, returnType)); if (method.isEmpty()) { throw new RuntimeException( "Could not find method " @@ -71,6 +103,28 @@ public void initialize( + methodWrapper.getDeclaringClass()); } + // Update the project's config to set the test method as the (single) entry point + // See + // https://github.com/opalj/opal/blob/ff01c1c9e696946a88b090a52881a41445cf07f1/DEVELOPING_OPAL/tools/src/main/scala/org/opalj/support/info/CallGraph.scala#L406 + Config config = project.config(); + + String key = InitialEntryPointsKey.ConfigKeyPrefix() + "entryPoints"; + List currentValues = config.getList(key).unwrapped(); + + Map configValue = new HashMap<>(); + configValue.put( + "declaringClass", method.get().classFile().thisType().toJava().replace(".", "/")); + configValue.put("name", method.get().name()); + + currentValues.add(ConfigValueFactory.fromMap(configValue)); + config = config.withValue(key, ConfigValueFactory.fromIterable(currentValues)); + config = + config.withValue( + InitialEntryPointsKey.ConfigKeyPrefix() + "analysis", + ConfigValueFactory.fromAnyRef( + "org.opalj.br.analyses.cg.ConfigurationEntryPointsFinder")); + project = Project$.MODULE$.recreate(project, config, true); + testMethod = method.get(); } @@ -90,4 +144,22 @@ public FrameworkScope createFrameworkScope(DataFlowScope dataFlowScope) { CollectionConverters.asScala(Set.of(testMethod)).toSet(), dataFlowScope); } + + private String convertType(String type) { + if (type.equals("void")) return VoidType$.MODULE$.toJVMTypeName(); + if (type.equals("byte")) return ByteType$.MODULE$.toJVMTypeName(); + if (type.equals("char")) return CharType$.MODULE$.toJVMTypeName(); + if (type.equals("double")) return DoubleType$.MODULE$.toJVMTypeName(); + if (type.equals("float")) return FloatType$.MODULE$.toJVMTypeName(); + if (type.equals("int")) return IntegerType$.MODULE$.toJVMTypeName(); + if (type.equals("long")) return LongType$.MODULE$.toJVMTypeName(); + if (type.equals("short")) return ShortType$.MODULE$.toJVMTypeName(); + if (type.equals("boolean")) return BooleanType$.MODULE$.toJVMTypeName(); + if (type.contains("[]")) { + return new StringBuilder(type.replace(".", "/")).insert(0, "[").toString(); + } + + // Convert class types: java.lang.Object => Ljava.lang.Object; + return new StringBuilder(type.replace(".", "/")).insert(0, "L").append(";").toString(); + } } From c568b3f1dc488ec5ce03c76c13980e7796a5c14e Mon Sep 17 00:00:00 2001 From: Sven Meyer Date: Fri, 28 Mar 2025 14:45:33 +0100 Subject: [PATCH 26/61] Various small fixes --- .../test/cases/fields/BasicFieldTarget.java | 76 +++++ .../test/cases/fields/BasicFieldTest.java | 37 +++ .../boomerang/scope/opal/OpalCallGraph.scala | 25 +- .../boomerang/scope/opal/tac/OpalField.scala | 2 +- .../scope/opal/tac/OpalInstanceFieldRef.scala | 15 +- .../boomerang/scope/opal/tac/OpalLocal.scala | 2 + .../scope/opal/tac/OpalStatement.scala | 4 +- .../boomerang/scope/opal/tac/OpalVal.scala | 1 + .../opal/transformer/BasicPropagation.scala | 270 ++++++++++++++---- .../transformer/BasicPropagationOld.scala | 85 ++++++ .../opal/transformer/TacTransformer.scala | 19 +- .../boomerang/scope/opal/OpalArrayTest.scala | 2 +- .../boomerang/scope/opal/OpalFieldTest.scala | 20 +- .../scope/opal/OpalInvokeExprTest.scala | 30 +- .../scope/test/targets/ConstructorTarget.java | 38 +++ .../scope/test/targets/FieldClass.java | 8 + .../scope/test/targets/InvokeExprTarget.java | 8 + .../scope/test/targets/SingleTarget.java | 11 + 18 files changed, 567 insertions(+), 86 deletions(-) create mode 100644 boomerangPDS/src/test/java/test/cases/fields/BasicFieldTarget.java create mode 100644 boomerangPDS/src/test/java/test/cases/fields/BasicFieldTest.java create mode 100644 boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/BasicPropagationOld.scala create mode 100644 boomerangScope/src/test/java/boomerang/scope/test/targets/ConstructorTarget.java diff --git a/boomerangPDS/src/test/java/test/cases/fields/BasicFieldTarget.java b/boomerangPDS/src/test/java/test/cases/fields/BasicFieldTarget.java new file mode 100644 index 000000000..201a1756a --- /dev/null +++ b/boomerangPDS/src/test/java/test/cases/fields/BasicFieldTarget.java @@ -0,0 +1,76 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ +package test.cases.fields; + +import test.TestMethod; +import test.core.QueryMethods; + +@SuppressWarnings("unused") +public class BasicFieldTarget { + + @TestMethod + public void basicFieldReadAndWriteTest() { + ClassWithField c = new ClassWithField(); + Alloc alloc = new Alloc(); + + c.field = alloc; + Alloc query = c.field; + + QueryMethods.queryFor(query); + } + + @TestMethod + public void basicFieldGetAndSetTest() { + ClassWithField c = new ClassWithField(); + Alloc alloc = new Alloc(); + + c.setField(alloc); + Alloc query = c.getField(); + + QueryMethods.queryFor(query); + } + + @TestMethod + public void nestedFieldReadAndWriteTest() { + ClassWithNestedFields c = new ClassWithNestedFields(); + Alloc alloc = new Alloc(); + + c.c.field = alloc; + Alloc query = c.c.field; + + QueryMethods.queryFor(query); + } + + private static class ClassWithField { + Alloc field; + + public Alloc getField() { + return field; + } + + public void setField(Alloc alloc) { + this.field = alloc; + } + } + + private static class ClassWithNestedFields { + ClassWithField c; + + public ClassWithField getC() { + return c; + } + + public void setC(ClassWithField c) { + this.c = c; + } + } +} diff --git a/boomerangPDS/src/test/java/test/cases/fields/BasicFieldTest.java b/boomerangPDS/src/test/java/test/cases/fields/BasicFieldTest.java new file mode 100644 index 000000000..a6b01e5e5 --- /dev/null +++ b/boomerangPDS/src/test/java/test/cases/fields/BasicFieldTest.java @@ -0,0 +1,37 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ +package test.cases.fields; + +import org.junit.Ignore; +import org.junit.Test; +import test.core.AbstractBoomerangTest; + +public class BasicFieldTest extends AbstractBoomerangTest { + + private final String target = BasicFieldTarget.class.getName(); + + @Test + public void basicFieldReadAndWriteTest() { + analyze(target, testName.getMethodName()); + } + + @Test + public void basicFieldGetAndSetTest() { + analyze(target, testName.getMethodName()); + } + + @Ignore + @Test + public void nestedFieldReadAndWriteTest() { + analyze(target, testName.getMethodName()); + } +} diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalCallGraph.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalCallGraph.scala index 2689b73c5..377f2fe1a 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalCallGraph.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalCallGraph.scala @@ -1,10 +1,11 @@ package boomerang.scope.opal -import boomerang.scope.CallGraph +import boomerang.scope.{CallGraph, InvokeExpr} import boomerang.scope.CallGraph.Edge -import boomerang.scope.opal.tac.{OpalMethod, OpalPhantomMethod, OpalStatement} -import boomerang.scope.opal.transformer.{BoomerangTACode, TacTransformer} +import boomerang.scope.opal.tac.{OpalFunctionInvokeExpr, OpalMethod, OpalMethodInvokeExpr, OpalPhantomMethod, OpalStatement} +import boomerang.scope.opal.transformer.TacTransformer import org.opalj.br.{DefinedMethod, Method, MultipleDefinedMethods, VirtualDeclaredMethod} +import org.opalj.tac.{NonVirtualFunctionCall, StaticFunctionCall, VirtualFunctionCall} class OpalCallGraph(callGraph: org.opalj.tac.cg.CallGraph, entryPoints: Set[Method]) extends CallGraph { @@ -25,7 +26,9 @@ class OpalCallGraph(callGraph: org.opalj.tac.cg.CallGraph, entryPoints: Set[Meth val srcStatement = new OpalStatement(stmt, OpalMethod(method.definedMethod, tacCode)) if (srcStatement.containsInvokeExpr()) { - val callees = callGraph.directCalleesOf(method, stmt.pc) + // Due to inlining variables, the PC's of statements and invoke expressions may differ + val invokeExprPc = getPcForInvokeExpr(srcStatement.getInvokeExpr) + val callees = callGraph.directCalleesOf(method, invokeExprPc) callees.foreach(callee => { callee.method match { @@ -49,6 +52,20 @@ class OpalCallGraph(callGraph: org.opalj.tac.cg.CallGraph, entryPoints: Set[Meth }) } + private def getPcForInvokeExpr(invokeExpr: InvokeExpr): Int = { + invokeExpr match { + case methodInvokeExpr: OpalMethodInvokeExpr => methodInvokeExpr.delegate.pc + case functionInvokeExpr: OpalFunctionInvokeExpr => + functionInvokeExpr.delegate match { + case call: NonVirtualFunctionCall[_] => call.pc + case call: VirtualFunctionCall[_] => call.pc + case call: StaticFunctionCall[_] => call.pc + case _ => throw new RuntimeException("Unknown function call: " + functionInvokeExpr) + } + case _ => throw new RuntimeException("Unknown invoke expression: " + invokeExpr) + } + } + entryPoints.foreach(entryPoint => { if (entryPoint.body.isDefined) { addEntryPoint(OpalMethod(entryPoint)) diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalField.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalField.scala index 67477f215..cb2ff1980 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalField.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalField.scala @@ -11,5 +11,5 @@ case class OpalField(declaringClass: ObjectType, fieldType: FieldType, name: Str override def getType: Type = OpalType(fieldType) - override def toString: String = s"<${declaringClass.fqn}>.${fieldType.toJava} $name" + override def toString: String = s"${declaringClass.fqn}.${fieldType.toJava} $name" } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalInstanceFieldRef.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalInstanceFieldRef.scala index 1f0f7d152..d762adda5 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalInstanceFieldRef.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalInstanceFieldRef.scala @@ -3,7 +3,9 @@ package boomerang.scope.opal.tac import boomerang.scope.{ControlFlowGraph, Method, Pair, Type, Val} import boomerang.scope.opal.transformer.TacLocal -case class OpalInstanceFieldRef(base: TacLocal, fieldType: org.opalj.br.Type, fieldName: String, method: OpalMethod, unbalanced: ControlFlowGraph.Edge = null) extends Val(method, unbalanced) { +import java.util.Objects + +class OpalInstanceFieldRef(val base: TacLocal, val fieldType: org.opalj.br.Type, val fieldName: String, method: OpalMethod, unbalanced: ControlFlowGraph.Edge = null) extends Val(method, unbalanced) { override def getType: Type = OpalType(fieldType) @@ -13,7 +15,7 @@ case class OpalInstanceFieldRef(base: TacLocal, fieldType: org.opalj.br.Type, fi override def getNewExprType: Type = throw new RuntimeException("Instance field ref is not a new expression") - override def asUnbalanced(stmt: ControlFlowGraph.Edge): Val = OpalInstanceFieldRef(base, fieldType, fieldName, method, stmt) + override def asUnbalanced(stmt: ControlFlowGraph.Edge): Val = new OpalInstanceFieldRef(base, fieldType, fieldName, method, stmt) override def isLocal: Boolean = false @@ -51,7 +53,7 @@ case class OpalInstanceFieldRef(base: TacLocal, fieldType: org.opalj.br.Type, fi override def getClassConstantType: Type = throw new RuntimeException("Instance field ref is not a class constant") - override def withNewMethod(callee: Method): Val = OpalInstanceFieldRef(base, fieldType, fieldName, callee.asInstanceOf[OpalMethod]) + override def withNewMethod(callee: Method): Val = new OpalInstanceFieldRef(base, fieldType, fieldName, callee.asInstanceOf[OpalMethod]) override def isLongConstant: Boolean = false @@ -63,5 +65,12 @@ case class OpalInstanceFieldRef(base: TacLocal, fieldType: org.opalj.br.Type, fi override def getVariableName: String = s"$base.$fieldName" + override def hashCode: Int = Objects.hash(base, fieldType, fieldName) + + override def equals(other: Any): Boolean = other match { + case that: OpalInstanceFieldRef => super.equals(other) && this.base == that.base && this.fieldType == that.fieldType && this.fieldName == that.fieldName + case _ => false + } + override def toString: String = getVariableName } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalLocal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalLocal.scala index 37e4a3add..455c9b2c7 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalLocal.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalLocal.scala @@ -23,6 +23,8 @@ class OpalLocal(val delegate: Var[TacLocal], method: OpalMethod, unbalanced: Con } else { return OpalType(value.asReferenceValue.asReferenceType) } + } else { + return OpalType(value.asReferenceValue.upperTypeBound.head) } // Over approximation: Same behavior as in Soot diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala index d671d7f90..bb65245c1 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala @@ -103,7 +103,7 @@ class OpalStatement(val delegate: Stmt[TacLocal], m: OpalMethod) extends Stateme if (isFieldStore) { val fieldStore = delegate.asPutField - return OpalInstanceFieldRef(fieldStore.objRef.asVar, fieldStore.declaredFieldType, fieldStore.name, m) + return new OpalInstanceFieldRef(fieldStore.objRef.asVar, fieldStore.declaredFieldType, fieldStore.name, m) } if (isArrayStore) { @@ -129,7 +129,7 @@ class OpalStatement(val delegate: Stmt[TacLocal], m: OpalMethod) extends Stateme if (rightExpr.isGetField) { val getField = rightExpr.asGetField - return OpalInstanceFieldRef(getField.objRef.asVar, getField.declaredFieldType, getField.name, m) + return new OpalInstanceFieldRef(getField.objRef.asVar, getField.declaredFieldType, getField.name, m) } if (rightExpr.isArrayLoad) { diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalVal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalVal.scala index d450b9c84..5090e888e 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalVal.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalVal.scala @@ -155,6 +155,7 @@ class OpalVal(val delegate: Expr[TacLocal], method: OpalMethod, unbalanced: Cont case longConst: LongConst => longConst.value.toString case newExpr: New => s"new ${newExpr.tpe.toJava}" case newArrayExpr: NewArray[_] => s"new ${newArrayExpr.tpe.toJava}" + case _: NullExpr => "null" case _ => delegate.toString } } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/BasicPropagation.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/BasicPropagation.scala index 4c1ba9935..a5b49127a 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/BasicPropagation.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/BasicPropagation.scala @@ -1,82 +1,242 @@ package boomerang.scope.opal.transformer -import org.opalj.tac.{Assignment, Expr, NewArray, Nop, SimpleValueConst, Stmt} +import org.opalj.br.FieldType +import org.opalj.collection.immutable.IntIntPair +import org.opalj.tac.{ArrayLength, ArrayLoad, ArrayStore, Assignment, BinaryExpr, Checkcast, Compare, Expr, ExprStmt, FunctionCall, GetField, GetStatic, IdBasedVar, If, InstanceOf, InvokedynamicFunctionCall, InvokedynamicMethodCall, MonitorEnter, MonitorExit, NewArray, NonVirtualFunctionCall, NonVirtualMethodCall, Nop, PrefixExpr, PrimitiveTypecastExpr, PutField, PutStatic, ReturnValue, SimpleValueConst, StaticFunctionCall, StaticMethodCall, Stmt, Switch, TACStmts, Throw, VirtualFunctionCall, VirtualMethodCall} object BasicPropagation { - def apply(tacStatements: Array[Stmt[TacLocal]]): Array[Stmt[TacLocal]] = { - val statements = tacStatements.map(identity) + def apply(code: Array[Stmt[TacLocal]]): Array[Stmt[TacLocal]] = { + val statements = code.map(identity) - Range(0, tacStatements.length - 1).foreach(i => { - tacStatements(i) match { - /* Transform constant assignments: - * $s = + val max = code.length - 1 + Range(0, max).foreach(i => { + statements(i) match { + + /* Inline simple stack to register definitions: + * $s = * r = $s * * becomes - * - * Nop - * r = + * r = */ - case Assignment(pc, targetVar, c @ (_: SimpleValueConst)) => - tacStatements(i + 1) match { - // Case: r = $s - case Assignment(nextPc, nextTargetVar, `targetVar`) => + case Assignment(pc, targetVar: StackLocal, c @ (_: SimpleValueConst | _: FunctionCall[TacLocal] | _: GetField[TacLocal] | _: GetStatic)) => + statements(i + 1) match { + case Assignment(nextPc, nextTargetVar: RegisterLocal, `targetVar`) => statements(i) = Nop(pc) statements(i + 1) = Assignment(nextPc, nextTargetVar, c) case _ => } + case _ => + } + }) - /* Transform array assignments and try to find their counts: - * $s0 = 0 - * $s1 = 1 - * $s2 = NewArray(counts($s1, $s0)) - * r = $s2 - * - * becomes - * - * Nop - * Nop - * Nop - * r = NewArray(counts(1, 0)) - */ - case Assignment(pc, targetVar, NewArray(exprPc, counts, tpe)) => - val newCounts = counts.map(c => { - val allocSite = propagateBackward(i, c) - - if (allocSite.isDefined) { - val allocStmt = statements(allocSite.get) - statements(allocSite.get) = Nop(allocStmt.pc) - - allocStmt.asAssignment.expr - } else { - c - } + Range(0, max).foreach(i => { + statements(i) match { + // If we have an assignment $s = r, we replace $s with r in all following statements + case Assignment(pc, stackLocal: StackLocal, registerLocal: RegisterLocal) => + Range.inclusive(i + 1, max).foreach(j => { + val currStmt = statements(j) + statements(j) = updateStatementWithLocal(currStmt, stackLocal, registerLocal) }) - val newArray = NewArray(exprPc, newCounts, tpe) - tacStatements(i + 1) match { - case Assignment(nextPc, nextTargetVar, `targetVar`) => - statements(i) = Nop(pc) - statements(i + 1) = Assignment(nextPc, nextTargetVar, newArray) - case _ => - } + statements(i) = Nop(pc) case _ => } }) - def propagateBackward(i: Int, local: Expr[TacLocal]): Option[Int] = { - Range.inclusive(i - 1, 0, -1).foreach(j => { - val currStmt = statements(j) + def updateStatementWithLocal(stmt: Stmt[TacLocal], stackLocal: StackLocal, registerLocal: RegisterLocal): Stmt[TacLocal] = { + stmt.astID match { + case If.ASTID => + val ifStmt = stmt.asIf - if (currStmt.astID == Assignment.ASTID) { - if (currStmt.asAssignment.targetVar == local && currStmt.asAssignment.expr.isConst) { - return Option(j) - } + val left = updateExpressionWithLocal(ifStmt.left, stackLocal, registerLocal) + val right = updateExpressionWithLocal(ifStmt.left, stackLocal, registerLocal) + + return If(ifStmt.pc, left, ifStmt.condition, right, ifStmt.targetStmt) + case Switch.ASTID => + val switchStmt = stmt.asSwitch + val index = updateExpressionWithLocal(switchStmt.index, stackLocal, registerLocal) + + return Switch(switchStmt.pc, switchStmt.defaultStmt, index, switchStmt.caseStmts.map(p => IntIntPair(-1, p))) + case Assignment.ASTID => + val assignStmt = stmt.asAssignment + val targetVar = updateExpressionWithLocal(assignStmt.targetVar, stackLocal, registerLocal) + val expr = updateExpressionWithLocal(assignStmt.expr, stackLocal, registerLocal) + + return Assignment(assignStmt.pc, targetVar.asVar, expr) + case ReturnValue.ASTID => + val expr = updateExpressionWithLocal(stmt.asReturnValue.expr, stackLocal, registerLocal) + + return ReturnValue(stmt.pc, expr) + case MonitorEnter.ASTID => + val objRef = updateExpressionWithLocal(stmt.asMonitorEnter.objRef, stackLocal, registerLocal) + + return MonitorEnter(stmt.pc, objRef) + case MonitorExit.ASTID => + val objRef = updateExpressionWithLocal(stmt.asMonitorExit.objRef, stackLocal, registerLocal) + + return MonitorExit(stmt.pc, objRef) + case ArrayStore.ASTID => + val arrayStore = stmt.asArrayStore + + val arrayRef = updateExpressionWithLocal(arrayStore.arrayRef, stackLocal, registerLocal) + val index = updateExpressionWithLocal(arrayStore.index, stackLocal, registerLocal) + val value = updateExpressionWithLocal(arrayStore.value, stackLocal, registerLocal) + + return ArrayStore(arrayStore.pc, arrayRef, index, value) + case Throw.ASTID => + val throwStmt = stmt.asThrow + val exception = updateExpressionWithLocal(throwStmt.exception, stackLocal, registerLocal) + + return Throw(throwStmt.pc, exception) + case PutStatic.ASTID => + + val putStatic = stmt.asPutStatic + val value = updateExpressionWithLocal(putStatic.value, stackLocal, registerLocal) + + return PutStatic(putStatic.pc, putStatic.declaringClass, putStatic.name, putStatic.declaredFieldType, value) + case PutField.ASTID => + + val putField = stmt.asPutField + + val objRef = updateExpressionWithLocal(putField.objRef, stackLocal, registerLocal) + val value = updateExpressionWithLocal(putField.value, stackLocal, registerLocal) + + return PutField(putField.pc, putField.declaringClass, putField.name, putField.declaredFieldType, objRef, value) + case NonVirtualMethodCall.ASTID => + val methodCall = stmt.asNonVirtualMethodCall + + val baseLocal = updateExpressionWithLocal(methodCall.receiver, stackLocal, registerLocal) + val paramLocals = methodCall.params.map(p => updateExpressionWithLocal(p, stackLocal, registerLocal)) + + return NonVirtualMethodCall(methodCall.pc, methodCall.declaringClass, methodCall.isInterface, methodCall.name, methodCall.descriptor, baseLocal, paramLocals) + case VirtualMethodCall.ASTID => + val methodCall = stmt.asVirtualMethodCall + + val baseLocal = updateExpressionWithLocal(methodCall.receiver, stackLocal, registerLocal) + val paramLocals = methodCall.params.map(p => updateExpressionWithLocal(p, stackLocal, registerLocal)) + + return VirtualMethodCall(methodCall.pc, methodCall.declaringClass, methodCall.isInterface, methodCall.name, methodCall.descriptor, baseLocal, paramLocals) + case StaticMethodCall.ASTID => + val methodCall = stmt.asStaticMethodCall + val params = methodCall.params.map(p => updateExpressionWithLocal(p, stackLocal, registerLocal)) + + return StaticMethodCall(methodCall.pc, methodCall.declaringClass, methodCall.isInterface, methodCall.name, methodCall.descriptor, params) + case InvokedynamicMethodCall.ASTID => + val methodCall = stmt.asInvokedynamicMethodCall + val params = methodCall.params.map(p => updateExpressionWithLocal(p, stackLocal, registerLocal)) + + return InvokedynamicMethodCall(methodCall.pc, methodCall.bootstrapMethod, methodCall.name, methodCall.descriptor, params) + case ExprStmt.ASTID => + val expr = updateExpressionWithLocal(stmt.asExprStmt.expr, stackLocal, registerLocal) + + return ExprStmt(stmt.pc, expr) + case Checkcast.ASTID => + val castExpr = stmt.asCheckcast + val value = updateExpressionWithLocal(castExpr.value, stackLocal, registerLocal) + + return Checkcast(castExpr.pc, value, castExpr.cmpTpe) + case _ => return stmt + } + + throw new RuntimeException("Could not update statement: " + stmt) + } + + def updateExpressionWithLocal(expr: Expr[TacLocal], stackLocal: StackLocal, registerLocal: RegisterLocal): Expr[TacLocal] = { + if (expr.isVar) { + if (expr.asVar.isRegisterLocal) return expr + + // Replace stack local with register local + if (expr.asVar.isStackLocal && expr.asVar == stackLocal) { + return registerLocal + } else { + return expr } - }) + } + + expr.astID match { + case InstanceOf.ASTID => + val instanceOf = expr.asInstanceOf + val value = updateExpressionWithLocal(instanceOf.value, stackLocal, registerLocal) + + return InstanceOf(instanceOf.pc, value, instanceOf.cmpTpe) + case Compare.ASTID => + val compareExpr = expr.asCompare + + val leftLocal = updateExpressionWithLocal(compareExpr.left, stackLocal, registerLocal) + val rightLocal = updateExpressionWithLocal(compareExpr.right, stackLocal, registerLocal) + + return Compare(compareExpr.pc, leftLocal, compareExpr.condition, rightLocal) + case BinaryExpr.ASTID => + val binaryExpr = expr.asBinaryExpr + + val left = updateExpressionWithLocal(binaryExpr.left, stackLocal, registerLocal) + val right = updateExpressionWithLocal(binaryExpr.right, stackLocal, registerLocal) + + return BinaryExpr(binaryExpr.pc, binaryExpr.cTpe, binaryExpr.op, left, right) + case PrefixExpr.ASTID => + val prefixExpr = expr.asPrefixExpr + val operand = updateExpressionWithLocal(prefixExpr.operand, stackLocal, registerLocal) + + return PrefixExpr(prefixExpr.pc, prefixExpr.cTpe, prefixExpr.op, operand) + case PrimitiveTypecastExpr.ASTID => + val primitiveTypecastExpr = expr.asPrimitiveTypeCastExpr + val operand = updateExpressionWithLocal(primitiveTypecastExpr.operand, stackLocal, registerLocal) + + return PrimitiveTypecastExpr(primitiveTypecastExpr.pc, primitiveTypecastExpr.targetTpe, operand) + case NewArray.ASTID => + val newArray = expr.asNewArray + val counts = newArray.counts.map(c => updateExpressionWithLocal(c, stackLocal, registerLocal)) + + return NewArray(newArray.pc, counts, newArray.tpe) + case ArrayLoad.ASTID => + val arrayLoad = expr.asArrayLoad + + val index = updateExpressionWithLocal(arrayLoad.index, stackLocal, registerLocal) + val arrayRef = updateExpressionWithLocal(arrayLoad.arrayRef, stackLocal, registerLocal) + + return ArrayLoad(arrayLoad.pc, index, arrayRef) + case ArrayLength.ASTID => + val arrayLength = expr.asArrayLength + val arrayRef = updateExpressionWithLocal(arrayLength.arrayRef, stackLocal, registerLocal) + + return ArrayLength(arrayLength.pc, arrayRef) + case GetField.ASTID => + val getField = expr.asGetField + val objRef = updateExpressionWithLocal(getField.objRef, stackLocal, registerLocal) + + return GetField(getField.pc, getField.declaringClass, getField.name, getField.declaredFieldType, objRef) + case InvokedynamicFunctionCall.ASTID => + val functionCall = expr.asInvokedynamicFunctionCall + val params = functionCall.params.map(p => updateExpressionWithLocal(p, stackLocal, registerLocal)) + + return InvokedynamicFunctionCall(functionCall.pc, functionCall.bootstrapMethod, functionCall.name, functionCall.descriptor, params) + case NonVirtualFunctionCall.ASTID => + val functionCall = expr.asNonVirtualFunctionCall + + val base = updateExpressionWithLocal(functionCall.receiver, stackLocal, registerLocal) + val params = functionCall.params.map(p => updateExpressionWithLocal(p, stackLocal, registerLocal)) + + return NonVirtualFunctionCall(functionCall.pc, functionCall.declaringClass, functionCall.isInterface, functionCall.name, functionCall.descriptor, base, params) + case VirtualFunctionCall.ASTID => + val functionCall = expr.asVirtualFunctionCall + + val base = updateExpressionWithLocal(functionCall.receiver, stackLocal, registerLocal) + val params = functionCall.params.map(p => updateExpressionWithLocal(p, stackLocal, registerLocal)) + + return VirtualFunctionCall(functionCall.pc, functionCall.declaringClass, functionCall.isInterface, functionCall.name, functionCall.descriptor, base, params) + case StaticFunctionCall.ASTID => + val functionCall = expr.asStaticFunctionCall + + val params = functionCall.params + val paramLocals = params.map(p => updateExpressionWithLocal(p, stackLocal, registerLocal)) + + return StaticFunctionCall(functionCall.pc, functionCall.declaringClass, functionCall.isInterface, functionCall.name, functionCall.descriptor, paramLocals) + case _ => return expr + } - Option.empty + throw new RuntimeException("Could not update expression: " + expr) } statements diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/BasicPropagationOld.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/BasicPropagationOld.scala new file mode 100644 index 000000000..61d28cd7a --- /dev/null +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/BasicPropagationOld.scala @@ -0,0 +1,85 @@ +package boomerang.scope.opal.transformer + +import org.opalj.tac.{Assignment, Expr, NewArray, Nop, SimpleValueConst, Stmt} + +object BasicPropagationOld { + + def apply(tacStatements: Array[Stmt[TacLocal]]): Array[Stmt[TacLocal]] = { + val statements = tacStatements.map(identity) + + Range(0, tacStatements.length - 1).foreach(i => { + tacStatements(i) match { + /* Transform constant assignments: + * $s = + * r = $s + * + * becomes + * + * Nop + * r = + */ + case Assignment(pc, targetVar, c @ (_: SimpleValueConst)) => + tacStatements(i + 1) match { + // Case: r = $s + case Assignment(nextPc, nextTargetVar, `targetVar`) => + statements(i) = Nop(pc) + statements(i + 1) = Assignment(nextPc, nextTargetVar, c) + case _ => + } + + /* Transform array assignments and try to find their counts: + * $s0 = 0 + * $s1 = 1 + * $s2 = NewArray(counts($s1, $s0)) + * r = $s2 + * + * becomes + * + * Nop + * Nop + * Nop + * r = NewArray(counts(1, 0)) + */ + case Assignment(pc, targetVar, NewArray(exprPc, counts, tpe)) => + val newCounts = counts.map(c => { + val allocSite = propagateBackward(i, c) + + if (allocSite.isDefined) { + val allocStmt = statements(allocSite.get) + statements(allocSite.get) = Nop(allocStmt.pc) + + allocStmt.asAssignment.expr + } else { + c + } + }) + + val newArray = NewArray(exprPc, newCounts, tpe) + tacStatements(i + 1) match { + case Assignment(nextPc, nextTargetVar, `targetVar`) => + statements(i) = Nop(pc) + statements(i + 1) = Assignment(nextPc, nextTargetVar, newArray) + case _ => + } + case _ => + } + }) + + def propagateBackward(i: Int, local: Expr[TacLocal]): Option[Int] = { + Range.inclusive(i - 1, 0, -1).foreach(j => { + val currStmt = statements(j) + + if (currStmt.astID == Assignment.ASTID) { + if (currStmt.asAssignment.targetVar == local && currStmt.asAssignment.expr.isConst) { + return Option(j) + } + } + }) + + Option.empty + } + + statements + } + +} diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacTransformer.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacTransformer.scala index 1d9ee7dbb..916b79819 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacTransformer.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacTransformer.scala @@ -6,7 +6,7 @@ import org.opalj.ai.{AIResult, BaseAI} import org.opalj.br.{ClassHierarchy, Method} import org.opalj.br.cfg.CFGFactory import org.opalj.collection.immutable.IntIntPair -import org.opalj.tac.{ArrayLength, ArrayLoad, ArrayStore, Assignment, BinaryExpr, CaughtException, Checkcast, ClassConst, Compare, DoubleConst, DynamicConst, Expr, ExprStmt, FloatConst, GetField, GetStatic, Goto, IdBasedVar, If, IntConst, InvokedynamicFunctionCall, InvokedynamicMethodCall, JSR, LongConst, MethodHandleConst, MethodTypeConst, MonitorEnter, MonitorExit, NaiveTACode, New, NewArray, NonVirtualFunctionCall, NonVirtualMethodCall, Nop, NullExpr, Param, PrefixExpr, PrimitiveTypecastExpr, PutField, PutStatic, Ret, Return, ReturnValue, StaticFunctionCall, StaticMethodCall, Stmt, StringConst, Switch, TACNaive, TACOptimization, TACStmts, Throw, VirtualFunctionCall, VirtualMethodCall} +import org.opalj.tac.{ArrayLength, ArrayLoad, ArrayStore, Assignment, BinaryExpr, CaughtException, Checkcast, ClassConst, Compare, DoubleConst, DynamicConst, Expr, ExprStmt, FloatConst, GetField, GetStatic, Goto, IdBasedVar, If, InstanceOf, IntConst, InvokedynamicFunctionCall, InvokedynamicMethodCall, JSR, LongConst, MethodHandleConst, MethodTypeConst, MonitorEnter, MonitorExit, NaiveTACode, New, NewArray, NonVirtualFunctionCall, NonVirtualMethodCall, Nop, NullExpr, Param, PrefixExpr, PrimitiveTypecastExpr, PutField, PutStatic, Ret, Return, ReturnValue, StaticFunctionCall, StaticMethodCall, Stmt, StringConst, Switch, TACNaive, TACOptimization, TACStmts, Throw, VirtualFunctionCall, VirtualMethodCall} import scala.collection.mutable @@ -17,7 +17,7 @@ object TacTransformer { var stackCounter = -1 val currentStack = mutable.Map.empty[Int, TacLocal] - val aiResult: AIResult = BaseAI(method, new PrimitiveTACAIDomain(OpalClient.getClassHierarchy, method)) + val aiResult: AIResult = BaseAI(method, new PrimitiveTACAIDomain(classHierarchy, method)) val operandsArray: aiResult.domain.OperandsArray = aiResult.operandsArray val localArray = aiResult.localsArray @@ -62,7 +62,7 @@ object TacTransformer { // Store the current stack and register locals on our own 'stack' currentStack(stmt.asAssignment.targetVar.id) = target - return new Assignment[TacLocal](stmt.pc, target, transformedExpr) + return new Assignment(stmt.pc, target, transformedExpr) } if (stmt.astID == ReturnValue.ASTID) { @@ -191,15 +191,15 @@ object TacTransformer { val nextPc = tacNaive.stmts(tacNaive.pcToIndex(pc) + 1).pc if (idBasedVar.id >= 0) { - if (isThis) { + /*if (isThis) { val value = operandsArray(nextPc).head new StackLocal(-1, idBasedVar.cTpe, value) - } else { + } else {*/ stackCounter += 1 val value = operandsArray(nextPc).head new StackLocal(stackCounter, idBasedVar.cTpe, value) - } + //} } else { val local = localArray(nextPc) new RegisterLocal(idBasedVar.id, idBasedVar.cTpe, local(-idBasedVar.id - 1)) @@ -211,6 +211,13 @@ object TacTransformer { return currentStack.getOrElse(expr.asVar.id, throw new RuntimeException("No local on stack")) } + if (expr.astID == InstanceOf.ASTID) { + val instanceOf = expr.asInstanceOf + val value = transformExpr(instanceOf.value) + + return InstanceOf(instanceOf.pc, value, instanceOf.cmpTpe) + } + if (expr.astID == Compare.ASTID) { val compareExpr = expr.asCompare diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalArrayTest.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalArrayTest.scala index d8352467d..145393404 100644 --- a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalArrayTest.scala +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalArrayTest.scala @@ -1,7 +1,7 @@ package boomerang.scope.opal import boomerang.scope.opal.tac.OpalMethod -import boomerang.scope.opal.transformer.{BasicPropagation, TacLocal} +import boomerang.scope.opal.transformer.{BasicPropagationOld, TacLocal} import boomerang.scope.test.MethodSignature import boomerang.scope.test.targets.ArrayTarget import org.junit.{Assert, Test} diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalFieldTest.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalFieldTest.scala index 4014f9d65..4bfd93ded 100644 --- a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalFieldTest.scala +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalFieldTest.scala @@ -26,7 +26,8 @@ class OpalFieldTest { Assert.assertFalse(field.isInnerClassField) val fieldLoad = stmt.getFieldLoad - Assert.assertTrue(fieldLoad.getX.getType.toString.equals(classOf[FieldClass].getName)) + val classType = fieldLoad.getX.getType.toString + Assert.assertTrue(classType.equals("int") || classType.equals(classOf[FieldClass].getName)) val fieldType = fieldLoad.getY.getType.toString Assert.assertFalse(fieldLoad.getY.isPredefinedField) @@ -52,7 +53,8 @@ class OpalFieldTest { fieldStoreCount += 1 val fieldStore = stmt.getFieldStore - Assert.assertTrue(fieldStore.getX.getType.toString.equals(classOf[FieldClass].getName)) + val fieldClass = fieldStore.getX.getType.toString + Assert.assertTrue(fieldClass.equals("int") || fieldClass.equals(classOf[FieldClass].getName)) val fieldType = fieldStore.getY.getType.toString Assert.assertFalse(fieldStore.getY.isPredefinedField) @@ -83,7 +85,7 @@ class OpalFieldTest { Assert.assertFalse(staticField.field().isInnerClassField) val typeName = staticField.getType.toString - //Assert.assertTrue(typeName.equals("int") || typeName.equals(classOf[A].getName)) + Assert.assertTrue(typeName.equals("int") || typeName.equals(classOf[A].getName)) } }) @@ -109,7 +111,7 @@ class OpalFieldTest { Assert.assertFalse(staticField.field().isInnerClassField) val typeName = staticField.getType.toString - //Assert.assertTrue(typeName.equals("int") || typeName.equals(classOf[A].getName)) + Assert.assertTrue(typeName.equals("int") || typeName.equals(classOf[A].getName)) } }) @@ -135,11 +137,12 @@ class OpalFieldTest { Assert.assertTrue(field.isInnerClassField) val fieldLoad = stmt.getFieldLoad - Assert.assertTrue(fieldLoad.getX.getType.toString.equals(classOf[FieldClass.InnerFieldClass].getName)) + val classType = fieldLoad.getX.getType.toString + Assert.assertTrue(classType.equals("int") || classType.equals(classOf[FieldClass.InnerFieldClass].getName)) val fieldType = fieldLoad.getY.getType.toString Assert.assertFalse(fieldLoad.getY.isPredefinedField) - //Assert.assertTrue(fieldType.equals("int") || fieldType.equals(classOf[A].getName)) + Assert.assertTrue(fieldType.equals("int") || fieldType.equals(classOf[A].getName)) } }) @@ -161,12 +164,13 @@ class OpalFieldTest { fieldStoreCount += 1 val fieldStore = stmt.getFieldStore - Assert.assertTrue(fieldStore.getX.getType.toString.equals(classOf[FieldClass.InnerFieldClass].getName)) + val classType = fieldStore.getX.getType.toString + Assert.assertTrue(classType.equals("int") || classType.equals(classOf[FieldClass.InnerFieldClass].getName)) val fieldType = fieldStore.getY.getType.toString Assert.assertFalse(fieldStore.getY.isPredefinedField) Assert.assertTrue(fieldStore.getY.isInnerClassField) - //Assert.assertTrue(fieldType.equals("int") || fieldType.equals(classOf[A].getName)) + Assert.assertTrue(fieldType.equals("int") || fieldType.equals(classOf[A].getName)) } }) diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala index afb1a2461..a9822729d 100644 --- a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala @@ -3,12 +3,15 @@ package boomerang.scope.opal import boomerang.scope.DataFlowScope import boomerang.scope.opal.tac.OpalMethod import boomerang.scope.test.MethodSignature -import boomerang.scope.test.targets.{InvokeExprTarget, SingleTarget} +import boomerang.scope.test.targets.{ConstructorTarget, InvokeExprTarget, SingleTarget} +import com.typesafe.config.{Config, ConfigValueFactory} import org.junit.Test +import org.opalj.br.analyses.Project +import org.opalj.br.analyses.cg.InitialEntryPointsKey import org.opalj.tac.cg.{CHACallGraphKey, CallGraph} import java.util -import java.util.Set +import java.util.{HashMap, List, Map, Set} import scala.jdk.javaapi.CollectionConverters class OpalInvokeExprTest { @@ -16,17 +19,32 @@ class OpalInvokeExprTest { @Test def instanceInvokeExprTest(): Unit = { val opalSetup = new OpalSetup() - opalSetup.setupOpal(classOf[SingleTarget].getName) + opalSetup.setupOpal(classOf[ConstructorTarget].getName) - val signature = new MethodSignature(classOf[SingleTarget].getName, "identityTest", "Void") + val signature = new MethodSignature(classOf[ConstructorTarget].getName, "undefinedConstructor", "Void") val method = opalSetup.resolveMethod(signature) val opalMethod = OpalMethod(method) opalMethod.getControlFlowGraph + // Update the project's config to set the test method as the (single) entry point + // See + // https://github.com/opalj/opal/blob/ff01c1c9e696946a88b090a52881a41445cf07f1/DEVELOPING_OPAL/tools/src/main/scala/org/opalj/support/info/CallGraph.scala#L406 + var config = OpalClient.project.get.config - val callGraph: CallGraph = OpalClient.project.get.get(CHACallGraphKey) + val key = InitialEntryPointsKey.ConfigKeyPrefix + "entryPoints" + val currentValues = config.getList(key).unwrapped - val scope = new OpalFrameworkScope(OpalClient.project.get, callGraph, CollectionConverters.asScala(util.Set.of(method)).toSet, DataFlowScope.EXCLUDE_PHANTOM_CLASSES) + val configValue = new util.HashMap[String, String] + configValue.put("declaringClass", method.classFile.thisType.toJava.replace(".", "/")) + configValue.put("name", method.name) + + currentValues.add(ConfigValueFactory.fromMap(configValue)) + config = config.withValue(key, ConfigValueFactory.fromIterable(currentValues)) + config = config.withValue(InitialEntryPointsKey.ConfigKeyPrefix + "analysis", ConfigValueFactory.fromAnyRef("org.opalj.br.analyses.cg.ConfigurationEntryPointsFinder")) + val project = Project.recreate(OpalClient.project.get, config, useOldConfigAsFallback = true) + + val callGraph: CallGraph = project.get(CHACallGraphKey) + val scope = new OpalFrameworkScope(project, callGraph, CollectionConverters.asScala(util.Set.of(method)).toSet, DataFlowScope.EXCLUDE_PHANTOM_CLASSES) println(opalMethod.tac.statements.mkString("Array(\n\t", "\n\t", "\n)")) } diff --git a/boomerangScope/src/test/java/boomerang/scope/test/targets/ConstructorTarget.java b/boomerangScope/src/test/java/boomerang/scope/test/targets/ConstructorTarget.java new file mode 100644 index 000000000..204d3e495 --- /dev/null +++ b/boomerangScope/src/test/java/boomerang/scope/test/targets/ConstructorTarget.java @@ -0,0 +1,38 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ +package boomerang.scope.test.targets; + +public class ConstructorTarget { + + public static void main(String[] args) { + definedConstructor(); + undefinedConstructor(); + } + + public static void definedConstructor() { + ClassWithDefinedField defined = new ClassWithDefinedField(); + System.out.println(defined.a); + } + + public static void undefinedConstructor() { + ClassWithUndefinedField undefined = new ClassWithUndefinedField(); + System.out.println(undefined.a); + } + + private static class ClassWithDefinedField { + A a = new A(); + } + + private static class ClassWithUndefinedField { + A a; + } +} diff --git a/boomerangScope/src/test/java/boomerang/scope/test/targets/FieldClass.java b/boomerangScope/src/test/java/boomerang/scope/test/targets/FieldClass.java index ae6902870..480e1e88c 100644 --- a/boomerangScope/src/test/java/boomerang/scope/test/targets/FieldClass.java +++ b/boomerangScope/src/test/java/boomerang/scope/test/targets/FieldClass.java @@ -24,6 +24,14 @@ public FieldClass() { a = new A(); } + public A getA() { + return a; + } + + public void setA(A a) { + this.a = a; + } + public static class InnerFieldClass { public int innerI; diff --git a/boomerangScope/src/test/java/boomerang/scope/test/targets/InvokeExprTarget.java b/boomerangScope/src/test/java/boomerang/scope/test/targets/InvokeExprTarget.java index 3c34ea4d7..e6d1abd3e 100644 --- a/boomerangScope/src/test/java/boomerang/scope/test/targets/InvokeExprTarget.java +++ b/boomerangScope/src/test/java/boomerang/scope/test/targets/InvokeExprTarget.java @@ -50,4 +50,12 @@ public static void alias2() { System.out.println(alias2); } + + public void cast() { + A alias1 = new Subclass(); + Subclass alias2 = (Subclass) alias1; + System.out.println(alias2); + } + + public static class Subclass extends A {} } diff --git a/boomerangScope/src/test/java/boomerang/scope/test/targets/SingleTarget.java b/boomerangScope/src/test/java/boomerang/scope/test/targets/SingleTarget.java index adb7c7374..87f45a9b9 100644 --- a/boomerangScope/src/test/java/boomerang/scope/test/targets/SingleTarget.java +++ b/boomerangScope/src/test/java/boomerang/scope/test/targets/SingleTarget.java @@ -14,6 +14,7 @@ public class SingleTarget { public static void main(String[] args) { + getAndSetField(); identityTest(); } @@ -27,4 +28,14 @@ private static A identity(A param) { A mapped = param; return mapped; } + + private static void getAndSetField() { + FieldClass c = new FieldClass(); + A a = new A(); + + c.setA(a); + A query = c.getA(); + + System.out.println(query); + } } From cadd657e00699552f5d54695e347c15688e1cbf5 Mon Sep 17 00:00:00 2001 From: Sven Meyer Date: Sat, 29 Mar 2025 10:33:49 +0100 Subject: [PATCH 27/61] Prepare for StmtGraph --- .../boomerang/scope/opal/OpalCallGraph.scala | 2 +- .../boomerang/scope/opal/tac/OpalMethod.scala | 2 +- .../transformer/BasicPropagationOld.scala | 85 ---- .../opal/transformer/LocalTransformer.scala | 370 +++++++++++++++++ .../NullifyFieldsTransformer.scala | 71 ++++ .../scope/opal/transformer/TacLocal.scala | 8 +- .../opal/transformer/TacTransformer.scala | 383 +----------------- .../boomerang/scope/opal/OpalArrayTest.scala | 2 - .../scope/opal/OpalInvokeExprTest.scala | 3 +- .../scope/test/targets/ConstructorTarget.java | 6 +- 10 files changed, 465 insertions(+), 467 deletions(-) delete mode 100644 boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/BasicPropagationOld.scala create mode 100644 boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/LocalTransformer.scala create mode 100644 boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/NullifyFieldsTransformer.scala diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalCallGraph.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalCallGraph.scala index 377f2fe1a..cd55450f9 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalCallGraph.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalCallGraph.scala @@ -20,7 +20,7 @@ class OpalCallGraph(callGraph: org.opalj.tac.cg.CallGraph, entryPoints: Set[Meth }) private def addEdgesFromMethod(method: DefinedMethod): Unit = { - val tacCode = TacTransformer(method.definedMethod, OpalClient.getClassHierarchy) + val tacCode = TacTransformer(OpalClient.project.get, method.definedMethod) tacCode.statements.foreach(stmt => { val srcStatement = new OpalStatement(stmt, OpalMethod(method.definedMethod, tacCode)) diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalMethod.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalMethod.scala index b41769637..24251a737 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalMethod.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalMethod.scala @@ -133,7 +133,7 @@ class OpalMethod private(val delegate: org.opalj.br.Method, val tac: BoomerangTA object OpalMethod { - def apply(delegate: org.opalj.br.Method): OpalMethod = new OpalMethod(delegate, TacTransformer(delegate, OpalClient.getClassHierarchy)) + def apply(delegate: org.opalj.br.Method): OpalMethod = new OpalMethod(delegate, TacTransformer(OpalClient.project.get, delegate)) def apply(delegate: org.opalj.br.Method, tac: BoomerangTACode): OpalMethod = new OpalMethod(delegate, tac) } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/BasicPropagationOld.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/BasicPropagationOld.scala deleted file mode 100644 index 61d28cd7a..000000000 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/BasicPropagationOld.scala +++ /dev/null @@ -1,85 +0,0 @@ -package boomerang.scope.opal.transformer - -import org.opalj.tac.{Assignment, Expr, NewArray, Nop, SimpleValueConst, Stmt} - -object BasicPropagationOld { - - def apply(tacStatements: Array[Stmt[TacLocal]]): Array[Stmt[TacLocal]] = { - val statements = tacStatements.map(identity) - - Range(0, tacStatements.length - 1).foreach(i => { - tacStatements(i) match { - /* Transform constant assignments: - * $s = - * r = $s - * - * becomes - * - * Nop - * r = - */ - case Assignment(pc, targetVar, c @ (_: SimpleValueConst)) => - tacStatements(i + 1) match { - // Case: r = $s - case Assignment(nextPc, nextTargetVar, `targetVar`) => - statements(i) = Nop(pc) - statements(i + 1) = Assignment(nextPc, nextTargetVar, c) - case _ => - } - - /* Transform array assignments and try to find their counts: - * $s0 = 0 - * $s1 = 1 - * $s2 = NewArray(counts($s1, $s0)) - * r = $s2 - * - * becomes - * - * Nop - * Nop - * Nop - * r = NewArray(counts(1, 0)) - */ - case Assignment(pc, targetVar, NewArray(exprPc, counts, tpe)) => - val newCounts = counts.map(c => { - val allocSite = propagateBackward(i, c) - - if (allocSite.isDefined) { - val allocStmt = statements(allocSite.get) - statements(allocSite.get) = Nop(allocStmt.pc) - - allocStmt.asAssignment.expr - } else { - c - } - }) - - val newArray = NewArray(exprPc, newCounts, tpe) - tacStatements(i + 1) match { - case Assignment(nextPc, nextTargetVar, `targetVar`) => - statements(i) = Nop(pc) - statements(i + 1) = Assignment(nextPc, nextTargetVar, newArray) - case _ => - } - case _ => - } - }) - - def propagateBackward(i: Int, local: Expr[TacLocal]): Option[Int] = { - Range.inclusive(i - 1, 0, -1).foreach(j => { - val currStmt = statements(j) - - if (currStmt.astID == Assignment.ASTID) { - if (currStmt.asAssignment.targetVar == local && currStmt.asAssignment.expr.isConst) { - return Option(j) - } - } - }) - - Option.empty - } - - statements - } - -} diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/LocalTransformer.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/LocalTransformer.scala new file mode 100644 index 000000000..31f2737eb --- /dev/null +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/LocalTransformer.scala @@ -0,0 +1,370 @@ +package boomerang.scope.opal.transformer + +import org.opalj.ai.{AIResult, BaseAI} +import org.opalj.ai.domain.l0.PrimitiveTACAIDomain +import org.opalj.br.{ClassHierarchy, Method} +import org.opalj.collection.immutable.IntIntPair +import org.opalj.tac.{ArrayLength, ArrayLoad, ArrayStore, Assignment, BinaryExpr, CaughtException, Checkcast, ClassConst, Compare, DoubleConst, DynamicConst, Expr, ExprStmt, FloatConst, GetField, GetStatic, Goto, IdBasedVar, If, InstanceOf, IntConst, InvokedynamicFunctionCall, InvokedynamicMethodCall, JSR, LongConst, MethodHandleConst, MethodTypeConst, MonitorEnter, MonitorExit, NaiveTACode, New, NewArray, NonVirtualFunctionCall, NonVirtualMethodCall, Nop, NullExpr, Param, PrefixExpr, PrimitiveTypecastExpr, PutField, PutStatic, Ret, Return, ReturnValue, StaticFunctionCall, StaticMethodCall, Stmt, StringConst, Switch, TACNaive, Throw, VirtualFunctionCall, VirtualMethodCall} + +import scala.collection.mutable + +object LocalTransformer { + + def apply(method: Method, tacNaive: NaiveTACode[_], aiResult: AIResult): Array[Stmt[TacLocal]] = { + var paramCounter = -1 + var stackCounter = -1 + val currentStack = mutable.Map.empty[Int, TacLocal] + + val operandsArray: aiResult.domain.OperandsArray = aiResult.operandsArray + val localArray = aiResult.localsArray + + def transformStatement(stmt: Stmt[IdBasedVar]): Stmt[TacLocal] = { + if (stmt.astID == If.ASTID) { + val ifStmt = stmt.asIf + + val left = transformExpr(ifStmt.left) + val right = transformExpr(ifStmt.right) + + return If(ifStmt.pc, left, ifStmt.condition, right, ifStmt.targetStmt) + } + + if (stmt.astID == Goto.ASTID) { + return stmt.asGoto + } + + if (stmt.astID == Ret.ASTID) { + return stmt.asRet + } + + if (stmt.astID == JSR.ASTID) { + return stmt.asJSR + } + + if (stmt.astID == Switch.ASTID) { + val switchStmt = stmt.asSwitch + val index = transformExpr(switchStmt.index) + + // Inserting -1 as it is only used in previous remapping steps + return Switch(switchStmt.pc, switchStmt.defaultStmt, index, switchStmt.caseStmts.map(p => IntIntPair(-1, p))) + } + + if (stmt.astID == Assignment.ASTID) { + val transformedExpr = transformExpr(stmt.asAssignment.expr) + val isThisAssignment = !method.isStatic && transformedExpr.isVar && transformedExpr.asVar.id == -1 + + val target = createNewLocal(stmt.pc, stmt.asAssignment.targetVar, isThisAssignment) + + // Store the current stack and register locals on our own 'stack' + currentStack(stmt.asAssignment.targetVar.id) = target + + return new Assignment(stmt.pc, target, transformedExpr) + } + + if (stmt.astID == ReturnValue.ASTID) { + val returnStmt = stmt.asReturnValue + val returnValue = transformExpr(returnStmt.expr) + + return ReturnValue(returnStmt.pc, returnValue) + } + + if (stmt.astID == Return.ASTID) { + return Return(stmt.asReturn.pc) + } + + if (stmt.astID == Nop.ASTID) { + return Nop(stmt.asNop.pc) + } + + if (stmt.astID == MonitorEnter.ASTID) { + val monitorEnter = stmt.asMonitorEnter + val objRef = transformExpr(monitorEnter.objRef) + + return MonitorEnter(monitorEnter.pc, objRef) + } + + if (stmt.astID == MonitorExit.ASTID) { + val monitorExit = stmt.asMonitorExit + val objRef = transformExpr(monitorExit.objRef) + + return MonitorExit(monitorExit.pc, objRef) + } + + if (stmt.astID == ArrayStore.ASTID) { + val arrayStore = stmt.asArrayStore + + val arrayRef = transformExpr(arrayStore.arrayRef) + val index = transformExpr(arrayStore.index) + val value = transformExpr(arrayStore.value) + + return ArrayStore(arrayStore.pc, arrayRef, index, value) + } + + if (stmt.astID == Throw.ASTID) { + val throwStmt = stmt.asThrow + val exception = transformExpr(throwStmt.exception) + + return Throw(throwStmt.pc, exception) + } + + if (stmt.astID == PutStatic.ASTID) { + val putStatic = stmt.asPutStatic + val value = transformExpr(putStatic.value) + + return PutStatic(putStatic.pc, putStatic.declaringClass, putStatic.name, putStatic.declaredFieldType, value) + } + + if (stmt.astID == PutField.ASTID) { + val putField = stmt.asPutField + + val objRef = transformExpr(putField.objRef) + val value = transformExpr(putField.value) + + return PutField(putField.pc, putField.declaringClass, putField.name, putField.declaredFieldType, objRef, value) + } + + if (stmt.astID == NonVirtualMethodCall.ASTID) { + val methodCall = stmt.asNonVirtualMethodCall + + val baseLocal = transformExpr(methodCall.receiver) + val paramLocals = methodCall.params.map(p => transformExpr(p)) + + return NonVirtualMethodCall(methodCall.pc, methodCall.declaringClass, methodCall.isInterface, methodCall.name, methodCall.descriptor, baseLocal, paramLocals) + } + + if (stmt.astID == VirtualMethodCall.ASTID) { + val methodCall = stmt.asVirtualMethodCall + + val baseLocal = transformExpr(methodCall.receiver) + val paramLocals = methodCall.params.map(p => transformExpr(p)) + + return VirtualMethodCall(methodCall.pc, methodCall.declaringClass, methodCall.isInterface, methodCall.name, methodCall.descriptor, baseLocal, paramLocals) + } + + if (stmt.astID == StaticMethodCall.ASTID) { + val methodCall = stmt.asStaticMethodCall + val params = methodCall.params.map(p => transformExpr(p)) + + return StaticMethodCall(methodCall.pc, methodCall.declaringClass, methodCall.isInterface, methodCall.name, methodCall.descriptor, params) + } + + if (stmt.astID == InvokedynamicMethodCall.ASTID) { + val methodCall = stmt.asInvokedynamicMethodCall + val params = methodCall.params.map(p => transformExpr(p)) + + return InvokedynamicMethodCall(methodCall.pc, methodCall.bootstrapMethod, methodCall.name, methodCall.descriptor, params) + } + + if (stmt.astID == ExprStmt.ASTID) { + val expr = transformExpr(stmt.asExprStmt.expr) + + return ExprStmt(stmt.pc, expr) + } + + if (stmt.astID == CaughtException.ASTID) { + val caughtException = stmt.asCaughtException + + return CaughtException(caughtException.pc, caughtException.exceptionType, caughtException.origins) + } + + if (stmt.astID == Checkcast.ASTID) { + val castExpr = stmt.asCheckcast + val value = transformExpr(castExpr.value) + + return Checkcast(castExpr.pc, value, castExpr.cmpTpe) + } + + throw new RuntimeException("Could not transform statement: " + stmt) + } + + def createNewLocal(pc: Int, idBasedVar: IdBasedVar, isThis: Boolean = false): TacLocal = { + if (pc == -1) { + val local = localArray(0) + + return new RegisterLocal(idBasedVar.id, idBasedVar.cTpe, local(-idBasedVar.id - 1)) + } + + val nextPc = tacNaive.stmts(tacNaive.pcToIndex(pc) + 1).pc + + if (idBasedVar.id >= 0) { + /*if (isThis) { + val value = operandsArray(nextPc).head + new StackLocal(-1, idBasedVar.cTpe, value) + } else {*/ + stackCounter += 1 + + val value = operandsArray(nextPc).head + new StackLocal(stackCounter, idBasedVar.cTpe, value) + //} + } else { + val local = localArray(nextPc) + new RegisterLocal(idBasedVar.id, idBasedVar.cTpe, local(-idBasedVar.id - 1)) + } + } + + def transformExpr(expr: Expr[IdBasedVar]): Expr[TacLocal] = { + if (expr.isVar) { + return currentStack.getOrElse(expr.asVar.id, throw new RuntimeException("No local on stack")) + } + + if (expr.astID == InstanceOf.ASTID) { + val instanceOf = expr.asInstanceOf + val value = transformExpr(instanceOf.value) + + return InstanceOf(instanceOf.pc, value, instanceOf.cmpTpe) + } + + if (expr.astID == Compare.ASTID) { + val compareExpr = expr.asCompare + + val leftLocal = transformExpr(compareExpr.left) + val rightLocal = transformExpr(compareExpr.right) + + return Compare(compareExpr.pc, leftLocal, compareExpr.condition, rightLocal) + } + + if (expr.astID == Param.ASTID) { + paramCounter += 1 + return new ParameterLocal(paramCounter, expr.asParam.cTpe, expr.asParam.name) + } + + if (expr.astID == MethodTypeConst.ASTID) { + return MethodTypeConst(expr.asMethodTypeConst.pc, expr.asMethodTypeConst.value) + } + + if (expr.astID == MethodHandleConst.ASTID) { + return MethodHandleConst(expr.asMethodHandleConst.pc, expr.asMethodHandleConst.value) + } + + if (expr.astID == IntConst.ASTID) { + return IntConst(expr.asIntConst.pc, expr.asIntConst.value) + } + + if (expr.astID == LongConst.ASTID) { + return LongConst(expr.asLongConst.pc, expr.asLongConst.value) + } + + if (expr.astID == FloatConst.ASTID) { + return FloatConst(expr.asFloatConst.pc, expr.asFloatConst.value) + } + + if (expr.astID == DoubleConst.ASTID) { + return DoubleConst(expr.asDoubleConst.pc, expr.asDoubleConst.value) + } + + if (expr.astID == StringConst.ASTID) { + return StringConst(expr.asStringConst.pc, expr.asStringConst.value) + } + + if (expr.astID == ClassConst.ASTID) { + return ClassConst(expr.asClassConst.pc, expr.asClassConst.value) + } + + if (expr.astID == DynamicConst.ASTID) { + return DynamicConst(expr.asDynamicConst.pc, expr.asDynamicConst.bootstrapMethod, expr.asDynamicConst.name, expr.asDynamicConst.descriptor) + } + + if (expr.astID == NullExpr.ASTID) { + return NullExpr(expr.asNullExpr.pc) + } + + if (expr.astID == BinaryExpr.ASTID) { + val binaryExpr = expr.asBinaryExpr + + val left = transformExpr(binaryExpr.left) + val right = transformExpr(binaryExpr.right) + + return BinaryExpr(binaryExpr.pc, binaryExpr.cTpe, binaryExpr.op, left, right) + } + + if (expr.astID == PrefixExpr.ASTID) { + val prefixExpr = expr.asPrefixExpr + val operand = transformExpr(prefixExpr.operand) + + return PrefixExpr(prefixExpr.pc, prefixExpr.cTpe, prefixExpr.op, operand) + } + + if (expr.astID == PrimitiveTypecastExpr.ASTID) { + val primitiveTypecastExpr = expr.asPrimitiveTypeCastExpr + val operand = transformExpr(primitiveTypecastExpr.operand) + + return PrimitiveTypecastExpr(primitiveTypecastExpr.pc, primitiveTypecastExpr.targetTpe, operand) + } + + if (expr.astID == New.ASTID) { + return New(expr.asNew.pc, expr.asNew.tpe) + } + + if (expr.astID == NewArray.ASTID) { + val newArray = expr.asNewArray + val counts = newArray.counts.map(c => transformExpr(c)) + + return NewArray(newArray.pc, counts, newArray.tpe) + } + + if (expr.astID == ArrayLoad.ASTID) { + val arrayLoad = expr.asArrayLoad + + val index = transformExpr(arrayLoad.index) + val arrayRef = transformExpr(arrayLoad.arrayRef) + + return ArrayLoad(arrayLoad.pc, index, arrayRef) + } + + if (expr.astID == ArrayLength.ASTID) { + val arrayLength = expr.asArrayLength + val arrayRef = transformExpr(arrayLength.arrayRef) + + return ArrayLength(arrayLength.pc, arrayRef) + } + + if (expr.astID == GetField.ASTID) { + val getField = expr.asGetField + val objRef = transformExpr(getField.objRef) + + return GetField(getField.pc, getField.declaringClass, getField.name, getField.declaredFieldType, objRef) + } + + if (expr.astID == GetStatic.ASTID) { + return GetStatic(expr.asGetStatic.pc, expr.asGetStatic.declaringClass, expr.asGetStatic.name, expr.asGetStatic.declaredFieldType) + } + + if (expr.astID == InvokedynamicFunctionCall.ASTID) { + val functionCall = expr.asInvokedynamicFunctionCall + val params = functionCall.params.map(p => transformExpr(p)) + + return InvokedynamicFunctionCall(functionCall.pc, functionCall.bootstrapMethod, functionCall.name, functionCall.descriptor, params) + } + + if (expr.astID == NonVirtualFunctionCall.ASTID) { + val functionCall = expr.asNonVirtualFunctionCall + + val base = transformExpr(functionCall.receiver) + val params = functionCall.params.map(p => transformExpr(p)) + + return NonVirtualFunctionCall(functionCall.pc, functionCall.declaringClass, functionCall.isInterface, functionCall.name, functionCall.descriptor, base, params) + } + + if (expr.astID == VirtualFunctionCall.ASTID) { + val functionCall = expr.asVirtualFunctionCall + + val base = transformExpr(functionCall.receiver) + val params = functionCall.params.map(p => transformExpr(p)) + + return VirtualFunctionCall(functionCall.pc, functionCall.declaringClass, functionCall.isInterface, functionCall.name, functionCall.descriptor, base, params) + } + + if (expr.astID == StaticFunctionCall.ASTID) { + val functionCall = expr.asStaticFunctionCall + + val params = functionCall.params + val paramLocals = params.map(p => transformExpr(p)) + + return StaticFunctionCall(functionCall.pc, functionCall.declaringClass, functionCall.isInterface, functionCall.name, functionCall.descriptor, paramLocals) + } + + throw new RuntimeException("Could not transform expression: " + expr) + } + + tacNaive.stmts.map(stmt => transformStatement(stmt)) + } +} diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/NullifyFieldsTransformer.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/NullifyFieldsTransformer.scala new file mode 100644 index 000000000..d8ad9a893 --- /dev/null +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/NullifyFieldsTransformer.scala @@ -0,0 +1,71 @@ +package boomerang.scope.opal.transformer + +import org.opalj.br.{Field, Method} +import org.opalj.tac.{Assignment, Expr, NullExpr, PutField, Stmt} + +object NullifyFieldsTransformer { + + final val NULLIFIED_FIELD = -2 + + def apply(method: Method, tac: Array[Stmt[TacLocal]], pcToIndex: Array[Int]): (Array[Stmt[TacLocal]], Array[Int]) = { + if (!method.isConstructor || method.isStatic) { + return (tac.map(identity), pcToIndex) + } + + var stackCounter = -1 + + def isFieldDefined(field: Field): Boolean = { + // TODO Also consider super classes + tac.foreach { + // TODO Maybe also match 'this' local? + case PutField(_, _, field.name, field.fieldType, _, _) => return true + case _ => + } + false + } + + def getThisLocal: Expr[TacLocal] = { + tac.foreach(stmt => { + if (stmt.pc == -1 && stmt.asAssignment.targetVar.id == -1) return stmt.asAssignment.targetVar + }) + + throw new RuntimeException("'this' local not found in method: " + method.name) + } + + val definedFields = method.classFile.fields.filter(f => isFieldDefined(f)) + val undefinedFields = method.classFile.fields.filter(f => !definedFields.contains(f) && f.isNotStatic && f.isNotFinal) + + // For each undefined field, we add a definition and a field store statement + val cutIndex = 2 * undefinedFields.size + val nullifiedTac = new Array[Stmt[TacLocal]](tac.length + cutIndex) + + // Add the parameter definitions + val paramDefinitions = tac.filter(stmt => stmt.pc == -1) + Range(0, paramDefinitions.length).foreach(i => nullifiedTac(i) = tac(i)) + + // Create the nullified fields + Range(0, undefinedFields.size).foreach(i => { + val currField = undefinedFields(i) + // TODO Types + val local = new StackLocal(stackCounter, null, null) + stackCounter -= 1 + + val defSite = Assignment[TacLocal](NULLIFIED_FIELD, local, NullExpr(NULLIFIED_FIELD)) + val putField = PutField(NULLIFIED_FIELD, method.classFile.thisType, currField.name, currField.fieldType, getThisLocal, local) + + nullifiedTac(paramDefinitions.length + 2 * i) = defSite + nullifiedTac(paramDefinitions.length + 2 * i + 1) = putField + }) + + // Append the original tac statements + val offset = paramDefinitions.length + cutIndex - 1 + Range(paramDefinitions.length, tac.length).foreach(i => { + nullifiedTac(i + offset) = tac(i) + }) + + // Nullified fields were added before the original statements. Hence, the original + // statements are shifted by the amount of new statements + val nullifiedPcToIndex = pcToIndex.map(i => if (i == Int.MinValue) i else i + cutIndex) + (nullifiedTac, nullifiedPcToIndex) + } +} diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacLocal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacLocal.scala index 19bdbd458..821ef439a 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacLocal.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacLocal.scala @@ -41,13 +41,7 @@ class StackLocal(identifier: Int, computationalType: ComputationalType, valueInf override def isParameterLocal: Boolean = false - override def name: String = { - if (identifier == -1) { - "this" - } else { - s"$$s$identifier" - } - } + override def name: String = s"$$s$identifier" override def cTpe: ComputationalType = computationalType diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacTransformer.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacTransformer.scala index 916b79819..0bf22770a 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacTransformer.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacTransformer.scala @@ -1,386 +1,35 @@ package boomerang.scope.opal.transformer -import boomerang.scope.opal.OpalClient -import org.opalj.ai.domain.l0.PrimitiveTACAIDomain import org.opalj.ai.{AIResult, BaseAI} -import org.opalj.br.{ClassHierarchy, Method} +import org.opalj.ai.domain.l0.PrimitiveTACAIDomain +import org.opalj.br.analyses.Project import org.opalj.br.cfg.CFGFactory -import org.opalj.collection.immutable.IntIntPair -import org.opalj.tac.{ArrayLength, ArrayLoad, ArrayStore, Assignment, BinaryExpr, CaughtException, Checkcast, ClassConst, Compare, DoubleConst, DynamicConst, Expr, ExprStmt, FloatConst, GetField, GetStatic, Goto, IdBasedVar, If, InstanceOf, IntConst, InvokedynamicFunctionCall, InvokedynamicMethodCall, JSR, LongConst, MethodHandleConst, MethodTypeConst, MonitorEnter, MonitorExit, NaiveTACode, New, NewArray, NonVirtualFunctionCall, NonVirtualMethodCall, Nop, NullExpr, Param, PrefixExpr, PrimitiveTypecastExpr, PutField, PutStatic, Ret, Return, ReturnValue, StaticFunctionCall, StaticMethodCall, Stmt, StringConst, Switch, TACNaive, TACOptimization, TACStmts, Throw, VirtualFunctionCall, VirtualMethodCall} - -import scala.collection.mutable +import org.opalj.br.Method +import org.opalj.tac.{Stmt, TACNaive, TACStmts} object TacTransformer { - def apply(method: Method, classHierarchy: ClassHierarchy, optimizations: List[TACOptimization[Param, IdBasedVar, NaiveTACode[Param]]] = List.empty): BoomerangTACode = { - var paramCounter = -1 - var stackCounter = -1 - val currentStack = mutable.Map.empty[Int, TacLocal] - - val aiResult: AIResult = BaseAI(method, new PrimitiveTACAIDomain(classHierarchy, method)) - val operandsArray: aiResult.domain.OperandsArray = aiResult.operandsArray - val localArray = aiResult.localsArray - - val tacNaive = TACNaive(method, classHierarchy, optimizations) - - def transformStatement(stmt: Stmt[IdBasedVar]): Stmt[TacLocal] = { - if (stmt.astID == If.ASTID) { - val ifStmt = stmt.asIf - - val left = transformExpr(ifStmt.left) - val right = transformExpr(ifStmt.right) - - return If(ifStmt.pc, left, ifStmt.condition, right, ifStmt.targetStmt) - } - - if (stmt.astID == Goto.ASTID) { - return stmt.asGoto - } - - if (stmt.astID == Ret.ASTID) { - return stmt.asRet - } - - if (stmt.astID == JSR.ASTID) { - return stmt.asJSR - } - - if (stmt.astID == Switch.ASTID) { - val switchStmt = stmt.asSwitch - val index = transformExpr(switchStmt.index) - - // Inserting -1 as it is only used in previous remapping steps - return Switch(switchStmt.pc, switchStmt.defaultStmt, index, switchStmt.caseStmts.map(p => IntIntPair(-1, p))) - } - - if (stmt.astID == Assignment.ASTID) { - val transformedExpr = transformExpr(stmt.asAssignment.expr) - val isThisAssignment = !method.isStatic && transformedExpr.isVar && transformedExpr.asVar.id == -1 - - val target = createNewLocal(stmt.pc, stmt.asAssignment.targetVar, isThisAssignment) - - // Store the current stack and register locals on our own 'stack' - currentStack(stmt.asAssignment.targetVar.id) = target - - return new Assignment(stmt.pc, target, transformedExpr) - } - - if (stmt.astID == ReturnValue.ASTID) { - val returnStmt = stmt.asReturnValue - val returnValue = transformExpr(returnStmt.expr) - - return ReturnValue(returnStmt.pc, returnValue) - } - - if (stmt.astID == Return.ASTID) { - return Return(stmt.asReturn.pc) - } - - if (stmt.astID == Nop.ASTID) { - return Nop(stmt.asNop.pc) - } - - if (stmt.astID == MonitorEnter.ASTID) { - val monitorEnter = stmt.asMonitorEnter - val objRef = transformExpr(monitorEnter.objRef) - - return MonitorEnter(monitorEnter.pc, objRef) - } - - if (stmt.astID == MonitorExit.ASTID) { - val monitorExit = stmt.asMonitorExit - val objRef = transformExpr(monitorExit.objRef) - - return MonitorExit(monitorExit.pc, objRef) - } - - if (stmt.astID == ArrayStore.ASTID) { - val arrayStore = stmt.asArrayStore - - val arrayRef = transformExpr(arrayStore.arrayRef) - val index = transformExpr(arrayStore.index) - val value = transformExpr(arrayStore.value) - - return ArrayStore(arrayStore.pc, arrayRef, index, value) - } - - if (stmt.astID == Throw.ASTID) { - val throwStmt = stmt.asThrow - val exception = transformExpr(throwStmt.exception) - - return Throw(throwStmt.pc, exception) - } - - if (stmt.astID == PutStatic.ASTID) { - val putStatic = stmt.asPutStatic - val value = transformExpr(putStatic.value) - - return PutStatic(putStatic.pc, putStatic.declaringClass, putStatic.name, putStatic.declaredFieldType, value) - } - - if (stmt.astID == PutField.ASTID) { - val putField = stmt.asPutField - - val objRef = transformExpr(putField.objRef) - val value = transformExpr(putField.value) - - return PutField(putField.pc, putField.declaringClass, putField.name, putField.declaredFieldType, objRef, value) - } - - if (stmt.astID == NonVirtualMethodCall.ASTID) { - val methodCall = stmt.asNonVirtualMethodCall - - val baseLocal = transformExpr(methodCall.receiver) - val paramLocals = methodCall.params.map(p => transformExpr(p)) - - return NonVirtualMethodCall(methodCall.pc, methodCall.declaringClass, methodCall.isInterface, methodCall.name, methodCall.descriptor, baseLocal, paramLocals) - } - - if (stmt.astID == VirtualMethodCall.ASTID) { - val methodCall = stmt.asVirtualMethodCall - - val baseLocal = transformExpr(methodCall.receiver) - val paramLocals = methodCall.params.map(p => transformExpr(p)) - - return VirtualMethodCall(methodCall.pc, methodCall.declaringClass, methodCall.isInterface, methodCall.name, methodCall.descriptor, baseLocal, paramLocals) - } - - if (stmt.astID == StaticMethodCall.ASTID) { - val methodCall = stmt.asStaticMethodCall - val params = methodCall.params.map(p => transformExpr(p)) - - return StaticMethodCall(methodCall.pc, methodCall.declaringClass, methodCall.isInterface, methodCall.name, methodCall.descriptor, params) - } - - if (stmt.astID == InvokedynamicMethodCall.ASTID) { - val methodCall = stmt.asInvokedynamicMethodCall - val params = methodCall.params.map(p => transformExpr(p)) - - return InvokedynamicMethodCall(methodCall.pc, methodCall.bootstrapMethod, methodCall.name, methodCall.descriptor, params) - } - - if (stmt.astID == ExprStmt.ASTID) { - val expr = transformExpr(stmt.asExprStmt.expr) - - return ExprStmt(stmt.pc, expr) - } - - if (stmt.astID == CaughtException.ASTID) { - val caughtException = stmt.asCaughtException - - return CaughtException(caughtException.pc, caughtException.exceptionType, caughtException.origins) - } - - if (stmt.astID == Checkcast.ASTID) { - val castExpr = stmt.asCheckcast - val value = transformExpr(castExpr.value) - - return Checkcast(castExpr.pc, value, castExpr.cmpTpe) - } - - throw new RuntimeException("Could not transform statement: " + stmt) - } + def apply(project: Project[_], method: Method): BoomerangTACode = { - def createNewLocal(pc: Int, idBasedVar: IdBasedVar, isThis: Boolean = false): TacLocal = { - if (pc == -1) { - val local = localArray(0) + val aiResult: AIResult = BaseAI(method, new PrimitiveTACAIDomain(project.classHierarchy, method)) - return new RegisterLocal(idBasedVar.id, idBasedVar.cTpe, local(-idBasedVar.id - 1)) - } - - val nextPc = tacNaive.stmts(tacNaive.pcToIndex(pc) + 1).pc - - if (idBasedVar.id >= 0) { - /*if (isThis) { - val value = operandsArray(nextPc).head - new StackLocal(-1, idBasedVar.cTpe, value) - } else {*/ - stackCounter += 1 - - val value = operandsArray(nextPc).head - new StackLocal(stackCounter, idBasedVar.cTpe, value) - //} - } else { - val local = localArray(nextPc) - new RegisterLocal(idBasedVar.id, idBasedVar.cTpe, local(-idBasedVar.id - 1)) - } - } - - def transformExpr(expr: Expr[IdBasedVar]): Expr[TacLocal] = { - if (expr.isVar) { - return currentStack.getOrElse(expr.asVar.id, throw new RuntimeException("No local on stack")) - } - - if (expr.astID == InstanceOf.ASTID) { - val instanceOf = expr.asInstanceOf - val value = transformExpr(instanceOf.value) - - return InstanceOf(instanceOf.pc, value, instanceOf.cmpTpe) - } - - if (expr.astID == Compare.ASTID) { - val compareExpr = expr.asCompare - - val leftLocal = transformExpr(compareExpr.left) - val rightLocal = transformExpr(compareExpr.right) - - return Compare(compareExpr.pc, leftLocal, compareExpr.condition, rightLocal) - } - - if (expr.astID == Param.ASTID) { - paramCounter += 1 - return new ParameterLocal(paramCounter, expr.asParam.cTpe, expr.asParam.name) - } - - if (expr.astID == MethodTypeConst.ASTID) { - return MethodTypeConst(expr.asMethodTypeConst.pc, expr.asMethodTypeConst.value) - } - - if (expr.astID == MethodHandleConst.ASTID) { - return MethodHandleConst(expr.asMethodHandleConst.pc, expr.asMethodHandleConst.value) - } - - if (expr.astID == IntConst.ASTID) { - return IntConst(expr.asIntConst.pc, expr.asIntConst.value) - } - - if (expr.astID == LongConst.ASTID) { - return LongConst(expr.asLongConst.pc, expr.asLongConst.value) - } - - if (expr.astID == FloatConst.ASTID) { - return FloatConst(expr.asFloatConst.pc, expr.asFloatConst.value) - } - - if (expr.astID == DoubleConst.ASTID) { - return DoubleConst(expr.asDoubleConst.pc, expr.asDoubleConst.value) - } - - if (expr.astID == StringConst.ASTID) { - return StringConst(expr.asStringConst.pc, expr.asStringConst.value) - } - - if (expr.astID == ClassConst.ASTID) { - return ClassConst(expr.asClassConst.pc, expr.asClassConst.value) - } - - if (expr.astID == DynamicConst.ASTID) { - return DynamicConst(expr.asDynamicConst.pc, expr.asDynamicConst.bootstrapMethod, expr.asDynamicConst.name, expr.asDynamicConst.descriptor) - } - - if (expr.astID == NullExpr.ASTID) { - return NullExpr(expr.asNullExpr.pc) - } - - if (expr.astID == BinaryExpr.ASTID) { - val binaryExpr = expr.asBinaryExpr - - val left = transformExpr(binaryExpr.left) - val right = transformExpr(binaryExpr.right) - - return BinaryExpr(binaryExpr.pc, binaryExpr.cTpe, binaryExpr.op, left, right) - } - - if (expr.astID == PrefixExpr.ASTID) { - val prefixExpr = expr.asPrefixExpr - val operand = transformExpr(prefixExpr.operand) - - return PrefixExpr(prefixExpr.pc, prefixExpr.cTpe, prefixExpr.op, operand) - } - - if (expr.astID == PrimitiveTypecastExpr.ASTID) { - val primitiveTypecastExpr = expr.asPrimitiveTypeCastExpr - val operand = transformExpr(primitiveTypecastExpr.operand) - - return PrimitiveTypecastExpr(primitiveTypecastExpr.pc, primitiveTypecastExpr.targetTpe, operand) - } - - if (expr.astID == New.ASTID) { - return New(expr.asNew.pc, expr.asNew.tpe) - } - - if (expr.astID == NewArray.ASTID) { - val newArray = expr.asNewArray - val counts = newArray.counts.map(c => transformExpr(c)) - - return NewArray(newArray.pc, counts, newArray.tpe) - } - - if (expr.astID == ArrayLoad.ASTID) { - val arrayLoad = expr.asArrayLoad - - val index = transformExpr(arrayLoad.index) - val arrayRef = transformExpr(arrayLoad.arrayRef) - - return ArrayLoad(arrayLoad.pc, index, arrayRef) - } - - if (expr.astID == ArrayLength.ASTID) { - val arrayLength = expr.asArrayLength - val arrayRef = transformExpr(arrayLength.arrayRef) - - return ArrayLength(arrayLength.pc, arrayRef) - } - - if (expr.astID == GetField.ASTID) { - val getField = expr.asGetField - val objRef = transformExpr(getField.objRef) - - return GetField(getField.pc, getField.declaringClass, getField.name, getField.declaredFieldType, objRef) - } - - if (expr.astID == GetStatic.ASTID) { - return GetStatic(expr.asGetStatic.pc, expr.asGetStatic.declaringClass, expr.asGetStatic.name, expr.asGetStatic.declaredFieldType) - } - - if (expr.astID == InvokedynamicFunctionCall.ASTID) { - val functionCall = expr.asInvokedynamicFunctionCall - val params = functionCall.params.map(p => transformExpr(p)) - - return InvokedynamicFunctionCall(functionCall.pc, functionCall.bootstrapMethod, functionCall.name, functionCall.descriptor, params) - } - - if (expr.astID == NonVirtualFunctionCall.ASTID) { - val functionCall = expr.asNonVirtualFunctionCall - - val base = transformExpr(functionCall.receiver) - val params = functionCall.params.map(p => transformExpr(p)) - - return NonVirtualFunctionCall(functionCall.pc, functionCall.declaringClass, functionCall.isInterface, functionCall.name, functionCall.descriptor, base, params) - } - - if (expr.astID == VirtualFunctionCall.ASTID) { - val functionCall = expr.asVirtualFunctionCall - - val base = transformExpr(functionCall.receiver) - val params = functionCall.params.map(p => transformExpr(p)) - - return VirtualFunctionCall(functionCall.pc, functionCall.declaringClass, functionCall.isInterface, functionCall.name, functionCall.descriptor, base, params) - } - - if (expr.astID == StaticFunctionCall.ASTID) { - val functionCall = expr.asStaticFunctionCall - - val params = functionCall.params - val paramLocals = params.map(p => transformExpr(p)) - - return StaticFunctionCall(functionCall.pc, functionCall.declaringClass, functionCall.isInterface, functionCall.name, functionCall.descriptor, paramLocals) - } - - throw new RuntimeException("Could not transform expression: " + expr) - } + val tacNaive = TACNaive(method, project.classHierarchy) - val transformedTac: Array[Stmt[TacLocal]] = tacNaive.stmts.map(stmt => transformStatement(stmt)) - val optimizedTac: Array[Stmt[TacLocal]] = BasicPropagation(transformedTac) + val transformedTac: Array[Stmt[TacLocal]] = LocalTransformer(method, tacNaive, aiResult) + val simplifiedTac: Array[Stmt[TacLocal]] = BasicPropagation(transformedTac) + val nullifiedTac = NullifyFieldsTransformer(method, simplifiedTac, tacNaive.pcToIndex) // Update the CFG - val cfg = CFGFactory(method, classHierarchy) + val cfg = CFGFactory(method, project.classHierarchy) if (cfg.isEmpty) { throw new RuntimeException("Could not compute CFG for method " + method.name) } - val tacCfg = cfg.get.mapPCsToIndexes[Stmt[TacLocal], TACStmts[TacLocal]](TACStmts(optimizedTac), tacNaive.pcToIndex, i => i, optimizedTac.length) + val tacCfg = cfg.get.mapPCsToIndexes[Stmt[TacLocal], TACStmts[TacLocal]](TACStmts(nullifiedTac._1), nullifiedTac._2, i => i, nullifiedTac._1.length) + val tacCfg2 = cfg.get.mapPCsToIndexes[Stmt[TacLocal], TACStmts[TacLocal]](TACStmts(simplifiedTac), tacNaive.pcToIndex, i => i, simplifiedTac.length) + val preds = tacCfg.predecessors(5) + val preds2 = tacCfg2.predecessors(5) - new BoomerangTACode(tacNaive.params, optimizedTac, tacNaive.pcToIndex, tacCfg, tacNaive.exceptionHandlers) + new BoomerangTACode(tacNaive.params, simplifiedTac, tacNaive.pcToIndex, tacCfg, tacNaive.exceptionHandlers) } } diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalArrayTest.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalArrayTest.scala index 145393404..8ca10a887 100644 --- a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalArrayTest.scala +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalArrayTest.scala @@ -1,12 +1,10 @@ package boomerang.scope.opal import boomerang.scope.opal.tac.OpalMethod -import boomerang.scope.opal.transformer.{BasicPropagationOld, TacLocal} import boomerang.scope.test.MethodSignature import boomerang.scope.test.targets.ArrayTarget import org.junit.{Assert, Test} import org.opalj.br.IntegerType -import org.opalj.tac.Stmt import java.util diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala index a9822729d..bdb7b30f6 100644 --- a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala @@ -26,8 +26,7 @@ class OpalInvokeExprTest { val opalMethod = OpalMethod(method) opalMethod.getControlFlowGraph - // Update the project's config to set the test method as the (single) entry point - // See + // Update the project's config to set the test method as the (single) entry point. See // https://github.com/opalj/opal/blob/ff01c1c9e696946a88b090a52881a41445cf07f1/DEVELOPING_OPAL/tools/src/main/scala/org/opalj/support/info/CallGraph.scala#L406 var config = OpalClient.project.get.config diff --git a/boomerangScope/src/test/java/boomerang/scope/test/targets/ConstructorTarget.java b/boomerangScope/src/test/java/boomerang/scope/test/targets/ConstructorTarget.java index 204d3e495..0b7e9ffc1 100644 --- a/boomerangScope/src/test/java/boomerang/scope/test/targets/ConstructorTarget.java +++ b/boomerangScope/src/test/java/boomerang/scope/test/targets/ConstructorTarget.java @@ -20,19 +20,21 @@ public static void main(String[] args) { public static void definedConstructor() { ClassWithDefinedField defined = new ClassWithDefinedField(); - System.out.println(defined.a); + System.out.println(defined.a + " " + defined.i); } public static void undefinedConstructor() { ClassWithUndefinedField undefined = new ClassWithUndefinedField(); - System.out.println(undefined.a); + System.out.println(undefined.a + " " + undefined.i); } private static class ClassWithDefinedField { A a = new A(); + int i; } private static class ClassWithUndefinedField { A a; + int i = 10; } } From a09e04faa657425dd3ea88d94da5bd8afc63397b Mon Sep 17 00:00:00 2001 From: Sven Meyer Date: Mon, 31 Mar 2025 11:54:24 +0200 Subject: [PATCH 28/61] Add StmtGraph for TAC --- .../scope/opal/tac/OpalControlFlowGraph.scala | 37 ++++++++++- .../scope/opal/tac/OpalStatement.scala | 15 ++++- .../opal/transformer/BoomerangTACode.scala | 8 +-- .../NullifyFieldsTransformer.scala | 22 +++---- .../scope/opal/transformer/StmtGraph.scala | 66 +++++++++++++++++++ .../scope/opal/transformer/TacLocal.scala | 26 +++++++- .../opal/transformer/TacTransformer.scala | 13 ++-- .../boomerang/scope/opal/OpalArrayTest.scala | 3 +- .../boomerang/scope/opal/OpalLocalTest.scala | 3 +- 9 files changed, 161 insertions(+), 32 deletions(-) create mode 100644 boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/StmtGraph.scala diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalControlFlowGraph.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalControlFlowGraph.scala index 755e8e9ac..ac3d3ec46 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalControlFlowGraph.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalControlFlowGraph.scala @@ -50,7 +50,40 @@ class OpalControlFlowGraph(method: OpalMethod) extends ControlFlowGraph { private def buildCache(): Unit = { if (cacheBuilt) return - // Definition of parameter locals + val graph = method.tac.cfg + + val head = new OpalStatement(Nop(-1), method) + startPointCache.add(head) + statements.add(head) + + graph.heads.foreach(stmt => { + val headStmt = new OpalStatement(stmt, method) + + predsOfCache.put(headStmt, head) + succsOfCache.put(head, headStmt) + }) + + graph.tails.foreach(stmt => { + val tailStmt = new OpalStatement(stmt, method) + + endPointCache.add(tailStmt) + }) + + method.tac.statements.foreach(stmt => { + val statement = new OpalStatement(stmt, method) + statements.add(statement) + + graph.predecessors(stmt).foreach(pred => { + val predStmt = new OpalStatement(pred, method) + predsOfCache.put(statement, predStmt) + }) + + graph.successors(stmt).foreach(succ => { + val succStmt = new OpalStatement(succ, method) + succsOfCache.put(statement, succStmt) + }) + }) + /*// Definition of parameter locals method.tac.statements.filter(stmt => stmt.pc == -1).foreach(stmt => { val statement = new OpalStatement(stmt, method) statements.add(statement) @@ -95,7 +128,7 @@ class OpalControlFlowGraph(method: OpalMethod) extends ControlFlowGraph { succsOfCache.put(statement, successorStatement) }) } - }) + })*/ cacheBuilt = true } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala index bb65245c1..f8cc54a13 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala @@ -92,7 +92,18 @@ class OpalStatement(val delegate: Stmt[TacLocal], m: OpalMethod) extends Stateme false } - override def isAssignStmt: Boolean = delegate.isAssignment || isFieldStore || isArrayStore + override def isAssignStmt: Boolean = { + if (delegate.isAssignment) { + if (delegate.asAssignment.expr.isVar) { + return !delegate.asAssignment.expr.asVar.isParameterLocal + } else { + return true + } + } + + // TODO Add static field store + isFieldStore || isArrayStore + } override def getLeftOp: Val = { if (isAssignStmt) { @@ -313,7 +324,7 @@ class OpalStatement(val delegate: Stmt[TacLocal], m: OpalMethod) extends Stateme private def canEqual(a: Any): Boolean = a.isInstanceOf[OpalStatement] override def equals(obj: Any): Boolean = obj match { - case other: OpalStatement => other.canEqual(this) && this.delegate.pc == other.delegate.pc + case other: OpalStatement => other.canEqual(this) && this.delegate == other.delegate case _ => false } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/BoomerangTACode.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/BoomerangTACode.scala index e719e0728..701c85877 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/BoomerangTACode.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/BoomerangTACode.scala @@ -1,15 +1,11 @@ package boomerang.scope.opal.transformer -import org.opalj.br.ExceptionHandlers -import org.opalj.br.cfg.CFG -import org.opalj.tac.{Assignment, Param, Parameters, Stmt, TACStmts} +import org.opalj.tac.{Assignment, Stmt} class BoomerangTACode( - val params: Parameters[Param], val statements: Array[Stmt[TacLocal]], val pcToIndex: Array[Int], - val cfg: CFG[Stmt[TacLocal], TACStmts[TacLocal]], - val exceptionHandlers: ExceptionHandlers + val cfg: StmtGraph ) { def getLocals: Set[TacLocal] = statements.filter(stmt => stmt.astID == Assignment.ASTID).map(stmt => stmt.asAssignment.targetVar).toSet diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/NullifyFieldsTransformer.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/NullifyFieldsTransformer.scala index d8ad9a893..4e0fdb1b9 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/NullifyFieldsTransformer.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/NullifyFieldsTransformer.scala @@ -1,18 +1,18 @@ package boomerang.scope.opal.transformer -import org.opalj.br.{Field, Method} +import org.opalj.br.{ComputationalTypeReference, Field, Method} import org.opalj.tac.{Assignment, Expr, NullExpr, PutField, Stmt} object NullifyFieldsTransformer { final val NULLIFIED_FIELD = -2 - def apply(method: Method, tac: Array[Stmt[TacLocal]], pcToIndex: Array[Int]): (Array[Stmt[TacLocal]], Array[Int]) = { + def apply(method: Method, tac: Array[Stmt[TacLocal]]): (Array[Stmt[TacLocal]], Int) = { if (!method.isConstructor || method.isStatic) { - return (tac.map(identity), pcToIndex) + return (tac.map(identity), 0) } - var stackCounter = -1 + var localCounter = 0 def isFieldDefined(field: Field): Boolean = { // TODO Also consider super classes @@ -36,8 +36,8 @@ object NullifyFieldsTransformer { val undefinedFields = method.classFile.fields.filter(f => !definedFields.contains(f) && f.isNotStatic && f.isNotFinal) // For each undefined field, we add a definition and a field store statement - val cutIndex = 2 * undefinedFields.size - val nullifiedTac = new Array[Stmt[TacLocal]](tac.length + cutIndex) + val offset = 2 * undefinedFields.size + val nullifiedTac = new Array[Stmt[TacLocal]](tac.length + offset) // Add the parameter definitions val paramDefinitions = tac.filter(stmt => stmt.pc == -1) @@ -47,8 +47,8 @@ object NullifyFieldsTransformer { Range(0, undefinedFields.size).foreach(i => { val currField = undefinedFields(i) // TODO Types - val local = new StackLocal(stackCounter, null, null) - stackCounter -= 1 + val local = new NullifiedLocal(localCounter, ComputationalTypeReference) + localCounter += 1 val defSite = Assignment[TacLocal](NULLIFIED_FIELD, local, NullExpr(NULLIFIED_FIELD)) val putField = PutField(NULLIFIED_FIELD, method.classFile.thisType, currField.name, currField.fieldType, getThisLocal, local) @@ -58,14 +58,10 @@ object NullifyFieldsTransformer { }) // Append the original tac statements - val offset = paramDefinitions.length + cutIndex - 1 Range(paramDefinitions.length, tac.length).foreach(i => { nullifiedTac(i + offset) = tac(i) }) - // Nullified fields were added before the original statements. Hence, the original - // statements are shifted by the amount of new statements - val nullifiedPcToIndex = pcToIndex.map(i => if (i == Int.MinValue) i else i + cutIndex) - (nullifiedTac, nullifiedPcToIndex) + (nullifiedTac, offset) } } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/StmtGraph.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/StmtGraph.scala new file mode 100644 index 000000000..52955f074 --- /dev/null +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/StmtGraph.scala @@ -0,0 +1,66 @@ +package boomerang.scope.opal.transformer + +import org.opalj.br.cfg.CFG +import org.opalj.tac.{Stmt, TACStmts} + +class StmtGraph(val heads: Set[Stmt[TacLocal]], val tails: Set[Stmt[TacLocal]], val predecessors: Map[Stmt[TacLocal], Set[Stmt[TacLocal]]], val successors: Map[Stmt[TacLocal], Set[Stmt[TacLocal]]]) { + +} + +object StmtGraph { + + def apply(tac: Array[Stmt[TacLocal]], cfg: CFG[Stmt[TacLocal], TACStmts[TacLocal]], pcToIndex: Array[Int], offset: Int): StmtGraph = { + + def computeHeads: Set[Stmt[TacLocal]] = Set(tac(0)) + + def computeTails: Set[Stmt[TacLocal]] = { + tac.filter(stmt => stmt.pc >= 0).filter(stmt => { + val stmtIndex = pcToIndex(stmt.pc) + val successors = cfg.successors(stmtIndex) + + // No successors => tail statement + successors.isEmpty + }).toSet + } + + def computePredecessors(stmt: Stmt[TacLocal]): Set[Stmt[TacLocal]] = { + // head + if (stmt == tac(0)) return Set.empty + + // Pred of identity statements are just the previous statement + if (stmt.pc < 0) { + val stmtIndex = tac.indexOf(stmt) + return Set(tac(stmtIndex - 1)) + } + + // The first original statement + if (stmt.pc == 0) { + val stmtIndex = tac.indexOf(stmt) + return Set(tac(stmtIndex - 1)) + } + + val stmtIndex = pcToIndex(stmt.pc) + val predecessors = cfg.predecessors(stmtIndex) + predecessors.map(predecessorIndex => tac(predecessorIndex + offset)) + } + + def computeSuccessors(stmt: Stmt[TacLocal]): Set[Stmt[TacLocal]] = { + // Successor of identity statements is just the following statement + if (stmt.pc < 0) { + val stmtIndex = tac.indexOf(stmt) + return Set(tac(stmtIndex + 1)) + } + + val stmtIndex = pcToIndex(stmt.pc) + val successors = cfg.successors(stmtIndex) + successors.map(successorIndex => tac(successorIndex + offset)) + } + + val heads = computeHeads + val tails = computeTails + val predecessors = tac.map(stmt => stmt -> computePredecessors(stmt)).toMap + val successors = tac.map(stmt => stmt -> computeSuccessors(stmt)).toMap + + new StmtGraph(heads, tails, predecessors, successors) + } +} diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacLocal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacLocal.scala index 821ef439a..cc6a84b7d 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacLocal.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacLocal.scala @@ -2,7 +2,7 @@ package boomerang.scope.opal.transformer import org.opalj.br.ComputationalType import org.opalj.tac.{DUVar, Var} -import org.opalj.value.ValueInformation +import org.opalj.value.{IsNullValue, ValueInformation} import java.util.Objects @@ -103,4 +103,28 @@ class ParameterLocal(identifier: Int, computationalType: ComputationalType, para } } +class NullifiedLocal(identifier: Int, computationalType: ComputationalType) extends TacLocal { + + override def id: Int = identifier + + override def isStackLocal: Boolean = false + + override def isRegisterLocal: Boolean = false + + override def isParameterLocal: Boolean = false + + override def cTpe: ComputationalType = computationalType + + override def value: ValueInformation = IsNullValue + + override def name: String = s"n$identifier" + + override def hashCode(): Int = Objects.hash(id, isStackLocal, isRegisterLocal, isParameterLocal) + + override def equals(other: Any): Boolean = other match { + case that: NullifiedLocal => this.id == that.id + case _ => false + } +} + // TODO Consider TempLocal in SWAP diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacTransformer.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacTransformer.scala index 0bf22770a..38b338d06 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacTransformer.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacTransformer.scala @@ -17,7 +17,7 @@ object TacTransformer { val transformedTac: Array[Stmt[TacLocal]] = LocalTransformer(method, tacNaive, aiResult) val simplifiedTac: Array[Stmt[TacLocal]] = BasicPropagation(transformedTac) - val nullifiedTac = NullifyFieldsTransformer(method, simplifiedTac, tacNaive.pcToIndex) + val nullifiedTac = NullifyFieldsTransformer(method, simplifiedTac) // Update the CFG val cfg = CFGFactory(method, project.classHierarchy) @@ -25,11 +25,12 @@ object TacTransformer { throw new RuntimeException("Could not compute CFG for method " + method.name) } - val tacCfg = cfg.get.mapPCsToIndexes[Stmt[TacLocal], TACStmts[TacLocal]](TACStmts(nullifiedTac._1), nullifiedTac._2, i => i, nullifiedTac._1.length) - val tacCfg2 = cfg.get.mapPCsToIndexes[Stmt[TacLocal], TACStmts[TacLocal]](TACStmts(simplifiedTac), tacNaive.pcToIndex, i => i, simplifiedTac.length) - val preds = tacCfg.predecessors(5) - val preds2 = tacCfg2.predecessors(5) + val tacCfg = cfg.get.mapPCsToIndexes[Stmt[TacLocal], TACStmts[TacLocal]](TACStmts(simplifiedTac), tacNaive.pcToIndex, i => i, simplifiedTac.length) + val stmtGraph = StmtGraph(nullifiedTac._1, tacCfg, tacNaive.pcToIndex, nullifiedTac._2) - new BoomerangTACode(tacNaive.params, simplifiedTac, tacNaive.pcToIndex, tacCfg, tacNaive.exceptionHandlers) + // Nullified fields were added before the original statements. Hence, the original + // statements are shifted by the amount of new statements + val nullifiedPcToIndex = tacNaive.pcToIndex.map(i => if (i == Int.MinValue) i else i + nullifiedTac._2) + new BoomerangTACode(nullifiedTac._1, nullifiedPcToIndex, stmtGraph) } } diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalArrayTest.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalArrayTest.scala index 8ca10a887..7cb2ef453 100644 --- a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalArrayTest.scala +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalArrayTest.scala @@ -3,11 +3,12 @@ package boomerang.scope.opal import boomerang.scope.opal.tac.OpalMethod import boomerang.scope.test.MethodSignature import boomerang.scope.test.targets.ArrayTarget -import org.junit.{Assert, Test} +import org.junit.{Assert, Ignore, Test} import org.opalj.br.IntegerType import java.util +@Ignore class OpalArrayTest { private val integerType = IntegerType.toJVMTypeName diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalLocalTest.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalLocalTest.scala index 7b4cc115b..d9dd4188b 100644 --- a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalLocalTest.scala +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalLocalTest.scala @@ -4,11 +4,12 @@ import boomerang.scope.Statement import boomerang.scope.opal.tac.OpalMethod import boomerang.scope.test.targets.{A, HashCodeEqualsLocalTarget, LocalCountTarget, ParameterLocalsTarget, ThisLocalTarget} import boomerang.scope.test.MethodSignature -import org.junit.{Assert, Test} +import org.junit.{Assert, Ignore, Test} import org.opalj.br.IntegerType import java.util +@Ignore class OpalLocalTest { private val integerType = IntegerType.toJVMTypeName From 164e752dda45a44a9a13a319224bdeb81934e038 Mon Sep 17 00:00:00 2001 From: Sven Meyer Date: Tue, 1 Apr 2025 21:01:04 +0200 Subject: [PATCH 29/61] Add simulation for operand stack --- .../scope/opal/OpalFrameworkScope.scala | 4 +- .../opal/transformer/LocalTransformer.scala | 565 ++++++++---------- .../transformer/LocalTransformerOld.scala | 371 ++++++++++++ .../scope/opal/transformer/OperandStack.scala | 105 ++++ .../opal/transformer/TacTransformer.scala | 9 +- .../scope/opal/OpalInvokeExprTest.scala | 4 +- .../boomerang/scope/soot/SootScopeTest.java | 16 +- .../scope/test/targets/SingleTarget.java | 23 + 8 files changed, 754 insertions(+), 343 deletions(-) create mode 100644 boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/LocalTransformerOld.scala create mode 100644 boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/OperandStack.scala diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalFrameworkScope.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalFrameworkScope.scala index afffa6c4d..2ab5a4b6b 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalFrameworkScope.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalFrameworkScope.scala @@ -1,9 +1,7 @@ package boomerang.scope.opal -import boomerang.scope.{CallGraph, DataFlowScope, Field, FrameworkScope, Method, StaticFieldVal, Val} -import org.opalj.ai.domain +import boomerang.scope._ import org.opalj.br.analyses.Project -import org.opalj.tac.ComputeTACAIKey import java.util.stream diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/LocalTransformer.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/LocalTransformer.scala index 31f2737eb..1e90a4365 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/LocalTransformer.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/LocalTransformer.scala @@ -2,175 +2,137 @@ package boomerang.scope.opal.transformer import org.opalj.ai.{AIResult, BaseAI} import org.opalj.ai.domain.l0.PrimitiveTACAIDomain -import org.opalj.br.{ClassHierarchy, Method} +import org.opalj.br.Method import org.opalj.collection.immutable.IntIntPair -import org.opalj.tac.{ArrayLength, ArrayLoad, ArrayStore, Assignment, BinaryExpr, CaughtException, Checkcast, ClassConst, Compare, DoubleConst, DynamicConst, Expr, ExprStmt, FloatConst, GetField, GetStatic, Goto, IdBasedVar, If, InstanceOf, IntConst, InvokedynamicFunctionCall, InvokedynamicMethodCall, JSR, LongConst, MethodHandleConst, MethodTypeConst, MonitorEnter, MonitorExit, NaiveTACode, New, NewArray, NonVirtualFunctionCall, NonVirtualMethodCall, Nop, NullExpr, Param, PrefixExpr, PrimitiveTypecastExpr, PutField, PutStatic, Ret, Return, ReturnValue, StaticFunctionCall, StaticMethodCall, Stmt, StringConst, Switch, TACNaive, Throw, VirtualFunctionCall, VirtualMethodCall} +import org.opalj.tac.{ArrayLength, ArrayLoad, ArrayStore, Assignment, BinaryExpr, CaughtException, Checkcast, ClassConst, Compare, DoubleConst, DynamicConst, Expr, ExprStmt, FloatConst, GetField, GetStatic, Goto, IdBasedVar, If, InstanceOf, IntConst, InvokedynamicFunctionCall, InvokedynamicMethodCall, JSR, LongConst, MethodHandleConst, MethodTypeConst, MonitorEnter, MonitorExit, NaiveTACode, New, NewArray, NonVirtualFunctionCall, NonVirtualMethodCall, Nop, NullExpr, Param, PrefixExpr, PrimitiveTypecastExpr, PutField, PutStatic, Ret, Return, ReturnValue, StaticFunctionCall, StaticMethodCall, Stmt, StringConst, Switch, Throw, VirtualFunctionCall, VirtualMethodCall} import scala.collection.mutable object LocalTransformer { - def apply(method: Method, tacNaive: NaiveTACode[_], aiResult: AIResult): Array[Stmt[TacLocal]] = { + def apply(method: Method, tacNaive: NaiveTACode[_], domain: PrimitiveTACAIDomain): Array[Stmt[TacLocal]] = { var paramCounter = -1 - var stackCounter = -1 - val currentStack = mutable.Map.empty[Int, TacLocal] + val currentLocals = mutable.Map.empty[Int, TacLocal] + val operandStack = OperandStack(tacNaive.stmts, tacNaive.cfg) + // Domain components + val aiResult: AIResult = BaseAI(method, domain) val operandsArray: aiResult.domain.OperandsArray = aiResult.operandsArray - val localArray = aiResult.localsArray + val localArray: aiResult.domain.LocalsArray = aiResult.localsArray def transformStatement(stmt: Stmt[IdBasedVar]): Stmt[TacLocal] = { - if (stmt.astID == If.ASTID) { - val ifStmt = stmt.asIf - - val left = transformExpr(ifStmt.left) - val right = transformExpr(ifStmt.right) - - return If(ifStmt.pc, left, ifStmt.condition, right, ifStmt.targetStmt) - } - - if (stmt.astID == Goto.ASTID) { - return stmt.asGoto - } - - if (stmt.astID == Ret.ASTID) { - return stmt.asRet - } - - if (stmt.astID == JSR.ASTID) { - return stmt.asJSR - } - - if (stmt.astID == Switch.ASTID) { - val switchStmt = stmt.asSwitch - val index = transformExpr(switchStmt.index) - - // Inserting -1 as it is only used in previous remapping steps - return Switch(switchStmt.pc, switchStmt.defaultStmt, index, switchStmt.caseStmts.map(p => IntIntPair(-1, p))) - } - - if (stmt.astID == Assignment.ASTID) { - val transformedExpr = transformExpr(stmt.asAssignment.expr) - val isThisAssignment = !method.isStatic && transformedExpr.isVar && transformedExpr.asVar.id == -1 - - val target = createNewLocal(stmt.pc, stmt.asAssignment.targetVar, isThisAssignment) - - // Store the current stack and register locals on our own 'stack' - currentStack(stmt.asAssignment.targetVar.id) = target - - return new Assignment(stmt.pc, target, transformedExpr) - } - - if (stmt.astID == ReturnValue.ASTID) { - val returnStmt = stmt.asReturnValue - val returnValue = transformExpr(returnStmt.expr) - - return ReturnValue(returnStmt.pc, returnValue) - } - - if (stmt.astID == Return.ASTID) { - return Return(stmt.asReturn.pc) - } - - if (stmt.astID == Nop.ASTID) { - return Nop(stmt.asNop.pc) - } - - if (stmt.astID == MonitorEnter.ASTID) { - val monitorEnter = stmt.asMonitorEnter - val objRef = transformExpr(monitorEnter.objRef) - - return MonitorEnter(monitorEnter.pc, objRef) - } - - if (stmt.astID == MonitorExit.ASTID) { - val monitorExit = stmt.asMonitorExit - val objRef = transformExpr(monitorExit.objRef) - - return MonitorExit(monitorExit.pc, objRef) - } - - if (stmt.astID == ArrayStore.ASTID) { - val arrayStore = stmt.asArrayStore - - val arrayRef = transformExpr(arrayStore.arrayRef) - val index = transformExpr(arrayStore.index) - val value = transformExpr(arrayStore.value) - - return ArrayStore(arrayStore.pc, arrayRef, index, value) - } - - if (stmt.astID == Throw.ASTID) { - val throwStmt = stmt.asThrow - val exception = transformExpr(throwStmt.exception) - - return Throw(throwStmt.pc, exception) - } - - if (stmt.astID == PutStatic.ASTID) { - val putStatic = stmt.asPutStatic - val value = transformExpr(putStatic.value) - - return PutStatic(putStatic.pc, putStatic.declaringClass, putStatic.name, putStatic.declaredFieldType, value) - } - - if (stmt.astID == PutField.ASTID) { - val putField = stmt.asPutField - - val objRef = transformExpr(putField.objRef) - val value = transformExpr(putField.value) - - return PutField(putField.pc, putField.declaringClass, putField.name, putField.declaredFieldType, objRef, value) - } - - if (stmt.astID == NonVirtualMethodCall.ASTID) { - val methodCall = stmt.asNonVirtualMethodCall - - val baseLocal = transformExpr(methodCall.receiver) - val paramLocals = methodCall.params.map(p => transformExpr(p)) - - return NonVirtualMethodCall(methodCall.pc, methodCall.declaringClass, methodCall.isInterface, methodCall.name, methodCall.descriptor, baseLocal, paramLocals) - } - - if (stmt.astID == VirtualMethodCall.ASTID) { - val methodCall = stmt.asVirtualMethodCall - - val baseLocal = transformExpr(methodCall.receiver) - val paramLocals = methodCall.params.map(p => transformExpr(p)) - - return VirtualMethodCall(methodCall.pc, methodCall.declaringClass, methodCall.isInterface, methodCall.name, methodCall.descriptor, baseLocal, paramLocals) - } - - if (stmt.astID == StaticMethodCall.ASTID) { - val methodCall = stmt.asStaticMethodCall - val params = methodCall.params.map(p => transformExpr(p)) - - return StaticMethodCall(methodCall.pc, methodCall.declaringClass, methodCall.isInterface, methodCall.name, methodCall.descriptor, params) - } - - if (stmt.astID == InvokedynamicMethodCall.ASTID) { - val methodCall = stmt.asInvokedynamicMethodCall - val params = methodCall.params.map(p => transformExpr(p)) - - return InvokedynamicMethodCall(methodCall.pc, methodCall.bootstrapMethod, methodCall.name, methodCall.descriptor, params) - } - - if (stmt.astID == ExprStmt.ASTID) { - val expr = transformExpr(stmt.asExprStmt.expr) - - return ExprStmt(stmt.pc, expr) - } - - if (stmt.astID == CaughtException.ASTID) { - val caughtException = stmt.asCaughtException - - return CaughtException(caughtException.pc, caughtException.exceptionType, caughtException.origins) - } - - if (stmt.astID == Checkcast.ASTID) { - val castExpr = stmt.asCheckcast - val value = transformExpr(castExpr.value) - - return Checkcast(castExpr.pc, value, castExpr.cmpTpe) + stmt.astID match { + case If.ASTID => + val ifStmt = stmt.asIf + + val left = transformExpr(stmt.pc, ifStmt.left) + val right = transformExpr(stmt.pc, ifStmt.right) + + return If(ifStmt.pc, left, ifStmt.condition, right, ifStmt.targetStmt) + case Goto.ASTID => + return stmt.asGoto + case Ret.ASTID => + return stmt.asRet + case JSR.ASTID => + return stmt.asJSR + case Switch.ASTID => + val switchStmt = stmt.asSwitch + val index = transformExpr(stmt.pc, switchStmt.index) + + // Inserting -1 as it is only used in previous remapping steps + return Switch(switchStmt.pc, switchStmt.defaultStmt, index, switchStmt.caseStmts.map(p => IntIntPair(-1, p))) + case Assignment.ASTID => + val transformedExpr = transformExpr(stmt.pc, stmt.asAssignment.expr) + val isThisAssignment = !method.isStatic && transformedExpr.isVar && transformedExpr.asVar.id == -1 + + val target = createNewLocal(stmt.pc, stmt.asAssignment.targetVar, isThisAssignment) + + // Store the current stack and register locals on our own 'stack' + currentLocals(target.id) = target + + return new Assignment(stmt.pc, target, transformedExpr) + case ReturnValue.ASTID => + val returnStmt = stmt.asReturnValue + val returnValue = transformExpr(stmt.pc, returnStmt.expr) + + return ReturnValue(returnStmt.pc, returnValue) + case Return.ASTID => + return stmt.asReturn + case Nop.ASTID => + return stmt.asNop + case MonitorEnter.ASTID => + val monitorEnter = stmt.asMonitorEnter + val objRef = transformExpr(stmt.pc, monitorEnter.objRef) + + return MonitorEnter(monitorEnter.pc, objRef) + case MonitorExit.ASTID => + val monitorExit = stmt.asMonitorExit + val objRef = transformExpr(stmt.pc, monitorExit.objRef) + + return MonitorExit(monitorExit.pc, objRef) + case ArrayStore.ASTID => + val arrayStore = stmt.asArrayStore + + val arrayRef = transformExpr(stmt.pc, arrayStore.arrayRef) + val index = transformExpr(stmt.pc, arrayStore.index) + val value = transformExpr(stmt.pc, arrayStore.value) + + return ArrayStore(arrayStore.pc, arrayRef, index, value) + case Throw.ASTID => + val throwStmt = stmt.asThrow + val exception = transformExpr(stmt.pc, throwStmt.exception) + + return Throw(throwStmt.pc, exception) + case PutStatic.ASTID => + val putStatic = stmt.asPutStatic + val value = transformExpr(stmt.pc, putStatic.value) + + return PutStatic(putStatic.pc, putStatic.declaringClass, putStatic.name, putStatic.declaredFieldType, value) + case PutField.ASTID => + val putField = stmt.asPutField + + val objRef = transformExpr(stmt.pc, putField.objRef) + val value = transformExpr(stmt.pc, putField.value) + + return PutField(putField.pc, putField.declaringClass, putField.name, putField.declaredFieldType, objRef, value) + case NonVirtualMethodCall.ASTID => + val methodCall = stmt.asNonVirtualMethodCall + + val baseLocal = transformExpr(stmt.pc, methodCall.receiver) + val paramLocals = methodCall.params.map(p => transformExpr(stmt.pc, p)) + + return NonVirtualMethodCall(methodCall.pc, methodCall.declaringClass, methodCall.isInterface, methodCall.name, methodCall.descriptor, baseLocal, paramLocals) + case VirtualMethodCall.ASTID => + val methodCall = stmt.asVirtualMethodCall + + val baseLocal = transformExpr(stmt.pc, methodCall.receiver) + val paramLocals = methodCall.params.map(p => transformExpr(stmt.pc, p)) + + return VirtualMethodCall(methodCall.pc, methodCall.declaringClass, methodCall.isInterface, methodCall.name, methodCall.descriptor, baseLocal, paramLocals) + case StaticMethodCall.ASTID => + val methodCall = stmt.asStaticMethodCall + val params = methodCall.params.map(p => transformExpr(stmt.pc, p)) + + return StaticMethodCall(methodCall.pc, methodCall.declaringClass, methodCall.isInterface, methodCall.name, methodCall.descriptor, params) + case InvokedynamicMethodCall.ASTID => + val methodCall = stmt.asInvokedynamicMethodCall + val params = methodCall.params.map(p => transformExpr(stmt.pc, p)) + + return InvokedynamicMethodCall(methodCall.pc, methodCall.bootstrapMethod, methodCall.name, methodCall.descriptor, params) + case ExprStmt.ASTID => + val expr = transformExpr(stmt.pc, stmt.asExprStmt.expr) + + return ExprStmt(stmt.pc, expr) + case CaughtException.ASTID => + val caughtException = stmt.asCaughtException + + return CaughtException(caughtException.pc, caughtException.exceptionType, caughtException.origins) + case Checkcast.ASTID => + val castExpr = stmt.asCheckcast + val value = transformExpr(stmt.pc, castExpr.value) + + return Checkcast(castExpr.pc, value, castExpr.cmpTpe) + case _ => throw new RuntimeException("Unknown statement: " + stmt) } throw new RuntimeException("Could not transform statement: " + stmt) @@ -187,13 +149,14 @@ object LocalTransformer { if (idBasedVar.id >= 0) { /*if (isThis) { - val value = operandsArray(nextPc).head - new StackLocal(-1, idBasedVar.cTpe, value) - } else {*/ - stackCounter += 1 + val value = operandsArray(nextPc).head + new StackLocal(-1, idBasedVar.cTpe, value) + } else {*/ + val index = tacNaive.pcToIndex(pc) + val counter = operandStack.operandCounterAtStmt(index + 1, idBasedVar.id) val value = operandsArray(nextPc).head - new StackLocal(stackCounter, idBasedVar.cTpe, value) + new StackLocal(counter, idBasedVar.cTpe, value) //} } else { val local = localArray(nextPc) @@ -201,165 +164,125 @@ object LocalTransformer { } } - def transformExpr(expr: Expr[IdBasedVar]): Expr[TacLocal] = { + def transformExpr(pc: Int, expr: Expr[IdBasedVar]): Expr[TacLocal] = { if (expr.isVar) { - return currentStack.getOrElse(expr.asVar.id, throw new RuntimeException("No local on stack")) - } - - if (expr.astID == InstanceOf.ASTID) { - val instanceOf = expr.asInstanceOf - val value = transformExpr(instanceOf.value) - - return InstanceOf(instanceOf.pc, value, instanceOf.cmpTpe) - } - - if (expr.astID == Compare.ASTID) { - val compareExpr = expr.asCompare - - val leftLocal = transformExpr(compareExpr.left) - val rightLocal = transformExpr(compareExpr.right) - - return Compare(compareExpr.pc, leftLocal, compareExpr.condition, rightLocal) - } - - if (expr.astID == Param.ASTID) { - paramCounter += 1 - return new ParameterLocal(paramCounter, expr.asParam.cTpe, expr.asParam.name) - } - - if (expr.astID == MethodTypeConst.ASTID) { - return MethodTypeConst(expr.asMethodTypeConst.pc, expr.asMethodTypeConst.value) - } - - if (expr.astID == MethodHandleConst.ASTID) { - return MethodHandleConst(expr.asMethodHandleConst.pc, expr.asMethodHandleConst.value) - } - - if (expr.astID == IntConst.ASTID) { - return IntConst(expr.asIntConst.pc, expr.asIntConst.value) - } - - if (expr.astID == LongConst.ASTID) { - return LongConst(expr.asLongConst.pc, expr.asLongConst.value) - } - - if (expr.astID == FloatConst.ASTID) { - return FloatConst(expr.asFloatConst.pc, expr.asFloatConst.value) - } - - if (expr.astID == DoubleConst.ASTID) { - return DoubleConst(expr.asDoubleConst.pc, expr.asDoubleConst.value) - } - - if (expr.astID == StringConst.ASTID) { - return StringConst(expr.asStringConst.pc, expr.asStringConst.value) - } - - if (expr.astID == ClassConst.ASTID) { - return ClassConst(expr.asClassConst.pc, expr.asClassConst.value) - } - - if (expr.astID == DynamicConst.ASTID) { - return DynamicConst(expr.asDynamicConst.pc, expr.asDynamicConst.bootstrapMethod, expr.asDynamicConst.name, expr.asDynamicConst.descriptor) - } - - if (expr.astID == NullExpr.ASTID) { - return NullExpr(expr.asNullExpr.pc) - } - - if (expr.astID == BinaryExpr.ASTID) { - val binaryExpr = expr.asBinaryExpr - - val left = transformExpr(binaryExpr.left) - val right = transformExpr(binaryExpr.right) - - return BinaryExpr(binaryExpr.pc, binaryExpr.cTpe, binaryExpr.op, left, right) - } - - if (expr.astID == PrefixExpr.ASTID) { - val prefixExpr = expr.asPrefixExpr - val operand = transformExpr(prefixExpr.operand) - - return PrefixExpr(prefixExpr.pc, prefixExpr.cTpe, prefixExpr.op, operand) - } - - if (expr.astID == PrimitiveTypecastExpr.ASTID) { - val primitiveTypecastExpr = expr.asPrimitiveTypeCastExpr - val operand = transformExpr(primitiveTypecastExpr.operand) - - return PrimitiveTypecastExpr(primitiveTypecastExpr.pc, primitiveTypecastExpr.targetTpe, operand) - } - - if (expr.astID == New.ASTID) { - return New(expr.asNew.pc, expr.asNew.tpe) - } - - if (expr.astID == NewArray.ASTID) { - val newArray = expr.asNewArray - val counts = newArray.counts.map(c => transformExpr(c)) - - return NewArray(newArray.pc, counts, newArray.tpe) - } - - if (expr.astID == ArrayLoad.ASTID) { - val arrayLoad = expr.asArrayLoad - - val index = transformExpr(arrayLoad.index) - val arrayRef = transformExpr(arrayLoad.arrayRef) - - return ArrayLoad(arrayLoad.pc, index, arrayRef) - } - - if (expr.astID == ArrayLength.ASTID) { - val arrayLength = expr.asArrayLength - val arrayRef = transformExpr(arrayLength.arrayRef) - - return ArrayLength(arrayLength.pc, arrayRef) - } - - if (expr.astID == GetField.ASTID) { - val getField = expr.asGetField - val objRef = transformExpr(getField.objRef) - - return GetField(getField.pc, getField.declaringClass, getField.name, getField.declaredFieldType, objRef) - } - - if (expr.astID == GetStatic.ASTID) { - return GetStatic(expr.asGetStatic.pc, expr.asGetStatic.declaringClass, expr.asGetStatic.name, expr.asGetStatic.declaredFieldType) - } - - if (expr.astID == InvokedynamicFunctionCall.ASTID) { - val functionCall = expr.asInvokedynamicFunctionCall - val params = functionCall.params.map(p => transformExpr(p)) - - return InvokedynamicFunctionCall(functionCall.pc, functionCall.bootstrapMethod, functionCall.name, functionCall.descriptor, params) - } - - if (expr.astID == NonVirtualFunctionCall.ASTID) { - val functionCall = expr.asNonVirtualFunctionCall - - val base = transformExpr(functionCall.receiver) - val params = functionCall.params.map(p => transformExpr(p)) - - return NonVirtualFunctionCall(functionCall.pc, functionCall.declaringClass, functionCall.isInterface, functionCall.name, functionCall.descriptor, base, params) - } - - if (expr.astID == VirtualFunctionCall.ASTID) { - val functionCall = expr.asVirtualFunctionCall - - val base = transformExpr(functionCall.receiver) - val params = functionCall.params.map(p => transformExpr(p)) - - return VirtualFunctionCall(functionCall.pc, functionCall.declaringClass, functionCall.isInterface, functionCall.name, functionCall.descriptor, base, params) - } - - if (expr.astID == StaticFunctionCall.ASTID) { - val functionCall = expr.asStaticFunctionCall - - val params = functionCall.params - val paramLocals = params.map(p => transformExpr(p)) - - return StaticFunctionCall(functionCall.pc, functionCall.declaringClass, functionCall.isInterface, functionCall.name, functionCall.descriptor, paramLocals) + if (expr.asVar.id >= 0) { + val index = tacNaive.pcToIndex(pc) + val count = operandStack.operandCounterAtStmt(index, expr.asVar.id) + + return currentLocals(count) + } + + return currentLocals(expr.asVar.id) + } + + expr.astID match { + case InstanceOf.ASTID => + val instanceOf = expr.asInstanceOf + val value = transformExpr(pc, instanceOf.value) + + return InstanceOf(instanceOf.pc, value, instanceOf.cmpTpe) + case Compare.ASTID => + val compareExpr = expr.asCompare + + val leftLocal = transformExpr(pc, compareExpr.left) + val rightLocal = transformExpr(pc, compareExpr.right) + + return Compare(compareExpr.pc, leftLocal, compareExpr.condition, rightLocal) + case Param.ASTID => + paramCounter += 1 + + return new ParameterLocal(paramCounter, expr.asParam.cTpe, expr.asParam.name) + case MethodTypeConst.ASTID => + return expr.asMethodTypeConst + case MethodHandleConst.ASTID => + return expr.asMethodHandleConst + case IntConst.ASTID => + return expr.asIntConst + case LongConst.ASTID => + return expr.asLongConst + case FloatConst.ASTID => + return expr.asFloatConst + case DoubleConst.ASTID => + return expr.asDoubleConst + case StringConst.ASTID => + return expr.asStringConst + case ClassConst.ASTID => + return expr.asClassConst + case DynamicConst.ASTID => + return expr.asDynamicConst + case NullExpr.ASTID => + return expr.asNullExpr + case BinaryExpr.ASTID => + val binaryExpr = expr.asBinaryExpr + + val left = transformExpr(pc, binaryExpr.left) + val right = transformExpr(pc, binaryExpr.right) + + return BinaryExpr(binaryExpr.pc, binaryExpr.cTpe, binaryExpr.op, left, right) + case PrefixExpr.ASTID => + val prefixExpr = expr.asPrefixExpr + val operand = transformExpr(pc, prefixExpr.operand) + + return PrefixExpr(prefixExpr.pc, prefixExpr.cTpe, prefixExpr.op, operand) + case PrimitiveTypecastExpr.ASTID => + val primitiveTypecastExpr = expr.asPrimitiveTypeCastExpr + val operand = transformExpr(pc, primitiveTypecastExpr.operand) + + return PrimitiveTypecastExpr(primitiveTypecastExpr.pc, primitiveTypecastExpr.targetTpe, operand) + case New.ASTID => + return expr.asNew + case NewArray.ASTID => + val newArray = expr.asNewArray + val counts = newArray.counts.map(c => transformExpr(pc, c)) + + return NewArray(newArray.pc, counts, newArray.tpe) + case ArrayLoad.ASTID => + val arrayLoad = expr.asArrayLoad + + val index = transformExpr(pc, arrayLoad.index) + val arrayRef = transformExpr(pc, arrayLoad.arrayRef) + + return ArrayLoad(arrayLoad.pc, index, arrayRef) + case ArrayLength.ASTID => + val arrayLength = expr.asArrayLength + val arrayRef = transformExpr(pc, arrayLength.arrayRef) + + return ArrayLength(arrayLength.pc, arrayRef) + case GetField.ASTID => + val getField = expr.asGetField + val objRef = transformExpr(pc, getField.objRef) + + return GetField(getField.pc, getField.declaringClass, getField.name, getField.declaredFieldType, objRef) + case GetStatic.ASTID => + return expr.asGetStatic + case InvokedynamicFunctionCall.ASTID => + val functionCall = expr.asInvokedynamicFunctionCall + val params = functionCall.params.map(p => transformExpr(pc, p)) + + return InvokedynamicFunctionCall(functionCall.pc, functionCall.bootstrapMethod, functionCall.name, functionCall.descriptor, params) + case NonVirtualFunctionCall.ASTID => + val functionCall = expr.asNonVirtualFunctionCall + + val base = transformExpr(pc, functionCall.receiver) + val params = functionCall.params.map(p => transformExpr(pc, p)) + + return NonVirtualFunctionCall(functionCall.pc, functionCall.declaringClass, functionCall.isInterface, functionCall.name, functionCall.descriptor, base, params) + case VirtualFunctionCall.ASTID => + val functionCall = expr.asVirtualFunctionCall + + val base = transformExpr(pc, functionCall.receiver) + val params = functionCall.params.map(p => transformExpr(pc, p)) + + return VirtualFunctionCall(functionCall.pc, functionCall.declaringClass, functionCall.isInterface, functionCall.name, functionCall.descriptor, base, params) + case StaticFunctionCall.ASTID => + val functionCall = expr.asStaticFunctionCall + + val params = functionCall.params + val paramLocals = params.map(p => transformExpr(pc, p)) + + return StaticFunctionCall(functionCall.pc, functionCall.declaringClass, functionCall.isInterface, functionCall.name, functionCall.descriptor, paramLocals) + case _ => throw new RuntimeException("Unknown expression: " + expr) } throw new RuntimeException("Could not transform expression: " + expr) diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/LocalTransformerOld.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/LocalTransformerOld.scala new file mode 100644 index 000000000..4cb2b65fc --- /dev/null +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/LocalTransformerOld.scala @@ -0,0 +1,371 @@ +package boomerang.scope.opal.transformer + +import org.opalj.ai.domain.l0.PrimitiveTACAIDomain +import org.opalj.ai.{AIResult, BaseAI} +import org.opalj.br.Method +import org.opalj.collection.immutable.IntIntPair +import org.opalj.tac._ + +import scala.collection.mutable + +object LocalTransformerOld { + + def apply(method: Method, tacNaive: NaiveTACode[_], domain: PrimitiveTACAIDomain): Array[Stmt[TacLocal]] = { + var paramCounter = -1 + var stackCounter = -1 + val currentStack = mutable.Map.empty[Int, TacLocal] + + val aiResult: AIResult = BaseAI(method, domain) + val operandsArray: aiResult.domain.OperandsArray = aiResult.operandsArray + val localArray: aiResult.domain.LocalsArray = aiResult.localsArray + + def transformStatement(stmt: Stmt[IdBasedVar]): Stmt[TacLocal] = { + if (stmt.astID == If.ASTID) { + val ifStmt = stmt.asIf + + val left = transformExpr(stmt.pc, ifStmt.left) + val right = transformExpr(stmt.pc, ifStmt.right) + + return If(ifStmt.pc, left, ifStmt.condition, right, ifStmt.targetStmt) + } + + if (stmt.astID == Goto.ASTID) { + return stmt.asGoto + } + + if (stmt.astID == Ret.ASTID) { + return stmt.asRet + } + + if (stmt.astID == JSR.ASTID) { + return stmt.asJSR + } + + if (stmt.astID == Switch.ASTID) { + val switchStmt = stmt.asSwitch + val index = transformExpr(stmt.pc, switchStmt.index) + + // Inserting -1 as it is only used in previous remapping steps + return Switch(switchStmt.pc, switchStmt.defaultStmt, index, switchStmt.caseStmts.map(p => IntIntPair(-1, p))) + } + + if (stmt.astID == Assignment.ASTID) { + val transformedExpr = transformExpr(stmt.pc, stmt.asAssignment.expr) + val isThisAssignment = !method.isStatic && transformedExpr.isVar && transformedExpr.asVar.id == -1 + + val target = createNewLocal(stmt.pc, stmt.asAssignment.targetVar, isThisAssignment) + + // Store the current stack and register locals on our own 'stack' + currentStack(stmt.asAssignment.targetVar.id) = target + + return new Assignment(stmt.pc, target, transformedExpr) + } + + if (stmt.astID == ReturnValue.ASTID) { + val returnStmt = stmt.asReturnValue + val returnValue = transformExpr(stmt.pc, returnStmt.expr) + + return ReturnValue(returnStmt.pc, returnValue) + } + + if (stmt.astID == Return.ASTID) { + return Return(stmt.asReturn.pc) + } + + if (stmt.astID == Nop.ASTID) { + return Nop(stmt.asNop.pc) + } + + if (stmt.astID == MonitorEnter.ASTID) { + val monitorEnter = stmt.asMonitorEnter + val objRef = transformExpr(stmt.pc, monitorEnter.objRef) + + return MonitorEnter(monitorEnter.pc, objRef) + } + + if (stmt.astID == MonitorExit.ASTID) { + val monitorExit = stmt.asMonitorExit + val objRef = transformExpr(stmt.pc, monitorExit.objRef) + + return MonitorExit(monitorExit.pc, objRef) + } + + if (stmt.astID == ArrayStore.ASTID) { + val arrayStore = stmt.asArrayStore + + val arrayRef = transformExpr(stmt.pc, arrayStore.arrayRef) + val index = transformExpr(stmt.pc, arrayStore.index) + val value = transformExpr(stmt.pc, arrayStore.value) + + return ArrayStore(arrayStore.pc, arrayRef, index, value) + } + + if (stmt.astID == Throw.ASTID) { + val throwStmt = stmt.asThrow + val exception = transformExpr(stmt.pc, throwStmt.exception) + + return Throw(throwStmt.pc, exception) + } + + if (stmt.astID == PutStatic.ASTID) { + val putStatic = stmt.asPutStatic + val value = transformExpr(stmt.pc, putStatic.value) + + return PutStatic(putStatic.pc, putStatic.declaringClass, putStatic.name, putStatic.declaredFieldType, value) + } + + if (stmt.astID == PutField.ASTID) { + val putField = stmt.asPutField + + val objRef = transformExpr(stmt.pc, putField.objRef) + val value = transformExpr(stmt.pc, putField.value) + + return PutField(putField.pc, putField.declaringClass, putField.name, putField.declaredFieldType, objRef, value) + } + + if (stmt.astID == NonVirtualMethodCall.ASTID) { + val methodCall = stmt.asNonVirtualMethodCall + + val baseLocal = transformExpr(stmt.pc, methodCall.receiver) + val paramLocals = methodCall.params.map(p => transformExpr(stmt.pc, p)) + + return NonVirtualMethodCall(methodCall.pc, methodCall.declaringClass, methodCall.isInterface, methodCall.name, methodCall.descriptor, baseLocal, paramLocals) + } + + if (stmt.astID == VirtualMethodCall.ASTID) { + val methodCall = stmt.asVirtualMethodCall + + val baseLocal = transformExpr(stmt.pc, methodCall.receiver) + val paramLocals = methodCall.params.map(p => transformExpr(stmt.pc, p)) + + return VirtualMethodCall(methodCall.pc, methodCall.declaringClass, methodCall.isInterface, methodCall.name, methodCall.descriptor, baseLocal, paramLocals) + } + + if (stmt.astID == StaticMethodCall.ASTID) { + val methodCall = stmt.asStaticMethodCall + val params = methodCall.params.map(p => transformExpr(stmt.pc, p)) + + return StaticMethodCall(methodCall.pc, methodCall.declaringClass, methodCall.isInterface, methodCall.name, methodCall.descriptor, params) + } + + if (stmt.astID == InvokedynamicMethodCall.ASTID) { + val methodCall = stmt.asInvokedynamicMethodCall + val params = methodCall.params.map(p => transformExpr(stmt.pc, p)) + + return InvokedynamicMethodCall(methodCall.pc, methodCall.bootstrapMethod, methodCall.name, methodCall.descriptor, params) + } + + if (stmt.astID == ExprStmt.ASTID) { + val expr = transformExpr(stmt.pc, stmt.asExprStmt.expr) + + return ExprStmt(stmt.pc, expr) + } + + if (stmt.astID == CaughtException.ASTID) { + val caughtException = stmt.asCaughtException + + return CaughtException(caughtException.pc, caughtException.exceptionType, caughtException.origins) + } + + if (stmt.astID == Checkcast.ASTID) { + val castExpr = stmt.asCheckcast + val value = transformExpr(stmt.pc, castExpr.value) + + return Checkcast(castExpr.pc, value, castExpr.cmpTpe) + } + + throw new RuntimeException("Could not transform statement: " + stmt) + } + + def createNewLocal(pc: Int, idBasedVar: IdBasedVar, isThis: Boolean = false): TacLocal = { + if (pc == -1) { + val local = localArray(0) + + return new RegisterLocal(idBasedVar.id, idBasedVar.cTpe, local(-idBasedVar.id - 1)) + } + + val nextPc = tacNaive.stmts(tacNaive.pcToIndex(pc) + 1).pc + + if (idBasedVar.id >= 0) { + /*if (isThis) { + val value = operandsArray(nextPc).head + new StackLocal(-1, idBasedVar.cTpe, value) + } else {*/ + stackCounter += 1 + + val value = operandsArray(nextPc).head + new StackLocal(stackCounter, idBasedVar.cTpe, value) + //} + } else { + val local = localArray(nextPc) + new RegisterLocal(idBasedVar.id, idBasedVar.cTpe, local(-idBasedVar.id - 1)) + } + } + + def transformExpr(pc: Int, expr: Expr[IdBasedVar]): Expr[TacLocal] = { + if (expr.isVar) { + return currentStack.getOrElse(expr.asVar.id, throw new RuntimeException("No local on stack")) + } + + if (expr.astID == InstanceOf.ASTID) { + val instanceOf = expr.asInstanceOf + val value = transformExpr(pc, instanceOf.value) + + return InstanceOf(instanceOf.pc, value, instanceOf.cmpTpe) + } + + if (expr.astID == Compare.ASTID) { + val compareExpr = expr.asCompare + + val leftLocal = transformExpr(pc, compareExpr.left) + val rightLocal = transformExpr(pc, compareExpr.right) + + return Compare(compareExpr.pc, leftLocal, compareExpr.condition, rightLocal) + } + + if (expr.astID == Param.ASTID) { + paramCounter += 1 + return new ParameterLocal(paramCounter, expr.asParam.cTpe, expr.asParam.name) + } + + if (expr.astID == MethodTypeConst.ASTID) { + return MethodTypeConst(expr.asMethodTypeConst.pc, expr.asMethodTypeConst.value) + } + + if (expr.astID == MethodHandleConst.ASTID) { + return MethodHandleConst(expr.asMethodHandleConst.pc, expr.asMethodHandleConst.value) + } + + if (expr.astID == IntConst.ASTID) { + return IntConst(expr.asIntConst.pc, expr.asIntConst.value) + } + + if (expr.astID == LongConst.ASTID) { + return LongConst(expr.asLongConst.pc, expr.asLongConst.value) + } + + if (expr.astID == FloatConst.ASTID) { + return FloatConst(expr.asFloatConst.pc, expr.asFloatConst.value) + } + + if (expr.astID == DoubleConst.ASTID) { + return DoubleConst(expr.asDoubleConst.pc, expr.asDoubleConst.value) + } + + if (expr.astID == StringConst.ASTID) { + return StringConst(expr.asStringConst.pc, expr.asStringConst.value) + } + + if (expr.astID == ClassConst.ASTID) { + return ClassConst(expr.asClassConst.pc, expr.asClassConst.value) + } + + if (expr.astID == DynamicConst.ASTID) { + return DynamicConst(expr.asDynamicConst.pc, expr.asDynamicConst.bootstrapMethod, expr.asDynamicConst.name, expr.asDynamicConst.descriptor) + } + + if (expr.astID == NullExpr.ASTID) { + return NullExpr(expr.asNullExpr.pc) + } + + if (expr.astID == BinaryExpr.ASTID) { + val binaryExpr = expr.asBinaryExpr + + val left = transformExpr(pc, binaryExpr.left) + val right = transformExpr(pc, binaryExpr.right) + + return BinaryExpr(binaryExpr.pc, binaryExpr.cTpe, binaryExpr.op, left, right) + } + + if (expr.astID == PrefixExpr.ASTID) { + val prefixExpr = expr.asPrefixExpr + val operand = transformExpr(pc, prefixExpr.operand) + + return PrefixExpr(prefixExpr.pc, prefixExpr.cTpe, prefixExpr.op, operand) + } + + if (expr.astID == PrimitiveTypecastExpr.ASTID) { + val primitiveTypecastExpr = expr.asPrimitiveTypeCastExpr + val operand = transformExpr(pc, primitiveTypecastExpr.operand) + + return PrimitiveTypecastExpr(primitiveTypecastExpr.pc, primitiveTypecastExpr.targetTpe, operand) + } + + if (expr.astID == New.ASTID) { + return New(expr.asNew.pc, expr.asNew.tpe) + } + + if (expr.astID == NewArray.ASTID) { + val newArray = expr.asNewArray + val counts = newArray.counts.map(c => transformExpr(pc, c)) + + return NewArray(newArray.pc, counts, newArray.tpe) + } + + if (expr.astID == ArrayLoad.ASTID) { + val arrayLoad = expr.asArrayLoad + + val index = transformExpr(pc, arrayLoad.index) + val arrayRef = transformExpr(pc, arrayLoad.arrayRef) + + return ArrayLoad(arrayLoad.pc, index, arrayRef) + } + + if (expr.astID == ArrayLength.ASTID) { + val arrayLength = expr.asArrayLength + val arrayRef = transformExpr(pc, arrayLength.arrayRef) + + return ArrayLength(arrayLength.pc, arrayRef) + } + + if (expr.astID == GetField.ASTID) { + val getField = expr.asGetField + val objRef = transformExpr(pc, getField.objRef) + + return GetField(getField.pc, getField.declaringClass, getField.name, getField.declaredFieldType, objRef) + } + + if (expr.astID == GetStatic.ASTID) { + return GetStatic(expr.asGetStatic.pc, expr.asGetStatic.declaringClass, expr.asGetStatic.name, expr.asGetStatic.declaredFieldType) + } + + if (expr.astID == InvokedynamicFunctionCall.ASTID) { + val functionCall = expr.asInvokedynamicFunctionCall + val params = functionCall.params.map(p => transformExpr(pc, p)) + + return InvokedynamicFunctionCall(functionCall.pc, functionCall.bootstrapMethod, functionCall.name, functionCall.descriptor, params) + } + + if (expr.astID == NonVirtualFunctionCall.ASTID) { + val functionCall = expr.asNonVirtualFunctionCall + + val base = transformExpr(pc, functionCall.receiver) + val params = functionCall.params.map(p => transformExpr(pc, p)) + + return NonVirtualFunctionCall(functionCall.pc, functionCall.declaringClass, functionCall.isInterface, functionCall.name, functionCall.descriptor, base, params) + } + + if (expr.astID == VirtualFunctionCall.ASTID) { + val functionCall = expr.asVirtualFunctionCall + + val base = transformExpr(pc, functionCall.receiver) + val params = functionCall.params.map(p => transformExpr(pc, p)) + + return VirtualFunctionCall(functionCall.pc, functionCall.declaringClass, functionCall.isInterface, functionCall.name, functionCall.descriptor, base, params) + } + + if (expr.astID == StaticFunctionCall.ASTID) { + val functionCall = expr.asStaticFunctionCall + + val params = functionCall.params + val paramLocals = params.map(p => transformExpr(pc, p)) + + return StaticFunctionCall(functionCall.pc, functionCall.declaringClass, functionCall.isInterface, functionCall.name, functionCall.descriptor, paramLocals) + } + + throw new RuntimeException("Could not transform expression: " + expr) + } + + tacNaive.stmts.map(stmt => transformStatement(stmt)) + } +} diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/OperandStack.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/OperandStack.scala new file mode 100644 index 000000000..449330ad5 --- /dev/null +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/OperandStack.scala @@ -0,0 +1,105 @@ +package boomerang.scope.opal.transformer + +import org.opalj.br.cfg.CFG +import org.opalj.tac.{Assignment, IdBasedVar, Stmt, TACStmts} + +import scala.collection.mutable + +class OperandStack(tac: Array[Stmt[IdBasedVar]]) { + + private val stmtStacks = new Array[mutable.Map[Int, (Int, List[Int])]](tac.length) + stmtStacks(0) = mutable.Map.empty[Int, (Int, List[Int])] + + def push(currIndex: Int, nextIndex: Int, operand: IdBasedVar, stackCounter: Int): Unit = { + val currStack = stmtStacks(currIndex).map(identity) + + // Update all entries with current statement index + val nextStack = currStack.map { case (k, (id, useSite)) => k -> (id, useSite :+ nextIndex) } + nextStack.put(operand.id, (stackCounter, List(nextIndex))) + + stmtStacks(nextIndex) = nextStack + } + + def update(currIndex: Int, nextIndex: Int): Unit = { + val currStack = stmtStacks(currIndex).map(identity) + val existingStack = stmtStacks(nextIndex) + + if (existingStack != null) { + mergeStacks(existingStack.toMap, currStack.toMap) + } else { + // Update with currIndex + val nextStack = currStack.map { + case (k, (id, scope)) => k -> (id, scope :+ nextIndex) + } + stmtStacks(nextIndex) = nextStack + } + } + + private def mergeStacks(existingStack: Map[Int, (Int, List[Int])], incomingStack: Map[Int, (Int, List[Int])]): Unit = { + existingStack.foreach { + case (id, (currStackCounter, _)) => + incomingStack.foreach { + case (`id`, (incomingStackCounter, scope)) => + // If the stack counter is equal, no merge is needed as the operands describe the same stack local + if (currStackCounter != incomingStackCounter) { + scope.foreach(s => { + val currIndex = stmtStacks(s) + + // Update the stack counter s.t. the operands describe the same stack local + currIndex.put(id, (currStackCounter, currIndex(id)._2)) + }) + } + case _ => + } + } + } + + def operandCountersAtStmt(stmtIndex: Int): Map[Int, Int] = { + val stmtStack = stmtStacks(stmtIndex) + + stmtStack.map { case (id, (counter, _)) => id -> counter}.toMap + } + + def operandCounterAtStmt(stmtIndex: Int, operandId: Int): Int = { + operandCountersAtStmt(stmtIndex).getOrElse(operandId, throw new RuntimeException("Could not find operand on stack with id " + operandId)) + } +} + +object OperandStack { + + def apply(tac: Array[Stmt[IdBasedVar]], cfg: CFG[Stmt[IdBasedVar], TACStmts[IdBasedVar]]): OperandStack = { + val stack = new OperandStack(tac) + var stackCounter = 0 + + var workList: List[Int] = List(0) + while (workList.nonEmpty) { + val currIndex = workList.head + val currStmt = tac(currIndex) + workList = workList.tail + + if (currStmt.pc == -1) { + schedule(currIndex + 1) + } else { + val nextIndices = cfg.successors(currIndex) + nextIndices.foreach(nextIndex => { + if (isOperandPushStmt(currStmt)) { + val targetVar = currStmt.asAssignment.targetVar + + stack.push(currIndex, nextIndex, targetVar, stackCounter) + stackCounter += 1 + } else { + stack.update(currIndex, nextIndex) + } + + schedule(nextIndex) + }) + } + + def schedule(nextIndex: Int): Unit = workList ::= nextIndex + + def isOperandPushStmt(stmt: Stmt[IdBasedVar]): Boolean = stmt.astID == Assignment.ASTID && stmt.asAssignment.targetVar.id >= 0 + } + + stack + } +} diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacTransformer.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacTransformer.scala index 38b338d06..a051fc6d9 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacTransformer.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacTransformer.scala @@ -1,6 +1,5 @@ package boomerang.scope.opal.transformer -import org.opalj.ai.{AIResult, BaseAI} import org.opalj.ai.domain.l0.PrimitiveTACAIDomain import org.opalj.br.analyses.Project import org.opalj.br.cfg.CFGFactory @@ -10,12 +9,12 @@ import org.opalj.tac.{Stmt, TACNaive, TACStmts} object TacTransformer { def apply(project: Project[_], method: Method): BoomerangTACode = { - - val aiResult: AIResult = BaseAI(method, new PrimitiveTACAIDomain(project.classHierarchy, method)) - val tacNaive = TACNaive(method, project.classHierarchy) - val transformedTac: Array[Stmt[TacLocal]] = LocalTransformer(method, tacNaive, aiResult) + val domain = new PrimitiveTACAIDomain(project.classHierarchy, method) + val transformedTac: Array[Stmt[TacLocal]] = LocalTransformerOld(method, tacNaive, domain) + val stack = OperandStack(tacNaive.stmts, tacNaive.cfg) + val tac = LocalTransformer(method, tacNaive, domain) val simplifiedTac: Array[Stmt[TacLocal]] = BasicPropagation(transformedTac) val nullifiedTac = NullifyFieldsTransformer(method, simplifiedTac) diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala index bdb7b30f6..705685649 100644 --- a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala @@ -19,9 +19,9 @@ class OpalInvokeExprTest { @Test def instanceInvokeExprTest(): Unit = { val opalSetup = new OpalSetup() - opalSetup.setupOpal(classOf[ConstructorTarget].getName) + opalSetup.setupOpal(classOf[SingleTarget].getName) - val signature = new MethodSignature(classOf[ConstructorTarget].getName, "undefinedConstructor", "Void") + val signature = new MethodSignature(classOf[SingleTarget].getName, "branching", "I") val method = opalSetup.resolveMethod(signature) val opalMethod = OpalMethod(method) opalMethod.getControlFlowGraph diff --git a/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootScopeTest.java b/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootScopeTest.java index ca26d9404..59c2a15e1 100644 --- a/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootScopeTest.java +++ b/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootScopeTest.java @@ -21,6 +21,7 @@ import boomerang.scope.test.targets.AssignmentTarget; import boomerang.scope.test.targets.HashCodeEqualsLocalTarget; import boomerang.scope.test.targets.ParameterLocalsTarget; +import boomerang.scope.test.targets.SingleTarget; import boomerang.scope.test.targets.ThisLocalTarget; import java.util.List; import org.junit.Assert; @@ -142,23 +143,14 @@ public void hashCodeEqualsLocalTest() { @Test public void fieldStoreAssignmentTest() { SootSetup sootSetup = new SootSetup(); - sootSetup.setupSoot(AssignmentTarget.class.getName()); + sootSetup.setupSoot(SingleTarget.class.getName()); // Parameter locals MethodSignature signature = - new MethodSignature(AssignmentTarget.class.getName(), "fieldStoreAssignment"); + new MethodSignature(SingleTarget.class.getName(), "branching2", "void"); SootMethod method = sootSetup.resolveMethod(signature); Method jimpleMethod = JimpleMethod.of(method); - for (Statement stmt : jimpleMethod.getStatements()) { - if (stmt.isFieldStore()) { - Assert.assertTrue(stmt.isAssignStmt()); - - Val leftOp = stmt.getLeftOp(); - Val rightOp = stmt.getRightOp(); - - System.out.println(); - } - } + System.out.println(method.getActiveBody()); } } diff --git a/boomerangScope/src/test/java/boomerang/scope/test/targets/SingleTarget.java b/boomerangScope/src/test/java/boomerang/scope/test/targets/SingleTarget.java index 87f45a9b9..3a85833a4 100644 --- a/boomerangScope/src/test/java/boomerang/scope/test/targets/SingleTarget.java +++ b/boomerangScope/src/test/java/boomerang/scope/test/targets/SingleTarget.java @@ -16,6 +16,8 @@ public class SingleTarget { public static void main(String[] args) { getAndSetField(); identityTest(); + branching(); + usage(); } public static void identityTest() { @@ -38,4 +40,25 @@ private static void getAndSetField() { System.out.println(query); } + + private static int branching() { + return ((Math.random() > 0.5) ? 10 : 100); + } + + private static void branching2() { + int i; + if (Math.random() > 0.5) { + i = 10; + } else { + i = 100; + } + } + + private static void usage() { + A a = new A(); + int i = 10; + + a.methodCall(i); + a.methodCall(i); + } } From 11d4eaf9287ea650ccf327b390dcca36c381bb34 Mon Sep 17 00:00:00 2001 From: Sven Meyer Date: Wed, 2 Apr 2025 13:16:39 +0200 Subject: [PATCH 30/61] Improve operand stack --- .../opal/transformer/BasicPropagation.scala | 4 +- .../opal/transformer/LocalTransformer.scala | 2 +- .../scope/opal/transformer/OperandStack.scala | 66 ++++++++++++------- .../opal/transformer/TacTransformer.scala | 3 + .../scope/test/targets/SingleTarget.java | 2 +- 5 files changed, 51 insertions(+), 26 deletions(-) diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/BasicPropagation.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/BasicPropagation.scala index a5b49127a..cb2b7a470 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/BasicPropagation.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/BasicPropagation.scala @@ -31,7 +31,7 @@ object BasicPropagation { } }) - Range(0, max).foreach(i => { + /*Range(0, max).foreach(i => { statements(i) match { // If we have an assignment $s = r, we replace $s with r in all following statements case Assignment(pc, stackLocal: StackLocal, registerLocal: RegisterLocal) => @@ -43,7 +43,7 @@ object BasicPropagation { statements(i) = Nop(pc) case _ => } - }) + })*/ def updateStatementWithLocal(stmt: Stmt[TacLocal], stackLocal: StackLocal, registerLocal: RegisterLocal): Stmt[TacLocal] = { stmt.astID match { diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/LocalTransformer.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/LocalTransformer.scala index 1e90a4365..8c18346a8 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/LocalTransformer.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/LocalTransformer.scala @@ -153,7 +153,7 @@ object LocalTransformer { new StackLocal(-1, idBasedVar.cTpe, value) } else {*/ val index = tacNaive.pcToIndex(pc) - val counter = operandStack.operandCounterAtStmt(index + 1, idBasedVar.id) + val counter = operandStack.operandDefSite(index) val value = operandsArray(nextPc).head new StackLocal(counter, idBasedVar.cTpe, value) diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/OperandStack.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/OperandStack.scala index 449330ad5..84306c0d6 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/OperandStack.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/OperandStack.scala @@ -7,17 +7,25 @@ import scala.collection.mutable class OperandStack(tac: Array[Stmt[IdBasedVar]]) { - private val stmtStacks = new Array[mutable.Map[Int, (Int, List[Int])]](tac.length) - stmtStacks(0) = mutable.Map.empty[Int, (Int, List[Int])] + private val stmtStacks = new Array[mutable.Map[Int, (Int, List[Int], List[Int])]](tac.length) + private val operandDefSites = Array.fill(tac.length)(-1) + stmtStacks(0) = mutable.Map.empty[Int, (Int, List[Int], List[Int])] def push(currIndex: Int, nextIndex: Int, operand: IdBasedVar, stackCounter: Int): Unit = { val currStack = stmtStacks(currIndex).map(identity) // Update all entries with current statement index - val nextStack = currStack.map { case (k, (id, useSite)) => k -> (id, useSite :+ nextIndex) } - nextStack.put(operand.id, (stackCounter, List(nextIndex))) + val nextStack = currStack.map { case (k, (id, defSite, scope)) => k -> (id, defSite, scope :+ nextIndex) } + nextStack.put(operand.id, (stackCounter, List(currIndex), List(nextIndex))) - stmtStacks(nextIndex) = nextStack + operandDefSites(currIndex) = stackCounter + + val existingStack = stmtStacks(nextIndex) + if (existingStack != null) { + mergeStacks(nextIndex, existingStack.toMap, nextStack.toMap) + } else { + stmtStacks(nextIndex) = nextStack + } } def update(currIndex: Int, nextIndex: Int): Unit = { @@ -25,43 +33,56 @@ class OperandStack(tac: Array[Stmt[IdBasedVar]]) { val existingStack = stmtStacks(nextIndex) if (existingStack != null) { - mergeStacks(existingStack.toMap, currStack.toMap) + mergeStacks(nextIndex, existingStack.toMap, currStack.toMap) } else { - // Update with currIndex + // Update with next index val nextStack = currStack.map { - case (k, (id, scope)) => k -> (id, scope :+ nextIndex) + case (k, (id, defSite, scope)) => k -> (id, defSite, scope :+ nextIndex) } stmtStacks(nextIndex) = nextStack } } - private def mergeStacks(existingStack: Map[Int, (Int, List[Int])], incomingStack: Map[Int, (Int, List[Int])]): Unit = { + private def mergeStacks(currIndex: Int, existingStack: Map[Int, (Int, List[Int], List[Int])], incomingStack: Map[Int, (Int, List[Int], List[Int])]): Unit = { existingStack.foreach { - case (id, (currStackCounter, _)) => + case (id, (currStackCounter, existingDefSites, existingScope)) => incomingStack.foreach { - case (`id`, (incomingStackCounter, scope)) => - // If the stack counter is equal, no merge is needed as the operands describe the same stack local + case (`id`, (incomingStackCounter, incomingDefSites, incomingScope)) => if (currStackCounter != incomingStackCounter) { - scope.foreach(s => { - val currIndex = stmtStacks(s) + incomingScope.foreach(s => { + val currStack = stmtStacks(s) // Update the stack counter s.t. the operands describe the same stack local - currIndex.put(id, (currStackCounter, currIndex(id)._2)) + currStack.put(id, (currStackCounter, incomingDefSites, currStack(id)._3)) + + incomingDefSites.foreach(d => operandDefSites(d) = currStackCounter) }) } + + // Update the def sites and scopes for the merge statement + val currStack = stmtStacks(currIndex) + val mergedDefSites = (existingDefSites ++ incomingDefSites).distinct + val mergedScopes = (existingScope ++ incomingScope).distinct + currStack.put(id, (currStackCounter, mergedDefSites, mergedScopes)) + case _ => } } } - def operandCountersAtStmt(stmtIndex: Int): Map[Int, Int] = { - val stmtStack = stmtStacks(stmtIndex) + def operandDefSite(stmtIndex: Int): Int = operandDefSites(stmtIndex) - stmtStack.map { case (id, (counter, _)) => id -> counter}.toMap - } + def operandCounterAtStmt(stmtIndex: Int, operandId: Int): Int = stmtStacks(stmtIndex).getOrElse(operandId, throw new RuntimeException("Could not find operand on stack with id " + operandId))._1 + + def operandHasMultipleDefSites(stackLocalId: Int): Boolean = { + stmtStacks.foreach(m => { + m.foreach { + case (_, (`stackLocalId`, defSites, _)) => if (defSites.size > 1) return true + case _ => + } + }) - def operandCounterAtStmt(stmtIndex: Int, operandId: Int): Int = { - operandCountersAtStmt(stmtIndex).getOrElse(operandId, throw new RuntimeException("Could not find operand on stack with id " + operandId)) + false } } @@ -80,7 +101,8 @@ object OperandStack { if (currStmt.pc == -1) { schedule(currIndex + 1) } else { - val nextIndices = cfg.successors(currIndex) + // Reversing is not needed; however, this way, the stack locals are enumerated in ascending order + val nextIndices = cfg.successors(currIndex).toList.reverse nextIndices.foreach(nextIndex => { if (isOperandPushStmt(currStmt)) { val targetVar = currStmt.asAssignment.targetVar diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacTransformer.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacTransformer.scala index a051fc6d9..30ec8a700 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacTransformer.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacTransformer.scala @@ -15,6 +15,9 @@ object TacTransformer { val transformedTac: Array[Stmt[TacLocal]] = LocalTransformerOld(method, tacNaive, domain) val stack = OperandStack(tacNaive.stmts, tacNaive.cfg) val tac = LocalTransformer(method, tacNaive, domain) + val propagatedTac = BasicPropagation(tac) + + val simplifiedTac: Array[Stmt[TacLocal]] = BasicPropagation(transformedTac) val nullifiedTac = NullifyFieldsTransformer(method, simplifiedTac) diff --git a/boomerangScope/src/test/java/boomerang/scope/test/targets/SingleTarget.java b/boomerangScope/src/test/java/boomerang/scope/test/targets/SingleTarget.java index 3a85833a4..b896c96f3 100644 --- a/boomerangScope/src/test/java/boomerang/scope/test/targets/SingleTarget.java +++ b/boomerangScope/src/test/java/boomerang/scope/test/targets/SingleTarget.java @@ -42,7 +42,7 @@ private static void getAndSetField() { } private static int branching() { - return ((Math.random() > 0.5) ? 10 : 100); + return ((Math.random() > 0.5) ? 10 : (Math.random() > 0.5) ? 100 : 1000); } private static void branching2() { From 9e58e2a3c49cb4e8a02cdb045b97a78ef33f25df Mon Sep 17 00:00:00 2001 From: Sven Meyer Date: Wed, 2 Apr 2025 20:45:03 +0200 Subject: [PATCH 31/61] Make this local consistent --- .../opal/tac/OpalStatementFormatter.scala | 8 +++- .../opal/transformer/BasicPropagation.scala | 19 ++++----- .../opal/transformer/LocalTransformer.scala | 14 +++---- .../scope/opal/transformer/OperandStack.scala | 40 +++++++++++++------ .../scope/opal/transformer/TacLocal.scala | 20 ++++++++-- .../opal/transformer/TacTransformer.scala | 9 ++--- .../scope/opal/OpalInvokeExprTest.scala | 2 +- .../scope/test/targets/SingleTarget.java | 11 ++++- 8 files changed, 80 insertions(+), 43 deletions(-) diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatementFormatter.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatementFormatter.scala index e327d9edb..31021ec44 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatementFormatter.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatementFormatter.scala @@ -1,7 +1,7 @@ package boomerang.scope.opal.tac import com.google.common.base.Joiner -import org.opalj.tac.{Nop, PutField, Return} +import org.opalj.tac.{Nop, Param, PutField, Return} object OpalStatementFormatter { @@ -34,6 +34,12 @@ object OpalStatementFormatter { } } + if (delegate.isAssignment) { + if (delegate.asAssignment.expr.isVar && delegate.asAssignment.expr.asVar.isParameterLocal) { + return s"${delegate.asAssignment.targetVar} := @${delegate.asAssignment.expr}: ${stmt.getMethod}" + } + } + if (delegate.astID == PutField.ASTID) { return s"${stmt.getLeftOp} = ${stmt.getRightOp}" } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/BasicPropagation.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/BasicPropagation.scala index cb2b7a470..f6c020750 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/BasicPropagation.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/BasicPropagation.scala @@ -1,12 +1,11 @@ package boomerang.scope.opal.transformer -import org.opalj.br.FieldType import org.opalj.collection.immutable.IntIntPair import org.opalj.tac.{ArrayLength, ArrayLoad, ArrayStore, Assignment, BinaryExpr, Checkcast, Compare, Expr, ExprStmt, FunctionCall, GetField, GetStatic, IdBasedVar, If, InstanceOf, InvokedynamicFunctionCall, InvokedynamicMethodCall, MonitorEnter, MonitorExit, NewArray, NonVirtualFunctionCall, NonVirtualMethodCall, Nop, PrefixExpr, PrimitiveTypecastExpr, PutField, PutStatic, ReturnValue, SimpleValueConst, StaticFunctionCall, StaticMethodCall, Stmt, Switch, TACStmts, Throw, VirtualFunctionCall, VirtualMethodCall} object BasicPropagation { - def apply(code: Array[Stmt[TacLocal]]): Array[Stmt[TacLocal]] = { + def apply(code: Array[Stmt[TacLocal]], operandStack: OperandStack): Array[Stmt[TacLocal]] = { val statements = code.map(identity) val max = code.length - 1 @@ -31,19 +30,21 @@ object BasicPropagation { } }) - /*Range(0, max).foreach(i => { + Range(0, max).foreach(i => { statements(i) match { // If we have an assignment $s = r, we replace $s with r in all following statements case Assignment(pc, stackLocal: StackLocal, registerLocal: RegisterLocal) => - Range.inclusive(i + 1, max).foreach(j => { - val currStmt = statements(j) - statements(j) = updateStatementWithLocal(currStmt, stackLocal, registerLocal) - }) + if (!operandStack.operandHasMultipleDefSites(stackLocal.id)) { + Range.inclusive(i + 1, max).foreach(j => { + val currStmt = statements(j) + statements(j) = updateStatementWithLocal(currStmt, stackLocal, registerLocal) + }) - statements(i) = Nop(pc) + statements(i) = Nop(pc) + } case _ => } - })*/ + }) def updateStatementWithLocal(stmt: Stmt[TacLocal], stackLocal: StackLocal, registerLocal: RegisterLocal): Stmt[TacLocal] = { stmt.astID match { diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/LocalTransformer.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/LocalTransformer.scala index 8c18346a8..cc2b3aeb5 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/LocalTransformer.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/LocalTransformer.scala @@ -43,7 +43,7 @@ object LocalTransformer { return Switch(switchStmt.pc, switchStmt.defaultStmt, index, switchStmt.caseStmts.map(p => IntIntPair(-1, p))) case Assignment.ASTID => val transformedExpr = transformExpr(stmt.pc, stmt.asAssignment.expr) - val isThisAssignment = !method.isStatic && transformedExpr.isVar && transformedExpr.asVar.id == -1 + val isThisAssignment = transformedExpr.isVar && transformedExpr.asVar.isThisLocal val target = createNewLocal(stmt.pc, stmt.asAssignment.targetVar, isThisAssignment) @@ -142,25 +142,21 @@ object LocalTransformer { if (pc == -1) { val local = localArray(0) - return new RegisterLocal(idBasedVar.id, idBasedVar.cTpe, local(-idBasedVar.id - 1)) + val isThisDef = method.isNotStatic && idBasedVar.id == -1 + return new RegisterLocal(idBasedVar.id, idBasedVar.cTpe, local(-idBasedVar.id - 1), isThisDef) } val nextPc = tacNaive.stmts(tacNaive.pcToIndex(pc) + 1).pc if (idBasedVar.id >= 0) { - /*if (isThis) { - val value = operandsArray(nextPc).head - new StackLocal(-1, idBasedVar.cTpe, value) - } else {*/ val index = tacNaive.pcToIndex(pc) val counter = operandStack.operandDefSite(index) val value = operandsArray(nextPc).head - new StackLocal(counter, idBasedVar.cTpe, value) - //} + new StackLocal(counter, idBasedVar.cTpe, value, isThis) } else { val local = localArray(nextPc) - new RegisterLocal(idBasedVar.id, idBasedVar.cTpe, local(-idBasedVar.id - 1)) + new RegisterLocal(idBasedVar.id, idBasedVar.cTpe, local(-idBasedVar.id - 1), isThis) } } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/OperandStack.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/OperandStack.scala index 84306c0d6..1b4a4e2f2 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/OperandStack.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/OperandStack.scala @@ -5,13 +5,13 @@ import org.opalj.tac.{Assignment, IdBasedVar, Stmt, TACStmts} import scala.collection.mutable -class OperandStack(tac: Array[Stmt[IdBasedVar]]) { +class OperandStack(tac: Array[Stmt[IdBasedVar]], startIndex: Int) { private val stmtStacks = new Array[mutable.Map[Int, (Int, List[Int], List[Int])]](tac.length) private val operandDefSites = Array.fill(tac.length)(-1) - stmtStacks(0) = mutable.Map.empty[Int, (Int, List[Int], List[Int])] + stmtStacks(startIndex) = mutable.Map.empty[Int, (Int, List[Int], List[Int])] - def push(currIndex: Int, nextIndex: Int, operand: IdBasedVar, stackCounter: Int): Unit = { + def push(currIndex: Int, nextIndex: Int, operand: IdBasedVar, stackCounter: Int): Boolean = { val currStack = stmtStacks(currIndex).map(identity) // Update all entries with current statement index @@ -25,10 +25,12 @@ class OperandStack(tac: Array[Stmt[IdBasedVar]]) { mergeStacks(nextIndex, existingStack.toMap, nextStack.toMap) } else { stmtStacks(nextIndex) = nextStack + + true } } - def update(currIndex: Int, nextIndex: Int): Unit = { + def update(currIndex: Int, nextIndex: Int): Boolean = { val currStack = stmtStacks(currIndex).map(identity) val existingStack = stmtStacks(nextIndex) @@ -40,10 +42,14 @@ class OperandStack(tac: Array[Stmt[IdBasedVar]]) { case (k, (id, defSite, scope)) => k -> (id, defSite, scope :+ nextIndex) } stmtStacks(nextIndex) = nextStack + + true } } - private def mergeStacks(currIndex: Int, existingStack: Map[Int, (Int, List[Int], List[Int])], incomingStack: Map[Int, (Int, List[Int], List[Int])]): Unit = { + private def mergeStacks(currIndex: Int, existingStack: Map[Int, (Int, List[Int], List[Int])], incomingStack: Map[Int, (Int, List[Int], List[Int])]): Boolean = { + var merged = false + existingStack.foreach { case (id, (currStackCounter, existingDefSites, existingScope)) => incomingStack.foreach { @@ -54,8 +60,9 @@ class OperandStack(tac: Array[Stmt[IdBasedVar]]) { // Update the stack counter s.t. the operands describe the same stack local currStack.put(id, (currStackCounter, incomingDefSites, currStack(id)._3)) - incomingDefSites.foreach(d => operandDefSites(d) = currStackCounter) + + merged = true }) } @@ -65,9 +72,13 @@ class OperandStack(tac: Array[Stmt[IdBasedVar]]) { val mergedScopes = (existingScope ++ incomingScope).distinct currStack.put(id, (currStackCounter, mergedDefSites, mergedScopes)) + if (existingDefSites != mergedDefSites || existingScope != mergedScopes) merged = true + case _ => } } + + merged } def operandDefSite(stmtIndex: Int): Int = operandDefSites(stmtIndex) @@ -75,7 +86,7 @@ class OperandStack(tac: Array[Stmt[IdBasedVar]]) { def operandCounterAtStmt(stmtIndex: Int, operandId: Int): Int = stmtStacks(stmtIndex).getOrElse(operandId, throw new RuntimeException("Could not find operand on stack with id " + operandId))._1 def operandHasMultipleDefSites(stackLocalId: Int): Boolean = { - stmtStacks.foreach(m => { + stmtStacks.filter(m => m != null).foreach(m => { m.foreach { case (_, (`stackLocalId`, defSites, _)) => if (defSites.size > 1) return true case _ => @@ -89,10 +100,11 @@ class OperandStack(tac: Array[Stmt[IdBasedVar]]) { object OperandStack { def apply(tac: Array[Stmt[IdBasedVar]], cfg: CFG[Stmt[IdBasedVar], TACStmts[IdBasedVar]]): OperandStack = { - val stack = new OperandStack(tac) + val firstNonNegativeIndex = tac.indexWhere(stmt => stmt.pc >= 0) + val stack = new OperandStack(tac, firstNonNegativeIndex) var stackCounter = 0 - var workList: List[Int] = List(0) + var workList: List[Int] = List(firstNonNegativeIndex) while (workList.nonEmpty) { val currIndex = workList.head val currStmt = tac(currIndex) @@ -101,19 +113,23 @@ object OperandStack { if (currStmt.pc == -1) { schedule(currIndex + 1) } else { + var stackChanged = false + // Reversing is not needed; however, this way, the stack locals are enumerated in ascending order val nextIndices = cfg.successors(currIndex).toList.reverse nextIndices.foreach(nextIndex => { if (isOperandPushStmt(currStmt)) { val targetVar = currStmt.asAssignment.targetVar - stack.push(currIndex, nextIndex, targetVar, stackCounter) + stackChanged = stack.push(currIndex, nextIndex, targetVar, stackCounter) stackCounter += 1 } else { - stack.update(currIndex, nextIndex) + stackChanged = stack.update(currIndex, nextIndex) } - schedule(nextIndex) + if (stackChanged) { + schedule(nextIndex) + } }) } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacLocal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacLocal.scala index cc6a84b7d..772a5a398 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacLocal.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacLocal.scala @@ -16,6 +16,8 @@ trait TacLocal extends Var[TacLocal] { def isParameterLocal: Boolean + def isThisLocal: Boolean + def cTpe: ComputationalType def value: ValueInformation @@ -31,7 +33,7 @@ trait TacLocal extends Var[TacLocal] { override def toString: String = name } -class StackLocal(identifier: Int, computationalType: ComputationalType, valueInfo: ValueInformation) extends TacLocal { +class StackLocal(identifier: Int, computationalType: ComputationalType, valueInfo: ValueInformation, isThis: Boolean = false) extends TacLocal { override def id: Int = identifier @@ -41,7 +43,9 @@ class StackLocal(identifier: Int, computationalType: ComputationalType, valueInf override def isParameterLocal: Boolean = false - override def name: String = s"$$s$identifier" + override def isThisLocal: Boolean = isThis + + override def name: String = if (isThis) "$this" else s"$$s$identifier" override def cTpe: ComputationalType = computationalType @@ -51,11 +55,12 @@ class StackLocal(identifier: Int, computationalType: ComputationalType, valueInf override def equals(other: Any): Boolean = other match { case that: StackLocal => this.id == that.id + case that: RegisterLocal => this.isThisLocal && that.isThisLocal case _ => false } } -class RegisterLocal(identifier: Int, computationalType: ComputationalType, valueInfo: ValueInformation) extends TacLocal { +class RegisterLocal(identifier: Int, computationalType: ComputationalType, valueInfo: ValueInformation, isThis: Boolean = false) extends TacLocal { override def id: Int = identifier @@ -65,7 +70,9 @@ class RegisterLocal(identifier: Int, computationalType: ComputationalType, value override def isParameterLocal: Boolean = false - override def name: String = s"r${-identifier - 1}" + override def isThisLocal: Boolean = isThis + + override def name: String = if (isThis) "this" else s"r${-identifier - 1}" override def cTpe: ComputationalType = computationalType @@ -75,6 +82,7 @@ class RegisterLocal(identifier: Int, computationalType: ComputationalType, value override def equals(other: Any): Boolean = other match { case that: RegisterLocal => this.id == that.id + case that: StackLocal => this.isThisLocal && that.isThisLocal case _ => false } } @@ -89,6 +97,8 @@ class ParameterLocal(identifier: Int, computationalType: ComputationalType, para override def isParameterLocal: Boolean = true + override def isThisLocal: Boolean = false + override def cTpe: ComputationalType = computationalType override def value: ValueInformation = throw new UnsupportedOperationException("No value information available for parameter local") @@ -113,6 +123,8 @@ class NullifiedLocal(identifier: Int, computationalType: ComputationalType) exte override def isParameterLocal: Boolean = false + override def isThisLocal: Boolean = false + override def cTpe: ComputationalType = computationalType override def value: ValueInformation = IsNullValue diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacTransformer.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacTransformer.scala index 30ec8a700..fa6f43f54 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacTransformer.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacTransformer.scala @@ -12,13 +12,10 @@ object TacTransformer { val tacNaive = TACNaive(method, project.classHierarchy) val domain = new PrimitiveTACAIDomain(project.classHierarchy, method) - val transformedTac: Array[Stmt[TacLocal]] = LocalTransformerOld(method, tacNaive, domain) - val stack = OperandStack(tacNaive.stmts, tacNaive.cfg) - val tac = LocalTransformer(method, tacNaive, domain) - val propagatedTac = BasicPropagation(tac) - - val simplifiedTac: Array[Stmt[TacLocal]] = BasicPropagation(transformedTac) + val operandStack = OperandStack(tacNaive.stmts, tacNaive.cfg) + val transformedTac = LocalTransformer(method, tacNaive, domain) + val simplifiedTac = BasicPropagation(transformedTac, operandStack) val nullifiedTac = NullifyFieldsTransformer(method, simplifiedTac) // Update the CFG diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala index 705685649..b0009199b 100644 --- a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala @@ -21,7 +21,7 @@ class OpalInvokeExprTest { val opalSetup = new OpalSetup() opalSetup.setupOpal(classOf[SingleTarget].getName) - val signature = new MethodSignature(classOf[SingleTarget].getName, "branching", "I") + val signature = new MethodSignature(classOf[SingleTarget].getName, "whileLoop", "V") val method = opalSetup.resolveMethod(signature) val opalMethod = OpalMethod(method) opalMethod.getControlFlowGraph diff --git a/boomerangScope/src/test/java/boomerang/scope/test/targets/SingleTarget.java b/boomerangScope/src/test/java/boomerang/scope/test/targets/SingleTarget.java index b896c96f3..246a7de8a 100644 --- a/boomerangScope/src/test/java/boomerang/scope/test/targets/SingleTarget.java +++ b/boomerangScope/src/test/java/boomerang/scope/test/targets/SingleTarget.java @@ -45,13 +45,22 @@ private static int branching() { return ((Math.random() > 0.5) ? 10 : (Math.random() > 0.5) ? 100 : 1000); } - private static void branching2() { + private static int branching2() { int i; if (Math.random() > 0.5) { i = 10; } else { i = 100; } + + return i; + } + + private static void whileLoop() { + A a = new A(); + while (Math.random() > 0.5) { + System.out.println("Loop"); + } } private static void usage() { From d08f607bd93e629c0ad0c743055c41837bb58f81 Mon Sep 17 00:00:00 2001 From: Sven Meyer Date: Thu, 3 Apr 2025 18:24:14 +0200 Subject: [PATCH 32/61] Make StmtGraph main data structure --- .../scope/opal/tac/OpalControlFlowGraph.scala | 46 --- .../opal/transformer/BoomerangTACode.scala | 8 +- .../opal/transformer/LocalTransformer.scala | 6 +- .../transformer/LocalTransformerOld.scala | 371 ------------------ .../opal/transformer/NopTransformer.scala | 43 ++ .../NullifyFieldsTransformer.scala | 44 +-- .../scope/opal/transformer/OperandStack.scala | 38 +- .../scope/opal/transformer/StmtGraph.scala | 87 +++- .../opal/transformer/TacTransformer.scala | 14 +- .../scope/opal/OpalInvokeExprTest.scala | 4 +- .../boomerang/scope/soot/SootScopeTest.java | 4 +- .../scope/test/targets/SingleTarget.java | 4 +- 12 files changed, 172 insertions(+), 497 deletions(-) delete mode 100644 boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/LocalTransformerOld.scala create mode 100644 boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/NopTransformer.scala diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalControlFlowGraph.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalControlFlowGraph.scala index ac3d3ec46..ecb44bb35 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalControlFlowGraph.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalControlFlowGraph.scala @@ -83,52 +83,6 @@ class OpalControlFlowGraph(method: OpalMethod) extends ControlFlowGraph { succsOfCache.put(statement, succStmt) }) }) - /*// Definition of parameter locals - method.tac.statements.filter(stmt => stmt.pc == -1).foreach(stmt => { - val statement = new OpalStatement(stmt, method) - statements.add(statement) - }) - - val head = new OpalStatement(Nop(-1), method) - statements.add(head) - startPointCache.add(head) - - var headAdded = false - method.tac.statements.filter(stmt => stmt.pc >= 0).foreach(stmt => { - val statement = new OpalStatement(stmt, method) - statements.add(statement) - - val stmtPc = method.tac.pcToIndex(stmt.pc) - - if (!headAdded) { - headAdded = true - - predsOfCache.put(statement, head) - succsOfCache.put(head, statement) - } else { - val predecessors = method.tac.cfg.predecessors(stmtPc) - predecessors.foreach(predecessorPc => { - val predecessor = method.tac.statements(predecessorPc) - val predecessorStatement = new OpalStatement(predecessor, method) - - predsOfCache.put(statement, predecessorStatement) - }) - } - - val successors = method.tac.cfg.successors(stmtPc) - if (successors.isEmpty) { - // No successors => Tail statement - endPointCache.add(statement) - succsOfCache.putAll(statement, util.Collections.emptySet()) - } else { - successors.foreach(successorPc => { - val successor = method.tac.statements(successorPc) - val successorStatement = new OpalStatement(successor, method) - - succsOfCache.put(statement, successorStatement) - }) - } - })*/ cacheBuilt = true } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/BoomerangTACode.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/BoomerangTACode.scala index 701c85877..e455de617 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/BoomerangTACode.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/BoomerangTACode.scala @@ -2,11 +2,9 @@ package boomerang.scope.opal.transformer import org.opalj.tac.{Assignment, Stmt} -class BoomerangTACode( - val statements: Array[Stmt[TacLocal]], - val pcToIndex: Array[Int], - val cfg: StmtGraph - ) { +class BoomerangTACode(val cfg: StmtGraph) { + + def statements: Array[Stmt[TacLocal]] = cfg.statements.toArray def getLocals: Set[TacLocal] = statements.filter(stmt => stmt.astID == Assignment.ASTID).map(stmt => stmt.asAssignment.targetVar).toSet diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/LocalTransformer.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/LocalTransformer.scala index cc2b3aeb5..2dd5c22a4 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/LocalTransformer.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/LocalTransformer.scala @@ -1,7 +1,6 @@ package boomerang.scope.opal.transformer -import org.opalj.ai.{AIResult, BaseAI} -import org.opalj.ai.domain.l0.PrimitiveTACAIDomain +import org.opalj.ai.{AIResult, BaseAI, Domain} import org.opalj.br.Method import org.opalj.collection.immutable.IntIntPair import org.opalj.tac.{ArrayLength, ArrayLoad, ArrayStore, Assignment, BinaryExpr, CaughtException, Checkcast, ClassConst, Compare, DoubleConst, DynamicConst, Expr, ExprStmt, FloatConst, GetField, GetStatic, Goto, IdBasedVar, If, InstanceOf, IntConst, InvokedynamicFunctionCall, InvokedynamicMethodCall, JSR, LongConst, MethodHandleConst, MethodTypeConst, MonitorEnter, MonitorExit, NaiveTACode, New, NewArray, NonVirtualFunctionCall, NonVirtualMethodCall, Nop, NullExpr, Param, PrefixExpr, PrimitiveTypecastExpr, PutField, PutStatic, Ret, Return, ReturnValue, StaticFunctionCall, StaticMethodCall, Stmt, StringConst, Switch, Throw, VirtualFunctionCall, VirtualMethodCall} @@ -10,10 +9,9 @@ import scala.collection.mutable object LocalTransformer { - def apply(method: Method, tacNaive: NaiveTACode[_], domain: PrimitiveTACAIDomain): Array[Stmt[TacLocal]] = { + def apply(method: Method, tacNaive: NaiveTACode[_], domain: Domain, operandStack: OperandStack): Array[Stmt[TacLocal]] = { var paramCounter = -1 val currentLocals = mutable.Map.empty[Int, TacLocal] - val operandStack = OperandStack(tacNaive.stmts, tacNaive.cfg) // Domain components val aiResult: AIResult = BaseAI(method, domain) diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/LocalTransformerOld.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/LocalTransformerOld.scala deleted file mode 100644 index 4cb2b65fc..000000000 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/LocalTransformerOld.scala +++ /dev/null @@ -1,371 +0,0 @@ -package boomerang.scope.opal.transformer - -import org.opalj.ai.domain.l0.PrimitiveTACAIDomain -import org.opalj.ai.{AIResult, BaseAI} -import org.opalj.br.Method -import org.opalj.collection.immutable.IntIntPair -import org.opalj.tac._ - -import scala.collection.mutable - -object LocalTransformerOld { - - def apply(method: Method, tacNaive: NaiveTACode[_], domain: PrimitiveTACAIDomain): Array[Stmt[TacLocal]] = { - var paramCounter = -1 - var stackCounter = -1 - val currentStack = mutable.Map.empty[Int, TacLocal] - - val aiResult: AIResult = BaseAI(method, domain) - val operandsArray: aiResult.domain.OperandsArray = aiResult.operandsArray - val localArray: aiResult.domain.LocalsArray = aiResult.localsArray - - def transformStatement(stmt: Stmt[IdBasedVar]): Stmt[TacLocal] = { - if (stmt.astID == If.ASTID) { - val ifStmt = stmt.asIf - - val left = transformExpr(stmt.pc, ifStmt.left) - val right = transformExpr(stmt.pc, ifStmt.right) - - return If(ifStmt.pc, left, ifStmt.condition, right, ifStmt.targetStmt) - } - - if (stmt.astID == Goto.ASTID) { - return stmt.asGoto - } - - if (stmt.astID == Ret.ASTID) { - return stmt.asRet - } - - if (stmt.astID == JSR.ASTID) { - return stmt.asJSR - } - - if (stmt.astID == Switch.ASTID) { - val switchStmt = stmt.asSwitch - val index = transformExpr(stmt.pc, switchStmt.index) - - // Inserting -1 as it is only used in previous remapping steps - return Switch(switchStmt.pc, switchStmt.defaultStmt, index, switchStmt.caseStmts.map(p => IntIntPair(-1, p))) - } - - if (stmt.astID == Assignment.ASTID) { - val transformedExpr = transformExpr(stmt.pc, stmt.asAssignment.expr) - val isThisAssignment = !method.isStatic && transformedExpr.isVar && transformedExpr.asVar.id == -1 - - val target = createNewLocal(stmt.pc, stmt.asAssignment.targetVar, isThisAssignment) - - // Store the current stack and register locals on our own 'stack' - currentStack(stmt.asAssignment.targetVar.id) = target - - return new Assignment(stmt.pc, target, transformedExpr) - } - - if (stmt.astID == ReturnValue.ASTID) { - val returnStmt = stmt.asReturnValue - val returnValue = transformExpr(stmt.pc, returnStmt.expr) - - return ReturnValue(returnStmt.pc, returnValue) - } - - if (stmt.astID == Return.ASTID) { - return Return(stmt.asReturn.pc) - } - - if (stmt.astID == Nop.ASTID) { - return Nop(stmt.asNop.pc) - } - - if (stmt.astID == MonitorEnter.ASTID) { - val monitorEnter = stmt.asMonitorEnter - val objRef = transformExpr(stmt.pc, monitorEnter.objRef) - - return MonitorEnter(monitorEnter.pc, objRef) - } - - if (stmt.astID == MonitorExit.ASTID) { - val monitorExit = stmt.asMonitorExit - val objRef = transformExpr(stmt.pc, monitorExit.objRef) - - return MonitorExit(monitorExit.pc, objRef) - } - - if (stmt.astID == ArrayStore.ASTID) { - val arrayStore = stmt.asArrayStore - - val arrayRef = transformExpr(stmt.pc, arrayStore.arrayRef) - val index = transformExpr(stmt.pc, arrayStore.index) - val value = transformExpr(stmt.pc, arrayStore.value) - - return ArrayStore(arrayStore.pc, arrayRef, index, value) - } - - if (stmt.astID == Throw.ASTID) { - val throwStmt = stmt.asThrow - val exception = transformExpr(stmt.pc, throwStmt.exception) - - return Throw(throwStmt.pc, exception) - } - - if (stmt.astID == PutStatic.ASTID) { - val putStatic = stmt.asPutStatic - val value = transformExpr(stmt.pc, putStatic.value) - - return PutStatic(putStatic.pc, putStatic.declaringClass, putStatic.name, putStatic.declaredFieldType, value) - } - - if (stmt.astID == PutField.ASTID) { - val putField = stmt.asPutField - - val objRef = transformExpr(stmt.pc, putField.objRef) - val value = transformExpr(stmt.pc, putField.value) - - return PutField(putField.pc, putField.declaringClass, putField.name, putField.declaredFieldType, objRef, value) - } - - if (stmt.astID == NonVirtualMethodCall.ASTID) { - val methodCall = stmt.asNonVirtualMethodCall - - val baseLocal = transformExpr(stmt.pc, methodCall.receiver) - val paramLocals = methodCall.params.map(p => transformExpr(stmt.pc, p)) - - return NonVirtualMethodCall(methodCall.pc, methodCall.declaringClass, methodCall.isInterface, methodCall.name, methodCall.descriptor, baseLocal, paramLocals) - } - - if (stmt.astID == VirtualMethodCall.ASTID) { - val methodCall = stmt.asVirtualMethodCall - - val baseLocal = transformExpr(stmt.pc, methodCall.receiver) - val paramLocals = methodCall.params.map(p => transformExpr(stmt.pc, p)) - - return VirtualMethodCall(methodCall.pc, methodCall.declaringClass, methodCall.isInterface, methodCall.name, methodCall.descriptor, baseLocal, paramLocals) - } - - if (stmt.astID == StaticMethodCall.ASTID) { - val methodCall = stmt.asStaticMethodCall - val params = methodCall.params.map(p => transformExpr(stmt.pc, p)) - - return StaticMethodCall(methodCall.pc, methodCall.declaringClass, methodCall.isInterface, methodCall.name, methodCall.descriptor, params) - } - - if (stmt.astID == InvokedynamicMethodCall.ASTID) { - val methodCall = stmt.asInvokedynamicMethodCall - val params = methodCall.params.map(p => transformExpr(stmt.pc, p)) - - return InvokedynamicMethodCall(methodCall.pc, methodCall.bootstrapMethod, methodCall.name, methodCall.descriptor, params) - } - - if (stmt.astID == ExprStmt.ASTID) { - val expr = transformExpr(stmt.pc, stmt.asExprStmt.expr) - - return ExprStmt(stmt.pc, expr) - } - - if (stmt.astID == CaughtException.ASTID) { - val caughtException = stmt.asCaughtException - - return CaughtException(caughtException.pc, caughtException.exceptionType, caughtException.origins) - } - - if (stmt.astID == Checkcast.ASTID) { - val castExpr = stmt.asCheckcast - val value = transformExpr(stmt.pc, castExpr.value) - - return Checkcast(castExpr.pc, value, castExpr.cmpTpe) - } - - throw new RuntimeException("Could not transform statement: " + stmt) - } - - def createNewLocal(pc: Int, idBasedVar: IdBasedVar, isThis: Boolean = false): TacLocal = { - if (pc == -1) { - val local = localArray(0) - - return new RegisterLocal(idBasedVar.id, idBasedVar.cTpe, local(-idBasedVar.id - 1)) - } - - val nextPc = tacNaive.stmts(tacNaive.pcToIndex(pc) + 1).pc - - if (idBasedVar.id >= 0) { - /*if (isThis) { - val value = operandsArray(nextPc).head - new StackLocal(-1, idBasedVar.cTpe, value) - } else {*/ - stackCounter += 1 - - val value = operandsArray(nextPc).head - new StackLocal(stackCounter, idBasedVar.cTpe, value) - //} - } else { - val local = localArray(nextPc) - new RegisterLocal(idBasedVar.id, idBasedVar.cTpe, local(-idBasedVar.id - 1)) - } - } - - def transformExpr(pc: Int, expr: Expr[IdBasedVar]): Expr[TacLocal] = { - if (expr.isVar) { - return currentStack.getOrElse(expr.asVar.id, throw new RuntimeException("No local on stack")) - } - - if (expr.astID == InstanceOf.ASTID) { - val instanceOf = expr.asInstanceOf - val value = transformExpr(pc, instanceOf.value) - - return InstanceOf(instanceOf.pc, value, instanceOf.cmpTpe) - } - - if (expr.astID == Compare.ASTID) { - val compareExpr = expr.asCompare - - val leftLocal = transformExpr(pc, compareExpr.left) - val rightLocal = transformExpr(pc, compareExpr.right) - - return Compare(compareExpr.pc, leftLocal, compareExpr.condition, rightLocal) - } - - if (expr.astID == Param.ASTID) { - paramCounter += 1 - return new ParameterLocal(paramCounter, expr.asParam.cTpe, expr.asParam.name) - } - - if (expr.astID == MethodTypeConst.ASTID) { - return MethodTypeConst(expr.asMethodTypeConst.pc, expr.asMethodTypeConst.value) - } - - if (expr.astID == MethodHandleConst.ASTID) { - return MethodHandleConst(expr.asMethodHandleConst.pc, expr.asMethodHandleConst.value) - } - - if (expr.astID == IntConst.ASTID) { - return IntConst(expr.asIntConst.pc, expr.asIntConst.value) - } - - if (expr.astID == LongConst.ASTID) { - return LongConst(expr.asLongConst.pc, expr.asLongConst.value) - } - - if (expr.astID == FloatConst.ASTID) { - return FloatConst(expr.asFloatConst.pc, expr.asFloatConst.value) - } - - if (expr.astID == DoubleConst.ASTID) { - return DoubleConst(expr.asDoubleConst.pc, expr.asDoubleConst.value) - } - - if (expr.astID == StringConst.ASTID) { - return StringConst(expr.asStringConst.pc, expr.asStringConst.value) - } - - if (expr.astID == ClassConst.ASTID) { - return ClassConst(expr.asClassConst.pc, expr.asClassConst.value) - } - - if (expr.astID == DynamicConst.ASTID) { - return DynamicConst(expr.asDynamicConst.pc, expr.asDynamicConst.bootstrapMethod, expr.asDynamicConst.name, expr.asDynamicConst.descriptor) - } - - if (expr.astID == NullExpr.ASTID) { - return NullExpr(expr.asNullExpr.pc) - } - - if (expr.astID == BinaryExpr.ASTID) { - val binaryExpr = expr.asBinaryExpr - - val left = transformExpr(pc, binaryExpr.left) - val right = transformExpr(pc, binaryExpr.right) - - return BinaryExpr(binaryExpr.pc, binaryExpr.cTpe, binaryExpr.op, left, right) - } - - if (expr.astID == PrefixExpr.ASTID) { - val prefixExpr = expr.asPrefixExpr - val operand = transformExpr(pc, prefixExpr.operand) - - return PrefixExpr(prefixExpr.pc, prefixExpr.cTpe, prefixExpr.op, operand) - } - - if (expr.astID == PrimitiveTypecastExpr.ASTID) { - val primitiveTypecastExpr = expr.asPrimitiveTypeCastExpr - val operand = transformExpr(pc, primitiveTypecastExpr.operand) - - return PrimitiveTypecastExpr(primitiveTypecastExpr.pc, primitiveTypecastExpr.targetTpe, operand) - } - - if (expr.astID == New.ASTID) { - return New(expr.asNew.pc, expr.asNew.tpe) - } - - if (expr.astID == NewArray.ASTID) { - val newArray = expr.asNewArray - val counts = newArray.counts.map(c => transformExpr(pc, c)) - - return NewArray(newArray.pc, counts, newArray.tpe) - } - - if (expr.astID == ArrayLoad.ASTID) { - val arrayLoad = expr.asArrayLoad - - val index = transformExpr(pc, arrayLoad.index) - val arrayRef = transformExpr(pc, arrayLoad.arrayRef) - - return ArrayLoad(arrayLoad.pc, index, arrayRef) - } - - if (expr.astID == ArrayLength.ASTID) { - val arrayLength = expr.asArrayLength - val arrayRef = transformExpr(pc, arrayLength.arrayRef) - - return ArrayLength(arrayLength.pc, arrayRef) - } - - if (expr.astID == GetField.ASTID) { - val getField = expr.asGetField - val objRef = transformExpr(pc, getField.objRef) - - return GetField(getField.pc, getField.declaringClass, getField.name, getField.declaredFieldType, objRef) - } - - if (expr.astID == GetStatic.ASTID) { - return GetStatic(expr.asGetStatic.pc, expr.asGetStatic.declaringClass, expr.asGetStatic.name, expr.asGetStatic.declaredFieldType) - } - - if (expr.astID == InvokedynamicFunctionCall.ASTID) { - val functionCall = expr.asInvokedynamicFunctionCall - val params = functionCall.params.map(p => transformExpr(pc, p)) - - return InvokedynamicFunctionCall(functionCall.pc, functionCall.bootstrapMethod, functionCall.name, functionCall.descriptor, params) - } - - if (expr.astID == NonVirtualFunctionCall.ASTID) { - val functionCall = expr.asNonVirtualFunctionCall - - val base = transformExpr(pc, functionCall.receiver) - val params = functionCall.params.map(p => transformExpr(pc, p)) - - return NonVirtualFunctionCall(functionCall.pc, functionCall.declaringClass, functionCall.isInterface, functionCall.name, functionCall.descriptor, base, params) - } - - if (expr.astID == VirtualFunctionCall.ASTID) { - val functionCall = expr.asVirtualFunctionCall - - val base = transformExpr(pc, functionCall.receiver) - val params = functionCall.params.map(p => transformExpr(pc, p)) - - return VirtualFunctionCall(functionCall.pc, functionCall.declaringClass, functionCall.isInterface, functionCall.name, functionCall.descriptor, base, params) - } - - if (expr.astID == StaticFunctionCall.ASTID) { - val functionCall = expr.asStaticFunctionCall - - val params = functionCall.params - val paramLocals = params.map(p => transformExpr(pc, p)) - - return StaticFunctionCall(functionCall.pc, functionCall.declaringClass, functionCall.isInterface, functionCall.name, functionCall.descriptor, paramLocals) - } - - throw new RuntimeException("Could not transform expression: " + expr) - } - - tacNaive.stmts.map(stmt => transformStatement(stmt)) - } -} diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/NopTransformer.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/NopTransformer.scala new file mode 100644 index 000000000..03b1c7e8d --- /dev/null +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/NopTransformer.scala @@ -0,0 +1,43 @@ +package boomerang.scope.opal.transformer + +import org.opalj.tac.{If, Nop} + +object NopTransformer { + + // TODO Make it more general + final val INITIAL_NOP = -10 + + def apply(stmtGraph: StmtGraph): StmtGraph = { + val tac = stmtGraph.tac + + def removeNopStatements(stmtGraph: StmtGraph): Unit = { + tac.foreach(stmt => { + if (stmt.astID == Nop.ASTID) { + stmtGraph.remove(stmt) + } + }) + } + + def addNopStatements(stmtGraph: StmtGraph): StmtGraph = { + // Add a nop statement in the beginning + val nop = Nop(INITIAL_NOP) + var result = stmtGraph.insertBefore(nop, stmtGraph.heads.head) + + tac.zipWithIndex.foreach(stmt => { + if (stmt._1.astID == If.ASTID) { + val nextStmt = tac(stmt._2 + 1) + val targetStmt = tac(stmt._1.asIf.targetStmt) + + result = result.insertBefore(Nop(-nextStmt.pc), nextStmt) + result = result.insertBefore(Nop(-targetStmt.pc), targetStmt) + } + }) + + result + } + + // TODO Remove NOPs before inserting them + // removeNopStatements(stmtGraph) + addNopStatements(stmtGraph) + } +} diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/NullifyFieldsTransformer.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/NullifyFieldsTransformer.scala index 4e0fdb1b9..0f3f5e3d0 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/NullifyFieldsTransformer.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/NullifyFieldsTransformer.scala @@ -1,17 +1,18 @@ package boomerang.scope.opal.transformer -import org.opalj.br.{ComputationalTypeReference, Field, Method} -import org.opalj.tac.{Assignment, Expr, NullExpr, PutField, Stmt} +import org.opalj.br.{ComputationalTypeReference, Field, FieldType, Method} +import org.opalj.tac.{Assignment, Expr, NullExpr, PutField} object NullifyFieldsTransformer { final val NULLIFIED_FIELD = -2 - def apply(method: Method, tac: Array[Stmt[TacLocal]]): (Array[Stmt[TacLocal]], Int) = { + def apply(method: Method, stmtGraph: StmtGraph): StmtGraph = { if (!method.isConstructor || method.isStatic) { - return (tac.map(identity), 0) + return stmtGraph } + val tac = stmtGraph.tac var localCounter = 0 def isFieldDefined(field: Field): Boolean = { @@ -32,36 +33,29 @@ object NullifyFieldsTransformer { throw new RuntimeException("'this' local not found in method: " + method.name) } + def createNullifiedLocal(localCounter: Int, fieldType: FieldType): NullifiedLocal = { + // TODO Types + new NullifiedLocal(localCounter, ComputationalTypeReference) + } + val definedFields = method.classFile.fields.filter(f => isFieldDefined(f)) val undefinedFields = method.classFile.fields.filter(f => !definedFields.contains(f) && f.isNotStatic && f.isNotFinal) + val firstOriginalStmt = tac.find(stmt => stmt.pc >= 0).get + var result = stmtGraph - // For each undefined field, we add a definition and a field store statement - val offset = 2 * undefinedFields.size - val nullifiedTac = new Array[Stmt[TacLocal]](tac.length + offset) - - // Add the parameter definitions - val paramDefinitions = tac.filter(stmt => stmt.pc == -1) - Range(0, paramDefinitions.length).foreach(i => nullifiedTac(i) = tac(i)) - - // Create the nullified fields - Range(0, undefinedFields.size).foreach(i => { - val currField = undefinedFields(i) - // TODO Types - val local = new NullifiedLocal(localCounter, ComputationalTypeReference) + undefinedFields.foreach(field => { + val local = createNullifiedLocal(localCounter, field.fieldType) localCounter += 1 val defSite = Assignment[TacLocal](NULLIFIED_FIELD, local, NullExpr(NULLIFIED_FIELD)) - val putField = PutField(NULLIFIED_FIELD, method.classFile.thisType, currField.name, currField.fieldType, getThisLocal, local) + val putField = PutField(NULLIFIED_FIELD, method.classFile.thisType, field.name, field.fieldType, getThisLocal, local) - nullifiedTac(paramDefinitions.length + 2 * i) = defSite - nullifiedTac(paramDefinitions.length + 2 * i + 1) = putField - }) + result = result.insertBefore(defSite, firstOriginalStmt) + result = result.insertBefore(putField, firstOriginalStmt) - // Append the original tac statements - Range(paramDefinitions.length, tac.length).foreach(i => { - nullifiedTac(i + offset) = tac(i) }) - (nullifiedTac, offset) + result } + } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/OperandStack.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/OperandStack.scala index 1b4a4e2f2..3f652766d 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/OperandStack.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/OperandStack.scala @@ -11,7 +11,7 @@ class OperandStack(tac: Array[Stmt[IdBasedVar]], startIndex: Int) { private val operandDefSites = Array.fill(tac.length)(-1) stmtStacks(startIndex) = mutable.Map.empty[Int, (Int, List[Int], List[Int])] - def push(currIndex: Int, nextIndex: Int, operand: IdBasedVar, stackCounter: Int): Boolean = { + def push(currIndex: Int, nextIndex: Int, operand: IdBasedVar, stackCounter: Int): Unit = { val currStack = stmtStacks(currIndex).map(identity) // Update all entries with current statement index @@ -25,12 +25,10 @@ class OperandStack(tac: Array[Stmt[IdBasedVar]], startIndex: Int) { mergeStacks(nextIndex, existingStack.toMap, nextStack.toMap) } else { stmtStacks(nextIndex) = nextStack - - true } } - def update(currIndex: Int, nextIndex: Int): Boolean = { + def update(currIndex: Int, nextIndex: Int): Unit = { val currStack = stmtStacks(currIndex).map(identity) val existingStack = stmtStacks(nextIndex) @@ -42,14 +40,10 @@ class OperandStack(tac: Array[Stmt[IdBasedVar]], startIndex: Int) { case (k, (id, defSite, scope)) => k -> (id, defSite, scope :+ nextIndex) } stmtStacks(nextIndex) = nextStack - - true } } - private def mergeStacks(currIndex: Int, existingStack: Map[Int, (Int, List[Int], List[Int])], incomingStack: Map[Int, (Int, List[Int], List[Int])]): Boolean = { - var merged = false - + private def mergeStacks(currIndex: Int, existingStack: Map[Int, (Int, List[Int], List[Int])], incomingStack: Map[Int, (Int, List[Int], List[Int])]): Unit = { existingStack.foreach { case (id, (currStackCounter, existingDefSites, existingScope)) => incomingStack.foreach { @@ -61,8 +55,6 @@ class OperandStack(tac: Array[Stmt[IdBasedVar]], startIndex: Int) { // Update the stack counter s.t. the operands describe the same stack local currStack.put(id, (currStackCounter, incomingDefSites, currStack(id)._3)) incomingDefSites.foreach(d => operandDefSites(d) = currStackCounter) - - merged = true }) } @@ -72,13 +64,9 @@ class OperandStack(tac: Array[Stmt[IdBasedVar]], startIndex: Int) { val mergedScopes = (existingScope ++ incomingScope).distinct currStack.put(id, (currStackCounter, mergedDefSites, mergedScopes)) - if (existingDefSites != mergedDefSites || existingScope != mergedScopes) merged = true - case _ => } } - - merged } def operandDefSite(stmtIndex: Int): Int = operandDefSites(stmtIndex) @@ -113,21 +101,19 @@ object OperandStack { if (currStmt.pc == -1) { schedule(currIndex + 1) } else { - var stackChanged = false - // Reversing is not needed; however, this way, the stack locals are enumerated in ascending order val nextIndices = cfg.successors(currIndex).toList.reverse nextIndices.foreach(nextIndex => { - if (isOperandPushStmt(currStmt)) { - val targetVar = currStmt.asAssignment.targetVar - - stackChanged = stack.push(currIndex, nextIndex, targetVar, stackCounter) - stackCounter += 1 - } else { - stackChanged = stack.update(currIndex, nextIndex) - } + if (currIndex < nextIndex) { + if (isOperandPushStmt(currStmt)) { + val targetVar = currStmt.asAssignment.targetVar + + stack.push(currIndex, nextIndex, targetVar, stackCounter) + stackCounter += 1 + } else { + stack.update(currIndex, nextIndex) + } - if (stackChanged) { schedule(nextIndex) } }) diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/StmtGraph.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/StmtGraph.scala index 52955f074..f515c10f2 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/StmtGraph.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/StmtGraph.scala @@ -1,17 +1,88 @@ package boomerang.scope.opal.transformer import org.opalj.br.cfg.CFG -import org.opalj.tac.{Stmt, TACStmts} +import org.opalj.tac.{Return, Stmt, TACStmts} -class StmtGraph(val heads: Set[Stmt[TacLocal]], val tails: Set[Stmt[TacLocal]], val predecessors: Map[Stmt[TacLocal], Set[Stmt[TacLocal]]], val successors: Map[Stmt[TacLocal], Set[Stmt[TacLocal]]]) { +import scala.collection.mutable +class StmtGraph private (val tac: Array[Stmt[TacLocal]], val heads: Set[Stmt[TacLocal]], val tails: Set[Stmt[TacLocal]], val predecessors: Map[Stmt[TacLocal], Set[Stmt[TacLocal]]], val successors: Map[Stmt[TacLocal], Set[Stmt[TacLocal]]], val statements: List[Stmt[TacLocal]]) { + + def insertBefore(insertStmt: Stmt[TacLocal], existingStmt: Stmt[TacLocal]): StmtGraph = { + val tempSuccessor = mutable.Map.from(successors) + + // Insert s1 between s0 -> s2 + val preds = predecessors(existingStmt) + preds.foreach(pred => { + // Update succs of s0 from s2 to s1, giving s0 -> s1 ... s2 + val succsOfPred = successors(pred) + assert(succsOfPred.contains(existingStmt)) + + val newSuccs = succsOfPred - existingStmt + insertStmt + tempSuccessor.put(pred, newSuccs) + }) + + // Update preds of s2 from s0 to (only) s1, giving s0 ... s1 <- s2 + val tempPreds = mutable.Map.from(predecessors) + tempPreds.put(existingStmt, Set(insertStmt)) + + // Add the new statement + tempPreds.put(insertStmt, preds) + tempSuccessor.put(insertStmt, Set(existingStmt)) + + // Potential head statement update + var newHeads = heads.map(identity) + if (heads.contains(existingStmt)) { + newHeads = Set(insertStmt) + } + + val newStatements = statements.flatMap { + case `existingStmt` => List(insertStmt, existingStmt) + case x => List(x) + } + + new StmtGraph(tac, newHeads, tails, tempPreds.toMap, tempSuccessor.toMap, newStatements) + } + + def remove(stmt: Stmt[TacLocal]): StmtGraph = { + if (stmt.astID == Return.ASTID) throw new RuntimeException("Cannot remove return statement") + + val tempPreds = mutable.Map.from(predecessors) + val tempSuccs = mutable.Map.from(successors) + + val preds = predecessors(stmt) + val succs = successors(stmt) + preds.foreach(pred => { + val succsOfPred = successors(pred) + tempSuccs.put(pred, succsOfPred ++ succs) + }) + + succs.foreach(succ => { + val predsOfSuccs = predecessors(succ) + tempPreds.put(succ, predsOfSuccs ++ preds) + }) + + var newHeads = heads.map(identity) + if (heads.contains(stmt)) { + newHeads = newHeads - stmt + + if (newHeads.isEmpty) { + newHeads = succs + } + } + + val newStatements = statements.filter(s => s != stmt) + val newPreds = tempPreds.filter(s => s._1 != stmt).toMap + val newSuccs = tempSuccs.filter(s => s._1 != stmt).toMap + + new StmtGraph(tac, newHeads, tails, newPreds, newSuccs, newStatements) + } } object StmtGraph { - def apply(tac: Array[Stmt[TacLocal]], cfg: CFG[Stmt[TacLocal], TACStmts[TacLocal]], pcToIndex: Array[Int], offset: Int): StmtGraph = { + def apply(tac: Array[Stmt[TacLocal]], cfg: CFG[Stmt[TacLocal], TACStmts[TacLocal]], pcToIndex: Array[Int]): StmtGraph = { - def computeHeads: Set[Stmt[TacLocal]] = Set(tac(0)) + def computeHead: Set[Stmt[TacLocal]] = Set(tac(0)) def computeTails: Set[Stmt[TacLocal]] = { tac.filter(stmt => stmt.pc >= 0).filter(stmt => { @@ -41,7 +112,7 @@ object StmtGraph { val stmtIndex = pcToIndex(stmt.pc) val predecessors = cfg.predecessors(stmtIndex) - predecessors.map(predecessorIndex => tac(predecessorIndex + offset)) + predecessors.map(predecessorIndex => tac(predecessorIndex)) } def computeSuccessors(stmt: Stmt[TacLocal]): Set[Stmt[TacLocal]] = { @@ -53,14 +124,14 @@ object StmtGraph { val stmtIndex = pcToIndex(stmt.pc) val successors = cfg.successors(stmtIndex) - successors.map(successorIndex => tac(successorIndex + offset)) + successors.map(successorIndex => tac(successorIndex)) } - val heads = computeHeads + val heads = computeHead val tails = computeTails val predecessors = tac.map(stmt => stmt -> computePredecessors(stmt)).toMap val successors = tac.map(stmt => stmt -> computeSuccessors(stmt)).toMap - new StmtGraph(heads, tails, predecessors, successors) + new StmtGraph(tac, heads, tails, predecessors, successors, tac.toList) } } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacTransformer.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacTransformer.scala index fa6f43f54..20f5d8505 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacTransformer.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacTransformer.scala @@ -12,11 +12,9 @@ object TacTransformer { val tacNaive = TACNaive(method, project.classHierarchy) val domain = new PrimitiveTACAIDomain(project.classHierarchy, method) - val operandStack = OperandStack(tacNaive.stmts, tacNaive.cfg) - val transformedTac = LocalTransformer(method, tacNaive, domain) + val transformedTac = LocalTransformer(method, tacNaive, domain, operandStack) val simplifiedTac = BasicPropagation(transformedTac, operandStack) - val nullifiedTac = NullifyFieldsTransformer(method, simplifiedTac) // Update the CFG val cfg = CFGFactory(method, project.classHierarchy) @@ -25,11 +23,11 @@ object TacTransformer { } val tacCfg = cfg.get.mapPCsToIndexes[Stmt[TacLocal], TACStmts[TacLocal]](TACStmts(simplifiedTac), tacNaive.pcToIndex, i => i, simplifiedTac.length) - val stmtGraph = StmtGraph(nullifiedTac._1, tacCfg, tacNaive.pcToIndex, nullifiedTac._2) - // Nullified fields were added before the original statements. Hence, the original - // statements are shifted by the amount of new statements - val nullifiedPcToIndex = tacNaive.pcToIndex.map(i => if (i == Int.MinValue) i else i + nullifiedTac._2) - new BoomerangTACode(nullifiedTac._1, nullifiedPcToIndex, stmtGraph) + val stmtGraph = StmtGraph(simplifiedTac, tacCfg, tacNaive.pcToIndex) + val nopStmtGraph = NopTransformer(stmtGraph) + val nullifiedStmtGraph = NullifyFieldsTransformer(method, nopStmtGraph) + + new BoomerangTACode(nullifiedStmtGraph) } } diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala index b0009199b..5aa7b732c 100644 --- a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala @@ -19,9 +19,9 @@ class OpalInvokeExprTest { @Test def instanceInvokeExprTest(): Unit = { val opalSetup = new OpalSetup() - opalSetup.setupOpal(classOf[SingleTarget].getName) + opalSetup.setupOpal(classOf[ConstructorTarget].getName) - val signature = new MethodSignature(classOf[SingleTarget].getName, "whileLoop", "V") + val signature = new MethodSignature(classOf[ConstructorTarget].getName, "definedConstructor", "V") val method = opalSetup.resolveMethod(signature) val opalMethod = OpalMethod(method) opalMethod.getControlFlowGraph diff --git a/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootScopeTest.java b/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootScopeTest.java index 59c2a15e1..519eb80f7 100644 --- a/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootScopeTest.java +++ b/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootScopeTest.java @@ -147,9 +147,11 @@ public void fieldStoreAssignmentTest() { // Parameter locals MethodSignature signature = - new MethodSignature(SingleTarget.class.getName(), "branching2", "void"); + new MethodSignature(SingleTarget.class.getName(), "branching2", "int"); SootMethod method = sootSetup.resolveMethod(signature); + BoomerangPretransformer.v().apply(); Method jimpleMethod = JimpleMethod.of(method); + jimpleMethod.getControlFlowGraph().getStatements(); System.out.println(method.getActiveBody()); } diff --git a/boomerangScope/src/test/java/boomerang/scope/test/targets/SingleTarget.java b/boomerangScope/src/test/java/boomerang/scope/test/targets/SingleTarget.java index 246a7de8a..ddc7e6a13 100644 --- a/boomerangScope/src/test/java/boomerang/scope/test/targets/SingleTarget.java +++ b/boomerangScope/src/test/java/boomerang/scope/test/targets/SingleTarget.java @@ -17,7 +17,9 @@ public static void main(String[] args) { getAndSetField(); identityTest(); branching(); + branching2(); usage(); + whileLoop(); } public static void identityTest() { @@ -57,7 +59,7 @@ private static int branching2() { } private static void whileLoop() { - A a = new A(); + String s = "s"; while (Math.random() > 0.5) { System.out.println("Loop"); } From 6e8b31962239f71aaca3191cb0ff924760b6df54 Mon Sep 17 00:00:00 2001 From: Sven Meyer Date: Fri, 4 Apr 2025 11:20:28 +0200 Subject: [PATCH 33/61] Include exception flows --- .../opal/transformer/LocalTransformer.scala | 93 +++++++++++++++---- .../scope/opal/transformer/OperandStack.scala | 15 ++- .../scope/opal/transformer/TacLocal.scala | 28 +++++- .../opal/transformer/TacTransformer.scala | 2 +- .../scope/opal/OpalInvokeExprTest.scala | 4 +- .../scope/test/targets/SingleTarget.java | 9 ++ 6 files changed, 128 insertions(+), 23 deletions(-) diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/LocalTransformer.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/LocalTransformer.scala index 2dd5c22a4..7407275c2 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/LocalTransformer.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/LocalTransformer.scala @@ -12,6 +12,7 @@ object LocalTransformer { def apply(method: Method, tacNaive: NaiveTACode[_], domain: Domain, operandStack: OperandStack): Array[Stmt[TacLocal]] = { var paramCounter = -1 val currentLocals = mutable.Map.empty[Int, TacLocal] + val exceptionHandlers = tacNaive.exceptionHandlers.map(eh => eh.handlerPC) // Domain components val aiResult: AIResult = BaseAI(method, domain) @@ -40,7 +41,56 @@ object LocalTransformer { // Inserting -1 as it is only used in previous remapping steps return Switch(switchStmt.pc, switchStmt.defaultStmt, index, switchStmt.caseStmts.map(p => IntIntPair(-1, p))) case Assignment.ASTID => - val transformedExpr = transformExpr(stmt.pc, stmt.asAssignment.expr) + val assignStmt = stmt.asAssignment + val targetVar = assignStmt.targetVar + + if (assignStmt.pc == -1) { + val paramLocal = createNewParameterLocal(targetVar) + val transformedExpr = transformExpr(stmt.pc, assignStmt.expr) + + currentLocals(paramLocal.id) = paramLocal + return new Assignment[TacLocal](stmt.pc, paramLocal, transformedExpr) + } + + if (exceptionHandlers.contains(tacNaive.pcToIndex(stmt.pc)) && stmt.asAssignment.expr.isVar) { + val exceptionLocal = createNewExceptionLocal(stmt.pc, stmt.asAssignment.expr.asVar) + val targetLocal = if (targetVar.id >= 0) createNewStackLocal(stmt.pc, targetVar, exceptionLocal.isThisLocal) else createNewRegisterLocal(stmt.pc, targetVar, exceptionLocal.isThisLocal) + + currentLocals(exceptionLocal.id) = exceptionLocal + currentLocals(targetLocal.id) = targetLocal + return new Assignment[TacLocal](stmt.pc, targetLocal, exceptionLocal) + } + + if (targetVar.id >= 0) { + val transformedExpr = transformExpr(stmt.pc, assignStmt.expr) + + val isThisAssignment = transformedExpr.isVar && transformedExpr.asVar.isThisLocal + val targetLocal = createNewStackLocal(stmt.pc, targetVar, isThisAssignment) + + currentLocals(targetLocal.id) = targetLocal + return new Assignment[TacLocal](stmt.pc, targetLocal, transformedExpr) + } + + if (targetVar.id < 0) { + val transformedExpr = transformExpr(stmt.pc, assignStmt.expr) + + val isThisAssignment = transformedExpr.isVar && transformedExpr.asVar.isThisLocal + val targetLocal = createNewRegisterLocal(stmt.pc, targetVar, isThisAssignment) + + currentLocals(targetLocal.id) = targetLocal + return new Assignment[TacLocal](stmt.pc, targetLocal, transformedExpr) + } + + throw new RuntimeException("Could not transform assignment: " + assignStmt) + + /*val transformedExpr = if (exceptionHandlers.contains(tacNaive.pcToIndex(stmt.pc)) && stmt.asAssignment.expr.isVar) { + val exceptionVar = createNewLocal(stmt.pc, stmt.asAssignment.expr.asVar) + currentLocals(exceptionVar.id) = exceptionVar + + exceptionVar + } else { + transformExpr(stmt.pc, stmt.asAssignment.expr) + } val isThisAssignment = transformedExpr.isVar && transformedExpr.asVar.isThisLocal val target = createNewLocal(stmt.pc, stmt.asAssignment.targetVar, isThisAssignment) @@ -48,7 +98,7 @@ object LocalTransformer { // Store the current stack and register locals on our own 'stack' currentLocals(target.id) = target - return new Assignment(stmt.pc, target, transformedExpr) + return new Assignment(stmt.pc, target, transformedExpr)*/ case ReturnValue.ASTID => val returnStmt = stmt.asReturnValue val returnValue = transformExpr(stmt.pc, returnStmt.expr) @@ -136,26 +186,35 @@ object LocalTransformer { throw new RuntimeException("Could not transform statement: " + stmt) } - def createNewLocal(pc: Int, idBasedVar: IdBasedVar, isThis: Boolean = false): TacLocal = { - if (pc == -1) { - val local = localArray(0) + def createNewParameterLocal(idBasedVar: IdBasedVar): TacLocal = { + val local = localArray(0) + val isThisDef = method.isNotStatic && idBasedVar.id == -1 - val isThisDef = method.isNotStatic && idBasedVar.id == -1 - return new RegisterLocal(idBasedVar.id, idBasedVar.cTpe, local(-idBasedVar.id - 1), isThisDef) - } + new RegisterLocal(idBasedVar.id, idBasedVar.cTpe, local(-idBasedVar.id - 1), isThisDef) + } + def createNewStackLocal(pc: Int, idBasedVar: IdBasedVar, isThis: Boolean): TacLocal = { val nextPc = tacNaive.stmts(tacNaive.pcToIndex(pc) + 1).pc + val index = tacNaive.pcToIndex(pc) + val counter = operandStack.operandDefSite(index) - if (idBasedVar.id >= 0) { - val index = tacNaive.pcToIndex(pc) - val counter = operandStack.operandDefSite(index) + val value = operandsArray(nextPc).head + new StackLocal(counter, idBasedVar.cTpe, value, isThis) + } - val value = operandsArray(nextPc).head - new StackLocal(counter, idBasedVar.cTpe, value, isThis) - } else { - val local = localArray(nextPc) - new RegisterLocal(idBasedVar.id, idBasedVar.cTpe, local(-idBasedVar.id - 1), isThis) - } + def createNewRegisterLocal(pc: Int, idBasedVar: IdBasedVar, isThis: Boolean): TacLocal = { + val nextPc = tacNaive.stmts(tacNaive.pcToIndex(pc) + 1).pc + + val local = localArray(nextPc) + new RegisterLocal(idBasedVar.id, idBasedVar.cTpe, local(-idBasedVar.id - 1), isThis) + } + + def createNewExceptionLocal(pc: Int, idBasedVar: IdBasedVar): TacLocal = { + val index = tacNaive.pcToIndex(pc) + val counter = operandStack.operandDefSite(index) + + val value = operandsArray(pc).head + new ExceptionLocal(counter, idBasedVar.cTpe, value) } def transformExpr(pc: Int, expr: Expr[IdBasedVar]): Expr[TacLocal] = { diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/OperandStack.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/OperandStack.scala index 3f652766d..39d81e417 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/OperandStack.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/OperandStack.scala @@ -1,7 +1,7 @@ package boomerang.scope.opal.transformer import org.opalj.br.cfg.CFG -import org.opalj.tac.{Assignment, IdBasedVar, Stmt, TACStmts} +import org.opalj.tac.{Assignment, IdBasedVar, NaiveTACode, Stmt, TACStmts} import scala.collection.mutable @@ -87,7 +87,11 @@ class OperandStack(tac: Array[Stmt[IdBasedVar]], startIndex: Int) { object OperandStack { - def apply(tac: Array[Stmt[IdBasedVar]], cfg: CFG[Stmt[IdBasedVar], TACStmts[IdBasedVar]]): OperandStack = { + def apply(code: NaiveTACode[_]): OperandStack = { + val tac = code.stmts + val cfg = code.cfg + val exceptionHandlers = code.exceptionHandlers.map(eh => eh.handlerPC) + val firstNonNegativeIndex = tac.indexWhere(stmt => stmt.pc >= 0) val stack = new OperandStack(tac, firstNonNegativeIndex) var stackCounter = 0 @@ -110,6 +114,11 @@ object OperandStack { stack.push(currIndex, nextIndex, targetVar, stackCounter) stackCounter += 1 + } else if (isExceptionLoadStmt(currStmt)) { + val exceptionVar = currStmt.asAssignment.expr.asVar + + stack.push(currIndex, nextIndex, exceptionVar, stackCounter) + stackCounter += 1 } else { stack.update(currIndex, nextIndex) } @@ -122,6 +131,8 @@ object OperandStack { def schedule(nextIndex: Int): Unit = workList ::= nextIndex def isOperandPushStmt(stmt: Stmt[IdBasedVar]): Boolean = stmt.astID == Assignment.ASTID && stmt.asAssignment.targetVar.id >= 0 + + def isExceptionLoadStmt(stmt: Stmt[IdBasedVar]): Boolean = stmt.astID == Assignment.ASTID && stmt.asAssignment.expr.isVar && exceptionHandlers.contains(code.pcToIndex(stmt.pc)) } stack diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacLocal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacLocal.scala index 772a5a398..be95d4dce 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacLocal.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacLocal.scala @@ -131,7 +131,7 @@ class NullifiedLocal(identifier: Int, computationalType: ComputationalType) exte override def name: String = s"n$identifier" - override def hashCode(): Int = Objects.hash(id, isStackLocal, isRegisterLocal, isParameterLocal) + override def hashCode: Int = Objects.hash(id, isStackLocal, isRegisterLocal, isParameterLocal) override def equals(other: Any): Boolean = other match { case that: NullifiedLocal => this.id == that.id @@ -139,4 +139,30 @@ class NullifiedLocal(identifier: Int, computationalType: ComputationalType) exte } } +class ExceptionLocal(identifier: Int, computationalType: ComputationalType, valueInfo: ValueInformation) extends TacLocal { + + override def id: Int = identifier + + override def isStackLocal: Boolean = true + + override def isRegisterLocal: Boolean = false + + override def isParameterLocal: Boolean = false + + override def isThisLocal: Boolean = false + + override def cTpe: ComputationalType = computationalType + + override def value: ValueInformation = valueInfo + + override def name: String = s"e$identifier" + + override def hashCode: Int = Objects.hash(id) + + override def equals(other: Any): Boolean = other match { + case that: ExceptionLocal => this.id == that.id + case _ => false + } +} + // TODO Consider TempLocal in SWAP diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacTransformer.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacTransformer.scala index 20f5d8505..6ed406ea0 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacTransformer.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacTransformer.scala @@ -12,7 +12,7 @@ object TacTransformer { val tacNaive = TACNaive(method, project.classHierarchy) val domain = new PrimitiveTACAIDomain(project.classHierarchy, method) - val operandStack = OperandStack(tacNaive.stmts, tacNaive.cfg) + val operandStack = OperandStack(tacNaive) val transformedTac = LocalTransformer(method, tacNaive, domain, operandStack) val simplifiedTac = BasicPropagation(transformedTac, operandStack) diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala index 5aa7b732c..5f3f5ce6d 100644 --- a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala @@ -19,9 +19,9 @@ class OpalInvokeExprTest { @Test def instanceInvokeExprTest(): Unit = { val opalSetup = new OpalSetup() - opalSetup.setupOpal(classOf[ConstructorTarget].getName) + opalSetup.setupOpal(classOf[SingleTarget].getName) - val signature = new MethodSignature(classOf[ConstructorTarget].getName, "definedConstructor", "V") + val signature = new MethodSignature(classOf[SingleTarget].getName, "tryCatch", "V") val method = opalSetup.resolveMethod(signature) val opalMethod = OpalMethod(method) opalMethod.getControlFlowGraph diff --git a/boomerangScope/src/test/java/boomerang/scope/test/targets/SingleTarget.java b/boomerangScope/src/test/java/boomerang/scope/test/targets/SingleTarget.java index ddc7e6a13..3eb144570 100644 --- a/boomerangScope/src/test/java/boomerang/scope/test/targets/SingleTarget.java +++ b/boomerangScope/src/test/java/boomerang/scope/test/targets/SingleTarget.java @@ -20,6 +20,7 @@ public static void main(String[] args) { branching2(); usage(); whileLoop(); + tryCatch(); } public static void identityTest() { @@ -72,4 +73,12 @@ private static void usage() { a.methodCall(i); a.methodCall(i); } + + private static void tryCatch() { + try { + usage(); + } catch (Exception e) { + System.out.println(e); + } + } } From 57b1f24cd4adf5c2bc74bf3c2fbdeca77433d5dd Mon Sep 17 00:00:00 2001 From: Sven Meyer Date: Fri, 4 Apr 2025 13:43:29 +0200 Subject: [PATCH 34/61] Fix handling of identity statements --- .../boomerang/scope/opal/tac/OpalMethod.scala | 16 +--------------- .../boomerang/scope/opal/tac/OpalStatement.scala | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 17 deletions(-) diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalMethod.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalMethod.scala index 24251a737..b81ada964 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalMethod.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalMethod.scala @@ -38,6 +38,7 @@ class OpalMethod private(val delegate: org.opalj.br.Method, val tac: BoomerangTA override def isThisLocal(fact: Val): Boolean = { if (isStatic) return false + if (fact.isStatic) return false val thisLocal = getThisLocal thisLocal.equals(fact) @@ -66,21 +67,6 @@ class OpalMethod private(val delegate: org.opalj.br.Method, val tac: BoomerangTA localCache = Some(new util.HashSet[Val]()) tac.getLocals.foreach(l => localCache.get.add(new OpalLocal(l, this))) - /*// 'this' local - if (!isStatic) { - localCache.get.add(getThisLocal) - } - - // Parameter locals - localCache.get.addAll(getParameterLocals) - - tac.statements.foreach(stmt => { - if (stmt.isAssignment) { - val targetVar = stmt.asAssignment.targetVar - - localCache.get.add(new OpalLocal(targetVar, this)) - } - })*/ } localCache.get diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala index f8cc54a13..e0f1fa73a 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala @@ -94,8 +94,18 @@ class OpalStatement(val delegate: Stmt[TacLocal], m: OpalMethod) extends Stateme override def isAssignStmt: Boolean = { if (delegate.isAssignment) { - if (delegate.asAssignment.expr.isVar) { - return !delegate.asAssignment.expr.asVar.isParameterLocal + val targetVar = delegate.asAssignment.targetVar + val expr = delegate.asAssignment.expr + + if (expr.isVar) { + /* Difference between Soot and Opal: + * - Soot considers parameter definitions and self assignments of the this local as identity statements (no assignments) + * - Opal considers these statements as basic assignments, so we have to exclude them manually + */ + if (expr.asVar.isParameterLocal) return false + if (targetVar.isThisLocal && expr.asVar.isThisLocal) return false + + return true } else { return true } From 1eebc2fcd2dff231ab178af9e43bcba48384c1e3 Mon Sep 17 00:00:00 2001 From: Sven Meyer Date: Sat, 5 Apr 2025 14:22:15 +0200 Subject: [PATCH 35/61] Fix exception flows in StmtGraph --- .../scope/opal/transformer/OperandStack.scala | 13 +++++++------ .../scope/opal/transformer/StmtGraph.scala | 13 +++++++++---- .../scope/opal/transformer/TacTransformer.scala | 3 ++- .../java/boomerang/scope/soot/SootScopeTest.java | 1 - .../scope/test/targets/SingleTarget.java | 16 +++++++++++++++- .../src/main/java/test/setup/OpalTestSetup.java | 8 ++++++-- 6 files changed, 39 insertions(+), 15 deletions(-) diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/OperandStack.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/OperandStack.scala index 39d81e417..0e1096228 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/OperandStack.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/OperandStack.scala @@ -5,11 +5,12 @@ import org.opalj.tac.{Assignment, IdBasedVar, NaiveTACode, Stmt, TACStmts} import scala.collection.mutable -class OperandStack(tac: Array[Stmt[IdBasedVar]], startIndex: Int) { +class OperandStack(tac: Array[Stmt[IdBasedVar]], startIndex: Int, exceptionHandlers: List[Int]) { private val stmtStacks = new Array[mutable.Map[Int, (Int, List[Int], List[Int])]](tac.length) private val operandDefSites = Array.fill(tac.length)(-1) - stmtStacks(startIndex) = mutable.Map.empty[Int, (Int, List[Int], List[Int])] + stmtStacks(startIndex) = mutable.Map.empty + exceptionHandlers.foreach(i => stmtStacks(i) = mutable.Map.empty) def push(currIndex: Int, nextIndex: Int, operand: IdBasedVar, stackCounter: Int): Unit = { val currStack = stmtStacks(currIndex).map(identity) @@ -90,13 +91,13 @@ object OperandStack { def apply(code: NaiveTACode[_]): OperandStack = { val tac = code.stmts val cfg = code.cfg - val exceptionHandlers = code.exceptionHandlers.map(eh => eh.handlerPC) + val exceptionHandlers = code.exceptionHandlers.map(eh => eh.handlerPC).toList val firstNonNegativeIndex = tac.indexWhere(stmt => stmt.pc >= 0) - val stack = new OperandStack(tac, firstNonNegativeIndex) + val stack = new OperandStack(tac, firstNonNegativeIndex, exceptionHandlers) var stackCounter = 0 - var workList: List[Int] = List(firstNonNegativeIndex) + var workList: List[Int] = firstNonNegativeIndex :: exceptionHandlers while (workList.nonEmpty) { val currIndex = workList.head val currStmt = tac(currIndex) @@ -108,7 +109,7 @@ object OperandStack { // Reversing is not needed; however, this way, the stack locals are enumerated in ascending order val nextIndices = cfg.successors(currIndex).toList.reverse nextIndices.foreach(nextIndex => { - if (currIndex < nextIndex) { + if (currIndex < nextIndex && !exceptionHandlers.contains(nextIndex)) { if (isOperandPushStmt(currStmt)) { val targetVar = currStmt.asAssignment.targetVar diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/StmtGraph.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/StmtGraph.scala index f515c10f2..8c497af2f 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/StmtGraph.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/StmtGraph.scala @@ -7,6 +7,7 @@ import scala.collection.mutable class StmtGraph private (val tac: Array[Stmt[TacLocal]], val heads: Set[Stmt[TacLocal]], val tails: Set[Stmt[TacLocal]], val predecessors: Map[Stmt[TacLocal], Set[Stmt[TacLocal]]], val successors: Map[Stmt[TacLocal], Set[Stmt[TacLocal]]], val statements: List[Stmt[TacLocal]]) { + // TODO Update if and goto targets def insertBefore(insertStmt: Stmt[TacLocal], existingStmt: Stmt[TacLocal]): StmtGraph = { val tempSuccessor = mutable.Map.from(successors) @@ -32,7 +33,7 @@ class StmtGraph private (val tac: Array[Stmt[TacLocal]], val heads: Set[Stmt[Tac // Potential head statement update var newHeads = heads.map(identity) if (heads.contains(existingStmt)) { - newHeads = Set(insertStmt) + newHeads = newHeads - existingStmt + insertStmt } val newStatements = statements.flatMap { @@ -80,9 +81,9 @@ class StmtGraph private (val tac: Array[Stmt[TacLocal]], val heads: Set[Stmt[Tac object StmtGraph { - def apply(tac: Array[Stmt[TacLocal]], cfg: CFG[Stmt[TacLocal], TACStmts[TacLocal]], pcToIndex: Array[Int]): StmtGraph = { + def apply(tac: Array[Stmt[TacLocal]], cfg: CFG[Stmt[TacLocal], TACStmts[TacLocal]], pcToIndex: Array[Int], exceptionHandlers: Array[Int]): StmtGraph = { - def computeHead: Set[Stmt[TacLocal]] = Set(tac(0)) + def computeHead: Set[Stmt[TacLocal]] = exceptionHandlers.map(eh => tac(eh)).toSet + tac(0) def computeTails: Set[Stmt[TacLocal]] = { tac.filter(stmt => stmt.pc >= 0).filter(stmt => { @@ -111,6 +112,10 @@ object StmtGraph { } val stmtIndex = pcToIndex(stmt.pc) + if (exceptionHandlers.contains(stmtIndex)) { + return Set() + } + val predecessors = cfg.predecessors(stmtIndex) predecessors.map(predecessorIndex => tac(predecessorIndex)) } @@ -124,7 +129,7 @@ object StmtGraph { val stmtIndex = pcToIndex(stmt.pc) val successors = cfg.successors(stmtIndex) - successors.map(successorIndex => tac(successorIndex)) + successors.filter(s => !exceptionHandlers.contains(s)).map(successorIndex => tac(successorIndex)) } val heads = computeHead diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacTransformer.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacTransformer.scala index 6ed406ea0..4990f2ead 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacTransformer.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacTransformer.scala @@ -24,7 +24,8 @@ object TacTransformer { val tacCfg = cfg.get.mapPCsToIndexes[Stmt[TacLocal], TACStmts[TacLocal]](TACStmts(simplifiedTac), tacNaive.pcToIndex, i => i, simplifiedTac.length) - val stmtGraph = StmtGraph(simplifiedTac, tacCfg, tacNaive.pcToIndex) + val exceptionHandlers = tacNaive.exceptionHandlers.map(eh => eh.handlerPC).toArray + val stmtGraph = StmtGraph(simplifiedTac, tacCfg, tacNaive.pcToIndex, exceptionHandlers) val nopStmtGraph = NopTransformer(stmtGraph) val nullifiedStmtGraph = NullifyFieldsTransformer(method, nopStmtGraph) diff --git a/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootScopeTest.java b/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootScopeTest.java index 519eb80f7..65da4a30c 100644 --- a/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootScopeTest.java +++ b/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootScopeTest.java @@ -18,7 +18,6 @@ import boomerang.scope.soot.jimple.JimpleMethod; import boomerang.scope.test.MethodSignature; import boomerang.scope.test.targets.A; -import boomerang.scope.test.targets.AssignmentTarget; import boomerang.scope.test.targets.HashCodeEqualsLocalTarget; import boomerang.scope.test.targets.ParameterLocalsTarget; import boomerang.scope.test.targets.SingleTarget; diff --git a/boomerangScope/src/test/java/boomerang/scope/test/targets/SingleTarget.java b/boomerangScope/src/test/java/boomerang/scope/test/targets/SingleTarget.java index 3eb144570..defd87bb2 100644 --- a/boomerangScope/src/test/java/boomerang/scope/test/targets/SingleTarget.java +++ b/boomerangScope/src/test/java/boomerang/scope/test/targets/SingleTarget.java @@ -21,6 +21,9 @@ public static void main(String[] args) { usage(); whileLoop(); tryCatch(); + + SingleTarget target = new SingleTarget(); + target.block(); } public static void identityTest() { @@ -78,7 +81,18 @@ private static void tryCatch() { try { usage(); } catch (Exception e) { - System.out.println(e); + A a = new A(); + throw e; + } + } + + Object field; + + public void block() { + synchronized (field) { + A a = new A(); + + System.out.println(a); } } } diff --git a/testCore/src/main/java/test/setup/OpalTestSetup.java b/testCore/src/main/java/test/setup/OpalTestSetup.java index e11a50db9..3be62e8f7 100644 --- a/testCore/src/main/java/test/setup/OpalTestSetup.java +++ b/testCore/src/main/java/test/setup/OpalTestSetup.java @@ -155,8 +155,12 @@ private String convertType(String type) { if (type.equals("long")) return LongType$.MODULE$.toJVMTypeName(); if (type.equals("short")) return ShortType$.MODULE$.toJVMTypeName(); if (type.equals("boolean")) return BooleanType$.MODULE$.toJVMTypeName(); - if (type.contains("[]")) { - return new StringBuilder(type.replace(".", "/")).insert(0, "[").toString(); + // TODO Consider all array types (not just ref types + if (type.endsWith("[]")) { + return new StringBuilder(type.replace(".", "/").replace("[]", "")) + .insert(0, "[L") + .append(";") + .toString(); } // Convert class types: java.lang.Object => Ljava.lang.Object; From 1fb11beeb47d33bb99a45ecd825899db12cc3177 Mon Sep 17 00:00:00 2001 From: Sven Meyer Date: Sat, 12 Apr 2025 09:26:19 +0200 Subject: [PATCH 36/61] Rework of operand stack --- .../opal/transformation/TacBodyBuilder.scala | 16 ++ .../scope/opal/transformation/TacLocal.scala | 168 ++++++++++++++ .../opal/transformation/stack/Operand.scala | 26 +++ .../transformation/stack/OperandStack.scala | 55 +++++ .../stack/OperandStackBuilder.scala | 201 ++++++++++++++++ .../stack/OperandStackHandler.scala | 56 +++++ .../transformer/LocalTransformer.scala | 215 ++++++++++++++++++ .../scope/opal/OpalInvokeExprTest.scala | 5 +- 8 files changed, 741 insertions(+), 1 deletion(-) create mode 100644 boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacBodyBuilder.scala create mode 100644 boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacLocal.scala create mode 100644 boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/Operand.scala create mode 100644 boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStack.scala create mode 100644 boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackBuilder.scala create mode 100644 boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackHandler.scala create mode 100644 boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/LocalTransformer.scala diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacBodyBuilder.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacBodyBuilder.scala new file mode 100644 index 000000000..cb6001c5a --- /dev/null +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacBodyBuilder.scala @@ -0,0 +1,16 @@ +package boomerang.scope.opal.transformation + +import boomerang.scope.opal.transformation.stack.OperandStackBuilder +import boomerang.scope.opal.transformer.BoomerangTACode +import org.opalj.br.Method +import org.opalj.br.analyses.Project +import org.opalj.tac.TACNaive + +object TacBodyBuilder { + + def apply(project: Project[_], method: Method): BoomerangTACode = { + val tacNaive = TACNaive(method, project.classHierarchy) + val stackHandler = OperandStackBuilder(method, tacNaive) + ??? + } +} diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacLocal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacLocal.scala new file mode 100644 index 000000000..2c31a4f76 --- /dev/null +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacLocal.scala @@ -0,0 +1,168 @@ +package boomerang.scope.opal.transformation + +import org.opalj.br.ComputationalType +import org.opalj.tac.{DUVar, Var} +import org.opalj.value.{IsNullValue, ValueInformation} + +import java.util.Objects + +trait TacLocal extends Var[TacLocal] { + + def id: Int + + def isStackLocal: Boolean + + def isRegisterLocal: Boolean + + def isParameterLocal: Boolean + + def isThisLocal: Boolean + + def cTpe: ComputationalType + + def value: ValueInformation + + final def isSideEffectFree: Boolean = true + + override def toCanonicalForm(implicit ev: TacLocal <:< DUVar[ValueInformation]): Nothing = { + throw new IncompatibleClassChangeError( + "TacLocal objects are not expected to inherit from DUVar" + ) + } + + override def toString: String = name +} + +class StackLocal(identifier: Int, computationalType: ComputationalType, valueInfo: ValueInformation, isThis: Boolean = false) extends TacLocal { + + override def id: Int = identifier + + override def isStackLocal: Boolean = true + + override def isRegisterLocal: Boolean = false + + override def isParameterLocal: Boolean = false + + override def isThisLocal: Boolean = isThis + + override def name: String = if (isThis) "$this" else s"$$s$identifier" + + override def cTpe: ComputationalType = computationalType + + override def value: ValueInformation = valueInfo + + override def hashCode: Int = Objects.hash(id, isStackLocal, isRegisterLocal, isParameterLocal) + + override def equals(other: Any): Boolean = other match { + case that: StackLocal => this.id == that.id + case that: RegisterLocal => this.isThisLocal && that.isThisLocal + case _ => false + } +} + +class RegisterLocal(identifier: Int, computationalType: ComputationalType, valueInfo: ValueInformation, isThis: Boolean = false) extends TacLocal { + + override def id: Int = identifier + + override def isStackLocal: Boolean = false + + override def isRegisterLocal: Boolean = true + + override def isParameterLocal: Boolean = false + + override def isThisLocal: Boolean = isThis + + override def name: String = if (isThis) "this" else s"r${-identifier - 1}" + + override def cTpe: ComputationalType = computationalType + + override def value: ValueInformation = valueInfo + + override def hashCode: Int = Objects.hash(id, isStackLocal, isRegisterLocal, isParameterLocal) + + override def equals(other: Any): Boolean = other match { + case that: RegisterLocal => this.id == that.id + case that: StackLocal => this.isThisLocal && that.isThisLocal + case _ => false + } +} + +class ParameterLocal(identifier: Int, computationalType: ComputationalType, paramName: String) extends TacLocal { + + override def id: Int = identifier + + override def isStackLocal: Boolean = false + + override def isRegisterLocal: Boolean = false + + override def isParameterLocal: Boolean = true + + override def isThisLocal: Boolean = false + + override def cTpe: ComputationalType = computationalType + + override def value: ValueInformation = throw new UnsupportedOperationException("No value information available for parameter local") + + override def name: String = paramName + + override def hashCode: Int = Objects.hash(id, isStackLocal, isRegisterLocal, isParameterLocal) + + override def equals(other: Any): Boolean = other match { + case that: ParameterLocal => this.id == that.id + case _ => false + } +} + +class NullifiedLocal(identifier: Int, computationalType: ComputationalType) extends TacLocal { + + override def id: Int = identifier + + override def isStackLocal: Boolean = false + + override def isRegisterLocal: Boolean = false + + override def isParameterLocal: Boolean = false + + override def isThisLocal: Boolean = false + + override def cTpe: ComputationalType = computationalType + + override def value: ValueInformation = IsNullValue + + override def name: String = s"n$identifier" + + override def hashCode: Int = Objects.hash(id, isStackLocal, isRegisterLocal, isParameterLocal) + + override def equals(other: Any): Boolean = other match { + case that: NullifiedLocal => this.id == that.id + case _ => false + } +} + +class ExceptionLocal(identifier: Int, computationalType: ComputationalType, valueInfo: ValueInformation) extends TacLocal { + + override def id: Int = identifier + + override def isStackLocal: Boolean = true + + override def isRegisterLocal: Boolean = false + + override def isParameterLocal: Boolean = false + + override def isThisLocal: Boolean = false + + override def cTpe: ComputationalType = computationalType + + override def value: ValueInformation = valueInfo + + override def name: String = s"e$identifier" + + override def hashCode: Int = Objects.hash(id) + + override def equals(other: Any): Boolean = other match { + case that: ExceptionLocal => this.id == that.id + case _ => false + } +} + +// TODO Consider TempLocal in SWAP diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/Operand.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/Operand.scala new file mode 100644 index 000000000..97d91cdd6 --- /dev/null +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/Operand.scala @@ -0,0 +1,26 @@ +package boomerang.scope.opal.transformation.stack + +import java.util.Objects + +class Operand(val id: Int, private var counter: Int) { + + private var modified = false + + def localId: Int = counter + + def updateCounter(newCount: Int): Unit = { + counter = newCount + modified = true + } + + def isBranchedOperand: Boolean = modified + + override def hashCode: Int = Objects.hash(id) + + override def equals(obj: Any): Boolean = obj match { + case that: Operand => this.id == that.id + case _ => false + } + + override def toString: String = s"op$id ($counter)" +} diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStack.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStack.scala new file mode 100644 index 000000000..37d9c2f6e --- /dev/null +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStack.scala @@ -0,0 +1,55 @@ +package boomerang.scope.opal.transformation.stack + +import org.opalj.tac.IdBasedVar + +class OperandStack private(stackHandler: OperandStackHandler, private var stack: List[Operand]) { + + def push(idBasedVar: IdBasedVar): Unit = { + val operand = new Operand(idBasedVar.id, stackHandler.nextLocalCounter) + stack = operand :: stack + } + + def push(operand: Operand): Unit = { + stack = operand :: stack + } + + def pop(idBasedVar: IdBasedVar): Unit = { + if (stack.isEmpty) { + throw new IllegalStateException(s"Cannot pop operand $idBasedVar from empty stack") + } + + val top :: rest = stack + stack = rest + + // Check if stack is in consistent state + assert(idBasedVar.id == top.id, s"Invalid pop operation on operand $idBasedVar") + } + + def pop: Operand = { + if (stack.isEmpty) { + throw new IllegalStateException(s"Cannot pop operand from empty stack") + } + + val top :: rest = stack + stack = rest + + top + } + + def peek: Operand = { + if (stack.isEmpty) return null + + val top :: _ = stack + top + } + + def copy: OperandStack = new OperandStack(stackHandler, stack.map(identity)) + + override def toString: String = stack.toString() + +} + +object OperandStack { + + def apply(stackHandler: OperandStackHandler, stack: List[Operand] = List.empty) = new OperandStack(stackHandler, stack) +} diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackBuilder.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackBuilder.scala new file mode 100644 index 000000000..642558b7b --- /dev/null +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackBuilder.scala @@ -0,0 +1,201 @@ +package boomerang.scope.opal.transformation.stack + +import org.opalj.br.{Method, NoPCs} +import org.opalj.br.instructions.{DUP, DUP2, DUP2_X1, DUP2_X2, DUP_X1, DUP_X2, NOP, POP, POP2, WIDE} +import org.opalj.bytecode.PC +import org.opalj.tac.{ArrayLength, ArrayLoad, ArrayStore, Assignment, BinaryExpr, CaughtException, Checkcast, ClassConst, Compare, Const, DoubleConst, DynamicConst, Expr, ExprStmt, FloatConst, GetField, GetStatic, Goto, IdBasedVar, If, InstanceOf, IntConst, InvokedynamicFunctionCall, InvokedynamicMethodCall, JSR, LongConst, MethodHandleConst, MethodTypeConst, MonitorEnter, MonitorExit, NaiveTACode, New, NewArray, NonVirtualFunctionCall, NonVirtualMethodCall, Nop, NullExpr, Param, PrefixExpr, PrimitiveTypecastExpr, PutField, PutStatic, Ret, Return, ReturnValue, StaticFunctionCall, StaticMethodCall, Stmt, StringConst, Switch, Throw, VirtualFunctionCall, VirtualMethodCall} + +object OperandStackBuilder { + + def apply(method: Method, tacNaive: NaiveTACode[_]): OperandStackHandler = { + val stackHandler = new OperandStackHandler + + // Initialize work list; we always start with pc 0 + var workList = List(0) + for (eh <- tacNaive.exceptionHandlers) { + workList ::= eh.handlerPC + } + + while (workList.nonEmpty) { + val currPc = workList.head + val currStmt = tacNaive.stmts(tacNaive.pcToIndex(currPc)) + workList = workList.tail + + processStmt(currStmt) + + def pcOfNextStatement(pc: PC): PC = method.body.get.pcOfNextInstruction(pc) + + def schedule(nextPc: PC, stack: OperandStack): Unit = { + val merged = stackHandler.mergeStack(nextPc, stack) + + if (merged) { + workList ::= nextPc + } + } + + def processStmt(stmt: Stmt[IdBasedVar]): Unit = { + val stack = stackHandler.getOrCreate(stmt.pc) + + stmt match { + case If(pc, left, _, right, target) => + val leftOps = processExpr(left) + leftOps.foreach(op => stack.pop(op)) + + val rightOps = processExpr(right) + rightOps.foreach(op => stack.pop(op)) + + schedule(pcOfNextStatement(pc), stack) + + val targetStmt = tacNaive.stmts(target) + schedule(targetStmt.pc, stack) + case Goto(_, target) => + val targetStmt = tacNaive.stmts(target) + schedule(targetStmt.pc, stack) + case Ret(pc, returnAddresses) => + // TODO + case JSR(_, target) => + schedule(target, stack) + case Switch(_, defaultTarget, index: IdBasedVar, nPairs) => + stack.pop(index) + + // TODO branch targets + schedule(defaultTarget, stack) + case Assignment(pc, targetVar: IdBasedVar, expr: Expr[IdBasedVar]) => + val operands = processExpr(expr) + operands.foreach(op => stack.pop(op)) + + if (targetVar.id >= 0) { + stack.push(targetVar) + stackHandler.addDefSite(pc, stack.peek) + } + + schedule(pcOfNextStatement(pc), stack) + case ReturnValue(_, expr: IdBasedVar) => + stack.pop(expr) + // No scheduling since there is no next statement + case Return(_) => // No scheduling since there is no next statement + case Nop(pc) => + val instr = method.body.get.instructions(pc) + + instr.opcode match { + case NOP.opcode => + case POP.opcode | POP2.opcode => + stack.pop + case DUP.opcode => + val dupOperand = stack.peek + stack.push(dupOperand) + case DUP_X1.opcode => + val val1 = stack.pop + val val2 = stack.pop + + stack.push(val1) + stack.push(val2) + stack.push(val1) + case DUP_X2.opcode => + // TODO + case DUP2.opcode => + // TODO + case DUP2_X1.opcode => + // TODO + case DUP2_X2.opcode => + // TODO + case WIDE.opcode => + } + + schedule(pcOfNextStatement(pc), stack) + case MonitorEnter(pc, objRef: IdBasedVar) => + stack.pop(objRef) + + schedule(pcOfNextStatement(pc), stack) + case MonitorExit(pc, objRef: IdBasedVar) => + stack.pop(objRef) + + schedule(pcOfNextStatement(pc), stack) + case ArrayStore(pc, arrayRef: IdBasedVar, index: IdBasedVar, value: IdBasedVar) => + stack.pop(arrayRef) + stack.pop(index) + stack.pop(value) + + schedule(pcOfNextStatement(pc), stack) + case Throw(_, exception: IdBasedVar) => + stack.pop(exception) + // No scheduling since there is no next statement + case PutStatic(pc, _, _, _, value: IdBasedVar) => + stack.pop(value) + + schedule(pcOfNextStatement(pc), stack) + case PutField(pc, _, _, _, objRef: IdBasedVar, value: IdBasedVar) => + stack.pop(objRef) + stack.pop(value) + + schedule(pcOfNextStatement(pc), stack) + case NonVirtualMethodCall(pc, _, _, _, _, receiver: IdBasedVar, params: Seq[IdBasedVar]) => + params.foreach(p => stack.pop(p.asVar)) + stack.pop(receiver) + + schedule(pcOfNextStatement(pc), stack) + case VirtualMethodCall(pc, _, _, _, _, receiver: IdBasedVar, params: Seq[IdBasedVar]) => + params.foreach(p => stack.pop(p.asVar)) + stack.pop(receiver) + + schedule(pcOfNextStatement(pc), stack) + case StaticMethodCall(pc, _, _, _, _, params: Seq[IdBasedVar]) => + params.foreach(p => stack.pop(p.asVar)) + + schedule(pcOfNextStatement(pc), stack) + case InvokedynamicMethodCall(pc, _, _, _, params: Seq[IdBasedVar]) => + params.foreach(p => stack.pop(p.asVar)) + + schedule(pcOfNextStatement(pc), stack) + case ExprStmt(pc, expr) => + processExpr(expr) + + schedule(pcOfNextStatement(pc), stack) + case CaughtException(pc, _, _) => + // Only used in TACAI, so no stack manipulation is required + schedule(pcOfNextStatement(pc), stack) + case Checkcast(pc, value, _) => + // TODO Push new stack value + schedule(pcOfNextStatement(pc), stack) + case _ => throw new RuntimeException("Unknown statement: " + stmt) + } + } + + def processExpr(expr: Expr[IdBasedVar]): List[IdBasedVar] = { + expr match { + case v: IdBasedVar => if (v.id >= 0) List(v) else List() + case InstanceOf(_, value: IdBasedVar, _) => List(value) + case Compare(_, left: IdBasedVar, _, right: IdBasedVar) => List(right, left) + case Param(_, _) => List() + case MethodTypeConst(_, _) => List() + case MethodHandleConst(_, _) => List() + case IntConst(_, _) => List() + case LongConst(_, _) => List() + case FloatConst(_, _) => List() + case DoubleConst(_, _) => List() + case StringConst(_, _) => List() + case ClassConst(_, _) => List() + case DynamicConst(_, _, _, _) => List() + case NullExpr(_) => List() + case BinaryExpr(_, _, _, left: IdBasedVar, right: IdBasedVar) => List(left, right) + case PrefixExpr(_, _, _, operand: IdBasedVar) => List(operand) + case PrimitiveTypecastExpr(_, _, operand: IdBasedVar) => List(operand) + case New(_, _) => List() + case NewArray(_, counts: Seq[IdBasedVar], _) => counts.map(c => c.asVar).toList + case ArrayLoad(_, index: IdBasedVar, arrayRef: IdBasedVar) => List(index, arrayRef) + case ArrayLength(_, arrayRef: IdBasedVar) => List(arrayRef) + case GetField(_, _, _, _, objRef: IdBasedVar) => List(objRef) + case GetStatic(_, _, _, _) => List() + case InvokedynamicFunctionCall(_, _, _, _, params: Seq[IdBasedVar]) => params.map(p => p.asVar).toList + case NonVirtualFunctionCall(_, _, _, _, _, receiver: IdBasedVar, params: Seq[IdBasedVar]) => params.map(p => p.asVar).toList :+ receiver + case VirtualFunctionCall(_, _, _, _, _, receiver: IdBasedVar, params: Seq[IdBasedVar]) => params.map(p => p.asVar).toList :+ receiver + case StaticFunctionCall(_, _, _, _, _, params: Seq[IdBasedVar]) => params.map(p => p.asVar).toList + case _ => throw new RuntimeException("Unknown expression: " + expr) + } + } + + } + stackHandler + } + +} diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackHandler.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackHandler.scala new file mode 100644 index 000000000..ea05b5d25 --- /dev/null +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackHandler.scala @@ -0,0 +1,56 @@ +package boomerang.scope.opal.transformation.stack + +import org.opalj.br.PC + +import scala.collection.mutable + +class OperandStackHandler { + + private val pcToStack = mutable.Map.empty[PC, OperandStack] + private val defSites = mutable.Map.empty[PC, Operand] + private var localCounter = 0 + + def getOrCreate(pc: PC): OperandStack = { + if (pcToStack.contains(pc)) { + pcToStack(pc).copy + } else { + val stack = OperandStack(this) + pcToStack.put(pc, stack) + + stack.copy + } + } + + def addDefSite(pc: PC, operand: Operand): Unit = { + defSites.put(pc, operand) + } + + def mergeStack(nextPc: PC, incomingStack: OperandStack): Boolean = { + val existingStack = pcToStack.getOrElse(nextPc, null) + + if (existingStack == null) { + pcToStack.put(nextPc, incomingStack) + + true + } else { + var modified = false + existingStack.stack.foreach(existingOp => { + incomingStack.stack.foreach(incomingOp => { + if (existingOp.id == incomingOp.id && existingOp.localId != incomingOp.localId) { + incomingOp.updateCounter(existingOp.localId) + + modified = true + } + }) + }) + modified + } + } + + def nextLocalCounter: Int = { + localCounter += 1 + + localCounter + } + +} diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/LocalTransformer.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/LocalTransformer.scala new file mode 100644 index 000000000..43cd00ed6 --- /dev/null +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/LocalTransformer.scala @@ -0,0 +1,215 @@ +package boomerang.scope.opal.transformation.transformer + +import boomerang.scope.opal.transformation.{ExceptionLocal, ParameterLocal, RegisterLocal, TacLocal} +import boomerang.scope.opal.transformation.stack.OperandStackHandler +import org.opalj.ai.{AIResult, BaseAI, Domain} +import org.opalj.br.{Method, PC} +import org.opalj.tac.{ArrayLength, ArrayLoad, ArrayStore, Assignment, BinaryExpr, CaughtException, Checkcast, ClassConst, Compare, DoubleConst, DynamicConst, Expr, ExprStmt, FloatConst, GetField, GetStatic, Goto, IdBasedVar, If, InstanceOf, IntConst, InvokedynamicFunctionCall, InvokedynamicMethodCall, JSR, LongConst, MethodHandleConst, MethodTypeConst, MonitorEnter, MonitorExit, NaiveTACode, New, NewArray, NonVirtualFunctionCall, NonVirtualMethodCall, Nop, NullExpr, Param, PrefixExpr, PrimitiveTypecastExpr, PutField, PutStatic, Ret, Return, ReturnValue, StaticFunctionCall, StaticMethodCall, Stmt, StringConst, Switch, Throw, VirtualFunctionCall, VirtualMethodCall} + +object LocalTransformer { + + def apply(method: Method, tac: NaiveTACode[_], stackHandler: OperandStackHandler, domain: Domain): Array[Stmt[TacLocal]] = { + var paramCount = -1 + var exceptionCount = -1 + val exceptionHandlers = tac.exceptionHandlers.map(eh => eh.handlerPC) + + // Domain components + val aiResult: AIResult = BaseAI(method, domain) + val operandsArray: aiResult.domain.OperandsArray = aiResult.operandsArray + val localArray: aiResult.domain.LocalsArray = aiResult.localsArray + + def transformStmt(stmt: Stmt[IdBasedVar]): Stmt[TacLocal] = { + stmt match { + case If(pc, left, condition, right, target) => + val leftExpr = transformExpr(left) + val rightExpr = transformExpr(right) + + return If(pc, leftExpr, condition, rightExpr, target) + case Goto(pc, target) => return Goto(pc, target) + case Ret(pc, returnAddresses) => return Ret(pc, returnAddresses) + case JSR(pc, target) => return JSR(pc, target) + case Switch(pc, defaultTarget, index, nPairs) => + val indexExpr = transformExpr(index) + + return Switch(pc,defaultTarget, indexExpr, nPairs) + case Assignment(pc, targetVar, expr) => + // Parameter definition statements + if (pc == -1) { + val paramLocal = createNewParameterLocal(targetVar) + val transformedExpr = transformExpr(expr) + + return Assignment(pc, paramLocal, transformedExpr) + } + + // Definition of exception handlers + if (exceptionHandlers.contains(tac.pcToIndex(pc)) && expr.isVar) { + val exceptionLocal = createNewExceptionLocal(pc, expr.asVar) + } + // TODO + case ReturnValue(pc, expr) => + val returnExpr = transformExpr(expr) + + return ReturnValue(pc, returnExpr) + case Return(pc) => return Return(pc) + case Nop(pc) => return Nop(pc) + case MonitorEnter(pc, objRef) => + val objRefExpr = transformExpr(objRef) + + return MonitorEnter(pc, objRefExpr) + case MonitorExit(pc, objRef) => + val objRefExpr = transformExpr(objRef) + + return MonitorExit(pc, objRefExpr) + case ArrayStore(pc, arrayRef, index, value) => + val arrayRefExpr = transformExpr(arrayRef) + val indexExpr = transformExpr(index) + val valueExpr = transformExpr(value) + + return ArrayStore(pc, arrayRefExpr, indexExpr, valueExpr) + case Throw(pc, exception) => + val exceptionExpr = transformExpr(exception) + + return Throw(pc, exceptionExpr) + case PutStatic(pc, declaringClass, name, declaredFieldType, value) => + val valueExpr = transformExpr(value) + + return PutStatic(pc, declaringClass, name, declaredFieldType, valueExpr) + case PutField(pc, declaringClass, name, declaredFieldType, objRef, value) => + val objRefExpr = transformExpr(objRef) + val valueExpr = transformExpr(value) + + return PutField(pc, declaringClass, name, declaredFieldType, objRefExpr, valueExpr) + case NonVirtualMethodCall(pc, declaringClass, isInterface, name, descriptor, receiver, params) => + val receiverExpr = transformExpr(receiver) + val paramsExpr = params.map(p => transformExpr(p)) + + return NonVirtualMethodCall(pc, declaringClass, isInterface, name, descriptor, receiverExpr, paramsExpr) + case VirtualMethodCall(pc, declaringClass, isInterface, name, descriptor, receiver, params) => + val receiverExpr = transformExpr(receiver) + val paramsExpr = params.map(p => transformExpr(p)) + + return VirtualMethodCall(pc, declaringClass, isInterface, name, descriptor, receiverExpr, paramsExpr) + case StaticMethodCall(pc, declaringClass, isInterface, name, descriptor, params) => + val paramsExpr = params.map(p => transformExpr(p)) + + return StaticMethodCall(pc, declaringClass, isInterface, name, descriptor, paramsExpr) + case InvokedynamicMethodCall(pc, bootstrapMethod, name, descriptor, params) => + val paramsExpr = params.map(p => transformExpr(p)) + + return InvokedynamicMethodCall(pc, bootstrapMethod, name, descriptor, paramsExpr) + case ExprStmt(pc, expr) => + val transformedExpr = transformExpr(expr) + + return ExprStmt(pc, transformedExpr) + case CaughtException(pc, exceptionType, throwingStatements) => return CaughtException(pc, exceptionType, throwingStatements) + case Checkcast(pc, value, cmpTpe) => + val valueExpr = transformExpr(value) + // TODO Transform into assignment + return Checkcast(pc, valueExpr, cmpTpe) + case _ => throw new RuntimeException("Unknown statement: " + stmt) + } + + throw new RuntimeException("Could not transform statement: " + stmt) + } + + def isThisVar(idBasedVar: IdBasedVar): Boolean = method.isNotStatic && idBasedVar.id == -1 + + def createNewParameterLocal(idBasedVar: IdBasedVar): TacLocal = { + val local = localArray(0) + + new RegisterLocal(idBasedVar.id, idBasedVar.cTpe, local(-idBasedVar.id - 1), isThisVar(idBasedVar)) + } + + def createNewExceptionLocal(pc: PC, idBasedVar: IdBasedVar): TacLocal = { + exceptionCount += 1 + + val value = operandsArray(pc).head + new ExceptionLocal(exceptionCount, idBasedVar.cTpe, value) + } + + def transformExpr(expr: Expr[IdBasedVar]): Expr[TacLocal] = { + expr match { + case v: IdBasedVar => ??? + case InstanceOf(pc, value, cmpTpe) => + val valueExpr = transformExpr(value) + + return InstanceOf(pc, valueExpr, cmpTpe) + case Compare(pc, left, condition, right) => + val leftExpr = transformExpr(left) + val rightExpr = transformExpr(right) + + return Compare(pc, leftExpr, condition, rightExpr) + case Param(cTpe, name) => + paramCount += 1 + + return new ParameterLocal(paramCount, cTpe, name) + case MethodTypeConst(pc, value) => return MethodTypeConst(pc, value) + case MethodHandleConst(pc, value) => return MethodHandleConst(pc, value) + case IntConst(pc, value) => return IntConst(pc, value) + case LongConst(pc, value) => return LongConst(pc, value) + case FloatConst(pc, value) => return FloatConst(pc, value) + case DoubleConst(pc, value) => return DoubleConst(pc, value) + case StringConst(pc, value) => return StringConst(pc, value) + case ClassConst(pc, value) => return ClassConst(pc, value) + case DynamicConst(pc, bootstrapMethod, name, descriptor) => return DynamicConst(pc, bootstrapMethod, name, descriptor) + case NullExpr(pc) => return NullExpr(pc) + case BinaryExpr(pc, cTpe, op, left, right) => + val leftExpr = transformExpr(left) + val rightExpr = transformExpr(right) + + return BinaryExpr(pc, cTpe, op, leftExpr, rightExpr) + case PrefixExpr(pc, cTpe, op, operand) => + val operandExpr = transformExpr(operand) + + return PrefixExpr(pc, cTpe, op, operandExpr) + case PrimitiveTypecastExpr(pc, targetTpe, operand) => + val operandExpr = transformExpr(operand) + + return PrimitiveTypecastExpr(pc, targetTpe, operandExpr) + case New(pc, tpe) => return New(pc, tpe) + case NewArray(pc, counts, tpe) => + val countsExpr = counts.map(c => transformExpr(c)) + + return NewArray(pc, countsExpr, tpe) + case ArrayLoad(pc, index, arrayRef) => + val indexExpr = transformExpr(index) + val arrayRefExpr = transformExpr(arrayRef) + + return ArrayLoad(pc, indexExpr, arrayRefExpr) + case ArrayLength(pc, arrayRef) => + val arrayRefExpr = transformExpr(arrayRef) + + return ArrayLength(pc, arrayRefExpr) + case GetField(pc, declaringClass, name, declaredFieldType, objRef) => + val objRefExpr = transformExpr(objRef) + + return GetField(pc, declaringClass, name, declaredFieldType, objRefExpr) + case GetStatic(pc, declaringClass, name, declaredFieldType) => return GetStatic(pc, declaringClass, name, declaredFieldType) + case InvokedynamicFunctionCall(pc, bootstrapMethod, name, descriptor, params) => + val paramsExpr = params.map(p => transformExpr(p)) + + return InvokedynamicFunctionCall(pc, bootstrapMethod, name, descriptor, paramsExpr) + case NonVirtualFunctionCall(pc, declaringClass, isInterface, name, descriptor, receiver, params) => + val receiverExpr = transformExpr(receiver) + val paramsExpr = params.map(p => transformExpr(p)) + + return NonVirtualFunctionCall(pc, declaringClass, isInterface, name, descriptor, receiverExpr, paramsExpr) + case VirtualFunctionCall(pc, declaringClass, isInterface, name, descriptor, receiver, params) => + val receiverExpr = transformExpr(receiver) + val paramsExpr = params.map(p => transformExpr(p)) + + return VirtualFunctionCall(pc, declaringClass, isInterface, name, descriptor, receiverExpr, paramsExpr) + case StaticFunctionCall(pc, declaringClass, isInterface, name, descriptor, params) => + val paramsExpr = params.map(p => transformExpr(p)) + + return StaticFunctionCall(pc, declaringClass, isInterface, name, descriptor, paramsExpr) + case _ => throw new RuntimeException("Unknown expression: " + expr) + } + + throw new RuntimeException("Could not transform expr: " + expr) + } + + tac.stmts.map(stmt => transformStmt(stmt)) + } + +} diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala index 5f3f5ce6d..ed8797352 100644 --- a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala @@ -2,6 +2,7 @@ package boomerang.scope.opal import boomerang.scope.DataFlowScope import boomerang.scope.opal.tac.OpalMethod +import boomerang.scope.opal.transformation.TacBodyBuilder import boomerang.scope.test.MethodSignature import boomerang.scope.test.targets.{ConstructorTarget, InvokeExprTarget, SingleTarget} import com.typesafe.config.{Config, ConfigValueFactory} @@ -21,11 +22,13 @@ class OpalInvokeExprTest { val opalSetup = new OpalSetup() opalSetup.setupOpal(classOf[SingleTarget].getName) - val signature = new MethodSignature(classOf[SingleTarget].getName, "tryCatch", "V") + val signature = new MethodSignature(classOf[SingleTarget].getName, "branching", "I") val method = opalSetup.resolveMethod(signature) val opalMethod = OpalMethod(method) opalMethod.getControlFlowGraph + val test = TacBodyBuilder(OpalClient.project.get, method) + // Update the project's config to set the test method as the (single) entry point. See // https://github.com/opalj/opal/blob/ff01c1c9e696946a88b090a52881a41445cf07f1/DEVELOPING_OPAL/tools/src/main/scala/org/opalj/support/info/CallGraph.scala#L406 var config = OpalClient.project.get.config From a1cecfcc794c0473116fe9f261db1952c80b1eb4 Mon Sep 17 00:00:00 2001 From: Sven Meyer Date: Sat, 12 Apr 2025 19:02:49 +0200 Subject: [PATCH 37/61] Switch completely to new operand stack handling --- .../boomerang/scope/opal/OpalCallGraph.scala | 4 +- .../scope/opal/tac/OpalArrayRef.scala | 2 +- .../scope/opal/tac/OpalDoubleVal.scala | 2 +- .../scope/opal/tac/OpalIfStatement.scala | 2 +- .../scope/opal/tac/OpalInstanceFieldRef.scala | 2 +- .../scope/opal/tac/OpalInvokeExpr.scala | 2 +- .../boomerang/scope/opal/tac/OpalLocal.scala | 2 +- .../boomerang/scope/opal/tac/OpalMethod.scala | 4 +- .../scope/opal/tac/OpalStatement.scala | 2 +- .../boomerang/scope/opal/tac/OpalVal.scala | 2 +- .../BoomerangTACode.scala | 2 +- .../StmtGraph.scala | 2 +- .../opal/transformation/TacBodyBuilder.scala | 27 +- .../scope/opal/transformation/TacLocal.scala | 50 +-- .../transformation/stack/OperandStack.scala | 3 +- .../stack/OperandStackBuilder.scala | 23 +- .../stack/OperandStackHandler.scala | 26 +- .../transformer/InlineLocalTransformer.scala} | 12 +- .../transformer/LocalTransformer.scala | 155 +++++--- .../transformer/NopTransformer.scala | 3 +- .../NullifyFieldsTransformer.scala | 3 +- .../opal/transformer/LocalTransformer.scala | 346 ------------------ .../scope/opal/transformer/OperandStack.scala | 141 ------- .../scope/opal/transformer/TacLocal.scala | 168 --------- .../opal/transformer/TacTransformer.scala | 34 -- .../scope/opal/OpalInvokeExprTest.scala | 2 - 26 files changed, 202 insertions(+), 819 deletions(-) rename boomerangScope-Opal/src/main/scala/boomerang/scope/opal/{transformer => transformation}/BoomerangTACode.scala (90%) rename boomerangScope-Opal/src/main/scala/boomerang/scope/opal/{transformer => transformation}/StmtGraph.scala (99%) rename boomerangScope-Opal/src/main/scala/boomerang/scope/opal/{transformer/BasicPropagation.scala => transformation/transformer/InlineLocalTransformer.scala} (93%) rename boomerangScope-Opal/src/main/scala/boomerang/scope/opal/{ => transformation}/transformer/NopTransformer.scala (90%) rename boomerangScope-Opal/src/main/scala/boomerang/scope/opal/{ => transformation}/transformer/NullifyFieldsTransformer.scala (93%) delete mode 100644 boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/LocalTransformer.scala delete mode 100644 boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/OperandStack.scala delete mode 100644 boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacLocal.scala delete mode 100644 boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacTransformer.scala diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalCallGraph.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalCallGraph.scala index cd55450f9..d0103a416 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalCallGraph.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalCallGraph.scala @@ -3,7 +3,7 @@ package boomerang.scope.opal import boomerang.scope.{CallGraph, InvokeExpr} import boomerang.scope.CallGraph.Edge import boomerang.scope.opal.tac.{OpalFunctionInvokeExpr, OpalMethod, OpalMethodInvokeExpr, OpalPhantomMethod, OpalStatement} -import boomerang.scope.opal.transformer.TacTransformer +import boomerang.scope.opal.transformation.TacBodyBuilder import org.opalj.br.{DefinedMethod, Method, MultipleDefinedMethods, VirtualDeclaredMethod} import org.opalj.tac.{NonVirtualFunctionCall, StaticFunctionCall, VirtualFunctionCall} @@ -20,7 +20,7 @@ class OpalCallGraph(callGraph: org.opalj.tac.cg.CallGraph, entryPoints: Set[Meth }) private def addEdgesFromMethod(method: DefinedMethod): Unit = { - val tacCode = TacTransformer(OpalClient.project.get, method.definedMethod) + val tacCode = TacBodyBuilder(OpalClient.project.get, method.definedMethod) tacCode.statements.foreach(stmt => { val srcStatement = new OpalStatement(stmt, OpalMethod(method.definedMethod, tacCode)) diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalArrayRef.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalArrayRef.scala index a6b4d258c..30b04a3a8 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalArrayRef.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalArrayRef.scala @@ -1,7 +1,7 @@ package boomerang.scope.opal.tac import boomerang.scope._ -import boomerang.scope.opal.transformer.TacLocal +import boomerang.scope.opal.transformation.TacLocal import org.opalj.br.ObjectType import org.opalj.tac.{DUVar, DVar, Expr, IdBasedVar, UVar, Var} import org.opalj.value.ValueInformation diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalDoubleVal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalDoubleVal.scala index fcd10405f..e4bd87db4 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalDoubleVal.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalDoubleVal.scala @@ -1,6 +1,6 @@ package boomerang.scope.opal.tac -import boomerang.scope.opal.transformer.TacLocal +import boomerang.scope.opal.transformation.TacLocal import boomerang.scope.{Val, ValWithFalseVariable} import org.opalj.tac.{DUVar, Expr, IdBasedVar, Var} import org.opalj.value.ValueInformation diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalIfStatement.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalIfStatement.scala index 47d568ae2..c706e41fe 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalIfStatement.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalIfStatement.scala @@ -1,7 +1,7 @@ package boomerang.scope.opal.tac import boomerang.scope.opal.OpalClient -import boomerang.scope.opal.transformer.TacLocal +import boomerang.scope.opal.transformation.TacLocal import boomerang.scope.{IfStatement, Statement, Val} import org.opalj.tac.{DUVar, IdBasedVar, If, Var} import org.opalj.value.ValueInformation diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalInstanceFieldRef.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalInstanceFieldRef.scala index d762adda5..51056f37e 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalInstanceFieldRef.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalInstanceFieldRef.scala @@ -1,7 +1,7 @@ package boomerang.scope.opal.tac +import boomerang.scope.opal.transformation.TacLocal import boomerang.scope.{ControlFlowGraph, Method, Pair, Type, Val} -import boomerang.scope.opal.transformer.TacLocal import java.util.Objects diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalInvokeExpr.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalInvokeExpr.scala index 96fc60994..d687176a7 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalInvokeExpr.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalInvokeExpr.scala @@ -1,6 +1,6 @@ package boomerang.scope.opal.tac -import boomerang.scope.opal.transformer.TacLocal +import boomerang.scope.opal.transformation.TacLocal import boomerang.scope.{DeclaredMethod, InvokeExpr, Val} import org.opalj.tac._ diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalLocal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalLocal.scala index 455c9b2c7..3463f8170 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalLocal.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalLocal.scala @@ -1,7 +1,7 @@ package boomerang.scope.opal.tac import boomerang.scope._ -import boomerang.scope.opal.transformer.TacLocal +import boomerang.scope.opal.transformation.TacLocal import org.opalj.br.ObjectType import org.opalj.tac.Var diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalMethod.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalMethod.scala index b81ada964..907f34fbc 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalMethod.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalMethod.scala @@ -2,7 +2,7 @@ package boomerang.scope.opal.tac import boomerang.scope._ import boomerang.scope.opal.OpalClient -import boomerang.scope.opal.transformer.{BoomerangTACode, TacTransformer} +import boomerang.scope.opal.transformation.{BoomerangTACode, TacBodyBuilder} import java.util import java.util.Objects @@ -119,7 +119,7 @@ class OpalMethod private(val delegate: org.opalj.br.Method, val tac: BoomerangTA object OpalMethod { - def apply(delegate: org.opalj.br.Method): OpalMethod = new OpalMethod(delegate, TacTransformer(OpalClient.project.get, delegate)) + def apply(delegate: org.opalj.br.Method): OpalMethod = new OpalMethod(delegate, TacBodyBuilder(OpalClient.project.get, delegate)) def apply(delegate: org.opalj.br.Method, tac: BoomerangTACode): OpalMethod = new OpalMethod(delegate, tac) } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala index e0f1fa73a..de674fc50 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala @@ -1,7 +1,7 @@ package boomerang.scope.opal.tac import boomerang.scope._ -import boomerang.scope.opal.transformer.TacLocal +import boomerang.scope.opal.transformation.TacLocal import com.google.common.base.Joiner import org.opalj.tac.{DUVar, IdBasedVar, PrimitiveTypecastExpr, Stmt, Var} import org.opalj.value.ValueInformation diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalVal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalVal.scala index 5090e888e..2b1439d97 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalVal.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalVal.scala @@ -2,7 +2,7 @@ package boomerang.scope.opal.tac import boomerang.scope.opal.OpalClient import boomerang.scope._ -import boomerang.scope.opal.transformer.TacLocal +import boomerang.scope.opal.transformation.TacLocal import org.opalj.br.ReferenceType import org.opalj.tac._ diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/BoomerangTACode.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/BoomerangTACode.scala similarity index 90% rename from boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/BoomerangTACode.scala rename to boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/BoomerangTACode.scala index e455de617..00f025bbc 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/BoomerangTACode.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/BoomerangTACode.scala @@ -1,4 +1,4 @@ -package boomerang.scope.opal.transformer +package boomerang.scope.opal.transformation import org.opalj.tac.{Assignment, Stmt} diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/StmtGraph.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/StmtGraph.scala similarity index 99% rename from boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/StmtGraph.scala rename to boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/StmtGraph.scala index 8c497af2f..b32042693 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/StmtGraph.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/StmtGraph.scala @@ -1,4 +1,4 @@ -package boomerang.scope.opal.transformer +package boomerang.scope.opal.transformation import org.opalj.br.cfg.CFG import org.opalj.tac.{Return, Stmt, TACStmts} diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacBodyBuilder.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacBodyBuilder.scala index cb6001c5a..eff74b099 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacBodyBuilder.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacBodyBuilder.scala @@ -1,16 +1,37 @@ package boomerang.scope.opal.transformation import boomerang.scope.opal.transformation.stack.OperandStackBuilder -import boomerang.scope.opal.transformer.BoomerangTACode +import boomerang.scope.opal.transformation.transformer.{InlineLocalTransformer, LocalTransformer, NopTransformer, NullifyFieldsTransformer} +import org.opalj.ai.domain.l0.PrimitiveTACAIDomain import org.opalj.br.Method import org.opalj.br.analyses.Project -import org.opalj.tac.TACNaive +import org.opalj.br.cfg.CFGFactory +import org.opalj.tac.{Stmt, TACNaive, TACStmts} object TacBodyBuilder { def apply(project: Project[_], method: Method): BoomerangTACode = { val tacNaive = TACNaive(method, project.classHierarchy) val stackHandler = OperandStackBuilder(method, tacNaive) - ??? + + val domain = new PrimitiveTACAIDomain(project.classHierarchy, method) + val localTransformedTac = LocalTransformer(method, tacNaive, stackHandler, domain) + val inlinedTac = InlineLocalTransformer(localTransformedTac, stackHandler) + + // Update the CFG + val cfg = CFGFactory(method, project.classHierarchy) + if (cfg.isEmpty) { + throw new RuntimeException("Could not compute CFG for method " + method.name) + } + + val tacCfg = cfg.get.mapPCsToIndexes[Stmt[TacLocal], TACStmts[TacLocal]](TACStmts(inlinedTac), tacNaive.pcToIndex, i => i, inlinedTac.length) + + val exceptionHandlers = tacNaive.exceptionHandlers.map(eh => eh.handlerPC).toArray + val stmtGraph = StmtGraph(inlinedTac, tacCfg, tacNaive.pcToIndex, exceptionHandlers) + + val nopStmtGraph = NopTransformer(stmtGraph) + val nullifiedStmtGraph = transformer.NullifyFieldsTransformer(method, nopStmtGraph) + + new BoomerangTACode(nullifiedStmtGraph) } } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacLocal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacLocal.scala index 2c31a4f76..ab5b7f771 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacLocal.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacLocal.scala @@ -10,13 +10,15 @@ trait TacLocal extends Var[TacLocal] { def id: Int - def isStackLocal: Boolean + def isStackLocal: Boolean = false - def isRegisterLocal: Boolean + def isRegisterLocal: Boolean = false - def isParameterLocal: Boolean + def isParameterLocal: Boolean = false - def isThisLocal: Boolean + def isThisLocal: Boolean = false + + def isExceptionLocal: Boolean = false def cTpe: ComputationalType @@ -39,10 +41,6 @@ class StackLocal(identifier: Int, computationalType: ComputationalType, valueInf override def isStackLocal: Boolean = true - override def isRegisterLocal: Boolean = false - - override def isParameterLocal: Boolean = false - override def isThisLocal: Boolean = isThis override def name: String = if (isThis) "$this" else s"$$s$identifier" @@ -51,7 +49,7 @@ class StackLocal(identifier: Int, computationalType: ComputationalType, valueInf override def value: ValueInformation = valueInfo - override def hashCode: Int = Objects.hash(id, isStackLocal, isRegisterLocal, isParameterLocal) + override def hashCode: Int = Objects.hash(id) override def equals(other: Any): Boolean = other match { case that: StackLocal => this.id == that.id @@ -64,12 +62,8 @@ class RegisterLocal(identifier: Int, computationalType: ComputationalType, value override def id: Int = identifier - override def isStackLocal: Boolean = false - override def isRegisterLocal: Boolean = true - override def isParameterLocal: Boolean = false - override def isThisLocal: Boolean = isThis override def name: String = if (isThis) "this" else s"r${-identifier - 1}" @@ -78,7 +72,7 @@ class RegisterLocal(identifier: Int, computationalType: ComputationalType, value override def value: ValueInformation = valueInfo - override def hashCode: Int = Objects.hash(id, isStackLocal, isRegisterLocal, isParameterLocal) + override def hashCode: Int = Objects.hash(id) override def equals(other: Any): Boolean = other match { case that: RegisterLocal => this.id == that.id @@ -91,21 +85,15 @@ class ParameterLocal(identifier: Int, computationalType: ComputationalType, para override def id: Int = identifier - override def isStackLocal: Boolean = false - - override def isRegisterLocal: Boolean = false - override def isParameterLocal: Boolean = true - override def isThisLocal: Boolean = false - override def cTpe: ComputationalType = computationalType override def value: ValueInformation = throw new UnsupportedOperationException("No value information available for parameter local") override def name: String = paramName - override def hashCode: Int = Objects.hash(id, isStackLocal, isRegisterLocal, isParameterLocal) + override def hashCode: Int = Objects.hash(id) override def equals(other: Any): Boolean = other match { case that: ParameterLocal => this.id == that.id @@ -117,21 +105,13 @@ class NullifiedLocal(identifier: Int, computationalType: ComputationalType) exte override def id: Int = identifier - override def isStackLocal: Boolean = false - - override def isRegisterLocal: Boolean = false - - override def isParameterLocal: Boolean = false - - override def isThisLocal: Boolean = false - override def cTpe: ComputationalType = computationalType override def value: ValueInformation = IsNullValue override def name: String = s"n$identifier" - override def hashCode: Int = Objects.hash(id, isStackLocal, isRegisterLocal, isParameterLocal) + override def hashCode: Int = Objects.hash(id) override def equals(other: Any): Boolean = other match { case that: NullifiedLocal => this.id == that.id @@ -143,13 +123,7 @@ class ExceptionLocal(identifier: Int, computationalType: ComputationalType, valu override def id: Int = identifier - override def isStackLocal: Boolean = true - - override def isRegisterLocal: Boolean = false - - override def isParameterLocal: Boolean = false - - override def isThisLocal: Boolean = false + override def isExceptionLocal: Boolean = true override def cTpe: ComputationalType = computationalType @@ -164,5 +138,3 @@ class ExceptionLocal(identifier: Int, computationalType: ComputationalType, valu case _ => false } } - -// TODO Consider TempLocal in SWAP diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStack.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStack.scala index 37d9c2f6e..bfbf43692 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStack.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStack.scala @@ -4,6 +4,8 @@ import org.opalj.tac.IdBasedVar class OperandStack private(stackHandler: OperandStackHandler, private var stack: List[Operand]) { + def stackEntries: List[Operand] = stack + def push(idBasedVar: IdBasedVar): Unit = { val operand = new Operand(idBasedVar.id, stackHandler.nextLocalCounter) stack = operand :: stack @@ -46,7 +48,6 @@ class OperandStack private(stackHandler: OperandStackHandler, private var stack: def copy: OperandStack = new OperandStack(stackHandler, stack.map(identity)) override def toString: String = stack.toString() - } object OperandStack { diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackBuilder.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackBuilder.scala index 642558b7b..7660664df 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackBuilder.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackBuilder.scala @@ -12,8 +12,10 @@ object OperandStackBuilder { // Initialize work list; we always start with pc 0 var workList = List(0) - for (eh <- tacNaive.exceptionHandlers) { - workList ::= eh.handlerPC + + val exceptionHandlersPc = tacNaive.exceptionHandlers.map(eh => tacNaive.stmts(eh.handlerPC).pc) + for (eh <- exceptionHandlersPc) { + workList ::= eh } while (workList.nonEmpty) { @@ -38,12 +40,12 @@ object OperandStackBuilder { stmt match { case If(pc, left, _, right, target) => - val leftOps = processExpr(left) - leftOps.foreach(op => stack.pop(op)) - val rightOps = processExpr(right) rightOps.foreach(op => stack.pop(op)) + val leftOps = processExpr(left) + leftOps.foreach(op => stack.pop(op)) + schedule(pcOfNextStatement(pc), stack) val targetStmt = tacNaive.stmts(target) @@ -61,8 +63,11 @@ object OperandStackBuilder { // TODO branch targets schedule(defaultTarget, stack) case Assignment(pc, targetVar: IdBasedVar, expr: Expr[IdBasedVar]) => - val operands = processExpr(expr) - operands.foreach(op => stack.pop(op)) + // Exception handlers are defined implicitly, so cannot pop them from the stack + if (!exceptionHandlersPc.contains(pc)) { + val operands = processExpr(expr) + operands.foreach(op => stack.pop(op)) + } if (targetVar.id >= 0) { stack.push(targetVar) @@ -125,8 +130,8 @@ object OperandStackBuilder { schedule(pcOfNextStatement(pc), stack) case PutField(pc, _, _, _, objRef: IdBasedVar, value: IdBasedVar) => - stack.pop(objRef) stack.pop(value) + stack.pop(objRef) schedule(pcOfNextStatement(pc), stack) case NonVirtualMethodCall(pc, _, _, _, _, receiver: IdBasedVar, params: Seq[IdBasedVar]) => @@ -177,7 +182,7 @@ object OperandStackBuilder { case ClassConst(_, _) => List() case DynamicConst(_, _, _, _) => List() case NullExpr(_) => List() - case BinaryExpr(_, _, _, left: IdBasedVar, right: IdBasedVar) => List(left, right) + case BinaryExpr(_, _, _, left, right) => processExpr(left) ++ processExpr(right) case PrefixExpr(_, _, _, operand: IdBasedVar) => List(operand) case PrimitiveTypecastExpr(_, _, operand: IdBasedVar) => List(operand) case New(_, _) => List() diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackHandler.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackHandler.scala index ea05b5d25..26d6dfd44 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackHandler.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackHandler.scala @@ -8,7 +8,7 @@ class OperandStackHandler { private val pcToStack = mutable.Map.empty[PC, OperandStack] private val defSites = mutable.Map.empty[PC, Operand] - private var localCounter = 0 + private var localCounter = -1 def getOrCreate(pc: PC): OperandStack = { if (pcToStack.contains(pc)) { @@ -34,8 +34,8 @@ class OperandStackHandler { true } else { var modified = false - existingStack.stack.foreach(existingOp => { - incomingStack.stack.foreach(incomingOp => { + existingStack.stackEntries.foreach(existingOp => { + incomingStack.stackEntries.foreach(incomingOp => { if (existingOp.id == incomingOp.id && existingOp.localId != incomingOp.localId) { incomingOp.updateCounter(existingOp.localId) @@ -53,4 +53,24 @@ class OperandStackHandler { localCounter } + def defSiteAtPc(pc: PC): Int = defSites.getOrElse(pc, throw new RuntimeException(s"No operand definition at PC $pc")).localId + + def counterForOperand(pc: PC, id: Int): Int = { + val stack = pcToStack.getOrElse(pc, throw new RuntimeException(s"Stack for PC $pc not available")) + stack.stackEntries.foreach(op => if (op.id == id) return op.localId) + + throw new RuntimeException(s"Could not find operand with id $id on stack") + } + + def isBranchedOperand(pc: PC, id: Int): Boolean = { + val defSite = defSites.getOrElse(pc, throw new RuntimeException(s"No def site found at pc $pc")) + + defSite.isBranchedOperand + //val stack = pcToStack.getOrElse(pc, throw new RuntimeException(s"Stack for PC $pc not available")) + //stack.stackEntries.foreach(op => if (op.id == id) return op.isBranchedOperand) + + + //throw new RuntimeException(s"Could not find operand with id $id on stack") + } + } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/BasicPropagation.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/InlineLocalTransformer.scala similarity index 93% rename from boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/BasicPropagation.scala rename to boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/InlineLocalTransformer.scala index f6c020750..703a72daa 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/BasicPropagation.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/InlineLocalTransformer.scala @@ -1,11 +1,13 @@ -package boomerang.scope.opal.transformer +package boomerang.scope.opal.transformation.transformer +import boomerang.scope.opal.transformation.stack.OperandStackHandler +import boomerang.scope.opal.transformation.{RegisterLocal, StackLocal, TacLocal} import org.opalj.collection.immutable.IntIntPair -import org.opalj.tac.{ArrayLength, ArrayLoad, ArrayStore, Assignment, BinaryExpr, Checkcast, Compare, Expr, ExprStmt, FunctionCall, GetField, GetStatic, IdBasedVar, If, InstanceOf, InvokedynamicFunctionCall, InvokedynamicMethodCall, MonitorEnter, MonitorExit, NewArray, NonVirtualFunctionCall, NonVirtualMethodCall, Nop, PrefixExpr, PrimitiveTypecastExpr, PutField, PutStatic, ReturnValue, SimpleValueConst, StaticFunctionCall, StaticMethodCall, Stmt, Switch, TACStmts, Throw, VirtualFunctionCall, VirtualMethodCall} +import org.opalj.tac._ -object BasicPropagation { +object InlineLocalTransformer { - def apply(code: Array[Stmt[TacLocal]], operandStack: OperandStack): Array[Stmt[TacLocal]] = { + def apply(code: Array[Stmt[TacLocal]], stackHandler: OperandStackHandler): Array[Stmt[TacLocal]] = { val statements = code.map(identity) val max = code.length - 1 @@ -34,7 +36,7 @@ object BasicPropagation { statements(i) match { // If we have an assignment $s = r, we replace $s with r in all following statements case Assignment(pc, stackLocal: StackLocal, registerLocal: RegisterLocal) => - if (!operandStack.operandHasMultipleDefSites(stackLocal.id)) { + if (!stackHandler.isBranchedOperand(pc, stackLocal.id)) { Range.inclusive(i + 1, max).foreach(j => { val currStmt = statements(j) statements(j) = updateStatementWithLocal(currStmt, stackLocal, registerLocal) diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/LocalTransformer.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/LocalTransformer.scala index 43cd00ed6..e81a007a7 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/LocalTransformer.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/LocalTransformer.scala @@ -1,16 +1,19 @@ package boomerang.scope.opal.transformation.transformer -import boomerang.scope.opal.transformation.{ExceptionLocal, ParameterLocal, RegisterLocal, TacLocal} +import boomerang.scope.opal.transformation.{ExceptionLocal, ParameterLocal, RegisterLocal, StackLocal, TacLocal} import boomerang.scope.opal.transformation.stack.OperandStackHandler import org.opalj.ai.{AIResult, BaseAI, Domain} import org.opalj.br.{Method, PC} import org.opalj.tac.{ArrayLength, ArrayLoad, ArrayStore, Assignment, BinaryExpr, CaughtException, Checkcast, ClassConst, Compare, DoubleConst, DynamicConst, Expr, ExprStmt, FloatConst, GetField, GetStatic, Goto, IdBasedVar, If, InstanceOf, IntConst, InvokedynamicFunctionCall, InvokedynamicMethodCall, JSR, LongConst, MethodHandleConst, MethodTypeConst, MonitorEnter, MonitorExit, NaiveTACode, New, NewArray, NonVirtualFunctionCall, NonVirtualMethodCall, Nop, NullExpr, Param, PrefixExpr, PrimitiveTypecastExpr, PutField, PutStatic, Ret, Return, ReturnValue, StaticFunctionCall, StaticMethodCall, Stmt, StringConst, Switch, Throw, VirtualFunctionCall, VirtualMethodCall} +import scala.collection.mutable + object LocalTransformer { def apply(method: Method, tac: NaiveTACode[_], stackHandler: OperandStackHandler, domain: Domain): Array[Stmt[TacLocal]] = { var paramCount = -1 var exceptionCount = -1 + val currentLocals = mutable.Map.empty[Int, TacLocal] val exceptionHandlers = tac.exceptionHandlers.map(eh => eh.handlerPC) // Domain components @@ -21,89 +24,108 @@ object LocalTransformer { def transformStmt(stmt: Stmt[IdBasedVar]): Stmt[TacLocal] = { stmt match { case If(pc, left, condition, right, target) => - val leftExpr = transformExpr(left) - val rightExpr = transformExpr(right) + val leftExpr = transformExpr(pc, left) + val rightExpr = transformExpr(pc, right) return If(pc, leftExpr, condition, rightExpr, target) case Goto(pc, target) => return Goto(pc, target) case Ret(pc, returnAddresses) => return Ret(pc, returnAddresses) case JSR(pc, target) => return JSR(pc, target) case Switch(pc, defaultTarget, index, nPairs) => - val indexExpr = transformExpr(index) + val indexExpr = transformExpr(pc, index) return Switch(pc,defaultTarget, indexExpr, nPairs) case Assignment(pc, targetVar, expr) => // Parameter definition statements if (pc == -1) { - val paramLocal = createNewParameterLocal(targetVar) - val transformedExpr = transformExpr(expr) + val paramLocal = createParameterLocal(targetVar) + val transformedExpr = transformExpr(pc, expr) + currentLocals(paramLocal.id) = paramLocal return Assignment(pc, paramLocal, transformedExpr) } - // Definition of exception handlers - if (exceptionHandlers.contains(tac.pcToIndex(pc)) && expr.isVar) { - val exceptionLocal = createNewExceptionLocal(pc, expr.asVar) + if (targetVar.id >= 0) { + val transformedExpr = transformExpr(pc, expr) + + // Consider 'this' assignment from register to stack: s = this + val isThisAssignment = transformedExpr.isVar && transformedExpr.asVar.isThisLocal + val targetLocal = createStackLocal(pc, targetVar, isThisAssignment) + + currentLocals(targetLocal.id) = targetLocal + return Assignment(pc, targetLocal, transformedExpr) + } + + if (targetVar.id < 0) { + val transformedExpr = transformExpr(pc, expr) + + // Consider 'this' assignment from stack to register: r0 = $this + val isThisAssignment = transformedExpr.isVar && transformedExpr.asVar.isThisLocal + val targetLocal = createRegisterLocal(pc, targetVar, isThisAssignment) + + currentLocals(targetLocal.id) = targetLocal + return Assignment(pc, targetLocal, transformedExpr) } - // TODO + + throw new RuntimeException("Should never be reached") case ReturnValue(pc, expr) => - val returnExpr = transformExpr(expr) + val returnExpr = transformExpr(pc, expr) return ReturnValue(pc, returnExpr) case Return(pc) => return Return(pc) case Nop(pc) => return Nop(pc) case MonitorEnter(pc, objRef) => - val objRefExpr = transformExpr(objRef) + val objRefExpr = transformExpr(pc, objRef) return MonitorEnter(pc, objRefExpr) case MonitorExit(pc, objRef) => - val objRefExpr = transformExpr(objRef) + val objRefExpr = transformExpr(pc, objRef) return MonitorExit(pc, objRefExpr) case ArrayStore(pc, arrayRef, index, value) => - val arrayRefExpr = transformExpr(arrayRef) - val indexExpr = transformExpr(index) - val valueExpr = transformExpr(value) + val arrayRefExpr = transformExpr(pc, arrayRef) + val indexExpr = transformExpr(pc, index) + val valueExpr = transformExpr(pc, value) return ArrayStore(pc, arrayRefExpr, indexExpr, valueExpr) case Throw(pc, exception) => - val exceptionExpr = transformExpr(exception) + val exceptionExpr = transformExpr(pc, exception) return Throw(pc, exceptionExpr) case PutStatic(pc, declaringClass, name, declaredFieldType, value) => - val valueExpr = transformExpr(value) + val valueExpr = transformExpr(pc, value) return PutStatic(pc, declaringClass, name, declaredFieldType, valueExpr) case PutField(pc, declaringClass, name, declaredFieldType, objRef, value) => - val objRefExpr = transformExpr(objRef) - val valueExpr = transformExpr(value) + val objRefExpr = transformExpr(pc, objRef) + val valueExpr = transformExpr(pc, value) return PutField(pc, declaringClass, name, declaredFieldType, objRefExpr, valueExpr) case NonVirtualMethodCall(pc, declaringClass, isInterface, name, descriptor, receiver, params) => - val receiverExpr = transformExpr(receiver) - val paramsExpr = params.map(p => transformExpr(p)) + val receiverExpr = transformExpr(pc, receiver) + val paramsExpr = params.map(p => transformExpr(pc, p)) return NonVirtualMethodCall(pc, declaringClass, isInterface, name, descriptor, receiverExpr, paramsExpr) case VirtualMethodCall(pc, declaringClass, isInterface, name, descriptor, receiver, params) => - val receiverExpr = transformExpr(receiver) - val paramsExpr = params.map(p => transformExpr(p)) + val receiverExpr = transformExpr(pc, receiver) + val paramsExpr = params.map(p => transformExpr(pc, p)) return VirtualMethodCall(pc, declaringClass, isInterface, name, descriptor, receiverExpr, paramsExpr) case StaticMethodCall(pc, declaringClass, isInterface, name, descriptor, params) => - val paramsExpr = params.map(p => transformExpr(p)) + val paramsExpr = params.map(p => transformExpr(pc, p)) return StaticMethodCall(pc, declaringClass, isInterface, name, descriptor, paramsExpr) case InvokedynamicMethodCall(pc, bootstrapMethod, name, descriptor, params) => - val paramsExpr = params.map(p => transformExpr(p)) + val paramsExpr = params.map(p => transformExpr(pc, p)) return InvokedynamicMethodCall(pc, bootstrapMethod, name, descriptor, paramsExpr) case ExprStmt(pc, expr) => - val transformedExpr = transformExpr(expr) + val transformedExpr = transformExpr(pc, expr) return ExprStmt(pc, transformedExpr) case CaughtException(pc, exceptionType, throwingStatements) => return CaughtException(pc, exceptionType, throwingStatements) case Checkcast(pc, value, cmpTpe) => - val valueExpr = transformExpr(value) + val valueExpr = transformExpr(pc, value) // TODO Transform into assignment return Checkcast(pc, valueExpr, cmpTpe) case _ => throw new RuntimeException("Unknown statement: " + stmt) @@ -114,29 +136,58 @@ object LocalTransformer { def isThisVar(idBasedVar: IdBasedVar): Boolean = method.isNotStatic && idBasedVar.id == -1 - def createNewParameterLocal(idBasedVar: IdBasedVar): TacLocal = { + def createParameterLocal(idBasedVar: IdBasedVar): TacLocal = { val local = localArray(0) new RegisterLocal(idBasedVar.id, idBasedVar.cTpe, local(-idBasedVar.id - 1), isThisVar(idBasedVar)) } - def createNewExceptionLocal(pc: PC, idBasedVar: IdBasedVar): TacLocal = { - exceptionCount += 1 + def createStackLocal(pc: PC, idBasedVar: IdBasedVar, isThis: Boolean): TacLocal = { + val nextPc = method.body.get.pcOfNextInstruction(pc) + val value = operandsArray(nextPc).head + + val counter = stackHandler.defSiteAtPc(pc) + new StackLocal(counter, idBasedVar.cTpe, value, isThis) + } + + def createRegisterLocal(pc: PC, idBasedVar: IdBasedVar, isThis: Boolean): TacLocal = { + val nextPc = method.body.get.pcOfNextInstruction(pc) + val local = localArray(nextPc) + + new RegisterLocal(idBasedVar.id, idBasedVar.cTpe, local(-idBasedVar.id - 1), isThis) + } + def createExceptionLocal(pc: PC, idBasedVar: IdBasedVar, localId: Int): TacLocal = { val value = operandsArray(pc).head - new ExceptionLocal(exceptionCount, idBasedVar.cTpe, value) + + new ExceptionLocal(localId, idBasedVar.cTpe, value) } - def transformExpr(expr: Expr[IdBasedVar]): Expr[TacLocal] = { + def transformExpr(pc: PC, expr: Expr[IdBasedVar]): Expr[TacLocal] = { expr match { - case v: IdBasedVar => ??? + case v: IdBasedVar => + // Exception locals are implicitly defined and denoted with s0. They are + // not pushed on the operand stack, so we have to define it explicitly + if (exceptionHandlers.contains(tac.pcToIndex(pc))) { + exceptionCount += 1 + + return createExceptionLocal(pc, v, exceptionCount) + } + + if (v.id >= 0) { + val counter = stackHandler.counterForOperand(pc, v.id) + + return currentLocals(counter) + } + + return currentLocals(v.id) case InstanceOf(pc, value, cmpTpe) => - val valueExpr = transformExpr(value) + val valueExpr = transformExpr(pc, value) return InstanceOf(pc, valueExpr, cmpTpe) case Compare(pc, left, condition, right) => - val leftExpr = transformExpr(left) - val rightExpr = transformExpr(right) + val leftExpr = transformExpr(pc, left) + val rightExpr = transformExpr(pc, right) return Compare(pc, leftExpr, condition, rightExpr) case Param(cTpe, name) => @@ -154,53 +205,53 @@ object LocalTransformer { case DynamicConst(pc, bootstrapMethod, name, descriptor) => return DynamicConst(pc, bootstrapMethod, name, descriptor) case NullExpr(pc) => return NullExpr(pc) case BinaryExpr(pc, cTpe, op, left, right) => - val leftExpr = transformExpr(left) - val rightExpr = transformExpr(right) + val leftExpr = transformExpr(pc, left) + val rightExpr = transformExpr(pc, right) return BinaryExpr(pc, cTpe, op, leftExpr, rightExpr) case PrefixExpr(pc, cTpe, op, operand) => - val operandExpr = transformExpr(operand) + val operandExpr = transformExpr(pc, operand) return PrefixExpr(pc, cTpe, op, operandExpr) case PrimitiveTypecastExpr(pc, targetTpe, operand) => - val operandExpr = transformExpr(operand) + val operandExpr = transformExpr(pc, operand) return PrimitiveTypecastExpr(pc, targetTpe, operandExpr) case New(pc, tpe) => return New(pc, tpe) case NewArray(pc, counts, tpe) => - val countsExpr = counts.map(c => transformExpr(c)) + val countsExpr = counts.map(c => transformExpr(pc, c)) return NewArray(pc, countsExpr, tpe) case ArrayLoad(pc, index, arrayRef) => - val indexExpr = transformExpr(index) - val arrayRefExpr = transformExpr(arrayRef) + val indexExpr = transformExpr(pc, index) + val arrayRefExpr = transformExpr(pc, arrayRef) return ArrayLoad(pc, indexExpr, arrayRefExpr) case ArrayLength(pc, arrayRef) => - val arrayRefExpr = transformExpr(arrayRef) + val arrayRefExpr = transformExpr(pc, arrayRef) return ArrayLength(pc, arrayRefExpr) case GetField(pc, declaringClass, name, declaredFieldType, objRef) => - val objRefExpr = transformExpr(objRef) + val objRefExpr = transformExpr(pc, objRef) return GetField(pc, declaringClass, name, declaredFieldType, objRefExpr) case GetStatic(pc, declaringClass, name, declaredFieldType) => return GetStatic(pc, declaringClass, name, declaredFieldType) case InvokedynamicFunctionCall(pc, bootstrapMethod, name, descriptor, params) => - val paramsExpr = params.map(p => transformExpr(p)) + val paramsExpr = params.map(p => transformExpr(pc, p)) return InvokedynamicFunctionCall(pc, bootstrapMethod, name, descriptor, paramsExpr) case NonVirtualFunctionCall(pc, declaringClass, isInterface, name, descriptor, receiver, params) => - val receiverExpr = transformExpr(receiver) - val paramsExpr = params.map(p => transformExpr(p)) + val receiverExpr = transformExpr(pc, receiver) + val paramsExpr = params.map(p => transformExpr(pc, p)) return NonVirtualFunctionCall(pc, declaringClass, isInterface, name, descriptor, receiverExpr, paramsExpr) case VirtualFunctionCall(pc, declaringClass, isInterface, name, descriptor, receiver, params) => - val receiverExpr = transformExpr(receiver) - val paramsExpr = params.map(p => transformExpr(p)) + val receiverExpr = transformExpr(pc, receiver) + val paramsExpr = params.map(p => transformExpr(pc, p)) return VirtualFunctionCall(pc, declaringClass, isInterface, name, descriptor, receiverExpr, paramsExpr) case StaticFunctionCall(pc, declaringClass, isInterface, name, descriptor, params) => - val paramsExpr = params.map(p => transformExpr(p)) + val paramsExpr = params.map(p => transformExpr(pc, p)) return StaticFunctionCall(pc, declaringClass, isInterface, name, descriptor, paramsExpr) case _ => throw new RuntimeException("Unknown expression: " + expr) diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/NopTransformer.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/NopTransformer.scala similarity index 90% rename from boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/NopTransformer.scala rename to boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/NopTransformer.scala index 03b1c7e8d..1984e42ca 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/NopTransformer.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/NopTransformer.scala @@ -1,5 +1,6 @@ -package boomerang.scope.opal.transformer +package boomerang.scope.opal.transformation.transformer +import boomerang.scope.opal.transformation.StmtGraph import org.opalj.tac.{If, Nop} object NopTransformer { diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/NullifyFieldsTransformer.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/NullifyFieldsTransformer.scala similarity index 93% rename from boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/NullifyFieldsTransformer.scala rename to boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/NullifyFieldsTransformer.scala index 0f3f5e3d0..a3663908e 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/NullifyFieldsTransformer.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/NullifyFieldsTransformer.scala @@ -1,5 +1,6 @@ -package boomerang.scope.opal.transformer +package boomerang.scope.opal.transformation.transformer +import boomerang.scope.opal.transformation.{NullifiedLocal, StmtGraph, TacLocal} import org.opalj.br.{ComputationalTypeReference, Field, FieldType, Method} import org.opalj.tac.{Assignment, Expr, NullExpr, PutField} diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/LocalTransformer.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/LocalTransformer.scala deleted file mode 100644 index 7407275c2..000000000 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/LocalTransformer.scala +++ /dev/null @@ -1,346 +0,0 @@ -package boomerang.scope.opal.transformer - -import org.opalj.ai.{AIResult, BaseAI, Domain} -import org.opalj.br.Method -import org.opalj.collection.immutable.IntIntPair -import org.opalj.tac.{ArrayLength, ArrayLoad, ArrayStore, Assignment, BinaryExpr, CaughtException, Checkcast, ClassConst, Compare, DoubleConst, DynamicConst, Expr, ExprStmt, FloatConst, GetField, GetStatic, Goto, IdBasedVar, If, InstanceOf, IntConst, InvokedynamicFunctionCall, InvokedynamicMethodCall, JSR, LongConst, MethodHandleConst, MethodTypeConst, MonitorEnter, MonitorExit, NaiveTACode, New, NewArray, NonVirtualFunctionCall, NonVirtualMethodCall, Nop, NullExpr, Param, PrefixExpr, PrimitiveTypecastExpr, PutField, PutStatic, Ret, Return, ReturnValue, StaticFunctionCall, StaticMethodCall, Stmt, StringConst, Switch, Throw, VirtualFunctionCall, VirtualMethodCall} - -import scala.collection.mutable - -object LocalTransformer { - - def apply(method: Method, tacNaive: NaiveTACode[_], domain: Domain, operandStack: OperandStack): Array[Stmt[TacLocal]] = { - var paramCounter = -1 - val currentLocals = mutable.Map.empty[Int, TacLocal] - val exceptionHandlers = tacNaive.exceptionHandlers.map(eh => eh.handlerPC) - - // Domain components - val aiResult: AIResult = BaseAI(method, domain) - val operandsArray: aiResult.domain.OperandsArray = aiResult.operandsArray - val localArray: aiResult.domain.LocalsArray = aiResult.localsArray - - def transformStatement(stmt: Stmt[IdBasedVar]): Stmt[TacLocal] = { - stmt.astID match { - case If.ASTID => - val ifStmt = stmt.asIf - - val left = transformExpr(stmt.pc, ifStmt.left) - val right = transformExpr(stmt.pc, ifStmt.right) - - return If(ifStmt.pc, left, ifStmt.condition, right, ifStmt.targetStmt) - case Goto.ASTID => - return stmt.asGoto - case Ret.ASTID => - return stmt.asRet - case JSR.ASTID => - return stmt.asJSR - case Switch.ASTID => - val switchStmt = stmt.asSwitch - val index = transformExpr(stmt.pc, switchStmt.index) - - // Inserting -1 as it is only used in previous remapping steps - return Switch(switchStmt.pc, switchStmt.defaultStmt, index, switchStmt.caseStmts.map(p => IntIntPair(-1, p))) - case Assignment.ASTID => - val assignStmt = stmt.asAssignment - val targetVar = assignStmt.targetVar - - if (assignStmt.pc == -1) { - val paramLocal = createNewParameterLocal(targetVar) - val transformedExpr = transformExpr(stmt.pc, assignStmt.expr) - - currentLocals(paramLocal.id) = paramLocal - return new Assignment[TacLocal](stmt.pc, paramLocal, transformedExpr) - } - - if (exceptionHandlers.contains(tacNaive.pcToIndex(stmt.pc)) && stmt.asAssignment.expr.isVar) { - val exceptionLocal = createNewExceptionLocal(stmt.pc, stmt.asAssignment.expr.asVar) - val targetLocal = if (targetVar.id >= 0) createNewStackLocal(stmt.pc, targetVar, exceptionLocal.isThisLocal) else createNewRegisterLocal(stmt.pc, targetVar, exceptionLocal.isThisLocal) - - currentLocals(exceptionLocal.id) = exceptionLocal - currentLocals(targetLocal.id) = targetLocal - return new Assignment[TacLocal](stmt.pc, targetLocal, exceptionLocal) - } - - if (targetVar.id >= 0) { - val transformedExpr = transformExpr(stmt.pc, assignStmt.expr) - - val isThisAssignment = transformedExpr.isVar && transformedExpr.asVar.isThisLocal - val targetLocal = createNewStackLocal(stmt.pc, targetVar, isThisAssignment) - - currentLocals(targetLocal.id) = targetLocal - return new Assignment[TacLocal](stmt.pc, targetLocal, transformedExpr) - } - - if (targetVar.id < 0) { - val transformedExpr = transformExpr(stmt.pc, assignStmt.expr) - - val isThisAssignment = transformedExpr.isVar && transformedExpr.asVar.isThisLocal - val targetLocal = createNewRegisterLocal(stmt.pc, targetVar, isThisAssignment) - - currentLocals(targetLocal.id) = targetLocal - return new Assignment[TacLocal](stmt.pc, targetLocal, transformedExpr) - } - - throw new RuntimeException("Could not transform assignment: " + assignStmt) - - /*val transformedExpr = if (exceptionHandlers.contains(tacNaive.pcToIndex(stmt.pc)) && stmt.asAssignment.expr.isVar) { - val exceptionVar = createNewLocal(stmt.pc, stmt.asAssignment.expr.asVar) - currentLocals(exceptionVar.id) = exceptionVar - - exceptionVar - } else { - transformExpr(stmt.pc, stmt.asAssignment.expr) - } - val isThisAssignment = transformedExpr.isVar && transformedExpr.asVar.isThisLocal - - val target = createNewLocal(stmt.pc, stmt.asAssignment.targetVar, isThisAssignment) - - // Store the current stack and register locals on our own 'stack' - currentLocals(target.id) = target - - return new Assignment(stmt.pc, target, transformedExpr)*/ - case ReturnValue.ASTID => - val returnStmt = stmt.asReturnValue - val returnValue = transformExpr(stmt.pc, returnStmt.expr) - - return ReturnValue(returnStmt.pc, returnValue) - case Return.ASTID => - return stmt.asReturn - case Nop.ASTID => - return stmt.asNop - case MonitorEnter.ASTID => - val monitorEnter = stmt.asMonitorEnter - val objRef = transformExpr(stmt.pc, monitorEnter.objRef) - - return MonitorEnter(monitorEnter.pc, objRef) - case MonitorExit.ASTID => - val monitorExit = stmt.asMonitorExit - val objRef = transformExpr(stmt.pc, monitorExit.objRef) - - return MonitorExit(monitorExit.pc, objRef) - case ArrayStore.ASTID => - val arrayStore = stmt.asArrayStore - - val arrayRef = transformExpr(stmt.pc, arrayStore.arrayRef) - val index = transformExpr(stmt.pc, arrayStore.index) - val value = transformExpr(stmt.pc, arrayStore.value) - - return ArrayStore(arrayStore.pc, arrayRef, index, value) - case Throw.ASTID => - val throwStmt = stmt.asThrow - val exception = transformExpr(stmt.pc, throwStmt.exception) - - return Throw(throwStmt.pc, exception) - case PutStatic.ASTID => - val putStatic = stmt.asPutStatic - val value = transformExpr(stmt.pc, putStatic.value) - - return PutStatic(putStatic.pc, putStatic.declaringClass, putStatic.name, putStatic.declaredFieldType, value) - case PutField.ASTID => - val putField = stmt.asPutField - - val objRef = transformExpr(stmt.pc, putField.objRef) - val value = transformExpr(stmt.pc, putField.value) - - return PutField(putField.pc, putField.declaringClass, putField.name, putField.declaredFieldType, objRef, value) - case NonVirtualMethodCall.ASTID => - val methodCall = stmt.asNonVirtualMethodCall - - val baseLocal = transformExpr(stmt.pc, methodCall.receiver) - val paramLocals = methodCall.params.map(p => transformExpr(stmt.pc, p)) - - return NonVirtualMethodCall(methodCall.pc, methodCall.declaringClass, methodCall.isInterface, methodCall.name, methodCall.descriptor, baseLocal, paramLocals) - case VirtualMethodCall.ASTID => - val methodCall = stmt.asVirtualMethodCall - - val baseLocal = transformExpr(stmt.pc, methodCall.receiver) - val paramLocals = methodCall.params.map(p => transformExpr(stmt.pc, p)) - - return VirtualMethodCall(methodCall.pc, methodCall.declaringClass, methodCall.isInterface, methodCall.name, methodCall.descriptor, baseLocal, paramLocals) - case StaticMethodCall.ASTID => - val methodCall = stmt.asStaticMethodCall - val params = methodCall.params.map(p => transformExpr(stmt.pc, p)) - - return StaticMethodCall(methodCall.pc, methodCall.declaringClass, methodCall.isInterface, methodCall.name, methodCall.descriptor, params) - case InvokedynamicMethodCall.ASTID => - val methodCall = stmt.asInvokedynamicMethodCall - val params = methodCall.params.map(p => transformExpr(stmt.pc, p)) - - return InvokedynamicMethodCall(methodCall.pc, methodCall.bootstrapMethod, methodCall.name, methodCall.descriptor, params) - case ExprStmt.ASTID => - val expr = transformExpr(stmt.pc, stmt.asExprStmt.expr) - - return ExprStmt(stmt.pc, expr) - case CaughtException.ASTID => - val caughtException = stmt.asCaughtException - - return CaughtException(caughtException.pc, caughtException.exceptionType, caughtException.origins) - case Checkcast.ASTID => - val castExpr = stmt.asCheckcast - val value = transformExpr(stmt.pc, castExpr.value) - - return Checkcast(castExpr.pc, value, castExpr.cmpTpe) - case _ => throw new RuntimeException("Unknown statement: " + stmt) - } - - throw new RuntimeException("Could not transform statement: " + stmt) - } - - def createNewParameterLocal(idBasedVar: IdBasedVar): TacLocal = { - val local = localArray(0) - val isThisDef = method.isNotStatic && idBasedVar.id == -1 - - new RegisterLocal(idBasedVar.id, idBasedVar.cTpe, local(-idBasedVar.id - 1), isThisDef) - } - - def createNewStackLocal(pc: Int, idBasedVar: IdBasedVar, isThis: Boolean): TacLocal = { - val nextPc = tacNaive.stmts(tacNaive.pcToIndex(pc) + 1).pc - val index = tacNaive.pcToIndex(pc) - val counter = operandStack.operandDefSite(index) - - val value = operandsArray(nextPc).head - new StackLocal(counter, idBasedVar.cTpe, value, isThis) - } - - def createNewRegisterLocal(pc: Int, idBasedVar: IdBasedVar, isThis: Boolean): TacLocal = { - val nextPc = tacNaive.stmts(tacNaive.pcToIndex(pc) + 1).pc - - val local = localArray(nextPc) - new RegisterLocal(idBasedVar.id, idBasedVar.cTpe, local(-idBasedVar.id - 1), isThis) - } - - def createNewExceptionLocal(pc: Int, idBasedVar: IdBasedVar): TacLocal = { - val index = tacNaive.pcToIndex(pc) - val counter = operandStack.operandDefSite(index) - - val value = operandsArray(pc).head - new ExceptionLocal(counter, idBasedVar.cTpe, value) - } - - def transformExpr(pc: Int, expr: Expr[IdBasedVar]): Expr[TacLocal] = { - if (expr.isVar) { - if (expr.asVar.id >= 0) { - val index = tacNaive.pcToIndex(pc) - val count = operandStack.operandCounterAtStmt(index, expr.asVar.id) - - return currentLocals(count) - } - - return currentLocals(expr.asVar.id) - } - - expr.astID match { - case InstanceOf.ASTID => - val instanceOf = expr.asInstanceOf - val value = transformExpr(pc, instanceOf.value) - - return InstanceOf(instanceOf.pc, value, instanceOf.cmpTpe) - case Compare.ASTID => - val compareExpr = expr.asCompare - - val leftLocal = transformExpr(pc, compareExpr.left) - val rightLocal = transformExpr(pc, compareExpr.right) - - return Compare(compareExpr.pc, leftLocal, compareExpr.condition, rightLocal) - case Param.ASTID => - paramCounter += 1 - - return new ParameterLocal(paramCounter, expr.asParam.cTpe, expr.asParam.name) - case MethodTypeConst.ASTID => - return expr.asMethodTypeConst - case MethodHandleConst.ASTID => - return expr.asMethodHandleConst - case IntConst.ASTID => - return expr.asIntConst - case LongConst.ASTID => - return expr.asLongConst - case FloatConst.ASTID => - return expr.asFloatConst - case DoubleConst.ASTID => - return expr.asDoubleConst - case StringConst.ASTID => - return expr.asStringConst - case ClassConst.ASTID => - return expr.asClassConst - case DynamicConst.ASTID => - return expr.asDynamicConst - case NullExpr.ASTID => - return expr.asNullExpr - case BinaryExpr.ASTID => - val binaryExpr = expr.asBinaryExpr - - val left = transformExpr(pc, binaryExpr.left) - val right = transformExpr(pc, binaryExpr.right) - - return BinaryExpr(binaryExpr.pc, binaryExpr.cTpe, binaryExpr.op, left, right) - case PrefixExpr.ASTID => - val prefixExpr = expr.asPrefixExpr - val operand = transformExpr(pc, prefixExpr.operand) - - return PrefixExpr(prefixExpr.pc, prefixExpr.cTpe, prefixExpr.op, operand) - case PrimitiveTypecastExpr.ASTID => - val primitiveTypecastExpr = expr.asPrimitiveTypeCastExpr - val operand = transformExpr(pc, primitiveTypecastExpr.operand) - - return PrimitiveTypecastExpr(primitiveTypecastExpr.pc, primitiveTypecastExpr.targetTpe, operand) - case New.ASTID => - return expr.asNew - case NewArray.ASTID => - val newArray = expr.asNewArray - val counts = newArray.counts.map(c => transformExpr(pc, c)) - - return NewArray(newArray.pc, counts, newArray.tpe) - case ArrayLoad.ASTID => - val arrayLoad = expr.asArrayLoad - - val index = transformExpr(pc, arrayLoad.index) - val arrayRef = transformExpr(pc, arrayLoad.arrayRef) - - return ArrayLoad(arrayLoad.pc, index, arrayRef) - case ArrayLength.ASTID => - val arrayLength = expr.asArrayLength - val arrayRef = transformExpr(pc, arrayLength.arrayRef) - - return ArrayLength(arrayLength.pc, arrayRef) - case GetField.ASTID => - val getField = expr.asGetField - val objRef = transformExpr(pc, getField.objRef) - - return GetField(getField.pc, getField.declaringClass, getField.name, getField.declaredFieldType, objRef) - case GetStatic.ASTID => - return expr.asGetStatic - case InvokedynamicFunctionCall.ASTID => - val functionCall = expr.asInvokedynamicFunctionCall - val params = functionCall.params.map(p => transformExpr(pc, p)) - - return InvokedynamicFunctionCall(functionCall.pc, functionCall.bootstrapMethod, functionCall.name, functionCall.descriptor, params) - case NonVirtualFunctionCall.ASTID => - val functionCall = expr.asNonVirtualFunctionCall - - val base = transformExpr(pc, functionCall.receiver) - val params = functionCall.params.map(p => transformExpr(pc, p)) - - return NonVirtualFunctionCall(functionCall.pc, functionCall.declaringClass, functionCall.isInterface, functionCall.name, functionCall.descriptor, base, params) - case VirtualFunctionCall.ASTID => - val functionCall = expr.asVirtualFunctionCall - - val base = transformExpr(pc, functionCall.receiver) - val params = functionCall.params.map(p => transformExpr(pc, p)) - - return VirtualFunctionCall(functionCall.pc, functionCall.declaringClass, functionCall.isInterface, functionCall.name, functionCall.descriptor, base, params) - case StaticFunctionCall.ASTID => - val functionCall = expr.asStaticFunctionCall - - val params = functionCall.params - val paramLocals = params.map(p => transformExpr(pc, p)) - - return StaticFunctionCall(functionCall.pc, functionCall.declaringClass, functionCall.isInterface, functionCall.name, functionCall.descriptor, paramLocals) - case _ => throw new RuntimeException("Unknown expression: " + expr) - } - - throw new RuntimeException("Could not transform expression: " + expr) - } - - tacNaive.stmts.map(stmt => transformStatement(stmt)) - } -} diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/OperandStack.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/OperandStack.scala deleted file mode 100644 index 0e1096228..000000000 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/OperandStack.scala +++ /dev/null @@ -1,141 +0,0 @@ -package boomerang.scope.opal.transformer - -import org.opalj.br.cfg.CFG -import org.opalj.tac.{Assignment, IdBasedVar, NaiveTACode, Stmt, TACStmts} - -import scala.collection.mutable - -class OperandStack(tac: Array[Stmt[IdBasedVar]], startIndex: Int, exceptionHandlers: List[Int]) { - - private val stmtStacks = new Array[mutable.Map[Int, (Int, List[Int], List[Int])]](tac.length) - private val operandDefSites = Array.fill(tac.length)(-1) - stmtStacks(startIndex) = mutable.Map.empty - exceptionHandlers.foreach(i => stmtStacks(i) = mutable.Map.empty) - - def push(currIndex: Int, nextIndex: Int, operand: IdBasedVar, stackCounter: Int): Unit = { - val currStack = stmtStacks(currIndex).map(identity) - - // Update all entries with current statement index - val nextStack = currStack.map { case (k, (id, defSite, scope)) => k -> (id, defSite, scope :+ nextIndex) } - nextStack.put(operand.id, (stackCounter, List(currIndex), List(nextIndex))) - - operandDefSites(currIndex) = stackCounter - - val existingStack = stmtStacks(nextIndex) - if (existingStack != null) { - mergeStacks(nextIndex, existingStack.toMap, nextStack.toMap) - } else { - stmtStacks(nextIndex) = nextStack - } - } - - def update(currIndex: Int, nextIndex: Int): Unit = { - val currStack = stmtStacks(currIndex).map(identity) - val existingStack = stmtStacks(nextIndex) - - if (existingStack != null) { - mergeStacks(nextIndex, existingStack.toMap, currStack.toMap) - } else { - // Update with next index - val nextStack = currStack.map { - case (k, (id, defSite, scope)) => k -> (id, defSite, scope :+ nextIndex) - } - stmtStacks(nextIndex) = nextStack - } - } - - private def mergeStacks(currIndex: Int, existingStack: Map[Int, (Int, List[Int], List[Int])], incomingStack: Map[Int, (Int, List[Int], List[Int])]): Unit = { - existingStack.foreach { - case (id, (currStackCounter, existingDefSites, existingScope)) => - incomingStack.foreach { - case (`id`, (incomingStackCounter, incomingDefSites, incomingScope)) => - if (currStackCounter != incomingStackCounter) { - incomingScope.foreach(s => { - val currStack = stmtStacks(s) - - // Update the stack counter s.t. the operands describe the same stack local - currStack.put(id, (currStackCounter, incomingDefSites, currStack(id)._3)) - incomingDefSites.foreach(d => operandDefSites(d) = currStackCounter) - }) - } - - // Update the def sites and scopes for the merge statement - val currStack = stmtStacks(currIndex) - val mergedDefSites = (existingDefSites ++ incomingDefSites).distinct - val mergedScopes = (existingScope ++ incomingScope).distinct - currStack.put(id, (currStackCounter, mergedDefSites, mergedScopes)) - - case _ => - } - } - } - - def operandDefSite(stmtIndex: Int): Int = operandDefSites(stmtIndex) - - def operandCounterAtStmt(stmtIndex: Int, operandId: Int): Int = stmtStacks(stmtIndex).getOrElse(operandId, throw new RuntimeException("Could not find operand on stack with id " + operandId))._1 - - def operandHasMultipleDefSites(stackLocalId: Int): Boolean = { - stmtStacks.filter(m => m != null).foreach(m => { - m.foreach { - case (_, (`stackLocalId`, defSites, _)) => if (defSites.size > 1) return true - case _ => - } - }) - - false - } -} - -object OperandStack { - - def apply(code: NaiveTACode[_]): OperandStack = { - val tac = code.stmts - val cfg = code.cfg - val exceptionHandlers = code.exceptionHandlers.map(eh => eh.handlerPC).toList - - val firstNonNegativeIndex = tac.indexWhere(stmt => stmt.pc >= 0) - val stack = new OperandStack(tac, firstNonNegativeIndex, exceptionHandlers) - var stackCounter = 0 - - var workList: List[Int] = firstNonNegativeIndex :: exceptionHandlers - while (workList.nonEmpty) { - val currIndex = workList.head - val currStmt = tac(currIndex) - workList = workList.tail - - if (currStmt.pc == -1) { - schedule(currIndex + 1) - } else { - // Reversing is not needed; however, this way, the stack locals are enumerated in ascending order - val nextIndices = cfg.successors(currIndex).toList.reverse - nextIndices.foreach(nextIndex => { - if (currIndex < nextIndex && !exceptionHandlers.contains(nextIndex)) { - if (isOperandPushStmt(currStmt)) { - val targetVar = currStmt.asAssignment.targetVar - - stack.push(currIndex, nextIndex, targetVar, stackCounter) - stackCounter += 1 - } else if (isExceptionLoadStmt(currStmt)) { - val exceptionVar = currStmt.asAssignment.expr.asVar - - stack.push(currIndex, nextIndex, exceptionVar, stackCounter) - stackCounter += 1 - } else { - stack.update(currIndex, nextIndex) - } - - schedule(nextIndex) - } - }) - } - - def schedule(nextIndex: Int): Unit = workList ::= nextIndex - - def isOperandPushStmt(stmt: Stmt[IdBasedVar]): Boolean = stmt.astID == Assignment.ASTID && stmt.asAssignment.targetVar.id >= 0 - - def isExceptionLoadStmt(stmt: Stmt[IdBasedVar]): Boolean = stmt.astID == Assignment.ASTID && stmt.asAssignment.expr.isVar && exceptionHandlers.contains(code.pcToIndex(stmt.pc)) - } - - stack - } -} diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacLocal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacLocal.scala deleted file mode 100644 index be95d4dce..000000000 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacLocal.scala +++ /dev/null @@ -1,168 +0,0 @@ -package boomerang.scope.opal.transformer - -import org.opalj.br.ComputationalType -import org.opalj.tac.{DUVar, Var} -import org.opalj.value.{IsNullValue, ValueInformation} - -import java.util.Objects - -trait TacLocal extends Var[TacLocal] { - - def id: Int - - def isStackLocal: Boolean - - def isRegisterLocal: Boolean - - def isParameterLocal: Boolean - - def isThisLocal: Boolean - - def cTpe: ComputationalType - - def value: ValueInformation - - final def isSideEffectFree: Boolean = true - - override def toCanonicalForm(implicit ev: TacLocal <:< DUVar[ValueInformation]): Nothing = { - throw new IncompatibleClassChangeError( - "TacLocal objects are not expected to inherit from DUVar" - ) - } - - override def toString: String = name -} - -class StackLocal(identifier: Int, computationalType: ComputationalType, valueInfo: ValueInformation, isThis: Boolean = false) extends TacLocal { - - override def id: Int = identifier - - override def isStackLocal: Boolean = true - - override def isRegisterLocal: Boolean = false - - override def isParameterLocal: Boolean = false - - override def isThisLocal: Boolean = isThis - - override def name: String = if (isThis) "$this" else s"$$s$identifier" - - override def cTpe: ComputationalType = computationalType - - override def value: ValueInformation = valueInfo - - override def hashCode: Int = Objects.hash(id, isStackLocal, isRegisterLocal, isParameterLocal) - - override def equals(other: Any): Boolean = other match { - case that: StackLocal => this.id == that.id - case that: RegisterLocal => this.isThisLocal && that.isThisLocal - case _ => false - } -} - -class RegisterLocal(identifier: Int, computationalType: ComputationalType, valueInfo: ValueInformation, isThis: Boolean = false) extends TacLocal { - - override def id: Int = identifier - - override def isStackLocal: Boolean = false - - override def isRegisterLocal: Boolean = true - - override def isParameterLocal: Boolean = false - - override def isThisLocal: Boolean = isThis - - override def name: String = if (isThis) "this" else s"r${-identifier - 1}" - - override def cTpe: ComputationalType = computationalType - - override def value: ValueInformation = valueInfo - - override def hashCode: Int = Objects.hash(id, isStackLocal, isRegisterLocal, isParameterLocal) - - override def equals(other: Any): Boolean = other match { - case that: RegisterLocal => this.id == that.id - case that: StackLocal => this.isThisLocal && that.isThisLocal - case _ => false - } -} - -class ParameterLocal(identifier: Int, computationalType: ComputationalType, paramName: String) extends TacLocal { - - override def id: Int = identifier - - override def isStackLocal: Boolean = false - - override def isRegisterLocal: Boolean = false - - override def isParameterLocal: Boolean = true - - override def isThisLocal: Boolean = false - - override def cTpe: ComputationalType = computationalType - - override def value: ValueInformation = throw new UnsupportedOperationException("No value information available for parameter local") - - override def name: String = paramName - - override def hashCode: Int = Objects.hash(id, isStackLocal, isRegisterLocal, isParameterLocal) - - override def equals(other: Any): Boolean = other match { - case that: ParameterLocal => this.id == that.id - case _ => false - } -} - -class NullifiedLocal(identifier: Int, computationalType: ComputationalType) extends TacLocal { - - override def id: Int = identifier - - override def isStackLocal: Boolean = false - - override def isRegisterLocal: Boolean = false - - override def isParameterLocal: Boolean = false - - override def isThisLocal: Boolean = false - - override def cTpe: ComputationalType = computationalType - - override def value: ValueInformation = IsNullValue - - override def name: String = s"n$identifier" - - override def hashCode: Int = Objects.hash(id, isStackLocal, isRegisterLocal, isParameterLocal) - - override def equals(other: Any): Boolean = other match { - case that: NullifiedLocal => this.id == that.id - case _ => false - } -} - -class ExceptionLocal(identifier: Int, computationalType: ComputationalType, valueInfo: ValueInformation) extends TacLocal { - - override def id: Int = identifier - - override def isStackLocal: Boolean = true - - override def isRegisterLocal: Boolean = false - - override def isParameterLocal: Boolean = false - - override def isThisLocal: Boolean = false - - override def cTpe: ComputationalType = computationalType - - override def value: ValueInformation = valueInfo - - override def name: String = s"e$identifier" - - override def hashCode: Int = Objects.hash(id) - - override def equals(other: Any): Boolean = other match { - case that: ExceptionLocal => this.id == that.id - case _ => false - } -} - -// TODO Consider TempLocal in SWAP diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacTransformer.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacTransformer.scala deleted file mode 100644 index 4990f2ead..000000000 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformer/TacTransformer.scala +++ /dev/null @@ -1,34 +0,0 @@ -package boomerang.scope.opal.transformer - -import org.opalj.ai.domain.l0.PrimitiveTACAIDomain -import org.opalj.br.analyses.Project -import org.opalj.br.cfg.CFGFactory -import org.opalj.br.Method -import org.opalj.tac.{Stmt, TACNaive, TACStmts} - -object TacTransformer { - - def apply(project: Project[_], method: Method): BoomerangTACode = { - val tacNaive = TACNaive(method, project.classHierarchy) - - val domain = new PrimitiveTACAIDomain(project.classHierarchy, method) - val operandStack = OperandStack(tacNaive) - val transformedTac = LocalTransformer(method, tacNaive, domain, operandStack) - val simplifiedTac = BasicPropagation(transformedTac, operandStack) - - // Update the CFG - val cfg = CFGFactory(method, project.classHierarchy) - if (cfg.isEmpty) { - throw new RuntimeException("Could not compute CFG for method " + method.name) - } - - val tacCfg = cfg.get.mapPCsToIndexes[Stmt[TacLocal], TACStmts[TacLocal]](TACStmts(simplifiedTac), tacNaive.pcToIndex, i => i, simplifiedTac.length) - - val exceptionHandlers = tacNaive.exceptionHandlers.map(eh => eh.handlerPC).toArray - val stmtGraph = StmtGraph(simplifiedTac, tacCfg, tacNaive.pcToIndex, exceptionHandlers) - val nopStmtGraph = NopTransformer(stmtGraph) - val nullifiedStmtGraph = NullifyFieldsTransformer(method, nopStmtGraph) - - new BoomerangTACode(nullifiedStmtGraph) - } -} diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala index ed8797352..4c3372524 100644 --- a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala @@ -27,8 +27,6 @@ class OpalInvokeExprTest { val opalMethod = OpalMethod(method) opalMethod.getControlFlowGraph - val test = TacBodyBuilder(OpalClient.project.get, method) - // Update the project's config to set the test method as the (single) entry point. See // https://github.com/opalj/opal/blob/ff01c1c9e696946a88b090a52881a41445cf07f1/DEVELOPING_OPAL/tools/src/main/scala/org/opalj/support/info/CallGraph.scala#L406 var config = OpalClient.project.get.config From c5efc916cf7e79a12c4e7ab1d2f007090d558a32 Mon Sep 17 00:00:00 2001 From: Sven Meyer Date: Tue, 15 Apr 2025 18:33:26 +0200 Subject: [PATCH 38/61] Replace sets.newHashSet with LinkedHashSet --- .../java/sync/pds/solver/SyncPDSSolver.java | 20 +- .../main/java/sync/pds/weights/SetDomain.java | 5 +- .../main/java/wpds/impl/StackListener.java | 4 +- .../java/wpds/impl/WeightedPAutomaton.java | 45 +-- .../wpds/impl/WeightedPushdownSystem.java | 14 +- .../java/tests/ForwardDFSVisitorTest.java | 12 +- .../src/main/java/boomerang/QueryGraph.java | 8 +- .../java/boomerang/WeightedBoomerang.java | 10 +- .../callgraph/BoomerangResolver.java | 8 +- .../boomerang/debugger/IDEVizDebugger.java | 4 +- .../DefaultBackwardFlowFunction.java | 8 +- .../DefaultForwardFlowFunction.java | 8 +- .../guided/DemandDrivenGuidedAnalysis.java | 3 +- .../SimpleSpecificationGuidedManager.java | 8 +- .../java/boomerang/guided/Specification.java | 8 +- .../boomerang/poi/CopyAccessPathChain.java | 4 +- .../poi/ExecuteImportFieldStmtPOI.java | 4 +- .../boomerang/poi/PointOfIndirection.java | 6 +- .../results/BackwardBoomerangResults.java | 10 +- .../results/ExtractAllAliasListener.java | 8 +- .../results/ForwardBoomerangResults.java | 12 +- .../boomerang/scope/AccessPathParser.java | 6 +- .../java/boomerang/scope/AnalysisScope.java | 6 +- .../solver/AbstractBoomerangSolver.java | 6 +- .../solver/BackwardBoomerangSolver.java | 4 +- .../solver/ForwardBoomerangSolver.java | 4 +- .../stats/AdvancedBoomerangStats.java | 23 +- .../stats/CSVBoomerangStatsWriter.java | 31 +- .../boomerang/stats/SimpleBoomerangStats.java | 9 +- .../weights/PathConditionWeight.java | 8 +- .../boomerang/weights/PathTrackingWeight.java | 15 +- .../main/resources/simplelogger.properties | 4 + .../DemandDrivenGuidedAnalysisTest.java | 3 +- .../java/test/core/AbstractBoomerangTest.java | 12 +- .../test/core/MultiQueryBoomerangTest.java | 6 +- .../scope/opal/tac/OpalArrayRef.scala | 18 +- .../boomerang/scope/opal/tac/OpalLocal.scala | 2 +- .../scope/opal/tac/OpalStatement.scala | 24 +- .../opal/tac/OpalStatementFormatter.scala | 18 +- .../opal/transformation/TacBodyBuilder.scala | 18 +- .../stack/OperandStackBuilder.scala | 4 +- .../transformer/InlineLocalTransformer.scala | 302 ++++++------------ .../LocalPropagationTransformer.scala | 226 +++++++++++++ .../boomerang/scope/opal/OpalArrayTest.scala | 62 +++- .../scope/soot/BoomerangPretransformer.java | 10 +- .../soot/jimple/ExplicitNullifyFields.java | 4 +- .../scope/soot/jimple/JimpleMethod.java | 4 +- .../scope/soot/jimple/JimpleWrappedClass.java | 4 +- .../boomerang/scope/soot/SootArrayTest.java | 2 +- .../jimple/JimpleUpControlFlowGraph.java | 6 +- .../boomerang/scope/wala/WALACallGraph.java | 4 +- .../scope/wala/WALAControlFlowGraph.java | 10 +- .../java/boomerang/scope/wala/WALAMethod.java | 4 +- .../main/java/boomerang/scope/CallGraph.java | 8 +- .../src/main/java/boomerang/scope/Method.java | 4 +- .../scope/test/targets/ArrayTarget.java | 26 +- .../src/main/java/ideal/IDEALSeedSolver.java | 4 +- .../main/java/ideal/IDEALWeightFunctions.java | 12 +- .../java/typestate/TransitionFunction.java | 12 +- .../TypeStateMachineWeightFunctions.java | 4 +- 60 files changed, 669 insertions(+), 469 deletions(-) create mode 100644 boomerangPDS/src/main/resources/simplelogger.properties create mode 100644 boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/LocalPropagationTransformer.scala diff --git a/SynchronizedPDS/src/main/java/sync/pds/solver/SyncPDSSolver.java b/SynchronizedPDS/src/main/java/sync/pds/solver/SyncPDSSolver.java index 7c90c9c65..cd20b0d1b 100644 --- a/SynchronizedPDS/src/main/java/sync/pds/solver/SyncPDSSolver.java +++ b/SynchronizedPDS/src/main/java/sync/pds/solver/SyncPDSSolver.java @@ -16,11 +16,11 @@ import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multimap; -import com.google.common.collect.Sets; import de.fraunhofer.iem.Location; import java.util.AbstractMap; import java.util.Collection; import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.Map; import java.util.Map.Entry; import java.util.Set; @@ -70,10 +70,10 @@ public String toString() { return "Field " + SyncPDSSolver.this; } }; - private final Set> reachedStates = Sets.newHashSet(); - private final Set> callingContextReachable = Sets.newHashSet(); - private final Set> fieldContextReachable = Sets.newHashSet(); - private final Set> updateListeners = Sets.newHashSet(); + private final Set> reachedStates = new LinkedHashSet<>(); + private final Set> callingContextReachable = new LinkedHashSet<>(); + private final Set> fieldContextReachable = new LinkedHashSet<>(); + private final Set> updateListeners = new LinkedHashSet<>(); private final Multimap, SyncStatePDSUpdateListener> reachedStateUpdateListeners = HashMultimap.create(); protected final WeightedPAutomaton>, W> fieldAutomaton; @@ -594,8 +594,8 @@ private void applyCallSummary(Stmt callSite, Fact factInCallee, Stmt spInCallee) }); } - Set

    summaries = Sets.newHashSet(); - Set summaryListeners = Sets.newHashSet(); + Set summaries = new LinkedHashSet<>(); + Set summaryListeners = new LinkedHashSet<>(); public void addApplySummaryListener(OnAddedSummaryListener l) { if (summaryListeners.add(l)) { @@ -794,7 +794,7 @@ public void addGeneratedFieldState(GeneratedState, Field> state public abstract Field fieldWildCard(); public Set> getReachedStates() { - return Sets.newHashSet(reachedStates); + return new LinkedHashSet(reachedStates); } public void debugOutput() { @@ -802,9 +802,9 @@ public void debugOutput() { logger.debug("All reachable states"); prettyPrintSet(getReachedStates()); - HashSet> notFieldReachable = Sets.newHashSet(callingContextReachable); + HashSet> notFieldReachable = new LinkedHashSet(callingContextReachable); notFieldReachable.removeAll(getReachedStates()); - HashSet> notCallingContextReachable = Sets.newHashSet(fieldContextReachable); + HashSet> notCallingContextReachable = new LinkedHashSet(fieldContextReachable); notCallingContextReachable.removeAll(getReachedStates()); if (!notFieldReachable.isEmpty()) { logger.debug("Calling context reachable"); diff --git a/SynchronizedPDS/src/main/java/sync/pds/weights/SetDomain.java b/SynchronizedPDS/src/main/java/sync/pds/weights/SetDomain.java index 486dffd73..e40a66292 100644 --- a/SynchronizedPDS/src/main/java/sync/pds/weights/SetDomain.java +++ b/SynchronizedPDS/src/main/java/sync/pds/weights/SetDomain.java @@ -14,6 +14,7 @@ import com.google.common.collect.Sets; import de.fraunhofer.iem.Location; import java.util.Collection; +import java.util.LinkedHashSet; import java.util.Set; import sync.pds.solver.nodes.Node; import wpds.impl.Weight; @@ -56,7 +57,7 @@ public Weight combineWith(Weight other) { if (this.equals(zero())) return other; if (this.equals(one()) || other.equals(one())) return one(); if (other instanceof SetDomain) { - Set> merged = Sets.newHashSet(nodes); + Set> merged = new LinkedHashSet(nodes); merged.addAll(((SetDomain) other).nodes); return new SetDomain(merged); } @@ -103,6 +104,6 @@ public boolean equals(Object obj) { } public Collection> elements() { - return Sets.newHashSet(nodes); + return new LinkedHashSet(nodes); } } diff --git a/WPDS/src/main/java/wpds/impl/StackListener.java b/WPDS/src/main/java/wpds/impl/StackListener.java index 7a2ae3d3a..c47d33d34 100644 --- a/WPDS/src/main/java/wpds/impl/StackListener.java +++ b/WPDS/src/main/java/wpds/impl/StackListener.java @@ -11,8 +11,8 @@ */ package wpds.impl; -import com.google.common.collect.Sets; import de.fraunhofer.iem.Location; +import java.util.LinkedHashSet; import java.util.Set; import wpds.interfaces.State; import wpds.interfaces.WPAStateListener; @@ -23,7 +23,7 @@ public abstract class StackListener aut; private final N source; - private final Set notifiedStacks = Sets.newHashSet(); + private final Set notifiedStacks = new LinkedHashSet<>(); public StackListener(WeightedPAutomaton weightedPAutomaton, D state, N source) { super(state); diff --git a/WPDS/src/main/java/wpds/impl/WeightedPAutomaton.java b/WPDS/src/main/java/wpds/impl/WeightedPAutomaton.java index 5bf5b82bd..ce9fc7985 100644 --- a/WPDS/src/main/java/wpds/impl/WeightedPAutomaton.java +++ b/WPDS/src/main/java/wpds/impl/WeightedPAutomaton.java @@ -18,12 +18,12 @@ import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multimap; -import com.google.common.collect.Sets; import com.google.common.collect.Table; import de.fraunhofer.iem.Location; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -51,26 +51,27 @@ public abstract class WeightedPAutomaton> transitions = Sets.newHashSet(); + protected Set> transitions = new LinkedHashSet<>(); // set F in paper [Reps2003] - protected Set finalState = Sets.newHashSet(); + protected Set finalState = new LinkedHashSet<>(); protected Multimap initialStatesToSource = HashMultimap.create(); // set P in paper [Reps2003] - protected Set states = Sets.newHashSet(); + protected Set states = new LinkedHashSet<>(); private final Multimap> transitionsOutOf = HashMultimap.create(); private final Multimap> transitionsInto = HashMultimap.create(); - private final Set> listeners = Sets.newHashSet(); + private final Set> listeners = new LinkedHashSet<>(); private final Multimap> stateListeners = HashMultimap.create(); private final Map> stateToDFS = Maps.newHashMap(); private final Map> stateToEpsilonDFS = Maps.newHashMap(); - private final Set> nestedAutomatons = Sets.newHashSet(); - private final Set> nestedAutomataListeners = Sets.newHashSet(); + private final Set> nestedAutomatons = new LinkedHashSet<>(); + private final Set> nestedAutomataListeners = + new LinkedHashSet<>(); private final Map> stateToEpsilonReachabilityListener = Maps.newHashMap(); private final Map> stateToReachabilityListener = Maps.newHashMap(); - private final Set connectedPushes = Sets.newHashSet(); - private final Set> conntectedPushListeners = Sets.newHashSet(); - private final Set> unbalancedPopListeners = Sets.newHashSet(); + private final Set connectedPushes = new LinkedHashSet<>(); + private final Set> conntectedPushListeners = new LinkedHashSet<>(); + private final Set> unbalancedPopListeners = new LinkedHashSet<>(); private final Map unbalancedPops = Maps.newHashMap(); private final Map, W> transitionsToFinalWeights = Maps.newHashMap(); private ForwardDFSVisitor dfsVisitor; @@ -130,7 +131,7 @@ private String wrapFinalState(D s) { private static final boolean SUMMARIZE = false; public String toDotString() { - return toDotString(Sets.newHashSet()); + return toDotString(new LinkedHashSet<>()); } private String toDotString(Set> visited) { @@ -140,7 +141,7 @@ private String toDotString(Set> visited) { String s = "digraph {\n"; TreeSet trans = new TreeSet(); List summaryIdentifier = Lists.newArrayList(); - Set> removableTrans = Sets.newHashSet(); + Set> removableTrans = new LinkedHashSet<>(); if (SUMMARIZE) { Table>> mergableStates = HashBasedTable.create(); for (D source : states) { @@ -148,7 +149,7 @@ private String toDotString(Set> visited) { for (Transition t : transitionsOutOf.get(source)) { Set> set = mergableStates.get(t.getLabel(), t.getTarget()); if (set == null) { - set = Sets.newHashSet(); + set = new LinkedHashSet<>(); } set.add(t); removableTrans.add(t); @@ -225,7 +226,7 @@ public String toLabelGroupedDotString() { HashBasedTable> groupedByTargetAndLabel = HashBasedTable.create(); for (Transition t : transitions) { Collection collection = groupedByTargetAndLabel.get(t.getTarget(), t.getLabel()); - if (collection == null) collection = Sets.newHashSet(); + if (collection == null) collection = new LinkedHashSet<>(); collection.add(t.getStart()); groupedByTargetAndLabel.put(t.getTarget(), t.getLabel(), collection); } @@ -277,7 +278,7 @@ public Set getStates() { } public Set> getEdges() { - Set> trans = Sets.newHashSet(); + Set> trans = new LinkedHashSet<>(); for (Edge tran : transitions) { if (!tran.getLabel().equals(epsilon())) { trans.add(new Transition(tran.getTarget(), tran.getLabel(), tran.getStart())); @@ -499,8 +500,8 @@ public void unbalancedPop(D targetState, Transition trans, W weight) { } } - private final Set> summaryEdges = Sets.newHashSet(); - private final Set> summaryEdgeListener = Sets.newHashSet(); + private final Set> summaryEdges = new LinkedHashSet<>(); + private final Set> summaryEdgeListener = new LinkedHashSet<>(); public void registerSummaryEdge(Transition t) { if (summaryEdges.add(t)) { @@ -737,7 +738,7 @@ public IRegEx toRegEx(D start, D end) { public boolean containsLoop() { // Performs a backward DFS - HashSet visited = Sets.newHashSet(); + HashSet visited = new LinkedHashSet<>(); LinkedList worklist = Lists.newLinkedList(); worklist.addAll(initialStatesToSource.keySet()); while (!worklist.isEmpty()) { @@ -771,7 +772,7 @@ public Set getLongestPath() { if (!isGeneratedState(next)) continue; if (next.equals(pop)) continue; Set atNext = getOrCreate(pathReachingD, next); - Set newAtCurr = Sets.newHashSet(atCurr); + Set newAtCurr = new LinkedHashSet(atCurr); if (newAtCurr.add(t.getLabel())) { boolean addAll = atNext.addAll(newAtCurr); if (addAll) { @@ -780,7 +781,7 @@ public Set getLongestPath() { } } } - Set longest = Sets.newHashSet(); + Set longest = new LinkedHashSet<>(); for (Set l : pathReachingD.values()) { if (longest.size() < l.size()) { longest = l; @@ -792,7 +793,7 @@ public Set getLongestPath() { private Set getOrCreate(Map> pathReachingD, D pop) { Set collection = pathReachingD.get(pop); if (collection == null) { - collection = Sets.newHashSet(); + collection = new LinkedHashSet<>(); pathReachingD.put(pop, collection); } return collection; @@ -804,7 +805,7 @@ public boolean isUnbalancedState(D target) { public boolean addUnbalancedState(D state, D parent) { Integer distance = 0; - Collection parents = Sets.newHashSet(); + Collection parents = new LinkedHashSet<>(); if (!initialStatesToSource.containsKey(parent)) { distance = stateToUnbalancedDistance.get(parent); parents.add(parent); diff --git a/WPDS/src/main/java/wpds/impl/WeightedPushdownSystem.java b/WPDS/src/main/java/wpds/impl/WeightedPushdownSystem.java index aab9d57f4..b9853eea4 100644 --- a/WPDS/src/main/java/wpds/impl/WeightedPushdownSystem.java +++ b/WPDS/src/main/java/wpds/impl/WeightedPushdownSystem.java @@ -13,10 +13,10 @@ import com.google.common.base.Joiner; import com.google.common.collect.Lists; -import com.google.common.collect.Sets; import de.fraunhofer.iem.Location; import de.fraunhofer.iem.wildcard.Wildcard; import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.Set; import wpds.interfaces.IPushdownSystem; import wpds.interfaces.State; @@ -24,10 +24,10 @@ public class WeightedPushdownSystem implements IPushdownSystem { - protected final Set> pushRules = Sets.newHashSet(); - protected final Set> popRules = Sets.newHashSet(); - protected final Set> normalRules = Sets.newHashSet(); - protected final Set> listeners = Sets.newHashSet(); + protected final Set> pushRules = new LinkedHashSet<>(); + protected final Set> popRules = new LinkedHashSet<>(); + protected final Set> normalRules = new LinkedHashSet<>(); + protected final Set> listeners = new LinkedHashSet<>(); @Override public boolean addRule(Rule rule) { @@ -73,7 +73,7 @@ public Set> getPushRules() { @Override public Set> getAllRules() { - Set> rules = Sets.newHashSet(); + Set> rules = new LinkedHashSet<>(); rules.addAll(normalRules); rules.addAll(popRules); rules.addAll(pushRules); @@ -122,7 +122,7 @@ public Set> getPushRulesEnding(D start, N string) { @Override public Set getStates() { - Set states = Sets.newHashSet(); + Set states = new LinkedHashSet<>(); for (Rule r : getAllRules()) { states.add(r.getS1()); states.add(r.getS2()); diff --git a/WPDS/src/test/java/tests/ForwardDFSVisitorTest.java b/WPDS/src/test/java/tests/ForwardDFSVisitorTest.java index 1a959deeb..f21f8e8f3 100644 --- a/WPDS/src/test/java/tests/ForwardDFSVisitorTest.java +++ b/WPDS/src/test/java/tests/ForwardDFSVisitorTest.java @@ -20,8 +20,8 @@ import static tests.TestHelper.t; import com.google.common.base.Joiner; -import com.google.common.collect.Sets; import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.Set; import org.junit.Assert; import org.junit.Before; @@ -53,7 +53,7 @@ public boolean isGeneratedState(Abstraction d) { return d.s != null; } }; - final Set> reachables = Sets.newHashSet(); + final Set> reachables = new LinkedHashSet<>(); @Test public void delayedAdd() { @@ -193,9 +193,9 @@ public void doublePushSummaryReachabilityTest() { private void assertSetEquals( Set> s1, Set> s2) { if (s1.equals(s2)) return; - Set> s1MinusS2 = Sets.newHashSet(s1); + Set> s1MinusS2 = new LinkedHashSet(s1); s1MinusS2.removeAll(s2); - Set> s2MinusS1 = Sets.newHashSet(s2); + Set> s2MinusS1 = new LinkedHashSet(s2); s2MinusS1.removeAll(s1); throw new AssertionError( "The sets are not equal: \n S1\\S2 = \n" @@ -206,7 +206,7 @@ private void assertSetEquals( private Set> reachableFrom( PAutomaton aut, Abstraction a) { - final Set> reachable = Sets.newHashSet(); + final Set> reachable = new LinkedHashSet<>(); aut.registerDFSListener( a, new ReachabilityListener() { @@ -219,7 +219,7 @@ public void reachable(Transition t) { } private Set> reachableMinusTrans() { - HashSet> res = Sets.newHashSet(fa.getTransitions()); + HashSet> res = new LinkedHashSet(fa.getTransitions()); res.removeAll(reachables); return res; } diff --git a/boomerangPDS/src/main/java/boomerang/QueryGraph.java b/boomerangPDS/src/main/java/boomerang/QueryGraph.java index e076268c9..182f389db 100644 --- a/boomerangPDS/src/main/java/boomerang/QueryGraph.java +++ b/boomerangPDS/src/main/java/boomerang/QueryGraph.java @@ -26,8 +26,8 @@ import com.google.common.collect.HashMultimap; import com.google.common.collect.Lists; import com.google.common.collect.Multimap; -import com.google.common.collect.Sets; import java.util.ArrayList; +import java.util.LinkedHashSet; import java.util.Map.Entry; import java.util.Set; import java.util.TreeSet; @@ -47,7 +47,7 @@ public class QueryGraph { private final ObservableICFG icfg; private final Multimap sourceToQueryEdgeLookUp = HashMultimap.create(); private final Multimap targetToQueryEdgeLookUp = HashMultimap.create(); - private final Set roots = Sets.newHashSet(); + private final Set roots = new LinkedHashSet<>(); private final DefaultValueMap> forwardSolvers; private final Multimap edgeAddListener = HashMultimap.create(); private final DefaultValueMap> backwardSolver; @@ -87,7 +87,7 @@ public void unregisterAllListeners() { } public Set getNodes() { - Set nodes = Sets.newHashSet(sourceToQueryEdgeLookUp.keySet()); + Set nodes = new LinkedHashSet(sourceToQueryEdgeLookUp.keySet()); nodes.addAll(targetToQueryEdgeLookUp.keySet()); return nodes; } @@ -176,7 +176,7 @@ public String toString() { int level = 0; for (Query root : roots) { s += "Root:" + root + "\n"; - s += visit(root, "", ++level, Sets.newHashSet()); + s += visit(root, "", ++level, new LinkedHashSet<>()); } return s; } diff --git a/boomerangPDS/src/main/java/boomerang/WeightedBoomerang.java b/boomerangPDS/src/main/java/boomerang/WeightedBoomerang.java index 5c9bb55f1..7c9ac4362 100644 --- a/boomerangPDS/src/main/java/boomerang/WeightedBoomerang.java +++ b/boomerangPDS/src/main/java/boomerang/WeightedBoomerang.java @@ -54,11 +54,11 @@ import com.google.common.collect.HashMultimap; import com.google.common.collect.Lists; import com.google.common.collect.Multimap; -import com.google.common.collect.Sets; import com.google.common.collect.Table; import com.google.common.collect.Table.Cell; import java.util.Collection; import java.util.HashMap; +import java.util.LinkedHashSet; import java.util.Map; import java.util.Map.Entry; import java.util.Optional; @@ -93,8 +93,8 @@ public abstract class WeightedBoomerang { new HashMap<>(); private long lastTick; private final IBoomerangStats stats; - private final Set visitedMethods = Sets.newHashSet(); - private final Set> solverCreationListeners = Sets.newHashSet(); + private final Set visitedMethods = new LinkedHashSet<>(); + private final Set> solverCreationListeners = new LinkedHashSet<>(); private final Multimap> poiListeners = HashMultimap.create(); private final Multimap>> activatedPoi = HashMultimap.create(); @@ -1484,8 +1484,8 @@ private void printRules() { // LOGGER.debug("BackwardFieldRules " + backwardSolver.getFieldPDS().getAllRules().size()); long forwardCallElaps = 0; long forwardFieldElaps = 0; - Set allCallRules = Sets.newHashSet(); - Set allFieldRules = Sets.newHashSet(); + Set allCallRules = new LinkedHashSet<>(); + Set allFieldRules = new LinkedHashSet<>(); for (ForwardBoomerangSolver v : queryToSolvers.values()) { allCallRules.addAll(v.getCallPDS().getAllRules()); allFieldRules.addAll(v.getFieldPDS().getAllRules()); diff --git a/boomerangPDS/src/main/java/boomerang/callgraph/BoomerangResolver.java b/boomerangPDS/src/main/java/boomerang/callgraph/BoomerangResolver.java index 247c24ff2..9d4f8216c 100644 --- a/boomerangPDS/src/main/java/boomerang/callgraph/BoomerangResolver.java +++ b/boomerangPDS/src/main/java/boomerang/callgraph/BoomerangResolver.java @@ -34,9 +34,9 @@ import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.common.collect.Multimap; -import com.google.common.collect.Sets; import java.util.ArrayList; import java.util.Collection; +import java.util.LinkedHashSet; import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -65,8 +65,8 @@ public enum NoCalleeFoundFallbackOptions { private final CallGraph precomputedCallGraph; private final WeightedBoomerang solver; - private final Set queriedInvokeExprAndAllocationSitesFound = Sets.newHashSet(); - private final Set queriedInvokeExpr = Sets.newHashSet(); + private final Set queriedInvokeExprAndAllocationSitesFound = new LinkedHashSet<>(); + private final Set queriedInvokeExpr = new LinkedHashSet<>(); public BoomerangResolver(FrameworkScope frameworkScope) { this.solver = new Boomerang(frameworkScope); @@ -169,7 +169,7 @@ private Collection forAnyAllocationSiteOfQuery( private Collection getMethodFromClassOrFromSuperclass( DeclaredMethod method, WrappedClass sootClass) { - Set res = Sets.newHashSet(); + Set res = new LinkedHashSet<>(); WrappedClass originalClass = sootClass; while (sootClass != null) { for (Method candidate : sootClass.getMethods()) { diff --git a/boomerangPDS/src/main/java/boomerang/debugger/IDEVizDebugger.java b/boomerangPDS/src/main/java/boomerang/debugger/IDEVizDebugger.java index 37ff65a1c..7835c4ff1 100644 --- a/boomerangPDS/src/main/java/boomerang/debugger/IDEVizDebugger.java +++ b/boomerangPDS/src/main/java/boomerang/debugger/IDEVizDebugger.java @@ -30,7 +30,6 @@ import com.google.common.collect.HashMultimap; import com.google.common.collect.Lists; import com.google.common.collect.Multimap; -import com.google.common.collect.Sets; import com.google.common.collect.Table; import com.google.common.collect.Table.Cell; import java.io.File; @@ -38,6 +37,7 @@ import java.io.IOException; import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -82,7 +82,7 @@ private void callRules(Query q, Set, W>> allRules) { private Set, W>> getOrCreateRuleSet(Query q, Method method) { Set, W>> map = rules.get(q, method); if (map != null) return map; - rules.put(q, method, Sets.newHashSet()); + rules.put(q, method, new LinkedHashSet<>()); return rules.get(q, method); } diff --git a/boomerangPDS/src/main/java/boomerang/flowfunction/DefaultBackwardFlowFunction.java b/boomerangPDS/src/main/java/boomerang/flowfunction/DefaultBackwardFlowFunction.java index a731dd58a..ea3c707d9 100644 --- a/boomerangPDS/src/main/java/boomerang/flowfunction/DefaultBackwardFlowFunction.java +++ b/boomerangPDS/src/main/java/boomerang/flowfunction/DefaultBackwardFlowFunction.java @@ -22,9 +22,9 @@ import boomerang.solver.BackwardBoomerangSolver; import boomerang.solver.Strategies; import com.google.common.collect.Multimap; -import com.google.common.collect.Sets; import java.util.Collection; import java.util.Collections; +import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import sync.pds.solver.SyncPDSSolver.PDSSystem; @@ -46,7 +46,7 @@ public DefaultBackwardFlowFunction(DefaultBackwardFlowFunctionOptions options) { @Override public Collection returnFlow(Method callee, Statement returnStmt, Val returnedVal) { - Set out = Sets.newHashSet(); + Set out = new LinkedHashSet<>(); if (!callee.isStatic()) { if (callee.getThisLocal().equals(returnedVal)) { out.add(returnedVal); @@ -69,7 +69,7 @@ public Collection callFlow(Statement callSite, Val fact, Method callee, Sta throw new RuntimeException("Call site does not contain an invoke expression."); } InvokeExpr invokeExpr = callSite.getInvokeExpr(); - Set out = Sets.newHashSet(); + Set out = new LinkedHashSet<>(); if (invokeExpr.isInstanceInvokeExpr()) { if (invokeExpr.getBase().equals(fact) && !callee.isStatic()) { out.add(callee.getThisLocal()); @@ -105,7 +105,7 @@ public Collection normalFlow(Edge currEdge, Val fact) { if (curr.isThrowStmt()) { return Collections.emptySet(); } - Set out = Sets.newHashSet(); + Set out = new LinkedHashSet<>(); boolean leftSideMatches = false; if (curr.isAssignStmt()) { diff --git a/boomerangPDS/src/main/java/boomerang/flowfunction/DefaultForwardFlowFunction.java b/boomerangPDS/src/main/java/boomerang/flowfunction/DefaultForwardFlowFunction.java index ece4cc377..b9535c421 100644 --- a/boomerangPDS/src/main/java/boomerang/flowfunction/DefaultForwardFlowFunction.java +++ b/boomerangPDS/src/main/java/boomerang/flowfunction/DefaultForwardFlowFunction.java @@ -23,9 +23,9 @@ import boomerang.solver.ForwardBoomerangSolver; import boomerang.solver.Strategies; import com.google.common.collect.Multimap; -import com.google.common.collect.Sets; import java.util.Collection; import java.util.Collections; +import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import sync.pds.solver.SyncPDSSolver.PDSSystem; @@ -47,7 +47,7 @@ public DefaultForwardFlowFunction(DefaultForwardFlowFunctionOptions options) { @Override public Set returnFlow(Method method, Statement curr, Val value) { - Set out = Sets.newHashSet(); + Set out = new LinkedHashSet<>(); if (curr.isThrowStmt() && !options.throwFlows()) { return Collections.emptySet(); } @@ -80,7 +80,7 @@ public Set callFlow(Statement callSite, Val fact, Method callee) { if (callee.isStaticInitializer()) { return Collections.emptySet(); } - Set out = Sets.newHashSet(); + Set out = new LinkedHashSet<>(); InvokeExpr invokeExpr = callSite.getInvokeExpr(); if (invokeExpr.isInstanceInvokeExpr()) { if (invokeExpr.getBase().equals(fact) && !callee.isStatic()) { @@ -104,7 +104,7 @@ public Set callFlow(Statement callSite, Val fact, Method callee) { @Override public Set normalFlow(ForwardQuery query, Edge nextEdge, Val fact) { Statement succ = nextEdge.getStart(); - Set out = Sets.newHashSet(); + Set out = new LinkedHashSet<>(); if (killFlow(succ, fact)) { return out; } diff --git a/boomerangPDS/src/main/java/boomerang/guided/DemandDrivenGuidedAnalysis.java b/boomerangPDS/src/main/java/boomerang/guided/DemandDrivenGuidedAnalysis.java index 2aaf90788..9627c0d22 100644 --- a/boomerangPDS/src/main/java/boomerang/guided/DemandDrivenGuidedAnalysis.java +++ b/boomerangPDS/src/main/java/boomerang/guided/DemandDrivenGuidedAnalysis.java @@ -25,7 +25,6 @@ import boomerang.scope.FrameworkScope; import boomerang.scope.Val; import com.google.common.collect.Lists; -import com.google.common.collect.Sets; import com.google.common.collect.Table; import com.google.common.collect.Table.Cell; import java.util.*; @@ -37,7 +36,7 @@ public class DemandDrivenGuidedAnalysis { private final IDemandDrivenGuidedManager spec; private final LinkedList queryQueue = Lists.newLinkedList(); - private final Set visited = Sets.newHashSet(); + private final Set visited = new LinkedHashSet<>(); private final Boomerang solver; private boolean triggered; diff --git a/boomerangPDS/src/main/java/boomerang/guided/SimpleSpecificationGuidedManager.java b/boomerangPDS/src/main/java/boomerang/guided/SimpleSpecificationGuidedManager.java index 00fd90973..13aa0dc2f 100644 --- a/boomerangPDS/src/main/java/boomerang/guided/SimpleSpecificationGuidedManager.java +++ b/boomerangPDS/src/main/java/boomerang/guided/SimpleSpecificationGuidedManager.java @@ -23,8 +23,8 @@ import boomerang.scope.Method; import boomerang.scope.Statement; import boomerang.scope.Val; -import com.google.common.collect.Sets; import java.util.Collection; +import java.util.LinkedHashSet; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; @@ -40,7 +40,7 @@ public SimpleSpecificationGuidedManager(Specification spec) { @Override public Collection onForwardFlow(ForwardQuery query, Edge dataFlowEdge, Val dataFlowVal) { Statement stmt = dataFlowEdge.getStart(); - Set res = Sets.newHashSet(); + Set res = new LinkedHashSet<>(); if (stmt.containsInvokeExpr()) { Set selectors = spec.getMethodAndQueries().stream() @@ -56,7 +56,7 @@ public Collection onForwardFlow(ForwardQuery query, Edge dataFlowEdge, Va @Override public Collection onBackwardFlow(BackwardQuery query, Edge dataFlowEdge, Val dataFlowVal) { Statement stmt = dataFlowEdge.getStart(); - Set res = Sets.newHashSet(); + Set res = new LinkedHashSet<>(); if (stmt.containsInvokeExpr()) { Set selectors = spec.getMethodAndQueries().stream() @@ -70,7 +70,7 @@ public Collection onBackwardFlow(BackwardQuery query, Edge dataFlowEdge, } private Collection createNewQueries(MethodWithSelector sel, Statement stmt) { - Set results = Sets.newHashSet(); + Set results = new LinkedHashSet<>(); Method method = stmt.getMethod(); for (QuerySelector qSel : sel.getGo()) { Optional parameterVal = getParameterVal(stmt, qSel.argumentSelection); diff --git a/boomerangPDS/src/main/java/boomerang/guided/Specification.java b/boomerangPDS/src/main/java/boomerang/guided/Specification.java index c6f61f467..5e677bd5a 100644 --- a/boomerangPDS/src/main/java/boomerang/guided/Specification.java +++ b/boomerangPDS/src/main/java/boomerang/guided/Specification.java @@ -12,11 +12,11 @@ package boomerang.guided; import com.google.common.base.Objects; -import com.google.common.collect.Sets; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; import java.util.Collection; +import java.util.LinkedHashSet; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -42,8 +42,8 @@ private Specification(Collection spec) { private MethodWithSelector parse(String input) { Pattern arguments = Pattern.compile("\\((.*?)\\)"); Matcher argumentMatcher = arguments.matcher(input); - Set on = Sets.newHashSet(); - Set go = Sets.newHashSet(); + Set on = new LinkedHashSet<>(); + Set go = new LinkedHashSet<>(); // Handle arguments if (argumentMatcher.find()) { @@ -190,7 +190,7 @@ public static Specification loadFrom(String filePath) throws IOException { } public static Specification create(String... spec) { - return new Specification(Sets.newHashSet(spec)); + return new Specification(Set.of(spec)); } public Set getMethodAndQueries() { diff --git a/boomerangPDS/src/main/java/boomerang/poi/CopyAccessPathChain.java b/boomerangPDS/src/main/java/boomerang/poi/CopyAccessPathChain.java index 34014f3b1..27466111a 100644 --- a/boomerangPDS/src/main/java/boomerang/poi/CopyAccessPathChain.java +++ b/boomerangPDS/src/main/java/boomerang/poi/CopyAccessPathChain.java @@ -22,7 +22,7 @@ import com.google.common.collect.HashMultimap; import com.google.common.collect.Lists; import com.google.common.collect.Multimap; -import com.google.common.collect.Sets; +import java.util.LinkedHashSet; import java.util.Set; import sync.pds.solver.nodes.INode; import sync.pds.solver.nodes.Node; @@ -145,7 +145,7 @@ private CopyAccessPathChain getEnclosingInstance() { // Copied from ExecuteImportFielStmtPOI - private final Set>> reachable = Sets.newHashSet(); + private final Set>> reachable = new LinkedHashSet<>(); private final Multimap>, InsertFieldTransitionCallback> delayedTransitions = HashMultimap.create(); diff --git a/boomerangPDS/src/main/java/boomerang/poi/ExecuteImportFieldStmtPOI.java b/boomerangPDS/src/main/java/boomerang/poi/ExecuteImportFieldStmtPOI.java index 95925a1a7..26b2ebe39 100644 --- a/boomerangPDS/src/main/java/boomerang/poi/ExecuteImportFieldStmtPOI.java +++ b/boomerangPDS/src/main/java/boomerang/poi/ExecuteImportFieldStmtPOI.java @@ -22,7 +22,7 @@ import com.google.common.collect.HashMultimap; import com.google.common.collect.Lists; import com.google.common.collect.Multimap; -import com.google.common.collect.Sets; +import java.util.LinkedHashSet; import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -39,7 +39,7 @@ public abstract class ExecuteImportFieldStmtPOI { private static final Logger LOGGER = LoggerFactory.getLogger(ExecuteImportFieldStmtPOI.class); private static final int MAX_IMPORT_DEPTH = -1; - private final Set>> reachable = Sets.newHashSet(); + private final Set>> reachable = new LinkedHashSet<>(); private final Multimap>, InsertFieldTransitionCallback> delayedTransitions = HashMultimap.create(); protected final ForwardBoomerangSolver baseSolver; diff --git a/boomerangPDS/src/main/java/boomerang/poi/PointOfIndirection.java b/boomerangPDS/src/main/java/boomerang/poi/PointOfIndirection.java index 127479973..1e4364bcb 100644 --- a/boomerangPDS/src/main/java/boomerang/poi/PointOfIndirection.java +++ b/boomerangPDS/src/main/java/boomerang/poi/PointOfIndirection.java @@ -15,13 +15,13 @@ import boomerang.Query; import boomerang.scope.ControlFlowGraph.Edge; import com.google.common.collect.Lists; -import com.google.common.collect.Sets; +import java.util.LinkedHashSet; import java.util.Set; public abstract class PointOfIndirection { - private final Set actualBaseAllocations = Sets.newHashSet(); - private final Set flowAllocations = Sets.newHashSet(); + private final Set actualBaseAllocations = new LinkedHashSet<>(); + private final Set flowAllocations = new LinkedHashSet<>(); public abstract void execute(ForwardQuery baseAllocation, Query flowAllocation); diff --git a/boomerangPDS/src/main/java/boomerang/results/BackwardBoomerangResults.java b/boomerangPDS/src/main/java/boomerang/results/BackwardBoomerangResults.java index aa5900e4c..d19e15a79 100644 --- a/boomerangPDS/src/main/java/boomerang/results/BackwardBoomerangResults.java +++ b/boomerangPDS/src/main/java/boomerang/results/BackwardBoomerangResults.java @@ -26,7 +26,7 @@ import boomerang.util.DefaultValueMap; import com.google.common.base.Stopwatch; import com.google.common.collect.Maps; -import com.google.common.collect.Sets; +import java.util.LinkedHashSet; import java.util.Map; import java.util.Map.Entry; import java.util.Set; @@ -82,7 +82,7 @@ public Stopwatch getAnalysisWatch() { private void computeAllocations() { if (allocationSites != null) return; - final Set results = Sets.newHashSet(); + final Set results = new LinkedHashSet<>(); for (final Entry> fw : queryToSolvers.entrySet()) { for (INode> node : fw.getValue().getFieldAutomaton().getInitialStates()) fw.getValue() @@ -117,7 +117,7 @@ public boolean aliases(Query el) { } public Set getAllAliases(Edge stmt) { - final Set results = Sets.newHashSet(); + final Set results = new LinkedHashSet<>(); for (final ForwardQuery fw : getAllocationSites().keySet()) { queryToSolvers .getOrCreate(fw) @@ -147,7 +147,7 @@ public boolean isEmpty() { * @return Set of types the backward analysis propagates */ public Set getPropagationType() { - Set types = Sets.newHashSet(); + Set types = new LinkedHashSet<>(); for (Transition> t : backwardSolver.getCallAutomaton().getTransitions()) { if (!t.getStart().fact().isStatic()) types.add(t.getStart().fact().getType()); } @@ -164,7 +164,7 @@ public Set getPropagationType() { */ @Deprecated public Set> getDataFlowPath(ForwardQuery query) { - Set> dataFlowPath = Sets.newHashSet(); + Set> dataFlowPath = new LinkedHashSet<>(); WeightedPAutomaton, W> callAut = queryToSolvers.getOrCreate(query).getCallAutomaton(); for (Entry>, W> e : diff --git a/boomerangPDS/src/main/java/boomerang/results/ExtractAllAliasListener.java b/boomerangPDS/src/main/java/boomerang/results/ExtractAllAliasListener.java index 0baef169f..7883cb2cc 100644 --- a/boomerangPDS/src/main/java/boomerang/results/ExtractAllAliasListener.java +++ b/boomerangPDS/src/main/java/boomerang/results/ExtractAllAliasListener.java @@ -17,9 +17,9 @@ import boomerang.solver.AbstractBoomerangSolver; import boomerang.util.AccessPath; import com.google.common.collect.Lists; -import com.google.common.collect.Sets; import de.fraunhofer.iem.Empty; import java.util.Collection; +import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import sync.pds.solver.SyncPDSUpdateListener; @@ -110,10 +110,10 @@ public void onOutTransitionAdded( WeightedPAutomaton>, W> weightedPAutomaton) { if (t.getLabel().equals(Field.epsilon())) return; Collection>>> copiedFields = - (fields instanceof Set ? Sets.newHashSet(fields) : Lists.newArrayList(fields)); + (fields instanceof Set ? new LinkedHashSet(fields) : Lists.newArrayList(fields)); if (!t.getLabel().equals(Field.empty())) { if (copiedFields.contains(t)) { - copiedFields = Sets.newHashSet(fields); + copiedFields = new LinkedHashSet(fields); } if (!(t.getLabel() instanceof Empty)) copiedFields.add(t); } @@ -132,7 +132,7 @@ private Collection convert( if (fields instanceof List) { res = Lists.newArrayList(); } else { - res = Sets.newHashSet(); + res = new LinkedHashSet<>(); } for (Transition>> f : fields) { res.add(f.getLabel()); diff --git a/boomerangPDS/src/main/java/boomerang/results/ForwardBoomerangResults.java b/boomerangPDS/src/main/java/boomerang/results/ForwardBoomerangResults.java index cc4195c1b..bf8485816 100644 --- a/boomerangPDS/src/main/java/boomerang/results/ForwardBoomerangResults.java +++ b/boomerangPDS/src/main/java/boomerang/results/ForwardBoomerangResults.java @@ -36,10 +36,10 @@ import com.google.common.collect.HashBasedTable; import com.google.common.collect.Lists; import com.google.common.collect.Maps; -import com.google.common.collect.Sets; import com.google.common.collect.Table; import java.util.Collection; import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -111,7 +111,7 @@ public Table getObjectDestructingStatements() { return HashBasedTable.create(); } Table res = asEdgeValWeightTable(); - Set visitedMethods = Sets.newHashSet(); + Set visitedMethods = new LinkedHashSet<>(); for (Edge s : res.rowKeySet()) { visitedMethods.add(s.getMethod()); } @@ -122,7 +122,7 @@ public Table getObjectDestructingStatements() { for (Statement predOfExit : exitStmt.getMethod().getControlFlowGraph().getPredsOf(exitStmt)) { Edge exitEdge = new Edge(predOfExit, exitStmt); - Set escapes = Sets.newHashSet(); + Set escapes = new LinkedHashSet<>(); icfg.addCallerListener( new CallerListener() { @Override @@ -168,7 +168,7 @@ private void findLastUsage( ForwardBoomerangSolver forwardSolver) { LinkedList worklist = Lists.newLinkedList(); worklist.add(exitStmt); - Set visited = Sets.newHashSet(); + Set visited = new LinkedHashSet<>(); while (!worklist.isEmpty()) { Edge curr = worklist.poll(); if (!visited.add(curr)) { @@ -249,7 +249,7 @@ public Collection getInvokeStatementsOnInstance() { public QueryResults getPotentialNullPointerDereferences() { // FIXME this should be located nullpointer analysis - Set> res = Sets.newHashSet(); + Set> res = new LinkedHashSet<>(); for (Transition>> t : queryToSolvers.get(query).getFieldAutomaton().getTransitions()) { if (!t.getLabel().equals(Field.empty()) || t.getStart() instanceof GeneratedState) { @@ -261,7 +261,7 @@ public QueryResults getPotentialNullPointerDereferences() { res.add(nullPointerNode); } } - Set resWithContext = Sets.newHashSet(); + Set resWithContext = new LinkedHashSet<>(); for (Node r : res) { // Context context = constructContextGraph(query, r); if (trackDataFlowPath) { diff --git a/boomerangPDS/src/main/java/boomerang/scope/AccessPathParser.java b/boomerangPDS/src/main/java/boomerang/scope/AccessPathParser.java index 764151fc0..91056902d 100644 --- a/boomerangPDS/src/main/java/boomerang/scope/AccessPathParser.java +++ b/boomerangPDS/src/main/java/boomerang/scope/AccessPathParser.java @@ -13,15 +13,15 @@ import boomerang.util.AccessPath; import com.google.common.collect.Lists; -import com.google.common.collect.Sets; import java.util.Collection; +import java.util.LinkedHashSet; import java.util.List; import java.util.Set; public class AccessPathParser { public static Collection parseAllFromString(String value, Method m) { - Set results = Sets.newHashSet(); + Set results = new LinkedHashSet<>(); for (String v : value.split(";")) { results.add(parseAccessPathFromString(v, m)); } @@ -57,7 +57,7 @@ private static AccessPath parseAccessPathFromString(String value, Method m) { type = fieldByName.getType(); } } - return new AccessPath( new JimpleVal(base, m), (!overApproximated ? fields : Sets.newHashSet(fields))); + return new AccessPath( new JimpleVal(base, m), (!overApproximated ? fields : new LinkedHashSet(fields))); } private static Local getLocal(JimpleMethod m, String baseName) { diff --git a/boomerangPDS/src/main/java/boomerang/scope/AnalysisScope.java b/boomerangPDS/src/main/java/boomerang/scope/AnalysisScope.java index 638ea3e29..793b8756a 100644 --- a/boomerangPDS/src/main/java/boomerang/scope/AnalysisScope.java +++ b/boomerangPDS/src/main/java/boomerang/scope/AnalysisScope.java @@ -14,8 +14,8 @@ import boomerang.Query; import com.google.common.base.Stopwatch; import com.google.common.collect.Lists; -import com.google.common.collect.Sets; import java.util.Collection; +import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.Set; import org.slf4j.Logger; @@ -31,9 +31,9 @@ public AnalysisScope(CallGraph cg) { this.cg = cg; } - private final Set seeds = Sets.newHashSet(); + private final Set seeds = new LinkedHashSet<>(); - private final Collection processed = Sets.newHashSet(); + private final Collection processed = new LinkedHashSet<>(); private int statementCount; public void setScanLibraryClasses(boolean enabled) { diff --git a/boomerangPDS/src/main/java/boomerang/solver/AbstractBoomerangSolver.java b/boomerangPDS/src/main/java/boomerang/solver/AbstractBoomerangSolver.java index 5ba2f911f..8b864ce0a 100644 --- a/boomerangPDS/src/main/java/boomerang/solver/AbstractBoomerangSolver.java +++ b/boomerangPDS/src/main/java/boomerang/solver/AbstractBoomerangSolver.java @@ -32,10 +32,10 @@ import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multimap; -import com.google.common.collect.Sets; import com.google.common.collect.Table; import java.util.AbstractMap; import java.util.Collection; +import java.util.LinkedHashSet; import java.util.Map; import java.util.Map.Entry; import java.util.Set; @@ -171,7 +171,7 @@ public void synchedEmptyStackReachable( sourceNode, new WitnessListener() { final Multimap> potentialFieldCandidate = HashMultimap.create(); - final Set potentialCallCandidate = Sets.newHashSet(); + final Set potentialCallCandidate = new LinkedHashSet<>(); @Override public void fieldWitness(Transition>> t) { @@ -307,7 +307,7 @@ public void allowUnbalanced(Method callee, Statement callSite) { } protected boolean isMatchingCallSiteCalleePair(Statement callSite, Method method) { - Set callsitesOfCall = Sets.newHashSet(); + Set callsitesOfCall = new LinkedHashSet<>(); icfg.addCallerListener( new CallerListener() { @Override diff --git a/boomerangPDS/src/main/java/boomerang/solver/BackwardBoomerangSolver.java b/boomerangPDS/src/main/java/boomerang/solver/BackwardBoomerangSolver.java index f3e32a3b7..bad6d05b2 100644 --- a/boomerangPDS/src/main/java/boomerang/solver/BackwardBoomerangSolver.java +++ b/boomerangPDS/src/main/java/boomerang/solver/BackwardBoomerangSolver.java @@ -30,10 +30,10 @@ import boomerang.scope.Type; import boomerang.scope.Val; import com.google.common.collect.Multimap; -import com.google.common.collect.Sets; import de.fraunhofer.iem.Location; import java.util.AbstractMap.SimpleEntry; import java.util.Collection; +import java.util.LinkedHashSet; import java.util.Map; import java.util.Map.Entry; import java.util.Set; @@ -256,7 +256,7 @@ protected Collection computeNormalFlow(Method method, Edge currEdge, Val @Override public void applyCallSummary( Edge callSiteEdge, Val factAtSpInCallee, Edge spInCallee, Edge exitStmt, Val exitingFact) { - Set> out = Sets.newHashSet(); + Set> out = new LinkedHashSet<>(); Statement callSite = callSiteEdge.getTarget(); if (callSite.containsInvokeExpr()) { if (exitingFact.isThisLocal()) { diff --git a/boomerangPDS/src/main/java/boomerang/solver/ForwardBoomerangSolver.java b/boomerangPDS/src/main/java/boomerang/solver/ForwardBoomerangSolver.java index fa8bbb5ef..73c0dad68 100644 --- a/boomerangPDS/src/main/java/boomerang/solver/ForwardBoomerangSolver.java +++ b/boomerangPDS/src/main/java/boomerang/solver/ForwardBoomerangSolver.java @@ -29,10 +29,10 @@ import boomerang.scope.Type; import boomerang.scope.Val; import com.google.common.collect.Multimap; -import com.google.common.collect.Sets; import de.fraunhofer.iem.Location; import java.util.Collection; import java.util.Collections; +import java.util.LinkedHashSet; import java.util.Map; import java.util.Map.Entry; import java.util.Set; @@ -331,7 +331,7 @@ public void applyCallSummary( Val returnedFact) { Statement callSite = returnSiteStatement.getStart(); - Set> out = Sets.newHashSet(); + Set> out = new LinkedHashSet<>(); if (callSite.containsInvokeExpr()) { if (returnedFact.isThisLocal()) { if (callSite.getInvokeExpr().isInstanceInvokeExpr()) { diff --git a/boomerangPDS/src/main/java/boomerang/stats/AdvancedBoomerangStats.java b/boomerangPDS/src/main/java/boomerang/stats/AdvancedBoomerangStats.java index 6f04d8e88..ff9234430 100644 --- a/boomerangPDS/src/main/java/boomerang/stats/AdvancedBoomerangStats.java +++ b/boomerangPDS/src/main/java/boomerang/stats/AdvancedBoomerangStats.java @@ -26,10 +26,10 @@ import boomerang.solver.BackwardBoomerangSolver; import boomerang.solver.ForwardBoomerangSolver; import com.google.common.collect.Maps; -import com.google.common.collect.Sets; import de.fraunhofer.iem.Location; import java.util.Collection; import java.util.Comparator; +import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; import java.util.TreeMap; @@ -44,22 +44,23 @@ public class AdvancedBoomerangStats implements IBoomerangStats private final Map> queries = Maps.newHashMap(); private final Set>, W>> globalFieldTransitions = - Sets.newHashSet(); + new LinkedHashSet<>(); private int fieldTransitionCollisions; private final Set, W>> globalCallTransitions = - Sets.newHashSet(); + new LinkedHashSet<>(); private int callTransitionCollisions; - private final Set>, W>> globalFieldRules = Sets.newHashSet(); + private final Set>, W>> globalFieldRules = + new LinkedHashSet<>(); private int fieldRulesCollisions; - private final Set, W>> globalCallRules = Sets.newHashSet(); + private final Set, W>> globalCallRules = new LinkedHashSet<>(); private int callRulesCollisions; - private final Set> reachedForwardNodes = Sets.newHashSet(); + private final Set> reachedForwardNodes = new LinkedHashSet<>(); private int reachedForwardNodeCollisions; - private final Set> reachedBackwardNodes = Sets.newHashSet(); + private final Set> reachedBackwardNodes = new LinkedHashSet<>(); private int reachedBackwardNodeCollisions; - private final Set callVisitedMethods = Sets.newHashSet(); - private final Set fieldVisitedMethods = Sets.newHashSet(); + private final Set callVisitedMethods = new LinkedHashSet<>(); + private final Set fieldVisitedMethods = new LinkedHashSet<>(); private int arrayFlows; private int staticFlows; private final boolean COUNT_TOP_METHODS = false; @@ -242,7 +243,7 @@ private String topMostMethods(Map fieldMethodsRules, String sys @Override public Set getCallVisitedMethods() { - return Sets.newHashSet(callVisitedMethods); + return new LinkedHashSet(callVisitedMethods); } private String computeMetrics() { @@ -300,7 +301,7 @@ public boolean equals(Object obj) { @Override public Collection> getForwardReachesNodes() { - Set> res = Sets.newHashSet(); + Set> res = new LinkedHashSet<>(); for (Query q : queries.keySet()) { if (q instanceof ForwardQuery) res.addAll(queries.get(q).getReachedStates()); } diff --git a/boomerangPDS/src/main/java/boomerang/stats/CSVBoomerangStatsWriter.java b/boomerangPDS/src/main/java/boomerang/stats/CSVBoomerangStatsWriter.java index 98918fc84..9ae173692 100644 --- a/boomerangPDS/src/main/java/boomerang/stats/CSVBoomerangStatsWriter.java +++ b/boomerangPDS/src/main/java/boomerang/stats/CSVBoomerangStatsWriter.java @@ -28,7 +28,6 @@ import com.google.common.base.Joiner; import com.google.common.collect.Lists; import com.google.common.collect.Maps; -import com.google.common.collect.Sets; import de.fraunhofer.iem.Location; import java.io.File; import java.io.FileWriter; @@ -36,6 +35,7 @@ import java.nio.file.Files; import java.util.Collection; import java.util.Comparator; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -53,26 +53,27 @@ public class CSVBoomerangStatsWriter implements IBoomerangStat private final Map> queries = Maps.newHashMap(); private final Set>, W>> globalFieldTransitions = - Sets.newHashSet(); + new LinkedHashSet<>(); private int fieldTransitionCollisions; private final Set, W>> globalCallTransitions = - Sets.newHashSet(); + new LinkedHashSet<>(); private int callTransitionCollisions; - private final Set>, W>> globalFieldRules = Sets.newHashSet(); + private final Set>, W>> globalFieldRules = + new LinkedHashSet<>(); private int fieldRulesCollisions; - private final Set, W>> globalCallRules = Sets.newHashSet(); + private final Set, W>> globalCallRules = new LinkedHashSet<>(); private int callRulesCollisions; - private final Set> reachedForwardNodes = Sets.newHashSet(); + private final Set> reachedForwardNodes = new LinkedHashSet<>(); private int reachedForwardNodeCollisions; - private final Set> reachedBackwardNodes = Sets.newHashSet(); + private final Set> reachedBackwardNodes = new LinkedHashSet<>(); private int reachedBackwardNodeCollisions; - private final Set callVisitedMethods = Sets.newHashSet(); - private final Set fieldVisitedMethods = Sets.newHashSet(); - private final Set callVisitedStmts = Sets.newHashSet(); - private final Set fieldVisitedStmts = Sets.newHashSet(); - private final Set>> fieldGeneratedStates = Sets.newHashSet(); - private final Set> callGeneratedStates = Sets.newHashSet(); + private final Set callVisitedMethods = new LinkedHashSet<>(); + private final Set fieldVisitedMethods = new LinkedHashSet<>(); + private final Set callVisitedStmts = new LinkedHashSet<>(); + private final Set fieldVisitedStmts = new LinkedHashSet<>(); + private final Set>> fieldGeneratedStates = new LinkedHashSet<>(); + private final Set> callGeneratedStates = new LinkedHashSet<>(); private int arrayFlows; private int staticFlows; private int fieldWritePOIs; @@ -276,7 +277,7 @@ public String toString() { @Override public Set getCallVisitedMethods() { - return Sets.newHashSet(callVisitedMethods); + return new LinkedHashSet(callVisitedMethods); } private String computeMetrics() { @@ -334,7 +335,7 @@ public boolean equals(Object obj) { @Override public Collection> getForwardReachesNodes() { - Set> res = Sets.newHashSet(); + Set> res = new LinkedHashSet<>(); for (Query q : queries.keySet()) { if (q instanceof ForwardQuery) res.addAll(queries.get(q).getReachedStates()); } diff --git a/boomerangPDS/src/main/java/boomerang/stats/SimpleBoomerangStats.java b/boomerangPDS/src/main/java/boomerang/stats/SimpleBoomerangStats.java index 1316b9635..c8c5e70e1 100644 --- a/boomerangPDS/src/main/java/boomerang/stats/SimpleBoomerangStats.java +++ b/boomerangPDS/src/main/java/boomerang/stats/SimpleBoomerangStats.java @@ -24,6 +24,7 @@ import com.google.common.collect.Maps; import com.google.common.collect.Sets; import java.util.Collection; +import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; import sync.pds.solver.nodes.INode; @@ -37,8 +38,8 @@ public class SimpleBoomerangStats implements IBoomerangStats { private final Map> queries = Maps.newHashMap(); - private final Set callVisitedMethods = Sets.newHashSet(); - private final Set fieldVisitedMethods = Sets.newHashSet(); + private final Set callVisitedMethods = new LinkedHashSet<>(); + private final Set fieldVisitedMethods = new LinkedHashSet<>(); @Override public void registerSolver(Query key, final AbstractBoomerangSolver solver) { @@ -94,7 +95,7 @@ public String toString() { @Override public Collection> getForwardReachesNodes() { - Set> res = Sets.newHashSet(); + Set> res = new LinkedHashSet<>(); for (Query q : queries.keySet()) { if (q instanceof ForwardQuery) res.addAll(queries.get(q).getReachedStates()); } @@ -103,7 +104,7 @@ public Collection> getForwardReachesNodes() { @Override public Set getCallVisitedMethods() { - return Sets.newHashSet(callVisitedMethods); + return new LinkedHashSet(callVisitedMethods); } @Override diff --git a/boomerangPDS/src/main/java/boomerang/weights/PathConditionWeight.java b/boomerangPDS/src/main/java/boomerang/weights/PathConditionWeight.java index 7b7d3d990..59fb651b4 100644 --- a/boomerangPDS/src/main/java/boomerang/weights/PathConditionWeight.java +++ b/boomerangPDS/src/main/java/boomerang/weights/PathConditionWeight.java @@ -15,7 +15,7 @@ import boomerang.scope.Statement; import boomerang.scope.Val; import com.google.common.collect.Maps; -import com.google.common.collect.Sets; +import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; import wpds.impl.Weight; @@ -25,7 +25,7 @@ public class PathConditionWeight extends Weight { private static PathConditionWeight one; private Map ifStatements = Maps.newHashMap(); private Map variableToValue = Maps.newHashMap(); - private Set returnVals = Sets.newHashSet(); + private Set returnVals = new LinkedHashSet<>(); private Map calleeToCallSite = Maps.newHashMap(); private String rep; @@ -115,7 +115,7 @@ public Weight extendWith(Weight o) { } } newVals.putAll(returnToAssignedVariableMap); - Set newReturnVals = Sets.newHashSet(returnVals); + Set newReturnVals = new LinkedHashSet(returnVals); newReturnVals.addAll(other.returnVals); Map calleeToCallSiteMapping = Maps.newHashMap(calleeToCallSite); calleeToCallSiteMapping.putAll(other.calleeToCallSite); @@ -179,7 +179,7 @@ public Weight combineWith(Weight o) { } } newVals.putAll(returnToAssignedVariableMap); - Set newReturnVals = Sets.newHashSet(returnVals); + Set newReturnVals = new LinkedHashSet(returnVals); newReturnVals.addAll(other.returnVals); Map calleeToCallSiteMapping = Maps.newHashMap(calleeToCallSite); calleeToCallSiteMapping.putAll(other.calleeToCallSite); diff --git a/boomerangPDS/src/main/java/boomerang/weights/PathTrackingWeight.java b/boomerangPDS/src/main/java/boomerang/weights/PathTrackingWeight.java index d8ffa378a..63e3ed0f5 100644 --- a/boomerangPDS/src/main/java/boomerang/weights/PathTrackingWeight.java +++ b/boomerangPDS/src/main/java/boomerang/weights/PathTrackingWeight.java @@ -14,7 +14,6 @@ import boomerang.scope.ControlFlowGraph.Edge; import boomerang.scope.Val; import com.google.common.collect.Lists; -import com.google.common.collect.Sets; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; @@ -34,7 +33,7 @@ public class PathTrackingWeight extends Weight { /** * This set keeps track of all statement along all paths that use an alias from source to sink. */ - private Set>> allPathWitness = Sets.newHashSet(); + private Set>> allPathWitness = new LinkedHashSet<>(); private String rep; @@ -75,7 +74,7 @@ public Weight extendWith(Weight o) { Set>> newAllPathStatements = new LinkedHashSet<>(); for (LinkedHashSet> pathPrefix : allPathWitness) { for (LinkedHashSet> pathSuffix : other.allPathWitness) { - LinkedHashSet> combinedPath = Sets.newLinkedHashSet(); + LinkedHashSet> combinedPath = new LinkedHashSet<>(); combinedPath.addAll(pathPrefix); combinedPath.addAll(pathSuffix); newAllPathStatements.add(combinedPath); @@ -83,14 +82,14 @@ public Weight extendWith(Weight o) { } if (allPathWitness.isEmpty()) { for (LinkedHashSet> pathSuffix : other.allPathWitness) { - LinkedHashSet> combinedPath = Sets.newLinkedHashSet(); + LinkedHashSet> combinedPath = new LinkedHashSet<>(); combinedPath.addAll(pathSuffix); newAllPathStatements.add(combinedPath); } } if (other.allPathWitness.isEmpty()) { for (LinkedHashSet> pathSuffix : allPathWitness) { - LinkedHashSet> combinedPath = Sets.newLinkedHashSet(); + LinkedHashSet> combinedPath = new LinkedHashSet<>(); combinedPath.addAll(pathSuffix); newAllPathStatements.add(combinedPath); } @@ -106,12 +105,12 @@ public Weight combineWith(Weight o) { PathTrackingWeight other = (PathTrackingWeight) o; Set>> newAllPathStatements = new LinkedHashSet<>(); for (LinkedHashSet> pathPrefix : allPathWitness) { - LinkedHashSet> combinedPath = Sets.newLinkedHashSet(); + LinkedHashSet> combinedPath = new LinkedHashSet<>(); combinedPath.addAll(pathPrefix); newAllPathStatements.add(combinedPath); } for (LinkedHashSet> pathPrefix : other.allPathWitness) { - LinkedHashSet> combinedPath = Sets.newLinkedHashSet(); + LinkedHashSet> combinedPath = new LinkedHashSet<>(); combinedPath.addAll(pathPrefix); newAllPathStatements.add(combinedPath); } @@ -161,6 +160,6 @@ public List> getShortestPathWitness() { } public Set>> getAllPathWitness() { - return Sets.newHashSet(allPathWitness); + return new LinkedHashSet<>(allPathWitness); } } diff --git a/boomerangPDS/src/main/resources/simplelogger.properties b/boomerangPDS/src/main/resources/simplelogger.properties new file mode 100644 index 000000000..716158ec1 --- /dev/null +++ b/boomerangPDS/src/main/resources/simplelogger.properties @@ -0,0 +1,4 @@ +org.slf4j.simpleLogger.defaultLogLevel=trace +org.slf4j.simpleLogger.logFile=System.out +org.slf4j.simpleLogger.showDateTime=true +org.slf4j.simpleLogger.dateTimeFormat=yyyy-MM-dd HH:mm:ss diff --git a/boomerangPDS/src/test/java/boomerang/guided/DemandDrivenGuidedAnalysisTest.java b/boomerangPDS/src/test/java/boomerang/guided/DemandDrivenGuidedAnalysisTest.java index 6907073f0..556b5eb98 100644 --- a/boomerangPDS/src/test/java/boomerang/guided/DemandDrivenGuidedAnalysisTest.java +++ b/boomerangPDS/src/test/java/boomerang/guided/DemandDrivenGuidedAnalysisTest.java @@ -45,7 +45,6 @@ import boomerang.scope.Method; import boomerang.scope.Statement; import boomerang.scope.Val; -import com.google.common.collect.Sets; import java.io.Serializable; import java.util.List; import java.util.Optional; @@ -579,7 +578,7 @@ protected void runAnalysis( .map(x -> (x.isIntConstant() ? x.getIntValue() : x.getStringValue())) .collect(Collectors.toSet()); - Assert.assertEquals(Sets.newHashSet(expectedValues), collect); + Assert.assertEquals(Set.of(expectedValues), collect); } private IAllocationSite allocationSite() { diff --git a/boomerangPDS/src/test/java/test/core/AbstractBoomerangTest.java b/boomerangPDS/src/test/java/test/core/AbstractBoomerangTest.java index a462bc93b..d9aa7fdd0 100644 --- a/boomerangPDS/src/test/java/test/core/AbstractBoomerangTest.java +++ b/boomerangPDS/src/test/java/test/core/AbstractBoomerangTest.java @@ -33,11 +33,11 @@ import com.google.common.base.Joiner; import com.google.common.base.Stopwatch; import com.google.common.collect.Lists; -import com.google.common.collect.Sets; import java.time.Duration; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.Set; import java.util.stream.Collectors; import org.junit.Assert; @@ -81,8 +81,8 @@ public class AbstractBoomerangTest extends TestingFramework { private Collection expectedAllocationSites; private Collection> explicitlyUnexpectedAllocationSites; protected Collection queryForCallSites; - protected Collection unsoundErrors = Sets.newHashSet(); - protected Collection imprecisionErrors = Sets.newHashSet(); + protected Collection unsoundErrors = new LinkedHashSet<>(); + protected Collection imprecisionErrors = new LinkedHashSet<>(); private static Duration globalQueryTime = Duration.ofMillis(0); protected int analysisTimeout = 3000 * 1000; @@ -153,7 +153,7 @@ private void analyzeWithCallGraph(FrameworkScope frameworkScope) { } private void runWholeProgram(FrameworkScope frameworkScope) { - final Set> results = Sets.newHashSet(); + final Set> results = new LinkedHashSet<>(); BoomerangOptions options = BoomerangOptions.builder().withAnalysisTimeout(analysisTimeout).build(); WholeProgramBoomerang solver = @@ -266,7 +266,7 @@ private ArrayList parse(Val arg) { private Set> runQuery( FrameworkScope frameworkScope, Collection queries) { - final Set> results = Sets.newHashSet(); + final Set> results = new LinkedHashSet<>(); for (final Query query : queries) { BoomerangOptions options = createBoomerangOptions(); @@ -346,7 +346,7 @@ private void compareQuery( } private void checkContainsAllExpectedAccessPath(Set allAliases) { - HashSet expected = Sets.newHashSet(queryDetector.expectedAccessPaths); + HashSet expected = new LinkedHashSet(queryDetector.expectedAccessPaths); expected.removeAll(allAliases); if (!expected.isEmpty()) { Assert.fail("Did not find all access path! " + expected); diff --git a/boomerangPDS/src/test/java/test/core/MultiQueryBoomerangTest.java b/boomerangPDS/src/test/java/test/core/MultiQueryBoomerangTest.java index dce71ad1c..db5a75b24 100644 --- a/boomerangPDS/src/test/java/test/core/MultiQueryBoomerangTest.java +++ b/boomerangPDS/src/test/java/test/core/MultiQueryBoomerangTest.java @@ -23,9 +23,9 @@ import com.google.common.base.Joiner; import com.google.common.collect.HashMultimap; import com.google.common.collect.Multimap; -import com.google.common.collect.Sets; import java.util.Collection; import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.Map.Entry; import java.util.concurrent.TimeUnit; import org.junit.Assert; @@ -44,8 +44,8 @@ public class MultiQueryBoomerangTest extends TestingFramework { protected Collection queryForCallSites; protected Multimap expectedAllocsForQuery = HashMultimap.create(); - protected Collection unsoundErrors = Sets.newHashSet(); - protected Collection imprecisionErrors = Sets.newHashSet(); + protected Collection unsoundErrors = new LinkedHashSet<>(); + protected Collection imprecisionErrors = new LinkedHashSet<>(); protected int analysisTimeout = 300 * 1000; diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalArrayRef.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalArrayRef.scala index 30b04a3a8..10aa442ff 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalArrayRef.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalArrayRef.scala @@ -3,16 +3,10 @@ package boomerang.scope.opal.tac import boomerang.scope._ import boomerang.scope.opal.transformation.TacLocal import org.opalj.br.ObjectType -import org.opalj.tac.{DUVar, DVar, Expr, IdBasedVar, UVar, Var} -import org.opalj.value.ValueInformation import java.util.Objects -class OpalArrayRef(val arrayRef: Expr[TacLocal], val index: Int, method: OpalMethod, unbalanced: ControlFlowGraph.Edge = null) extends Val(method, unbalanced) { - - if (!arrayRef.isVar) { - throw new RuntimeException("Array Ref has to be a variable") - } +class OpalArrayRef(val arrayRef: TacLocal, val index: Int, method: OpalMethod, unbalanced: ControlFlowGraph.Edge = null) extends Val(method, unbalanced) { // TODO Type override def getType: Type = OpalType(ObjectType.Array) @@ -70,18 +64,12 @@ class OpalArrayRef(val arrayRef: Expr[TacLocal], val index: Int, method: OpalMet override def getLongValue: Long = throw new RuntimeException("Array Value is not a long constant") override def getArrayBase: Pair[Val, Integer] = { - val base = new OpalLocal(arrayRef.asVar, method) + val base = new OpalLocal(arrayRef, method) new Pair[Val, Integer](base, index) } - override def getVariableName: String = { - arrayRef match { - case dVar: DVar[_] => s"var(D)[$index]" // TODO insert origin - case uVar: UVar[_] => s"var(${uVar.definedBy.head})[$index]" - case _ => arrayRef.toString - } - } + override def getVariableName: String = s"$arrayRef[$index]" override def hashCode: Int = Objects.hash(super.hashCode(), arrayRef, index) diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalLocal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalLocal.scala index 3463f8170..43a671ba7 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalLocal.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalLocal.scala @@ -95,7 +95,7 @@ class OpalLocal(val delegate: Var[TacLocal], method: OpalMethod, unbalanced: Con override def getVariableName: String = delegate.asVar.name - override def hashCode: Int = Objects.hash(delegate.asVar.id) + override def hashCode: Int = Objects.hash(delegate.asVar) override def equals(other: Any): Boolean = other match { case that: OpalLocal => super.equals(that) && this.delegate == that.delegate diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala index de674fc50..c63f02f16 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala @@ -131,11 +131,11 @@ class OpalStatement(val delegate: Stmt[TacLocal], m: OpalMethod) extends Stateme val base = delegate.asArrayStore.arrayRef val indexValue = delegate.asArrayStore.index - if (!indexValue.isVar) return new OpalArrayRef(base, -1, m) - //if (!indexValue.asVar.value.isPrimitiveValue) return new OpalArrayRef(base, -1, m) + if (indexValue.isIntConst) { + return new OpalArrayRef(base.asVar, indexValue.asIntConst.value, m) + } - //val index = indexValue.asVar.value.asPrimitiveValue.asConstantInteger.intValue() - return new OpalArrayRef(base, -1, m) + return new OpalArrayRef(base.asVar, -1, m) } } @@ -157,11 +157,11 @@ class OpalStatement(val delegate: Stmt[TacLocal], m: OpalMethod) extends Stateme val base = rightExpr.asArrayLoad.arrayRef val indexValue = rightExpr.asArrayLoad.index - if (!indexValue.isVar) return new OpalArrayRef(base, -1, m) - //if (!indexValue.asVar.value.isPrimitiveValue) return new OpalArrayRef(base, -1, m) + if (indexValue.isIntConst) { + return new OpalArrayRef(base.asVar, indexValue.asIntConst.value, m) + } - //val index = indexValue.asVar.value.asPrimitiveValue.asConstantInteger.intValue() - return new OpalArrayRef(base, -1, m) + return new OpalArrayRef(base.asVar, -1, m) } if (rightExpr.isVar) { @@ -182,9 +182,13 @@ class OpalStatement(val delegate: Stmt[TacLocal], m: OpalMethod) extends Stateme } if (isArrayStore) { - // TODO Distinguish between constant and variable val arrayStore = delegate.asArrayStore - return new OpalLocal(arrayStore.arrayRef.asVar, m) + + if (arrayStore.value.isVar) { + return new OpalLocal(arrayStore.value.asVar, m) + } else { + return new OpalVal(arrayStore.value, m) + } } } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatementFormatter.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatementFormatter.scala index 31021ec44..d34da37c9 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatementFormatter.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatementFormatter.scala @@ -23,14 +23,16 @@ object OpalStatementFormatter { if (stmt.isAssignStmt) { if (delegate.isAssignment) { - if (stmt.isFieldStore) { - return s"${stmt.getLeftOp} = ${stmt.getFieldStore.getX}.${stmt.getFieldStore.getY}" - } else if (stmt.isArrayStore) { - val base = stmt.getArrayBase - return s"${base.getX.getVariableName}[${base.getY}] = ${stmt.getRightOp}" - } else { - return s"${stmt.getLeftOp} = ${stmt.getRightOp}" - } + return s"${stmt.getLeftOp} = ${stmt.getRightOp}" + } + + if (stmt.isFieldStore) { + return s"${stmt.getLeftOp} = ${stmt.getFieldStore.getX}.${stmt.getFieldStore.getY}" + } + + if (stmt.isArrayStore) { + val base = stmt.getArrayBase + return s"${base.getX.getVariableName}[${base.getY}] = ${stmt.getRightOp}" } } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacBodyBuilder.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacBodyBuilder.scala index eff74b099..bfd5ca7db 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacBodyBuilder.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacBodyBuilder.scala @@ -1,7 +1,7 @@ package boomerang.scope.opal.transformation import boomerang.scope.opal.transformation.stack.OperandStackBuilder -import boomerang.scope.opal.transformation.transformer.{InlineLocalTransformer, LocalTransformer, NopTransformer, NullifyFieldsTransformer} +import boomerang.scope.opal.transformation.transformer.{InlineLocalTransformer, LocalPropagationTransformer, LocalTransformer, NopTransformer, NullifyFieldsTransformer} import org.opalj.ai.domain.l0.PrimitiveTACAIDomain import org.opalj.br.Method import org.opalj.br.analyses.Project @@ -16,7 +16,15 @@ object TacBodyBuilder { val domain = new PrimitiveTACAIDomain(project.classHierarchy, method) val localTransformedTac = LocalTransformer(method, tacNaive, stackHandler, domain) - val inlinedTac = InlineLocalTransformer(localTransformedTac, stackHandler) + assert(tacNaive.stmts.length == localTransformedTac.length, "Wrong transformation") + + val inlinedTac = InlineLocalTransformer(localTransformedTac, tacNaive.cfg) + assert(tacNaive.stmts.length == inlinedTac.length, "Wrong transformation") + + val propagatedTac = LocalPropagationTransformer(inlinedTac, stackHandler) + assert(tacNaive.stmts.length == propagatedTac.length, "Wrong transformation") + + // TODO Local propagation // Update the CFG val cfg = CFGFactory(method, project.classHierarchy) @@ -24,13 +32,13 @@ object TacBodyBuilder { throw new RuntimeException("Could not compute CFG for method " + method.name) } - val tacCfg = cfg.get.mapPCsToIndexes[Stmt[TacLocal], TACStmts[TacLocal]](TACStmts(inlinedTac), tacNaive.pcToIndex, i => i, inlinedTac.length) + val tacCfg = cfg.get.mapPCsToIndexes[Stmt[TacLocal], TACStmts[TacLocal]](TACStmts(propagatedTac), tacNaive.pcToIndex, i => i, propagatedTac.length) val exceptionHandlers = tacNaive.exceptionHandlers.map(eh => eh.handlerPC).toArray - val stmtGraph = StmtGraph(inlinedTac, tacCfg, tacNaive.pcToIndex, exceptionHandlers) + val stmtGraph = StmtGraph(propagatedTac, tacCfg, tacNaive.pcToIndex, exceptionHandlers) val nopStmtGraph = NopTransformer(stmtGraph) - val nullifiedStmtGraph = transformer.NullifyFieldsTransformer(method, nopStmtGraph) + val nullifiedStmtGraph = NullifyFieldsTransformer(method, nopStmtGraph) new BoomerangTACode(nullifiedStmtGraph) } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackBuilder.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackBuilder.scala index 7660664df..394442ae8 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackBuilder.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackBuilder.scala @@ -117,9 +117,9 @@ object OperandStackBuilder { schedule(pcOfNextStatement(pc), stack) case ArrayStore(pc, arrayRef: IdBasedVar, index: IdBasedVar, value: IdBasedVar) => - stack.pop(arrayRef) - stack.pop(index) stack.pop(value) + stack.pop(index) + stack.pop(arrayRef) schedule(pcOfNextStatement(pc), stack) case Throw(_, exception: IdBasedVar) => diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/InlineLocalTransformer.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/InlineLocalTransformer.scala index 703a72daa..31bf69cc4 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/InlineLocalTransformer.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/InlineLocalTransformer.scala @@ -1,15 +1,91 @@ package boomerang.scope.opal.transformation.transformer -import boomerang.scope.opal.transformation.stack.OperandStackHandler import boomerang.scope.opal.transformation.{RegisterLocal, StackLocal, TacLocal} -import org.opalj.collection.immutable.IntIntPair +import org.opalj.br.cfg.CFG import org.opalj.tac._ +import scala.collection.mutable + object InlineLocalTransformer { - def apply(code: Array[Stmt[TacLocal]], stackHandler: OperandStackHandler): Array[Stmt[TacLocal]] = { + def apply(code: Array[Stmt[TacLocal]], cfg: CFG[Stmt[IdBasedVar], TACStmts[IdBasedVar]]): Array[Stmt[TacLocal]] = { val statements = code.map(identity) + val bbs = cfg.allBBs + bbs.withFilter(bb => bb.startPC < bb.endPC).foreach(bb => { + val localCache = mutable.Map.empty[TacLocal, Expr[TacLocal]] + val localDefSites = mutable.Map.empty[TacLocal, (Int, Int)] + + var index = bb.startPC + while (index <= bb.endPC) { + code(index) match { + case Assignment(pc, targetVar: StackLocal, c @ (_: SimpleValueConst | _: FunctionCall[TacLocal] | _: GetField[TacLocal] | _: GetStatic)) => + localCache.put(targetVar, c) + localDefSites.put(targetVar, (index, pc)) + case Assignment(pc, targetVar: RegisterLocal, rightVar: StackLocal) => + /*if (localCache.contains(rightVar)) { + val localExpr = localCache(rightVar) + statements(index) = Assignment(pc, targetVar, localExpr) + + val localDefSite = localDefSites.getOrElse(rightVar, throw new RuntimeException("Def sites not consistent")) + statements(localDefSite._1) = Nop(localDefSite._2) + }*/ + case Assignment(pc, targetVar: StackLocal, expr) => + expr match { + case NewArray(arrPc, counts, arrayType) => + var countDefSites = List.empty[(Int, Int)] + + val newCounts = counts.map(c => { + if (c.isVar && localCache.contains(c.asVar)) { + val localExpr = localCache(c.asVar) + + if (localExpr.isIntConst) { + val countDefSite = localDefSites.getOrElse(c.asVar, throw new RuntimeException("Def sites not consistent")) + countDefSites = countDefSites :+ countDefSite + + localExpr + } else { + c + } + } else { + c + } + }) + + statements(index) = Assignment(pc, targetVar, NewArray(arrPc, newCounts, arrayType)) + countDefSites.foreach(defSite => statements(defSite._1) = Nop(defSite._2)) + case ArrayLoad(arrPc, arrayIndex: StackLocal, arrayRef) => + if (localCache.contains(arrayIndex)) { + val localExpr = localCache(arrayIndex) + + if (localExpr.isIntConst) { + statements(index) = Assignment(pc, targetVar, ArrayLoad(arrPc, localExpr, arrayRef)) + + val localDefSite = localDefSites.getOrElse(arrayIndex, throw new RuntimeException("Def sites not consistent")) + statements(localDefSite._1) = Nop(localDefSite._2) + } + } + case _ => + } + case ArrayStore(pc, arrayRef, arrayIndex: StackLocal, value) => + if (localCache.contains(arrayIndex)) { + val localExpr = localCache(arrayIndex) + + if (localExpr.isIntConst) { + // TODO Also inline value if it is a simple constant + statements(index) = ArrayStore(pc, arrayRef, localExpr, value) + + val localDefSite = localDefSites.getOrElse(arrayIndex, throw new RuntimeException("Def sites not consistent")) + statements(localDefSite._1) = Nop(localDefSite._2) + } + } + case _ => + } + + index += 1 + } + }) + val max = code.length - 1 Range(0, max).foreach(i => { statements(i) match { @@ -21,7 +97,7 @@ object InlineLocalTransformer { * becomes * r = */ - case Assignment(pc, targetVar: StackLocal, c @ (_: SimpleValueConst | _: FunctionCall[TacLocal] | _: GetField[TacLocal] | _: GetStatic)) => + case Assignment(pc, targetVar: StackLocal, c @ (_: SimpleValueConst | _: FunctionCall[TacLocal] | _: NewArray[TacLocal] | _: ArrayLoad[TacLocal] | _: GetField[TacLocal] | _: GetStatic)) => statements(i + 1) match { case Assignment(nextPc, nextTargetVar: RegisterLocal, `targetVar`) => statements(i) = Nop(pc) @@ -32,215 +108,33 @@ object InlineLocalTransformer { } }) - Range(0, max).foreach(i => { + /*Range(0, max).foreach(i => { statements(i) match { - // If we have an assignment $s = r, we replace $s with r in all following statements - case Assignment(pc, stackLocal: StackLocal, registerLocal: RegisterLocal) => - if (!stackHandler.isBranchedOperand(pc, stackLocal.id)) { - Range.inclusive(i + 1, max).foreach(j => { - val currStmt = statements(j) - statements(j) = updateStatementWithLocal(currStmt, stackLocal, registerLocal) - }) - - statements(i) = Nop(pc) - } + case ArrayStore(pc, arrayRef, index, value) => + val allocSiteIndex = findArrayIndexAllocSite(i, index) + val allocSiteStmt = statements(i) + + //statements(allocSiteIndex) = Nop(allocSiteStmt.pc) + //statements(i) = ArrayStore(pc, arrayRef, allocSiteStmt.asAssignment) case _ => } }) - def updateStatementWithLocal(stmt: Stmt[TacLocal], stackLocal: StackLocal, registerLocal: RegisterLocal): Stmt[TacLocal] = { - stmt.astID match { - case If.ASTID => - val ifStmt = stmt.asIf - - val left = updateExpressionWithLocal(ifStmt.left, stackLocal, registerLocal) - val right = updateExpressionWithLocal(ifStmt.left, stackLocal, registerLocal) - - return If(ifStmt.pc, left, ifStmt.condition, right, ifStmt.targetStmt) - case Switch.ASTID => - val switchStmt = stmt.asSwitch - val index = updateExpressionWithLocal(switchStmt.index, stackLocal, registerLocal) - - return Switch(switchStmt.pc, switchStmt.defaultStmt, index, switchStmt.caseStmts.map(p => IntIntPair(-1, p))) - case Assignment.ASTID => - val assignStmt = stmt.asAssignment - val targetVar = updateExpressionWithLocal(assignStmt.targetVar, stackLocal, registerLocal) - val expr = updateExpressionWithLocal(assignStmt.expr, stackLocal, registerLocal) - - return Assignment(assignStmt.pc, targetVar.asVar, expr) - case ReturnValue.ASTID => - val expr = updateExpressionWithLocal(stmt.asReturnValue.expr, stackLocal, registerLocal) - - return ReturnValue(stmt.pc, expr) - case MonitorEnter.ASTID => - val objRef = updateExpressionWithLocal(stmt.asMonitorEnter.objRef, stackLocal, registerLocal) - - return MonitorEnter(stmt.pc, objRef) - case MonitorExit.ASTID => - val objRef = updateExpressionWithLocal(stmt.asMonitorExit.objRef, stackLocal, registerLocal) - - return MonitorExit(stmt.pc, objRef) - case ArrayStore.ASTID => - val arrayStore = stmt.asArrayStore - - val arrayRef = updateExpressionWithLocal(arrayStore.arrayRef, stackLocal, registerLocal) - val index = updateExpressionWithLocal(arrayStore.index, stackLocal, registerLocal) - val value = updateExpressionWithLocal(arrayStore.value, stackLocal, registerLocal) - - return ArrayStore(arrayStore.pc, arrayRef, index, value) - case Throw.ASTID => - val throwStmt = stmt.asThrow - val exception = updateExpressionWithLocal(throwStmt.exception, stackLocal, registerLocal) - - return Throw(throwStmt.pc, exception) - case PutStatic.ASTID => - - val putStatic = stmt.asPutStatic - val value = updateExpressionWithLocal(putStatic.value, stackLocal, registerLocal) - - return PutStatic(putStatic.pc, putStatic.declaringClass, putStatic.name, putStatic.declaredFieldType, value) - case PutField.ASTID => - - val putField = stmt.asPutField - - val objRef = updateExpressionWithLocal(putField.objRef, stackLocal, registerLocal) - val value = updateExpressionWithLocal(putField.value, stackLocal, registerLocal) - - return PutField(putField.pc, putField.declaringClass, putField.name, putField.declaredFieldType, objRef, value) - case NonVirtualMethodCall.ASTID => - val methodCall = stmt.asNonVirtualMethodCall - - val baseLocal = updateExpressionWithLocal(methodCall.receiver, stackLocal, registerLocal) - val paramLocals = methodCall.params.map(p => updateExpressionWithLocal(p, stackLocal, registerLocal)) - - return NonVirtualMethodCall(methodCall.pc, methodCall.declaringClass, methodCall.isInterface, methodCall.name, methodCall.descriptor, baseLocal, paramLocals) - case VirtualMethodCall.ASTID => - val methodCall = stmt.asVirtualMethodCall - - val baseLocal = updateExpressionWithLocal(methodCall.receiver, stackLocal, registerLocal) - val paramLocals = methodCall.params.map(p => updateExpressionWithLocal(p, stackLocal, registerLocal)) - - return VirtualMethodCall(methodCall.pc, methodCall.declaringClass, methodCall.isInterface, methodCall.name, methodCall.descriptor, baseLocal, paramLocals) - case StaticMethodCall.ASTID => - val methodCall = stmt.asStaticMethodCall - val params = methodCall.params.map(p => updateExpressionWithLocal(p, stackLocal, registerLocal)) - - return StaticMethodCall(methodCall.pc, methodCall.declaringClass, methodCall.isInterface, methodCall.name, methodCall.descriptor, params) - case InvokedynamicMethodCall.ASTID => - val methodCall = stmt.asInvokedynamicMethodCall - val params = methodCall.params.map(p => updateExpressionWithLocal(p, stackLocal, registerLocal)) + def findArrayIndexAllocSite(index: Int, expr: Expr[TacLocal]): Int = { + Range(index, 0, -1).foreach(i => { + val currStmt = statements(i) - return InvokedynamicMethodCall(methodCall.pc, methodCall.bootstrapMethod, methodCall.name, methodCall.descriptor, params) - case ExprStmt.ASTID => - val expr = updateExpressionWithLocal(stmt.asExprStmt.expr, stackLocal, registerLocal) + if (currStmt.isAssignment) { + val assignStmt = currStmt.asAssignment - return ExprStmt(stmt.pc, expr) - case Checkcast.ASTID => - val castExpr = stmt.asCheckcast - val value = updateExpressionWithLocal(castExpr.value, stackLocal, registerLocal) - - return Checkcast(castExpr.pc, value, castExpr.cmpTpe) - case _ => return stmt - } - - throw new RuntimeException("Could not update statement: " + stmt) - } - - def updateExpressionWithLocal(expr: Expr[TacLocal], stackLocal: StackLocal, registerLocal: RegisterLocal): Expr[TacLocal] = { - if (expr.isVar) { - if (expr.asVar.isRegisterLocal) return expr - - // Replace stack local with register local - if (expr.asVar.isStackLocal && expr.asVar == stackLocal) { - return registerLocal - } else { - return expr + if (assignStmt.targetVar == expr && assignStmt.expr.isIntConst) { + return i + } } - } - - expr.astID match { - case InstanceOf.ASTID => - val instanceOf = expr.asInstanceOf - val value = updateExpressionWithLocal(instanceOf.value, stackLocal, registerLocal) - - return InstanceOf(instanceOf.pc, value, instanceOf.cmpTpe) - case Compare.ASTID => - val compareExpr = expr.asCompare - - val leftLocal = updateExpressionWithLocal(compareExpr.left, stackLocal, registerLocal) - val rightLocal = updateExpressionWithLocal(compareExpr.right, stackLocal, registerLocal) - - return Compare(compareExpr.pc, leftLocal, compareExpr.condition, rightLocal) - case BinaryExpr.ASTID => - val binaryExpr = expr.asBinaryExpr - - val left = updateExpressionWithLocal(binaryExpr.left, stackLocal, registerLocal) - val right = updateExpressionWithLocal(binaryExpr.right, stackLocal, registerLocal) - - return BinaryExpr(binaryExpr.pc, binaryExpr.cTpe, binaryExpr.op, left, right) - case PrefixExpr.ASTID => - val prefixExpr = expr.asPrefixExpr - val operand = updateExpressionWithLocal(prefixExpr.operand, stackLocal, registerLocal) - - return PrefixExpr(prefixExpr.pc, prefixExpr.cTpe, prefixExpr.op, operand) - case PrimitiveTypecastExpr.ASTID => - val primitiveTypecastExpr = expr.asPrimitiveTypeCastExpr - val operand = updateExpressionWithLocal(primitiveTypecastExpr.operand, stackLocal, registerLocal) - - return PrimitiveTypecastExpr(primitiveTypecastExpr.pc, primitiveTypecastExpr.targetTpe, operand) - case NewArray.ASTID => - val newArray = expr.asNewArray - val counts = newArray.counts.map(c => updateExpressionWithLocal(c, stackLocal, registerLocal)) - - return NewArray(newArray.pc, counts, newArray.tpe) - case ArrayLoad.ASTID => - val arrayLoad = expr.asArrayLoad - - val index = updateExpressionWithLocal(arrayLoad.index, stackLocal, registerLocal) - val arrayRef = updateExpressionWithLocal(arrayLoad.arrayRef, stackLocal, registerLocal) - - return ArrayLoad(arrayLoad.pc, index, arrayRef) - case ArrayLength.ASTID => - val arrayLength = expr.asArrayLength - val arrayRef = updateExpressionWithLocal(arrayLength.arrayRef, stackLocal, registerLocal) - - return ArrayLength(arrayLength.pc, arrayRef) - case GetField.ASTID => - val getField = expr.asGetField - val objRef = updateExpressionWithLocal(getField.objRef, stackLocal, registerLocal) - - return GetField(getField.pc, getField.declaringClass, getField.name, getField.declaredFieldType, objRef) - case InvokedynamicFunctionCall.ASTID => - val functionCall = expr.asInvokedynamicFunctionCall - val params = functionCall.params.map(p => updateExpressionWithLocal(p, stackLocal, registerLocal)) - - return InvokedynamicFunctionCall(functionCall.pc, functionCall.bootstrapMethod, functionCall.name, functionCall.descriptor, params) - case NonVirtualFunctionCall.ASTID => - val functionCall = expr.asNonVirtualFunctionCall - - val base = updateExpressionWithLocal(functionCall.receiver, stackLocal, registerLocal) - val params = functionCall.params.map(p => updateExpressionWithLocal(p, stackLocal, registerLocal)) - - return NonVirtualFunctionCall(functionCall.pc, functionCall.declaringClass, functionCall.isInterface, functionCall.name, functionCall.descriptor, base, params) - case VirtualFunctionCall.ASTID => - val functionCall = expr.asVirtualFunctionCall - - val base = updateExpressionWithLocal(functionCall.receiver, stackLocal, registerLocal) - val params = functionCall.params.map(p => updateExpressionWithLocal(p, stackLocal, registerLocal)) - - return VirtualFunctionCall(functionCall.pc, functionCall.declaringClass, functionCall.isInterface, functionCall.name, functionCall.descriptor, base, params) - case StaticFunctionCall.ASTID => - val functionCall = expr.asStaticFunctionCall - - val params = functionCall.params - val paramLocals = params.map(p => updateExpressionWithLocal(p, stackLocal, registerLocal)) - - return StaticFunctionCall(functionCall.pc, functionCall.declaringClass, functionCall.isInterface, functionCall.name, functionCall.descriptor, paramLocals) - case _ => return expr - } + }) - throw new RuntimeException("Could not update expression: " + expr) - } + -1 + }*/ statements } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/LocalPropagationTransformer.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/LocalPropagationTransformer.scala new file mode 100644 index 000000000..4efb5a8cd --- /dev/null +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/LocalPropagationTransformer.scala @@ -0,0 +1,226 @@ +package boomerang.scope.opal.transformation.transformer + +import boomerang.scope.opal.transformation.{RegisterLocal, StackLocal, TacLocal} +import boomerang.scope.opal.transformation.stack.OperandStackHandler +import org.opalj.collection.immutable.IntIntPair +import org.opalj.tac.{ArrayLength, ArrayLoad, ArrayStore, Assignment, BinaryExpr, Checkcast, Compare, Expr, ExprStmt, GetField, If, InstanceOf, InvokedynamicFunctionCall, InvokedynamicMethodCall, MonitorEnter, MonitorExit, NewArray, NonVirtualFunctionCall, NonVirtualMethodCall, Nop, PrefixExpr, PrimitiveTypecastExpr, PutField, PutStatic, ReturnValue, StaticFunctionCall, StaticMethodCall, Stmt, Switch, Throw, VirtualFunctionCall, VirtualMethodCall} + +object LocalPropagationTransformer { + + def apply(code: Array[Stmt[TacLocal]], stackHandler: OperandStackHandler): Array[Stmt[TacLocal]] = { + val statements = code.map(identity) + + val max = code.length - 1 + Range(0, max).foreach(i => { + statements(i) match { + // If we have an assignment $s = r, we replace $s with r in all following statements + case Assignment(pc, stackLocal: StackLocal, registerLocal: RegisterLocal) => + if (!stackHandler.isBranchedOperand(pc, stackLocal.id)) { + Range.inclusive(i + 1, max).foreach(j => { + val currStmt = statements(j) + statements(j) = updateStatementWithLocal(currStmt, stackLocal, registerLocal) + }) + + statements(i) = Nop(pc) + } + case _ => + } + }) + + def updateStatementWithLocal(stmt: Stmt[TacLocal], stackLocal: StackLocal, registerLocal: RegisterLocal): Stmt[TacLocal] = { + stmt.astID match { + case If.ASTID => + val ifStmt = stmt.asIf + + val left = updateExpressionWithLocal(ifStmt.left, stackLocal, registerLocal) + val right = updateExpressionWithLocal(ifStmt.left, stackLocal, registerLocal) + + return If(ifStmt.pc, left, ifStmt.condition, right, ifStmt.targetStmt) + case Switch.ASTID => + val switchStmt = stmt.asSwitch + val index = updateExpressionWithLocal(switchStmt.index, stackLocal, registerLocal) + + return Switch(switchStmt.pc, switchStmt.defaultStmt, index, switchStmt.caseStmts.map(p => IntIntPair(-1, p))) + case Assignment.ASTID => + val assignStmt = stmt.asAssignment + val targetVar = updateExpressionWithLocal(assignStmt.targetVar, stackLocal, registerLocal) + val expr = updateExpressionWithLocal(assignStmt.expr, stackLocal, registerLocal) + + return Assignment(assignStmt.pc, targetVar.asVar, expr) + case ReturnValue.ASTID => + val expr = updateExpressionWithLocal(stmt.asReturnValue.expr, stackLocal, registerLocal) + + return ReturnValue(stmt.pc, expr) + case MonitorEnter.ASTID => + val objRef = updateExpressionWithLocal(stmt.asMonitorEnter.objRef, stackLocal, registerLocal) + + return MonitorEnter(stmt.pc, objRef) + case MonitorExit.ASTID => + val objRef = updateExpressionWithLocal(stmt.asMonitorExit.objRef, stackLocal, registerLocal) + + return MonitorExit(stmt.pc, objRef) + case ArrayStore.ASTID => + val arrayStore = stmt.asArrayStore + + val arrayRef = updateExpressionWithLocal(arrayStore.arrayRef, stackLocal, registerLocal) + val index = updateExpressionWithLocal(arrayStore.index, stackLocal, registerLocal) + val value = updateExpressionWithLocal(arrayStore.value, stackLocal, registerLocal) + + return ArrayStore(arrayStore.pc, arrayRef, index, value) + case Throw.ASTID => + val throwStmt = stmt.asThrow + val exception = updateExpressionWithLocal(throwStmt.exception, stackLocal, registerLocal) + + return Throw(throwStmt.pc, exception) + case PutStatic.ASTID => + + val putStatic = stmt.asPutStatic + val value = updateExpressionWithLocal(putStatic.value, stackLocal, registerLocal) + + return PutStatic(putStatic.pc, putStatic.declaringClass, putStatic.name, putStatic.declaredFieldType, value) + case PutField.ASTID => + + val putField = stmt.asPutField + + val objRef = updateExpressionWithLocal(putField.objRef, stackLocal, registerLocal) + val value = updateExpressionWithLocal(putField.value, stackLocal, registerLocal) + + return PutField(putField.pc, putField.declaringClass, putField.name, putField.declaredFieldType, objRef, value) + case NonVirtualMethodCall.ASTID => + val methodCall = stmt.asNonVirtualMethodCall + + val baseLocal = updateExpressionWithLocal(methodCall.receiver, stackLocal, registerLocal) + val paramLocals = methodCall.params.map(p => updateExpressionWithLocal(p, stackLocal, registerLocal)) + + return NonVirtualMethodCall(methodCall.pc, methodCall.declaringClass, methodCall.isInterface, methodCall.name, methodCall.descriptor, baseLocal, paramLocals) + case VirtualMethodCall.ASTID => + val methodCall = stmt.asVirtualMethodCall + + val baseLocal = updateExpressionWithLocal(methodCall.receiver, stackLocal, registerLocal) + val paramLocals = methodCall.params.map(p => updateExpressionWithLocal(p, stackLocal, registerLocal)) + + return VirtualMethodCall(methodCall.pc, methodCall.declaringClass, methodCall.isInterface, methodCall.name, methodCall.descriptor, baseLocal, paramLocals) + case StaticMethodCall.ASTID => + val methodCall = stmt.asStaticMethodCall + val params = methodCall.params.map(p => updateExpressionWithLocal(p, stackLocal, registerLocal)) + + return StaticMethodCall(methodCall.pc, methodCall.declaringClass, methodCall.isInterface, methodCall.name, methodCall.descriptor, params) + case InvokedynamicMethodCall.ASTID => + val methodCall = stmt.asInvokedynamicMethodCall + val params = methodCall.params.map(p => updateExpressionWithLocal(p, stackLocal, registerLocal)) + + return InvokedynamicMethodCall(methodCall.pc, methodCall.bootstrapMethod, methodCall.name, methodCall.descriptor, params) + case ExprStmt.ASTID => + val expr = updateExpressionWithLocal(stmt.asExprStmt.expr, stackLocal, registerLocal) + + return ExprStmt(stmt.pc, expr) + case Checkcast.ASTID => + val castExpr = stmt.asCheckcast + val value = updateExpressionWithLocal(castExpr.value, stackLocal, registerLocal) + + return Checkcast(castExpr.pc, value, castExpr.cmpTpe) + case _ => return stmt + } + + throw new RuntimeException("Could not update statement: " + stmt) + } + + def updateExpressionWithLocal(expr: Expr[TacLocal], stackLocal: StackLocal, registerLocal: RegisterLocal): Expr[TacLocal] = { + if (expr.isVar) { + if (expr.asVar.isRegisterLocal) return expr + + // Replace stack local with register local + if (expr.asVar.isStackLocal && expr.asVar == stackLocal) { + return registerLocal + } else { + return expr + } + } + + expr.astID match { + case InstanceOf.ASTID => + val instanceOf = expr.asInstanceOf + val value = updateExpressionWithLocal(instanceOf.value, stackLocal, registerLocal) + + return InstanceOf(instanceOf.pc, value, instanceOf.cmpTpe) + case Compare.ASTID => + val compareExpr = expr.asCompare + + val leftLocal = updateExpressionWithLocal(compareExpr.left, stackLocal, registerLocal) + val rightLocal = updateExpressionWithLocal(compareExpr.right, stackLocal, registerLocal) + + return Compare(compareExpr.pc, leftLocal, compareExpr.condition, rightLocal) + case BinaryExpr.ASTID => + val binaryExpr = expr.asBinaryExpr + + val left = updateExpressionWithLocal(binaryExpr.left, stackLocal, registerLocal) + val right = updateExpressionWithLocal(binaryExpr.right, stackLocal, registerLocal) + + return BinaryExpr(binaryExpr.pc, binaryExpr.cTpe, binaryExpr.op, left, right) + case PrefixExpr.ASTID => + val prefixExpr = expr.asPrefixExpr + val operand = updateExpressionWithLocal(prefixExpr.operand, stackLocal, registerLocal) + + return PrefixExpr(prefixExpr.pc, prefixExpr.cTpe, prefixExpr.op, operand) + case PrimitiveTypecastExpr.ASTID => + val primitiveTypecastExpr = expr.asPrimitiveTypeCastExpr + val operand = updateExpressionWithLocal(primitiveTypecastExpr.operand, stackLocal, registerLocal) + + return PrimitiveTypecastExpr(primitiveTypecastExpr.pc, primitiveTypecastExpr.targetTpe, operand) + case NewArray.ASTID => + val newArray = expr.asNewArray + val counts = newArray.counts.map(c => updateExpressionWithLocal(c, stackLocal, registerLocal)) + + return NewArray(newArray.pc, counts, newArray.tpe) + case ArrayLoad.ASTID => + val arrayLoad = expr.asArrayLoad + + val index = updateExpressionWithLocal(arrayLoad.index, stackLocal, registerLocal) + val arrayRef = updateExpressionWithLocal(arrayLoad.arrayRef, stackLocal, registerLocal) + + return ArrayLoad(arrayLoad.pc, index, arrayRef) + case ArrayLength.ASTID => + val arrayLength = expr.asArrayLength + val arrayRef = updateExpressionWithLocal(arrayLength.arrayRef, stackLocal, registerLocal) + + return ArrayLength(arrayLength.pc, arrayRef) + case GetField.ASTID => + val getField = expr.asGetField + val objRef = updateExpressionWithLocal(getField.objRef, stackLocal, registerLocal) + + return GetField(getField.pc, getField.declaringClass, getField.name, getField.declaredFieldType, objRef) + case InvokedynamicFunctionCall.ASTID => + val functionCall = expr.asInvokedynamicFunctionCall + val params = functionCall.params.map(p => updateExpressionWithLocal(p, stackLocal, registerLocal)) + + return InvokedynamicFunctionCall(functionCall.pc, functionCall.bootstrapMethod, functionCall.name, functionCall.descriptor, params) + case NonVirtualFunctionCall.ASTID => + val functionCall = expr.asNonVirtualFunctionCall + + val base = updateExpressionWithLocal(functionCall.receiver, stackLocal, registerLocal) + val params = functionCall.params.map(p => updateExpressionWithLocal(p, stackLocal, registerLocal)) + + return NonVirtualFunctionCall(functionCall.pc, functionCall.declaringClass, functionCall.isInterface, functionCall.name, functionCall.descriptor, base, params) + case VirtualFunctionCall.ASTID => + val functionCall = expr.asVirtualFunctionCall + + val base = updateExpressionWithLocal(functionCall.receiver, stackLocal, registerLocal) + val params = functionCall.params.map(p => updateExpressionWithLocal(p, stackLocal, registerLocal)) + + return VirtualFunctionCall(functionCall.pc, functionCall.declaringClass, functionCall.isInterface, functionCall.name, functionCall.descriptor, base, params) + case StaticFunctionCall.ASTID => + val functionCall = expr.asStaticFunctionCall + + val params = functionCall.params + val paramLocals = params.map(p => updateExpressionWithLocal(p, stackLocal, registerLocal)) + + return StaticFunctionCall(functionCall.pc, functionCall.declaringClass, functionCall.isInterface, functionCall.name, functionCall.descriptor, paramLocals) + case _ => return expr + } + + throw new RuntimeException("Could not update expression: " + expr) + } + + statements + } +} diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalArrayTest.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalArrayTest.scala index 7cb2ef453..79ece7c5e 100644 --- a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalArrayTest.scala +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalArrayTest.scala @@ -14,11 +14,11 @@ class OpalArrayTest { private val integerType = IntegerType.toJVMTypeName @Test - def singleArrayLoadTest(): Unit = { + def singleArrayLoadIndexTest(): Unit = { val opalSetup = new OpalSetup() opalSetup.setupOpal(classOf[ArrayTarget].getName) - val signature = new MethodSignature(classOf[ArrayTarget].getName, "singleArrayLoad", "Void", util.List.of("[" + integerType)) + val signature = new MethodSignature(classOf[ArrayTarget].getName, "singleArrayIndexLoad", "Void", util.List.of("[" + integerType)) val method = opalSetup.resolveMethod(signature) val opalMethod = OpalMethod(method) @@ -41,11 +41,38 @@ class OpalArrayTest { } @Test - def singleArrayStoreTest(): Unit = { + def singleArrayLoadVarTest(): Unit = { val opalSetup = new OpalSetup() opalSetup.setupOpal(classOf[ArrayTarget].getName) - val signature = new MethodSignature(classOf[ArrayTarget].getName, "singleArrayStore", "Void") + val signature = new MethodSignature(classOf[ArrayTarget].getName, "singleArrayVarLoad", "Void", util.List.of("[" + integerType)) + val method = opalSetup.resolveMethod(signature) + val opalMethod = OpalMethod(method) + + var arrayLoadCount = 0 + opalMethod.getStatements.forEach(stmt => { + if (stmt.isArrayLoad) { + arrayLoadCount += 1 + + val arrayBase = stmt.getArrayBase + Assert.assertFalse(arrayBase.getX.isArrayRef) + Assert.assertTrue(arrayBase.getX.isLocal) + Assert.assertEquals(-1, arrayBase.getY) + + val rightOp = stmt.getRightOp + Assert.assertTrue(rightOp.isArrayRef) + } + }) + + Assert.assertEquals(1, arrayLoadCount) + } + + @Test + def singleArrayStoreIndexTest(): Unit = { + val opalSetup = new OpalSetup() + opalSetup.setupOpal(classOf[ArrayTarget].getName) + + val signature = new MethodSignature(classOf[ArrayTarget].getName, "singleArrayStoreIndex", "Void") val method = opalSetup.resolveMethod(signature) val opalMethod = OpalMethod(method) @@ -67,6 +94,33 @@ class OpalArrayTest { Assert.assertEquals(1, arrayStoreCount) } + @Test + def singleArrayStoreVarTest(): Unit = { + val opalSetup = new OpalSetup() + opalSetup.setupOpal(classOf[ArrayTarget].getName) + + val signature = new MethodSignature(classOf[ArrayTarget].getName, "singleArrayStoreVar", "Void") + val method = opalSetup.resolveMethod(signature) + val opalMethod = OpalMethod(method) + + var arrayStoreCount = 0 + opalMethod.getStatements.forEach(stmt => { + if (stmt.isArrayStore) { + arrayStoreCount += 1 + + val arrayBase = stmt.getArrayBase + Assert.assertFalse(arrayBase.getX.isArrayRef) + Assert.assertTrue(arrayBase.getX.isLocal) + Assert.assertEquals(-1, arrayBase.getY) + + val leftOp = stmt.getLeftOp + Assert.assertTrue(leftOp.isArrayRef) + } + }) + + Assert.assertEquals(1, arrayStoreCount) + } + @Test def multiArrayStore(): Unit = { val opalSetup = new OpalSetup() diff --git a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/BoomerangPretransformer.java b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/BoomerangPretransformer.java index b946708bb..df4b0eb60 100644 --- a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/BoomerangPretransformer.java +++ b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/BoomerangPretransformer.java @@ -11,10 +11,10 @@ */ package boomerang.scope.soot; -import com.google.common.collect.Sets; import java.util.AbstractMap; import java.util.ArrayList; import java.util.HashMap; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -192,7 +192,7 @@ private void addNopStmtToMethods(Body b) { } } b.getUnits().insertBefore(nopStmt, b.getUnits().getFirst()); - Set ifStmts = Sets.newHashSet(); + Set ifStmts = new LinkedHashSet<>(); for (Unit u : b.getUnits()) { if (u instanceof IfStmt) { // ((IfStmt) u).getTarget(); @@ -214,7 +214,7 @@ private void addNopStmtToMethods(Body b) { } private Set getStmtsWithConstants(Body methodBody) { - Set retMap = Sets.newHashSet(); + Set retMap = new LinkedHashSet<>(); for (Unit u : methodBody.getUnits()) { if (u instanceof AssignStmt) { AssignStmt assignStmt = (AssignStmt) u; @@ -263,7 +263,7 @@ public void apply() { private static void addNulliefiedFields(SootMethod cons) { Chain fields = cons.getDeclaringClass().getFields(); UnitPatchingChain units = cons.getActiveBody().getUnits(); - Set fieldsDefinedInMethod = getFieldsDefinedInMethod(cons, Sets.newHashSet()); + Set fieldsDefinedInMethod = getFieldsDefinedInMethod(cons, new LinkedHashSet<>()); for (SootField f : fields) { if (fieldsDefinedInMethod.contains(f)) continue; if (f.isStatic()) continue; @@ -297,7 +297,7 @@ private static Unit findLastIdentityStmt(UnitPatchingChain units) { } private static Set getFieldsDefinedInMethod(SootMethod cons, Set visited) { - Set res = Sets.newHashSet(); + Set res = new LinkedHashSet<>(); if (!visited.add(cons)) return res; if (!cons.hasActiveBody()) return res; for (Unit u : cons.getActiveBody().getUnits()) { diff --git a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/ExplicitNullifyFields.java b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/ExplicitNullifyFields.java index a1e6c60ba..bf25e6cc8 100644 --- a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/ExplicitNullifyFields.java +++ b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/ExplicitNullifyFields.java @@ -11,7 +11,7 @@ */ package boomerang.scope.soot.jimple; -import com.google.common.collect.Sets; +import java.util.LinkedHashSet; import java.util.Set; import soot.RefType; import soot.Scene; @@ -57,7 +57,7 @@ private static void apply(SootMethod cons) { } private static Set getFieldsDefinedInMethod(SootMethod cons) { - Set res = Sets.newHashSet(); + Set res = new LinkedHashSet<>(); for (Unit u : cons.getActiveBody().getUnits()) { if (u instanceof AssignStmt) { AssignStmt as = (AssignStmt) u; diff --git a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleMethod.java b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleMethod.java index 263c071b8..51935f687 100644 --- a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleMethod.java +++ b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleMethod.java @@ -20,9 +20,9 @@ import com.google.common.collect.Interner; import com.google.common.collect.Interners; import com.google.common.collect.Lists; -import com.google.common.collect.Sets; import java.util.ArrayList; import java.util.Collection; +import java.util.LinkedHashSet; import java.util.List; import java.util.Objects; import soot.Local; @@ -104,7 +104,7 @@ public boolean isThisLocal(Val val) { @Override public Collection getLocals() { if (localCache == null) { - localCache = Sets.newHashSet(); + localCache = new LinkedHashSet<>(); Chain locals = delegate.getActiveBody().getLocals(); for (Local l : locals) { localCache.add(new JimpleVal(l, this)); diff --git a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleWrappedClass.java b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleWrappedClass.java index 4024bb5c4..0ba85e8ec 100644 --- a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleWrappedClass.java +++ b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleWrappedClass.java @@ -14,8 +14,8 @@ import boomerang.scope.Method; import boomerang.scope.Type; import boomerang.scope.WrappedClass; -import com.google.common.collect.Sets; import java.util.Collection; +import java.util.LinkedHashSet; import java.util.List; import java.util.Objects; import soot.SootClass; @@ -33,7 +33,7 @@ public JimpleWrappedClass(SootClass delegate) { public Collection getMethods() { List ms = delegate.getMethods(); if (methods == null) { - methods = Sets.newHashSet(); + methods = new LinkedHashSet<>(); for (SootMethod m : ms) { if (m.hasActiveBody()) methods.add(JimpleMethod.of(m)); } diff --git a/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootArrayTest.java b/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootArrayTest.java index 8aec91052..bfc75438c 100644 --- a/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootArrayTest.java +++ b/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootArrayTest.java @@ -30,7 +30,7 @@ public void singleArrayStoreConstantTest() { sootSetup.setupSoot(ArrayTarget.class.getName()); MethodSignature signature = - new MethodSignature(ArrayTarget.class.getName(), "singleArrayStore"); + new MethodSignature(ArrayTarget.class.getName(), "singleArrayStoreIndex"); SootMethod method = sootSetup.resolveMethod(signature); Method jimpleMethod = JimpleMethod.of(method); diff --git a/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpControlFlowGraph.java b/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpControlFlowGraph.java index 70c6e764f..b009e9760 100644 --- a/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpControlFlowGraph.java +++ b/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpControlFlowGraph.java @@ -16,8 +16,8 @@ import com.google.common.collect.HashMultimap; import com.google.common.collect.Lists; import com.google.common.collect.Multimap; -import com.google.common.collect.Sets; import java.util.Collection; +import java.util.LinkedHashSet; import java.util.List; import sootup.core.graph.StmtGraph; import sootup.core.jimple.common.stmt.JIdentityStmt; @@ -30,8 +30,8 @@ public class JimpleUpControlFlowGraph implements ControlFlowGraph { private boolean cacheBuilt = false; private final List statements = Lists.newArrayList(); - private final Collection startPointCache = Sets.newHashSet(); - private final Collection endPointCache = Sets.newHashSet(); + private final Collection startPointCache = new LinkedHashSet<>(); + private final Collection endPointCache = new LinkedHashSet<>(); private final Multimap predecessorsOfCache = HashMultimap.create(); private final Multimap successorsOfCache = HashMultimap.create(); diff --git a/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALACallGraph.java b/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALACallGraph.java index 1829f7877..0a5e3568e 100644 --- a/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALACallGraph.java +++ b/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALACallGraph.java @@ -14,7 +14,6 @@ import boomerang.scope.CallGraph; import com.google.common.base.Stopwatch; import com.google.common.collect.Lists; -import com.google.common.collect.Sets; import com.ibm.wala.classLoader.CallSiteReference; import com.ibm.wala.classLoader.IMethod; import com.ibm.wala.ipa.callgraph.CGNode; @@ -23,6 +22,7 @@ import java.util.Collection; import java.util.HashMap; import java.util.Iterator; +import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.Map; import java.util.Set; @@ -36,7 +36,7 @@ public class WALACallGraph extends CallGraph { public WALACallGraph(com.ibm.wala.ipa.callgraph.CallGraph cg, IClassHierarchy cha) { this.cha = cha; Collection ep = cg.getEntrypointNodes(); - Set visited = Sets.newHashSet(); + Set visited = new LinkedHashSet<>(); LinkedList worklist = Lists.newLinkedList(); for (CGNode e : ep) { worklist.add(e); diff --git a/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALAControlFlowGraph.java b/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALAControlFlowGraph.java index efcff751d..e15ca16a3 100644 --- a/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALAControlFlowGraph.java +++ b/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALAControlFlowGraph.java @@ -20,7 +20,6 @@ import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multimap; -import com.google.common.collect.Sets; import com.ibm.wala.classLoader.IClass; import com.ibm.wala.classLoader.IField; import com.ibm.wala.ipa.cha.IClassHierarchy; @@ -33,6 +32,7 @@ import com.ibm.wala.types.TypeReference; import java.util.Collection; import java.util.Iterator; +import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -68,7 +68,7 @@ private void buildCache() { if (cacheBuild) return; cacheBuild = true; - Set emptyBasicBlocks = Sets.newHashSet(); + Set emptyBasicBlocks = new LinkedHashSet<>(); Map basicBlockToLastStmt = Maps.newHashMap(); Iterator bbIt = cfg.iterator(); // Convert each basic block. @@ -105,7 +105,7 @@ private void buildCache() { for (ISSABasicBlock eBB : emptyBasicBlocks) { bbGraph.removeNode(eBB); } - Set visited = Sets.newHashSet(); + Set visited = new LinkedHashSet<>(); LinkedList worklist = Lists.newLinkedList(); worklist.addAll(bbGraph.entries); while (!worklist.isEmpty()) { @@ -287,7 +287,7 @@ private void containsNullVariables(WALAStatement call, List res) { private Graph buildDirectedGraph() { Graph graph = new Graph<>(); - Set visited = Sets.newHashSet(); + Set visited = new LinkedHashSet<>(); LinkedList worklist = Lists.newLinkedList(); worklist.add(cfg.entry()); graph.addEntry(cfg.entry()); @@ -309,7 +309,7 @@ private Graph buildDirectedGraph() { private static class Graph { Multimap outEdges = HashMultimap.create(); Multimap inEdges = HashMultimap.create(); - Set entries = Sets.newHashSet(); + Set entries = new LinkedHashSet<>(); public void removeNode(N bb) { Collection out = outEdges.get(bb); diff --git a/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALAMethod.java b/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALAMethod.java index cd63328be..dbfd0551c 100644 --- a/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALAMethod.java +++ b/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALAMethod.java @@ -18,7 +18,6 @@ import boomerang.scope.Val; import boomerang.scope.WrappedClass; import com.google.common.collect.Lists; -import com.google.common.collect.Sets; import com.ibm.wala.analysis.typeInference.TypeInference; import com.ibm.wala.cast.ir.ssa.AstIRFactory.AstIR; import com.ibm.wala.cast.java.analysis.typeInference.AstJavaTypeInference; @@ -26,6 +25,7 @@ import com.ibm.wala.ipa.cha.IClassHierarchy; import com.ibm.wala.ssa.IR; import java.util.ArrayList; +import java.util.LinkedHashSet; import java.util.List; import java.util.Set; @@ -90,7 +90,7 @@ public boolean isThisLocal(Val val) { @Override public Set getLocals() { if (valueCache == null) { - valueCache = Sets.newHashSet(); + valueCache = new LinkedHashSet<>(); for (int i = 0; i <= ir.getSymbolTable().getMaxValueNumber(); i++) { valueCache.add(new WALAVal(i, this)); } diff --git a/boomerangScope/src/main/java/boomerang/scope/CallGraph.java b/boomerangScope/src/main/java/boomerang/scope/CallGraph.java index 335e73b99..67a660b0b 100644 --- a/boomerangScope/src/main/java/boomerang/scope/CallGraph.java +++ b/boomerangScope/src/main/java/boomerang/scope/CallGraph.java @@ -13,8 +13,8 @@ import com.google.common.collect.HashMultimap; import com.google.common.collect.Multimap; -import com.google.common.collect.Sets; import java.util.Collection; +import java.util.LinkedHashSet; import java.util.Objects; import java.util.Set; import org.slf4j.Logger; @@ -23,10 +23,10 @@ public class CallGraph { protected static final Logger LOGGER = LoggerFactory.getLogger(CallGraph.class); - private final Set edges = Sets.newHashSet(); + private final Set edges = new LinkedHashSet<>(); private final Multimap edgesOutOf = HashMultimap.create(); private final Multimap edgesInto = HashMultimap.create(); - private final Set entryPoints = Sets.newHashSet(); + private final Set entryPoints = new LinkedHashSet<>(); private final Multimap fieldLoadStatements = HashMultimap.create(); private final Multimap fieldStoreStatements = HashMultimap.create(); @@ -105,7 +105,7 @@ public boolean addEntryPoint(Method m) { } public Set getReachableMethods() { - Set reachableMethod = Sets.newHashSet(); + Set reachableMethod = new LinkedHashSet<>(); reachableMethod.addAll(entryPoints); reachableMethod.addAll(edgesInto.keySet()); return reachableMethod; diff --git a/boomerangScope/src/main/java/boomerang/scope/Method.java b/boomerangScope/src/main/java/boomerang/scope/Method.java index dc95a23ee..be7d1a124 100644 --- a/boomerangScope/src/main/java/boomerang/scope/Method.java +++ b/boomerangScope/src/main/java/boomerang/scope/Method.java @@ -11,10 +11,10 @@ */ package boomerang.scope; -import com.google.common.collect.Sets; import de.fraunhofer.iem.Location; import java.util.Collection; import java.util.Collections; +import java.util.LinkedHashSet; import java.util.List; public abstract class Method implements Location { @@ -169,7 +169,7 @@ public Val getParameterLocal(int i) { public Collection getReturnLocals() { if (returnLocals == null) { - returnLocals = Sets.newHashSet(); + returnLocals = new LinkedHashSet<>(); for (Statement s : getStatements()) { if (s.isReturnStmt()) { returnLocals.add(s.getReturnOp()); diff --git a/boomerangScope/src/test/java/boomerang/scope/test/targets/ArrayTarget.java b/boomerangScope/src/test/java/boomerang/scope/test/targets/ArrayTarget.java index 697ace632..a6f346fc4 100644 --- a/boomerangScope/src/test/java/boomerang/scope/test/targets/ArrayTarget.java +++ b/boomerangScope/src/test/java/boomerang/scope/test/targets/ArrayTarget.java @@ -16,25 +16,43 @@ public class ArrayTarget { public static void main(String[] args) { - singleArrayLoad(new int[] {1, 2}); - singleArrayStore(); + singleArrayIndexLoad(new int[] {1, 2}); + singleArrayVarLoad(new int[] {1, 1}); + + singleArrayStoreIndex(); + singleArrayStoreVar(); multiArrayStore(); } - public static void singleArrayLoad(int[] arr) { + public static void singleArrayIndexLoad(int[] arr) { int i = arr[1]; System.out.println(i); } - public static void singleArrayStore() { + public static void singleArrayVarLoad(int[] arr) { + int index = 1; + int i = arr[index]; + + System.out.println(i); + } + + public static void singleArrayStoreIndex() { int[] arr = new int[2]; arr[0] = 1; System.out.println(Arrays.toString(arr)); } + public static void singleArrayStoreVar() { + int[] arr = new int[2]; + int index = 0; + arr[index] = 1; + + System.out.println(Arrays.toString(arr)); + } + public static void multiArrayStore() { int[][] arr = new int[2][3]; arr[0][0] = 1; diff --git a/idealPDS/src/main/java/ideal/IDEALSeedSolver.java b/idealPDS/src/main/java/ideal/IDEALSeedSolver.java index 9bd1713d9..35dedd3df 100644 --- a/idealPDS/src/main/java/ideal/IDEALSeedSolver.java +++ b/idealPDS/src/main/java/ideal/IDEALSeedSolver.java @@ -27,8 +27,8 @@ import com.google.common.collect.HashMultimap; import com.google.common.collect.Lists; import com.google.common.collect.Multimap; -import com.google.common.collect.Sets; import java.util.Collection; +import java.util.LinkedHashSet; import java.util.Map.Entry; import java.util.Set; import org.slf4j.Logger; @@ -61,7 +61,7 @@ public class IDEALSeedSolver { private final WeightedBoomerang phase2Solver; private final Stopwatch analysisStopwatch = Stopwatch.createUnstarted(); private final Multimap, Edge> affectedStrongUpdateStmt = HashMultimap.create(); - private final Set> weakUpdates = Sets.newHashSet(); + private final Set> weakUpdates = new LinkedHashSet<>(); private int killedRules; private final class AddIndirectFlowAtCallSite implements WPAUpdateListener, W> { diff --git a/idealPDS/src/main/java/ideal/IDEALWeightFunctions.java b/idealPDS/src/main/java/ideal/IDEALWeightFunctions.java index 3065c34a0..9d974acd8 100644 --- a/idealPDS/src/main/java/ideal/IDEALWeightFunctions.java +++ b/idealPDS/src/main/java/ideal/IDEALWeightFunctions.java @@ -16,9 +16,9 @@ import com.google.common.collect.HashMultimap; import com.google.common.collect.Lists; import com.google.common.collect.Multimap; -import com.google.common.collect.Sets; import ideal.IDEALSeedSolver.Phases; import java.util.Collection; +import java.util.LinkedHashSet; import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -31,14 +31,14 @@ public class IDEALWeightFunctions implements WeightFunctions delegate; - private final Set listeners = Sets.newHashSet(); - private final Set potentialStrongUpdates = Sets.newHashSet(); - private final Set weakUpdates = Sets.newHashSet(); - private final Set> nonOneFlowNodes = Sets.newHashSet(); + private final Set listeners = new LinkedHashSet<>(); + private final Set potentialStrongUpdates = new LinkedHashSet<>(); + private final Set weakUpdates = new LinkedHashSet<>(); + private final Set> nonOneFlowNodes = new LinkedHashSet<>(); private Phases phase; private final boolean strongUpdates; private final Multimap, Node> indirectAlias = HashMultimap.create(); - private final Set> nodesWithStrongUpdate = Sets.newHashSet(); + private final Set> nodesWithStrongUpdate = new LinkedHashSet<>(); public IDEALWeightFunctions(WeightFunctions delegate, boolean strongUpdates) { this.delegate = delegate; diff --git a/idealPDS/src/main/java/typestate/TransitionFunction.java b/idealPDS/src/main/java/typestate/TransitionFunction.java index c605ddf53..ee5425bdc 100644 --- a/idealPDS/src/main/java/typestate/TransitionFunction.java +++ b/idealPDS/src/main/java/typestate/TransitionFunction.java @@ -13,10 +13,10 @@ import boomerang.scope.ControlFlowGraph.Edge; import com.google.common.collect.Lists; -import com.google.common.collect.Sets; import java.util.Collection; import java.util.Collections; import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.Set; import typestate.finiteautomata.ITransition; import typestate.finiteautomata.Transition; @@ -45,9 +45,9 @@ public TransitionFunction(ITransition trans, Set stateChangeStatements) { } private TransitionFunction(String rep) { - this.value = Sets.newHashSet(); + this.value = new LinkedHashSet<>(); this.rep = rep; - this.stateChangeStatements = Sets.newHashSet(); + this.stateChangeStatements = new LinkedHashSet<>(); } public Collection values() { @@ -97,19 +97,19 @@ public Weight combineWith(Weight other) { TransitionFunction func = (TransitionFunction) other; if (other.equals(one()) || this.equals(one())) { Set transitions = new HashSet<>((other.equals(one()) ? value : func.value)); - Set idTransitions = Sets.newHashSet(); + Set idTransitions = new LinkedHashSet<>(); for (ITransition t : transitions) { idTransitions.add(new Transition(t.from(), t.from())); } transitions.addAll(idTransitions); return new TransitionFunction( transitions, - Sets.newHashSet( + new LinkedHashSet( (other.equals(one()) ? stateChangeStatements : func.stateChangeStatements))); } Set transitions = new HashSet<>(func.value); transitions.addAll(value); - HashSet newStateChangeStmts = Sets.newHashSet(stateChangeStatements); + HashSet newStateChangeStmts = new LinkedHashSet(stateChangeStatements); newStateChangeStmts.addAll(func.stateChangeStatements); return new TransitionFunction(transitions, newStateChangeStmts); } diff --git a/idealPDS/src/main/java/typestate/finiteautomata/TypeStateMachineWeightFunctions.java b/idealPDS/src/main/java/typestate/finiteautomata/TypeStateMachineWeightFunctions.java index cd1cd9b17..52812f4aa 100644 --- a/idealPDS/src/main/java/typestate/finiteautomata/TypeStateMachineWeightFunctions.java +++ b/idealPDS/src/main/java/typestate/finiteautomata/TypeStateMachineWeightFunctions.java @@ -19,10 +19,10 @@ import boomerang.scope.Val; import com.google.common.base.Joiner; import com.google.common.collect.Collections2; -import com.google.common.collect.Sets; import java.util.Collection; import java.util.Collections; import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -76,7 +76,7 @@ public TransitionFunction normal(Node curr, Node succ) { public TransitionFunction callToReturn( Node curr, Node succ, InvokeExpr invokeExpr) { - Set res = Sets.newHashSet(); + Set res = new LinkedHashSet<>(); if (invokeExpr.isInstanceInvokeExpr()) { if (invokeExpr.getBase().equals(succ.fact())) { for (MatcherTransition trans : transition) { From 53251ae1d3897bef0049b95f5199f0bbdee2eea7 Mon Sep 17 00:00:00 2001 From: Sven Meyer Date: Wed, 16 Apr 2025 10:28:33 +0200 Subject: [PATCH 39/61] Update inlining of locals --- .../java/boomerang/guided/Specification.java | 2 +- .../solver/BackwardBoomerangSolver.java | 13 ++-- .../solver/ForwardBoomerangSolver.java | 4 +- .../main/resources/simplelogger.properties | 2 +- .../guided/CustomFlowFunctionTest.java | 2 +- .../DemandDrivenGuidedAnalysisTest.java | 2 +- .../cases/bugfixes/issue5/Issue5Test.java | 2 +- .../java/test/core/AbstractBoomerangTest.java | 2 +- .../test/core/MultiQueryBoomerangTest.java | 2 +- .../scope/opal/tac/OpalStatement.scala | 7 +- .../opal/transformation/TacBodyBuilder.scala | 4 +- .../transformation/stack/OperandStack.scala | 7 +- .../stack/OperandStackBuilder.scala | 18 ++--- .../transformer/InlineLocalTransformer.scala | 71 +++++++------------ .../scope/opal/OpalInvokeExprTest.scala | 26 ++++++- .../java/boomerang/utils}/MethodWrapper.java | 2 +- .../java/boomerang/scope/test/targets/A.java | 3 + .../scope/test/targets/ArrayTarget.java | 4 +- .../scope/test/targets/InvokeExprTarget.java | 6 ++ .../test/java/test/IDEALTestingFramework.java | 2 +- .../src/main/java/test/TestingFramework.java | 2 +- .../main/java/test/setup/OpalTestSetup.java | 1 + .../main/java/test/setup/SootTestSetup.java | 1 + .../main/java/test/setup/SootUpTestSetup.java | 1 + .../src/main/java/test/setup/TestSetup.java | 1 + 25 files changed, 98 insertions(+), 89 deletions(-) rename {testCore/src/main/java/test/setup => boomerangScope/src/main/java/boomerang/utils}/MethodWrapper.java (99%) diff --git a/boomerangPDS/src/main/java/boomerang/guided/Specification.java b/boomerangPDS/src/main/java/boomerang/guided/Specification.java index 5e677bd5a..c9194099f 100644 --- a/boomerangPDS/src/main/java/boomerang/guided/Specification.java +++ b/boomerangPDS/src/main/java/boomerang/guided/Specification.java @@ -36,7 +36,7 @@ public enum QueryDirection { private final Set methodAndQueries; private Specification(Collection spec) { - methodAndQueries = spec.stream().map(x -> parse(x)).collect(Collectors.toSet()); + methodAndQueries = spec.stream().map(this::parse).collect(Collectors.toSet()); } private MethodWithSelector parse(String input) { diff --git a/boomerangPDS/src/main/java/boomerang/solver/BackwardBoomerangSolver.java b/boomerangPDS/src/main/java/boomerang/solver/BackwardBoomerangSolver.java index bad6d05b2..0ec9b2935 100644 --- a/boomerangPDS/src/main/java/boomerang/solver/BackwardBoomerangSolver.java +++ b/boomerangPDS/src/main/java/boomerang/solver/BackwardBoomerangSolver.java @@ -109,7 +109,7 @@ protected Collection computeReturnFlow( Method method, Statement callerReturnStatement, Val value) { return flowFunction.returnFlow(method, callerReturnStatement, value).stream() .map(x -> new PopNode<>(x, PDSSystem.CALLS)) - .collect(Collectors.toSet()); + .collect(Collectors.toCollection(LinkedHashSet::new)); } protected void callFlow(Method caller, Node curr, Statement callSite) { @@ -129,11 +129,8 @@ private void byPassFlowAtCallsite(Method caller, Node curr) { .getControlFlowGraph() .getPredsOf(curr.stmt().getStart())) { - Set res = - flowFunction - .callToReturnFlow(new Edge(returnSite, curr.stmt().getStart()), curr.fact()) - .stream() - .collect(Collectors.toSet()); + Collection res = + flowFunction.callToReturnFlow(new Edge(returnSite, curr.stmt().getStart()), curr.fact()); for (State s : res) { propagate(curr, s); } @@ -233,7 +230,7 @@ protected Collection computeCallFlow( Statement calleeSp = calleeStartEdge.getTarget(); return flowFunction.callFlow(callSiteEdge.getTarget(), fact, callee, calleeSp).stream() .map(x -> new PushNode<>(calleeStartEdge, x, callSiteEdge, PDSSystem.CALLS)) - .collect(Collectors.toSet()); + .collect(Collectors.toCollection(LinkedHashSet::new)); } @Override @@ -250,7 +247,7 @@ public void processPush( @Override protected Collection computeNormalFlow(Method method, Edge currEdge, Val fact) { - return flowFunction.normalFlow(currEdge, fact).stream().collect(Collectors.toSet()); + return flowFunction.normalFlow(currEdge, fact); } @Override diff --git a/boomerangPDS/src/main/java/boomerang/solver/ForwardBoomerangSolver.java b/boomerangPDS/src/main/java/boomerang/solver/ForwardBoomerangSolver.java index 73c0dad68..eaae6e502 100644 --- a/boomerangPDS/src/main/java/boomerang/solver/ForwardBoomerangSolver.java +++ b/boomerangPDS/src/main/java/boomerang/solver/ForwardBoomerangSolver.java @@ -375,7 +375,7 @@ public Collection computeCallFlow( Val fact = currNode.fact(); return flowFunctions.callFlow(callSite, fact, callee).stream() .map(x -> new PushNode<>(calleeStartEdge, x, succOfCallSite, PDSSystem.CALLS)) - .collect(Collectors.toSet()); + .collect(Collectors.toCollection(LinkedHashSet::new)); } public Query getQuery() { @@ -462,7 +462,7 @@ query, new Edge(callSite, returnSite), currNode.fact())) { public Collection computeReturnFlow(Method method, Statement curr, Val value) { return flowFunctions.returnFlow(method, curr, value).stream() .map(x -> new PopNode<>(x, PDSSystem.CALLS)) - .collect(Collectors.toSet()); + .collect(Collectors.toCollection(LinkedHashSet::new)); } @Override diff --git a/boomerangPDS/src/main/resources/simplelogger.properties b/boomerangPDS/src/main/resources/simplelogger.properties index 716158ec1..e669de85a 100644 --- a/boomerangPDS/src/main/resources/simplelogger.properties +++ b/boomerangPDS/src/main/resources/simplelogger.properties @@ -1,4 +1,4 @@ -org.slf4j.simpleLogger.defaultLogLevel=trace +org.slf4j.simpleLogger.defaultLogLevel=info org.slf4j.simpleLogger.logFile=System.out org.slf4j.simpleLogger.showDateTime=true org.slf4j.simpleLogger.dateTimeFormat=yyyy-MM-dd HH:mm:ss diff --git a/boomerangPDS/src/test/java/boomerang/guided/CustomFlowFunctionTest.java b/boomerangPDS/src/test/java/boomerang/guided/CustomFlowFunctionTest.java index 6ebba8ef5..14f294c09 100644 --- a/boomerangPDS/src/test/java/boomerang/guided/CustomFlowFunctionTest.java +++ b/boomerangPDS/src/test/java/boomerang/guided/CustomFlowFunctionTest.java @@ -37,7 +37,7 @@ import org.junit.Assert; import org.junit.Test; import test.TestingFramework; -import test.setup.MethodWrapper; +import boomerang.utils.MethodWrapper; import wpds.impl.Weight.NoWeight; public class CustomFlowFunctionTest { diff --git a/boomerangPDS/src/test/java/boomerang/guided/DemandDrivenGuidedAnalysisTest.java b/boomerangPDS/src/test/java/boomerang/guided/DemandDrivenGuidedAnalysisTest.java index 556b5eb98..f0ef2c5c3 100644 --- a/boomerangPDS/src/test/java/boomerang/guided/DemandDrivenGuidedAnalysisTest.java +++ b/boomerangPDS/src/test/java/boomerang/guided/DemandDrivenGuidedAnalysisTest.java @@ -54,7 +54,7 @@ import org.junit.Assert; import org.junit.Test; import test.TestingFramework; -import test.setup.MethodWrapper; +import boomerang.utils.MethodWrapper; import wpds.impl.Weight.NoWeight; public class DemandDrivenGuidedAnalysisTest { diff --git a/boomerangPDS/src/test/java/test/cases/bugfixes/issue5/Issue5Test.java b/boomerangPDS/src/test/java/test/cases/bugfixes/issue5/Issue5Test.java index 9787ed73b..a52f1edb0 100644 --- a/boomerangPDS/src/test/java/test/cases/bugfixes/issue5/Issue5Test.java +++ b/boomerangPDS/src/test/java/test/cases/bugfixes/issue5/Issue5Test.java @@ -33,7 +33,7 @@ import org.junit.Assert; import org.junit.Test; import test.TestingFramework; -import test.setup.MethodWrapper; +import boomerang.utils.MethodWrapper; import wpds.impl.Weight.NoWeight; /** diff --git a/boomerangPDS/src/test/java/test/core/AbstractBoomerangTest.java b/boomerangPDS/src/test/java/test/core/AbstractBoomerangTest.java index d9aa7fdd0..12e837a22 100644 --- a/boomerangPDS/src/test/java/test/core/AbstractBoomerangTest.java +++ b/boomerangPDS/src/test/java/test/core/AbstractBoomerangTest.java @@ -53,7 +53,7 @@ import test.TestingFramework; import test.core.selfrunning.AllocatedObject; import test.core.selfrunning.NoAllocatedObject; -import test.setup.MethodWrapper; +import boomerang.utils.MethodWrapper; import wpds.impl.Transition; import wpds.impl.Weight.NoWeight; import wpds.impl.WeightedPAutomaton; diff --git a/boomerangPDS/src/test/java/test/core/MultiQueryBoomerangTest.java b/boomerangPDS/src/test/java/test/core/MultiQueryBoomerangTest.java index db5a75b24..aca859b8b 100644 --- a/boomerangPDS/src/test/java/test/core/MultiQueryBoomerangTest.java +++ b/boomerangPDS/src/test/java/test/core/MultiQueryBoomerangTest.java @@ -33,7 +33,7 @@ import org.junit.rules.TestName; import org.junit.rules.Timeout; import test.TestingFramework; -import test.setup.MethodWrapper; +import boomerang.utils.MethodWrapper; import wpds.impl.Weight; public class MultiQueryBoomerangTest extends TestingFramework { diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala index c63f02f16..276ad89d5 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala @@ -53,19 +53,18 @@ class OpalStatement(val delegate: Stmt[TacLocal], m: OpalMethod) extends Stateme } if (isArrayStore) { - // TODO - val arrayStore = delegate.asArrayStore + return Field.array(getArrayBase.getY) } throw new RuntimeException("Statement is not a field store operation") } override def isFieldWriteWithBase(base: Val): Boolean = { - if (delegate.isAssignment && isFieldStore) { + if (isAssignStmt && isFieldStore) { return getFieldStore.getX.equals(base) } - if (delegate.isAssignment && isArrayStore) { + if (isAssignStmt && isArrayStore) { return getArrayBase.getX.equals(base) } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacBodyBuilder.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacBodyBuilder.scala index bfd5ca7db..bb9dae513 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacBodyBuilder.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacBodyBuilder.scala @@ -18,14 +18,12 @@ object TacBodyBuilder { val localTransformedTac = LocalTransformer(method, tacNaive, stackHandler, domain) assert(tacNaive.stmts.length == localTransformedTac.length, "Wrong transformation") - val inlinedTac = InlineLocalTransformer(localTransformedTac, tacNaive.cfg) + val inlinedTac = InlineLocalTransformer(localTransformedTac, stackHandler) assert(tacNaive.stmts.length == inlinedTac.length, "Wrong transformation") val propagatedTac = LocalPropagationTransformer(inlinedTac, stackHandler) assert(tacNaive.stmts.length == propagatedTac.length, "Wrong transformation") - // TODO Local propagation - // Update the CFG val cfg = CFGFactory(method, project.classHierarchy) if (cfg.isEmpty) { diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStack.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStack.scala index bfbf43692..335746174 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStack.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStack.scala @@ -20,11 +20,12 @@ class OperandStack private(stackHandler: OperandStackHandler, private var stack: throw new IllegalStateException(s"Cannot pop operand $idBasedVar from empty stack") } - val top :: rest = stack - stack = rest - // Check if stack is in consistent state + val top :: rest = stack assert(idBasedVar.id == top.id, s"Invalid pop operation on operand $idBasedVar") + + // Update stack + stack = rest } def pop: Operand = { diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackBuilder.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackBuilder.scala index 394442ae8..bf0877294 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackBuilder.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackBuilder.scala @@ -135,21 +135,21 @@ object OperandStackBuilder { schedule(pcOfNextStatement(pc), stack) case NonVirtualMethodCall(pc, _, _, _, _, receiver: IdBasedVar, params: Seq[IdBasedVar]) => - params.foreach(p => stack.pop(p.asVar)) + params.reverse.foreach(p => stack.pop(p.asVar)) stack.pop(receiver) schedule(pcOfNextStatement(pc), stack) case VirtualMethodCall(pc, _, _, _, _, receiver: IdBasedVar, params: Seq[IdBasedVar]) => - params.foreach(p => stack.pop(p.asVar)) + params.reverse.foreach(p => stack.pop(p.asVar)) stack.pop(receiver) schedule(pcOfNextStatement(pc), stack) case StaticMethodCall(pc, _, _, _, _, params: Seq[IdBasedVar]) => - params.foreach(p => stack.pop(p.asVar)) + params.reverse.foreach(p => stack.pop(p.asVar)) schedule(pcOfNextStatement(pc), stack) case InvokedynamicMethodCall(pc, _, _, _, params: Seq[IdBasedVar]) => - params.foreach(p => stack.pop(p.asVar)) + params.reverse.foreach(p => stack.pop(p.asVar)) schedule(pcOfNextStatement(pc), stack) case ExprStmt(pc, expr) => @@ -182,7 +182,7 @@ object OperandStackBuilder { case ClassConst(_, _) => List() case DynamicConst(_, _, _, _) => List() case NullExpr(_) => List() - case BinaryExpr(_, _, _, left, right) => processExpr(left) ++ processExpr(right) + case BinaryExpr(_, _, _, left, right) => processExpr(right) ++ processExpr(left) case PrefixExpr(_, _, _, operand: IdBasedVar) => List(operand) case PrimitiveTypecastExpr(_, _, operand: IdBasedVar) => List(operand) case New(_, _) => List() @@ -191,10 +191,10 @@ object OperandStackBuilder { case ArrayLength(_, arrayRef: IdBasedVar) => List(arrayRef) case GetField(_, _, _, _, objRef: IdBasedVar) => List(objRef) case GetStatic(_, _, _, _) => List() - case InvokedynamicFunctionCall(_, _, _, _, params: Seq[IdBasedVar]) => params.map(p => p.asVar).toList - case NonVirtualFunctionCall(_, _, _, _, _, receiver: IdBasedVar, params: Seq[IdBasedVar]) => params.map(p => p.asVar).toList :+ receiver - case VirtualFunctionCall(_, _, _, _, _, receiver: IdBasedVar, params: Seq[IdBasedVar]) => params.map(p => p.asVar).toList :+ receiver - case StaticFunctionCall(_, _, _, _, _, params: Seq[IdBasedVar]) => params.map(p => p.asVar).toList + case InvokedynamicFunctionCall(_, _, _, _, params: Seq[IdBasedVar]) => params.map(p => p.asVar).toList.reverse + case NonVirtualFunctionCall(_, _, _, _, _, receiver: IdBasedVar, params: Seq[IdBasedVar]) => params.map(p => p.asVar).toList.reverse :+ receiver + case VirtualFunctionCall(_, _, _, _, _, receiver: IdBasedVar, params: Seq[IdBasedVar]) => params.map(p => p.asVar).toList.reverse :+ receiver + case StaticFunctionCall(_, _, _, _, _, params: Seq[IdBasedVar]) => params.map(p => p.asVar).toList.reverse case _ => throw new RuntimeException("Unknown expression: " + expr) } } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/InlineLocalTransformer.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/InlineLocalTransformer.scala index 31bf69cc4..4843ee5c7 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/InlineLocalTransformer.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/InlineLocalTransformer.scala @@ -1,37 +1,46 @@ package boomerang.scope.opal.transformation.transformer +import boomerang.scope.opal.transformation.stack.OperandStackHandler import boomerang.scope.opal.transformation.{RegisterLocal, StackLocal, TacLocal} -import org.opalj.br.cfg.CFG import org.opalj.tac._ import scala.collection.mutable object InlineLocalTransformer { - def apply(code: Array[Stmt[TacLocal]], cfg: CFG[Stmt[IdBasedVar], TACStmts[IdBasedVar]]): Array[Stmt[TacLocal]] = { + def apply(code: Array[Stmt[TacLocal]], stackHandler: OperandStackHandler): Array[Stmt[TacLocal]] = { val statements = code.map(identity) - val bbs = cfg.allBBs - bbs.withFilter(bb => bb.startPC < bb.endPC).foreach(bb => { val localCache = mutable.Map.empty[TacLocal, Expr[TacLocal]] val localDefSites = mutable.Map.empty[TacLocal, (Int, Int)] - var index = bb.startPC - while (index <= bb.endPC) { - code(index) match { - case Assignment(pc, targetVar: StackLocal, c @ (_: SimpleValueConst | _: FunctionCall[TacLocal] | _: GetField[TacLocal] | _: GetStatic)) => - localCache.put(targetVar, c) - localDefSites.put(targetVar, (index, pc)) + val max = code.length - 1 + Range(0, max).foreach(i => { + statements(i) match { + // Collect all expressions that may replace stack to register assignments + case Assignment(pc, targetVar: StackLocal, c @ (_: SimpleValueConst)) => + if (!stackHandler.isBranchedOperand(pc, targetVar.id)) { + if (localCache.contains(targetVar)) { + throw new RuntimeException("Did not discover branched operand") + } + + localCache.put(targetVar, c) + localDefSites.put(targetVar, (i, pc)) + } + // Replace stack to register expressions if possible: + // r = $s becomes r = from previous assignment $s = case Assignment(pc, targetVar: RegisterLocal, rightVar: StackLocal) => /*if (localCache.contains(rightVar)) { val localExpr = localCache(rightVar) - statements(index) = Assignment(pc, targetVar, localExpr) + statements(i) = Assignment(pc, targetVar, localExpr) val localDefSite = localDefSites.getOrElse(rightVar, throw new RuntimeException("Def sites not consistent")) statements(localDefSite._1) = Nop(localDefSite._2) }*/ + // Array related assignments case Assignment(pc, targetVar: StackLocal, expr) => expr match { + // Replace the counts in new array creation with concrete integers if available case NewArray(arrPc, counts, arrayType) => var countDefSites = List.empty[(Int, Int)] @@ -52,14 +61,15 @@ object InlineLocalTransformer { } }) - statements(index) = Assignment(pc, targetVar, NewArray(arrPc, newCounts, arrayType)) + statements(i) = Assignment(pc, targetVar, NewArray(arrPc, newCounts, arrayType)) countDefSites.foreach(defSite => statements(defSite._1) = Nop(defSite._2)) + // Replace the index expression with the concrete integer value if available case ArrayLoad(arrPc, arrayIndex: StackLocal, arrayRef) => if (localCache.contains(arrayIndex)) { val localExpr = localCache(arrayIndex) if (localExpr.isIntConst) { - statements(index) = Assignment(pc, targetVar, ArrayLoad(arrPc, localExpr, arrayRef)) + statements(i) = Assignment(pc, targetVar, ArrayLoad(arrPc, localExpr, arrayRef)) val localDefSite = localDefSites.getOrElse(arrayIndex, throw new RuntimeException("Def sites not consistent")) statements(localDefSite._1) = Nop(localDefSite._2) @@ -73,7 +83,7 @@ object InlineLocalTransformer { if (localExpr.isIntConst) { // TODO Also inline value if it is a simple constant - statements(index) = ArrayStore(pc, arrayRef, localExpr, value) + statements(i) = ArrayStore(pc, arrayRef, localExpr, value) val localDefSite = localDefSites.getOrElse(arrayIndex, throw new RuntimeException("Def sites not consistent")) statements(localDefSite._1) = Nop(localDefSite._2) @@ -81,12 +91,8 @@ object InlineLocalTransformer { } case _ => } - - index += 1 - } }) - val max = code.length - 1 Range(0, max).foreach(i => { statements(i) match { @@ -108,35 +114,6 @@ object InlineLocalTransformer { } }) - /*Range(0, max).foreach(i => { - statements(i) match { - case ArrayStore(pc, arrayRef, index, value) => - val allocSiteIndex = findArrayIndexAllocSite(i, index) - val allocSiteStmt = statements(i) - - //statements(allocSiteIndex) = Nop(allocSiteStmt.pc) - //statements(i) = ArrayStore(pc, arrayRef, allocSiteStmt.asAssignment) - case _ => - } - }) - - def findArrayIndexAllocSite(index: Int, expr: Expr[TacLocal]): Int = { - Range(index, 0, -1).foreach(i => { - val currStmt = statements(i) - - if (currStmt.isAssignment) { - val assignStmt = currStmt.asAssignment - - if (assignStmt.targetVar == expr && assignStmt.expr.isIntConst) { - return i - } - } - }) - - -1 - }*/ - statements } - } diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala index 4c3372524..c30ad3215 100644 --- a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala @@ -6,7 +6,7 @@ import boomerang.scope.opal.transformation.TacBodyBuilder import boomerang.scope.test.MethodSignature import boomerang.scope.test.targets.{ConstructorTarget, InvokeExprTarget, SingleTarget} import com.typesafe.config.{Config, ConfigValueFactory} -import org.junit.Test +import org.junit.{Assert, Test} import org.opalj.br.analyses.Project import org.opalj.br.analyses.cg.InitialEntryPointsKey import org.opalj.tac.cg.{CHACallGraphKey, CallGraph} @@ -49,4 +49,28 @@ class OpalInvokeExprTest { println(opalMethod.tac.statements.mkString("Array(\n\t", "\n\t", "\n)")) } + @Test + def staticInvokeExprTest(): Unit = { + val opalSetup = new OpalSetup() + opalSetup.setupOpal(classOf[InvokeExprTarget].getName) + + val signature = new MethodSignature(classOf[InvokeExprTarget].getName, "staticInvokeExpr", "V") + val method = opalSetup.resolveMethod(signature) + val opalMethod = OpalMethod(method) + + var checked = false + opalMethod.getStatements.forEach(stmt => { + if (stmt.containsInvokeExpr()) { + val invokeExpr = stmt.getInvokeExpr + + Assert.assertTrue(invokeExpr.isStaticInvokeExpr) + Assert.assertEquals(2, invokeExpr.getArgs.size()) + + checked = true + } + }) + + Assert.assertTrue(checked) + } + } diff --git a/testCore/src/main/java/test/setup/MethodWrapper.java b/boomerangScope/src/main/java/boomerang/utils/MethodWrapper.java similarity index 99% rename from testCore/src/main/java/test/setup/MethodWrapper.java rename to boomerangScope/src/main/java/boomerang/utils/MethodWrapper.java index af7601d20..5f25fd862 100644 --- a/testCore/src/main/java/test/setup/MethodWrapper.java +++ b/boomerangScope/src/main/java/boomerang/utils/MethodWrapper.java @@ -9,7 +9,7 @@ *

    Contributors: Johannes Spaeth - initial API and implementation * ***************************************************************************** */ -package test.setup; +package boomerang.utils; import java.util.Collections; import java.util.List; diff --git a/boomerangScope/src/test/java/boomerang/scope/test/targets/A.java b/boomerangScope/src/test/java/boomerang/scope/test/targets/A.java index 27cc9766b..fac46905a 100644 --- a/boomerangScope/src/test/java/boomerang/scope/test/targets/A.java +++ b/boomerangScope/src/test/java/boomerang/scope/test/targets/A.java @@ -14,4 +14,7 @@ public class A { public void methodCall(@SuppressWarnings("unused") int i) {} + + public static void staticMethodCall( + @SuppressWarnings("unused") int i1, @SuppressWarnings("unused") int i2) {} } diff --git a/boomerangScope/src/test/java/boomerang/scope/test/targets/ArrayTarget.java b/boomerangScope/src/test/java/boomerang/scope/test/targets/ArrayTarget.java index a6f346fc4..6d61cdc0f 100644 --- a/boomerangScope/src/test/java/boomerang/scope/test/targets/ArrayTarget.java +++ b/boomerangScope/src/test/java/boomerang/scope/test/targets/ArrayTarget.java @@ -54,8 +54,8 @@ public static void singleArrayStoreVar() { } public static void multiArrayStore() { - int[][] arr = new int[2][3]; - arr[0][0] = 1; + A[][] arr = new A[2][3]; + arr[0][1] = new A(); System.out.println(Arrays.deepToString(arr)); } diff --git a/boomerangScope/src/test/java/boomerang/scope/test/targets/InvokeExprTarget.java b/boomerangScope/src/test/java/boomerang/scope/test/targets/InvokeExprTarget.java index e6d1abd3e..03d20af31 100644 --- a/boomerangScope/src/test/java/boomerang/scope/test/targets/InvokeExprTarget.java +++ b/boomerangScope/src/test/java/boomerang/scope/test/targets/InvokeExprTarget.java @@ -16,6 +16,7 @@ public class InvokeExprTarget { public static void main(String[] args) { constructorCall(); instanceInvokeExpr(); + staticInvokeExpr(); alias(); } @@ -30,6 +31,11 @@ public static void instanceInvokeExpr() { a.methodCall(i); } + public static void staticInvokeExpr() { + int i = 20; + A.staticMethodCall(10, i); + } + public static void alias() { int i = 10; A a = new A(); diff --git a/idealPDS/src/test/java/test/IDEALTestingFramework.java b/idealPDS/src/test/java/test/IDEALTestingFramework.java index d0caa04a0..e0c80cca2 100644 --- a/idealPDS/src/test/java/test/IDEALTestingFramework.java +++ b/idealPDS/src/test/java/test/IDEALTestingFramework.java @@ -43,7 +43,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import sync.pds.solver.WeightFunctions; -import test.setup.MethodWrapper; +import boomerang.utils.MethodWrapper; import typestate.TransitionFunction; import typestate.finiteautomata.TypeStateMachineWeightFunctions; diff --git a/testCore/src/main/java/test/TestingFramework.java b/testCore/src/main/java/test/TestingFramework.java index a39ab8a48..691d017f1 100644 --- a/testCore/src/main/java/test/TestingFramework.java +++ b/testCore/src/main/java/test/TestingFramework.java @@ -20,7 +20,7 @@ import java.util.List; import java.util.stream.Collectors; import org.junit.Assert; -import test.setup.MethodWrapper; +import boomerang.utils.MethodWrapper; import test.setup.OpalTestSetup; import test.setup.TestSetup; diff --git a/testCore/src/main/java/test/setup/OpalTestSetup.java b/testCore/src/main/java/test/setup/OpalTestSetup.java index 3be62e8f7..7bc92a99c 100644 --- a/testCore/src/main/java/test/setup/OpalTestSetup.java +++ b/testCore/src/main/java/test/setup/OpalTestSetup.java @@ -11,6 +11,7 @@ */ package test.setup; +import boomerang.utils.MethodWrapper; import boomerang.scope.DataFlowScope; import boomerang.scope.FrameworkScope; import boomerang.scope.Method; diff --git a/testCore/src/main/java/test/setup/SootTestSetup.java b/testCore/src/main/java/test/setup/SootTestSetup.java index 6ffb07bd1..4dfb78fe5 100644 --- a/testCore/src/main/java/test/setup/SootTestSetup.java +++ b/testCore/src/main/java/test/setup/SootTestSetup.java @@ -11,6 +11,7 @@ */ package test.setup; +import boomerang.utils.MethodWrapper; import boomerang.scope.DataFlowScope; import boomerang.scope.FrameworkScope; import boomerang.scope.Method; diff --git a/testCore/src/main/java/test/setup/SootUpTestSetup.java b/testCore/src/main/java/test/setup/SootUpTestSetup.java index 2348e9fd0..ec8a0c8dc 100644 --- a/testCore/src/main/java/test/setup/SootUpTestSetup.java +++ b/testCore/src/main/java/test/setup/SootUpTestSetup.java @@ -11,6 +11,7 @@ */ package test.setup; +import boomerang.utils.MethodWrapper; import boomerang.scope.DataFlowScope; import boomerang.scope.FrameworkScope; import boomerang.scope.Method; diff --git a/testCore/src/main/java/test/setup/TestSetup.java b/testCore/src/main/java/test/setup/TestSetup.java index 6e8f9e009..07b3ab9db 100644 --- a/testCore/src/main/java/test/setup/TestSetup.java +++ b/testCore/src/main/java/test/setup/TestSetup.java @@ -11,6 +11,7 @@ */ package test.setup; +import boomerang.utils.MethodWrapper; import boomerang.scope.DataFlowScope; import boomerang.scope.FrameworkScope; import boomerang.scope.Method; From 8cfa423ba86b184c323d05704cbbcf474918f734 Mon Sep 17 00:00:00 2001 From: Sven Meyer Date: Wed, 16 Apr 2025 14:17:59 +0200 Subject: [PATCH 40/61] Generalize method parsing in DemandDrivenAnalysis --- .../callgraph/BoomerangResolver.java | 12 ++- .../DefaultBackwardFlowFunction.java | 2 +- .../DefaultForwardFlowFunction.java | 2 +- .../SimpleSpecificationGuidedManager.java | 5 +- .../java/boomerang/guided/Specification.java | 90 +++++++++++++++---- .../options/IntAndStringAllocationSite.java | 2 +- .../results/ForwardBoomerangResults.java | 5 +- .../solver/BackwardBoomerangSolver.java | 2 +- .../solver/ForwardBoomerangSolver.java | 2 +- .../guided/CustomFlowFunctionTest.java | 13 ++- .../DemandDrivenGuidedAnalysisTest.java | 12 +-- .../CustomBackwardFlowFunction.java | 4 +- .../CustomForwardFlowFunction.java | 2 +- .../cases/bugfixes/issue5/Issue5Test.java | 4 +- .../fields/complexity/Fields20LongTest.java | 2 + .../java/test/core/AbstractBoomerangTest.java | 2 +- .../test/java/test/core/FirstArgumentOf.java | 3 +- .../test/core/MultiQueryBoomerangTest.java | 2 +- .../test/core/QueryForCallSiteDetector.java | 3 +- .../scope/opal/tac/OpalDeclaredMethod.scala | 11 ++- .../scope/opal/tac/OpalInvokeExpr.scala | 4 +- .../opal/tac/OpalStatementFormatter.scala | 2 +- .../boomerang/scope/opal/tac/OpalVal.scala | 14 ++- .../scope/opal/OpalAssignmentTest.scala | 2 +- .../boomerang/scope/opal/OpalLocalTest.scala | 6 +- .../soot/jimple/JimpleDeclaredMethod.java | 14 +++ .../scope/soot/jimple/JimpleInvokeExpr.java | 2 +- .../scope/soot/jimple/JimpleStatement.java | 4 +- .../boomerang/scope/soot/SootScopeTest.java | 4 +- .../sootup/jimple/JimpleUpDeclaredMethod.java | 13 +++ .../sootup/jimple/JimpleUpInvokeExpr.java | 2 +- .../scope/wala/WALADeclaredMethod.java | 6 ++ .../boomerang/scope/wala/WALAInvokeExpr.java | 2 +- .../java/boomerang/scope/DeclaredMethod.java | 3 + .../main/java/boomerang/scope/InvokeExpr.java | 2 +- .../TypeStateMachineWeightFunctions.java | 6 +- .../statemachines/HasNextStateMachine.java | 2 +- .../statemachines/KeyStoreStateMachine.java | 2 +- .../statemachines/SignatureStateMachine.java | 2 +- .../test/java/test/IDEALTestingFramework.java | 6 +- .../src/main/java/test/TestingFramework.java | 6 +- .../main/java/test/setup/OpalTestSetup.java | 2 +- .../main/java/test/setup/SootTestSetup.java | 2 +- .../main/java/test/setup/SootUpTestSetup.java | 2 +- .../src/main/java/test/setup/TestSetup.java | 2 +- 45 files changed, 211 insertions(+), 81 deletions(-) diff --git a/boomerangPDS/src/main/java/boomerang/callgraph/BoomerangResolver.java b/boomerangPDS/src/main/java/boomerang/callgraph/BoomerangResolver.java index 9d4f8216c..4a611b68a 100644 --- a/boomerangPDS/src/main/java/boomerang/callgraph/BoomerangResolver.java +++ b/boomerangPDS/src/main/java/boomerang/callgraph/BoomerangResolver.java @@ -115,7 +115,8 @@ public void computeFallback(ObservableDynamicICFG observableDynamicICFG) { @Override public Method resolveSpecialInvoke(InvokeExpr ie) { Collection methodFromClassOrFromSuperclass = - getMethodFromClassOrFromSuperclass(ie.getMethod(), ie.getMethod().getDeclaringClass()); + getMethodFromClassOrFromSuperclass( + ie.getDeclaredMethod(), ie.getDeclaredMethod().getDeclaringClass()); if (methodFromClassOrFromSuperclass.size() > 1) { throw new RuntimeException( "Illegal state, a special call should exactly resolve to one target"); @@ -126,7 +127,8 @@ public Method resolveSpecialInvoke(InvokeExpr ie) { @Override public Method resolveStaticInvoke(InvokeExpr ie) { Collection methodFromClassOrFromSuperclass = - getMethodFromClassOrFromSuperclass(ie.getMethod(), ie.getMethod().getDeclaringClass()); + getMethodFromClassOrFromSuperclass( + ie.getDeclaredMethod(), ie.getDeclaredMethod().getDeclaringClass()); if (methodFromClassOrFromSuperclass.size() > 1) { throw new RuntimeException( "Illegal state, a static call should exactly resolve to one target"); @@ -243,7 +245,8 @@ protected void allocationSiteFound( if (type.isRefType()) { for (Method calleeMethod : getMethodFromClassOrFromSuperclass( - invokeExpr.getInvokeExpr().getMethod(), type.getWrappedClass())) { + invokeExpr.getInvokeExpr().getDeclaredMethod(), + type.getWrappedClass())) { results.add(calleeMethod); } } else if (type.isArrayType()) { @@ -251,7 +254,8 @@ protected void allocationSiteFound( if (base.isRefType()) { for (Method calleeMethod : getMethodFromClassOrFromSuperclass( - invokeExpr.getInvokeExpr().getMethod(), base.getWrappedClass())) { + invokeExpr.getInvokeExpr().getDeclaredMethod(), + base.getWrappedClass())) { results.add(calleeMethod); } } diff --git a/boomerangPDS/src/main/java/boomerang/flowfunction/DefaultBackwardFlowFunction.java b/boomerangPDS/src/main/java/boomerang/flowfunction/DefaultBackwardFlowFunction.java index ea3c707d9..68fbf4adb 100644 --- a/boomerangPDS/src/main/java/boomerang/flowfunction/DefaultBackwardFlowFunction.java +++ b/boomerangPDS/src/main/java/boomerang/flowfunction/DefaultBackwardFlowFunction.java @@ -174,7 +174,7 @@ public Collection normalFlow(Edge currEdge, Val fact) { @Override public Collection callToReturnFlow(Edge edge, Val fact) { - if (FlowFunctionUtils.isSystemArrayCopy(edge.getTarget().getInvokeExpr().getMethod())) { + if (FlowFunctionUtils.isSystemArrayCopy(edge.getTarget().getInvokeExpr().getDeclaredMethod())) { return systemArrayCopyFlow(edge, fact); } return normalFlow(edge, fact); diff --git a/boomerangPDS/src/main/java/boomerang/flowfunction/DefaultForwardFlowFunction.java b/boomerangPDS/src/main/java/boomerang/flowfunction/DefaultForwardFlowFunction.java index b9535c421..959ab1be8 100644 --- a/boomerangPDS/src/main/java/boomerang/flowfunction/DefaultForwardFlowFunction.java +++ b/boomerangPDS/src/main/java/boomerang/flowfunction/DefaultForwardFlowFunction.java @@ -208,7 +208,7 @@ protected boolean killFlow(Statement curr, Val value) { @Override public Collection callToReturnFlow(ForwardQuery query, Edge edge, Val fact) { - if (FlowFunctionUtils.isSystemArrayCopy(edge.getStart().getInvokeExpr().getMethod())) { + if (FlowFunctionUtils.isSystemArrayCopy(edge.getStart().getInvokeExpr().getDeclaredMethod())) { return systemArrayCopyFlow(edge, fact); } return normalFlow(query, edge, fact); diff --git a/boomerangPDS/src/main/java/boomerang/guided/SimpleSpecificationGuidedManager.java b/boomerangPDS/src/main/java/boomerang/guided/SimpleSpecificationGuidedManager.java index 13aa0dc2f..a4ce1b398 100644 --- a/boomerangPDS/src/main/java/boomerang/guided/SimpleSpecificationGuidedManager.java +++ b/boomerangPDS/src/main/java/boomerang/guided/SimpleSpecificationGuidedManager.java @@ -102,7 +102,10 @@ public boolean isInOnList( // lets notify us in such a case.. throw new UnsupportedOperationException("possibly unspported case? investigate!"); } - if (stmt.getInvokeExpr().getMethod().getSignature().equals(methodSelector.getMethodStr())) { + if (stmt.getInvokeExpr() + .getDeclaredMethod() + .toMethodWrapper() + .equals(methodSelector.getMethod())) { Collection on = methodSelector.getOn(); return isInList(on, direction, stmt, fact); } diff --git a/boomerangPDS/src/main/java/boomerang/guided/Specification.java b/boomerangPDS/src/main/java/boomerang/guided/Specification.java index c9194099f..13c38c8a4 100644 --- a/boomerangPDS/src/main/java/boomerang/guided/Specification.java +++ b/boomerangPDS/src/main/java/boomerang/guided/Specification.java @@ -11,12 +11,15 @@ */ package boomerang.guided; +import boomerang.utils.MethodWrapper; import com.google.common.base.Objects; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; +import java.util.ArrayList; import java.util.Collection; import java.util.LinkedHashSet; +import java.util.List; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -33,19 +36,19 @@ public enum QueryDirection { BACKWARD } - private final Set methodAndQueries; + private final Collection methodAndQueries; private Specification(Collection spec) { - methodAndQueries = spec.stream().map(this::parse).collect(Collectors.toSet()); + this.methodAndQueries = spec.stream().map(this::parse).collect(Collectors.toSet()); } private MethodWithSelector parse(String input) { - Pattern arguments = Pattern.compile("\\((.*?)\\)"); - Matcher argumentMatcher = arguments.matcher(input); Set on = new LinkedHashSet<>(); Set go = new LinkedHashSet<>(); // Handle arguments + Pattern arguments = Pattern.compile("\\((.*?)\\)"); + Matcher argumentMatcher = arguments.matcher(input); if (argumentMatcher.find()) { String group = argumentMatcher.group(1); String[] args = group.split(","); @@ -89,7 +92,63 @@ private MethodWithSelector parse(String input) { throw new RuntimeException("Parsing Specification failed. Please check your specification"); } - return new MethodWithSelector(sootMethod, on, go); + // To avoid reworking the complete parsing process, we keep the soot signature and transform + // it into a general method descriptor + MethodWrapper methodWrapper = parseSootSignature(sootMethod); + return new MethodWithSelector(methodWrapper, on, go); + } + + private MethodWrapper parseSootSignature(String signature) { + String declaringClass; + String returnType; + String name; + List paramList; + + Pattern pattern1 = Pattern.compile("<([^:]+):"); + Matcher matcher1 = pattern1.matcher(signature); + if (matcher1.find()) { + declaringClass = matcher1.group(1).trim(); + } else { + throw new IllegalArgumentException( + "Could not extract declaring class from signature: " + signature); + } + + Pattern pattern2 = Pattern.compile(":\\s+([^\\s]+)\\s+[^\\s]+\\("); + Matcher matcher2 = pattern2.matcher(signature); + if (matcher2.find()) { + returnType = matcher2.group(1).trim(); + } else { + throw new IllegalArgumentException( + "Could not extract return type from signature: " + signature); + } + + Pattern pattern3 = Pattern.compile("\\s+([^\\s]+)\\("); + Matcher matcher3 = pattern3.matcher(signature); + if (matcher3.find()) { + name = matcher3.group(1).trim(); + } else { + throw new IllegalArgumentException("Could not extract name from signature: " + signature); + } + + Pattern pattern4 = Pattern.compile("\\(([^)]*)\\)"); + Matcher matcher4 = pattern4.matcher(signature); + if (matcher4.find()) { + String params = matcher4.group(1).trim(); + + paramList = new ArrayList<>(); + if (!params.isEmpty()) { + String[] paramArray = params.split(","); + + for (String param : paramArray) { + paramList.add(param.trim()); + } + } + } else { + throw new IllegalArgumentException( + "Could not extract parameters from signature: " + signature); + } + + return new MethodWrapper(declaringClass, name, returnType, paramList); } private void createQuerySelector( @@ -107,17 +166,18 @@ private void createQuerySelector( } public static class MethodWithSelector { - MethodWithSelector( - String methodStr, Collection on, Collection go) { - this.methodStr = methodStr; - this.on = on; - this.go = go; - } - private final String methodStr; + private final MethodWrapper method; private final Collection on; private final Collection go; + public MethodWithSelector( + MethodWrapper method, Collection on, Collection go) { + this.method = method; + this.on = on; + this.go = go; + } + public Collection getOn() { return on; } @@ -126,8 +186,8 @@ public Collection getGo() { return go; } - public String getMethodStr() { - return methodStr; + public MethodWrapper getMethod() { + return method; } } @@ -193,7 +253,7 @@ public static Specification create(String... spec) { return new Specification(Set.of(spec)); } - public Set getMethodAndQueries() { + public Collection getMethodAndQueries() { return methodAndQueries; } } diff --git a/boomerangPDS/src/main/java/boomerang/options/IntAndStringAllocationSite.java b/boomerangPDS/src/main/java/boomerang/options/IntAndStringAllocationSite.java index 8d6c4adc0..8f7567a47 100644 --- a/boomerangPDS/src/main/java/boomerang/options/IntAndStringAllocationSite.java +++ b/boomerangPDS/src/main/java/boomerang/options/IntAndStringAllocationSite.java @@ -39,7 +39,7 @@ public Optional getAllocationSite(Method method, Statement statement, // BigInteger.valueOf(x) -> allocation site is x if (statement.containsInvokeExpr()) { - DeclaredMethod declaredMethod = statement.getInvokeExpr().getMethod(); + DeclaredMethod declaredMethod = statement.getInvokeExpr().getDeclaredMethod(); if (declaredMethod .toString() diff --git a/boomerangPDS/src/main/java/boomerang/results/ForwardBoomerangResults.java b/boomerangPDS/src/main/java/boomerang/results/ForwardBoomerangResults.java index bf8485816..5e1318821 100644 --- a/boomerangPDS/src/main/java/boomerang/results/ForwardBoomerangResults.java +++ b/boomerangPDS/src/main/java/boomerang/results/ForwardBoomerangResults.java @@ -205,7 +205,7 @@ public Map getInvokedMethodOnInstance() { Map invokedMethodsOnInstance = Maps.newHashMap(); if (query.cfgEdge().getStart().containsInvokeExpr()) { invokedMethodsOnInstance.put( - query.cfgEdge(), query.cfgEdge().getStart().getInvokeExpr().getMethod()); + query.cfgEdge(), query.cfgEdge().getStart().getInvokeExpr().getDeclaredMethod()); } queryToSolvers .get(query) @@ -223,7 +223,8 @@ public Map getInvokedMethodOnInstance() { if (curr.getInvokeExpr().isInstanceInvokeExpr()) { Val base = curr.getInvokeExpr().getBase(); if (base.equals(fact)) { - invokedMethodsOnInstance.put(currEdge, curr.getInvokeExpr().getMethod()); + invokedMethodsOnInstance.put( + currEdge, curr.getInvokeExpr().getDeclaredMethod()); } } } diff --git a/boomerangPDS/src/main/java/boomerang/solver/BackwardBoomerangSolver.java b/boomerangPDS/src/main/java/boomerang/solver/BackwardBoomerangSolver.java index 0ec9b2935..faa485991 100644 --- a/boomerangPDS/src/main/java/boomerang/solver/BackwardBoomerangSolver.java +++ b/boomerangPDS/src/main/java/boomerang/solver/BackwardBoomerangSolver.java @@ -114,7 +114,7 @@ protected Collection computeReturnFlow( protected void callFlow(Method caller, Node curr, Statement callSite) { InvokeExpr invokeExpr = callSite.getInvokeExpr(); - if (dataFlowScope.isExcluded(invokeExpr.getMethod())) { + if (dataFlowScope.isExcluded(invokeExpr.getDeclaredMethod())) { byPassFlowAtCallsite(caller, curr); return; } diff --git a/boomerangPDS/src/main/java/boomerang/solver/ForwardBoomerangSolver.java b/boomerangPDS/src/main/java/boomerang/solver/ForwardBoomerangSolver.java index eaae6e502..7f058ddea 100644 --- a/boomerangPDS/src/main/java/boomerang/solver/ForwardBoomerangSolver.java +++ b/boomerangPDS/src/main/java/boomerang/solver/ForwardBoomerangSolver.java @@ -431,7 +431,7 @@ public void callFlow( Edge callSiteEdge, InvokeExpr invokeExpr) { assert icfg.isCallStmt(callSiteEdge.getStart()); - if (dataFlowScope.isExcluded(invokeExpr.getMethod())) { + if (dataFlowScope.isExcluded(invokeExpr.getDeclaredMethod())) { byPassFlowAtCallSite(caller, currNode, callSiteEdge.getStart()); return; } diff --git a/boomerangPDS/src/test/java/boomerang/guided/CustomFlowFunctionTest.java b/boomerangPDS/src/test/java/boomerang/guided/CustomFlowFunctionTest.java index 14f294c09..64b0ed7d4 100644 --- a/boomerangPDS/src/test/java/boomerang/guided/CustomFlowFunctionTest.java +++ b/boomerangPDS/src/test/java/boomerang/guided/CustomFlowFunctionTest.java @@ -31,13 +31,13 @@ import boomerang.scope.Statement; import boomerang.scope.Val; import boomerang.solver.BackwardBoomerangSolver; +import boomerang.utils.MethodWrapper; import com.google.common.collect.Table; import java.util.List; import java.util.Optional; import org.junit.Assert; import org.junit.Test; import test.TestingFramework; -import boomerang.utils.MethodWrapper; import wpds.impl.Weight.NoWeight; public class CustomFlowFunctionTest { @@ -132,7 +132,11 @@ public void killOnSystemExitForwardTest() { .anyMatch( statement -> statement.containsInvokeExpr() - && statement.getInvokeExpr().getMethod().getName().equals("queryFor")); + && statement + .getInvokeExpr() + .getDeclaredMethod() + .getName() + .equals("queryFor")); Assert.assertFalse(t); } @@ -142,8 +146,9 @@ public static BackwardQuery selectQueryForStatement(Method method) { .filter(Statement::containsInvokeExpr) .filter( x -> { - System.out.println("methodname: " + x.getInvokeExpr().getMethod().getName()); - return x.getInvokeExpr().getMethod().getName().equals("queryFor"); + System.out.println( + "methodname: " + x.getInvokeExpr().getDeclaredMethod().getName()); + return x.getInvokeExpr().getDeclaredMethod().getName().equals("queryFor"); }) .findFirst(); if (queryStatement.isEmpty()) { diff --git a/boomerangPDS/src/test/java/boomerang/guided/DemandDrivenGuidedAnalysisTest.java b/boomerangPDS/src/test/java/boomerang/guided/DemandDrivenGuidedAnalysisTest.java index f0ef2c5c3..4f69a9ae3 100644 --- a/boomerangPDS/src/test/java/boomerang/guided/DemandDrivenGuidedAnalysisTest.java +++ b/boomerangPDS/src/test/java/boomerang/guided/DemandDrivenGuidedAnalysisTest.java @@ -45,6 +45,7 @@ import boomerang.scope.Method; import boomerang.scope.Statement; import boomerang.scope.Val; +import boomerang.utils.MethodWrapper; import java.io.Serializable; import java.util.List; import java.util.Optional; @@ -54,7 +55,6 @@ import org.junit.Assert; import org.junit.Test; import test.TestingFramework; -import boomerang.utils.MethodWrapper; import wpds.impl.Weight.NoWeight; public class DemandDrivenGuidedAnalysisTest { @@ -438,9 +438,9 @@ public static BackwardQuery selectFirstArgOfQueryTarget(Method method) { .filter(Statement::containsInvokeExpr) .filter( x -> - x.getInvokeExpr().getMethod().getName().equals("queryFor") + x.getInvokeExpr().getDeclaredMethod().getName().equals("queryFor") && x.getInvokeExpr() - .getMethod() + .getDeclaredMethod() .getDeclaringClass() .getFullyQualifiedName() .equals("boomerang.guided.targets.Query")) @@ -474,9 +474,9 @@ public static BackwardQuery selectFirstFileInitArgument(Method method) { .filter(Statement::containsInvokeExpr) .filter( x -> - x.getInvokeExpr().getMethod().getName().equals("") + x.getInvokeExpr().getDeclaredMethod().getName().equals("") && x.getInvokeExpr() - .getMethod() + .getDeclaredMethod() .getDeclaringClass() .getFullyQualifiedName() .equals("java.io.File")) @@ -501,7 +501,7 @@ public static BackwardQuery selectFirstBaseOfToString(Method method) { Optional toStringCall = method.getStatements().stream() .filter(Statement::containsInvokeExpr) - .filter(x -> x.getInvokeExpr().getMethod().getName().equals("toString")) + .filter(x -> x.getInvokeExpr().getDeclaredMethod().getName().equals("toString")) .findFirst(); if (toStringCall.isEmpty()) { Assert.fail("No call to toString() found in method " + method.getName()); diff --git a/boomerangPDS/src/test/java/boomerang/guided/flowfunction/CustomBackwardFlowFunction.java b/boomerangPDS/src/test/java/boomerang/guided/flowfunction/CustomBackwardFlowFunction.java index 66e125cbd..4f82149a8 100644 --- a/boomerangPDS/src/test/java/boomerang/guided/flowfunction/CustomBackwardFlowFunction.java +++ b/boomerangPDS/src/test/java/boomerang/guided/flowfunction/CustomBackwardFlowFunction.java @@ -31,7 +31,7 @@ public CustomBackwardFlowFunction(DefaultBackwardFlowFunctionOptions options) { @Override public Collection normalFlow(Edge edge, Val fact) { if (edge.getTarget().containsInvokeExpr()) { - DeclaredMethod method = edge.getTarget().getInvokeExpr().getMethod(); + DeclaredMethod method = edge.getTarget().getInvokeExpr().getDeclaredMethod(); // Avoid any propagations by passing the call site (also when the fact is not used at the call // site). if (method.getDeclaringClass().getFullyQualifiedName().equals("java.lang.System") @@ -45,7 +45,7 @@ public Collection normalFlow(Edge edge, Val fact) { @Override public Collection callToReturnFlow(Edge edge, Val fact) { if (edge.getTarget().containsInvokeExpr()) { - DeclaredMethod method = edge.getTarget().getInvokeExpr().getMethod(); + DeclaredMethod method = edge.getTarget().getInvokeExpr().getDeclaredMethod(); // Avoid any propagations by passing the call site (also when the fact is not used at the call // site). if (method.getDeclaringClass().getFullyQualifiedName().equals("java.lang.System") diff --git a/boomerangPDS/src/test/java/boomerang/guided/flowfunction/CustomForwardFlowFunction.java b/boomerangPDS/src/test/java/boomerang/guided/flowfunction/CustomForwardFlowFunction.java index 15d3f5821..f144f6c20 100644 --- a/boomerangPDS/src/test/java/boomerang/guided/flowfunction/CustomForwardFlowFunction.java +++ b/boomerangPDS/src/test/java/boomerang/guided/flowfunction/CustomForwardFlowFunction.java @@ -54,7 +54,7 @@ public Set normalFlow(ForwardQuery query, Edge nextEdge, Val fact) { } public boolean declaredMethodIsSystemExit(Statement callSite) { - DeclaredMethod method = callSite.getInvokeExpr().getMethod(); + DeclaredMethod method = callSite.getInvokeExpr().getDeclaredMethod(); return method.getDeclaringClass().getFullyQualifiedName().equals("java.lang.System") && method.getName().equals("exit"); } diff --git a/boomerangPDS/src/test/java/test/cases/bugfixes/issue5/Issue5Test.java b/boomerangPDS/src/test/java/test/cases/bugfixes/issue5/Issue5Test.java index a52f1edb0..ff822331a 100644 --- a/boomerangPDS/src/test/java/test/cases/bugfixes/issue5/Issue5Test.java +++ b/boomerangPDS/src/test/java/test/cases/bugfixes/issue5/Issue5Test.java @@ -24,6 +24,7 @@ import boomerang.scope.Statement; import boomerang.scope.Type; import boomerang.scope.Val; +import boomerang.utils.MethodWrapper; import java.util.Collection; import java.util.HashSet; import java.util.List; @@ -33,7 +34,6 @@ import org.junit.Assert; import org.junit.Test; import test.TestingFramework; -import boomerang.utils.MethodWrapper; import wpds.impl.Weight.NoWeight; /** @@ -106,7 +106,7 @@ private void assertResults( Collection methodCalledOnFoo = new HashSet<>(); for (Statement s : statements) { System.out.println("\t" + s); - DeclaredMethod calledMethod = s.getInvokeExpr().getMethod(); + DeclaredMethod calledMethod = s.getInvokeExpr().getDeclaredMethod(); System.out.println("\t\t" + calledMethod); MethodWrapper methodWrapper = new MethodWrapper( diff --git a/boomerangPDS/src/test/java/test/cases/fields/complexity/Fields20LongTest.java b/boomerangPDS/src/test/java/test/cases/fields/complexity/Fields20LongTest.java index 16d261472..4b6ff85a8 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/complexity/Fields20LongTest.java +++ b/boomerangPDS/src/test/java/test/cases/fields/complexity/Fields20LongTest.java @@ -11,9 +11,11 @@ */ package test.cases.fields.complexity; +import org.junit.Ignore; import org.junit.Test; import test.core.AbstractBoomerangTest; +@Ignore("Takes too long") public class Fields20LongTest extends AbstractBoomerangTest { private final String target = Fields20LongTarget.class.getName(); diff --git a/boomerangPDS/src/test/java/test/core/AbstractBoomerangTest.java b/boomerangPDS/src/test/java/test/core/AbstractBoomerangTest.java index 12e837a22..9061dd4ee 100644 --- a/boomerangPDS/src/test/java/test/core/AbstractBoomerangTest.java +++ b/boomerangPDS/src/test/java/test/core/AbstractBoomerangTest.java @@ -30,6 +30,7 @@ import boomerang.solver.ForwardBoomerangSolver; import boomerang.util.AccessPath; import boomerang.util.DefaultValueMap; +import boomerang.utils.MethodWrapper; import com.google.common.base.Joiner; import com.google.common.base.Stopwatch; import com.google.common.collect.Lists; @@ -53,7 +54,6 @@ import test.TestingFramework; import test.core.selfrunning.AllocatedObject; import test.core.selfrunning.NoAllocatedObject; -import boomerang.utils.MethodWrapper; import wpds.impl.Transition; import wpds.impl.Weight.NoWeight; import wpds.impl.WeightedPAutomaton; diff --git a/boomerangPDS/src/test/java/test/core/FirstArgumentOf.java b/boomerangPDS/src/test/java/test/core/FirstArgumentOf.java index cb7ab60e3..564db64f7 100644 --- a/boomerangPDS/src/test/java/test/core/FirstArgumentOf.java +++ b/boomerangPDS/src/test/java/test/core/FirstArgumentOf.java @@ -30,7 +30,8 @@ public FirstArgumentOf(String methodNameMatcher) { public Optional test(Edge stmt) { if (!(stmt.getStart().containsInvokeExpr())) return Optional.empty(); InvokeExpr invokeExpr = stmt.getStart().getInvokeExpr(); - if (!invokeExpr.getMethod().getName().matches(methodNameMatcher)) return Optional.empty(); + if (!invokeExpr.getDeclaredMethod().getName().matches(methodNameMatcher)) + return Optional.empty(); Val param = invokeExpr.getArg(0); if (!param.isLocal()) return Optional.empty(); BackwardQuery newBackwardQuery = BackwardQuery.make(stmt, param); diff --git a/boomerangPDS/src/test/java/test/core/MultiQueryBoomerangTest.java b/boomerangPDS/src/test/java/test/core/MultiQueryBoomerangTest.java index aca859b8b..aeaf849c2 100644 --- a/boomerangPDS/src/test/java/test/core/MultiQueryBoomerangTest.java +++ b/boomerangPDS/src/test/java/test/core/MultiQueryBoomerangTest.java @@ -20,6 +20,7 @@ import boomerang.scope.AnalysisScope; import boomerang.scope.FrameworkScope; import boomerang.scope.Val; +import boomerang.utils.MethodWrapper; import com.google.common.base.Joiner; import com.google.common.collect.HashMultimap; import com.google.common.collect.Multimap; @@ -33,7 +34,6 @@ import org.junit.rules.TestName; import org.junit.rules.Timeout; import test.TestingFramework; -import boomerang.utils.MethodWrapper; import wpds.impl.Weight; public class MultiQueryBoomerangTest extends TestingFramework { diff --git a/boomerangPDS/src/test/java/test/core/QueryForCallSiteDetector.java b/boomerangPDS/src/test/java/test/core/QueryForCallSiteDetector.java index ebbd39aca..c9f71c3da 100644 --- a/boomerangPDS/src/test/java/test/core/QueryForCallSiteDetector.java +++ b/boomerangPDS/src/test/java/test/core/QueryForCallSiteDetector.java @@ -57,7 +57,8 @@ public FirstArgumentOf(String methodNameMatcher) { public Optional test(Edge stmt) { if (!(stmt.getTarget().containsInvokeExpr())) return Optional.empty(); InvokeExpr invokeExpr = stmt.getTarget().getInvokeExpr(); - if (!invokeExpr.getMethod().getName().matches(methodNameMatcher)) return Optional.empty(); + if (!invokeExpr.getDeclaredMethod().getName().matches(methodNameMatcher)) + return Optional.empty(); Val param = invokeExpr.getArg(0); if (!param.isLocal()) return Optional.empty(); BackwardQuery newBackwardQuery = BackwardQuery.make(stmt, param); diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalDeclaredMethod.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalDeclaredMethod.scala index a99bc2756..63cc66958 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalDeclaredMethod.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalDeclaredMethod.scala @@ -2,11 +2,12 @@ package boomerang.scope.opal.tac import boomerang.scope.opal.{OpalClient, OpalFrameworkScope} import boomerang.scope.{DeclaredMethod, InvokeExpr, Type, WrappedClass} +import boomerang.utils.MethodWrapper import org.opalj.br.MethodSignature -import org.opalj.tac.{Call, DUVar, Var} -import org.opalj.value.ValueInformation +import org.opalj.tac.{Call, Var} import java.util +import scala.jdk.CollectionConverters._ case class OpalDeclaredMethod[+V <: Var[V]](invokeExpr: InvokeExpr, delegate: Call[V]) extends DeclaredMethod(invokeExpr) { @@ -42,5 +43,11 @@ case class OpalDeclaredMethod[+V <: Var[V]](invokeExpr: InvokeExpr, delegate: Ca override def getReturnType: Type = OpalType(delegate.descriptor.returnType) + override def toMethodWrapper: MethodWrapper = new MethodWrapper( + delegate.declaringClass.toJava, + delegate.name, + delegate.descriptor.returnType.toJava, + delegate.descriptor.parameterTypes.map(p => p.toJava).toList.asJava) + override def toString: String = delegate.descriptor.toJava } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalInvokeExpr.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalInvokeExpr.scala index d687176a7..b85ce36f1 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalInvokeExpr.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalInvokeExpr.scala @@ -31,7 +31,7 @@ class OpalMethodInvokeExpr(val delegate: MethodCall[TacLocal], method: OpalMetho throw new RuntimeException("Method call is not an instance invoke expression") } - override def getMethod: DeclaredMethod = OpalDeclaredMethod(this, delegate) + override def getDeclaredMethod: DeclaredMethod = OpalDeclaredMethod(this, delegate) override def isSpecialInvokeExpr: Boolean = delegate.astID == NonVirtualMethodCall.ASTID @@ -73,7 +73,7 @@ class OpalFunctionInvokeExpr(val delegate: FunctionCall[TacLocal], method: OpalM throw new RuntimeException("Function call is not an instance invoke expression") } - override def getMethod: DeclaredMethod = OpalDeclaredMethod(this, delegate) + override def getDeclaredMethod: DeclaredMethod = OpalDeclaredMethod(this, delegate) override def isSpecialInvokeExpr: Boolean = delegate.astID == NonVirtualFunctionCall.ASTID diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatementFormatter.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatementFormatter.scala index d34da37c9..99596b350 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatementFormatter.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatementFormatter.scala @@ -18,7 +18,7 @@ object OpalStatementFormatter { assign = s"${stmt.getLeftOp} = " } - return s"$assign$base${stmt.getInvokeExpr.getMethod.getName}(${Joiner.on(",").join(stmt.getInvokeExpr.getArgs)})" + return s"$assign$base${stmt.getInvokeExpr.getDeclaredMethod.getName}(${Joiner.on(",").join(stmt.getInvokeExpr.getArgs)})" } if (stmt.isAssignStmt) { diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalVal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalVal.scala index 2b1439d97..d5f83e0c5 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalVal.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalVal.scala @@ -42,10 +42,20 @@ class OpalVal(val delegate: Expr[TacLocal], method: OpalMethod, unbalanced: Cont override def isArrayAllocationVal: Boolean = delegate.isNewArray - // TODO Deal with multiple arrays override def getArrayAllocationSize: Val = { if (isArrayAllocationVal) { - return new OpalLocal(delegate.asNewArray.counts.head.asVar, method) + val counts = delegate.asNewArray.counts + + /* TODO + * For now, the scope just returns the size of the first dimension. + * In the future, we may change it to returning a list of values + */ + val firstIndex = counts.last + if (firstIndex.isVar) { + return new OpalLocal(firstIndex.asVar, method) + } else { + return new OpalVal(firstIndex, method) + } } throw new RuntimeException("Value is not an array allocation expression") diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalAssignmentTest.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalAssignmentTest.scala index 42ace91d0..b54ced889 100644 --- a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalAssignmentTest.scala +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalAssignmentTest.scala @@ -27,7 +27,7 @@ class OpalAssignmentTest { val leftOp = stmt.getLeftOp Assert.assertTrue(leftOp.isLocal) - Assert.assertTrue(rightOp.getArrayAllocationSize.isLocal) + Assert.assertTrue(rightOp.getArrayAllocationSize.isIntConstant) Assert.assertTrue(rightOp.getType.isArrayType) } } diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalLocalTest.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalLocalTest.scala index d9dd4188b..ce48e67f7 100644 --- a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalLocalTest.scala +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalLocalTest.scala @@ -25,7 +25,7 @@ class OpalLocalTest { var checked = false opalMethod.getStatements.forEach(stmt => { - if (stmt.containsInvokeExpr() && stmt.getInvokeExpr.getMethod.getName.equals("callWithThis")) { + if (stmt.containsInvokeExpr() && stmt.getInvokeExpr.getDeclaredMethod.getName.equals("callWithThis")) { val invokeExpr = stmt.getInvokeExpr val base = invokeExpr.getBase @@ -109,7 +109,7 @@ class OpalLocalTest { var checked = false opalMethod.getStatements.forEach(stmt => { - if (stmt.containsInvokeExpr() && stmt.getInvokeExpr.getMethod.getName.equals("methodCall")) { + if (stmt.containsInvokeExpr() && stmt.getInvokeExpr.getDeclaredMethod.getName.equals("methodCall")) { val invokeExpr = stmt.getInvokeExpr val base = invokeExpr.getBase val arg = invokeExpr.getArg(0) @@ -151,7 +151,7 @@ class OpalLocalTest { var checked2: Boolean = false jimpleMethod2.getStatements.forEach(stmt => { - if (stmt.containsInvokeExpr && stmt.getInvokeExpr.getMethod.getName == "methodCall") { + if (stmt.containsInvokeExpr && stmt.getInvokeExpr.getDeclaredMethod.getName == "methodCall") { val invokeExpr = stmt.getInvokeExpr val base = invokeExpr.getBase val arg = invokeExpr.getArg(0) diff --git a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleDeclaredMethod.java b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleDeclaredMethod.java index b9dc8adf6..205042994 100644 --- a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleDeclaredMethod.java +++ b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleDeclaredMethod.java @@ -15,9 +15,11 @@ import boomerang.scope.InvokeExpr; import boomerang.scope.Type; import boomerang.scope.WrappedClass; +import boomerang.utils.MethodWrapper; import java.util.ArrayList; import java.util.List; import java.util.Objects; +import java.util.stream.Collectors; import soot.SootMethodRef; public class JimpleDeclaredMethod extends DeclaredMethod { @@ -74,6 +76,18 @@ public Type getReturnType() { return new JimpleType(delegate.getReturnType()); } + @Override + public MethodWrapper toMethodWrapper() { + List paramTypes = + delegate.getParameterTypes().stream().map(soot.Type::toString).collect(Collectors.toList()); + + return new MethodWrapper( + delegate.getDeclaringClass().getName(), + delegate.getName(), + delegate.getReturnType().toString(), + paramTypes); + } + public SootMethodRef getDelegate() { return delegate; } diff --git a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleInvokeExpr.java b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleInvokeExpr.java index 9ec606e9b..be3ecf432 100644 --- a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleInvokeExpr.java +++ b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleInvokeExpr.java @@ -65,7 +65,7 @@ public Val getBase() { } @Override - public DeclaredMethod getMethod() { + public DeclaredMethod getDeclaredMethod() { return new JimpleDeclaredMethod(this, delegate.getMethodRef()); } diff --git a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleStatement.java b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleStatement.java index caddb7088..673b6a26d 100644 --- a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleStatement.java +++ b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleStatement.java @@ -246,7 +246,7 @@ public String getShortLabel() { InvokeExpr invokeExpr = getInvokeExpr(); if (invokeExpr.isStaticInvokeExpr()) { return (isAssignStmt() ? getLeftOp() + " = " : "") - + invokeExpr.getMethod() + + invokeExpr.getDeclaredMethod() + "(" + invokeExpr.getArgs().toString().replace("[", "").replace("]", "") + ")"; @@ -255,7 +255,7 @@ public String getShortLabel() { return (isAssignStmt() ? getLeftOp() + " = " : "") + invokeExpr.getBase() + "." - + invokeExpr.getMethod() + + invokeExpr.getDeclaredMethod() + "(" + invokeExpr.getArgs().toString().replace("[", "").replace("]", "") + ")"; diff --git a/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootScopeTest.java b/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootScopeTest.java index 65da4a30c..c51fa893e 100644 --- a/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootScopeTest.java +++ b/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootScopeTest.java @@ -41,7 +41,7 @@ public void thisLocalTest() { boolean checked = false; for (Statement stmt : jimpleMethod.getStatements()) { if (stmt.containsInvokeExpr() - && stmt.getInvokeExpr().getMethod().getName().equals("callWithThis")) { + && stmt.getInvokeExpr().getDeclaredMethod().getName().equals("callWithThis")) { InvokeExpr invokeExpr = stmt.getInvokeExpr(); Val base = invokeExpr.getBase(); @@ -114,7 +114,7 @@ public void hashCodeEqualsLocalTest() { boolean checked = false; for (Statement stmt : jimpleMethod.getStatements()) { if (stmt.containsInvokeExpr() - && stmt.getInvokeExpr().getMethod().getName().equals("methodCall")) { + && stmt.getInvokeExpr().getDeclaredMethod().getName().equals("methodCall")) { InvokeExpr invokeExpr = stmt.getInvokeExpr(); Val base = invokeExpr.getBase(); Val arg = invokeExpr.getArg(0); diff --git a/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpDeclaredMethod.java b/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpDeclaredMethod.java index 3ab91f921..2fbcc54a0 100644 --- a/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpDeclaredMethod.java +++ b/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpDeclaredMethod.java @@ -15,6 +15,7 @@ import boomerang.scope.Type; import boomerang.scope.WrappedClass; import boomerang.scope.sootup.SootUpFrameworkScope; +import boomerang.utils.MethodWrapper; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; @@ -81,6 +82,18 @@ public Type getReturnType() { return new JimpleUpType(delegate.getType()); } + @Override + public MethodWrapper toMethodWrapper() { + List paramTypes = + delegate.getParameterTypes().stream().map(Object::toString).collect(Collectors.toList()); + + return new MethodWrapper( + delegate.getDeclClassType().getFullyQualifiedName(), + delegate.getName(), + delegate.getType().toString(), + paramTypes); + } + @Override public int hashCode() { return Arrays.hashCode(new Object[] {delegate}); diff --git a/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpInvokeExpr.java b/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpInvokeExpr.java index 8fbd24659..9e10e7078 100644 --- a/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpInvokeExpr.java +++ b/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpInvokeExpr.java @@ -68,7 +68,7 @@ public Val getBase() { } @Override - public DeclaredMethod getMethod() { + public DeclaredMethod getDeclaredMethod() { return new JimpleUpDeclaredMethod(this, delegate.getMethodSignature()); } diff --git a/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALADeclaredMethod.java b/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALADeclaredMethod.java index ecf861a0e..668a18d75 100644 --- a/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALADeclaredMethod.java +++ b/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALADeclaredMethod.java @@ -15,6 +15,7 @@ import boomerang.scope.InvokeExpr; import boomerang.scope.Type; import boomerang.scope.WrappedClass; +import boomerang.utils.MethodWrapper; import com.ibm.wala.types.MethodReference; import java.util.List; @@ -67,6 +68,11 @@ public Type getReturnType() { throw new UnsupportedOperationException("Not implemented yet"); } + @Override + public MethodWrapper toMethodWrapper() { + throw new UnsupportedOperationException("Not implemented yet"); + } + @Override public int hashCode() { final int prime = 31; diff --git a/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALAInvokeExpr.java b/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALAInvokeExpr.java index aa145d85a..f02032586 100644 --- a/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALAInvokeExpr.java +++ b/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALAInvokeExpr.java @@ -57,7 +57,7 @@ public Val getBase() { } @Override - public DeclaredMethod getMethod() { + public DeclaredMethod getDeclaredMethod() { return new WALADeclaredMethod(this, inv.getCallSite().getDeclaredTarget()); } diff --git a/boomerangScope/src/main/java/boomerang/scope/DeclaredMethod.java b/boomerangScope/src/main/java/boomerang/scope/DeclaredMethod.java index 35af1263b..8308623b5 100644 --- a/boomerangScope/src/main/java/boomerang/scope/DeclaredMethod.java +++ b/boomerangScope/src/main/java/boomerang/scope/DeclaredMethod.java @@ -11,6 +11,7 @@ */ package boomerang.scope; +import boomerang.utils.MethodWrapper; import java.util.List; import java.util.Objects; @@ -38,6 +39,8 @@ public DeclaredMethod(InvokeExpr inv) { public abstract Type getReturnType(); + public abstract MethodWrapper toMethodWrapper(); + public InvokeExpr getInvokeExpr() { return inv; } diff --git a/boomerangScope/src/main/java/boomerang/scope/InvokeExpr.java b/boomerangScope/src/main/java/boomerang/scope/InvokeExpr.java index 87d11d32a..42789ae8a 100644 --- a/boomerangScope/src/main/java/boomerang/scope/InvokeExpr.java +++ b/boomerangScope/src/main/java/boomerang/scope/InvokeExpr.java @@ -23,7 +23,7 @@ public interface InvokeExpr { Val getBase(); - DeclaredMethod getMethod(); + DeclaredMethod getDeclaredMethod(); boolean isSpecialInvokeExpr(); diff --git a/idealPDS/src/main/java/typestate/finiteautomata/TypeStateMachineWeightFunctions.java b/idealPDS/src/main/java/typestate/finiteautomata/TypeStateMachineWeightFunctions.java index 52812f4aa..c05d92eaa 100644 --- a/idealPDS/src/main/java/typestate/finiteautomata/TypeStateMachineWeightFunctions.java +++ b/idealPDS/src/main/java/typestate/finiteautomata/TypeStateMachineWeightFunctions.java @@ -80,7 +80,7 @@ public TransitionFunction callToReturn( if (invokeExpr.isInstanceInvokeExpr()) { if (invokeExpr.getBase().equals(succ.fact())) { for (MatcherTransition trans : transition) { - if (trans.matches(invokeExpr.getMethod()) + if (trans.matches(invokeExpr.getDeclaredMethod()) && (trans.getType().equals(Type.OnCallToReturn) || trans.getType().equals(Type.OnCallOrOnCallToReturn))) { res.add(trans); @@ -106,7 +106,7 @@ private TransitionFunction getMatchingTransitions( Set res = new HashSet<>(); if (filteredTrans.isEmpty() || !transitionStmt.containsInvokeExpr()) return getOne(); for (MatcherTransition trans : filteredTrans) { - if (trans.matches(transitionStmt.getInvokeExpr().getMethod())) { + if (trans.matches(transitionStmt.getInvokeExpr().getDeclaredMethod())) { LOGGER.trace( "Found potential transition at {}, now checking if parameter match", transitionStmt); Parameter param = trans.getParam(); @@ -170,7 +170,7 @@ public Collection> generateThisAtAnyCal if (unit.containsInvokeExpr()) { if (unit.getInvokeExpr().isInstanceInvokeExpr()) { Val base = unit.getInvokeExpr().getBase(); - if (unit.getInvokeExpr().getMethod().getSignature().matches(declaredMethod)) { + if (unit.getInvokeExpr().getDeclaredMethod().getSignature().matches(declaredMethod)) { if (base.getType().isSubtypeOf(declaredType)) { return Collections.singleton( new WeightedForwardQuery<>( diff --git a/idealPDS/src/main/java/typestate/impl/statemachines/HasNextStateMachine.java b/idealPDS/src/main/java/typestate/impl/statemachines/HasNextStateMachine.java index c6ff52967..e7ef4f87b 100644 --- a/idealPDS/src/main/java/typestate/impl/statemachines/HasNextStateMachine.java +++ b/idealPDS/src/main/java/typestate/impl/statemachines/HasNextStateMachine.java @@ -77,7 +77,7 @@ public Set> generateSeed(Edge edge) { if (unit.containsInvokeExpr() && unit.isAssignStmt()) { InvokeExpr invokeExpr = unit.getInvokeExpr(); if (invokeExpr.isInstanceInvokeExpr()) { - if (invokeExpr.getMethod().getName().contains("iterator")) { + if (invokeExpr.getDeclaredMethod().getName().contains("iterator")) { return Collections.singleton( new WeightedForwardQuery<>( edge, diff --git a/idealPDS/src/main/java/typestate/impl/statemachines/KeyStoreStateMachine.java b/idealPDS/src/main/java/typestate/impl/statemachines/KeyStoreStateMachine.java index 75db660f0..013930868 100644 --- a/idealPDS/src/main/java/typestate/impl/statemachines/KeyStoreStateMachine.java +++ b/idealPDS/src/main/java/typestate/impl/statemachines/KeyStoreStateMachine.java @@ -85,7 +85,7 @@ private Set keyStoreConstructor() { public Set> generateSeed(Edge edge) { Statement unit = edge.getStart(); if (unit.isAssignStmt() && unit.containsInvokeExpr()) { - if (isKeyStoreConstructor(unit.getInvokeExpr().getMethod())) { + if (isKeyStoreConstructor(unit.getInvokeExpr().getDeclaredMethod())) { return Collections.singleton( new WeightedForwardQuery<>( edge, diff --git a/idealPDS/src/main/java/typestate/impl/statemachines/SignatureStateMachine.java b/idealPDS/src/main/java/typestate/impl/statemachines/SignatureStateMachine.java index 454362b59..7fa3e52d9 100644 --- a/idealPDS/src/main/java/typestate/impl/statemachines/SignatureStateMachine.java +++ b/idealPDS/src/main/java/typestate/impl/statemachines/SignatureStateMachine.java @@ -138,7 +138,7 @@ private Set constructor() { public Collection> generateSeed(Edge edge) { Statement unit = edge.getStart(); if (unit.containsInvokeExpr()) { - DeclaredMethod method = unit.getInvokeExpr().getMethod(); + DeclaredMethod method = unit.getInvokeExpr().getDeclaredMethod(); if (method.getName().equals("getInstance") && method.getSubSignature().contains("Signature")) { return getLeftSideOf(edge); diff --git a/idealPDS/src/test/java/test/IDEALTestingFramework.java b/idealPDS/src/test/java/test/IDEALTestingFramework.java index e0c80cca2..9c22f5dc3 100644 --- a/idealPDS/src/test/java/test/IDEALTestingFramework.java +++ b/idealPDS/src/test/java/test/IDEALTestingFramework.java @@ -29,6 +29,7 @@ import boomerang.scope.Statement; import boomerang.scope.Val; import boomerang.solver.Strategies; +import boomerang.utils.MethodWrapper; import ideal.IDEALAnalysis; import ideal.IDEALAnalysisDefinition; import ideal.IDEALResultHandler; @@ -43,7 +44,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import sync.pds.solver.WeightFunctions; -import boomerang.utils.MethodWrapper; import typestate.TransitionFunction; import typestate.finiteautomata.TypeStateMachineWeightFunctions; @@ -175,14 +175,14 @@ private void parseExpectedQueryResults( } InvokeExpr invokeExpr = stmt.getInvokeExpr(); - DeclaredMethod declaredMethod = invokeExpr.getMethod(); + DeclaredMethod declaredMethod = invokeExpr.getDeclaredMethod(); String assertionsName = Assertions.class.getName(); if (!declaredMethod.getDeclaringClass().getFullyQualifiedName().equals(assertionsName)) { continue; } - String invocationName = invokeExpr.getMethod().getName(); + String invocationName = invokeExpr.getDeclaredMethod().getName(); if (invocationName.equals("shouldNotBeAnalyzed")) { queries.add(new ShouldNotBeAnalyzed(stmt)); diff --git a/testCore/src/main/java/test/TestingFramework.java b/testCore/src/main/java/test/TestingFramework.java index 691d017f1..332e85d90 100644 --- a/testCore/src/main/java/test/TestingFramework.java +++ b/testCore/src/main/java/test/TestingFramework.java @@ -14,14 +14,14 @@ import boomerang.scope.DataFlowScope; import boomerang.scope.FrameworkScope; import boomerang.scope.Method; +import boomerang.utils.MethodWrapper; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.stream.Collectors; import org.junit.Assert; -import boomerang.utils.MethodWrapper; -import test.setup.OpalTestSetup; +import test.setup.SootTestSetup; import test.setup.TestSetup; public class TestingFramework { @@ -30,7 +30,7 @@ public class TestingFramework { public TestingFramework() { // TODO Parameterize - this.testSetup = new OpalTestSetup(); + this.testSetup = new SootTestSetup(); } public FrameworkScope getFrameworkScope(MethodWrapper methodWrapper) { diff --git a/testCore/src/main/java/test/setup/OpalTestSetup.java b/testCore/src/main/java/test/setup/OpalTestSetup.java index 7bc92a99c..5367b1bb9 100644 --- a/testCore/src/main/java/test/setup/OpalTestSetup.java +++ b/testCore/src/main/java/test/setup/OpalTestSetup.java @@ -11,12 +11,12 @@ */ package test.setup; -import boomerang.utils.MethodWrapper; import boomerang.scope.DataFlowScope; import boomerang.scope.FrameworkScope; import boomerang.scope.Method; import boomerang.scope.opal.OpalFrameworkScope; import boomerang.scope.opal.tac.OpalMethod; +import boomerang.utils.MethodWrapper; import com.typesafe.config.Config; import com.typesafe.config.ConfigValueFactory; import java.io.File; diff --git a/testCore/src/main/java/test/setup/SootTestSetup.java b/testCore/src/main/java/test/setup/SootTestSetup.java index 4dfb78fe5..a9c4a27ae 100644 --- a/testCore/src/main/java/test/setup/SootTestSetup.java +++ b/testCore/src/main/java/test/setup/SootTestSetup.java @@ -11,13 +11,13 @@ */ package test.setup; -import boomerang.utils.MethodWrapper; import boomerang.scope.DataFlowScope; import boomerang.scope.FrameworkScope; import boomerang.scope.Method; import boomerang.scope.soot.BoomerangPretransformer; import boomerang.scope.soot.SootFrameworkScope; import boomerang.scope.soot.jimple.JimpleMethod; +import boomerang.utils.MethodWrapper; import java.io.File; import java.util.ArrayList; import java.util.List; diff --git a/testCore/src/main/java/test/setup/SootUpTestSetup.java b/testCore/src/main/java/test/setup/SootUpTestSetup.java index ec8a0c8dc..e8a7551bb 100644 --- a/testCore/src/main/java/test/setup/SootUpTestSetup.java +++ b/testCore/src/main/java/test/setup/SootUpTestSetup.java @@ -11,12 +11,12 @@ */ package test.setup; -import boomerang.utils.MethodWrapper; import boomerang.scope.DataFlowScope; import boomerang.scope.FrameworkScope; import boomerang.scope.Method; import boomerang.scope.sootup.BoomerangPreInterceptor; import boomerang.scope.sootup.SootUpFrameworkScope; +import boomerang.utils.MethodWrapper; import com.google.common.collect.Lists; import jakarta.annotation.Nonnull; import java.io.IOException; diff --git a/testCore/src/main/java/test/setup/TestSetup.java b/testCore/src/main/java/test/setup/TestSetup.java index 07b3ab9db..262e6a977 100644 --- a/testCore/src/main/java/test/setup/TestSetup.java +++ b/testCore/src/main/java/test/setup/TestSetup.java @@ -11,10 +11,10 @@ */ package test.setup; -import boomerang.utils.MethodWrapper; import boomerang.scope.DataFlowScope; import boomerang.scope.FrameworkScope; import boomerang.scope.Method; +import boomerang.utils.MethodWrapper; import java.util.List; public interface TestSetup { From d05f55d541ace5e9713625c0817b914230d49b41 Mon Sep 17 00:00:00 2001 From: Sven Meyer Date: Thu, 17 Apr 2025 09:43:11 +0200 Subject: [PATCH 41/61] Final fixes for opal scope --- .../SimpleSpecificationGuidedManager.java | 8 -------- .../targets/BranchingAfterNewStringTest.java | 1 - .../cases/bugfixes/issue5/Issue5Test.java | 12 ++---------- .../boomerang/scope/opal/tac/OpalField.scala | 11 ++++++++++- .../opal/tac/OpalStatementFormatter.scala | 8 ++++++-- .../scope/opal/transformation/StmtGraph.scala | 19 ++++++++++++------- .../stack/OperandStackHandler.scala | 5 ++++- .../transformer/NopTransformer.scala | 3 +-- .../scope/opal/OpalInvokeExprTest.scala | 2 +- .../scope/test/targets/SingleTarget.java | 14 ++++++++++++++ .../src/main/java/test/TestingFramework.java | 4 ++-- 11 files changed, 52 insertions(+), 35 deletions(-) diff --git a/boomerangPDS/src/main/java/boomerang/guided/SimpleSpecificationGuidedManager.java b/boomerangPDS/src/main/java/boomerang/guided/SimpleSpecificationGuidedManager.java index a4ce1b398..727085a4a 100644 --- a/boomerangPDS/src/main/java/boomerang/guided/SimpleSpecificationGuidedManager.java +++ b/boomerangPDS/src/main/java/boomerang/guided/SimpleSpecificationGuidedManager.java @@ -94,14 +94,6 @@ private Collection createNewQueries(MethodWithSelector sel, Statement stm public boolean isInOnList( MethodWithSelector methodSelector, Statement stmt, Val fact, QueryDirection direction) { - - // [spaeth] This only works for Soot propagations - // TODO: [ms] refactored soot checks away.. lets investigate why! maybe it needs just some - // translation/mapping for other frameworks - if (!stmt.getClass().toString().contains("Jimple")) { - // lets notify us in such a case.. - throw new UnsupportedOperationException("possibly unspported case? investigate!"); - } if (stmt.getInvokeExpr() .getDeclaredMethod() .toMethodWrapper() diff --git a/boomerangPDS/src/test/java/boomerang/guided/targets/BranchingAfterNewStringTest.java b/boomerangPDS/src/test/java/boomerang/guided/targets/BranchingAfterNewStringTest.java index dc2c17e2c..101a8c918 100644 --- a/boomerangPDS/src/test/java/boomerang/guided/targets/BranchingAfterNewStringTest.java +++ b/boomerangPDS/src/test/java/boomerang/guided/targets/BranchingAfterNewStringTest.java @@ -20,7 +20,6 @@ public static void main(String... args) { String y = new String("foo"); String bar = doPassArgument(Math.random() > 0 ? x : y); new File(bar); - ; } public static String doPassArgument(String param) { diff --git a/boomerangPDS/src/test/java/test/cases/bugfixes/issue5/Issue5Test.java b/boomerangPDS/src/test/java/test/cases/bugfixes/issue5/Issue5Test.java index ff822331a..12d84ed72 100644 --- a/boomerangPDS/src/test/java/test/cases/bugfixes/issue5/Issue5Test.java +++ b/boomerangPDS/src/test/java/test/cases/bugfixes/issue5/Issue5Test.java @@ -30,7 +30,6 @@ import java.util.List; import java.util.Optional; import java.util.Set; -import java.util.stream.Collectors; import org.junit.Assert; import org.junit.Test; import test.TestingFramework; @@ -108,15 +107,8 @@ private void assertResults( System.out.println("\t" + s); DeclaredMethod calledMethod = s.getInvokeExpr().getDeclaredMethod(); System.out.println("\t\t" + calledMethod); - MethodWrapper methodWrapper = - new MethodWrapper( - calledMethod.getDeclaringClass().getFullyQualifiedName(), - calledMethod.getName(), - calledMethod.getReturnType().toString(), - calledMethod.getParameterTypes().stream() - .map(Object::toString) - .collect(Collectors.toList())); - methodCalledOnFoo.add(methodWrapper); + + methodCalledOnFoo.add(calledMethod.toMethodWrapper()); } Assert.assertEquals(Set.of(expectedCalledMethodsOnFoo), methodCalledOnFoo); diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalField.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalField.scala index cb2ff1980..3fb891882 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalField.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalField.scala @@ -3,6 +3,8 @@ package boomerang.scope.opal.tac import boomerang.scope.{Field, Type} import org.opalj.br.{FieldType, ObjectType} +import java.util.Objects + case class OpalField(declaringClass: ObjectType, fieldType: FieldType, name: String) extends Field { override def isPredefinedField: Boolean = false @@ -11,5 +13,12 @@ case class OpalField(declaringClass: ObjectType, fieldType: FieldType, name: Str override def getType: Type = OpalType(fieldType) - override def toString: String = s"${declaringClass.fqn}.${fieldType.toJava} $name" + override def hashCode: Int = Objects.hash(super.hashCode(), declaringClass, fieldType, name) + + override def equals(other: Any): Boolean = other match { + case that: OpalField => this.declaringClass == that.declaringClass && this.fieldType == that.fieldType && this.name == that.name + case _ => false + } + + override def toString: String = s"$name" } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatementFormatter.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatementFormatter.scala index 99596b350..86497d599 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatementFormatter.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatementFormatter.scala @@ -27,7 +27,7 @@ object OpalStatementFormatter { } if (stmt.isFieldStore) { - return s"${stmt.getLeftOp} = ${stmt.getFieldStore.getX}.${stmt.getFieldStore.getY}" + return s"${stmt.getLeftOp} = ${stmt.getRightOp}" } if (stmt.isArrayStore) { @@ -40,6 +40,10 @@ object OpalStatementFormatter { if (delegate.asAssignment.expr.isVar && delegate.asAssignment.expr.asVar.isParameterLocal) { return s"${delegate.asAssignment.targetVar} := @${delegate.asAssignment.expr}: ${stmt.getMethod}" } + + if (delegate.asAssignment.expr.isVar && delegate.asAssignment.expr.asVar.isExceptionLocal) { + return s"${delegate.asAssignment.targetVar} := @caughtException: ${delegate.asAssignment.expr}" + } } if (delegate.astID == PutField.ASTID) { @@ -55,7 +59,7 @@ object OpalStatementFormatter { } if (stmt.isReturnStmt) { - return s"${delegate.pc}: return ${stmt.getReturnOp}" + return s"return ${stmt.getReturnOp}" } delegate.toString diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/StmtGraph.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/StmtGraph.scala index b32042693..a98894997 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/StmtGraph.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/StmtGraph.scala @@ -45,7 +45,7 @@ class StmtGraph private (val tac: Array[Stmt[TacLocal]], val heads: Set[Stmt[Tac } def remove(stmt: Stmt[TacLocal]): StmtGraph = { - if (stmt.astID == Return.ASTID) throw new RuntimeException("Cannot remove return statement") + if (tails.contains(stmt)) throw new RuntimeException("Cannot remove tail statement") val tempPreds = mutable.Map.from(predecessors) val tempSuccs = mutable.Map.from(successors) @@ -54,27 +54,32 @@ class StmtGraph private (val tac: Array[Stmt[TacLocal]], val heads: Set[Stmt[Tac val succs = successors(stmt) preds.foreach(pred => { val succsOfPred = successors(pred) - tempSuccs.put(pred, succsOfPred ++ succs) + + assert(succsOfPred.contains(stmt), "Inconsistent state in graph") + tempSuccs.put(pred, succsOfPred ++ succs - stmt) }) succs.foreach(succ => { val predsOfSuccs = predecessors(succ) - tempPreds.put(succ, predsOfSuccs ++ preds) + + assert(predsOfSuccs.contains(stmt), "Inconsistent state in graph") + tempPreds.put(succ, predsOfSuccs ++ preds - stmt) }) var newHeads = heads.map(identity) if (heads.contains(stmt)) { newHeads = newHeads - stmt - - if (newHeads.isEmpty) { - newHeads = succs - } + newHeads = newHeads ++ succs } val newStatements = statements.filter(s => s != stmt) val newPreds = tempPreds.filter(s => s._1 != stmt).toMap val newSuccs = tempSuccs.filter(s => s._1 != stmt).toMap + assert(!newHeads.contains(stmt)) + assert(!newStatements.contains(stmt)) + assert(!newPreds.contains(stmt)) + assert(!newSuccs.contains(stmt)) new StmtGraph(tac, newHeads, tails, newPreds, newSuccs, newStatements) } } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackHandler.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackHandler.scala index 26d6dfd44..0e36ed337 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackHandler.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackHandler.scala @@ -36,7 +36,10 @@ class OperandStackHandler { var modified = false existingStack.stackEntries.foreach(existingOp => { incomingStack.stackEntries.foreach(incomingOp => { - if (existingOp.id == incomingOp.id && existingOp.localId != incomingOp.localId) { + if (existingOp.id == incomingOp.id) { + // Update the counter of the incoming operand s.t. both operands describe + // the same local and mark both operands as branched + existingOp.updateCounter(existingOp.localId) incomingOp.updateCounter(existingOp.localId) modified = true diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/NopTransformer.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/NopTransformer.scala index 1984e42ca..6a9f5ad77 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/NopTransformer.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/NopTransformer.scala @@ -5,8 +5,7 @@ import org.opalj.tac.{If, Nop} object NopTransformer { - // TODO Make it more general - final val INITIAL_NOP = -10 + private final val INITIAL_NOP = Integer.MIN_VALUE def apply(stmtGraph: StmtGraph): StmtGraph = { val tac = stmtGraph.tac diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala index c30ad3215..221e6039a 100644 --- a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala @@ -22,7 +22,7 @@ class OpalInvokeExprTest { val opalSetup = new OpalSetup() opalSetup.setupOpal(classOf[SingleTarget].getName) - val signature = new MethodSignature(classOf[SingleTarget].getName, "branching", "I") + val signature = new MethodSignature(classOf[SingleTarget].getName, "branch", "V") val method = opalSetup.resolveMethod(signature) val opalMethod = OpalMethod(method) opalMethod.getControlFlowGraph diff --git a/boomerangScope/src/test/java/boomerang/scope/test/targets/SingleTarget.java b/boomerangScope/src/test/java/boomerang/scope/test/targets/SingleTarget.java index defd87bb2..1885d0ab0 100644 --- a/boomerangScope/src/test/java/boomerang/scope/test/targets/SingleTarget.java +++ b/boomerangScope/src/test/java/boomerang/scope/test/targets/SingleTarget.java @@ -11,6 +11,8 @@ */ package boomerang.scope.test.targets; +import java.io.File; + public class SingleTarget { public static void main(String[] args) { @@ -21,6 +23,7 @@ public static void main(String[] args) { usage(); whileLoop(); tryCatch(); + branch(); SingleTarget target = new SingleTarget(); target.block(); @@ -95,4 +98,15 @@ public void block() { System.out.println(a); } } + + public static void branch() { + String x = new String("bar"); + String y = new String("foo"); + String bar = doPassArgument(Math.random() > 0 ? x : y); + new File(bar); + } + + public static String doPassArgument(String s) { + return s; + } } diff --git a/testCore/src/main/java/test/TestingFramework.java b/testCore/src/main/java/test/TestingFramework.java index 332e85d90..465402360 100644 --- a/testCore/src/main/java/test/TestingFramework.java +++ b/testCore/src/main/java/test/TestingFramework.java @@ -21,7 +21,7 @@ import java.util.List; import java.util.stream.Collectors; import org.junit.Assert; -import test.setup.SootTestSetup; +import test.setup.OpalTestSetup; import test.setup.TestSetup; public class TestingFramework { @@ -30,7 +30,7 @@ public class TestingFramework { public TestingFramework() { // TODO Parameterize - this.testSetup = new SootTestSetup(); + this.testSetup = new OpalTestSetup(); } public FrameworkScope getFrameworkScope(MethodWrapper methodWrapper) { From 7304037ec6488953914635e98e6b916aa86b4ca6 Mon Sep 17 00:00:00 2001 From: Sven Meyer Date: Thu, 17 Apr 2025 10:27:13 +0200 Subject: [PATCH 42/61] Fix branching for switch statements --- .../test/cases/sets/TreeSetsLongTest.java | 23 +++++++++++- .../stack/OperandStackBuilder.scala | 15 +++++--- .../transformer/LocalTransformer.scala | 2 +- .../scope/opal/OpalInvokeExprTest.scala | 6 ++-- .../scope/test/targets/BranchingTarget.java | 36 +++++++++++++++++++ 5 files changed, 72 insertions(+), 10 deletions(-) create mode 100644 boomerangScope/src/test/java/boomerang/scope/test/targets/BranchingTarget.java diff --git a/boomerangPDS/src/test/java/test/cases/sets/TreeSetsLongTest.java b/boomerangPDS/src/test/java/test/cases/sets/TreeSetsLongTest.java index 1c9343c3e..5b2b475d0 100644 --- a/boomerangPDS/src/test/java/test/cases/sets/TreeSetsLongTest.java +++ b/boomerangPDS/src/test/java/test/cases/sets/TreeSetsLongTest.java @@ -11,12 +11,33 @@ */ package test.cases.sets; +import java.util.List; +import org.junit.Ignore; import org.junit.Test; import test.core.AbstractBoomerangTest; +@Ignore("Figure out which classes from the JDK have to be included") public class TreeSetsLongTest extends AbstractBoomerangTest { - private final String target = TreeSetsLongTest.class.getName(); + private final String target = TreeSetsLongTarget.class.getName(); + + @Override + protected List getIncludedPackages() { + return List.of( + "java.util.Set", + "java.util.AbstractSet", + "java.util.NavigableSet", + "java.util.SortedSet", + "java.util.HashSet", + "java.util.TreeSet", + "java.util.Iterator", + "java.util.Map", + "java.util.AbstractMap", + "java.util.TreeMap", + "java.util.TreeMap$Entry", + "java.util.NavigableMap", + "java.util.SortedMap"); + } @Test public void addAndRetrieve() { diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackBuilder.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackBuilder.scala index bf0877294..8ae86d81b 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackBuilder.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackBuilder.scala @@ -1,9 +1,9 @@ package boomerang.scope.opal.transformation.stack -import org.opalj.br.{Method, NoPCs} +import org.opalj.br.Method import org.opalj.br.instructions.{DUP, DUP2, DUP2_X1, DUP2_X2, DUP_X1, DUP_X2, NOP, POP, POP2, WIDE} import org.opalj.bytecode.PC -import org.opalj.tac.{ArrayLength, ArrayLoad, ArrayStore, Assignment, BinaryExpr, CaughtException, Checkcast, ClassConst, Compare, Const, DoubleConst, DynamicConst, Expr, ExprStmt, FloatConst, GetField, GetStatic, Goto, IdBasedVar, If, InstanceOf, IntConst, InvokedynamicFunctionCall, InvokedynamicMethodCall, JSR, LongConst, MethodHandleConst, MethodTypeConst, MonitorEnter, MonitorExit, NaiveTACode, New, NewArray, NonVirtualFunctionCall, NonVirtualMethodCall, Nop, NullExpr, Param, PrefixExpr, PrimitiveTypecastExpr, PutField, PutStatic, Ret, Return, ReturnValue, StaticFunctionCall, StaticMethodCall, Stmt, StringConst, Switch, Throw, VirtualFunctionCall, VirtualMethodCall} +import org.opalj.tac._ object OperandStackBuilder { @@ -60,10 +60,15 @@ object OperandStackBuilder { case Switch(_, defaultTarget, index: IdBasedVar, nPairs) => stack.pop(index) - // TODO branch targets - schedule(defaultTarget, stack) + nPairs.foreach(target => { + val targetStmt = tacNaive.stmts(target.value) + schedule(targetStmt.pc, stack) + }) + + val defaultTargetStmt = tacNaive.stmts(defaultTarget) + schedule(defaultTargetStmt.pc, stack) case Assignment(pc, targetVar: IdBasedVar, expr: Expr[IdBasedVar]) => - // Exception handlers are defined implicitly, so cannot pop them from the stack + // Exception handlers are defined implicitly, so we cannot pop them from the stack if (!exceptionHandlersPc.contains(pc)) { val operands = processExpr(expr) operands.foreach(op => stack.pop(op)) diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/LocalTransformer.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/LocalTransformer.scala index e81a007a7..1346f39b0 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/LocalTransformer.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/LocalTransformer.scala @@ -34,7 +34,7 @@ object LocalTransformer { case Switch(pc, defaultTarget, index, nPairs) => val indexExpr = transformExpr(pc, index) - return Switch(pc,defaultTarget, indexExpr, nPairs) + return Switch(pc, defaultTarget, indexExpr, nPairs) case Assignment(pc, targetVar, expr) => // Parameter definition statements if (pc == -1) { diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala index 221e6039a..6a79eeb8f 100644 --- a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala @@ -4,7 +4,7 @@ import boomerang.scope.DataFlowScope import boomerang.scope.opal.tac.OpalMethod import boomerang.scope.opal.transformation.TacBodyBuilder import boomerang.scope.test.MethodSignature -import boomerang.scope.test.targets.{ConstructorTarget, InvokeExprTarget, SingleTarget} +import boomerang.scope.test.targets.{BranchingTarget, ConstructorTarget, InvokeExprTarget, SingleTarget} import com.typesafe.config.{Config, ConfigValueFactory} import org.junit.{Assert, Test} import org.opalj.br.analyses.Project @@ -20,9 +20,9 @@ class OpalInvokeExprTest { @Test def instanceInvokeExprTest(): Unit = { val opalSetup = new OpalSetup() - opalSetup.setupOpal(classOf[SingleTarget].getName) + opalSetup.setupOpal(classOf[BranchingTarget].getName) - val signature = new MethodSignature(classOf[SingleTarget].getName, "branch", "V") + val signature = new MethodSignature(classOf[BranchingTarget].getName, "switchBranching", "V") val method = opalSetup.resolveMethod(signature) val opalMethod = OpalMethod(method) opalMethod.getControlFlowGraph diff --git a/boomerangScope/src/test/java/boomerang/scope/test/targets/BranchingTarget.java b/boomerangScope/src/test/java/boomerang/scope/test/targets/BranchingTarget.java new file mode 100644 index 000000000..7f7f52536 --- /dev/null +++ b/boomerangScope/src/test/java/boomerang/scope/test/targets/BranchingTarget.java @@ -0,0 +1,36 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ +package boomerang.scope.test.targets; + +public class BranchingTarget { + + public static void main(String[] args) { + switchBranching(); + } + + public static void switchBranching() { + int i = (int) (Math.random() * 3); + switch (i) { + case 0: + System.out.println(0); + break; + case 2: + System.out.println(1); + break; + case 1: + System.out.println(2); + break; + default: + System.out.println(i); + } + } +} From 36586e8a3a1a7a15cc26fbd54da937498611124f Mon Sep 17 00:00:00 2001 From: Sven Meyer Date: Thu, 17 Apr 2025 11:46:32 +0200 Subject: [PATCH 43/61] Fix equals and hashcode for OpalField --- .../scope/opal/tac/OpalControlFlowGraph.scala | 7 +------ .../boomerang/scope/opal/tac/OpalField.scala | 6 +++--- .../scope/opal/tac/OpalStatement.scala | 18 ++++++++---------- 3 files changed, 12 insertions(+), 19 deletions(-) diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalControlFlowGraph.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalControlFlowGraph.scala index ecb44bb35..f5b899bc7 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalControlFlowGraph.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalControlFlowGraph.scala @@ -52,15 +52,10 @@ class OpalControlFlowGraph(method: OpalMethod) extends ControlFlowGraph { val graph = method.tac.cfg - val head = new OpalStatement(Nop(-1), method) - startPointCache.add(head) - statements.add(head) - graph.heads.foreach(stmt => { val headStmt = new OpalStatement(stmt, method) - predsOfCache.put(headStmt, head) - succsOfCache.put(head, headStmt) + startPointCache.add(headStmt) }) graph.tails.foreach(stmt => { diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalField.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalField.scala index 3fb891882..93ed16411 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalField.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalField.scala @@ -5,7 +5,7 @@ import org.opalj.br.{FieldType, ObjectType} import java.util.Objects -case class OpalField(declaringClass: ObjectType, fieldType: FieldType, name: String) extends Field { +class OpalField(declaringClass: ObjectType, val fieldType: FieldType, val name: String) extends Field { override def isPredefinedField: Boolean = false @@ -13,10 +13,10 @@ case class OpalField(declaringClass: ObjectType, fieldType: FieldType, name: Str override def getType: Type = OpalType(fieldType) - override def hashCode: Int = Objects.hash(super.hashCode(), declaringClass, fieldType, name) + override def hashCode: Int = Objects.hash(super.hashCode(), fieldType, name) override def equals(other: Any): Boolean = other match { - case that: OpalField => this.declaringClass == that.declaringClass && this.fieldType == that.fieldType && this.name == that.name + case that: OpalField => this.fieldType == that.fieldType && this.name == that.name case _ => false } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala index 276ad89d5..124a48378 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala @@ -2,9 +2,7 @@ package boomerang.scope.opal.tac import boomerang.scope._ import boomerang.scope.opal.transformation.TacLocal -import com.google.common.base.Joiner -import org.opalj.tac.{DUVar, IdBasedVar, PrimitiveTypecastExpr, Stmt, Var} -import org.opalj.value.ValueInformation +import org.opalj.tac.{PrimitiveTypecastExpr, Stmt} import java.util import java.util.Objects @@ -43,13 +41,13 @@ class OpalStatement(val delegate: Stmt[TacLocal], m: OpalMethod) extends Stateme if (isFieldStore) { val fieldStore = delegate.asPutField - return OpalField(fieldStore.declaringClass, fieldStore.declaredFieldType, fieldStore.name) + return new OpalField(fieldStore.declaringClass, fieldStore.declaredFieldType, fieldStore.name) } if (isStaticFieldStore) { val fieldStore = delegate.asPutStatic - return OpalField(fieldStore.declaringClass, fieldStore.declaredFieldType, fieldStore.name) + return new OpalField(fieldStore.declaringClass, fieldStore.declaredFieldType, fieldStore.name) } if (isArrayStore) { @@ -76,7 +74,7 @@ class OpalStatement(val delegate: Stmt[TacLocal], m: OpalMethod) extends Stateme if (isFieldLoad) { val fieldLoad = delegate.asAssignment.expr.asGetField - return OpalField(fieldLoad.declaringClass, fieldLoad.declaredFieldType, fieldLoad.name) + return new OpalField(fieldLoad.declaringClass, fieldLoad.declaredFieldType, fieldLoad.name) } throw new RuntimeException("Statement is not a field load operation") @@ -261,7 +259,7 @@ class OpalStatement(val delegate: Stmt[TacLocal], m: OpalMethod) extends Stateme val fieldStore = delegate.asPutField val local = new OpalLocal(fieldStore.objRef.asVar, m) - val field = OpalField(fieldStore.declaringClass, fieldStore.declaredFieldType, fieldStore.name) + val field = new OpalField(fieldStore.declaringClass, fieldStore.declaredFieldType, fieldStore.name) return new Pair(local, field) } @@ -274,7 +272,7 @@ class OpalStatement(val delegate: Stmt[TacLocal], m: OpalMethod) extends Stateme val fieldLoad = delegate.asAssignment.expr.asGetField val local = new OpalLocal(fieldLoad.objRef.asVar, m) - val field = OpalField(fieldLoad.declaringClass, fieldLoad.declaredFieldType, fieldLoad.name) + val field = new OpalField(fieldLoad.declaringClass, fieldLoad.declaredFieldType, fieldLoad.name) return new Pair(local, field) } @@ -290,14 +288,14 @@ class OpalStatement(val delegate: Stmt[TacLocal], m: OpalMethod) extends Stateme if (isStaticFieldLoad) { val staticFieldLoad = delegate.asAssignment.expr.asGetStatic - val staticField = OpalField(staticFieldLoad.declaringClass, staticFieldLoad.declaredFieldType, staticFieldLoad.name) + val staticField = new OpalField(staticFieldLoad.declaringClass, staticFieldLoad.declaredFieldType, staticFieldLoad.name) return new OpalStaticFieldVal(staticField, m) } if (isStaticFieldStore) { val staticFieldStore = delegate.asPutStatic - val staticField = OpalField(staticFieldStore.declaringClass, staticFieldStore.declaredFieldType, staticFieldStore.name) + val staticField = new OpalField(staticFieldStore.declaringClass, staticFieldStore.declaredFieldType, staticFieldStore.name) return new OpalStaticFieldVal(staticField, m) } From b9a0aec3660a04d2d9828d5780dea5ab242fbe24 Mon Sep 17 00:00:00 2001 From: Sven Meyer Date: Thu, 17 Apr 2025 18:18:21 +0200 Subject: [PATCH 44/61] Add logic for including JDK classes --- .../cases/lists/LinkedListsLongTarget.java | 1 + .../boomerang/scope/opal/OpalCallGraph.scala | 19 ++++- .../scope/opal/tac/OpalPhantomMethod.scala | 22 +++--- .../opal/transformation/TacBodyBuilder.scala | 4 + .../stack/OperandStackBuilder.scala | 3 +- .../stack/OperandStackHandler.scala | 12 +-- .../transformer/LocalTransformer.scala | 3 +- .../main/java/test/setup/OpalTestSetup.java | 73 ++++++++++++++++++- 8 files changed, 111 insertions(+), 26 deletions(-) diff --git a/boomerangPDS/src/test/java/test/cases/lists/LinkedListsLongTarget.java b/boomerangPDS/src/test/java/test/cases/lists/LinkedListsLongTarget.java index 14d794bbd..9001f27bd 100644 --- a/boomerangPDS/src/test/java/test/cases/lists/LinkedListsLongTarget.java +++ b/boomerangPDS/src/test/java/test/cases/lists/LinkedListsLongTarget.java @@ -18,6 +18,7 @@ import test.core.QueryMethods; import test.core.selfrunning.AllocatedObject; +@SuppressWarnings("unused") public class LinkedListsLongTarget { @TestMethod diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalCallGraph.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalCallGraph.scala index d0103a416..c38d276e2 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalCallGraph.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalCallGraph.scala @@ -11,7 +11,10 @@ class OpalCallGraph(callGraph: org.opalj.tac.cg.CallGraph, entryPoints: Set[Meth callGraph.reachableMethods().foreach(method => { method.method match { - case definedMethod: DefinedMethod => addEdgesFromMethod(definedMethod) + case definedMethod: DefinedMethod => + if (definedMethod.definedMethod.body.isDefined) { + addEdgesFromMethod(definedMethod) + } // TODO Should this case be considered? // case definedMethods: MultipleDefinedMethods => // definedMethods.foreachDefinedMethod(m => addEdgesFromMethod(m)) @@ -33,11 +36,19 @@ class OpalCallGraph(callGraph: org.opalj.tac.cg.CallGraph, entryPoints: Set[Meth callees.foreach(callee => { callee.method match { case definedMethod: DefinedMethod => - val targetMethod = OpalMethod(definedMethod.definedMethod) + val method = definedMethod.definedMethod - addEdge(new Edge(srcStatement, targetMethod)) + if (method.body.isDefined) { + val targetMethod = OpalMethod(method) + + addEdge(new Edge(srcStatement, targetMethod)) + } else { + val targetMethod = OpalPhantomMethod(definedMethod.declaringClassType, definedMethod.name, definedMethod.descriptor, method.isStatic) + + addEdge(new Edge(srcStatement, targetMethod)) + } case virtualMethod: VirtualDeclaredMethod => - val targetMethod = OpalPhantomMethod(virtualMethod, srcStatement.getInvokeExpr.isStaticInvokeExpr) + val targetMethod = OpalPhantomMethod(virtualMethod.declaringClassType, virtualMethod.name, virtualMethod.descriptor, srcStatement.getInvokeExpr.isStaticInvokeExpr) addEdge(new Edge(srcStatement, targetMethod)) case definedMethods: MultipleDefinedMethods => diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalPhantomMethod.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalPhantomMethod.scala index 66beba5e3..c320d1b98 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalPhantomMethod.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalPhantomMethod.scala @@ -2,29 +2,29 @@ package boomerang.scope.opal.tac import boomerang.scope.opal.OpalFrameworkScope import boomerang.scope.{ControlFlowGraph, Method, Statement, Type, Val, WrappedClass} -import org.opalj.br.{MethodSignature, VirtualDeclaredMethod} +import org.opalj.br.{MethodDescriptor, MethodSignature, ObjectType, VirtualDeclaredMethod} import java.util -case class OpalPhantomMethod(delegate: VirtualDeclaredMethod, static: Boolean) extends Method { +case class OpalPhantomMethod(declaringClassType: ObjectType, name: String, descriptor: MethodDescriptor, static: Boolean) extends Method { - override def isStaticInitializer: Boolean = delegate.name == OpalFrameworkScope.STATIC_INITIALIZER + override def isStaticInitializer: Boolean = name == OpalFrameworkScope.STATIC_INITIALIZER override def isParameterLocal(value: Val): Boolean = false override def getParameterTypes: util.List[Type] = { val result = new util.ArrayList[Type]() - delegate.descriptor.parameterTypes.foreach(paramType => { + descriptor.parameterTypes.foreach(paramType => { result.add(OpalType(paramType)) }) result } - override def getParameterType(index: Int): Type = OpalType(delegate.descriptor.parameterType(index)) + override def getParameterType(index: Int): Type = OpalType(descriptor.parameterType(index)) - override def getReturnType: Type = OpalType(delegate.descriptor.returnType) + override def getReturnType: Type = OpalType(descriptor.returnType) override def isThisLocal(value: Val): Boolean = false @@ -43,15 +43,15 @@ case class OpalPhantomMethod(delegate: VirtualDeclaredMethod, static: Boolean) e override def getStatements: util.List[Statement] = throw new RuntimeException("Statements of phantom method are not available") // TODO - override def getDeclaringClass: WrappedClass = OpalPhantomWrappedClass(delegate.declaringClassType) + override def getDeclaringClass: WrappedClass = OpalPhantomWrappedClass(declaringClassType) override def getControlFlowGraph: ControlFlowGraph = throw new RuntimeException("CFG of phantom method is not available") - override def getSubSignature: String = MethodSignature(delegate.name, delegate.descriptor).toJava + override def getSubSignature: String = MethodSignature(name, descriptor).toJava - override def getName: String = delegate.name + override def getName: String = name - override def isConstructor: Boolean = delegate.name == OpalFrameworkScope.CONSTRUCTOR + override def isConstructor: Boolean = name == OpalFrameworkScope.CONSTRUCTOR - override def toString: String = "PHANTOM: " + delegate.toJava + override def toString: String = s"PHANTOM: ${descriptor.toJava}" } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacBodyBuilder.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacBodyBuilder.scala index bb9dae513..6675fdd7e 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacBodyBuilder.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacBodyBuilder.scala @@ -11,6 +11,10 @@ import org.opalj.tac.{Stmt, TACNaive, TACStmts} object TacBodyBuilder { def apply(project: Project[_], method: Method): BoomerangTACode = { + if (method.body.isEmpty) { + throw new IllegalArgumentException("Cannot compute TAC for method without existing body: " + method) + } + val tacNaive = TACNaive(method, project.classHierarchy) val stackHandler = OperandStackBuilder(method, tacNaive) diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackBuilder.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackBuilder.scala index 8ae86d81b..ed7dca59c 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackBuilder.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackBuilder.scala @@ -81,7 +81,8 @@ object OperandStackBuilder { schedule(pcOfNextStatement(pc), stack) case ReturnValue(_, expr: IdBasedVar) => - stack.pop(expr) + // TODO Bug in Opal: Return instructions return always s0 and not the top operand + // stack.pop(expr) // No scheduling since there is no next statement case Return(_) => // No scheduling since there is no next statement case Nop(pc) => diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackHandler.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackHandler.scala index 0e36ed337..c08d0fcdc 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackHandler.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackHandler.scala @@ -42,6 +42,8 @@ class OperandStackHandler { existingOp.updateCounter(existingOp.localId) incomingOp.updateCounter(existingOp.localId) + // TODO Merge types + modified = true } }) @@ -58,10 +60,13 @@ class OperandStackHandler { def defSiteAtPc(pc: PC): Int = defSites.getOrElse(pc, throw new RuntimeException(s"No operand definition at PC $pc")).localId - def counterForOperand(pc: PC, id: Int): Int = { + def counterForOperand(pc: PC, id: Int, isReturn: Boolean = false): Int = { val stack = pcToStack.getOrElse(pc, throw new RuntimeException(s"Stack for PC $pc not available")) stack.stackEntries.foreach(op => if (op.id == id) return op.localId) + // TODO Bug in Opal: Return always has id 0, even if it may have another id + if (isReturn) return stack.stackEntries.head.localId + throw new RuntimeException(s"Could not find operand with id $id on stack") } @@ -69,11 +74,6 @@ class OperandStackHandler { val defSite = defSites.getOrElse(pc, throw new RuntimeException(s"No def site found at pc $pc")) defSite.isBranchedOperand - //val stack = pcToStack.getOrElse(pc, throw new RuntimeException(s"Stack for PC $pc not available")) - //stack.stackEntries.foreach(op => if (op.id == id) return op.isBranchedOperand) - - - //throw new RuntimeException(s"Could not find operand with id $id on stack") } } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/LocalTransformer.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/LocalTransformer.scala index 1346f39b0..186c9c556 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/LocalTransformer.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/LocalTransformer.scala @@ -175,7 +175,8 @@ object LocalTransformer { } if (v.id >= 0) { - val counter = stackHandler.counterForOperand(pc, v.id) + val stmt = tac.stmts(tac.pcToIndex(pc)) + val counter = stackHandler.counterForOperand(pc, v.id, stmt.isReturnValue) return currentLocals(counter) } diff --git a/testCore/src/main/java/test/setup/OpalTestSetup.java b/testCore/src/main/java/test/setup/OpalTestSetup.java index 5367b1bb9..2172b73c0 100644 --- a/testCore/src/main/java/test/setup/OpalTestSetup.java +++ b/testCore/src/main/java/test/setup/OpalTestSetup.java @@ -20,12 +20,24 @@ import com.typesafe.config.Config; import com.typesafe.config.ConfigValueFactory; import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.URI; import java.net.URL; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; +import java.util.stream.Stream; import org.opalj.br.BooleanType$; import org.opalj.br.ByteType$; import org.opalj.br.CharType$; @@ -67,7 +79,14 @@ public void initialize( List excludedPackages) { OPALLogger.updateLogger(GlobalLogContext$.MODULE$, DevNullLogger$.MODULE$); - project = Project.apply(new File(classPath)); + File[] classpathFiles = loadClassPathFiles(classPath, excludedPackages); + File[] includeFiles = loadJDKFiles(includedPackages); + File[] classFiles = + Stream.concat(Arrays.stream(classpathFiles), Arrays.stream(includeFiles)) + .toArray(File[]::new); + project = Project.apply(classFiles, new File[0]); // , package$.MODULE$.RTJar()); + scala.collection.Iterable files = + project.allClassFiles(); // .filter(c -> c.thisType().fqn().contains("java.util")); // Load the class that contains the test method Option testClass = @@ -136,7 +155,6 @@ public Method getTestMethod() { @Override public FrameworkScope createFrameworkScope(DataFlowScope dataFlowScope) { - // TODO Shrink to application and included classes only CallGraph callGraph = project.get(CHACallGraphKey$.MODULE$); return new OpalFrameworkScope( @@ -146,6 +164,55 @@ public FrameworkScope createFrameworkScope(DataFlowScope dataFlowScope) { dataFlowScope); } + private File[] loadClassPathFiles(String classpath, List excludeList) { + Path path = Path.of(classpath); + + try (Stream stream = Files.walk(path)) { + Stream classPathFiles = stream.filter(Files::isRegularFile).map(Path::toFile); + + // Filter for excluded classes + return classPathFiles + .filter(c -> !isExcludedFile(c, classpath, excludeList)) + .toArray(File[]::new); + } catch (IOException e) { + throw new RuntimeException("Could not read classpath: " + e.getMessage()); + } + } + + private boolean isExcludedFile(File file, String classpath, List excludeList) { + // Remove the classpath and the .class ending + String path = file.getPath().replace("/", ".").replace("\\", "."); + String formattedClassPath = classpath.replace("/", ".").replace("\\", "."); + String formattedPath = path.replace(formattedClassPath, "").replace(".class", "").substring(1); + + return excludeList.contains(formattedPath); + } + + private File[] loadJDKFiles(List includeList) { + Collection result = new ArrayList<>(); + + try (FileSystem fs = + FileSystems.newFileSystem(URI.create("jrt:/"), java.util.Collections.emptyMap())) { + for (String className : includeList) { + String pathInJrt = "/modules/java.base/" + className.replace('.', '/') + ".class"; + Path jrtPath = fs.getPath(pathInJrt); + + // Copy to a temp file + Path tempFile = Files.createTempFile(className.replace('.', '_'), ".class"); + try (InputStream in = Files.newInputStream(jrtPath); + OutputStream out = Files.newOutputStream(tempFile)) { + in.transferTo(out); + } + + result.add(tempFile.toFile()); + } + } catch (IOException e) { + throw new RuntimeException("Could not read classes from JDK: " + e.getMessage()); + } + + return result.toArray(new File[0]); + } + private String convertType(String type) { if (type.equals("void")) return VoidType$.MODULE$.toJVMTypeName(); if (type.equals("byte")) return ByteType$.MODULE$.toJVMTypeName(); @@ -156,7 +223,7 @@ private String convertType(String type) { if (type.equals("long")) return LongType$.MODULE$.toJVMTypeName(); if (type.equals("short")) return ShortType$.MODULE$.toJVMTypeName(); if (type.equals("boolean")) return BooleanType$.MODULE$.toJVMTypeName(); - // TODO Consider all array types (not just ref types + // TODO Consider all array types (not just ref types) if (type.endsWith("[]")) { return new StringBuilder(type.replace(".", "/").replace("[]", "")) .insert(0, "[L") From 11429ab81bf7d23f0c8df2c4e18098bfdd800b2b Mon Sep 17 00:00:00 2001 From: Sven Meyer Date: Fri, 18 Apr 2025 10:07:29 +0200 Subject: [PATCH 45/61] Generalize handling of Maps --- .../java/boomerang/WeightedBoomerang.java | 72 ++++++++++--------- .../ContextSpecificListTypeTarget.java | 2 +- .../test/cases/lists/LinkedListsLongTest.java | 7 ++ 3 files changed, 48 insertions(+), 33 deletions(-) diff --git a/boomerangPDS/src/main/java/boomerang/WeightedBoomerang.java b/boomerangPDS/src/main/java/boomerang/WeightedBoomerang.java index 7c9ac4362..b208c901e 100644 --- a/boomerangPDS/src/main/java/boomerang/WeightedBoomerang.java +++ b/boomerangPDS/src/main/java/boomerang/WeightedBoomerang.java @@ -49,6 +49,7 @@ import boomerang.stats.IBoomerangStats; import boomerang.stats.SimpleBoomerangStats; import boomerang.util.DefaultValueMap; +import boomerang.utils.MethodWrapper; import com.google.common.base.Stopwatch; import com.google.common.collect.HashBasedTable; import com.google.common.collect.HashMultimap; @@ -59,6 +60,7 @@ import java.util.Collection; import java.util.HashMap; import java.util.LinkedHashSet; +import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Optional; @@ -231,22 +233,28 @@ protected boolean isFirstStatementOfEntryPoint(Statement stmt) { && stmt.getMethod().getControlFlowGraph().getStartPoints().contains(stmt); } - private static final String MAP_PUT_SUB_SIGNATURE = "java.util.Map: java.lang.Object put("; - private static final String MAP_GET_SUB_SIGNATURE = "java.util.Map: java.lang.Object get("; + private static final MethodWrapper MAP_PUT_SIGNATURE = + new MethodWrapper( + "java.util.Map", + "put", + "java.lang.Object", + List.of("java.lang.Object", "java.lang.Object")); + private static final MethodWrapper MAP_GET_SIGNATURE = + new MethodWrapper("java.util.Map", "get", "java.lang.Object", List.of("java.lang.Object")); protected void handleMapsBackward(Node node) { - Statement rstmt = node.stmt().getStart(); - if (rstmt.isAssignStmt() - && rstmt.containsInvokeExpr() - && rstmt.getInvokeExpr().toString().contains(MAP_GET_SUB_SIGNATURE)) { - if (rstmt.getLeftOp().equals(node.fact())) { + Statement stmt = node.stmt().getStart(); + if (stmt.isAssignStmt() + && stmt.containsInvokeExpr() + && stmt.getInvokeExpr().getDeclaredMethod().toMethodWrapper().equals(MAP_GET_SIGNATURE)) { + if (stmt.getLeftOp().equals(node.fact())) { cfg.addPredsOfListener( - new PredecessorListener(rstmt) { + new PredecessorListener(stmt) { @Override public void getPredecessor(Statement pred) { BackwardQuery bwq = - BackwardQuery.make(new Edge(pred, rstmt), rstmt.getInvokeExpr().getArg(0)); + BackwardQuery.make(new Edge(pred, stmt), stmt.getInvokeExpr().getArg(0)); backwardSolve(bwq); for (ForwardQuery q : Lists.newArrayList(queryToSolvers.keySet())) { if (queryToSolvers.get(q).getReachedStates().contains(bwq.asNode())) { @@ -256,8 +264,8 @@ public void getPredecessor(Statement pred) { backwardSolverIns.propagate( node, new PushNode<>( - new Edge(pred, rstmt), - rstmt.getInvokeExpr().getBase(), + new Edge(pred, stmt), + stmt.getInvokeExpr().getBase(), Field.string(key), PDSSystem.FIELDS)); } @@ -267,15 +275,15 @@ public void getPredecessor(Statement pred) { }); } } - if (rstmt.containsInvokeExpr() - && rstmt.getInvokeExpr().toString().contains(MAP_PUT_SUB_SIGNATURE)) { - if (rstmt.getInvokeExpr().getBase().equals(node.fact())) { + if (stmt.containsInvokeExpr() + && stmt.getInvokeExpr().getDeclaredMethod().toMethodWrapper().equals(MAP_PUT_SIGNATURE)) { + if (stmt.getInvokeExpr().getBase().equals(node.fact())) { cfg.addPredsOfListener( - new PredecessorListener(rstmt) { + new PredecessorListener(stmt) { @Override public void getPredecessor(Statement pred) { BackwardQuery bwq = - BackwardQuery.make(new Edge(pred, rstmt), rstmt.getInvokeExpr().getArg(0)); + BackwardQuery.make(new Edge(pred, stmt), stmt.getInvokeExpr().getArg(0)); backwardSolve(bwq); for (ForwardQuery q : Lists.newArrayList(queryToSolvers.keySet())) { if (queryToSolvers.get(q).getReachedStates().contains(bwq.asNode())) { @@ -285,8 +293,8 @@ public void getPredecessor(Statement pred) { String key = v.getAllocVal().getStringValue(); NodeWithLocation succNode = new NodeWithLocation<>( - new Edge(pred, rstmt), - rstmt.getInvokeExpr().getArg(1), + new Edge(pred, stmt), + stmt.getInvokeExpr().getArg(1), Field.string(key)); backwardSolverIns.propagate(node, new PopNode<>(succNode, PDSSystem.FIELDS)); } @@ -299,15 +307,15 @@ public void getPredecessor(Statement pred) { } protected void handleMapsForward(ForwardBoomerangSolver solver, Node node) { - Statement rstmt = node.stmt().getTarget(); - if (rstmt.containsInvokeExpr()) { - if (rstmt.isAssignStmt() - && rstmt.getInvokeExpr().toString().contains(MAP_GET_SUB_SIGNATURE)) { - if (rstmt.getInvokeExpr().getBase().equals(node.fact())) { - BackwardQuery bwq = BackwardQuery.make(node.stmt(), rstmt.getInvokeExpr().getArg(0)); + Statement stmt = node.stmt().getTarget(); + if (stmt.containsInvokeExpr()) { + if (stmt.isAssignStmt() + && stmt.getInvokeExpr().getDeclaredMethod().toMethodWrapper().equals(MAP_GET_SIGNATURE)) { + if (stmt.getInvokeExpr().getBase().equals(node.fact())) { + BackwardQuery bwq = BackwardQuery.make(node.stmt(), stmt.getInvokeExpr().getArg(0)); backwardSolve(bwq); cfg.addSuccsOfListener( - new SuccessorListener(rstmt) { + new SuccessorListener(stmt) { @Override public void getSuccessor(Statement succ) { for (ForwardQuery q : Lists.newArrayList(queryToSolvers.keySet())) { @@ -318,7 +326,7 @@ public void getSuccessor(Statement succ) { String key = v.getAllocVal().getStringValue(); NodeWithLocation succNode = new NodeWithLocation<>( - new Edge(rstmt, succ), rstmt.getLeftOp(), Field.string(key)); + new Edge(stmt, succ), stmt.getLeftOp(), Field.string(key)); solver.propagate(node, new PopNode<>(succNode, PDSSystem.FIELDS)); } } @@ -327,13 +335,13 @@ public void getSuccessor(Statement succ) { }); } } - if (rstmt.getInvokeExpr().toString().contains(MAP_PUT_SUB_SIGNATURE)) { - if (rstmt.getInvokeExpr().getArg(1).equals(node.fact())) { + if (stmt.getInvokeExpr().getDeclaredMethod().toMethodWrapper().equals(MAP_PUT_SIGNATURE)) { + if (stmt.getInvokeExpr().getArg(1).equals(node.fact())) { - BackwardQuery bwq = BackwardQuery.make(node.stmt(), rstmt.getInvokeExpr().getArg(0)); + BackwardQuery bwq = BackwardQuery.make(node.stmt(), stmt.getInvokeExpr().getArg(0)); backwardSolve(bwq); cfg.addSuccsOfListener( - new SuccessorListener(rstmt) { + new SuccessorListener(stmt) { @Override public void getSuccessor(Statement succ) { for (ForwardQuery q : Lists.newArrayList(queryToSolvers.keySet())) { @@ -344,8 +352,8 @@ public void getSuccessor(Statement succ) { solver.propagate( node, new PushNode<>( - new Edge(rstmt, succ), - rstmt.getInvokeExpr().getBase(), + new Edge(stmt, succ), + stmt.getInvokeExpr().getBase(), Field.string(key), PDSSystem.FIELDS)); } diff --git a/boomerangPDS/src/test/java/test/cases/callgraph/ContextSpecificListTypeTarget.java b/boomerangPDS/src/test/java/test/cases/callgraph/ContextSpecificListTypeTarget.java index c457fe6fb..3a1ae5fad 100644 --- a/boomerangPDS/src/test/java/test/cases/callgraph/ContextSpecificListTypeTarget.java +++ b/boomerangPDS/src/test/java/test/cases/callgraph/ContextSpecificListTypeTarget.java @@ -40,7 +40,7 @@ public void testListType() { QueryMethods.queryFor(query); } - private static class WrongList extends LinkedList { + public static class WrongList extends LinkedList { @Override public boolean add(Object e) { unreachable(); diff --git a/boomerangPDS/src/test/java/test/cases/lists/LinkedListsLongTest.java b/boomerangPDS/src/test/java/test/cases/lists/LinkedListsLongTest.java index 37cd8e24d..fc4341708 100644 --- a/boomerangPDS/src/test/java/test/cases/lists/LinkedListsLongTest.java +++ b/boomerangPDS/src/test/java/test/cases/lists/LinkedListsLongTest.java @@ -13,6 +13,7 @@ import java.util.List; import org.junit.Test; +import test.cases.callgraph.ContextSpecificListTypeTarget; import test.core.AbstractBoomerangTest; public class LinkedListsLongTest extends AbstractBoomerangTest { @@ -31,6 +32,12 @@ protected List getIncludedPackages() { "java.util.Iterator"); } + @Override + protected List getExcludedPackages() { + // This is required because CHA adds an edge to the WrongList class, too + return List.of(ContextSpecificListTypeTarget.WrongList.class.getName()); + } + @Test public void addAndRetrieveWithIterator() { analyze(target, testName.getMethodName()); From c490823692547dafe633d7e93576cc3652c4d7fb Mon Sep 17 00:00:00 2001 From: Sven Meyer Date: Sat, 19 Apr 2025 11:08:32 +0200 Subject: [PATCH 46/61] Create alloc classes for each package --- .../java/test/cases/array/ArrayAlloc.java | 16 +++++ .../cases/array/ArrayContainerTarget.java | 7 +- .../test/java/test/cases/array/ArrayTest.java | 2 +- .../{Allocation.java => BasicAlloc.java} | 2 +- .../test/cases/basic/FieldlessTarget.java | 12 ++-- .../java/test/cases/basic/FieldlessTest.java | 2 +- .../cases/basic/InterproceduralTarget.java | 65 +++++++++---------- .../UnbalancedInterproceduralTarget.java | 15 ++--- .../test/cases/callgraph/CallGraphAlloc.java | 16 +++++ .../ContextSensitivityFieldTarget.java | 4 +- .../ContextSensitivityMyListTarget.java | 3 +- .../callgraph/ContextSensitivityTarget.java | 3 +- .../ContextSpecificListTypeTarget.java | 3 +- .../java/test/cases/context/ContextAlloc.java | 16 +++++ .../cases/context/ContextTypesTarget.java | 35 +++++----- .../context/PathingContextProblemTarget.java | 9 ++- .../context/SimpleContextQueryTarget.java | 3 +- .../test/cases/exceptions/ExceptionAlloc.java | 16 +++++ .../cases/exceptions/ExceptionTarget.java | 17 +++-- .../test/cases/fields/BasicFieldTarget.java | 18 ++--- .../java/test/cases/fields/CallPOITarget.java | 12 ++-- .../test/cases/fields/CastAndSetTarget.java | 2 +- .../cases/fields/FailOnVisitMethodTest.java | 4 +- .../fields/{Alloc.java => FieldAlloc.java} | 2 +- .../cases/fields/HiddenFieldLoadTarget.java | 14 ++-- .../cases/fields/NoIndirectionTarget.java | 12 ++-- .../test/cases/fields/NoIndirectionTest.java | 8 +-- .../fields/NullAllocationConstructorTest.java | 2 +- .../cases/fields/ObjectSensitivityTarget.java | 6 +- .../java/test/cases/fields/ReadPOITest.java | 2 +- .../cases/fields/ReuseOfSummaryTarget.java | 2 +- .../test/cases/fields/TypeChangeTarget.java | 4 +- .../java/test/cases/fields/WritePOITest.java | 4 +- .../complexity/Recursion2LongTarget.java | 10 +-- .../fields/complexity/Recursion2LongTest.java | 2 +- .../test/cases/hashmap/AllAliasLongTest.java | 2 +- .../cases/hashmap/KeySensitiveTarget.java | 13 ++-- .../java/test/cases/hashmap/MapAlloc.java | 16 +++++ .../lists/ArrayAndLinkedListsTarget.java | 3 +- .../cases/lists/ArrayListsLongTarget.java | 5 +- .../cases/lists/LinkedListsLongTarget.java | 3 +- .../test/cases/lists/LinkedListsLongTest.java | 10 +-- .../cases/lists/LinkedListsTypeLongTest.java | 3 +- .../test/java/test/cases/lists/ListAlloc.java | 16 +++++ .../ScalabilityOfBackwardAnalysisTest.java | 2 +- .../cases/reflection/ReflectionAlloc.java | 16 +++++ .../cases/reflection/ReflectionTarget.java | 7 +- .../test/cases/reflection/ReflectionTest.java | 2 +- .../java/test/cases/sets/CustomMapTarget.java | 10 +-- .../java/test/cases/sets/CustomSetTarget.java | 3 +- .../test/cases/sets/HashMapGetLongTarget.java | 5 +- .../test/cases/sets/HashMapsLongTarget.java | 3 +- .../test/java/test/cases/sets/SetAlloc.java | 16 +++++ .../test/cases/sets/TreeMapLongTarget.java | 3 +- .../sets/TreeMapMultipleInstancesTarget.java | 5 +- .../test/cases/sets/TreeSetsLongTarget.java | 5 +- .../test/cases/sets/TreeSetsLongTest.java | 38 +++++++---- .../cases/statics/SimpleSingletonTarget.java | 11 ++-- .../test/cases/statics/SingletonTarget.java | 23 ++++--- .../cases/statics/StaticFieldFlowsTarget.java | 31 +++++---- .../statics/StaticInitializerTarget.java | 3 +- .../statics/StaticWithSuperClassesTarget.java | 5 +- .../java/test/cases/statics/StaticsAlloc.java | 16 +++++ .../java/test/cases/string/StringTest.java | 8 +-- .../cases/subclassing/InnerClassTarget.java | 3 +- .../cases/subclassing/SubclassingAlloc.java | 16 +++++ .../test/cases/synchronizd/BlockTarget.java | 5 +- .../cases/synchronizd/SynchronizedAlloc.java | 16 +++++ .../threading/InnerClassWithThreadTarget.java | 7 +- .../test/cases/threading/ThreadingAlloc.java | 16 +++++ .../cases/unbalanced/UnbalancedAlloc.java | 16 +++++ .../unbalanced/UnbalancedScopesTarget.java | 7 +- .../java/test/core/AbstractBoomerangTest.java | 23 +++++-- .../main/java/test/setup/OpalTestSetup.java | 19 +++--- 74 files changed, 483 insertions(+), 278 deletions(-) create mode 100644 boomerangPDS/src/test/java/test/cases/array/ArrayAlloc.java rename boomerangPDS/src/test/java/test/cases/basic/{Allocation.java => BasicAlloc.java} (91%) create mode 100644 boomerangPDS/src/test/java/test/cases/callgraph/CallGraphAlloc.java create mode 100644 boomerangPDS/src/test/java/test/cases/context/ContextAlloc.java create mode 100644 boomerangPDS/src/test/java/test/cases/exceptions/ExceptionAlloc.java rename boomerangPDS/src/test/java/test/cases/fields/{Alloc.java => FieldAlloc.java} (91%) create mode 100644 boomerangPDS/src/test/java/test/cases/hashmap/MapAlloc.java create mode 100644 boomerangPDS/src/test/java/test/cases/lists/ListAlloc.java create mode 100644 boomerangPDS/src/test/java/test/cases/reflection/ReflectionAlloc.java create mode 100644 boomerangPDS/src/test/java/test/cases/sets/SetAlloc.java create mode 100644 boomerangPDS/src/test/java/test/cases/statics/StaticsAlloc.java create mode 100644 boomerangPDS/src/test/java/test/cases/subclassing/SubclassingAlloc.java create mode 100644 boomerangPDS/src/test/java/test/cases/synchronizd/SynchronizedAlloc.java create mode 100644 boomerangPDS/src/test/java/test/cases/threading/ThreadingAlloc.java create mode 100644 boomerangPDS/src/test/java/test/cases/unbalanced/UnbalancedAlloc.java diff --git a/boomerangPDS/src/test/java/test/cases/array/ArrayAlloc.java b/boomerangPDS/src/test/java/test/cases/array/ArrayAlloc.java new file mode 100644 index 000000000..465c6e203 --- /dev/null +++ b/boomerangPDS/src/test/java/test/cases/array/ArrayAlloc.java @@ -0,0 +1,16 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ +package test.cases.array; + +import test.core.selfrunning.AllocatedObject; + +public class ArrayAlloc implements AllocatedObject {} diff --git a/boomerangPDS/src/test/java/test/cases/array/ArrayContainerTarget.java b/boomerangPDS/src/test/java/test/cases/array/ArrayContainerTarget.java index bae893ef9..36a9dffb2 100644 --- a/boomerangPDS/src/test/java/test/cases/array/ArrayContainerTarget.java +++ b/boomerangPDS/src/test/java/test/cases/array/ArrayContainerTarget.java @@ -12,7 +12,6 @@ package test.cases.array; import test.TestMethod; -import test.cases.fields.Alloc; import test.core.QueryMethods; import test.core.selfrunning.AllocatedObject; import test.core.selfrunning.NoAllocatedObject; @@ -39,7 +38,7 @@ public void insertAndGet() { ArrayContainer container = new ArrayContainer(); Object o1 = new Object(); container.put(o1); - AllocatedObject o2 = new Alloc(); + AllocatedObject o2 = new ArrayAlloc(); container.put(o2); AllocatedObject alias = container.get(); QueryMethods.queryFor(alias); @@ -48,7 +47,7 @@ public void insertAndGet() { @TestMethod public void insertAndGetField() { ArrayContainerWithPublicFields container = new ArrayContainerWithPublicFields(); - AllocatedObject o2 = new Alloc(); + AllocatedObject o2 = new ArrayAlloc(); container.array[0] = o2; AllocatedObject alias = container.array[0]; QueryMethods.queryFor(alias); @@ -64,7 +63,7 @@ public void insertAndGetDouble() { ArrayContainer innerContainer1 = new ArrayContainer(); Object o1 = new NoAllocation(); innerContainer1.put(o1); - AllocatedObject o2 = new Alloc(); + AllocatedObject o2 = new ArrayAlloc(); innerContainer1.put(o2); outerContainer.put(innerContainer1); ArrayContainer innerContainer2 = outerContainer.get(); diff --git a/boomerangPDS/src/test/java/test/cases/array/ArrayTest.java b/boomerangPDS/src/test/java/test/cases/array/ArrayTest.java index e34be9a48..e50a6a809 100644 --- a/boomerangPDS/src/test/java/test/cases/array/ArrayTest.java +++ b/boomerangPDS/src/test/java/test/cases/array/ArrayTest.java @@ -57,6 +57,6 @@ public void arrayWithTwoObjectAndFieldTest() { @Test public void toCharArrayTest() { - analyze(target, testName.getMethodName()); + analyze(target, testName.getMethodName(), true); } } diff --git a/boomerangPDS/src/test/java/test/cases/basic/Allocation.java b/boomerangPDS/src/test/java/test/cases/basic/BasicAlloc.java similarity index 91% rename from boomerangPDS/src/test/java/test/cases/basic/Allocation.java rename to boomerangPDS/src/test/java/test/cases/basic/BasicAlloc.java index 3e0c12a03..bd50b1a25 100644 --- a/boomerangPDS/src/test/java/test/cases/basic/Allocation.java +++ b/boomerangPDS/src/test/java/test/cases/basic/BasicAlloc.java @@ -13,4 +13,4 @@ import test.core.selfrunning.AllocatedObject; -public class Allocation implements AllocatedObject {} +public class BasicAlloc implements AllocatedObject {} diff --git a/boomerangPDS/src/test/java/test/cases/basic/FieldlessTarget.java b/boomerangPDS/src/test/java/test/cases/basic/FieldlessTarget.java index a9a082d23..388088b1c 100644 --- a/boomerangPDS/src/test/java/test/cases/basic/FieldlessTarget.java +++ b/boomerangPDS/src/test/java/test/cases/basic/FieldlessTarget.java @@ -20,7 +20,7 @@ public class FieldlessTarget { @TestMethod public void simpleAssignment1() { - Object alloc1 = new Allocation(); + Object alloc1 = new BasicAlloc(); Object alias1 = alloc1; Object query = alias1; QueryMethods.queryFor(query); @@ -40,7 +40,7 @@ public void branchWithOverwrite() { Object alias2 = new AllocatedObject() {}; if (Math.random() > 0.5) { Object alias1 = alias2; - alias2 = new Allocation(); + alias2 = new BasicAlloc(); } QueryMethods.queryFor(alias2); @@ -48,8 +48,8 @@ public void branchWithOverwrite() { @TestMethod public void branchWithOverwriteSwapped() { - Object alias2 = new Allocation(); - Object alias1 = new Allocation(); + Object alias2 = new BasicAlloc(); + Object alias1 = new BasicAlloc(); if (Math.random() > 0.5) { alias2 = alias1; } @@ -70,12 +70,12 @@ private Object returnNull() { @TestMethod public void cast() { - Allocation alias1 = new Subclass(); + BasicAlloc alias1 = new Subclass(); Subclass alias2 = (Subclass) alias1; QueryMethods.queryFor(alias2); } - public static class Subclass extends Allocation {} + public static class Subclass extends BasicAlloc {} public AllocatedObject create() { AllocatedObject alloc1 = new AllocatedObject() {}; diff --git a/boomerangPDS/src/test/java/test/cases/basic/FieldlessTest.java b/boomerangPDS/src/test/java/test/cases/basic/FieldlessTest.java index 418c74597..27128aba8 100644 --- a/boomerangPDS/src/test/java/test/cases/basic/FieldlessTest.java +++ b/boomerangPDS/src/test/java/test/cases/basic/FieldlessTest.java @@ -40,7 +40,7 @@ public void branchWithOverwriteSwapped() { @Test public void returnNullAllocation() { - analyze(target, testName.getMethodName()); + analyze(target, testName.getMethodName(), true); } @Test diff --git a/boomerangPDS/src/test/java/test/cases/basic/InterproceduralTarget.java b/boomerangPDS/src/test/java/test/cases/basic/InterproceduralTarget.java index ca1f2ead7..d382b443a 100644 --- a/boomerangPDS/src/test/java/test/cases/basic/InterproceduralTarget.java +++ b/boomerangPDS/src/test/java/test/cases/basic/InterproceduralTarget.java @@ -12,7 +12,6 @@ package test.cases.basic; import test.TestMethod; -import test.cases.fields.Alloc; import test.core.QueryMethods; import test.core.selfrunning.AllocatedObject; @@ -34,13 +33,13 @@ public void simpleAnonymous() { @TestMethod public void simpleNonAnonymous() { - AllocatedObject alias1 = new Alloc(); + AllocatedObject alias1 = new BasicAlloc(); QueryMethods.queryFor(alias1); } @TestMethod public void identityTest1() { - Alloc alias1 = new Alloc(); + BasicAlloc alias1 = new BasicAlloc(); Object alias2 = alias1; identity(alias1); otherCall(alias2); @@ -60,7 +59,7 @@ public void summaryReuseTest1() { @TestMethod public void failedCast() { - Object o = new Object(); + Object o = new BasicAlloc(); Object returned = flow(o); String t = (String) returned; QueryMethods.queryFor(t); @@ -72,12 +71,12 @@ private Object flow(Object o) { @TestMethod public void summaryReuseTest4() { - Alloc alias2; + BasicAlloc alias2; if (Math.random() > 0.5) { - Alloc alias1 = new Alloc(); + BasicAlloc alias1 = new BasicAlloc(); alias2 = nestedIdentity(alias1); } else { - Alloc alias1 = new Alloc(); + BasicAlloc alias1 = new BasicAlloc(); alias2 = nestedIdentity(alias1); } QueryMethods.queryFor(alias2); @@ -85,8 +84,8 @@ public void summaryReuseTest4() { @TestMethod public void branchWithCall() { - Alloc a1 = new Alloc(); - Alloc a2 = new Alloc(); + BasicAlloc a1 = new BasicAlloc(); + BasicAlloc a2 = new BasicAlloc(); Object a = null; if (Math.random() > 0.5) { a = a1; @@ -99,9 +98,9 @@ public void branchWithCall() { private void wrappedFoo(Object param) {} - private Alloc nestedIdentity(Alloc param2) { + private BasicAlloc nestedIdentity(BasicAlloc param2) { int shouldNotSeeThis = 1; - Alloc returnVal = param2; + BasicAlloc returnVal = param2; return returnVal; } @@ -125,7 +124,7 @@ public void summaryReuseTest3() { @TestMethod public void interLoop() { - AllocatedObject alias = new Alloc() {}; + AllocatedObject alias = new BasicAlloc() {}; AllocatedObject aliased2; Object aliased = new AllocatedObject() {}, notAlias = new Object(); for (int i = 0; i < 20; i++) { @@ -168,7 +167,7 @@ public void unbalancedCreationStatic() { } private Object createStatic() { - return new Allocation(); + return new BasicAlloc(); } public AllocatedObject wrappedCreate() { @@ -187,75 +186,75 @@ private AllocatedObject identity(AllocatedObject param) { @TestMethod public void heavySummary() { - Allocation alias1 = new Allocation(); + BasicAlloc alias1 = new BasicAlloc(); Object q; if (Math.random() > 0.5) { q = doSummarize(alias1); } else if (Math.random() > 0.5) { - Allocation alias2 = new Allocation(); + BasicAlloc alias2 = new BasicAlloc(); q = doSummarize(alias2); } else { - Allocation alias3 = new Allocation(); + BasicAlloc alias3 = new BasicAlloc(); q = doSummarize(alias3); } QueryMethods.queryFor(q); } - private Allocation doSummarize(Allocation alias1) { - Allocation a = alias1; - Allocation b = a; - Allocation c = b; - Allocation d = c; + private BasicAlloc doSummarize(BasicAlloc alias1) { + BasicAlloc a = alias1; + BasicAlloc b = a; + BasicAlloc c = b; + BasicAlloc d = c; - Allocation e = d; - Allocation f = evenFurtherNested(e); - Allocation g = alias1; + BasicAlloc e = d; + BasicAlloc f = evenFurtherNested(e); + BasicAlloc g = alias1; if (Math.random() > 0.5) { g = f; } - Allocation h = g; + BasicAlloc h = g; return f; } - private Allocation evenFurtherNested(Allocation e) { + private BasicAlloc evenFurtherNested(BasicAlloc e) { return e; } @TestMethod public void summaryTest() { - Allocation alias1 = new Allocation(); + BasicAlloc alias1 = new BasicAlloc(); Object q; if (Math.random() > 0.5) { q = summary(alias1); } else { - Allocation alias2 = new Allocation(); + BasicAlloc alias2 = new BasicAlloc(); q = summary(alias2); } QueryMethods.queryFor(q); } - private Object summary(Allocation inner) { - Allocation ret = inner; + private Object summary(BasicAlloc inner) { + BasicAlloc ret = inner; return ret; } @TestMethod public void doubleNestedSummary() { - Allocation alias1 = new Allocation(); + BasicAlloc alias1 = new BasicAlloc(); Object q; if (Math.random() > 0.5) { q = nestedSummary(alias1); } else { - Allocation alias2 = new Allocation(); + BasicAlloc alias2 = new BasicAlloc(); q = nestedSummary(alias2); } QueryMethods.queryFor(q); } - private Object nestedSummary(Allocation inner) { + private Object nestedSummary(BasicAlloc inner) { Object ret = summary(inner); return ret; } diff --git a/boomerangPDS/src/test/java/test/cases/basic/UnbalancedInterproceduralTarget.java b/boomerangPDS/src/test/java/test/cases/basic/UnbalancedInterproceduralTarget.java index e796dcc24..abd0f3419 100644 --- a/boomerangPDS/src/test/java/test/cases/basic/UnbalancedInterproceduralTarget.java +++ b/boomerangPDS/src/test/java/test/cases/basic/UnbalancedInterproceduralTarget.java @@ -12,7 +12,6 @@ package test.cases.basic; import test.TestMethod; -import test.cases.fields.Alloc; import test.core.QueryMethods; @SuppressWarnings("unused") @@ -20,23 +19,23 @@ public class UnbalancedInterproceduralTarget { @TestMethod public void unbalancedCreation() { - Alloc alias1 = create(); - Alloc query = alias1; + BasicAlloc alias1 = create(); + BasicAlloc query = alias1; QueryMethods.queryFor(query); } @TestMethod public void doubleUnbalancedCreation() { - Alloc alias1 = wrappedCreate(); - Alloc query = alias1; + BasicAlloc alias1 = wrappedCreate(); + BasicAlloc query = alias1; QueryMethods.queryFor(query); } - private Alloc wrappedCreate() { + private BasicAlloc wrappedCreate() { return create(); } - private Alloc create() { - return new Alloc(); + private BasicAlloc create() { + return new BasicAlloc(); } } diff --git a/boomerangPDS/src/test/java/test/cases/callgraph/CallGraphAlloc.java b/boomerangPDS/src/test/java/test/cases/callgraph/CallGraphAlloc.java new file mode 100644 index 000000000..3752e5e7b --- /dev/null +++ b/boomerangPDS/src/test/java/test/cases/callgraph/CallGraphAlloc.java @@ -0,0 +1,16 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ +package test.cases.callgraph; + +import test.core.selfrunning.AllocatedObject; + +public class CallGraphAlloc implements AllocatedObject {} diff --git a/boomerangPDS/src/test/java/test/cases/callgraph/ContextSensitivityFieldTarget.java b/boomerangPDS/src/test/java/test/cases/callgraph/ContextSensitivityFieldTarget.java index 281e8ec8e..bd8d0339c 100644 --- a/boomerangPDS/src/test/java/test/cases/callgraph/ContextSensitivityFieldTarget.java +++ b/boomerangPDS/src/test/java/test/cases/callgraph/ContextSensitivityFieldTarget.java @@ -12,9 +12,9 @@ package test.cases.callgraph; import test.TestMethod; -import test.cases.fields.Alloc; import test.core.QueryMethods; +@SuppressWarnings("unused") public class ContextSensitivityFieldTarget { public void wrongContext() { @@ -23,7 +23,7 @@ public void wrongContext() { } public Object method(SuperClass type) { - Alloc alloc = new Alloc(); + CallGraphAlloc alloc = new CallGraphAlloc(); type.foo(alloc); return type.getO(); } diff --git a/boomerangPDS/src/test/java/test/cases/callgraph/ContextSensitivityMyListTarget.java b/boomerangPDS/src/test/java/test/cases/callgraph/ContextSensitivityMyListTarget.java index 3551558f0..6048bb396 100644 --- a/boomerangPDS/src/test/java/test/cases/callgraph/ContextSensitivityMyListTarget.java +++ b/boomerangPDS/src/test/java/test/cases/callgraph/ContextSensitivityMyListTarget.java @@ -16,7 +16,6 @@ import java.util.List; import java.util.ListIterator; import test.TestMethod; -import test.cases.fields.Alloc; import test.core.QueryMethods; @SuppressWarnings("unused") @@ -28,7 +27,7 @@ public void wrongContext() { } public Object method(List type) { - Alloc alloc = new Alloc(); + CallGraphAlloc alloc = new CallGraphAlloc(); type.add(alloc); return alloc; } diff --git a/boomerangPDS/src/test/java/test/cases/callgraph/ContextSensitivityTarget.java b/boomerangPDS/src/test/java/test/cases/callgraph/ContextSensitivityTarget.java index 6918ea608..43fbe5780 100644 --- a/boomerangPDS/src/test/java/test/cases/callgraph/ContextSensitivityTarget.java +++ b/boomerangPDS/src/test/java/test/cases/callgraph/ContextSensitivityTarget.java @@ -12,7 +12,6 @@ package test.cases.callgraph; import test.TestMethod; -import test.cases.fields.Alloc; import test.core.QueryMethods; @SuppressWarnings("unused") @@ -24,7 +23,7 @@ public void wrongContext() { } public Object method(SuperClass type) { - Alloc alloc = new Alloc(); + CallGraphAlloc alloc = new CallGraphAlloc(); type.foo(alloc); return alloc; } diff --git a/boomerangPDS/src/test/java/test/cases/callgraph/ContextSpecificListTypeTarget.java b/boomerangPDS/src/test/java/test/cases/callgraph/ContextSpecificListTypeTarget.java index 3a1ae5fad..ce5937610 100644 --- a/boomerangPDS/src/test/java/test/cases/callgraph/ContextSpecificListTypeTarget.java +++ b/boomerangPDS/src/test/java/test/cases/callgraph/ContextSpecificListTypeTarget.java @@ -15,7 +15,6 @@ import java.util.LinkedList; import java.util.List; import test.TestMethod; -import test.cases.fields.Alloc; import test.core.QueryMethods; @SuppressWarnings("unused") @@ -27,7 +26,7 @@ public void wrongContext() { } public Object method(List list) { - Alloc alloc = new Alloc(); + CallGraphAlloc alloc = new CallGraphAlloc(); list.add(alloc); return alloc; } diff --git a/boomerangPDS/src/test/java/test/cases/context/ContextAlloc.java b/boomerangPDS/src/test/java/test/cases/context/ContextAlloc.java new file mode 100644 index 000000000..e3269dcfb --- /dev/null +++ b/boomerangPDS/src/test/java/test/cases/context/ContextAlloc.java @@ -0,0 +1,16 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ +package test.cases.context; + +import test.core.selfrunning.AllocatedObject; + +public class ContextAlloc implements AllocatedObject {} diff --git a/boomerangPDS/src/test/java/test/cases/context/ContextTypesTarget.java b/boomerangPDS/src/test/java/test/cases/context/ContextTypesTarget.java index 92c54066e..ebf203a07 100644 --- a/boomerangPDS/src/test/java/test/cases/context/ContextTypesTarget.java +++ b/boomerangPDS/src/test/java/test/cases/context/ContextTypesTarget.java @@ -12,7 +12,6 @@ package test.cases.context; import test.TestMethod; -import test.cases.fields.Alloc; import test.core.QueryMethods; @SuppressWarnings("unused") @@ -20,59 +19,59 @@ public class ContextTypesTarget { @TestMethod public void openContext() { - Alloc alloc = new Alloc(); + ContextAlloc alloc = new ContextAlloc(); call(alloc); } @TestMethod public void twoOpenContexts() { - Alloc alloc = new Alloc(); + ContextAlloc alloc = new ContextAlloc(); call(alloc); - Alloc a = new Alloc(); + ContextAlloc a = new ContextAlloc(); call(a); } @TestMethod public void twoOpenContextsSameObject() { - Alloc alloc = new Alloc(); + ContextAlloc alloc = new ContextAlloc(); call(alloc); call(alloc); } - private void call(Alloc p) { + private void call(ContextAlloc p) { QueryMethods.queryFor(p); } @TestMethod public void closingContext() { - Alloc alloc = close(); + ContextAlloc alloc = close(); QueryMethods.queryFor(alloc); } - private Alloc close() { - return new Alloc(); + private ContextAlloc close() { + return new ContextAlloc(); } @TestMethod public void noContext() { - Alloc alloc = new Alloc(); + ContextAlloc alloc = new ContextAlloc(); QueryMethods.queryFor(alloc); } @TestMethod public void twoClosingContexts() { - Alloc alloc = wrappedClose(); + ContextAlloc alloc = wrappedClose(); QueryMethods.queryFor(alloc); } - private Alloc wrappedClose() { + private ContextAlloc wrappedClose() { return close(); } @TestMethod public void openContextWithField() { A a = new A(); - Alloc alloc = new Alloc(); + ContextAlloc alloc = new ContextAlloc(); a.b = alloc; call(a); } @@ -89,25 +88,25 @@ public static class A { @TestMethod public void threeStackedOpenContexts() { - Alloc alloc = new Alloc(); + ContextAlloc alloc = new ContextAlloc(); wrappedWrappedCall(alloc); } - private void wrappedWrappedCall(Alloc alloc) { + private void wrappedWrappedCall(ContextAlloc alloc) { wrappedCall(alloc); } - private void wrappedCall(Alloc alloc) { + private void wrappedCall(ContextAlloc alloc) { call(alloc); } @TestMethod public void recursionOpenCallStack() { - Alloc start = new Alloc(); + ContextAlloc start = new ContextAlloc(); recursionStart(start); } - private void recursionStart(Alloc rec) { + private void recursionStart(ContextAlloc rec) { if (Math.random() > 0.5) recursionStart(rec); call(rec); } diff --git a/boomerangPDS/src/test/java/test/cases/context/PathingContextProblemTarget.java b/boomerangPDS/src/test/java/test/cases/context/PathingContextProblemTarget.java index 4fce473b3..2c4599f15 100644 --- a/boomerangPDS/src/test/java/test/cases/context/PathingContextProblemTarget.java +++ b/boomerangPDS/src/test/java/test/cases/context/PathingContextProblemTarget.java @@ -12,7 +12,6 @@ package test.cases.context; import test.TestMethod; -import test.cases.basic.Allocation; import test.core.QueryMethods; @SuppressWarnings("unused") @@ -32,13 +31,13 @@ public void callee(Object a, Object b) { } public void test1() { - Object a1 = new Allocation(); + Object a1 = new ContextAlloc(); Object b1 = a1; callee(a1, b1); } public void test2() { - Object a2 = new Allocation(); + Object a2 = new ContextAlloc(); Object b2 = new Object(); callee(a2, b2); } @@ -58,14 +57,14 @@ public void callee(Object a, Object b) { } public void test1() { - Object a1 = new Allocation(); + Object a1 = new ContextAlloc(); Object b1 = a1; callee(a1, b1); } public void test2() { Object a2 = new Object(); - Object b2 = new Allocation(); + Object b2 = new ContextAlloc(); callee(a2, b2); } } diff --git a/boomerangPDS/src/test/java/test/cases/context/SimpleContextQueryTarget.java b/boomerangPDS/src/test/java/test/cases/context/SimpleContextQueryTarget.java index 169632678..d4994ed79 100644 --- a/boomerangPDS/src/test/java/test/cases/context/SimpleContextQueryTarget.java +++ b/boomerangPDS/src/test/java/test/cases/context/SimpleContextQueryTarget.java @@ -12,7 +12,6 @@ package test.cases.context; import test.TestMethod; -import test.cases.fields.Alloc; import test.core.QueryMethods; import test.core.selfrunning.AllocatedObject; @@ -21,7 +20,7 @@ public class SimpleContextQueryTarget { @TestMethod public void outerAllocation() { - AllocatedObject alloc = new Alloc(); + AllocatedObject alloc = new ContextAlloc(); methodOfQuery(alloc); } diff --git a/boomerangPDS/src/test/java/test/cases/exceptions/ExceptionAlloc.java b/boomerangPDS/src/test/java/test/cases/exceptions/ExceptionAlloc.java new file mode 100644 index 000000000..c28ab6645 --- /dev/null +++ b/boomerangPDS/src/test/java/test/cases/exceptions/ExceptionAlloc.java @@ -0,0 +1,16 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ +package test.cases.exceptions; + +import test.core.selfrunning.AllocatedObject; + +public class ExceptionAlloc implements AllocatedObject {} diff --git a/boomerangPDS/src/test/java/test/cases/exceptions/ExceptionTarget.java b/boomerangPDS/src/test/java/test/cases/exceptions/ExceptionTarget.java index 2e52ecc7d..e74c88a2a 100644 --- a/boomerangPDS/src/test/java/test/cases/exceptions/ExceptionTarget.java +++ b/boomerangPDS/src/test/java/test/cases/exceptions/ExceptionTarget.java @@ -12,7 +12,6 @@ package test.cases.exceptions; import test.TestMethod; -import test.cases.fields.Alloc; import test.core.QueryMethods; @SuppressWarnings("unused") @@ -23,7 +22,7 @@ public void compileTimeExceptionFlow() { try { throwException(); } catch (MyException e) { - Alloc object = e.field; + ExceptionAlloc object = e.field; QueryMethods.queryFor(e); } } @@ -33,31 +32,31 @@ public void runtimeExceptionFlow() { try { throwRuntimeException(); } catch (MyRuntimeException e) { - Alloc object = e.field; + ExceptionAlloc object = e.field; QueryMethods.queryFor(e); } } private void throwRuntimeException() { - new MyRuntimeException(new Alloc()); + new MyRuntimeException(new ExceptionAlloc()); } private static class MyRuntimeException extends RuntimeException { - Alloc field; + ExceptionAlloc field; - public MyRuntimeException(Alloc alloc) { + public MyRuntimeException(ExceptionAlloc alloc) { field = alloc; } } private void throwException() throws MyException { - throw new MyException(new Alloc()); + throw new MyException(new ExceptionAlloc()); } private static class MyException extends Exception { - Alloc field; + ExceptionAlloc field; - public MyException(Alloc alloc) { + public MyException(ExceptionAlloc alloc) { field = alloc; } } diff --git a/boomerangPDS/src/test/java/test/cases/fields/BasicFieldTarget.java b/boomerangPDS/src/test/java/test/cases/fields/BasicFieldTarget.java index 201a1756a..03cde1ecc 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/BasicFieldTarget.java +++ b/boomerangPDS/src/test/java/test/cases/fields/BasicFieldTarget.java @@ -20,10 +20,10 @@ public class BasicFieldTarget { @TestMethod public void basicFieldReadAndWriteTest() { ClassWithField c = new ClassWithField(); - Alloc alloc = new Alloc(); + FieldAlloc alloc = new FieldAlloc(); c.field = alloc; - Alloc query = c.field; + FieldAlloc query = c.field; QueryMethods.queryFor(query); } @@ -31,10 +31,10 @@ public void basicFieldReadAndWriteTest() { @TestMethod public void basicFieldGetAndSetTest() { ClassWithField c = new ClassWithField(); - Alloc alloc = new Alloc(); + FieldAlloc alloc = new FieldAlloc(); c.setField(alloc); - Alloc query = c.getField(); + FieldAlloc query = c.getField(); QueryMethods.queryFor(query); } @@ -42,22 +42,22 @@ public void basicFieldGetAndSetTest() { @TestMethod public void nestedFieldReadAndWriteTest() { ClassWithNestedFields c = new ClassWithNestedFields(); - Alloc alloc = new Alloc(); + FieldAlloc alloc = new FieldAlloc(); c.c.field = alloc; - Alloc query = c.c.field; + FieldAlloc query = c.c.field; QueryMethods.queryFor(query); } private static class ClassWithField { - Alloc field; + FieldAlloc field; - public Alloc getField() { + public FieldAlloc getField() { return field; } - public void setField(Alloc alloc) { + public void setField(FieldAlloc alloc) { this.field = alloc; } } diff --git a/boomerangPDS/src/test/java/test/cases/fields/CallPOITarget.java b/boomerangPDS/src/test/java/test/cases/fields/CallPOITarget.java index 1dbc4fb7d..2d296f25b 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/CallPOITarget.java +++ b/boomerangPDS/src/test/java/test/cases/fields/CallPOITarget.java @@ -30,7 +30,7 @@ public static class AllocObj implements AllocatedObject {} @TestMethod public void simpleButDiffer() { - Alloc c = new Alloc(); + FieldAlloc c = new FieldAlloc(); T t = new T(c); S s = new S(); t.foo(s); @@ -162,7 +162,7 @@ public void innerSetFieldOnAlias() { } private void set(Outer o) { - Alloc alloc = new Alloc(); + FieldAlloc alloc = new FieldAlloc(); Outer alias = o; alias.field = alloc; } @@ -186,17 +186,17 @@ public void indirectAllocationSiteViaParameterAliasedNoPreAllocs() { @TestMethod public void testForBackwardCallPOI() { // Thanks to Martin Mory for contributing the test. - Alloc v = new Alloc(); + FieldAlloc v = new FieldAlloc(); Object x = front(v); QueryMethods.queryFor(x); } public static Object fromIt(SomeObj it) { - Alloc x = it.f; + FieldAlloc x = it.f; return x; } - public static Object front(Alloc y) { + public static Object front(FieldAlloc y) { SomeObj it = new SomeObj(); SomeObj it2 = it; it2.f = y; @@ -205,7 +205,7 @@ public static Object front(Alloc y) { } public static class SomeObj { - Alloc f; + FieldAlloc f; } private void allocation(A1 a, AllocObj1 d) { diff --git a/boomerangPDS/src/test/java/test/cases/fields/CastAndSetTarget.java b/boomerangPDS/src/test/java/test/cases/fields/CastAndSetTarget.java index 3c9d9abaf..8c59b6819 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/CastAndSetTarget.java +++ b/boomerangPDS/src/test/java/test/cases/fields/CastAndSetTarget.java @@ -23,7 +23,7 @@ public void setAndGet() { Container container = new Container(); Object o1 = new Object(); container.set(o1); - AllocatedObject o2 = new Alloc(); + AllocatedObject o2 = new FieldAlloc(); container.set(o2); AllocatedObject alias = container.get(); QueryMethods.queryFor(alias); diff --git a/boomerangPDS/src/test/java/test/cases/fields/FailOnVisitMethodTest.java b/boomerangPDS/src/test/java/test/cases/fields/FailOnVisitMethodTest.java index 050488142..67bad73a4 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/FailOnVisitMethodTest.java +++ b/boomerangPDS/src/test/java/test/cases/fields/FailOnVisitMethodTest.java @@ -36,11 +36,11 @@ public void failOnVisitBarSameMethodAlloc() { @Test public void failOnVisitBarSameMethodSimpleAlloc() { - analyze(target, testName.getMethodName()); + analyze(target, testName.getMethodName(), true); } @Test public void doNotVisitBar() { - analyze(target, testName.getMethodName()); + analyze(target, testName.getMethodName(), true); } } diff --git a/boomerangPDS/src/test/java/test/cases/fields/Alloc.java b/boomerangPDS/src/test/java/test/cases/fields/FieldAlloc.java similarity index 91% rename from boomerangPDS/src/test/java/test/cases/fields/Alloc.java rename to boomerangPDS/src/test/java/test/cases/fields/FieldAlloc.java index 3e6c48cc2..ec16c7578 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/Alloc.java +++ b/boomerangPDS/src/test/java/test/cases/fields/FieldAlloc.java @@ -13,4 +13,4 @@ import test.core.selfrunning.AllocatedObject; -public class Alloc implements AllocatedObject {} +public class FieldAlloc implements AllocatedObject {} diff --git a/boomerangPDS/src/test/java/test/cases/fields/HiddenFieldLoadTarget.java b/boomerangPDS/src/test/java/test/cases/fields/HiddenFieldLoadTarget.java index 0f47b6633..693f7ad0f 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/HiddenFieldLoadTarget.java +++ b/boomerangPDS/src/test/java/test/cases/fields/HiddenFieldLoadTarget.java @@ -51,7 +51,7 @@ public void run7() { public void run3() { A b = new A(); A a = b; - Alloc alloc = new Alloc(); + FieldAlloc alloc = new FieldAlloc(); b.setF(alloc); // int x =1; Object alias = a.f(); @@ -62,7 +62,7 @@ public void run3() { public void run6() { A b = new A(); A a = b; - Alloc allocInRun6 = new Alloc(); + FieldAlloc allocInRun6 = new FieldAlloc(); b.setF(allocInRun6); int x = 1; Object alias = a.f; @@ -73,7 +73,7 @@ public void run6() { public void run2() { A b = new A(); A a = b; - Alloc c = new Alloc(); + FieldAlloc c = new FieldAlloc(); int y = 1; b.f = c; int x = 1; @@ -85,7 +85,7 @@ public void run2() { public void run4() { A b = new A(); A a = b; - b.f = new Alloc(); + b.f = new FieldAlloc(); Object alias = a.f; QueryMethods.queryFor(alias); } @@ -94,14 +94,14 @@ private static class A { Object f; public void setF() { - f = new Alloc(); + f = new FieldAlloc(); } public void setFBranched() { if (staticallyUnknown()) { - f = new Alloc(); + f = new FieldAlloc(); } else { - f = new Alloc(); + f = new FieldAlloc(); } } diff --git a/boomerangPDS/src/test/java/test/cases/fields/NoIndirectionTarget.java b/boomerangPDS/src/test/java/test/cases/fields/NoIndirectionTarget.java index 5090bccaa..9a51c8232 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/NoIndirectionTarget.java +++ b/boomerangPDS/src/test/java/test/cases/fields/NoIndirectionTarget.java @@ -19,7 +19,7 @@ public class NoIndirectionTarget { @TestMethod public void doubleWriteAndReadFieldPositive() { - Object query = new Alloc(); + Object query = new FieldAlloc(); A a = new A(); B b = new B(); a.b = query; @@ -43,7 +43,7 @@ public void doubleWriteAndReadFieldNegative() { @TestMethod public void writeWithinCallPositive() { - Alloc query = new Alloc(); + FieldAlloc query = new FieldAlloc(); A a = new A(); call(a, query); Object alias = a.b; @@ -61,7 +61,7 @@ public void writeWithinCallNegative() { @TestMethod public void writeWithinCallSummarizedPositive() { - Alloc query = new Alloc(); + FieldAlloc query = new FieldAlloc(); A a = new A(); call(a, query); Object alias = a.b; @@ -77,7 +77,7 @@ private void call(A a, Object query) { @TestMethod public void doubleWriteWithinCallPositive() { - Alloc query = new Alloc(); + FieldAlloc query = new FieldAlloc(); A a = new A(); B b = callAndReturn(a, query); A first = b.a; @@ -85,7 +85,7 @@ public void doubleWriteWithinCallPositive() { QueryMethods.queryFor(alias); } - private B callAndReturn(A a, Alloc query) { + private B callAndReturn(A a, FieldAlloc query) { a.b = query; B b = new B(); b.a = a; @@ -104,7 +104,7 @@ public void overwriteFieldTest() { @TestMethod public void overwriteButPositiveFieldTest() { - Alloc query = new Alloc(); + FieldAlloc query = new FieldAlloc(); A a = new A(); a.b = query; // a.c = null; diff --git a/boomerangPDS/src/test/java/test/cases/fields/NoIndirectionTest.java b/boomerangPDS/src/test/java/test/cases/fields/NoIndirectionTest.java index 2d5cfc036..0121fe7d8 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/NoIndirectionTest.java +++ b/boomerangPDS/src/test/java/test/cases/fields/NoIndirectionTest.java @@ -25,7 +25,7 @@ public void doubleWriteAndReadFieldPositive() { @Test public void doubleWriteAndReadFieldNegative() { - analyze(target, testName.getMethodName()); + analyze(target, testName.getMethodName(), true); } @Test @@ -35,7 +35,7 @@ public void writeWithinCallPositive() { @Test public void writeWithinCallNegative() { - analyze(target, testName.getMethodName()); + analyze(target, testName.getMethodName(), true); } @Test @@ -50,7 +50,7 @@ public void doubleWriteWithinCallPositive() { @Test public void overwriteFieldTest() { - analyze(target, testName.getMethodName()); + analyze(target, testName.getMethodName(), true); } @Test @@ -60,6 +60,6 @@ public void overwriteButPositiveFieldTest() { @Test public void overwriteButPositiveFieldTest2() { - analyze(target, testName.getMethodName()); + analyze(target, testName.getMethodName(), true); } } diff --git a/boomerangPDS/src/test/java/test/cases/fields/NullAllocationConstructorTest.java b/boomerangPDS/src/test/java/test/cases/fields/NullAllocationConstructorTest.java index ecbd14a1c..ff2a64a52 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/NullAllocationConstructorTest.java +++ b/boomerangPDS/src/test/java/test/cases/fields/NullAllocationConstructorTest.java @@ -20,6 +20,6 @@ public class NullAllocationConstructorTest extends AbstractBoomerangTest { @Test public void nullAllocationOfField() { - analyze(target, testName.getMethodName()); + analyze(target, testName.getMethodName(), true); } } diff --git a/boomerangPDS/src/test/java/test/cases/fields/ObjectSensitivityTarget.java b/boomerangPDS/src/test/java/test/cases/fields/ObjectSensitivityTarget.java index ff92c5668..f83346985 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/ObjectSensitivityTarget.java +++ b/boomerangPDS/src/test/java/test/cases/fields/ObjectSensitivityTarget.java @@ -20,7 +20,7 @@ public class ObjectSensitivityTarget { @TestMethod public void objectSensitivity0() { B b1 = new B(); - Alloc b2 = new Alloc(); + FieldAlloc b2 = new FieldAlloc(); A a1 = new A(); A a2 = new A(); @@ -37,7 +37,7 @@ public void objectSensitivity0() { @TestMethod public void objectSensitivity1() { B b1 = new B(); - Alloc b2 = new Alloc(); + FieldAlloc b2 = new FieldAlloc(); A a1 = new A(b1); A a2 = new A(b2); @@ -52,7 +52,7 @@ private void flow(Object b3) {} @TestMethod public void objectSensitivity2() { - Alloc b2 = new Alloc(); + FieldAlloc b2 = new FieldAlloc(); A a2 = new A(b2); otherScope(); diff --git a/boomerangPDS/src/test/java/test/cases/fields/ReadPOITest.java b/boomerangPDS/src/test/java/test/cases/fields/ReadPOITest.java index 91974d72c..880d1d2a9 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/ReadPOITest.java +++ b/boomerangPDS/src/test/java/test/cases/fields/ReadPOITest.java @@ -40,7 +40,7 @@ public void unbalancedField() { @Test public void loadTwice() { - analyze(target, testName.getMethodName()); + analyze(target, testName.getMethodName(), true); } @Test diff --git a/boomerangPDS/src/test/java/test/cases/fields/ReuseOfSummaryTarget.java b/boomerangPDS/src/test/java/test/cases/fields/ReuseOfSummaryTarget.java index b19fdfb92..1c93d84d4 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/ReuseOfSummaryTarget.java +++ b/boomerangPDS/src/test/java/test/cases/fields/ReuseOfSummaryTarget.java @@ -22,7 +22,7 @@ public void summaryTest() { A a = new A(); A b = new A(); - Object c = new Alloc(); // o1 + Object c = new FieldAlloc(); // o1 foo(a, b, c); foo(a, a, c); diff --git a/boomerangPDS/src/test/java/test/cases/fields/TypeChangeTarget.java b/boomerangPDS/src/test/java/test/cases/fields/TypeChangeTarget.java index 6814cf273..e7835b383 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/TypeChangeTarget.java +++ b/boomerangPDS/src/test/java/test/cases/fields/TypeChangeTarget.java @@ -41,11 +41,11 @@ public void returnValueAndBackCast() { } public static class D { - Alloc f = new Alloc(); + FieldAlloc f = new FieldAlloc(); D d = new D(); public Object getField() { - Alloc varShouldBeThere = this.f; + FieldAlloc varShouldBeThere = this.f; return varShouldBeThere; } diff --git a/boomerangPDS/src/test/java/test/cases/fields/WritePOITest.java b/boomerangPDS/src/test/java/test/cases/fields/WritePOITest.java index 7fee99317..8ba182136 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/WritePOITest.java +++ b/boomerangPDS/src/test/java/test/cases/fields/WritePOITest.java @@ -120,11 +120,11 @@ public void fieldStoreAndLoad2() { @Test public void doubleNested() { - analyze(target, testName.getMethodName()); + analyze(target, testName.getMethodName(), true); } @Test public void doubleNestedBranched() { - analyze(target, testName.getMethodName()); + analyze(target, testName.getMethodName(), true); } } diff --git a/boomerangPDS/src/test/java/test/cases/fields/complexity/Recursion2LongTarget.java b/boomerangPDS/src/test/java/test/cases/fields/complexity/Recursion2LongTarget.java index ef7ad6141..4e5f0830a 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/complexity/Recursion2LongTarget.java +++ b/boomerangPDS/src/test/java/test/cases/fields/complexity/Recursion2LongTarget.java @@ -12,15 +12,15 @@ package test.cases.fields.complexity; import test.TestMethod; -import test.cases.fields.Alloc; +import test.cases.fields.FieldAlloc; import test.core.QueryMethods; public class Recursion2LongTarget { @TestMethod public void test() { - Alloc alloc = new Alloc(); - Alloc alias = mainMethod(alloc, new A()); + FieldAlloc alloc = new FieldAlloc(); + FieldAlloc alias = mainMethod(alloc, new A()); QueryMethods.queryFor(alias); } @@ -32,10 +32,10 @@ public interface IFoo { public static class DS { public DS a; - private Alloc result; + private FieldAlloc result; } - public Alloc mainMethod(Alloc object, IFoo foo) { + public FieldAlloc mainMethod(FieldAlloc object, IFoo foo) { DS ds = new DS(); ds.result = object; DS a = foo.before(ds); diff --git a/boomerangPDS/src/test/java/test/cases/fields/complexity/Recursion2LongTest.java b/boomerangPDS/src/test/java/test/cases/fields/complexity/Recursion2LongTest.java index 7c2cae04a..168d96690 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/complexity/Recursion2LongTest.java +++ b/boomerangPDS/src/test/java/test/cases/fields/complexity/Recursion2LongTest.java @@ -20,6 +20,6 @@ public class Recursion2LongTest extends AbstractBoomerangTest { @Test public void test() { - analyze(target, testName.getMethodName()); + analyze(target, testName.getMethodName(), true); } } diff --git a/boomerangPDS/src/test/java/test/cases/hashmap/AllAliasLongTest.java b/boomerangPDS/src/test/java/test/cases/hashmap/AllAliasLongTest.java index 5a85b7db6..d9cec6a8c 100644 --- a/boomerangPDS/src/test/java/test/cases/hashmap/AllAliasLongTest.java +++ b/boomerangPDS/src/test/java/test/cases/hashmap/AllAliasLongTest.java @@ -20,6 +20,6 @@ public class AllAliasLongTest extends AbstractBoomerangTest { @Test public void test() { - analyze(target, testName.getMethodName()); + analyze(target, testName.getMethodName(), true); } } diff --git a/boomerangPDS/src/test/java/test/cases/hashmap/KeySensitiveTarget.java b/boomerangPDS/src/test/java/test/cases/hashmap/KeySensitiveTarget.java index 3f1f6ba3a..a8369f29a 100644 --- a/boomerangPDS/src/test/java/test/cases/hashmap/KeySensitiveTarget.java +++ b/boomerangPDS/src/test/java/test/cases/hashmap/KeySensitiveTarget.java @@ -14,7 +14,6 @@ import java.util.HashMap; import java.util.Map; import test.TestMethod; -import test.cases.fields.Alloc; import test.core.QueryMethods; import test.core.selfrunning.AllocatedObject; import test.core.selfrunning.NoAllocatedObject; @@ -28,7 +27,7 @@ public static class NoAllocation implements NoAllocatedObject {} @TestMethod public void directAccess() { - AllocatedObject someValue = new Alloc(); + AllocatedObject someValue = new MapAlloc(); Map x = new HashMap<>(); x.put("key", someValue); AllocatedObject t = x.get("key"); @@ -37,7 +36,7 @@ public void directAccess() { @TestMethod public void directAccess2Keys() { - AllocatedObject someValue = new Alloc(); + AllocatedObject someValue = new MapAlloc(); Map x = new HashMap<>(); x.put("key", someValue); x.put("key2", new NoAllocation()); @@ -47,7 +46,7 @@ public void directAccess2Keys() { @TestMethod public void overwrite() { - AllocatedObject someValue = new Alloc(); + AllocatedObject someValue = new MapAlloc(); Map x = new HashMap<>(); // False Positive: Overapproximation. We do not kill during the forward analysis. x.put("key", new Allocation()); @@ -58,7 +57,7 @@ public void overwrite() { @TestMethod public void accessWithAliasedKey() { - AllocatedObject someValue = new Alloc(); + AllocatedObject someValue = new MapAlloc(); Map x = new HashMap<>(); String key = "key"; x.put(key, someValue); @@ -69,7 +68,7 @@ public void accessWithAliasedKey() { @TestMethod public void accessWithKeyFromReturn() { - AllocatedObject someValue = new Alloc(); + AllocatedObject someValue = new MapAlloc(); Map x = new HashMap<>(); x.put(getKey(), someValue); x.put("key2", new NoAllocation()); @@ -79,7 +78,7 @@ public void accessWithKeyFromReturn() { @TestMethod public void interprocedural() { - AllocatedObject someValue = new Alloc(); + AllocatedObject someValue = new MapAlloc(); Map x = new HashMap<>(); x.put(getKey(), someValue); x.put("key2", new NoAllocation()); diff --git a/boomerangPDS/src/test/java/test/cases/hashmap/MapAlloc.java b/boomerangPDS/src/test/java/test/cases/hashmap/MapAlloc.java new file mode 100644 index 000000000..00ad2c8a4 --- /dev/null +++ b/boomerangPDS/src/test/java/test/cases/hashmap/MapAlloc.java @@ -0,0 +1,16 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ +package test.cases.hashmap; + +import test.core.selfrunning.AllocatedObject; + +public class MapAlloc implements AllocatedObject {} diff --git a/boomerangPDS/src/test/java/test/cases/lists/ArrayAndLinkedListsTarget.java b/boomerangPDS/src/test/java/test/cases/lists/ArrayAndLinkedListsTarget.java index f069ba028..7ce7e1629 100644 --- a/boomerangPDS/src/test/java/test/cases/lists/ArrayAndLinkedListsTarget.java +++ b/boomerangPDS/src/test/java/test/cases/lists/ArrayAndLinkedListsTarget.java @@ -15,7 +15,6 @@ import java.util.LinkedList; import java.util.List; import test.TestMethod; -import test.cases.fields.Alloc; import test.core.QueryMethods; @SuppressWarnings("unused") @@ -24,7 +23,7 @@ public class ArrayAndLinkedListsTarget { @TestMethod public void addAndRetrieve() { List list1 = new LinkedList<>(); - Object o = new Alloc(); + Object o = new ListAlloc(); add(list1, o); Object o2 = new Object(); List list2 = new ArrayList<>(); diff --git a/boomerangPDS/src/test/java/test/cases/lists/ArrayListsLongTarget.java b/boomerangPDS/src/test/java/test/cases/lists/ArrayListsLongTarget.java index a32e26fd5..e848f70f3 100644 --- a/boomerangPDS/src/test/java/test/cases/lists/ArrayListsLongTarget.java +++ b/boomerangPDS/src/test/java/test/cases/lists/ArrayListsLongTarget.java @@ -14,7 +14,6 @@ import java.util.ArrayList; import java.util.List; import test.TestMethod; -import test.cases.fields.Alloc; import test.core.QueryMethods; import test.core.selfrunning.AllocatedObject; @@ -36,7 +35,7 @@ public void addAndRetrieveWithIterator() { @TestMethod public void addAndRetrieveByIndex1() { List list = new ArrayList<>(); - Alloc alias = new Alloc(); + ListAlloc alias = new ListAlloc(); list.add(alias); Object ir = list.get(0); Object query2 = ir; @@ -57,7 +56,7 @@ public void addAndRetrieveByIndex2() { public void addAndRetrieveByIndex3() { ArrayList list = new ArrayList<>(); Object b = new Object(); - Object a = new Alloc(); + Object a = new ListAlloc(); list.add(a); list.add(b); Object c = list.get(0); diff --git a/boomerangPDS/src/test/java/test/cases/lists/LinkedListsLongTarget.java b/boomerangPDS/src/test/java/test/cases/lists/LinkedListsLongTarget.java index 9001f27bd..8d90136cc 100644 --- a/boomerangPDS/src/test/java/test/cases/lists/LinkedListsLongTarget.java +++ b/boomerangPDS/src/test/java/test/cases/lists/LinkedListsLongTarget.java @@ -14,7 +14,6 @@ import java.util.LinkedList; import java.util.List; import test.TestMethod; -import test.cases.fields.Alloc; import test.core.QueryMethods; import test.core.selfrunning.AllocatedObject; @@ -57,7 +56,7 @@ public void addAndRetrieveByIndex2() { public void addAndRetrieveByIndex3() { LinkedList list = new LinkedList<>(); Object b = new Object(); - Object a = new Alloc(); + Object a = new ListAlloc(); list.add(a); list.add(b); Object c = list.get(0); diff --git a/boomerangPDS/src/test/java/test/cases/lists/LinkedListsLongTest.java b/boomerangPDS/src/test/java/test/cases/lists/LinkedListsLongTest.java index fc4341708..7f2c81c1e 100644 --- a/boomerangPDS/src/test/java/test/cases/lists/LinkedListsLongTest.java +++ b/boomerangPDS/src/test/java/test/cases/lists/LinkedListsLongTest.java @@ -13,7 +13,6 @@ import java.util.List; import org.junit.Test; -import test.cases.callgraph.ContextSpecificListTypeTarget; import test.core.AbstractBoomerangTest; public class LinkedListsLongTest extends AbstractBoomerangTest { @@ -29,13 +28,8 @@ protected List getIncludedPackages() { "java.util.LinkedList", "java.util.LinkedList$ListItr", "java.util.LinkedList$Node", - "java.util.Iterator"); - } - - @Override - protected List getExcludedPackages() { - // This is required because CHA adds an edge to the WrongList class, too - return List.of(ContextSpecificListTypeTarget.WrongList.class.getName()); + "java.util.Iterator", + "java.util.ListIterator"); } @Test diff --git a/boomerangPDS/src/test/java/test/cases/lists/LinkedListsTypeLongTest.java b/boomerangPDS/src/test/java/test/cases/lists/LinkedListsTypeLongTest.java index 1ffe127d3..66865fe66 100644 --- a/boomerangPDS/src/test/java/test/cases/lists/LinkedListsTypeLongTest.java +++ b/boomerangPDS/src/test/java/test/cases/lists/LinkedListsTypeLongTest.java @@ -28,7 +28,8 @@ protected List getIncludedPackages() { "java.util.AbstractList", "java.util.AbstractSequentialList", "java.util.List", - "java.util.Iterator"); + "java.util.Iterator", + "java.util.ListIterator"); } @Test diff --git a/boomerangPDS/src/test/java/test/cases/lists/ListAlloc.java b/boomerangPDS/src/test/java/test/cases/lists/ListAlloc.java new file mode 100644 index 000000000..3a762bb6e --- /dev/null +++ b/boomerangPDS/src/test/java/test/cases/lists/ListAlloc.java @@ -0,0 +1,16 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ +package test.cases.lists; + +import test.core.selfrunning.AllocatedObject; + +public class ListAlloc implements AllocatedObject {} diff --git a/boomerangPDS/src/test/java/test/cases/realworld/ScalabilityOfBackwardAnalysisTest.java b/boomerangPDS/src/test/java/test/cases/realworld/ScalabilityOfBackwardAnalysisTest.java index 8cbb490d0..a57fca959 100644 --- a/boomerangPDS/src/test/java/test/cases/realworld/ScalabilityOfBackwardAnalysisTest.java +++ b/boomerangPDS/src/test/java/test/cases/realworld/ScalabilityOfBackwardAnalysisTest.java @@ -20,6 +20,6 @@ public class ScalabilityOfBackwardAnalysisTest extends AbstractBoomerangTest { @Test public void simpleButDifficult() { - analyze(target, testName.getMethodName()); + analyze(target, testName.getMethodName(), true); } } diff --git a/boomerangPDS/src/test/java/test/cases/reflection/ReflectionAlloc.java b/boomerangPDS/src/test/java/test/cases/reflection/ReflectionAlloc.java new file mode 100644 index 000000000..f194cfc74 --- /dev/null +++ b/boomerangPDS/src/test/java/test/cases/reflection/ReflectionAlloc.java @@ -0,0 +1,16 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ +package test.cases.reflection; + +import test.core.selfrunning.AllocatedObject; + +public class ReflectionAlloc implements AllocatedObject {} diff --git a/boomerangPDS/src/test/java/test/cases/reflection/ReflectionTarget.java b/boomerangPDS/src/test/java/test/cases/reflection/ReflectionTarget.java index 01a7f7ffa..6d9e3ff1c 100644 --- a/boomerangPDS/src/test/java/test/cases/reflection/ReflectionTarget.java +++ b/boomerangPDS/src/test/java/test/cases/reflection/ReflectionTarget.java @@ -12,7 +12,6 @@ package test.cases.reflection; import test.TestMethod; -import test.cases.fields.Alloc; import test.core.QueryMethods; @SuppressWarnings("unused") @@ -20,7 +19,7 @@ public class ReflectionTarget { @TestMethod public void bypassClassForName() throws ClassNotFoundException { - Alloc query = new Alloc(); + ReflectionAlloc query = new ReflectionAlloc(); Class cls = Class.forName(A.class.getName()); QueryMethods.queryFor(query); } @@ -31,11 +30,11 @@ public void loadObject() Class cls = Class.forName(A.class.getName()); Object newInstance = cls.newInstance(); A a = (A) newInstance; - Alloc query = a.field; + ReflectionAlloc query = a.field; QueryMethods.queryFor(query); } private static class A { - Alloc field = new Alloc(); + ReflectionAlloc field = new ReflectionAlloc(); } } diff --git a/boomerangPDS/src/test/java/test/cases/reflection/ReflectionTest.java b/boomerangPDS/src/test/java/test/cases/reflection/ReflectionTest.java index 54129f4ae..746741347 100644 --- a/boomerangPDS/src/test/java/test/cases/reflection/ReflectionTest.java +++ b/boomerangPDS/src/test/java/test/cases/reflection/ReflectionTest.java @@ -25,6 +25,6 @@ public void bypassClassForName() { @Test public void loadObject() { - analyze(target, testName.getMethodName()); + analyze(target, testName.getMethodName(), true); } } diff --git a/boomerangPDS/src/test/java/test/cases/sets/CustomMapTarget.java b/boomerangPDS/src/test/java/test/cases/sets/CustomMapTarget.java index 8d5d13d29..88cbb7a47 100644 --- a/boomerangPDS/src/test/java/test/cases/sets/CustomMapTarget.java +++ b/boomerangPDS/src/test/java/test/cases/sets/CustomMapTarget.java @@ -12,14 +12,14 @@ package test.cases.sets; import test.TestMethod; -import test.cases.fields.Alloc; import test.core.QueryMethods; +@SuppressWarnings("unused") public class CustomMapTarget { @TestMethod public void storeAndLoad() { - Alloc alloc = new Alloc(); + SetAlloc alloc = new SetAlloc(); Map map = new Map(); map.add(alloc); Object alias = map.get(); @@ -28,7 +28,7 @@ public void storeAndLoad() { @TestMethod public void storeAndLoadSimple() { - Alloc alloc = new Alloc(); + SetAlloc alloc = new SetAlloc(); Map map = new Map(); map.add(alloc); Object alias = map.m.content; @@ -37,7 +37,7 @@ public void storeAndLoadSimple() { @TestMethod public void onlyInnerMapSimple() { - Alloc alloc = new Alloc(); + SetAlloc alloc = new SetAlloc(); InnerMap map = new InnerMap(); map.innerAdd(alloc); Object alias = map.content; @@ -74,7 +74,7 @@ public Object get() { @TestMethod public void storeAndLoadSimpleNoInnerClasses() { - Alloc alloc = new Alloc(); + SetAlloc alloc = new SetAlloc(); MyMap map = new MyMap(); map.add(alloc); MyInnerMap load = map.m; diff --git a/boomerangPDS/src/test/java/test/cases/sets/CustomSetTarget.java b/boomerangPDS/src/test/java/test/cases/sets/CustomSetTarget.java index 7444cbd7d..2063956e3 100644 --- a/boomerangPDS/src/test/java/test/cases/sets/CustomSetTarget.java +++ b/boomerangPDS/src/test/java/test/cases/sets/CustomSetTarget.java @@ -13,7 +13,6 @@ import java.util.Iterator; import test.TestMethod; -import test.cases.fields.Alloc; import test.core.QueryMethods; import test.core.selfrunning.AllocatedObject; @@ -57,7 +56,7 @@ public void remove() {} @TestMethod public void mySetIterableTest() { MySet mySet = new MySet(); - AllocatedObject alias = new Alloc(); + AllocatedObject alias = new SetAlloc(); mySet.add(alias); Object query = null; for (Object el : mySet) { diff --git a/boomerangPDS/src/test/java/test/cases/sets/HashMapGetLongTarget.java b/boomerangPDS/src/test/java/test/cases/sets/HashMapGetLongTarget.java index 4da9c4909..65dea1ec6 100644 --- a/boomerangPDS/src/test/java/test/cases/sets/HashMapGetLongTarget.java +++ b/boomerangPDS/src/test/java/test/cases/sets/HashMapGetLongTarget.java @@ -14,7 +14,6 @@ import java.util.HashMap; import java.util.Map; import test.TestMethod; -import test.cases.fields.Alloc; import test.core.QueryMethods; import test.core.selfrunning.AllocatedObject; @@ -25,7 +24,7 @@ public class HashMapGetLongTarget { public void addAndRetrieve() { Map map = new HashMap<>(); Object key = new Object(); - AllocatedObject alias3 = new Alloc(); + AllocatedObject alias3 = new SetAlloc(); map.put(key, alias3); Object query = map.get(key); QueryMethods.queryFor(query); @@ -36,7 +35,7 @@ public void addAndLoadFromOther() { Map map = new HashMap<>(); Object key = new Object(); Object loadKey = new Object(); - AllocatedObject alias3 = new Alloc(); + AllocatedObject alias3 = new SetAlloc(); map.put(key, alias3); Object query = map.get(loadKey); QueryMethods.queryFor(query); diff --git a/boomerangPDS/src/test/java/test/cases/sets/HashMapsLongTarget.java b/boomerangPDS/src/test/java/test/cases/sets/HashMapsLongTarget.java index ac64747c5..3a4d2cc9d 100644 --- a/boomerangPDS/src/test/java/test/cases/sets/HashMapsLongTarget.java +++ b/boomerangPDS/src/test/java/test/cases/sets/HashMapsLongTarget.java @@ -14,7 +14,6 @@ import java.util.HashMap; import java.util.Map; import test.TestMethod; -import test.cases.fields.Alloc; import test.core.QueryMethods; import test.core.selfrunning.AllocatedObject; @@ -25,7 +24,7 @@ public class HashMapsLongTarget { public void addAndRetrieve() { Map set = new HashMap<>(); Object key = new Object(); - AllocatedObject alias3 = new Alloc(); + AllocatedObject alias3 = new SetAlloc(); set.put(key, alias3); Object alias2 = null; for (Object o : set.values()) alias2 = o; diff --git a/boomerangPDS/src/test/java/test/cases/sets/SetAlloc.java b/boomerangPDS/src/test/java/test/cases/sets/SetAlloc.java new file mode 100644 index 000000000..6efb8731e --- /dev/null +++ b/boomerangPDS/src/test/java/test/cases/sets/SetAlloc.java @@ -0,0 +1,16 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ +package test.cases.sets; + +import test.core.selfrunning.AllocatedObject; + +public class SetAlloc implements AllocatedObject {} diff --git a/boomerangPDS/src/test/java/test/cases/sets/TreeMapLongTarget.java b/boomerangPDS/src/test/java/test/cases/sets/TreeMapLongTarget.java index f5d88dbf3..eb2ad07b8 100644 --- a/boomerangPDS/src/test/java/test/cases/sets/TreeMapLongTarget.java +++ b/boomerangPDS/src/test/java/test/cases/sets/TreeMapLongTarget.java @@ -14,7 +14,6 @@ import java.util.Map; import java.util.TreeMap; import test.TestMethod; -import test.cases.fields.Alloc; import test.core.QueryMethods; @SuppressWarnings("unused") @@ -23,7 +22,7 @@ public class TreeMapLongTarget { @TestMethod public void addAndRetrieve() { Map set = new TreeMap<>(); - Alloc alias = new Alloc(); + SetAlloc alias = new SetAlloc(); set.put(1, alias); Object query2 = set.get(2); QueryMethods.queryFor(query2); diff --git a/boomerangPDS/src/test/java/test/cases/sets/TreeMapMultipleInstancesTarget.java b/boomerangPDS/src/test/java/test/cases/sets/TreeMapMultipleInstancesTarget.java index e587dbd19..396a82947 100644 --- a/boomerangPDS/src/test/java/test/cases/sets/TreeMapMultipleInstancesTarget.java +++ b/boomerangPDS/src/test/java/test/cases/sets/TreeMapMultipleInstancesTarget.java @@ -15,7 +15,6 @@ import java.util.Map; import java.util.TreeMap; import test.TestMethod; -import test.cases.fields.Alloc; import test.core.QueryMethods; @SuppressWarnings("unused") @@ -24,7 +23,7 @@ public class TreeMapMultipleInstancesTarget { @TestMethod public void addAndRetrieve() { Map set = new TreeMap<>(); - Alloc alias = new Alloc(); + SetAlloc alias = new SetAlloc(); set.put(1, alias); Object query2 = set.get(2); QueryMethods.queryFor(query2); @@ -36,7 +35,7 @@ public void addAndRetrieve() { @TestMethod public void contextSensitive() { Map map = new TreeMap<>(); - Object alias = new Alloc(); + Object alias = new SetAlloc(); Object ret = addToMap(map, alias); Map map2 = new TreeMap<>(); diff --git a/boomerangPDS/src/test/java/test/cases/sets/TreeSetsLongTarget.java b/boomerangPDS/src/test/java/test/cases/sets/TreeSetsLongTarget.java index f4a944506..ca4862737 100644 --- a/boomerangPDS/src/test/java/test/cases/sets/TreeSetsLongTarget.java +++ b/boomerangPDS/src/test/java/test/cases/sets/TreeSetsLongTarget.java @@ -15,7 +15,6 @@ import java.util.Set; import java.util.TreeSet; import test.TestMethod; -import test.cases.fields.Alloc; import test.core.QueryMethods; @SuppressWarnings("unused") @@ -24,9 +23,9 @@ public class TreeSetsLongTarget { @TestMethod public void addAndRetrieve() { Set set = new TreeSet<>(); - Alloc alias = new Alloc(); + SetAlloc alias = new SetAlloc(); set.add(alias); - alias = new Alloc(); + alias = new SetAlloc(); set.add(alias); Object alias2 = null; diff --git a/boomerangPDS/src/test/java/test/cases/sets/TreeSetsLongTest.java b/boomerangPDS/src/test/java/test/cases/sets/TreeSetsLongTest.java index 5b2b475d0..97a3dda55 100644 --- a/boomerangPDS/src/test/java/test/cases/sets/TreeSetsLongTest.java +++ b/boomerangPDS/src/test/java/test/cases/sets/TreeSetsLongTest.java @@ -24,19 +24,33 @@ public class TreeSetsLongTest extends AbstractBoomerangTest { @Override protected List getIncludedPackages() { return List.of( - "java.util.Set", - "java.util.AbstractSet", - "java.util.NavigableSet", - "java.util.SortedSet", - "java.util.HashSet", - "java.util.TreeSet", - "java.util.Iterator", - "java.util.Map", - "java.util.AbstractMap", - "java.util.TreeMap", + // TODO Add all superclasses from TreeSet and TreeMap + "java.util.TreeMap$EntrySpliterator", + "java.util.TreeMap$ValueSpliterator", + "java.util.TreeMap$DescendingKeySpliterator", + "java.util.TreeMap$KeySpliterator", + "java.util.TreeMap$TreeMapSpliterator", "java.util.TreeMap$Entry", - "java.util.NavigableMap", - "java.util.SortedMap"); + "java.util.TreeMap$SubMap", + "java.util.TreeMap$DescendingSubMap", + "java.util.TreeMap$AscendingSubMap", + "java.util.TreeMap$NavigableSubMap", + "java.util.TreeMap$DescendingKeyIterator", + "java.util.TreeMap$KeyIterator", + "java.util.TreeMap$ValueIterator", + "java.util.TreeMap$EntryIterator", + "java.util.TreeMap$PrivateEntryIterator", + "java.util.TreeMap$KeySet", + "java.util.TreeMap$EntrySet", + "java.util.TreeMap$Values", + "java.util.TreeMap$DescendingSubMap$DescendingEntrySetView", + "java.util.TreeMap$AscendingSubMap$AscendingEntrySetView", + "java.util.TreeMap$NavigableSubMap$DescendingSubMapKeyIterator", + "java.util.TreeMap$NavigableSubMap$SubMapKeyIterator", + "java.util.TreeMap$NavigableSubMap$DescendingSubMapEntryIterator", + "java.util.TreeMap$NavigableSubMap$SubMapEntryIterator", + "java.util.TreeMap$NavigableSubMap$SubMapIterator", + "java.util.TreeMap$NavigableSubMap$EntrySetView"); } @Test diff --git a/boomerangPDS/src/test/java/test/cases/statics/SimpleSingletonTarget.java b/boomerangPDS/src/test/java/test/cases/statics/SimpleSingletonTarget.java index cb30e36d9..dddc6c5fd 100644 --- a/boomerangPDS/src/test/java/test/cases/statics/SimpleSingletonTarget.java +++ b/boomerangPDS/src/test/java/test/cases/statics/SimpleSingletonTarget.java @@ -12,7 +12,6 @@ package test.cases.statics; import test.TestMethod; -import test.cases.fields.Alloc; import test.core.QueryMethods; @SuppressWarnings("unused") @@ -20,11 +19,11 @@ public class SimpleSingletonTarget { @TestMethod public void singletonDirect() { - Alloc singleton = alloc; + StaticsAlloc singleton = alloc; QueryMethods.queryForAndNotEmpty(singleton); } - private static Alloc alloc = new Alloc(); + private static StaticsAlloc alloc = new StaticsAlloc(); @TestMethod public void staticInnerAccessDirect() { @@ -33,7 +32,7 @@ public void staticInnerAccessDirect() { @Override public void run() { - Alloc singleton = alloc; + StaticsAlloc singleton = alloc; QueryMethods.queryForAndNotEmpty(singleton); } }; @@ -42,14 +41,14 @@ public void run() { @TestMethod public void simpleWithAssign() { - alloc = new Alloc(); + alloc = new StaticsAlloc(); Object b = alloc; QueryMethods.queryFor(b); } @TestMethod public void simpleWithAssign2() { - alloc = new Alloc(); + alloc = new StaticsAlloc(); Object b = alloc; Object a = alloc; QueryMethods.queryFor(b); diff --git a/boomerangPDS/src/test/java/test/cases/statics/SingletonTarget.java b/boomerangPDS/src/test/java/test/cases/statics/SingletonTarget.java index 1e12acd04..e2c8f1618 100644 --- a/boomerangPDS/src/test/java/test/cases/statics/SingletonTarget.java +++ b/boomerangPDS/src/test/java/test/cases/statics/SingletonTarget.java @@ -12,58 +12,57 @@ package test.cases.statics; import test.TestMethod; -import test.cases.fields.Alloc; import test.core.QueryMethods; @SuppressWarnings("unused") public class SingletonTarget { - private static Alloc instance; + private static StaticsAlloc instance; @TestMethod public void doubleSingleton() { - Alloc singleton = i(); + StaticsAlloc singleton = i(); Object alias = singleton; QueryMethods.queryFor(alias); } @TestMethod public void doubleSingletonDirect() { - Alloc singleton = objectGetter.getG(); + StaticsAlloc singleton = objectGetter.getG(); Object alias = singleton; QueryMethods.queryFor(alias); } @TestMethod public void singletonDirect() { - Alloc singleton = alloc; + StaticsAlloc singleton = alloc; QueryMethods.queryFor(singleton); } - public static Alloc i() { + public static StaticsAlloc i() { GlobalObjectGetter getter = objectGetter; - Alloc allocation = getter.getG(); + StaticsAlloc allocation = getter.getG(); return allocation; } public interface GlobalObjectGetter { - Alloc getG(); + StaticsAlloc getG(); void reset(); } - private static Alloc alloc; + private static StaticsAlloc alloc; private static final GlobalObjectGetter objectGetter = new GlobalObjectGetter() { - Alloc instance = new Alloc(); + StaticsAlloc instance = new StaticsAlloc(); - public Alloc getG() { + public StaticsAlloc getG() { return instance; } public void reset() { - instance = new Alloc(); + instance = new StaticsAlloc(); } }; } diff --git a/boomerangPDS/src/test/java/test/cases/statics/StaticFieldFlowsTarget.java b/boomerangPDS/src/test/java/test/cases/statics/StaticFieldFlowsTarget.java index b4a599126..204662af6 100644 --- a/boomerangPDS/src/test/java/test/cases/statics/StaticFieldFlowsTarget.java +++ b/boomerangPDS/src/test/java/test/cases/statics/StaticFieldFlowsTarget.java @@ -12,26 +12,25 @@ package test.cases.statics; import test.TestMethod; -import test.cases.fields.Alloc; import test.core.QueryMethods; @SuppressWarnings("unused") public class StaticFieldFlowsTarget { private static Object alloc; - private static Alloc instance; - private static Alloc i; + private static StaticsAlloc instance; + private static StaticsAlloc i; @TestMethod public void simple() { - alloc = new Alloc(); + alloc = new StaticsAlloc(); Object alias = alloc; QueryMethods.queryFor(alias); } @TestMethod public void simple2() { - alloc = new Alloc(); + alloc = new StaticsAlloc(); Object sr = new Object(); Object r = new String(); QueryMethods.queryFor(alloc); @@ -39,7 +38,7 @@ public void simple2() { @TestMethod public void withCallInbetween() { - alloc = new Alloc(); + alloc = new StaticsAlloc(); alloc.toString(); foo(); QueryMethods.queryFor(alloc); @@ -49,7 +48,7 @@ private void foo() {} @TestMethod public void singleton() { - Alloc singleton = v(); + StaticsAlloc singleton = v(); Object alias = singleton; QueryMethods.queryFor(alias); } @@ -66,30 +65,30 @@ private Object getStatic() { } private void setStatic() { - i = new Alloc(); + i = new StaticsAlloc(); } @TestMethod public void doubleUnbalancedSingleton() { - Alloc singleton = returns(); + StaticsAlloc singleton = returns(); Object alias = singleton; QueryMethods.queryFor(alias); } - private static Alloc returns() { + private static StaticsAlloc returns() { return v(); } - private static Alloc v() { - if (instance == null) instance = new Alloc(); - Alloc loaded = instance; + private static StaticsAlloc v() { + if (instance == null) instance = new StaticsAlloc(); + StaticsAlloc loaded = instance; return loaded; } @TestMethod public void overwriteStatic() { alloc = new Object(); - alloc = new Alloc(); + alloc = new StaticsAlloc(); Object alias = alloc; QueryMethods.queryFor(alias); } @@ -112,7 +111,7 @@ private int irrelevantFlow() { } private void update() { - alloc = new Alloc(); + alloc = new StaticsAlloc(); } @TestMethod @@ -123,6 +122,6 @@ public void intraprocedural() { } private void setStaticField() { - alloc = new Alloc(); + alloc = new StaticsAlloc(); } } diff --git a/boomerangPDS/src/test/java/test/cases/statics/StaticInitializerTarget.java b/boomerangPDS/src/test/java/test/cases/statics/StaticInitializerTarget.java index dd2069167..0f1f9f067 100644 --- a/boomerangPDS/src/test/java/test/cases/statics/StaticInitializerTarget.java +++ b/boomerangPDS/src/test/java/test/cases/statics/StaticInitializerTarget.java @@ -12,13 +12,12 @@ package test.cases.statics; import test.TestMethod; -import test.cases.fields.Alloc; import test.core.QueryMethods; @SuppressWarnings("unused") public class StaticInitializerTarget { - private static final Object alloc = new Alloc(); + private static final Object alloc = new StaticsAlloc(); @TestMethod public void doubleSingleton() { diff --git a/boomerangPDS/src/test/java/test/cases/statics/StaticWithSuperClassesTarget.java b/boomerangPDS/src/test/java/test/cases/statics/StaticWithSuperClassesTarget.java index 2a5bfa29d..c7e636c0e 100644 --- a/boomerangPDS/src/test/java/test/cases/statics/StaticWithSuperClassesTarget.java +++ b/boomerangPDS/src/test/java/test/cases/statics/StaticWithSuperClassesTarget.java @@ -12,7 +12,6 @@ package test.cases.statics; import test.TestMethod; -import test.cases.fields.Alloc; import test.core.QueryMethods; @SuppressWarnings("unused") @@ -27,7 +26,7 @@ public void simple() { private static class List { - private static final Object elementData = new Alloc(); + private static final Object elementData = new StaticsAlloc(); public Object get() { return elementData; @@ -43,7 +42,7 @@ public void superClass() { private static class MyList extends List { - private static final Object elementData2 = new Alloc(); + private static final Object elementData2 = new StaticsAlloc(); public Object get() { return elementData2; diff --git a/boomerangPDS/src/test/java/test/cases/statics/StaticsAlloc.java b/boomerangPDS/src/test/java/test/cases/statics/StaticsAlloc.java new file mode 100644 index 000000000..e9ba28c0d --- /dev/null +++ b/boomerangPDS/src/test/java/test/cases/statics/StaticsAlloc.java @@ -0,0 +1,16 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ +package test.cases.statics; + +import test.core.selfrunning.AllocatedObject; + +public class StaticsAlloc implements AllocatedObject {} diff --git a/boomerangPDS/src/test/java/test/cases/string/StringTest.java b/boomerangPDS/src/test/java/test/cases/string/StringTest.java index f041a21e4..262c6c106 100644 --- a/boomerangPDS/src/test/java/test/cases/string/StringTest.java +++ b/boomerangPDS/src/test/java/test/cases/string/StringTest.java @@ -20,7 +20,7 @@ public class StringTest extends AbstractBoomerangTest { @Test public void stringConcat() { - analyze(target, testName.getMethodName()); + analyze(target, testName.getMethodName(), true); } @Test @@ -35,16 +35,16 @@ public void stringBufferQueryByPass() { @Test public void stringToCharArray() { - analyze(target, testName.getMethodName()); + analyze(target, testName.getMethodName(), true); } @Test public void stringBuilderTest() { - analyze(target, testName.getMethodName()); + analyze(target, testName.getMethodName(), true); } @Test public void stringBuilder1Test() { - analyze(target, testName.getMethodName()); + analyze(target, testName.getMethodName(), true); } } diff --git a/boomerangPDS/src/test/java/test/cases/subclassing/InnerClassTarget.java b/boomerangPDS/src/test/java/test/cases/subclassing/InnerClassTarget.java index 194f9443e..46d3c1712 100644 --- a/boomerangPDS/src/test/java/test/cases/subclassing/InnerClassTarget.java +++ b/boomerangPDS/src/test/java/test/cases/subclassing/InnerClassTarget.java @@ -12,7 +12,6 @@ package test.cases.subclassing; import test.TestMethod; -import test.cases.fields.Alloc; import test.core.QueryMethods; import test.core.selfrunning.AllocatedObject; @@ -20,7 +19,7 @@ public class InnerClassTarget { public static class Instance { - public Object o = new Alloc(); + public Object o = new SubclassingAlloc(); public class Inner { public Object getOuter() { diff --git a/boomerangPDS/src/test/java/test/cases/subclassing/SubclassingAlloc.java b/boomerangPDS/src/test/java/test/cases/subclassing/SubclassingAlloc.java new file mode 100644 index 000000000..eee514046 --- /dev/null +++ b/boomerangPDS/src/test/java/test/cases/subclassing/SubclassingAlloc.java @@ -0,0 +1,16 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ +package test.cases.subclassing; + +import test.core.selfrunning.AllocatedObject; + +public class SubclassingAlloc implements AllocatedObject {} diff --git a/boomerangPDS/src/test/java/test/cases/synchronizd/BlockTarget.java b/boomerangPDS/src/test/java/test/cases/synchronizd/BlockTarget.java index 25128a842..ed77bd674 100644 --- a/boomerangPDS/src/test/java/test/cases/synchronizd/BlockTarget.java +++ b/boomerangPDS/src/test/java/test/cases/synchronizd/BlockTarget.java @@ -12,7 +12,6 @@ package test.cases.synchronizd; import test.TestMethod; -import test.cases.fields.Alloc; import test.core.QueryMethods; import test.core.selfrunning.AllocatedObject; @@ -24,7 +23,7 @@ public class BlockTarget { @TestMethod public void block() { synchronized (field) { - AllocatedObject o = new Alloc(); + AllocatedObject o = new SynchronizedAlloc(); QueryMethods.queryFor(o); } } @@ -40,7 +39,7 @@ public void block2() { private void set() { synchronized (field) { - field = new Alloc(); + field = new SynchronizedAlloc(); } } } diff --git a/boomerangPDS/src/test/java/test/cases/synchronizd/SynchronizedAlloc.java b/boomerangPDS/src/test/java/test/cases/synchronizd/SynchronizedAlloc.java new file mode 100644 index 000000000..3b71ea988 --- /dev/null +++ b/boomerangPDS/src/test/java/test/cases/synchronizd/SynchronizedAlloc.java @@ -0,0 +1,16 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ +package test.cases.synchronizd; + +import test.core.selfrunning.AllocatedObject; + +public class SynchronizedAlloc implements AllocatedObject {} diff --git a/boomerangPDS/src/test/java/test/cases/threading/InnerClassWithThreadTarget.java b/boomerangPDS/src/test/java/test/cases/threading/InnerClassWithThreadTarget.java index 3ad1b6779..f044651e3 100644 --- a/boomerangPDS/src/test/java/test/cases/threading/InnerClassWithThreadTarget.java +++ b/boomerangPDS/src/test/java/test/cases/threading/InnerClassWithThreadTarget.java @@ -12,18 +12,17 @@ package test.cases.threading; import test.TestMethod; -import test.cases.fields.Alloc; import test.core.QueryMethods; import test.core.selfrunning.AllocatedObject; @SuppressWarnings("unused") public class InnerClassWithThreadTarget { - private static Alloc param; + private static ThreadingAlloc param; @TestMethod public void runWithThreadStatic() { - param = new Alloc(); + param = new ThreadingAlloc(); Runnable r = new Runnable() { @@ -46,7 +45,7 @@ public void run() { @TestMethod public void runWithThread() { - final Alloc u = new Alloc(); + final ThreadingAlloc u = new ThreadingAlloc(); Runnable r = new Runnable() { diff --git a/boomerangPDS/src/test/java/test/cases/threading/ThreadingAlloc.java b/boomerangPDS/src/test/java/test/cases/threading/ThreadingAlloc.java new file mode 100644 index 000000000..b80869ad5 --- /dev/null +++ b/boomerangPDS/src/test/java/test/cases/threading/ThreadingAlloc.java @@ -0,0 +1,16 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ +package test.cases.threading; + +import test.core.selfrunning.AllocatedObject; + +public class ThreadingAlloc implements AllocatedObject {} diff --git a/boomerangPDS/src/test/java/test/cases/unbalanced/UnbalancedAlloc.java b/boomerangPDS/src/test/java/test/cases/unbalanced/UnbalancedAlloc.java new file mode 100644 index 000000000..ffc25967a --- /dev/null +++ b/boomerangPDS/src/test/java/test/cases/unbalanced/UnbalancedAlloc.java @@ -0,0 +1,16 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ +package test.cases.unbalanced; + +import test.core.selfrunning.AllocatedObject; + +public class UnbalancedAlloc implements AllocatedObject {} diff --git a/boomerangPDS/src/test/java/test/cases/unbalanced/UnbalancedScopesTarget.java b/boomerangPDS/src/test/java/test/cases/unbalanced/UnbalancedScopesTarget.java index 54525999a..379f477c7 100644 --- a/boomerangPDS/src/test/java/test/cases/unbalanced/UnbalancedScopesTarget.java +++ b/boomerangPDS/src/test/java/test/cases/unbalanced/UnbalancedScopesTarget.java @@ -12,7 +12,6 @@ package test.cases.unbalanced; import test.TestMethod; -import test.cases.fields.Alloc; import test.cases.fields.B; import test.core.QueryMethods; @@ -57,7 +56,7 @@ public void summaryReuse() { } private Object createA() { - Alloc c = new Alloc(); + UnbalancedAlloc c = new UnbalancedAlloc(); Object d = id(c); return d; } @@ -68,7 +67,7 @@ private Object id(Object c) { private Object aOrB() { if (staticallyUnknown()) { - return new Alloc(); + return new UnbalancedAlloc(); } return new B(); } @@ -84,6 +83,6 @@ private void inner(Object inner) { } private Object create() { - return new Alloc(); + return new UnbalancedAlloc(); } } diff --git a/boomerangPDS/src/test/java/test/core/AbstractBoomerangTest.java b/boomerangPDS/src/test/java/test/core/AbstractBoomerangTest.java index 9061dd4ee..b0a5d16bc 100644 --- a/boomerangPDS/src/test/java/test/core/AbstractBoomerangTest.java +++ b/boomerangPDS/src/test/java/test/core/AbstractBoomerangTest.java @@ -104,18 +104,27 @@ public int getIterations() { } protected void analyze(String targetClassName, String targetMethodName) { - analyze(targetClassName, targetMethodName, DataFlowScope.EXCLUDE_PHANTOM_CLASSES); + analyze(targetClassName, targetMethodName, DataFlowScope.EXCLUDE_PHANTOM_CLASSES, false); } protected void analyze( - String targetClassName, String targetMethodName, DataFlowScope dataFlowScope) { + String targetClassName, String targetMethodName, boolean ignoreAllocSites) { + analyze( + targetClassName, targetMethodName, DataFlowScope.EXCLUDE_PHANTOM_CLASSES, ignoreAllocSites); + } + + protected void analyze( + String targetClassName, + String targetMethodName, + DataFlowScope dataFlowScope, + boolean ignoreAllocSites) { MethodWrapper methodWrapper = new MethodWrapper(targetClassName, targetMethodName); FrameworkScope frameworkScope = super.getFrameworkScope(methodWrapper, dataFlowScope); - analyzeWithCallGraph(frameworkScope); + analyzeWithCallGraph(frameworkScope, ignoreAllocSites); } - private void analyzeWithCallGraph(FrameworkScope frameworkScope) { + private void analyzeWithCallGraph(FrameworkScope frameworkScope, boolean ignoreAllocSites) { CallGraph callGraph = frameworkScope.getCallGraph(); queryDetector = new QueryForCallSiteDetector(callGraph); queryForCallSites = queryDetector.computeSeeds(); @@ -123,10 +132,16 @@ private void analyzeWithCallGraph(FrameworkScope frameworkScope) { if (queryDetector.integerQueries) { Preanalysis an = new Preanalysis(callGraph, new IntegerAllocationSiteOf()); expectedAllocationSites = an.computeSeeds(); + if (expectedAllocationSites.isEmpty() && !ignoreAllocSites) { + Assert.fail("Did not find any allocation sites. Nothing is tested"); + } } else { Preanalysis an = new Preanalysis(callGraph, new AllocationSiteOf(AllocatedObject.class.getName())); expectedAllocationSites = an.computeSeeds(); + if (expectedAllocationSites.isEmpty() && !ignoreAllocSites) { + Assert.fail("Did not find any allocation sites. Nothing is tested"); + } an = new Preanalysis(callGraph, new AllocationSiteOf(NoAllocatedObject.class.getName())); explicitlyUnexpectedAllocationSites = an.computeSeeds().stream().map(Query::asNode).collect(Collectors.toList()); diff --git a/testCore/src/main/java/test/setup/OpalTestSetup.java b/testCore/src/main/java/test/setup/OpalTestSetup.java index 2172b73c0..d3866a185 100644 --- a/testCore/src/main/java/test/setup/OpalTestSetup.java +++ b/testCore/src/main/java/test/setup/OpalTestSetup.java @@ -79,14 +79,13 @@ public void initialize( List excludedPackages) { OPALLogger.updateLogger(GlobalLogContext$.MODULE$, DevNullLogger$.MODULE$); - File[] classpathFiles = loadClassPathFiles(classPath, excludedPackages); + File[] classpathFiles = + loadClassPathFiles(classPath, methodWrapper.getDeclaringClass(), excludedPackages); File[] includeFiles = loadJDKFiles(includedPackages); File[] classFiles = Stream.concat(Arrays.stream(classpathFiles), Arrays.stream(includeFiles)) .toArray(File[]::new); project = Project.apply(classFiles, new File[0]); // , package$.MODULE$.RTJar()); - scala.collection.Iterable files = - project.allClassFiles(); // .filter(c -> c.thisType().fqn().contains("java.util")); // Load the class that contains the test method Option testClass = @@ -164,28 +163,32 @@ public FrameworkScope createFrameworkScope(DataFlowScope dataFlowScope) { dataFlowScope); } - private File[] loadClassPathFiles(String classpath, List excludeList) { + private File[] loadClassPathFiles( + String classpath, String testClassName, List excludeList) { Path path = Path.of(classpath); try (Stream stream = Files.walk(path)) { Stream classPathFiles = stream.filter(Files::isRegularFile).map(Path::toFile); - // Filter for excluded classes + // Filter for excluded classes. Additionally, exclude all classes from different packages + // because CHA in Opal would add edges to methods from other classes + String packageName = testClassName.substring(0, testClassName.lastIndexOf(".")); return classPathFiles - .filter(c -> !isExcludedFile(c, classpath, excludeList)) + .filter(c -> !isExcludedFile(c, classpath, packageName, excludeList)) .toArray(File[]::new); } catch (IOException e) { throw new RuntimeException("Could not read classpath: " + e.getMessage()); } } - private boolean isExcludedFile(File file, String classpath, List excludeList) { + private boolean isExcludedFile( + File file, String classpath, String packageName, List excludeList) { // Remove the classpath and the .class ending String path = file.getPath().replace("/", ".").replace("\\", "."); String formattedClassPath = classpath.replace("/", ".").replace("\\", "."); String formattedPath = path.replace(formattedClassPath, "").replace(".class", "").substring(1); - return excludeList.contains(formattedPath); + return !formattedPath.startsWith(packageName) || excludeList.contains(formattedPath); } private File[] loadJDKFiles(List includeList) { From fe4fc2674cc1993c20fcf761645ba5b884319b0d Mon Sep 17 00:00:00 2001 From: Sven Meyer Date: Sat, 19 Apr 2025 12:49:16 +0200 Subject: [PATCH 47/61] Final fixes for static field refs --- .../fields/complexity/Fields20LongTest.java | 2 - .../scope/opal/tac/OpalInstanceFieldRef.scala | 2 +- .../scope/opal/tac/OpalStatement.scala | 30 +++++++- .../scope/opal/tac/OpalStaticFieldRef.scala | 76 +++++++++++++++++++ .../transformer/NopTransformer.scala | 15 +++- .../TypeStateMachineWeightFunctions.java | 6 +- .../typestate/tests/InputStreamLongTest.java | 6 -- 7 files changed, 121 insertions(+), 16 deletions(-) create mode 100644 boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStaticFieldRef.scala diff --git a/boomerangPDS/src/test/java/test/cases/fields/complexity/Fields20LongTest.java b/boomerangPDS/src/test/java/test/cases/fields/complexity/Fields20LongTest.java index 4b6ff85a8..16d261472 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/complexity/Fields20LongTest.java +++ b/boomerangPDS/src/test/java/test/cases/fields/complexity/Fields20LongTest.java @@ -11,11 +11,9 @@ */ package test.cases.fields.complexity; -import org.junit.Ignore; import org.junit.Test; import test.core.AbstractBoomerangTest; -@Ignore("Takes too long") public class Fields20LongTest extends AbstractBoomerangTest { private final String target = Fields20LongTarget.class.getName(); diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalInstanceFieldRef.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalInstanceFieldRef.scala index 51056f37e..aca96f720 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalInstanceFieldRef.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalInstanceFieldRef.scala @@ -65,7 +65,7 @@ class OpalInstanceFieldRef(val base: TacLocal, val fieldType: org.opalj.br.Type, override def getVariableName: String = s"$base.$fieldName" - override def hashCode: Int = Objects.hash(base, fieldType, fieldName) + override def hashCode: Int = Objects.hash(super.hashCode(), base, fieldType, fieldName) override def equals(other: Any): Boolean = other match { case that: OpalInstanceFieldRef => super.equals(other) && this.base == that.base && this.fieldType == that.fieldType && this.fieldName == that.fieldName diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala index 124a48378..e97ee21dc 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala @@ -100,6 +100,7 @@ class OpalStatement(val delegate: Stmt[TacLocal], m: OpalMethod) extends Stateme * - Opal considers these statements as basic assignments, so we have to exclude them manually */ if (expr.asVar.isParameterLocal) return false + if (expr.asVar.isExceptionLocal) return false if (targetVar.isThisLocal && expr.asVar.isThisLocal) return false return true @@ -108,8 +109,7 @@ class OpalStatement(val delegate: Stmt[TacLocal], m: OpalMethod) extends Stateme } } - // TODO Add static field store - isFieldStore || isArrayStore + isFieldStore || isArrayStore || isStaticFieldStore } override def getLeftOp: Val = { @@ -134,6 +134,12 @@ class OpalStatement(val delegate: Stmt[TacLocal], m: OpalMethod) extends Stateme return new OpalArrayRef(base.asVar, -1, m) } + + if (isStaticFieldStore) { + val staticFieldStore = delegate.asPutStatic + + return new OpalStaticFieldRef(staticFieldStore.declaringClass, staticFieldStore.declaredFieldType, staticFieldStore.name, m) + } } throw new RuntimeException("Statement is not an assignment") @@ -161,6 +167,12 @@ class OpalStatement(val delegate: Stmt[TacLocal], m: OpalMethod) extends Stateme return new OpalArrayRef(base.asVar, -1, m) } + if (rightExpr.isGetStatic) { + val staticFieldLoad = rightExpr.asGetStatic + + return new OpalStaticFieldRef(staticFieldLoad.declaringClass, staticFieldLoad.declaredFieldType, staticFieldLoad.name, m) + } + if (rightExpr.isVar) { return new OpalLocal(rightExpr.asVar, m) } @@ -172,9 +184,9 @@ class OpalStatement(val delegate: Stmt[TacLocal], m: OpalMethod) extends Stateme val fieldStore = delegate.asPutField if (fieldStore.value.isVar) { - return new OpalLocal(delegate.asPutField.value.asVar, m) + return new OpalLocal(fieldStore.value.asVar, m) } else { - return new OpalVal(delegate.asPutField.value, m) + return new OpalVal(fieldStore.value, m) } } @@ -187,6 +199,16 @@ class OpalStatement(val delegate: Stmt[TacLocal], m: OpalMethod) extends Stateme return new OpalVal(arrayStore.value, m) } } + + if (isStaticFieldStore) { + val staticFieldStore = delegate.asPutStatic + + if (staticFieldStore.value.isVar) { + return new OpalLocal(staticFieldStore.value.asVar, m) + } else { + return new OpalVal(staticFieldStore.value, m) + } + } } throw new RuntimeException("Statement is not an assignment") diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStaticFieldRef.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStaticFieldRef.scala new file mode 100644 index 000000000..23b96dd7c --- /dev/null +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStaticFieldRef.scala @@ -0,0 +1,76 @@ +package boomerang.scope.opal.tac + +import boomerang.scope.{ControlFlowGraph, Method, Pair, Type, Val} +import org.opalj.br.ObjectType + +import java.util.Objects + +class OpalStaticFieldRef(val declaringClass: ObjectType, val fieldType: org.opalj.br.Type, val fieldName: String, method: OpalMethod, unbalanced: ControlFlowGraph.Edge = null) extends Val(method, unbalanced) { + + override def getType: Type = OpalType(fieldType) + + override def isStatic: Boolean = true + + override def isNewExpr: Boolean = false + + override def getNewExprType: Type = throw new RuntimeException("Static field ref is not a new expression") + + override def asUnbalanced(stmt: ControlFlowGraph.Edge): Val = new OpalStaticFieldRef(declaringClass, fieldType, fieldName, method, stmt) + + override def isLocal: Boolean = false + + override def isArrayAllocationVal: Boolean = false + + override def getArrayAllocationSize: Val = throw new RuntimeException("Static field ref is not an array allocation site") + + override def isNull: Boolean = false + + override def isStringConstant: Boolean = false + + override def getStringValue: String = throw new RuntimeException("Static field ref is not a String constant") + + override def isStringBufferOrBuilder: Boolean = false + + override def isThrowableAllocationType: Boolean = false + + override def isCast: Boolean = false + + override def getCastOp: Val = throw new RuntimeException("Static field ref is not a cast expression") + + override def isArrayRef: Boolean = false + + override def isInstanceOfExpr: Boolean = false + + override def getInstanceOfOp: Val = throw new RuntimeException("Static field ref is not an instanceOf expression") + + override def isLengthExpr: Boolean = false + + override def getLengthOp: Val = throw new RuntimeException("Static field ref is not a length expression") + + override def isIntConstant: Boolean = false + + override def isClassConstant: Boolean = false + + override def getClassConstantType: Type = throw new RuntimeException("Static field ref is not a class constant") + + override def withNewMethod(callee: Method): Val = new OpalStaticFieldRef(declaringClass, fieldType, fieldName, callee.asInstanceOf[OpalMethod]) + + override def isLongConstant: Boolean = false + + override def getIntValue: Int = throw new RuntimeException("Static field ref is not an int constant") + + override def getLongValue: Long = throw new RuntimeException("Static field ref is not a long constant") + + override def getArrayBase: Pair[Val, Integer] = throw new RuntimeException("Static field ref has no array base") + + override def getVariableName: String = fieldName + + override def hashCode: Int = Objects.hash(super.hashCode(), declaringClass, fieldType, fieldName) + + override def equals(other: Any): Boolean = other match { + case that: OpalStaticFieldRef => super.equals(that) && this.declaringClass == that.declaringClass && this.fieldType == that.fieldType && this.fieldName == that.fieldName + case _ => false + } + + override def toString: String = s"${declaringClass.toJava}.$fieldName" +} diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/NopTransformer.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/NopTransformer.scala index 6a9f5ad77..0f96fc968 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/NopTransformer.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/NopTransformer.scala @@ -28,8 +28,19 @@ object NopTransformer { val nextStmt = tac(stmt._2 + 1) val targetStmt = tac(stmt._1.asIf.targetStmt) - result = result.insertBefore(Nop(-nextStmt.pc), nextStmt) - result = result.insertBefore(Nop(-targetStmt.pc), targetStmt) + /* If one or multiple branches target the same statement, we add exactly one Nop statement + * before the target statement (represented by the negative pc). This way, important + * data flows are covered + */ + val nextStmtNop = Nop(-nextStmt.pc) + if (!result.statements.contains(nextStmtNop)) { + result = result.insertBefore(nextStmtNop, nextStmt) + } + + val targetStmtNop = Nop(-targetStmt.pc) + if (!result.statements.contains(targetStmtNop)) { + result = result.insertBefore(targetStmtNop, targetStmt) + } } }) diff --git a/idealPDS/src/main/java/typestate/finiteautomata/TypeStateMachineWeightFunctions.java b/idealPDS/src/main/java/typestate/finiteautomata/TypeStateMachineWeightFunctions.java index c05d92eaa..734ae0af0 100644 --- a/idealPDS/src/main/java/typestate/finiteautomata/TypeStateMachineWeightFunctions.java +++ b/idealPDS/src/main/java/typestate/finiteautomata/TypeStateMachineWeightFunctions.java @@ -170,7 +170,11 @@ public Collection> generateThisAtAnyCal if (unit.containsInvokeExpr()) { if (unit.getInvokeExpr().isInstanceInvokeExpr()) { Val base = unit.getInvokeExpr().getBase(); - if (unit.getInvokeExpr().getDeclaredMethod().getSignature().matches(declaredMethod)) { + // TODO + // Soot, SootUp and Opal use different signatures. Hence, we should move away from + // using basic pattern matching to identify correct methods + String sig = " " + unit.getInvokeExpr().getDeclaredMethod().getName(); + if (sig.matches(declaredMethod)) { if (base.getType().isSubtypeOf(declaredType)) { return Collections.singleton( new WeightedForwardQuery<>( diff --git a/idealPDS/src/test/java/typestate/tests/InputStreamLongTest.java b/idealPDS/src/test/java/typestate/tests/InputStreamLongTest.java index 7e4590c80..a4aa7a755 100644 --- a/idealPDS/src/test/java/typestate/tests/InputStreamLongTest.java +++ b/idealPDS/src/test/java/typestate/tests/InputStreamLongTest.java @@ -11,7 +11,6 @@ */ package typestate.tests; -import java.util.ArrayList; import java.util.List; import org.junit.Test; import test.IDEALTestingFramework; @@ -33,11 +32,6 @@ protected List getIncludedPackages() { return List.of("java.io.FileInputStream"); } - @Override - protected List getExcludedPackages() { - return new ArrayList<>(); - } - @Test public void test1() { analyze(target, testName.getMethodName(), 1, 1); From 9850e777d1391b3fadd2d5b382088ab456e2db25 Mon Sep 17 00:00:00 2001 From: Sven Meyer Date: Mon, 21 Apr 2025 20:19:55 +0200 Subject: [PATCH 48/61] Clean up opal tests and transformers --- .../opal/transformation/TacBodyBuilder.scala | 11 +- .../transformer/NopEliminator.scala | 20 +++ .../transformer/NopTransformer.scala | 41 +++---- .../NullifyFieldsTransformer.scala | 3 +- .../boomerang/scope/opal/OpalArrayTest.scala | 30 ++--- .../scope/opal/OpalAssignmentTest.scala | 34 +++++- .../scope/opal/OpalInvokeExprTest.scala | 6 +- .../boomerang/scope/opal/OpalLocalTest.scala | 114 +----------------- .../boomerang/scope/soot/SootArrayTest.java | 4 +- .../scope/test/targets/ArrayTarget.java | 25 ++-- .../scope/test/targets/AssignmentTarget.java | 8 ++ 11 files changed, 106 insertions(+), 190 deletions(-) create mode 100644 boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/NopEliminator.scala diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacBodyBuilder.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacBodyBuilder.scala index 6675fdd7e..fe0651506 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacBodyBuilder.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacBodyBuilder.scala @@ -1,7 +1,7 @@ package boomerang.scope.opal.transformation import boomerang.scope.opal.transformation.stack.OperandStackBuilder -import boomerang.scope.opal.transformation.transformer.{InlineLocalTransformer, LocalPropagationTransformer, LocalTransformer, NopTransformer, NullifyFieldsTransformer} +import boomerang.scope.opal.transformation.transformer.{InlineLocalTransformer, LocalPropagationTransformer, LocalTransformer, NopEliminator, NopTransformer, NullifyFieldsTransformer} import org.opalj.ai.domain.l0.PrimitiveTACAIDomain import org.opalj.br.Method import org.opalj.br.analyses.Project @@ -37,11 +37,12 @@ object TacBodyBuilder { val tacCfg = cfg.get.mapPCsToIndexes[Stmt[TacLocal], TACStmts[TacLocal]](TACStmts(propagatedTac), tacNaive.pcToIndex, i => i, propagatedTac.length) val exceptionHandlers = tacNaive.exceptionHandlers.map(eh => eh.handlerPC).toArray - val stmtGraph = StmtGraph(propagatedTac, tacCfg, tacNaive.pcToIndex, exceptionHandlers) + var stmtGraph = StmtGraph(propagatedTac, tacCfg, tacNaive.pcToIndex, exceptionHandlers) - val nopStmtGraph = NopTransformer(stmtGraph) - val nullifiedStmtGraph = NullifyFieldsTransformer(method, nopStmtGraph) + stmtGraph = NopTransformer(stmtGraph) + stmtGraph = NullifyFieldsTransformer(method, stmtGraph) + stmtGraph = NopEliminator(stmtGraph) - new BoomerangTACode(nullifiedStmtGraph) + new BoomerangTACode(stmtGraph) } } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/NopEliminator.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/NopEliminator.scala new file mode 100644 index 000000000..b839e9c15 --- /dev/null +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/NopEliminator.scala @@ -0,0 +1,20 @@ +package boomerang.scope.opal.transformation.transformer + +import boomerang.scope.opal.transformation.StmtGraph +import org.opalj.tac.Nop + +object NopEliminator { + + def apply(stmtGraph: StmtGraph): StmtGraph = { + + def removeNopStatements(stmtGraph: StmtGraph): StmtGraph = { + val nopStatements = stmtGraph.statements.filter(s => s.astID == Nop.ASTID && s.pc >= 0) + var result = stmtGraph + + nopStatements.foreach(stmt => result = result.remove(stmt)) + result + } + + removeNopStatements(stmtGraph) + } +} diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/NopTransformer.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/NopTransformer.scala index 0f96fc968..8cec83803 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/NopTransformer.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/NopTransformer.scala @@ -1,7 +1,7 @@ package boomerang.scope.opal.transformation.transformer -import boomerang.scope.opal.transformation.StmtGraph -import org.opalj.tac.{If, Nop} +import boomerang.scope.opal.transformation.{StmtGraph, TacLocal} +import org.opalj.tac.{If, Nop, Stmt} object NopTransformer { @@ -10,45 +10,36 @@ object NopTransformer { def apply(stmtGraph: StmtGraph): StmtGraph = { val tac = stmtGraph.tac - def removeNopStatements(stmtGraph: StmtGraph): Unit = { - tac.foreach(stmt => { - if (stmt.astID == Nop.ASTID) { - stmtGraph.remove(stmt) - } - }) - } - def addNopStatements(stmtGraph: StmtGraph): StmtGraph = { // Add a nop statement in the beginning val nop = Nop(INITIAL_NOP) var result = stmtGraph.insertBefore(nop, stmtGraph.heads.head) + var beforeStmtInsert = List.empty[Stmt[TacLocal]] tac.zipWithIndex.foreach(stmt => { + // TODO Switch statements if (stmt._1.astID == If.ASTID) { val nextStmt = tac(stmt._2 + 1) val targetStmt = tac(stmt._1.asIf.targetStmt) - /* If one or multiple branches target the same statement, we add exactly one Nop statement - * before the target statement (represented by the negative pc). This way, important - * data flows are covered - */ - val nextStmtNop = Nop(-nextStmt.pc) - if (!result.statements.contains(nextStmtNop)) { - result = result.insertBefore(nextStmtNop, nextStmt) - } - - val targetStmtNop = Nop(-targetStmt.pc) - if (!result.statements.contains(targetStmtNop)) { - result = result.insertBefore(targetStmtNop, targetStmt) - } + beforeStmtInsert = beforeStmtInsert ++ List(nextStmt, targetStmt) + } + }) + + beforeStmtInsert.foreach(stmt => { + /* If one or multiple branches target the same statement, we add exactly one Nop statement + * before the target statement (represented by the negative pc). This way, important + * data flows are covered + */ + val nextStmtNop = Nop(-stmt.pc) + if (!result.statements.contains(nextStmtNop)) { + result = result.insertBefore(nextStmtNop, stmt) } }) result } - // TODO Remove NOPs before inserting them - // removeNopStatements(stmtGraph) addNopStatements(stmtGraph) } } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/NullifyFieldsTransformer.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/NullifyFieldsTransformer.scala index a3663908e..39a13753e 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/NullifyFieldsTransformer.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/NullifyFieldsTransformer.scala @@ -6,7 +6,7 @@ import org.opalj.tac.{Assignment, Expr, NullExpr, PutField} object NullifyFieldsTransformer { - final val NULLIFIED_FIELD = -2 + private final val NULLIFIED_FIELD = -2 def apply(method: Method, stmtGraph: StmtGraph): StmtGraph = { if (!method.isConstructor || method.isStatic) { @@ -53,7 +53,6 @@ object NullifyFieldsTransformer { result = result.insertBefore(defSite, firstOriginalStmt) result = result.insertBefore(putField, firstOriginalStmt) - }) result diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalArrayTest.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalArrayTest.scala index 79ece7c5e..710def675 100644 --- a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalArrayTest.scala +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalArrayTest.scala @@ -8,17 +8,16 @@ import org.opalj.br.IntegerType import java.util -@Ignore class OpalArrayTest { private val integerType = IntegerType.toJVMTypeName @Test - def singleArrayLoadIndexTest(): Unit = { + def arrayLoadIndexTest(): Unit = { val opalSetup = new OpalSetup() opalSetup.setupOpal(classOf[ArrayTarget].getName) - val signature = new MethodSignature(classOf[ArrayTarget].getName, "singleArrayIndexLoad", "Void", util.List.of("[" + integerType)) + val signature = new MethodSignature(classOf[ArrayTarget].getName, "arrayIndexLoad", "V", util.List.of("[" + integerType)) val method = opalSetup.resolveMethod(signature) val opalMethod = OpalMethod(method) @@ -41,11 +40,11 @@ class OpalArrayTest { } @Test - def singleArrayLoadVarTest(): Unit = { + def arrayLoadVarTest(): Unit = { val opalSetup = new OpalSetup() opalSetup.setupOpal(classOf[ArrayTarget].getName) - val signature = new MethodSignature(classOf[ArrayTarget].getName, "singleArrayVarLoad", "Void", util.List.of("[" + integerType)) + val signature = new MethodSignature(classOf[ArrayTarget].getName, "arrayVarLoad", "V", util.List.of("[" + integerType)) val method = opalSetup.resolveMethod(signature) val opalMethod = OpalMethod(method) @@ -68,11 +67,11 @@ class OpalArrayTest { } @Test - def singleArrayStoreIndexTest(): Unit = { + def arrayStoreIndexTest(): Unit = { val opalSetup = new OpalSetup() opalSetup.setupOpal(classOf[ArrayTarget].getName) - val signature = new MethodSignature(classOf[ArrayTarget].getName, "singleArrayStoreIndex", "Void") + val signature = new MethodSignature(classOf[ArrayTarget].getName, "arrayStoreIndex", "V") val method = opalSetup.resolveMethod(signature) val opalMethod = OpalMethod(method) @@ -95,11 +94,11 @@ class OpalArrayTest { } @Test - def singleArrayStoreVarTest(): Unit = { + def arrayStoreVarTest(): Unit = { val opalSetup = new OpalSetup() opalSetup.setupOpal(classOf[ArrayTarget].getName) - val signature = new MethodSignature(classOf[ArrayTarget].getName, "singleArrayStoreVar", "Void") + val signature = new MethodSignature(classOf[ArrayTarget].getName, "arrayStoreVar", "V") val method = opalSetup.resolveMethod(signature) val opalMethod = OpalMethod(method) @@ -120,17 +119,4 @@ class OpalArrayTest { Assert.assertEquals(1, arrayStoreCount) } - - @Test - def multiArrayStore(): Unit = { - val opalSetup = new OpalSetup() - opalSetup.setupOpal(classOf[ArrayTarget].getName) - - val signature = new MethodSignature(classOf[ArrayTarget].getName, "multiArrayStore", "Void") - val method = opalSetup.resolveMethod(signature) - val opalMethod = OpalMethod(method) - - println(opalMethod.tac.statements.mkString("Array(\n\t", "\n\t", "\n)")) - } - } diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalAssignmentTest.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalAssignmentTest.scala index b54ced889..e3d31ddd9 100644 --- a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalAssignmentTest.scala +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalAssignmentTest.scala @@ -12,7 +12,7 @@ class OpalAssignmentTest { val opalSetup = new OpalSetup() opalSetup.setupOpal(classOf[AssignmentTarget].getName) - val signature = new MethodSignature(classOf[AssignmentTarget].getName, "arrayAllocation", "Void") + val signature = new MethodSignature(classOf[AssignmentTarget].getName, "arrayAllocation", "V") val method = opalSetup.resolveMethod(signature) val opalMethod = OpalMethod(method) @@ -28,7 +28,7 @@ class OpalAssignmentTest { Assert.assertTrue(leftOp.isLocal) Assert.assertTrue(rightOp.getArrayAllocationSize.isIntConstant) - Assert.assertTrue(rightOp.getType.isArrayType) + Assert.assertEquals(2, rightOp.getArrayAllocationSize.getIntValue) } } }) @@ -36,6 +36,36 @@ class OpalAssignmentTest { Assert.assertEquals(1, arrayAllocationCount) } + @Test + def multiArrayAllocationTest(): Unit = { + val opalSetup = new OpalSetup() + opalSetup.setupOpal(classOf[AssignmentTarget].getName) + + val signature = new MethodSignature(classOf[AssignmentTarget].getName, "multiArrayAllocation", "V") + val method = opalSetup.resolveMethod(signature) + val opalMethod = OpalMethod(method) + + var checked = false + opalMethod.getStatements.forEach(stmt => { + if (stmt.isAssignStmt) { + val rightOp = stmt.getRightOp + + if (rightOp.isArrayAllocationVal) { + val leftOp = stmt.getLeftOp + Assert.assertTrue(leftOp.isLocal) + + val arraySize = rightOp.getArrayAllocationSize + Assert.assertTrue(arraySize.isIntConstant) + Assert.assertEquals(2, arraySize.getIntValue) + + checked = true + } + } + }) + + Assert.assertTrue(checked) + } + @Test def constantAssignmentTest(): Unit = { val opalSetup = new OpalSetup() diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala index 6a79eeb8f..fd7b73d1b 100644 --- a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala @@ -2,17 +2,15 @@ package boomerang.scope.opal import boomerang.scope.DataFlowScope import boomerang.scope.opal.tac.OpalMethod -import boomerang.scope.opal.transformation.TacBodyBuilder import boomerang.scope.test.MethodSignature -import boomerang.scope.test.targets.{BranchingTarget, ConstructorTarget, InvokeExprTarget, SingleTarget} -import com.typesafe.config.{Config, ConfigValueFactory} +import boomerang.scope.test.targets.{BranchingTarget, InvokeExprTarget} +import com.typesafe.config.ConfigValueFactory import org.junit.{Assert, Test} import org.opalj.br.analyses.Project import org.opalj.br.analyses.cg.InitialEntryPointsKey import org.opalj.tac.cg.{CHACallGraphKey, CallGraph} import java.util -import java.util.{HashMap, List, Map, Set} import scala.jdk.javaapi.CollectionConverters class OpalInvokeExprTest { diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalLocalTest.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalLocalTest.scala index ce48e67f7..320edca2e 100644 --- a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalLocalTest.scala +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalLocalTest.scala @@ -1,15 +1,13 @@ package boomerang.scope.opal -import boomerang.scope.Statement import boomerang.scope.opal.tac.OpalMethod -import boomerang.scope.test.targets.{A, HashCodeEqualsLocalTarget, LocalCountTarget, ParameterLocalsTarget, ThisLocalTarget} import boomerang.scope.test.MethodSignature -import org.junit.{Assert, Ignore, Test} +import boomerang.scope.test.targets.{A, ParameterLocalsTarget, ThisLocalTarget} +import org.junit.{Assert, Test} import org.opalj.br.IntegerType import java.util -@Ignore class OpalLocalTest { private val integerType = IntegerType.toJVMTypeName @@ -37,31 +35,7 @@ class OpalLocalTest { } }) - if (!checked) { - Assert.fail("Did not check this local") - } - } - - @Test - def localCountTest(): Unit = { - val opalSetup = new OpalSetup() - opalSetup.setupOpal(classOf[LocalCountTarget].getName) - - // Virtual - val virtualSignature = new MethodSignature(classOf[LocalCountTarget].getName, "virtualLocalCount", "Void", util.List.of(integerType, s"L${classOf[A].getName}L")) - val virtualMethod = opalSetup.resolveMethod(virtualSignature) - val virtualOpalMethod = OpalMethod(virtualMethod) - - val locals = virtualOpalMethod.getLocals - Assert.assertEquals(5, locals.size()) - - // Static - val staticSignature = new MethodSignature(classOf[LocalCountTarget].getName, "staticLocalCount", "Void", util.List.of(integerType, s"L${classOf[A].getName}L")) - val staticMethod = opalSetup.resolveMethod(staticSignature) - val staticOpalMethod = OpalMethod(staticMethod) - - val locals2 = staticOpalMethod.getLocals - Assert.assertEquals(4, locals2.size()) + Assert.assertTrue(checked) } @Test @@ -93,86 +67,4 @@ class OpalLocalTest { Assert.assertEquals("int", twoArgsMethod.getParameterLocal(0).getType.toString) Assert.assertEquals(classOf[A].getName, twoArgsMethod.getParameterLocal(1).getType.toString) } - - @Test - def hashCodeEqualsLocalTest(): Unit = { - val opalSetup = new OpalSetup() - opalSetup.setupOpal(classOf[HashCodeEqualsLocalTarget].getName) - - // Parameter locals - val signature = new MethodSignature(classOf[HashCodeEqualsLocalTarget].getName, "parameterCall", "Void", util.List.of(s"L${classOf[A].getName}L", integerType)) - val method = opalSetup.resolveMethod(signature) - val opalMethod = OpalMethod(method) - - val firstArg = opalMethod.getParameterLocal(0) - val secondArg = opalMethod.getParameterLocal(1) - - var checked = false - opalMethod.getStatements.forEach(stmt => { - if (stmt.containsInvokeExpr() && stmt.getInvokeExpr.getDeclaredMethod.getName.equals("methodCall")) { - val invokeExpr = stmt.getInvokeExpr - val base = invokeExpr.getBase - val arg = invokeExpr.getArg(0) - - // equals in both directions - Assert.assertTrue(base.equals(firstArg)) - Assert.assertTrue(firstArg.equals(base)) - - Assert.assertTrue(arg.equals(secondArg)) - Assert.assertTrue(secondArg.equals(arg)) - - // hash codes - Assert.assertEquals(base.hashCode, firstArg.hashCode) - Assert.assertEquals(arg.hashCode, secondArg.hashCode) - - checked = true - } - }) - - if (!checked) { - Assert.fail("Did not checked equals and hashCode methods") - } - - // Defined locals - val signature2 = new MethodSignature(classOf[ParameterLocalsTarget].getName, "definedCall", "Void") - val method2 = opalSetup.resolveMethod(signature2) - val jimpleMethod2 = OpalMethod(method2) - - // Find the definition sites - val refDefStmt = jimpleMethod2.getStatements.stream.filter((stmt: Statement) => stmt.isAssignStmt && stmt.getRightOp.isNewExpr).findFirst - val primDefStmt= jimpleMethod2.getStatements.stream.filter((stmt: Statement) => stmt.isAssignStmt && stmt.getRightOp.isIntConstant).findFirst - - if (refDefStmt.isEmpty || primDefStmt.isEmpty) { - Assert.fail("Could not find def statement") - } - - val refDefLocal = refDefStmt.get.getLeftOp - val primDefLocal = primDefStmt.get.getLeftOp - - var checked2: Boolean = false - jimpleMethod2.getStatements.forEach(stmt => { - if (stmt.containsInvokeExpr && stmt.getInvokeExpr.getDeclaredMethod.getName == "methodCall") { - val invokeExpr = stmt.getInvokeExpr - val base = invokeExpr.getBase - val arg = invokeExpr.getArg(0) - - // equals in both directions - Assert.assertEquals(base, refDefLocal) - Assert.assertEquals(refDefLocal, base) - - Assert.assertEquals(arg, primDefLocal) - Assert.assertEquals(primDefLocal, arg) - - // hash codes - Assert.assertEquals(base.hashCode, refDefLocal.hashCode) - Assert.assertEquals(arg.hashCode, primDefLocal.hashCode) - - checked2 = true - } - }) - - if (!checked2) { - Assert.fail("Did not check equals and hashCode methods for defined locals") - } - } } diff --git a/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootArrayTest.java b/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootArrayTest.java index bfc75438c..1da914ecf 100644 --- a/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootArrayTest.java +++ b/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootArrayTest.java @@ -25,12 +25,12 @@ public class SootArrayTest { @Test - public void singleArrayStoreConstantTest() { + public void arrayStoreConstantTest() { SootSetup sootSetup = new SootSetup(); sootSetup.setupSoot(ArrayTarget.class.getName()); MethodSignature signature = - new MethodSignature(ArrayTarget.class.getName(), "singleArrayStoreIndex"); + new MethodSignature(ArrayTarget.class.getName(), "arrayStoreIndex"); SootMethod method = sootSetup.resolveMethod(signature); Method jimpleMethod = JimpleMethod.of(method); diff --git a/boomerangScope/src/test/java/boomerang/scope/test/targets/ArrayTarget.java b/boomerangScope/src/test/java/boomerang/scope/test/targets/ArrayTarget.java index 6d61cdc0f..94660c089 100644 --- a/boomerangScope/src/test/java/boomerang/scope/test/targets/ArrayTarget.java +++ b/boomerangScope/src/test/java/boomerang/scope/test/targets/ArrayTarget.java @@ -16,47 +16,38 @@ public class ArrayTarget { public static void main(String[] args) { - singleArrayIndexLoad(new int[] {1, 2}); - singleArrayVarLoad(new int[] {1, 1}); + arrayIndexLoad(new int[] {1, 2}); + arrayVarLoad(new int[] {1, 1}); - singleArrayStoreIndex(); - singleArrayStoreVar(); - - multiArrayStore(); + arrayStoreIndex(); + arrayStoreVar(); } - public static void singleArrayIndexLoad(int[] arr) { + public static void arrayIndexLoad(int[] arr) { int i = arr[1]; System.out.println(i); } - public static void singleArrayVarLoad(int[] arr) { + public static void arrayVarLoad(int[] arr) { int index = 1; int i = arr[index]; System.out.println(i); } - public static void singleArrayStoreIndex() { + public static void arrayStoreIndex() { int[] arr = new int[2]; arr[0] = 1; System.out.println(Arrays.toString(arr)); } - public static void singleArrayStoreVar() { + public static void arrayStoreVar() { int[] arr = new int[2]; int index = 0; arr[index] = 1; System.out.println(Arrays.toString(arr)); } - - public static void multiArrayStore() { - A[][] arr = new A[2][3]; - arr[0][1] = new A(); - - System.out.println(Arrays.deepToString(arr)); - } } diff --git a/boomerangScope/src/test/java/boomerang/scope/test/targets/AssignmentTarget.java b/boomerangScope/src/test/java/boomerang/scope/test/targets/AssignmentTarget.java index 15cbcb14d..2140a54d0 100644 --- a/boomerangScope/src/test/java/boomerang/scope/test/targets/AssignmentTarget.java +++ b/boomerangScope/src/test/java/boomerang/scope/test/targets/AssignmentTarget.java @@ -17,6 +17,7 @@ public class AssignmentTarget { public static void main(String[] args) { arrayAllocation(); + multiArrayAllocation(); constantAssignment(); fieldStoreAssignment(); } @@ -27,6 +28,13 @@ public static void arrayAllocation() { System.out.println(Arrays.toString(arr)); } + public static void multiArrayAllocation() { + A[][] arr = new A[2][3]; + arr[0][1] = new A(); + + System.out.println(Arrays.deepToString(arr)); + } + public static void constantAssignment() { int i = 10; long l = 1000; From be4d01e4e3c67b2ddbd26218e8d6bc6e64864760 Mon Sep 17 00:00:00 2001 From: Sven Meyer Date: Tue, 22 Apr 2025 14:31:30 +0200 Subject: [PATCH 49/61] Clean up tac locals and add their original names --- .../scope/opal/tac/OpalInvokeExpr.scala | 4 +-- .../boomerang/scope/opal/tac/OpalLocal.scala | 5 +-- .../opal/transformation/TacBodyBuilder.scala | 3 +- .../scope/opal/transformation/TacLocal.scala | 31 +++++++++++-------- .../transformer/LocalTransformer.scala | 23 +++++++++++--- .../scope/opal/OpalInvokeExprTest.scala | 6 ++-- 6 files changed, 43 insertions(+), 29 deletions(-) diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalInvokeExpr.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalInvokeExpr.scala index b85ce36f1..d9492c44d 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalInvokeExpr.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalInvokeExpr.scala @@ -39,10 +39,8 @@ class OpalMethodInvokeExpr(val delegate: MethodCall[TacLocal], method: OpalMetho override def hashCode: Int = Objects.hash(delegate) - private def canEqual(a: Any): Boolean = a.isInstanceOf[OpalMethodInvokeExpr] - override def equals(obj: Any): Boolean = obj match { - case other: OpalMethodInvokeExpr => other.canEqual(this) && this.delegate == other.delegate + case other: OpalMethodInvokeExpr => this.delegate == other.delegate case _ => false } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalLocal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalLocal.scala index 43a671ba7..7bb0c1cb8 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalLocal.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalLocal.scala @@ -10,7 +10,7 @@ import java.util.Objects class OpalLocal(val delegate: Var[TacLocal], method: OpalMethod, unbalanced: ControlFlowGraph.Edge = null) extends Val(method, unbalanced) { override def getType: Type = { - val value = delegate.asVar.value + val value = delegate.asVar.valueInformation if (value.isPrimitiveValue) { return OpalType(value.asPrimitiveValue.primitiveType) @@ -26,9 +26,6 @@ class OpalLocal(val delegate: Var[TacLocal], method: OpalMethod, unbalanced: Con } else { return OpalType(value.asReferenceValue.upperTypeBound.head) } - - // Over approximation: Same behavior as in Soot - return OpalType(ObjectType("java/lang/Object")) } if (value.isVoid) { diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacBodyBuilder.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacBodyBuilder.scala index fe0651506..83c18ab46 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacBodyBuilder.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacBodyBuilder.scala @@ -1,7 +1,7 @@ package boomerang.scope.opal.transformation import boomerang.scope.opal.transformation.stack.OperandStackBuilder -import boomerang.scope.opal.transformation.transformer.{InlineLocalTransformer, LocalPropagationTransformer, LocalTransformer, NopEliminator, NopTransformer, NullifyFieldsTransformer} +import boomerang.scope.opal.transformation.transformer._ import org.opalj.ai.domain.l0.PrimitiveTACAIDomain import org.opalj.br.Method import org.opalj.br.analyses.Project @@ -18,6 +18,7 @@ object TacBodyBuilder { val tacNaive = TACNaive(method, project.classHierarchy) val stackHandler = OperandStackBuilder(method, tacNaive) + // TODO Use other domain to compute static type information val domain = new PrimitiveTACAIDomain(project.classHierarchy, method) val localTransformedTac = LocalTransformer(method, tacNaive, stackHandler, domain) assert(tacNaive.stmts.length == localTransformedTac.length, "Wrong transformation") diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacLocal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacLocal.scala index ab5b7f771..6863345b5 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacLocal.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacLocal.scala @@ -22,7 +22,7 @@ trait TacLocal extends Var[TacLocal] { def cTpe: ComputationalType - def value: ValueInformation + def valueInformation: ValueInformation final def isSideEffectFree: Boolean = true @@ -47,9 +47,9 @@ class StackLocal(identifier: Int, computationalType: ComputationalType, valueInf override def cTpe: ComputationalType = computationalType - override def value: ValueInformation = valueInfo + override def valueInformation: ValueInformation = valueInfo - override def hashCode: Int = Objects.hash(id) + override def hashCode: Int = Objects.hash(this.getClass.hashCode(), id) override def equals(other: Any): Boolean = other match { case that: StackLocal => this.id == that.id @@ -58,7 +58,7 @@ class StackLocal(identifier: Int, computationalType: ComputationalType, valueInf } } -class RegisterLocal(identifier: Int, computationalType: ComputationalType, valueInfo: ValueInformation, isThis: Boolean = false) extends TacLocal { +class RegisterLocal(identifier: Int, computationalType: ComputationalType, valueInfo: ValueInformation, isThis: Boolean = false, localName: Option[String] = Option.empty) extends TacLocal { override def id: Int = identifier @@ -66,13 +66,18 @@ class RegisterLocal(identifier: Int, computationalType: ComputationalType, value override def isThisLocal: Boolean = isThis - override def name: String = if (isThis) "this" else s"r${-identifier - 1}" + override def name: String = { + if (isThis) return "this" + if (localName.isDefined) return localName.get + + s"r${-identifier - 1}" + } override def cTpe: ComputationalType = computationalType - override def value: ValueInformation = valueInfo + override def valueInformation: ValueInformation = valueInfo - override def hashCode: Int = Objects.hash(id) + override def hashCode: Int = Objects.hash(this.getClass.hashCode(), id) override def equals(other: Any): Boolean = other match { case that: RegisterLocal => this.id == that.id @@ -89,11 +94,11 @@ class ParameterLocal(identifier: Int, computationalType: ComputationalType, para override def cTpe: ComputationalType = computationalType - override def value: ValueInformation = throw new UnsupportedOperationException("No value information available for parameter local") + override def valueInformation: ValueInformation = throw new UnsupportedOperationException("No value information available for parameter local") override def name: String = paramName - override def hashCode: Int = Objects.hash(id) + override def hashCode: Int = Objects.hash(this.getClass.hashCode(), id) override def equals(other: Any): Boolean = other match { case that: ParameterLocal => this.id == that.id @@ -107,11 +112,11 @@ class NullifiedLocal(identifier: Int, computationalType: ComputationalType) exte override def cTpe: ComputationalType = computationalType - override def value: ValueInformation = IsNullValue + override def valueInformation: ValueInformation = IsNullValue override def name: String = s"n$identifier" - override def hashCode: Int = Objects.hash(id) + override def hashCode: Int = Objects.hash(this.getClass.hashCode(), id) override def equals(other: Any): Boolean = other match { case that: NullifiedLocal => this.id == that.id @@ -127,11 +132,11 @@ class ExceptionLocal(identifier: Int, computationalType: ComputationalType, valu override def cTpe: ComputationalType = computationalType - override def value: ValueInformation = valueInfo + override def valueInformation: ValueInformation = valueInfo override def name: String = s"e$identifier" - override def hashCode: Int = Objects.hash(id) + override def hashCode: Int = Objects.hash(this.getClass.hashCode(), id) override def equals(other: Any): Boolean = other match { case that: ExceptionLocal => this.id == that.id diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/LocalTransformer.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/LocalTransformer.scala index 186c9c556..8469ca64a 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/LocalTransformer.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/LocalTransformer.scala @@ -38,9 +38,15 @@ object LocalTransformer { case Assignment(pc, targetVar, expr) => // Parameter definition statements if (pc == -1) { - val paramLocal = createParameterLocal(targetVar) val transformedExpr = transformExpr(pc, expr) + var paramName: Option[String] = None + if (transformedExpr.isVar && transformedExpr.asVar.isParameterLocal) { + paramName = Some(transformedExpr.asVar.name) + } + + val paramLocal = createParameterLocal(targetVar, paramName) + currentLocals(paramLocal.id) = paramLocal return Assignment(pc, paramLocal, transformedExpr) } @@ -136,10 +142,10 @@ object LocalTransformer { def isThisVar(idBasedVar: IdBasedVar): Boolean = method.isNotStatic && idBasedVar.id == -1 - def createParameterLocal(idBasedVar: IdBasedVar): TacLocal = { + def createParameterLocal(idBasedVar: IdBasedVar, paramName: Option[String] = Option.empty): TacLocal = { val local = localArray(0) - new RegisterLocal(idBasedVar.id, idBasedVar.cTpe, local(-idBasedVar.id - 1), isThisVar(idBasedVar)) + new RegisterLocal(idBasedVar.id, idBasedVar.cTpe, local(-idBasedVar.id - 1), isThisVar(idBasedVar), paramName) } def createStackLocal(pc: PC, idBasedVar: IdBasedVar, isThis: Boolean): TacLocal = { @@ -152,9 +158,16 @@ object LocalTransformer { def createRegisterLocal(pc: PC, idBasedVar: IdBasedVar, isThis: Boolean): TacLocal = { val nextPc = method.body.get.pcOfNextInstruction(pc) - val local = localArray(nextPc) + val locals = localArray(nextPc) + + val index = -idBasedVar.id - 1 + + val local = method.body.get.localVariable(nextPc, index) + if (local.isDefined) { + return new RegisterLocal(idBasedVar.id, idBasedVar.cTpe, locals(index), isThis, Option(local.get.name)) + } - new RegisterLocal(idBasedVar.id, idBasedVar.cTpe, local(-idBasedVar.id - 1), isThis) + new RegisterLocal(idBasedVar.id, idBasedVar.cTpe, locals(index), isThis) } def createExceptionLocal(pc: PC, idBasedVar: IdBasedVar, localId: Int): TacLocal = { diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala index fd7b73d1b..b8de09a30 100644 --- a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala @@ -3,7 +3,7 @@ package boomerang.scope.opal import boomerang.scope.DataFlowScope import boomerang.scope.opal.tac.OpalMethod import boomerang.scope.test.MethodSignature -import boomerang.scope.test.targets.{BranchingTarget, InvokeExprTarget} +import boomerang.scope.test.targets.{BranchingTarget, InvokeExprTarget, SingleTarget} import com.typesafe.config.ConfigValueFactory import org.junit.{Assert, Test} import org.opalj.br.analyses.Project @@ -18,9 +18,9 @@ class OpalInvokeExprTest { @Test def instanceInvokeExprTest(): Unit = { val opalSetup = new OpalSetup() - opalSetup.setupOpal(classOf[BranchingTarget].getName) + opalSetup.setupOpal(classOf[SingleTarget].getName) - val signature = new MethodSignature(classOf[BranchingTarget].getName, "switchBranching", "V") + val signature = new MethodSignature(classOf[SingleTarget].getName, "getAndSetField", "V") val method = opalSetup.resolveMethod(signature) val opalMethod = OpalMethod(method) opalMethod.getControlFlowGraph From b2194c80abd0432fcc1462fe77fb7041431ed10d Mon Sep 17 00:00:00 2001 From: Sven Meyer Date: Tue, 22 Apr 2025 20:08:07 +0200 Subject: [PATCH 50/61] Clean up identity statements --- .../boomerang/scope/opal/OpalCallGraph.scala | 6 ++- .../scope/opal/OpalFrameworkScope.scala | 2 +- .../scope/opal/tac/OpalStatement.scala | 40 ++++++++++--------- .../boomerang/scope/soot/SootArrayTest.java | 3 +- 4 files changed, 27 insertions(+), 24 deletions(-) diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalCallGraph.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalCallGraph.scala index c38d276e2..9bab15c15 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalCallGraph.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalCallGraph.scala @@ -4,11 +4,13 @@ import boomerang.scope.{CallGraph, InvokeExpr} import boomerang.scope.CallGraph.Edge import boomerang.scope.opal.tac.{OpalFunctionInvokeExpr, OpalMethod, OpalMethodInvokeExpr, OpalPhantomMethod, OpalStatement} import boomerang.scope.opal.transformation.TacBodyBuilder +import org.opalj.br.analyses.Project import org.opalj.br.{DefinedMethod, Method, MultipleDefinedMethods, VirtualDeclaredMethod} import org.opalj.tac.{NonVirtualFunctionCall, StaticFunctionCall, VirtualFunctionCall} -class OpalCallGraph(callGraph: org.opalj.tac.cg.CallGraph, entryPoints: Set[Method]) extends CallGraph { +class OpalCallGraph(project: Project[_], callGraph: org.opalj.tac.cg.CallGraph, entryPoints: Set[Method]) extends CallGraph { + // TODO Deal with callGraph.reachableMethods().foreach(method => { method.method match { case definedMethod: DefinedMethod => @@ -23,7 +25,7 @@ class OpalCallGraph(callGraph: org.opalj.tac.cg.CallGraph, entryPoints: Set[Meth }) private def addEdgesFromMethod(method: DefinedMethod): Unit = { - val tacCode = TacBodyBuilder(OpalClient.project.get, method.definedMethod) + val tacCode = TacBodyBuilder(project, method.definedMethod) tacCode.statements.foreach(stmt => { val srcStatement = new OpalStatement(stmt, OpalMethod(method.definedMethod, tacCode)) diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalFrameworkScope.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalFrameworkScope.scala index 2ab5a4b6b..fdf7fc8e9 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalFrameworkScope.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalFrameworkScope.scala @@ -8,7 +8,7 @@ import java.util.stream class OpalFrameworkScope(project: Project[_], callGraph: org.opalj.tac.cg.CallGraph, entryPoints: Set[org.opalj.br.Method], dataFlowScope: DataFlowScope) extends FrameworkScope { OpalClient.init(project) - private val opalCallGraph = new OpalCallGraph(callGraph, entryPoints) + private val opalCallGraph = new OpalCallGraph(project, callGraph, entryPoints) override def getCallGraph: CallGraph = opalCallGraph diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala index e97ee21dc..8591311f4 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala @@ -90,25 +90,10 @@ class OpalStatement(val delegate: Stmt[TacLocal], m: OpalMethod) extends Stateme } override def isAssignStmt: Boolean = { - if (delegate.isAssignment) { - val targetVar = delegate.asAssignment.targetVar - val expr = delegate.asAssignment.expr - - if (expr.isVar) { - /* Difference between Soot and Opal: - * - Soot considers parameter definitions and self assignments of the this local as identity statements (no assignments) - * - Opal considers these statements as basic assignments, so we have to exclude them manually - */ - if (expr.asVar.isParameterLocal) return false - if (expr.asVar.isExceptionLocal) return false - if (targetVar.isThisLocal && expr.asVar.isThisLocal) return false - - return true - } else { - return true - } - } + if (isIdentityStmt) return false + if (delegate.isAssignment) return true + // Store statements are no assignments in Opal isFieldStore || isArrayStore || isStaticFieldStore } @@ -274,7 +259,24 @@ class OpalStatement(val delegate: Stmt[TacLocal], m: OpalMethod) extends Stateme override def isFieldLoad: Boolean = delegate.isAssignment && delegate.asAssignment.expr.isGetField - override def isIdentityStmt: Boolean = false + override def isIdentityStmt: Boolean = { + if (delegate.isAssignment) { + /* Difference between Soot and Opal: + * - Soot considers parameter definitions and self assignments of the this local as identity statements (no assignments) + * - Opal considers these statements as basic assignments, so we have to exclude them manually + */ + val targetVar = delegate.asAssignment.targetVar + val expr = delegate.asAssignment.expr + + if (expr.isVar) { + if (expr.asVar.isParameterLocal) return true + if (expr.asVar.isExceptionLocal) return true + if (targetVar.isThisLocal && expr.asVar.isThisLocal) return true + } + } + + false + } override def getFieldStore: Pair[Val, Field] = { if (isFieldStore) { diff --git a/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootArrayTest.java b/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootArrayTest.java index 1da914ecf..cd813ed04 100644 --- a/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootArrayTest.java +++ b/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootArrayTest.java @@ -29,8 +29,7 @@ public void arrayStoreConstantTest() { SootSetup sootSetup = new SootSetup(); sootSetup.setupSoot(ArrayTarget.class.getName()); - MethodSignature signature = - new MethodSignature(ArrayTarget.class.getName(), "arrayStoreIndex"); + MethodSignature signature = new MethodSignature(ArrayTarget.class.getName(), "arrayStoreIndex"); SootMethod method = sootSetup.resolveMethod(signature); Method jimpleMethod = JimpleMethod.of(method); From aa6b5183a977ce52e4c3009aa73dfa6ee609118f Mon Sep 17 00:00:00 2001 From: Sven Meyer Date: Wed, 23 Apr 2025 10:18:13 +0200 Subject: [PATCH 51/61] Clean up --- .../src/main/java/sync/pds/weights/SetDomain.java | 3 +-- .../java/boomerang/results/ForwardBoomerangResults.java | 1 + .../main/java/boomerang/weights/PathConditionWeight.java | 2 -- .../src/main/java/boomerang/weights/PathTrackingWeight.java | 3 --- .../test/java/boomerang/guided/CustomFlowFunctionTest.java | 2 +- .../boomerang/guided/DemandDrivenGuidedAnalysisTest.java | 2 +- .../test/java/test/cases/bugfixes/issue5/Issue5Test.java | 2 +- .../src/test/java/test/core/AbstractBoomerangTest.java | 1 + .../src/test/java/test/core/MultiQueryBoomerangTest.java | 2 +- idealPDS/src/main/java/typestate/TransitionFunction.java | 6 +----- 10 files changed, 8 insertions(+), 16 deletions(-) diff --git a/SynchronizedPDS/src/main/java/sync/pds/weights/SetDomain.java b/SynchronizedPDS/src/main/java/sync/pds/weights/SetDomain.java index 2311d0f9f..56e558a3e 100644 --- a/SynchronizedPDS/src/main/java/sync/pds/weights/SetDomain.java +++ b/SynchronizedPDS/src/main/java/sync/pds/weights/SetDomain.java @@ -12,8 +12,7 @@ package sync.pds.weights; import java.util.Collection; -import java.util.LinkedHashSet; -import java.util.Set; +import org.jspecify.annotations.NonNull; import sync.pds.solver.nodes.Node; import wpds.impl.Weight; diff --git a/boomerangPDS/src/main/java/boomerang/results/ForwardBoomerangResults.java b/boomerangPDS/src/main/java/boomerang/results/ForwardBoomerangResults.java index 913421737..7929a6d60 100644 --- a/boomerangPDS/src/main/java/boomerang/results/ForwardBoomerangResults.java +++ b/boomerangPDS/src/main/java/boomerang/results/ForwardBoomerangResults.java @@ -44,6 +44,7 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Set; import sync.pds.solver.nodes.GeneratedState; import sync.pds.solver.nodes.INode; import sync.pds.solver.nodes.Node; diff --git a/boomerangPDS/src/main/java/boomerang/weights/PathConditionWeight.java b/boomerangPDS/src/main/java/boomerang/weights/PathConditionWeight.java index 2d4a78920..0b072a42d 100644 --- a/boomerangPDS/src/main/java/boomerang/weights/PathConditionWeight.java +++ b/boomerangPDS/src/main/java/boomerang/weights/PathConditionWeight.java @@ -13,8 +13,6 @@ import boomerang.scope.Statement; import boomerang.scope.Val; -import com.google.common.collect.Maps; -import java.util.LinkedHashSet; import java.util.Map; import wpds.impl.Weight; diff --git a/boomerangPDS/src/main/java/boomerang/weights/PathTrackingWeight.java b/boomerangPDS/src/main/java/boomerang/weights/PathTrackingWeight.java index 91b64f9fa..7d0e74e66 100644 --- a/boomerangPDS/src/main/java/boomerang/weights/PathTrackingWeight.java +++ b/boomerangPDS/src/main/java/boomerang/weights/PathTrackingWeight.java @@ -13,9 +13,6 @@ import boomerang.scope.ControlFlowGraph; import boomerang.scope.Val; -import com.google.common.collect.Lists; -import java.util.LinkedHashSet; -import java.util.List; import java.util.Set; import org.jspecify.annotations.NonNull; import sync.pds.solver.nodes.Node; diff --git a/boomerangPDS/src/test/java/boomerang/guided/CustomFlowFunctionTest.java b/boomerangPDS/src/test/java/boomerang/guided/CustomFlowFunctionTest.java index 64b0ed7d4..6be7e2ba1 100644 --- a/boomerangPDS/src/test/java/boomerang/guided/CustomFlowFunctionTest.java +++ b/boomerangPDS/src/test/java/boomerang/guided/CustomFlowFunctionTest.java @@ -38,7 +38,7 @@ import org.junit.Assert; import org.junit.Test; import test.TestingFramework; -import wpds.impl.Weight.NoWeight; +import wpds.impl.NoWeight; public class CustomFlowFunctionTest { diff --git a/boomerangPDS/src/test/java/boomerang/guided/DemandDrivenGuidedAnalysisTest.java b/boomerangPDS/src/test/java/boomerang/guided/DemandDrivenGuidedAnalysisTest.java index 4f69a9ae3..4739b3713 100644 --- a/boomerangPDS/src/test/java/boomerang/guided/DemandDrivenGuidedAnalysisTest.java +++ b/boomerangPDS/src/test/java/boomerang/guided/DemandDrivenGuidedAnalysisTest.java @@ -55,7 +55,7 @@ import org.junit.Assert; import org.junit.Test; import test.TestingFramework; -import wpds.impl.Weight.NoWeight; +import wpds.impl.NoWeight; public class DemandDrivenGuidedAnalysisTest { diff --git a/boomerangPDS/src/test/java/test/cases/bugfixes/issue5/Issue5Test.java b/boomerangPDS/src/test/java/test/cases/bugfixes/issue5/Issue5Test.java index 12d84ed72..057f9cf27 100644 --- a/boomerangPDS/src/test/java/test/cases/bugfixes/issue5/Issue5Test.java +++ b/boomerangPDS/src/test/java/test/cases/bugfixes/issue5/Issue5Test.java @@ -33,7 +33,7 @@ import org.junit.Assert; import org.junit.Test; import test.TestingFramework; -import wpds.impl.Weight.NoWeight; +import wpds.impl.NoWeight; /** * This code was added to test Issue diff --git a/boomerangPDS/src/test/java/test/core/AbstractBoomerangTest.java b/boomerangPDS/src/test/java/test/core/AbstractBoomerangTest.java index aa1f33aea..dd7858607 100644 --- a/boomerangPDS/src/test/java/test/core/AbstractBoomerangTest.java +++ b/boomerangPDS/src/test/java/test/core/AbstractBoomerangTest.java @@ -54,6 +54,7 @@ import test.TestingFramework; import test.core.selfrunning.AllocatedObject; import test.core.selfrunning.NoAllocatedObject; +import wpds.impl.NoWeight; import wpds.impl.Transition; import wpds.impl.WeightedPAutomaton; import wpds.interfaces.WPAStateListener; diff --git a/boomerangPDS/src/test/java/test/core/MultiQueryBoomerangTest.java b/boomerangPDS/src/test/java/test/core/MultiQueryBoomerangTest.java index 42e9cee7a..308a14c7e 100644 --- a/boomerangPDS/src/test/java/test/core/MultiQueryBoomerangTest.java +++ b/boomerangPDS/src/test/java/test/core/MultiQueryBoomerangTest.java @@ -34,7 +34,7 @@ import org.junit.rules.TestName; import org.junit.rules.Timeout; import test.TestingFramework; -import wpds.impl.Weight; +import wpds.impl.NoWeight; public class MultiQueryBoomerangTest extends TestingFramework { diff --git a/idealPDS/src/main/java/typestate/TransitionFunction.java b/idealPDS/src/main/java/typestate/TransitionFunction.java index 63d285f34..c6e8677af 100644 --- a/idealPDS/src/main/java/typestate/TransitionFunction.java +++ b/idealPDS/src/main/java/typestate/TransitionFunction.java @@ -11,12 +11,8 @@ */ package typestate; -import boomerang.scope.ControlFlowGraph.Edge; -import com.google.common.collect.Lists; +import boomerang.scope.ControlFlowGraph; import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.LinkedHashSet; import java.util.Set; import org.jspecify.annotations.NonNull; import typestate.finiteautomata.Transition; From 967120b2553ef61a2da648a04b9511c3e2f1a416 Mon Sep 17 00:00:00 2001 From: Sven Meyer Date: Wed, 23 Apr 2025 11:30:55 +0200 Subject: [PATCH 52/61] Fix backward static field handling --- .../ForwardSolverSuccessorListener.java | 7 ++-- .../DefaultBackwardFlowFunction.java | 33 ++++++++++--------- .../flowfunction/IBackwardFlowFunction.java | 10 +++--- .../solver/AbstractBoomerangSolver.java | 3 +- .../solver/BackwardBoomerangSolver.java | 11 ++++--- .../solver/ForwardBoomerangSolver.java | 3 +- .../FlowSensitiveStaticFieldStrategy.java | 2 +- .../CustomBackwardFlowFunction.java | 16 ++++----- .../cases/statics/SimpleSingletonTest.java | 2 -- .../test/cases/statics/SingletonTest.java | 4 +-- .../cases/statics/StaticFieldFlowsTest.java | 2 +- .../cases/statics/StaticInitializerTest.java | 2 -- .../boomerang/scope/opal/OpalCallGraph.scala | 11 +++++++ .../scope/opal/tac/OpalStatement.scala | 8 ++--- .../opal/tac/OpalStatementFormatter.scala | 4 +++ 15 files changed, 68 insertions(+), 50 deletions(-) diff --git a/boomerangPDS/src/main/java/boomerang/controlflowgraph/ForwardSolverSuccessorListener.java b/boomerangPDS/src/main/java/boomerang/controlflowgraph/ForwardSolverSuccessorListener.java index 532025203..5fd166c1c 100644 --- a/boomerangPDS/src/main/java/boomerang/controlflowgraph/ForwardSolverSuccessorListener.java +++ b/boomerangPDS/src/main/java/boomerang/controlflowgraph/ForwardSolverSuccessorListener.java @@ -34,7 +34,7 @@ public class ForwardSolverSuccessorListener extends SuccessorListener { private final Node node; private final org.slf4j.Logger LOGGER; // doesn't look good but this class also shouldn't exist alone - private final ForwardBoomerangSolver owner; + private final ForwardBoomerangSolver owner; public ForwardSolverSuccessorListener( ControlFlowGraph.Edge curr, @@ -43,7 +43,7 @@ public ForwardSolverSuccessorListener( Method method, Node node, org.slf4j.Logger LOGGER, - ForwardBoomerangSolver owner) { + ForwardBoomerangSolver owner) { super(curr.getTarget()); this.query = query; this.curr = curr; @@ -93,7 +93,8 @@ public void getSuccessor(Statement succ) { } } else {*/ Collection out = - owner.computeNormalFlow(method, new ControlFlowGraph.Edge(curr.getTarget(), succ), value); + owner.computeNormalFlow( + method, curr, new ControlFlowGraph.Edge(curr.getTarget(), succ), value); // if (method.getName().contains("main")) { // for (State s : out) { // if (s instanceof Node) { diff --git a/boomerangPDS/src/main/java/boomerang/flowfunction/DefaultBackwardFlowFunction.java b/boomerangPDS/src/main/java/boomerang/flowfunction/DefaultBackwardFlowFunction.java index 68fbf4adb..1c8d839a0 100644 --- a/boomerangPDS/src/main/java/boomerang/flowfunction/DefaultBackwardFlowFunction.java +++ b/boomerangPDS/src/main/java/boomerang/flowfunction/DefaultBackwardFlowFunction.java @@ -97,8 +97,8 @@ public Collection callFlow(Statement callSite, Val fact, Method callee, Sta } @Override - public Collection normalFlow(Edge currEdge, Val fact) { - Statement curr = currEdge.getTarget(); + public Collection normalFlow(Edge currEdge, Edge nextEdge, Val fact) { + Statement curr = nextEdge.getTarget(); if (options.allocationSite().getAllocationSite(curr.getMethod(), curr, fact).isPresent()) { return Collections.emptySet(); } @@ -117,7 +117,7 @@ public Collection normalFlow(Edge currEdge, Val fact) { if (options.trackFields()) { Pair ifr = curr.getFieldLoad(); if (options.includeInnerClassFields() || !ifr.getY().isInnerClassField()) { - out.add(new PushNode<>(currEdge, ifr.getX(), ifr.getY(), PDSSystem.FIELDS)); + out.add(new PushNode<>(nextEdge, ifr.getX(), ifr.getY(), PDSSystem.FIELDS)); } } } else if (curr.isStaticFieldLoad()) { @@ -129,20 +129,20 @@ public Collection normalFlow(Edge currEdge, Val fact) { } else if (rightOp.isArrayRef()) { Pair arrayBase = curr.getArrayBase(); if (options.trackFields()) { - strategies.getArrayHandlingStrategy().handleBackward(currEdge, arrayBase, out); + strategies.getArrayHandlingStrategy().handleBackward(nextEdge, arrayBase, out); } } else if (rightOp.isCast()) { - out.add(new Node<>(currEdge, rightOp.getCastOp())); + out.add(new Node<>(nextEdge, rightOp.getCastOp())); } else if (curr.isPhiStatement()) { Collection phiVals = curr.getPhiVals(); for (Val v : phiVals) { - out.add(new Node<>(currEdge, v)); + out.add(new Node<>(nextEdge, v)); } } else { if (curr.isFieldLoadWithBase(fact)) { - out.add(new ExclusionNode<>(currEdge, fact, curr.getLoadedField())); + out.add(new ExclusionNode<>(nextEdge, fact, curr.getLoadedField())); } else { - out.add(new Node<>(currEdge, rightOp)); + out.add(new Node<>(nextEdge, rightOp)); } } } @@ -151,33 +151,34 @@ public Collection normalFlow(Edge currEdge, Val fact) { Val base = ifr.getX(); if (base.equals(fact)) { NodeWithLocation succNode = - new NodeWithLocation<>(currEdge, rightOp, ifr.getY()); + new NodeWithLocation<>(nextEdge, rightOp, ifr.getY()); out.add(new PopNode<>(succNode, PDSSystem.FIELDS)); } } else if (curr.isStaticFieldStore()) { StaticFieldVal staticField = curr.getStaticField(); if (fact.isStatic() && fact.equals(staticField)) { - out.add(new Node<>(currEdge, rightOp)); + out.add(new Node<>(nextEdge, rightOp)); } } else if (leftOp.isArrayRef()) { Pair arrayBase = curr.getArrayBase(); if (arrayBase.getX().equals(fact)) { NodeWithLocation succNode = - new NodeWithLocation<>(currEdge, rightOp, Field.array(arrayBase.getY())); + new NodeWithLocation<>(nextEdge, rightOp, Field.array(arrayBase.getY())); out.add(new PopNode<>(succNode, PDSSystem.FIELDS)); } } } - if (!leftSideMatches) out.add(new Node<>(currEdge, fact)); + if (!leftSideMatches) out.add(new Node<>(nextEdge, fact)); return out; } @Override - public Collection callToReturnFlow(Edge edge, Val fact) { - if (FlowFunctionUtils.isSystemArrayCopy(edge.getTarget().getInvokeExpr().getDeclaredMethod())) { - return systemArrayCopyFlow(edge, fact); + public Collection callToReturnFlow(Edge currEdge, Edge nextEdge, Val fact) { + if (FlowFunctionUtils.isSystemArrayCopy( + nextEdge.getTarget().getInvokeExpr().getDeclaredMethod())) { + return systemArrayCopyFlow(nextEdge, fact); } - return normalFlow(edge, fact); + return normalFlow(currEdge, nextEdge, fact); } @Override diff --git a/boomerangPDS/src/main/java/boomerang/flowfunction/IBackwardFlowFunction.java b/boomerangPDS/src/main/java/boomerang/flowfunction/IBackwardFlowFunction.java index 591f6f58b..9b86aa928 100644 --- a/boomerangPDS/src/main/java/boomerang/flowfunction/IBackwardFlowFunction.java +++ b/boomerangPDS/src/main/java/boomerang/flowfunction/IBackwardFlowFunction.java @@ -55,11 +55,12 @@ public interface IBackwardFlowFunction { * The logic differs from general IFDS logic here. edge.getTarget() can also contain a call site, * but fact is not used in the call site (no parameter or base variable of the call expression) . * - * @param edge The control-flow graph edge that will be propagated next. + * @param currEdge the current control-flow graph edge + * @param nextEdge The control-flow graph edge that will be propagated next. * @param fact The incoming data-flow fact that reaches the edge. * @return A set of data-flow states (states in the pushdown system). */ - Collection normalFlow(Edge edge, Val fact); + Collection normalFlow(Edge currEdge, Edge nextEdge, Val fact); /** * Called by the backward analysis, when data-flow by-passes a call site with data-flow fact. Here @@ -69,12 +70,13 @@ public interface IBackwardFlowFunction { * the call expression. As a consequence, special handling for call site may need to be * implemented as part of callToReturn and normalFlow. * - * @param edge Edge that bypasses the call site. edge.getTarget() is the call site, + * @param currEdge Current edge that generates the next edge + * @param nextEdge Edge that bypasses the call site. edge.getTarget() is the call site, * edge.getStart() is any predecessor * @param fact The fact that by-passes the call site. * @return A set of data-flow states (states in the pushdown system) */ - Collection callToReturnFlow(Edge edge, Val fact); + Collection callToReturnFlow(Edge currEdge, Edge nextEdge, Val fact); void setSolver( BackwardBoomerangSolver solver, diff --git a/boomerangPDS/src/main/java/boomerang/solver/AbstractBoomerangSolver.java b/boomerangPDS/src/main/java/boomerang/solver/AbstractBoomerangSolver.java index 8b864ce0a..fec9f4de9 100644 --- a/boomerangPDS/src/main/java/boomerang/solver/AbstractBoomerangSolver.java +++ b/boomerangPDS/src/main/java/boomerang/solver/AbstractBoomerangSolver.java @@ -445,7 +445,8 @@ protected void returnFlow(Method method, Node currNo } } - protected abstract Collection computeNormalFlow(Method method, Edge currEdge, Val value); + protected abstract Collection computeNormalFlow( + Method method, Edge currEdge, Edge nextEdge, Val value); @Override public Field epsilonField() { diff --git a/boomerangPDS/src/main/java/boomerang/solver/BackwardBoomerangSolver.java b/boomerangPDS/src/main/java/boomerang/solver/BackwardBoomerangSolver.java index faa485991..3e8691e92 100644 --- a/boomerangPDS/src/main/java/boomerang/solver/BackwardBoomerangSolver.java +++ b/boomerangPDS/src/main/java/boomerang/solver/BackwardBoomerangSolver.java @@ -130,7 +130,8 @@ private void byPassFlowAtCallsite(Method caller, Node curr) { .getPredsOf(curr.stmt().getStart())) { Collection res = - flowFunction.callToReturnFlow(new Edge(returnSite, curr.stmt().getStart()), curr.fact()); + flowFunction.callToReturnFlow( + curr.stmt(), new Edge(returnSite, curr.stmt().getStart()), curr.fact()); for (State s : res) { propagate(curr, s); } @@ -180,7 +181,8 @@ protected void normalFlow(Method method, Node currNo { for (Statement pred : curr.getStart().getMethod().getControlFlowGraph().getPredsOf(curr.getStart())) { - Collection flow = computeNormalFlow(method, new Edge(pred, curr.getStart()), value); + Collection flow = + computeNormalFlow(method, curr, new Edge(pred, curr.getStart()), value); for (State s : flow) { options.getSparsificationStrategy().getCounter().countBackwardProgragation(); propagate(currNode, s); @@ -246,8 +248,9 @@ public void processPush( } @Override - protected Collection computeNormalFlow(Method method, Edge currEdge, Val fact) { - return flowFunction.normalFlow(currEdge, fact); + protected Collection computeNormalFlow( + Method method, Edge currEdge, Edge nextEdge, Val fact) { + return flowFunction.normalFlow(currEdge, nextEdge, fact); } @Override diff --git a/boomerangPDS/src/main/java/boomerang/solver/ForwardBoomerangSolver.java b/boomerangPDS/src/main/java/boomerang/solver/ForwardBoomerangSolver.java index 7f058ddea..953551949 100644 --- a/boomerangPDS/src/main/java/boomerang/solver/ForwardBoomerangSolver.java +++ b/boomerangPDS/src/main/java/boomerang/solver/ForwardBoomerangSolver.java @@ -421,7 +421,8 @@ protected abstract void overwriteFieldAtStatement( Edge fieldWriteStatementEdge, Transition>> killedTransition); @Override - public Collection computeNormalFlow(Method method, Edge nextEdge, Val fact) { + public Collection computeNormalFlow( + Method method, Edge currEdge, Edge nextEdge, Val fact) { return flowFunctions.normalFlow(query, nextEdge, fact); } diff --git a/boomerangPDS/src/main/java/boomerang/staticfields/FlowSensitiveStaticFieldStrategy.java b/boomerangPDS/src/main/java/boomerang/staticfields/FlowSensitiveStaticFieldStrategy.java index a0f533dba..c8a3145fd 100644 --- a/boomerangPDS/src/main/java/boomerang/staticfields/FlowSensitiveStaticFieldStrategy.java +++ b/boomerangPDS/src/main/java/boomerang/staticfields/FlowSensitiveStaticFieldStrategy.java @@ -28,6 +28,6 @@ public void handleForward( @Override public void handleBackward( Edge loadStatement, Val loadedVal, StaticFieldVal staticVal, Set out) { - out.add(new Node<>(loadStatement, loadStatement.getTarget().getStaticField())); + out.add(new Node<>(loadStatement, loadStatement.getStart().getStaticField())); } } diff --git a/boomerangPDS/src/test/java/boomerang/guided/flowfunction/CustomBackwardFlowFunction.java b/boomerangPDS/src/test/java/boomerang/guided/flowfunction/CustomBackwardFlowFunction.java index 4f82149a8..437ea3c15 100644 --- a/boomerangPDS/src/test/java/boomerang/guided/flowfunction/CustomBackwardFlowFunction.java +++ b/boomerangPDS/src/test/java/boomerang/guided/flowfunction/CustomBackwardFlowFunction.java @@ -29,9 +29,9 @@ public CustomBackwardFlowFunction(DefaultBackwardFlowFunctionOptions options) { } @Override - public Collection normalFlow(Edge edge, Val fact) { - if (edge.getTarget().containsInvokeExpr()) { - DeclaredMethod method = edge.getTarget().getInvokeExpr().getDeclaredMethod(); + public Collection normalFlow(Edge currEdge, Edge nextEdge, Val fact) { + if (nextEdge.getTarget().containsInvokeExpr()) { + DeclaredMethod method = nextEdge.getTarget().getInvokeExpr().getDeclaredMethod(); // Avoid any propagations by passing the call site (also when the fact is not used at the call // site). if (method.getDeclaringClass().getFullyQualifiedName().equals("java.lang.System") @@ -39,13 +39,13 @@ public Collection normalFlow(Edge edge, Val fact) { return Collections.emptySet(); } } - return super.normalFlow(edge, fact); + return super.normalFlow(currEdge, nextEdge, fact); } @Override - public Collection callToReturnFlow(Edge edge, Val fact) { - if (edge.getTarget().containsInvokeExpr()) { - DeclaredMethod method = edge.getTarget().getInvokeExpr().getDeclaredMethod(); + public Collection callToReturnFlow(Edge currEdge, Edge nextEdge, Val fact) { + if (nextEdge.getTarget().containsInvokeExpr()) { + DeclaredMethod method = nextEdge.getTarget().getInvokeExpr().getDeclaredMethod(); // Avoid any propagations by passing the call site (also when the fact is not used at the call // site). if (method.getDeclaringClass().getFullyQualifiedName().equals("java.lang.System") @@ -53,7 +53,7 @@ public Collection callToReturnFlow(Edge edge, Val fact) { return Collections.emptySet(); } } - return super.callToReturnFlow(edge, fact); + return super.callToReturnFlow(currEdge, nextEdge, fact); } @Override diff --git a/boomerangPDS/src/test/java/test/cases/statics/SimpleSingletonTest.java b/boomerangPDS/src/test/java/test/cases/statics/SimpleSingletonTest.java index 6b237ad6b..1930e3a61 100644 --- a/boomerangPDS/src/test/java/test/cases/statics/SimpleSingletonTest.java +++ b/boomerangPDS/src/test/java/test/cases/statics/SimpleSingletonTest.java @@ -11,11 +11,9 @@ */ package test.cases.statics; -import org.junit.Ignore; import org.junit.Test; import test.core.AbstractBoomerangTest; -@Ignore("Static fields are not handled correctly (see TODO in WeightedBoomerang") public class SimpleSingletonTest extends AbstractBoomerangTest { private final String target = SimpleSingletonTarget.class.getName(); diff --git a/boomerangPDS/src/test/java/test/cases/statics/SingletonTest.java b/boomerangPDS/src/test/java/test/cases/statics/SingletonTest.java index 5d893b873..8f5e71fe0 100644 --- a/boomerangPDS/src/test/java/test/cases/statics/SingletonTest.java +++ b/boomerangPDS/src/test/java/test/cases/statics/SingletonTest.java @@ -15,13 +15,12 @@ import org.junit.Test; import test.core.AbstractBoomerangTest; -@Ignore("Static fields are not handled correctly (see TODO in WeightedBoomerang") public class SingletonTest extends AbstractBoomerangTest { private final String target = SingletonTarget.class.getName(); @Test - @Ignore + @Ignore("Static fields are not handled correctly (see TODO in WeightedBoomerang") public void doubleSingleton() { analyze(target, testName.getMethodName()); } @@ -32,6 +31,7 @@ public void doubleSingletonDirect() { } @Test + @Ignore("Static fields are not handled correctly (see TODO in WeightedBoomerang") public void singletonDirect() { analyze(target, testName.getMethodName()); } diff --git a/boomerangPDS/src/test/java/test/cases/statics/StaticFieldFlowsTest.java b/boomerangPDS/src/test/java/test/cases/statics/StaticFieldFlowsTest.java index 2f255e179..0e72d3f8f 100644 --- a/boomerangPDS/src/test/java/test/cases/statics/StaticFieldFlowsTest.java +++ b/boomerangPDS/src/test/java/test/cases/statics/StaticFieldFlowsTest.java @@ -15,7 +15,6 @@ import org.junit.Test; import test.core.AbstractBoomerangTest; -@Ignore("Static fields are not handled correctly (see TODO in WeightedBoomerang") public class StaticFieldFlowsTest extends AbstractBoomerangTest { private final String target = StaticFieldFlowsTarget.class.getName(); @@ -41,6 +40,7 @@ public void singleton() { } @Test + @Ignore("Static fields are not handled correctly (see TODO in WeightedBoomerang") public void getAndSet() { analyze(target, testName.getMethodName()); } diff --git a/boomerangPDS/src/test/java/test/cases/statics/StaticInitializerTest.java b/boomerangPDS/src/test/java/test/cases/statics/StaticInitializerTest.java index 445be1729..73bb7b96f 100644 --- a/boomerangPDS/src/test/java/test/cases/statics/StaticInitializerTest.java +++ b/boomerangPDS/src/test/java/test/cases/statics/StaticInitializerTest.java @@ -11,11 +11,9 @@ */ package test.cases.statics; -import org.junit.Ignore; import org.junit.Test; import test.core.AbstractBoomerangTest; -@Ignore("Static fields are not handled correctly (see TODO in WeightedBoomerang") public class StaticInitializerTest extends AbstractBoomerangTest { private final String target = StaticInitializerTarget.class.getName(); diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalCallGraph.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalCallGraph.scala index 9bab15c15..10ae33827 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalCallGraph.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalCallGraph.scala @@ -79,6 +79,17 @@ class OpalCallGraph(project: Project[_], callGraph: org.opalj.tac.cg.CallGraph, } } + // Explicitly add static initializers () as they are called only implicitly + callGraph.reachableMethods().foreach(method => { + method.method match { + case definedMethod: DefinedMethod if definedMethod.definedMethod.isStaticInitializer => + if (definedMethod.definedMethod.body.isDefined) { + addEntryPoint(OpalMethod(definedMethod.definedMethod)) + } + case _ => + } + }) + entryPoints.foreach(entryPoint => { if (entryPoint.body.isDefined) { addEntryPoint(OpalMethod(entryPoint)) diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala index 8591311f4..9cee850e8 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala @@ -354,12 +354,10 @@ class OpalStatement(val delegate: Stmt[TacLocal], m: OpalMethod) extends Stateme override def isCatchStmt: Boolean = delegate.isCaughtException - override def hashCode: Int = Objects.hash(delegate) + override def hashCode: Int = Objects.hash(delegate, m) - private def canEqual(a: Any): Boolean = a.isInstanceOf[OpalStatement] - - override def equals(obj: Any): Boolean = obj match { - case other: OpalStatement => other.canEqual(this) && this.delegate == other.delegate + override def equals(other: Any): Boolean = other match { + case that: OpalStatement => this.delegate == that.delegate && this.method == that.method case _ => false } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatementFormatter.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatementFormatter.scala index 86497d599..f5ce57733 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatementFormatter.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatementFormatter.scala @@ -34,6 +34,10 @@ object OpalStatementFormatter { val base = stmt.getArrayBase return s"${base.getX.getVariableName}[${base.getY}] = ${stmt.getRightOp}" } + + if (stmt.isStaticFieldStore) { + return s"${stmt.getLeftOp} = ${stmt.getRightOp}" + } } if (delegate.isAssignment) { From 7d1cc121238e6736407c1f94440456adf8183b79 Mon Sep 17 00:00:00 2001 From: Sven Meyer Date: Wed, 23 Apr 2025 17:52:22 +0200 Subject: [PATCH 53/61] Parameterize test setup --- .github/workflows/maven.yml | 5 ++- .../test/cases/basic/InterproceduralTest.java | 2 + .../stack/OperandStackBuilder.scala | 18 ++++---- .../boomerang/scope/soot/SootScopeTest.java | 17 -------- pom.xml | 43 +++++++++++++++++++ .../src/main/java/test/TestingFramework.java | 31 ++++++++++++- 6 files changed, 87 insertions(+), 29 deletions(-) diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index de7adcb2f..04f732906 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -11,6 +11,9 @@ on: jobs: BuildAndTest: + strategy: + matrix: + framework: [soot, opal] # TODO Add SootUp when available runs-on: ubuntu-latest steps: - name: Checkout source code @@ -22,4 +25,4 @@ jobs: java-package: jdk java-version: 11 - name: Build with Maven - run: mvn -B clean verify + run: mvn -B clean verify -DtestSetup=${{ matrix.framework }} diff --git a/boomerangPDS/src/test/java/test/cases/basic/InterproceduralTest.java b/boomerangPDS/src/test/java/test/cases/basic/InterproceduralTest.java index b8650ff11..33d571471 100644 --- a/boomerangPDS/src/test/java/test/cases/basic/InterproceduralTest.java +++ b/boomerangPDS/src/test/java/test/cases/basic/InterproceduralTest.java @@ -11,6 +11,7 @@ */ package test.cases.basic; +import org.junit.Ignore; import org.junit.Test; import test.core.AbstractBoomerangTest; @@ -44,6 +45,7 @@ public void summaryReuseTest1() { } @Test + @Ignore("Soot fails") public void failedCast() { analyze(target, testName.getMethodName()); } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackBuilder.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackBuilder.scala index ed7dca59c..ca17a33aa 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackBuilder.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackBuilder.scala @@ -140,21 +140,21 @@ object OperandStackBuilder { stack.pop(objRef) schedule(pcOfNextStatement(pc), stack) - case NonVirtualMethodCall(pc, _, _, _, _, receiver: IdBasedVar, params: Seq[IdBasedVar]) => + case NonVirtualMethodCall(pc, _, _, _, _, receiver: IdBasedVar, params: Seq[_]) => params.reverse.foreach(p => stack.pop(p.asVar)) stack.pop(receiver) schedule(pcOfNextStatement(pc), stack) - case VirtualMethodCall(pc, _, _, _, _, receiver: IdBasedVar, params: Seq[IdBasedVar]) => + case VirtualMethodCall(pc, _, _, _, _, receiver: IdBasedVar, params: Seq[_]) => params.reverse.foreach(p => stack.pop(p.asVar)) stack.pop(receiver) schedule(pcOfNextStatement(pc), stack) - case StaticMethodCall(pc, _, _, _, _, params: Seq[IdBasedVar]) => + case StaticMethodCall(pc, _, _, _, _, params: Seq[_]) => params.reverse.foreach(p => stack.pop(p.asVar)) schedule(pcOfNextStatement(pc), stack) - case InvokedynamicMethodCall(pc, _, _, _, params: Seq[IdBasedVar]) => + case InvokedynamicMethodCall(pc, _, _, _, params: Seq[_]) => params.reverse.foreach(p => stack.pop(p.asVar)) schedule(pcOfNextStatement(pc), stack) @@ -192,15 +192,15 @@ object OperandStackBuilder { case PrefixExpr(_, _, _, operand: IdBasedVar) => List(operand) case PrimitiveTypecastExpr(_, _, operand: IdBasedVar) => List(operand) case New(_, _) => List() - case NewArray(_, counts: Seq[IdBasedVar], _) => counts.map(c => c.asVar).toList + case NewArray(_, counts: Seq[_], _) => counts.map(c => c.asVar).toList case ArrayLoad(_, index: IdBasedVar, arrayRef: IdBasedVar) => List(index, arrayRef) case ArrayLength(_, arrayRef: IdBasedVar) => List(arrayRef) case GetField(_, _, _, _, objRef: IdBasedVar) => List(objRef) case GetStatic(_, _, _, _) => List() - case InvokedynamicFunctionCall(_, _, _, _, params: Seq[IdBasedVar]) => params.map(p => p.asVar).toList.reverse - case NonVirtualFunctionCall(_, _, _, _, _, receiver: IdBasedVar, params: Seq[IdBasedVar]) => params.map(p => p.asVar).toList.reverse :+ receiver - case VirtualFunctionCall(_, _, _, _, _, receiver: IdBasedVar, params: Seq[IdBasedVar]) => params.map(p => p.asVar).toList.reverse :+ receiver - case StaticFunctionCall(_, _, _, _, _, params: Seq[IdBasedVar]) => params.map(p => p.asVar).toList.reverse + case InvokedynamicFunctionCall(_, _, _, _, params: Seq[_]) => params.map(p => p.asVar).toList.reverse + case NonVirtualFunctionCall(_, _, _, _, _, receiver: IdBasedVar, params: Seq[_]) => params.map(p => p.asVar).toList.reverse :+ receiver + case VirtualFunctionCall(_, _, _, _, _, receiver: IdBasedVar, params: Seq[_]) => params.map(p => p.asVar).toList.reverse :+ receiver + case StaticFunctionCall(_, _, _, _, _, params: Seq[_]) => params.map(p => p.asVar).toList.reverse case _ => throw new RuntimeException("Unknown expression: " + expr) } } diff --git a/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootScopeTest.java b/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootScopeTest.java index c51fa893e..cc82ef76c 100644 --- a/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootScopeTest.java +++ b/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootScopeTest.java @@ -20,7 +20,6 @@ import boomerang.scope.test.targets.A; import boomerang.scope.test.targets.HashCodeEqualsLocalTarget; import boomerang.scope.test.targets.ParameterLocalsTarget; -import boomerang.scope.test.targets.SingleTarget; import boomerang.scope.test.targets.ThisLocalTarget; import java.util.List; import org.junit.Assert; @@ -138,20 +137,4 @@ public void hashCodeEqualsLocalTest() { Assert.fail("Did not check equals and hashCode methods for parameter locals"); } } - - @Test - public void fieldStoreAssignmentTest() { - SootSetup sootSetup = new SootSetup(); - sootSetup.setupSoot(SingleTarget.class.getName()); - - // Parameter locals - MethodSignature signature = - new MethodSignature(SingleTarget.class.getName(), "branching2", "int"); - SootMethod method = sootSetup.resolveMethod(signature); - BoomerangPretransformer.v().apply(); - Method jimpleMethod = JimpleMethod.of(method); - jimpleMethod.getControlFlowGraph().getStatements(); - - System.out.println(method.getActiveBody()); - } } diff --git a/pom.xml b/pom.xml index 3dacfecba..1d1d5ea99 100644 --- a/pom.xml +++ b/pom.xml @@ -302,6 +302,13 @@ 3.5.3 -Xmx8G -Xss128m + + + testSetup + + ${testSetup} + + @@ -333,6 +340,42 @@ + + + enforce-test-setup-property + + + !skipTests + + + + + + org.apache.maven.plugins + maven-enforcer-plugin + 3.5.0 + + + enforce-test-setup + + enforce + + test + + + + testSetup + Running the tests requires the testSetup property. Use e.g. -DtestSetup=soot + + + + + + + + + + diff --git a/testCore/src/main/java/test/TestingFramework.java b/testCore/src/main/java/test/TestingFramework.java index 465402360..c3dc1aa25 100644 --- a/testCore/src/main/java/test/TestingFramework.java +++ b/testCore/src/main/java/test/TestingFramework.java @@ -22,15 +22,42 @@ import java.util.stream.Collectors; import org.junit.Assert; import test.setup.OpalTestSetup; +import test.setup.SootTestSetup; +import test.setup.SootUpTestSetup; import test.setup.TestSetup; public class TestingFramework { + private static final String SOOT = "soot"; + private static final String SOOT_UP = "sootup"; + private static final String OPAL = "opal"; + private final TestSetup testSetup; public TestingFramework() { - // TODO Parameterize - this.testSetup = new OpalTestSetup(); + this.testSetup = getTestSetup(); + } + + private TestSetup getTestSetup() { + String framework = System.getProperty("testSetup"); + if (framework == null) { + // This can be changed when executing tests locally + return new SootTestSetup(); + } + + switch (framework.toLowerCase()) { + case SOOT: + return new SootTestSetup(); + case SOOT_UP: + return new SootUpTestSetup(); + case OPAL: + return new OpalTestSetup(); + default: + throw new IllegalArgumentException( + "Cannot create test setup for framework " + + framework + + ". Available options are {Soot, SootUp, Opal}"); + } } public FrameworkScope getFrameworkScope(MethodWrapper methodWrapper) { From 28be871f06a26990edc513da9a60b9fad077bbf2 Mon Sep 17 00:00:00 2001 From: Sven Meyer Date: Wed, 23 Apr 2025 18:17:58 +0200 Subject: [PATCH 54/61] Add job to create GitHub release automatically --- .github/workflows/deploy.yml | 19 +++++++++++++++++++ .github/workflows/maven.yml | 2 +- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 2a2dd1a4c..481c038a8 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -59,3 +59,22 @@ jobs: gh pr create --draft -B develop -H ${{ env.BRANCH_NAME }} -t "Update to next SNAPSHOT version" -b "Update to next SNAPSHOT version" env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + release: + runs-on: ubuntu-latest + needs: deployment + steps: + - name: Checkout source code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Get latest tag + run: echo "tag=$(git describe --tags --abbrev=0)" >> $GITHUB_OUTPUT + + - name: Create GitHub release + run: | + gh release create "$TAG" + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + TAG: ${{ steps.get_tag.outputs.tag }} diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 04f732906..73e1c1032 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -13,7 +13,7 @@ jobs: BuildAndTest: strategy: matrix: - framework: [soot, opal] # TODO Add SootUp when available + framework: [Soot, Opal] # TODO Add SootUp when available runs-on: ubuntu-latest steps: - name: Checkout source code From af5a6dbf7bd70fb199d6629c33e13021b9c6160b Mon Sep 17 00:00:00 2001 From: Sven Meyer Date: Wed, 23 Apr 2025 18:23:26 +0200 Subject: [PATCH 55/61] (MINOR) version update and update README --- README.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 7c146c770..b2e0d3e55 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ This repository contains: - a Java implementation of [Synchronized Pushdown Systems](https://digital.ub.uni-paderborn.de/hs/content/titleinfo/3030984). - [Boomerang](boomerangPDS) to calculate on-demand points-to and dataflow information using a Synchronized Pushdown System. - [IDEal](idealPDS), an IDE solver based on a [Weighted Pushdown System](https://www.bodden.de/pubs/sab19context.pdf) that uses Boomerang to compute alias information only when required (i.e. on-demand). -- Implementation of scopes that allows you to run Boomerang and IDEal with the static analysis frameworks Soot. +- Implementation of scopes that allows you to run Boomerang and IDEal with the static analysis frameworks Soot and Opal. ## Examples @@ -38,6 +38,14 @@ The projects are released on [Maven Central](https://central.sonatype.com/artifa ``` +## Build and Installation +If you plan to install Boomerang and IDEal locally, you can use the following commands to build the project: + +- `mvn clean install -DskipTests` Install the projects and skip all tests +- `mvn clean install -DtestSetup=Soot` Install the projects and run the tests with Soot as the underlying framework +- `mvn clean install -DtestSetup=SootUp` Install the projects and run the tests with SootUp as the underlying framework +- `mvn clean install -DtestSetup=Opal` Install the projects and run the tests with Opal as the underlying framework + ## Contributing We hare happy for every contribution from the community! You can simply create a fork and open a pull request. Note that we use the Google style sheet to keep the code clean. To format the code, run the command From 59d5d8390175d7d54f7eae9d55ad2f08942f59b5 Mon Sep 17 00:00:00 2001 From: Sven Meyer Date: Wed, 23 Apr 2025 18:31:18 +0200 Subject: [PATCH 56/61] Rename statements --- .../DefaultBackwardFlowFunction.java | 40 +++++++++--------- .../DefaultForwardFlowFunction.java | 42 +++++++++---------- 2 files changed, 41 insertions(+), 41 deletions(-) diff --git a/boomerangPDS/src/main/java/boomerang/flowfunction/DefaultBackwardFlowFunction.java b/boomerangPDS/src/main/java/boomerang/flowfunction/DefaultBackwardFlowFunction.java index 1c8d839a0..6d5d5386c 100644 --- a/boomerangPDS/src/main/java/boomerang/flowfunction/DefaultBackwardFlowFunction.java +++ b/boomerangPDS/src/main/java/boomerang/flowfunction/DefaultBackwardFlowFunction.java @@ -98,69 +98,69 @@ public Collection callFlow(Statement callSite, Val fact, Method callee, Sta @Override public Collection normalFlow(Edge currEdge, Edge nextEdge, Val fact) { - Statement curr = nextEdge.getTarget(); - if (options.allocationSite().getAllocationSite(curr.getMethod(), curr, fact).isPresent()) { + Statement nextStmt = nextEdge.getTarget(); + if (options.allocationSite().getAllocationSite(nextStmt.getMethod(), nextStmt, fact).isPresent()) { return Collections.emptySet(); } - if (curr.isThrowStmt()) { + if (nextStmt.isThrowStmt()) { return Collections.emptySet(); } Set out = new LinkedHashSet<>(); boolean leftSideMatches = false; - if (curr.isAssignStmt()) { - Val leftOp = curr.getLeftOp(); - Val rightOp = curr.getRightOp(); + if (nextStmt.isAssignStmt()) { + Val leftOp = nextStmt.getLeftOp(); + Val rightOp = nextStmt.getRightOp(); if (leftOp.equals(fact)) { leftSideMatches = true; - if (curr.isFieldLoad()) { + if (nextStmt.isFieldLoad()) { if (options.trackFields()) { - Pair ifr = curr.getFieldLoad(); + Pair ifr = nextStmt.getFieldLoad(); if (options.includeInnerClassFields() || !ifr.getY().isInnerClassField()) { out.add(new PushNode<>(nextEdge, ifr.getX(), ifr.getY(), PDSSystem.FIELDS)); } } - } else if (curr.isStaticFieldLoad()) { + } else if (nextStmt.isStaticFieldLoad()) { if (options.trackFields()) { strategies .getStaticFieldStrategy() - .handleBackward(currEdge, curr.getLeftOp(), curr.getStaticField(), out); + .handleBackward(currEdge, nextStmt.getLeftOp(), nextStmt.getStaticField(), out); } } else if (rightOp.isArrayRef()) { - Pair arrayBase = curr.getArrayBase(); + Pair arrayBase = nextStmt.getArrayBase(); if (options.trackFields()) { strategies.getArrayHandlingStrategy().handleBackward(nextEdge, arrayBase, out); } } else if (rightOp.isCast()) { out.add(new Node<>(nextEdge, rightOp.getCastOp())); - } else if (curr.isPhiStatement()) { - Collection phiVals = curr.getPhiVals(); + } else if (nextStmt.isPhiStatement()) { + Collection phiVals = nextStmt.getPhiVals(); for (Val v : phiVals) { out.add(new Node<>(nextEdge, v)); } } else { - if (curr.isFieldLoadWithBase(fact)) { - out.add(new ExclusionNode<>(nextEdge, fact, curr.getLoadedField())); + if (nextStmt.isFieldLoadWithBase(fact)) { + out.add(new ExclusionNode<>(nextEdge, fact, nextStmt.getLoadedField())); } else { out.add(new Node<>(nextEdge, rightOp)); } } } - if (curr.isFieldStore()) { - Pair ifr = curr.getFieldStore(); + if (nextStmt.isFieldStore()) { + Pair ifr = nextStmt.getFieldStore(); Val base = ifr.getX(); if (base.equals(fact)) { NodeWithLocation succNode = new NodeWithLocation<>(nextEdge, rightOp, ifr.getY()); out.add(new PopNode<>(succNode, PDSSystem.FIELDS)); } - } else if (curr.isStaticFieldStore()) { - StaticFieldVal staticField = curr.getStaticField(); + } else if (nextStmt.isStaticFieldStore()) { + StaticFieldVal staticField = nextStmt.getStaticField(); if (fact.isStatic() && fact.equals(staticField)) { out.add(new Node<>(nextEdge, rightOp)); } } else if (leftOp.isArrayRef()) { - Pair arrayBase = curr.getArrayBase(); + Pair arrayBase = nextStmt.getArrayBase(); if (arrayBase.getX().equals(fact)) { NodeWithLocation succNode = new NodeWithLocation<>(nextEdge, rightOp, Field.array(arrayBase.getY())); diff --git a/boomerangPDS/src/main/java/boomerang/flowfunction/DefaultForwardFlowFunction.java b/boomerangPDS/src/main/java/boomerang/flowfunction/DefaultForwardFlowFunction.java index 959ab1be8..07c792169 100644 --- a/boomerangPDS/src/main/java/boomerang/flowfunction/DefaultForwardFlowFunction.java +++ b/boomerangPDS/src/main/java/boomerang/flowfunction/DefaultForwardFlowFunction.java @@ -103,39 +103,39 @@ public Set callFlow(Statement callSite, Val fact, Method callee) { @Override public Set normalFlow(ForwardQuery query, Edge nextEdge, Val fact) { - Statement succ = nextEdge.getStart(); + Statement nextStmt = nextEdge.getStart(); Set out = new LinkedHashSet<>(); - if (killFlow(succ, fact)) { + if (killFlow(nextStmt, fact)) { return out; } - if (!succ.isFieldWriteWithBase(fact)) { + if (!nextStmt.isFieldWriteWithBase(fact)) { // always maintain data-flow if not a field write // killFlow has // been taken care of if (!options.trackReturnOfInstanceOf() - || !(query.getType().isNullType() && succ.isInstanceOfStatement(fact))) { + || !(query.getType().isNullType() && nextStmt.isInstanceOfStatement(fact))) { out.add(new Node<>(nextEdge, fact)); } } else { - out.add(new ExclusionNode<>(nextEdge, fact, succ.getWrittenField())); + out.add(new ExclusionNode<>(nextEdge, fact, nextStmt.getWrittenField())); } - if (succ.isAssignStmt()) { - Val leftOp = succ.getLeftOp(); - Val rightOp = succ.getRightOp(); + if (nextStmt.isAssignStmt()) { + Val leftOp = nextStmt.getLeftOp(); + Val rightOp = nextStmt.getRightOp(); if (rightOp.equals(fact)) { - if (succ.isFieldStore()) { - Pair ifr = succ.getFieldStore(); + if (nextStmt.isFieldStore()) { + Pair ifr = nextStmt.getFieldStore(); if (options.trackFields()) { if (options.includeInnerClassFields() || !ifr.getY().isInnerClassField()) { out.add(new PushNode<>(nextEdge, ifr.getX(), ifr.getY(), PDSSystem.FIELDS)); } } - } else if (succ.isStaticFieldStore()) { - StaticFieldVal sf = succ.getStaticField(); + } else if (nextStmt.isStaticFieldStore()) { + StaticFieldVal sf = nextStmt.getStaticField(); if (options.trackFields()) { strategies.getStaticFieldStrategy().handleForward(nextEdge, rightOp, sf, out); } } else if (leftOp.isArrayRef()) { - Pair arrayBase = succ.getArrayBase(); + Pair arrayBase = nextStmt.getArrayBase(); if (options.trackFields()) { strategies.getArrayHandlingStrategy().handleForward(nextEdge, arrayBase, out); } @@ -143,20 +143,20 @@ public Set normalFlow(ForwardQuery query, Edge nextEdge, Val fact) { out.add(new Node<>(nextEdge, leftOp)); } } - if (succ.isFieldLoad()) { - Pair ifr = succ.getFieldLoad(); + if (nextStmt.isFieldLoad()) { + Pair ifr = nextStmt.getFieldLoad(); if (ifr.getX().equals(fact)) { NodeWithLocation succNode = new NodeWithLocation<>(nextEdge, leftOp, ifr.getY()); out.add(new PopNode<>(succNode, PDSSystem.FIELDS)); } - } else if (succ.isStaticFieldLoad()) { - StaticFieldVal sf = succ.getStaticField(); + } else if (nextStmt.isStaticFieldLoad()) { + StaticFieldVal sf = nextStmt.getStaticField(); if (fact.isStatic() && fact.equals(sf)) { out.add(new Node<>(nextEdge, leftOp)); } } else if (rightOp.isArrayRef()) { - Pair arrayBase = succ.getArrayBase(); + Pair arrayBase = nextStmt.getArrayBase(); if (arrayBase.getX().equals(fact)) { NodeWithLocation succNode = new NodeWithLocation<>(nextEdge, leftOp, Field.array(arrayBase.getY())); @@ -172,10 +172,10 @@ public Set normalFlow(ForwardQuery query, Edge nextEdge, Val fact) { if (rightOp.getInstanceOfOp().equals(fact)) { out.add(new Node<>(nextEdge, fact.withSecondVal(leftOp))); } - } else if (succ.isPhiStatement()) { - Collection phiVals = succ.getPhiVals(); + } else if (nextStmt.isPhiStatement()) { + Collection phiVals = nextStmt.getPhiVals(); if (phiVals.contains(fact)) { - out.add(new Node<>(nextEdge, succ.getLeftOp())); + out.add(new Node<>(nextEdge, nextStmt.getLeftOp())); } } } From 19be7ed0041fab8ff7748f0e43545a546e1a48c3 Mon Sep 17 00:00:00 2001 From: Sven Meyer Date: Wed, 23 Apr 2025 18:33:20 +0200 Subject: [PATCH 57/61] Style --- .../boomerang/flowfunction/DefaultBackwardFlowFunction.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/boomerangPDS/src/main/java/boomerang/flowfunction/DefaultBackwardFlowFunction.java b/boomerangPDS/src/main/java/boomerang/flowfunction/DefaultBackwardFlowFunction.java index 6d5d5386c..9d1eba996 100644 --- a/boomerangPDS/src/main/java/boomerang/flowfunction/DefaultBackwardFlowFunction.java +++ b/boomerangPDS/src/main/java/boomerang/flowfunction/DefaultBackwardFlowFunction.java @@ -99,7 +99,10 @@ public Collection callFlow(Statement callSite, Val fact, Method callee, Sta @Override public Collection normalFlow(Edge currEdge, Edge nextEdge, Val fact) { Statement nextStmt = nextEdge.getTarget(); - if (options.allocationSite().getAllocationSite(nextStmt.getMethod(), nextStmt, fact).isPresent()) { + if (options + .allocationSite() + .getAllocationSite(nextStmt.getMethod(), nextStmt, fact) + .isPresent()) { return Collections.emptySet(); } if (nextStmt.isThrowStmt()) { From 4154e03c964c32a43746325c395ed31257a439ce Mon Sep 17 00:00:00 2001 From: Sven Meyer Date: Thu, 24 Apr 2025 12:56:26 +0200 Subject: [PATCH 58/61] Add test for TAC body builder --- .../opal/transformation/TacBodyBuilder.scala | 2 +- .../opal/transformation/stack/Operand.scala | 4 +- .../transformation/stack/OperandStack.scala | 2 +- .../stack/OperandStackBuilder.scala | 119 ++++++++++++++++-- .../transformer/LocalTransformer.scala | 52 ++++++-- .../scope/opal/TacBodyBuilderTest.scala | 86 +++++++++++++ 6 files changed, 242 insertions(+), 23 deletions(-) create mode 100644 boomerangScope-Opal/src/test/scala/boomerang/scope/opal/TacBodyBuilderTest.scala diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacBodyBuilder.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacBodyBuilder.scala index 83c18ab46..76f49d854 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacBodyBuilder.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacBodyBuilder.scala @@ -20,7 +20,7 @@ object TacBodyBuilder { // TODO Use other domain to compute static type information val domain = new PrimitiveTACAIDomain(project.classHierarchy, method) - val localTransformedTac = LocalTransformer(method, tacNaive, stackHandler, domain) + val localTransformedTac = LocalTransformer(project, method, tacNaive, stackHandler, domain) assert(tacNaive.stmts.length == localTransformedTac.length, "Wrong transformation") val inlinedTac = InlineLocalTransformer(localTransformedTac, stackHandler) diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/Operand.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/Operand.scala index 97d91cdd6..f79a049f4 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/Operand.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/Operand.scala @@ -1,8 +1,10 @@ package boomerang.scope.opal.transformation.stack +import org.opalj.br.ComputationalType + import java.util.Objects -class Operand(val id: Int, private var counter: Int) { +class Operand(val id: Int, val cTpe: ComputationalType, private var counter: Int) { private var modified = false diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStack.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStack.scala index 335746174..718c1a4ed 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStack.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStack.scala @@ -7,7 +7,7 @@ class OperandStack private(stackHandler: OperandStackHandler, private var stack: def stackEntries: List[Operand] = stack def push(idBasedVar: IdBasedVar): Unit = { - val operand = new Operand(idBasedVar.id, stackHandler.nextLocalCounter) + val operand = new Operand(idBasedVar.id, idBasedVar.cTpe, stackHandler.nextLocalCounter) stack = operand :: stack } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackBuilder.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackBuilder.scala index ca17a33aa..c3cc91347 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackBuilder.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackBuilder.scala @@ -81,36 +81,133 @@ object OperandStackBuilder { schedule(pcOfNextStatement(pc), stack) case ReturnValue(_, expr: IdBasedVar) => - // TODO Bug in Opal: Return instructions return always s0 and not the top operand + // TODO Bug in Opal causes to return the wrong operand (fixed but not released yet) // stack.pop(expr) // No scheduling since there is no next statement case Return(_) => // No scheduling since there is no next statement case Nop(pc) => val instr = method.body.get.instructions(pc) + // TODO + // Use pattern matching from stack.stackEntries to avoid having so many sequential + // operations (as done in TacNaive) instr.opcode match { case NOP.opcode => - case POP.opcode | POP2.opcode => + schedule(pcOfNextStatement(pc), stack) + case POP.opcode => stack.pop + + schedule(pcOfNextStatement(pc), stack) + case POP2.opcode => + val top = stack.pop + if (top.cTpe.categoryId == 1) { + stack.pop + } + + schedule(pcOfNextStatement(pc), stack) case DUP.opcode => val dupOperand = stack.peek stack.push(dupOperand) + + schedule(pcOfNextStatement(pc), stack) case DUP_X1.opcode => - val val1 = stack.pop - val val2 = stack.pop + val v1 = stack.pop + val v2 = stack.pop + + stack.push(v1) + stack.push(v2) + stack.push(v1) - stack.push(val1) - stack.push(val2) - stack.push(val1) + schedule(pcOfNextStatement(pc), stack) case DUP_X2.opcode => - // TODO + val v1 = stack.pop + val v2 = stack.pop + + if (v2.cTpe.categoryId == 1) { + val v3 = stack.pop + + stack.push(v1) + stack.push(v3) + stack.push(v2) + stack.push(v1) + } else { + stack.push(v1) + stack.push(v2) + stack.push(v1) + } + + schedule(pcOfNextStatement(pc), stack) case DUP2.opcode => - // TODO + val v1 = stack.pop + + if (v1.cTpe.categoryId == 1) { + val v2 = stack.pop + + stack.push(v2) + stack.push(v1) + stack.push(v2) + stack.push(v1) + } else { + stack.push(v1) + stack.push(v1) + } + + schedule(pcOfNextStatement(pc), stack) case DUP2_X1.opcode => - // TODO + val v1 = stack.pop + val v2 = stack.pop + + if (v1.cTpe.categoryId == 1) { + val v3 = stack.pop + + stack.push(v2) + stack.push(v1) + stack.push(v3) + stack.push(v2) + stack.push(v1) + } else { + stack.push(v1) + stack.push(v2) + stack.push(v1) + } + + schedule(pcOfNextStatement(pc), stack) case DUP2_X2.opcode => - // TODO + val v1 = stack.pop + val v2 = stack.pop + val v3 = stack.pop + + if (v1.cTpe.categoryId == 1 && v2.cTpe.categoryId == 1 && v3.cTpe.categoryId == 1) { + val v4 = stack.pop + + stack.push(v2) + stack.push(v1) + stack.push(v4) + stack.push(v3) + stack.push(v2) + stack.push(v1) + } else if (v1.cTpe.categoryId == 2 && v2.cTpe.categoryId == 1 && v3.cTpe.categoryId == 1) { + stack.push(v1) + stack.push(v3) + stack.push(v2) + stack.push(v1) + } else if (v1.cTpe.categoryId == 1 && v2.cTpe.categoryId == 1 && v3.cTpe.categoryId == 2) { + stack.push(v2) + stack.push(v1) + stack.push(v3) + stack.push(v2) + stack.push(v1) + } else { + stack.push(v3) + stack.push(v1) + stack.push(v2) + stack.push(v1) + } + + schedule(pcOfNextStatement(pc), stack) case WIDE.opcode => + schedule(pcOfNextStatement(pc), stack) + case _ => throw new RuntimeException("Unknown instruction for NOP: " + instr) } schedule(pcOfNextStatement(pc), stack) diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/LocalTransformer.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/LocalTransformer.scala index 8469ca64a..7fc5195a0 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/LocalTransformer.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/LocalTransformer.scala @@ -3,14 +3,16 @@ package boomerang.scope.opal.transformation.transformer import boomerang.scope.opal.transformation.{ExceptionLocal, ParameterLocal, RegisterLocal, StackLocal, TacLocal} import boomerang.scope.opal.transformation.stack.OperandStackHandler import org.opalj.ai.{AIResult, BaseAI, Domain} -import org.opalj.br.{Method, PC} +import org.opalj.br.analyses.Project +import org.opalj.br.{ComputationalType, ComputationalTypeDouble, ComputationalTypeFloat, ComputationalTypeInt, ComputationalTypeLong, ComputationalTypeReference, ComputationalTypeReturnAddress, DoubleType, FieldType, FloatType, IntegerType, LongType, Method, ObjectType, PC} import org.opalj.tac.{ArrayLength, ArrayLoad, ArrayStore, Assignment, BinaryExpr, CaughtException, Checkcast, ClassConst, Compare, DoubleConst, DynamicConst, Expr, ExprStmt, FloatConst, GetField, GetStatic, Goto, IdBasedVar, If, InstanceOf, IntConst, InvokedynamicFunctionCall, InvokedynamicMethodCall, JSR, LongConst, MethodHandleConst, MethodTypeConst, MonitorEnter, MonitorExit, NaiveTACode, New, NewArray, NonVirtualFunctionCall, NonVirtualMethodCall, Nop, NullExpr, Param, PrefixExpr, PrimitiveTypecastExpr, PutField, PutStatic, Ret, Return, ReturnValue, StaticFunctionCall, StaticMethodCall, Stmt, StringConst, Switch, Throw, VirtualFunctionCall, VirtualMethodCall} +import org.opalj.value.ValueInformation import scala.collection.mutable object LocalTransformer { - def apply(method: Method, tac: NaiveTACode[_], stackHandler: OperandStackHandler, domain: Domain): Array[Stmt[TacLocal]] = { + def apply(project: Project[_], method: Method, tac: NaiveTACode[_], stackHandler: OperandStackHandler, domain: Domain): Array[Stmt[TacLocal]] = { var paramCount = -1 var exceptionCount = -1 val currentLocals = mutable.Map.empty[Int, TacLocal] @@ -150,10 +152,15 @@ object LocalTransformer { def createStackLocal(pc: PC, idBasedVar: IdBasedVar, isThis: Boolean): TacLocal = { val nextPc = method.body.get.pcOfNextInstruction(pc) - val value = operandsArray(nextPc).head - + val value = operandsArray(nextPc) val counter = stackHandler.defSiteAtPc(pc) - new StackLocal(counter, idBasedVar.cTpe, value, isThis) + + if (value == null) { + val fieldType = computationalTypeToFieldType(idBasedVar.cTpe) + new StackLocal(counter, idBasedVar.cTpe, ValueInformation.forProperValue(fieldType)(project.classHierarchy), isThis) + } else { + new StackLocal(counter, idBasedVar.cTpe, value.head, isThis) + } } def createRegisterLocal(pc: PC, idBasedVar: IdBasedVar, isThis: Boolean): TacLocal = { @@ -164,16 +171,43 @@ object LocalTransformer { val local = method.body.get.localVariable(nextPc, index) if (local.isDefined) { - return new RegisterLocal(idBasedVar.id, idBasedVar.cTpe, locals(index), isThis, Option(local.get.name)) + if (locals == null) { + val fieldType = computationalTypeToFieldType(idBasedVar.cTpe) + return new RegisterLocal(idBasedVar.id, idBasedVar.cTpe, ValueInformation.forProperValue(fieldType)(project.classHierarchy), isThis, Option(local.get.name)) + } else { + return new RegisterLocal(idBasedVar.id, idBasedVar.cTpe, locals(index), isThis, Option(local.get.name)) + } } - new RegisterLocal(idBasedVar.id, idBasedVar.cTpe, locals(index), isThis) + if (locals == null) { + val fieldType = computationalTypeToFieldType(idBasedVar.cTpe) + new RegisterLocal(idBasedVar.id, idBasedVar.cTpe, ValueInformation.forProperValue(fieldType)(project.classHierarchy), isThis) + } else { + new RegisterLocal(idBasedVar.id, idBasedVar.cTpe, locals(index), isThis) + } } def createExceptionLocal(pc: PC, idBasedVar: IdBasedVar, localId: Int): TacLocal = { - val value = operandsArray(pc).head + val value = operandsArray(pc) - new ExceptionLocal(localId, idBasedVar.cTpe, value) + if (value == null) { + val fieldType = computationalTypeToFieldType(idBasedVar.cTpe) + new ExceptionLocal(localId, idBasedVar.cTpe, ValueInformation.forProperValue(fieldType)(project.classHierarchy)) + } else { + new ExceptionLocal(localId, idBasedVar.cTpe, value.head) + } + } + + def computationalTypeToFieldType(cTpe: ComputationalType): FieldType = { + cTpe match { + case ComputationalTypeInt => IntegerType + case ComputationalTypeFloat => FloatType + case ComputationalTypeLong => LongType + case ComputationalTypeDouble => DoubleType + case ComputationalTypeReference => ObjectType.Object + case ComputationalTypeReturnAddress => ObjectType.Object + case _ => throw new RuntimeException("Unknown computational type " + cTpe) + } } def transformExpr(pc: PC, expr: Expr[IdBasedVar]): Expr[TacLocal] = { diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/TacBodyBuilderTest.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/TacBodyBuilderTest.scala new file mode 100644 index 000000000..a66f9b1ff --- /dev/null +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/TacBodyBuilderTest.scala @@ -0,0 +1,86 @@ +package boomerang.scope.opal + +import boomerang.scope.opal.transformation.TacBodyBuilder +import org.junit.Test +import org.opalj.br.Method +import org.opalj.br.analyses.Project +import org.opalj.log.{DevNullLogger, GlobalLogContext, OPALLogger} + +import java.io.File +import java.net.URI +import java.nio.file.{FileSystems, Files, Paths, StandardCopyOption} +import scala.collection.mutable.ArrayBuffer +import scala.jdk.CollectionConverters._ + +class TacBodyBuilderTest { + + @Test + def applyTacBodyBuilderTest(): Unit = { + OPALLogger.updateLogger(GlobalLogContext, DevNullLogger) + val jdkFiles = loadJDKFiles() + + val project = Project(jdkFiles, Array.empty[File]) + project.allProjectClassFiles.foreach(cf => { + cf.methods.foreach(method => { + if (!isOnIgnoreList(method)) { + TacBodyBuilder(project, method) + } + }) + }) + } + + def isOnIgnoreList(method: Method): Boolean = { + // No existing body -> No transformation possible + if (method.body.isEmpty) return true + + // Consider only java.lang package classes to reduce the number of classes + // TODO + // Maybe create additional tests for other packages (java.io, java.util) that run in parallel. + // Running them sequential would take too long + if (!method.toJava.startsWith("java.lang.")) return true + + // Static initializers may be very complex and take some time to compute (e.g. com.sun.crypto.provider.AESCrypt) + if (method.isStaticInitializer) return true + + // Bug in Opal causes an exception + if (method.toJava.equals("java.lang.Thread{ private static long nextThreadID() }")) return true + if (method.toJava.equals("java.util.concurrent.CompletableFuture$Signaller{ public boolean isReleasable() }")) return true + + false + } + + def loadJDKFiles(): Array[File] = { + val javaHome = sys.env("JAVA_HOME") + val jmodPath = Paths.get(javaHome, "jmods", "java.base.jmod") + + val outputDir = Paths.get("extracted_classes") + Files.createDirectories(outputDir) + + val classFiles = ArrayBuffer[File]() + + // Open the .jmod file as a zip filesystem + val uri = URI.create(s"jar:${jmodPath.toUri}") + val env = Map("create" -> "false").asJava + + val fs = FileSystems.newFileSystem(uri, env) + val rootPath = fs.getPath("/classes") + + // Walk the file tree inside the jmod's /classes directory + Files.walk(rootPath).iterator().asScala + .filter(p => Files.isRegularFile(p) && p.toString.endsWith(".class")) + .foreach { classPath => + val relativePath = rootPath.relativize(classPath) + val targetPath = outputDir.resolve(relativePath.toString) + + Files.createDirectories(targetPath.getParent) + Files.copy(classPath, targetPath, StandardCopyOption.REPLACE_EXISTING) + + classFiles += targetPath.toFile + } + + fs.close() + + classFiles.toArray + } + +} From 620303ded94fa68c8f9356abe321c10eab26ec94 Mon Sep 17 00:00:00 2001 From: Sven Meyer Date: Thu, 24 Apr 2025 13:19:17 +0200 Subject: [PATCH 59/61] Add style guide for Scala code --- .../boomerang/scope/opal/OpalCallGraph.scala | 196 ++-- .../boomerang/scope/opal/OpalClient.scala | 40 +- .../scope/opal/OpalFrameworkScope.scala | 42 +- .../scope/opal/tac/OpalArrayRef.scala | 122 ++- .../scope/opal/tac/OpalControlFlowGraph.scala | 174 ++-- .../scope/opal/tac/OpalDeclaredMethod.scala | 88 +- .../scope/opal/tac/OpalDoubleVal.scala | 47 +- .../boomerang/scope/opal/tac/OpalField.scala | 43 +- .../scope/opal/tac/OpalIfStatement.scala | 67 +- .../scope/opal/tac/OpalInstanceFieldRef.scala | 126 ++- .../scope/opal/tac/OpalInvokeExpr.scala | 140 +-- .../boomerang/scope/opal/tac/OpalLocal.scala | 150 +-- .../boomerang/scope/opal/tac/OpalMethod.scala | 175 ++-- .../scope/opal/tac/OpalNullType.scala | 37 +- .../scope/opal/tac/OpalPhantomMethod.scala | 98 +- .../opal/tac/OpalPhantomWrappedClass.scala | 38 +- .../scope/opal/tac/OpalStatement.scala | 605 ++++++------ .../opal/tac/OpalStatementFormatter.scala | 144 +-- .../scope/opal/tac/OpalStaticFieldRef.scala | 128 ++- .../scope/opal/tac/OpalStaticFieldVal.scala | 43 +- .../boomerang/scope/opal/tac/OpalType.scala | 99 +- .../boomerang/scope/opal/tac/OpalVal.scala | 273 +++--- .../scope/opal/tac/OpalWrappedClass.scala | 70 +- .../opal/transformation/BoomerangTACode.scala | 26 +- .../scope/opal/transformation/StmtGraph.scala | 291 +++--- .../opal/transformation/TacBodyBuilder.scala | 87 +- .../scope/opal/transformation/TacLocal.scala | 196 ++-- .../opal/transformation/stack/Operand.scala | 46 +- .../transformation/stack/OperandStack.scala | 93 +- .../stack/OperandStackBuilder.scala | 639 +++++++------ .../stack/OperandStackHandler.scala | 137 +-- .../transformer/InlineLocalTransformer.scala | 243 +++-- .../LocalPropagationTransformer.scala | 723 ++++++++++----- .../transformer/LocalTransformer.scala | 865 ++++++++++++------ .../transformer/NopEliminator.scala | 30 +- .../transformer/NopTransformer.scala | 86 +- .../NullifyFieldsTransformer.scala | 123 ++- .../boomerang/scope/opal/OpalArrayTest.scala | 248 ++--- .../scope/opal/OpalAssignmentTest.scala | 274 +++--- .../scope/opal/OpalControlFlowGraphTest.scala | 58 +- .../boomerang/scope/opal/OpalFieldTest.scala | 402 ++++---- .../scope/opal/OpalInvokeExprTest.scala | 156 ++-- .../boomerang/scope/opal/OpalLocalTest.scala | 162 ++-- .../boomerang/scope/opal/OpalSetup.scala | 69 +- .../scope/opal/TacBodyBuilderTest.scala | 170 ++-- misc/.scalafmt.conf | 46 + pom.xml | 8 + 47 files changed, 5014 insertions(+), 3109 deletions(-) create mode 100644 misc/.scalafmt.conf diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalCallGraph.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalCallGraph.scala index 10ae33827..a3a49f21b 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalCallGraph.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalCallGraph.scala @@ -1,98 +1,144 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ package boomerang.scope.opal -import boomerang.scope.{CallGraph, InvokeExpr} +import boomerang.scope.CallGraph import boomerang.scope.CallGraph.Edge -import boomerang.scope.opal.tac.{OpalFunctionInvokeExpr, OpalMethod, OpalMethodInvokeExpr, OpalPhantomMethod, OpalStatement} +import boomerang.scope.InvokeExpr +import boomerang.scope.opal.tac.OpalFunctionInvokeExpr +import boomerang.scope.opal.tac.OpalMethod +import boomerang.scope.opal.tac.OpalMethodInvokeExpr +import boomerang.scope.opal.tac.OpalPhantomMethod +import boomerang.scope.opal.tac.OpalStatement import boomerang.scope.opal.transformation.TacBodyBuilder +import org.opalj.br.DefinedMethod +import org.opalj.br.Method +import org.opalj.br.MultipleDefinedMethods +import org.opalj.br.VirtualDeclaredMethod import org.opalj.br.analyses.Project -import org.opalj.br.{DefinedMethod, Method, MultipleDefinedMethods, VirtualDeclaredMethod} -import org.opalj.tac.{NonVirtualFunctionCall, StaticFunctionCall, VirtualFunctionCall} +import org.opalj.tac.NonVirtualFunctionCall +import org.opalj.tac.StaticFunctionCall +import org.opalj.tac.VirtualFunctionCall -class OpalCallGraph(project: Project[_], callGraph: org.opalj.tac.cg.CallGraph, entryPoints: Set[Method]) extends CallGraph { +class OpalCallGraph( + project: Project[_], + callGraph: org.opalj.tac.cg.CallGraph, + entryPoints: Set[Method] +) extends CallGraph { - // TODO Deal with - callGraph.reachableMethods().foreach(method => { - method.method match { - case definedMethod: DefinedMethod => - if (definedMethod.definedMethod.body.isDefined) { - addEdgesFromMethod(definedMethod) - } - // TODO Should this case be considered? - // case definedMethods: MultipleDefinedMethods => - // definedMethods.foreachDefinedMethod(m => addEdgesFromMethod(m)) - case _ => - } - }) + // TODO Deal with + callGraph + .reachableMethods() + .foreach(method => { + method.method match { + case definedMethod: DefinedMethod => + if (definedMethod.definedMethod.body.isDefined) { + addEdgesFromMethod(definedMethod) + } + // TODO Should this case be considered? + // case definedMethods: MultipleDefinedMethods => + // definedMethods.foreachDefinedMethod(m => addEdgesFromMethod(m)) + case _ => + } + }) - private def addEdgesFromMethod(method: DefinedMethod): Unit = { - val tacCode = TacBodyBuilder(project, method.definedMethod) + private def addEdgesFromMethod(method: DefinedMethod): Unit = { + val tacCode = TacBodyBuilder(project, method.definedMethod) - tacCode.statements.foreach(stmt => { - val srcStatement = new OpalStatement(stmt, OpalMethod(method.definedMethod, tacCode)) + tacCode.statements.foreach(stmt => { + val srcStatement = + new OpalStatement(stmt, OpalMethod(method.definedMethod, tacCode)) - if (srcStatement.containsInvokeExpr()) { - // Due to inlining variables, the PC's of statements and invoke expressions may differ - val invokeExprPc = getPcForInvokeExpr(srcStatement.getInvokeExpr) - val callees = callGraph.directCalleesOf(method, invokeExprPc) + if (srcStatement.containsInvokeExpr()) { + // Due to inlining variables, the PC's of statements and invoke expressions may differ + val invokeExprPc = getPcForInvokeExpr(srcStatement.getInvokeExpr) + val callees = callGraph.directCalleesOf(method, invokeExprPc) - callees.foreach(callee => { - callee.method match { - case definedMethod: DefinedMethod => - val method = definedMethod.definedMethod + callees.foreach(callee => { + callee.method match { + case definedMethod: DefinedMethod => + val method = definedMethod.definedMethod - if (method.body.isDefined) { - val targetMethod = OpalMethod(method) + if (method.body.isDefined) { + val targetMethod = OpalMethod(method) - addEdge(new Edge(srcStatement, targetMethod)) - } else { - val targetMethod = OpalPhantomMethod(definedMethod.declaringClassType, definedMethod.name, definedMethod.descriptor, method.isStatic) + addEdge(new Edge(srcStatement, targetMethod)) + } else { + val targetMethod = OpalPhantomMethod( + definedMethod.declaringClassType, + definedMethod.name, + definedMethod.descriptor, + method.isStatic + ) - addEdge(new Edge(srcStatement, targetMethod)) - } - case virtualMethod: VirtualDeclaredMethod => - val targetMethod = OpalPhantomMethod(virtualMethod.declaringClassType, virtualMethod.name, virtualMethod.descriptor, srcStatement.getInvokeExpr.isStaticInvokeExpr) + addEdge(new Edge(srcStatement, targetMethod)) + } + case virtualMethod: VirtualDeclaredMethod => + val targetMethod = OpalPhantomMethod( + virtualMethod.declaringClassType, + virtualMethod.name, + virtualMethod.descriptor, + srcStatement.getInvokeExpr.isStaticInvokeExpr + ) - addEdge(new Edge(srcStatement, targetMethod)) - case definedMethods: MultipleDefinedMethods => - definedMethods.foreachDefinedMethod(method => { - val targetMethod = OpalMethod(method) + addEdge(new Edge(srcStatement, targetMethod)) + case definedMethods: MultipleDefinedMethods => + definedMethods.foreachDefinedMethod(method => { + val targetMethod = OpalMethod(method) - addEdge(new Edge(srcStatement, targetMethod)) - }) - } + addEdge(new Edge(srcStatement, targetMethod)) + }) + } + }) + } }) - } - }) - } - - private def getPcForInvokeExpr(invokeExpr: InvokeExpr): Int = { - invokeExpr match { - case methodInvokeExpr: OpalMethodInvokeExpr => methodInvokeExpr.delegate.pc - case functionInvokeExpr: OpalFunctionInvokeExpr => - functionInvokeExpr.delegate match { - case call: NonVirtualFunctionCall[_] => call.pc - case call: VirtualFunctionCall[_] => call.pc - case call: StaticFunctionCall[_] => call.pc - case _ => throw new RuntimeException("Unknown function call: " + functionInvokeExpr) - } - case _ => throw new RuntimeException("Unknown invoke expression: " + invokeExpr) } - } - // Explicitly add static initializers () as they are called only implicitly - callGraph.reachableMethods().foreach(method => { - method.method match { - case definedMethod: DefinedMethod if definedMethod.definedMethod.isStaticInitializer => - if (definedMethod.definedMethod.body.isDefined) { - addEntryPoint(OpalMethod(definedMethod.definedMethod)) + private def getPcForInvokeExpr(invokeExpr: InvokeExpr): Int = { + invokeExpr match { + case methodInvokeExpr: OpalMethodInvokeExpr => + methodInvokeExpr.delegate.pc + case functionInvokeExpr: OpalFunctionInvokeExpr => + functionInvokeExpr.delegate match { + case call: NonVirtualFunctionCall[_] => call.pc + case call: VirtualFunctionCall[_] => call.pc + case call: StaticFunctionCall[_] => call.pc + case _ => + throw new RuntimeException( + "Unknown function call: " + functionInvokeExpr + ) + } + case _ => + throw new RuntimeException("Unknown invoke expression: " + invokeExpr) } - case _ => } - }) - entryPoints.foreach(entryPoint => { - if (entryPoint.body.isDefined) { - addEntryPoint(OpalMethod(entryPoint)) - } - }) + // Explicitly add static initializers () as they are called only implicitly + callGraph + .reachableMethods() + .foreach(method => { + method.method match { + case definedMethod: DefinedMethod + if definedMethod.definedMethod.isStaticInitializer => + if (definedMethod.definedMethod.body.isDefined) { + addEntryPoint(OpalMethod(definedMethod.definedMethod)) + } + case _ => + } + }) + + entryPoints.foreach(entryPoint => { + if (entryPoint.body.isDefined) { + addEntryPoint(OpalMethod(entryPoint)) + } + }) } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalClient.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalClient.scala index a5b1f0e29..5085bc8de 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalClient.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalClient.scala @@ -1,20 +1,42 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ package boomerang.scope.opal -import org.opalj.br.{ClassFile, ClassHierarchy, DefinedMethod, Field, Method, MethodDescriptor, ObjectType, ReferenceType} -import org.opalj.br.analyses.{DeclaredMethods, DeclaredMethodsKey, Project} +import org.opalj.br.ClassFile +import org.opalj.br.ClassHierarchy +import org.opalj.br.DefinedMethod +import org.opalj.br.Field +import org.opalj.br.Method +import org.opalj.br.MethodDescriptor +import org.opalj.br.ObjectType +import org.opalj.br.ReferenceType +import org.opalj.br.analyses.DeclaredMethods +import org.opalj.br.analyses.DeclaredMethodsKey +import org.opalj.br.analyses.Project object OpalClient { - var project: Option[Project[_]] = None + var project: Option[Project[_]] = None - def init(p: Project[_]): Unit = { - project = Some(p) - } + def init(p: Project[_]): Unit = { + project = Some(p) + } - def getClassHierarchy: ClassHierarchy = project.get.classHierarchy + def getClassHierarchy: ClassHierarchy = project.get.classHierarchy - def getClassFileForType(objectType: ObjectType): Option[ClassFile] = project.get.classFile(objectType) + def getClassFileForType(objectType: ObjectType): Option[ClassFile] = + project.get.classFile(objectType) - def isApplicationClass(classFile: ClassFile): Boolean = project.get.allProjectClassFiles.toSet.contains(classFile) + def isApplicationClass(classFile: ClassFile): Boolean = + project.get.allProjectClassFiles.toSet.contains(classFile) } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalFrameworkScope.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalFrameworkScope.scala index fdf7fc8e9..d76317d75 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalFrameworkScope.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalFrameworkScope.scala @@ -1,29 +1,45 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ package boomerang.scope.opal import boomerang.scope._ -import org.opalj.br.analyses.Project - import java.util.stream +import org.opalj.br.analyses.Project -class OpalFrameworkScope(project: Project[_], callGraph: org.opalj.tac.cg.CallGraph, entryPoints: Set[org.opalj.br.Method], dataFlowScope: DataFlowScope) extends FrameworkScope { +class OpalFrameworkScope( + project: Project[_], + callGraph: org.opalj.tac.cg.CallGraph, + entryPoints: Set[org.opalj.br.Method], + dataFlowScope: DataFlowScope +) extends FrameworkScope { - OpalClient.init(project) - private val opalCallGraph = new OpalCallGraph(project, callGraph, entryPoints) + OpalClient.init(project) + private val opalCallGraph = new OpalCallGraph(project, callGraph, entryPoints) - override def getCallGraph: CallGraph = opalCallGraph + override def getCallGraph: CallGraph = opalCallGraph - override def getDataFlowScope: DataFlowScope = dataFlowScope + override def getDataFlowScope: DataFlowScope = dataFlowScope - override def getTrueValue(m: Method): Val = ??? + override def getTrueValue(m: Method): Val = ??? - override def getFalseValue(m: Method): Val = ??? + override def getFalseValue(m: Method): Val = ??? - override def handleStaticFieldInitializers(fact: Val): stream.Stream[Method] = ??? + override def handleStaticFieldInitializers(fact: Val): stream.Stream[Method] = + ??? - override def newStaticFieldVal(field: Field, m: Method): StaticFieldVal = ??? + override def newStaticFieldVal(field: Field, m: Method): StaticFieldVal = ??? } object OpalFrameworkScope { - final val STATIC_INITIALIZER: String = "" - final val CONSTRUCTOR: String = "" + final val STATIC_INITIALIZER: String = "" + final val CONSTRUCTOR: String = "" } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalArrayRef.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalArrayRef.scala index 10aa442ff..30af01cf3 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalArrayRef.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalArrayRef.scala @@ -1,82 +1,120 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ package boomerang.scope.opal.tac import boomerang.scope._ import boomerang.scope.opal.transformation.TacLocal -import org.opalj.br.ObjectType - import java.util.Objects +import org.opalj.br.ObjectType -class OpalArrayRef(val arrayRef: TacLocal, val index: Int, method: OpalMethod, unbalanced: ControlFlowGraph.Edge = null) extends Val(method, unbalanced) { +class OpalArrayRef( + val arrayRef: TacLocal, + val index: Int, + method: OpalMethod, + unbalanced: ControlFlowGraph.Edge = null +) extends Val(method, unbalanced) { - // TODO Type - override def getType: Type = OpalType(ObjectType.Array) + // TODO Type + override def getType: Type = OpalType(ObjectType.Array) - override def isStatic: Boolean = false + override def isStatic: Boolean = false - override def isNewExpr: Boolean = false + override def isNewExpr: Boolean = false - override def getNewExprType: Type = throw new RuntimeException("Array Value is not a new expression") + override def getNewExprType: Type = throw new RuntimeException( + "Array Value is not a new expression" + ) - override def asUnbalanced(stmt: ControlFlowGraph.Edge): Val = new OpalArrayRef(arrayRef, index, method, stmt) + override def asUnbalanced(stmt: ControlFlowGraph.Edge): Val = + new OpalArrayRef(arrayRef, index, method, stmt) - override def isLocal: Boolean = true + override def isLocal: Boolean = true - override def isArrayAllocationVal: Boolean = false + override def isArrayAllocationVal: Boolean = false - override def getArrayAllocationSize: Val = throw new RuntimeException("Array Value has no allocation size") + override def getArrayAllocationSize: Val = throw new RuntimeException( + "Array Value has no allocation size" + ) - override def isNull: Boolean = false + override def isNull: Boolean = false - override def isStringConstant: Boolean = false + override def isStringConstant: Boolean = false - override def getStringValue: String = throw new RuntimeException("Array Value is not a String constant") + override def getStringValue: String = throw new RuntimeException( + "Array Value is not a String constant" + ) - override def isStringBufferOrBuilder: Boolean = false + override def isStringBufferOrBuilder: Boolean = false - override def isThrowableAllocationType: Boolean = false + override def isThrowableAllocationType: Boolean = false - override def isCast: Boolean = false + override def isCast: Boolean = false - override def getCastOp: Val = throw new RuntimeException("Array Value is not a cast operation") + override def getCastOp: Val = throw new RuntimeException( + "Array Value is not a cast operation" + ) - override def isArrayRef: Boolean = true + override def isArrayRef: Boolean = true - override def isInstanceOfExpr: Boolean = false + override def isInstanceOfExpr: Boolean = false - override def getInstanceOfOp: Val = throw new RuntimeException("Array Value is not an instance of operation") + override def getInstanceOfOp: Val = throw new RuntimeException( + "Array Value is not an instance of operation" + ) - override def isLengthExpr: Boolean = false + override def isLengthExpr: Boolean = false - override def getLengthOp: Val = throw new RuntimeException("Array Value is not a length operation") + override def getLengthOp: Val = throw new RuntimeException( + "Array Value is not a length operation" + ) - override def isIntConstant: Boolean = false + override def isIntConstant: Boolean = false - override def isClassConstant: Boolean = false + override def isClassConstant: Boolean = false - override def getClassConstantType: Type = throw new RuntimeException("Array Value is not a class constant") + override def getClassConstantType: Type = throw new RuntimeException( + "Array Value is not a class constant" + ) - override def withNewMethod(callee: Method): Val = new OpalArrayRef(arrayRef, index, callee.asInstanceOf[OpalMethod]) + override def withNewMethod(callee: Method): Val = + new OpalArrayRef(arrayRef, index, callee.asInstanceOf[OpalMethod]) - override def isLongConstant: Boolean = false + override def isLongConstant: Boolean = false - override def getIntValue: Int = throw new RuntimeException("Array Value is not an integer constant") + override def getIntValue: Int = throw new RuntimeException( + "Array Value is not an integer constant" + ) - override def getLongValue: Long = throw new RuntimeException("Array Value is not a long constant") + override def getLongValue: Long = throw new RuntimeException( + "Array Value is not a long constant" + ) - override def getArrayBase: Pair[Val, Integer] = { - val base = new OpalLocal(arrayRef, method) + override def getArrayBase: Pair[Val, Integer] = { + val base = new OpalLocal(arrayRef, method) - new Pair[Val, Integer](base, index) - } + new Pair[Val, Integer](base, index) + } - override def getVariableName: String = s"$arrayRef[$index]" + override def getVariableName: String = s"$arrayRef[$index]" - override def hashCode: Int = Objects.hash(super.hashCode(), arrayRef, index) + override def hashCode: Int = Objects.hash(super.hashCode(), arrayRef, index) - override def equals(other: Any): Boolean = other match { - case that: OpalArrayRef => super.equals(that) && this.arrayRef == that.arrayRef && this.index == that.index - case _ => false - } + override def equals(other: Any): Boolean = other match { + case that: OpalArrayRef => + super.equals( + that + ) && this.arrayRef == that.arrayRef && this.index == that.index + case _ => false + } - override def toString: String = getVariableName + override def toString: String = getVariableName } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalControlFlowGraph.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalControlFlowGraph.scala index f5b899bc7..8a4824b2b 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalControlFlowGraph.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalControlFlowGraph.scala @@ -1,84 +1,104 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ package boomerang.scope.opal.tac -import boomerang.scope.{ControlFlowGraph, Statement} -import com.google.common.collect.{HashMultimap, Multimap} -import org.opalj.tac.Nop - +import boomerang.scope.ControlFlowGraph +import boomerang.scope.Statement +import com.google.common.collect.HashMultimap +import com.google.common.collect.Multimap import java.util +import org.opalj.tac.Nop class OpalControlFlowGraph(method: OpalMethod) extends ControlFlowGraph { - private var cacheBuilt = false - - private val startPointCache: util.List[Statement] = new util.ArrayList[Statement] - private val endPointCache: util.List[Statement] = new util.ArrayList[Statement] - private val predsOfCache: Multimap[Statement, Statement] = HashMultimap.create() - private val succsOfCache: Multimap[Statement, Statement] = HashMultimap.create() - private val statements: util.List[Statement] = new util.ArrayList[Statement]() - - def get(): OpalControlFlowGraph = { - buildCache() - - this - } - - override def getStartPoints: util.Collection[Statement] = { - buildCache() - startPointCache - } - - override def getEndPoints: util.Collection[Statement] = { - buildCache() - endPointCache - } - - override def getSuccsOf(curr: Statement): util.Collection[Statement] = { - buildCache() - succsOfCache.get(curr) - } - - override def getPredsOf(curr: Statement): util.Collection[Statement] = { - buildCache() - predsOfCache.get(curr) - } - - override def getStatements: util.List[Statement] = { - buildCache() - statements - } - - private def buildCache(): Unit = { - if (cacheBuilt) return - - val graph = method.tac.cfg - - graph.heads.foreach(stmt => { - val headStmt = new OpalStatement(stmt, method) - - startPointCache.add(headStmt) - }) - - graph.tails.foreach(stmt => { - val tailStmt = new OpalStatement(stmt, method) - - endPointCache.add(tailStmt) - }) - - method.tac.statements.foreach(stmt => { - val statement = new OpalStatement(stmt, method) - statements.add(statement) - - graph.predecessors(stmt).foreach(pred => { - val predStmt = new OpalStatement(pred, method) - predsOfCache.put(statement, predStmt) - }) - - graph.successors(stmt).foreach(succ => { - val succStmt = new OpalStatement(succ, method) - succsOfCache.put(statement, succStmt) - }) - }) - - cacheBuilt = true - } + private var cacheBuilt = false + + private val startPointCache: util.List[Statement] = + new util.ArrayList[Statement] + private val endPointCache: util.List[Statement] = + new util.ArrayList[Statement] + private val predsOfCache: Multimap[Statement, Statement] = + HashMultimap.create() + private val succsOfCache: Multimap[Statement, Statement] = + HashMultimap.create() + private val statements: util.List[Statement] = new util.ArrayList[Statement]() + + def get(): OpalControlFlowGraph = { + buildCache() + + this + } + + override def getStartPoints: util.Collection[Statement] = { + buildCache() + startPointCache + } + + override def getEndPoints: util.Collection[Statement] = { + buildCache() + endPointCache + } + + override def getSuccsOf(curr: Statement): util.Collection[Statement] = { + buildCache() + succsOfCache.get(curr) + } + + override def getPredsOf(curr: Statement): util.Collection[Statement] = { + buildCache() + predsOfCache.get(curr) + } + + override def getStatements: util.List[Statement] = { + buildCache() + statements + } + + private def buildCache(): Unit = { + if (cacheBuilt) return + + val graph = method.tac.cfg + + graph.heads.foreach(stmt => { + val headStmt = new OpalStatement(stmt, method) + + startPointCache.add(headStmt) + }) + + graph.tails.foreach(stmt => { + val tailStmt = new OpalStatement(stmt, method) + + endPointCache.add(tailStmt) + }) + + method.tac.statements.foreach(stmt => { + val statement = new OpalStatement(stmt, method) + statements.add(statement) + + graph + .predecessors(stmt) + .foreach(pred => { + val predStmt = new OpalStatement(pred, method) + predsOfCache.put(statement, predStmt) + }) + + graph + .successors(stmt) + .foreach(succ => { + val succStmt = new OpalStatement(succ, method) + succsOfCache.put(statement, succStmt) + }) + }) + + cacheBuilt = true + } } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalDeclaredMethod.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalDeclaredMethod.scala index 63cc66958..a9b99a2e6 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalDeclaredMethod.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalDeclaredMethod.scala @@ -1,53 +1,77 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ package boomerang.scope.opal.tac -import boomerang.scope.opal.{OpalClient, OpalFrameworkScope} -import boomerang.scope.{DeclaredMethod, InvokeExpr, Type, WrappedClass} +import boomerang.scope.DeclaredMethod +import boomerang.scope.InvokeExpr +import boomerang.scope.Type +import boomerang.scope.WrappedClass +import boomerang.scope.opal.OpalClient +import boomerang.scope.opal.OpalFrameworkScope import boomerang.utils.MethodWrapper -import org.opalj.br.MethodSignature -import org.opalj.tac.{Call, Var} - import java.util +import org.opalj.br.MethodSignature +import org.opalj.tac.Call +import org.opalj.tac.Var import scala.jdk.CollectionConverters._ -case class OpalDeclaredMethod[+V <: Var[V]](invokeExpr: InvokeExpr, delegate: Call[V]) extends DeclaredMethod(invokeExpr) { +case class OpalDeclaredMethod[+V <: Var[V]]( + invokeExpr: InvokeExpr, + delegate: Call[V] +) extends DeclaredMethod(invokeExpr) { - override def getSubSignature: String = MethodSignature(delegate.name, delegate.descriptor).toJava + override def getSubSignature: String = + MethodSignature(delegate.name, delegate.descriptor).toJava - override def getName: String = delegate.name + override def getName: String = delegate.name - override def isConstructor: Boolean = delegate.name == OpalFrameworkScope.CONSTRUCTOR + override def isConstructor: Boolean = + delegate.name == OpalFrameworkScope.CONSTRUCTOR - override def getSignature: String = delegate.descriptor.toJava(s"${delegate.declaringClass.toJava}.${delegate.name}") + override def getSignature: String = delegate.descriptor.toJava( + s"${delegate.declaringClass.toJava}.${delegate.name}" + ) - override def getDeclaringClass: WrappedClass = { - val decClass = OpalClient.getClassFileForType(delegate.declaringClass.asObjectType) + override def getDeclaringClass: WrappedClass = { + val decClass = + OpalClient.getClassFileForType(delegate.declaringClass.asObjectType) - if (decClass.isDefined) { - OpalWrappedClass(decClass.get) - } else { - OpalPhantomWrappedClass(delegate.declaringClass) + if (decClass.isDefined) { + OpalWrappedClass(decClass.get) + } else { + OpalPhantomWrappedClass(delegate.declaringClass) + } } - } - override def getParameterTypes: util.List[Type] = { - val result = new util.ArrayList[Type]() + override def getParameterTypes: util.List[Type] = { + val result = new util.ArrayList[Type]() - delegate.descriptor.parameterTypes.foreach(paramType => { - result.add(OpalType(paramType)) - }) + delegate.descriptor.parameterTypes.foreach(paramType => { + result.add(OpalType(paramType)) + }) - result - } + result + } - override def getParameterType(index: Int): Type = getParameterTypes.get(index) + override def getParameterType(index: Int): Type = getParameterTypes.get(index) - override def getReturnType: Type = OpalType(delegate.descriptor.returnType) + override def getReturnType: Type = OpalType(delegate.descriptor.returnType) - override def toMethodWrapper: MethodWrapper = new MethodWrapper( - delegate.declaringClass.toJava, - delegate.name, - delegate.descriptor.returnType.toJava, - delegate.descriptor.parameterTypes.map(p => p.toJava).toList.asJava) + override def toMethodWrapper: MethodWrapper = new MethodWrapper( + delegate.declaringClass.toJava, + delegate.name, + delegate.descriptor.returnType.toJava, + delegate.descriptor.parameterTypes.map(p => p.toJava).toList.asJava + ) - override def toString: String = delegate.descriptor.toJava + override def toString: String = delegate.descriptor.toJava } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalDoubleVal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalDoubleVal.scala index e4bd87db4..5bb003a77 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalDoubleVal.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalDoubleVal.scala @@ -1,25 +1,44 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ package boomerang.scope.opal.tac +import boomerang.scope.Val +import boomerang.scope.ValWithFalseVariable import boomerang.scope.opal.transformation.TacLocal -import boomerang.scope.{Val, ValWithFalseVariable} -import org.opalj.tac.{DUVar, Expr, IdBasedVar, Var} -import org.opalj.value.ValueInformation - import java.util.Objects +import org.opalj.tac.DUVar +import org.opalj.tac.Expr +import org.opalj.tac.IdBasedVar +import org.opalj.tac.Var +import org.opalj.value.ValueInformation -class OpalDoubleVal(delegate: Expr[TacLocal], method: OpalMethod, falseVal: Val) extends OpalVal(delegate, method) with ValWithFalseVariable { +class OpalDoubleVal(delegate: Expr[TacLocal], method: OpalMethod, falseVal: Val) + extends OpalVal(delegate, method) + with ValWithFalseVariable { - override def getFalseVariable: Val = falseVal + override def getFalseVariable: Val = falseVal - override def hashCode: Int = Objects.hash(super.hashCode, falseVal) + override def hashCode: Int = Objects.hash(super.hashCode, falseVal) - private def canEqual(a: Any): Boolean = a.isInstanceOf[OpalDoubleVal] + private def canEqual(a: Any): Boolean = a.isInstanceOf[OpalDoubleVal] - override def equals(obj: Any): Boolean = obj match { - case other: OpalDoubleVal => - other.canEqual(this) && super.equals(other) && falseVal.equals(other.getFalseVariable) - case _ => false - } + override def equals(obj: Any): Boolean = obj match { + case other: OpalDoubleVal => + other.canEqual(this) && super.equals(other) && falseVal.equals( + other.getFalseVariable + ) + case _ => false + } - override def toString: String = "FalseVal: " + falseVal + " from " + super.toString + override def toString: String = + "FalseVal: " + falseVal + " from " + super.toString } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalField.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalField.scala index 93ed16411..d686c9868 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalField.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalField.scala @@ -1,24 +1,41 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ package boomerang.scope.opal.tac -import boomerang.scope.{Field, Type} -import org.opalj.br.{FieldType, ObjectType} - +import boomerang.scope.Field +import boomerang.scope.Type import java.util.Objects +import org.opalj.br.FieldType +import org.opalj.br.ObjectType -class OpalField(declaringClass: ObjectType, val fieldType: FieldType, val name: String) extends Field { +class OpalField( + declaringClass: ObjectType, + val fieldType: FieldType, + val name: String +) extends Field { - override def isPredefinedField: Boolean = false + override def isPredefinedField: Boolean = false - override def isInnerClassField: Boolean = declaringClass.fqn.contains("$") + override def isInnerClassField: Boolean = declaringClass.fqn.contains("$") - override def getType: Type = OpalType(fieldType) + override def getType: Type = OpalType(fieldType) - override def hashCode: Int = Objects.hash(super.hashCode(), fieldType, name) + override def hashCode: Int = Objects.hash(super.hashCode(), fieldType, name) - override def equals(other: Any): Boolean = other match { - case that: OpalField => this.fieldType == that.fieldType && this.name == that.name - case _ => false - } + override def equals(other: Any): Boolean = other match { + case that: OpalField => + this.fieldType == that.fieldType && this.name == that.name + case _ => false + } - override def toString: String = s"$name" + override def toString: String = s"$name" } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalIfStatement.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalIfStatement.scala index c706e41fe..9b229b49d 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalIfStatement.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalIfStatement.scala @@ -1,44 +1,61 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ package boomerang.scope.opal.tac +import boomerang.scope.IfStatement +import boomerang.scope.Statement +import boomerang.scope.Val import boomerang.scope.opal.OpalClient import boomerang.scope.opal.transformation.TacLocal -import boomerang.scope.{IfStatement, Statement, Val} -import org.opalj.tac.{DUVar, IdBasedVar, If, Var} -import org.opalj.value.ValueInformation - import java.util.Objects +import org.opalj.tac.DUVar +import org.opalj.tac.IdBasedVar +import org.opalj.tac.If +import org.opalj.tac.Var +import org.opalj.value.ValueInformation class OpalIfStatement(val delegate: If[TacLocal], method: OpalMethod) extends IfStatement { - override def getTarget: Statement = { - /*val tac = OpalClient.getTacForMethod(method.delegate) + override def getTarget: Statement = { + /*val tac = OpalClient.getTacForMethod(method.delegate) val target = delegate.targetStmt new OpalStatement(tac.stmts(target), method)*/ - ??? - } + ??? + } - override def evaluate(otherVal: Val): IfStatement.Evaluation = IfStatement.Evaluation.UNKNOWN + override def evaluate(otherVal: Val): IfStatement.Evaluation = + IfStatement.Evaluation.UNKNOWN - override def uses(otherVal: Val): Boolean = { - // TODO - if (otherVal.isInstanceOf[OpalVal]) {} - if (otherVal.isInstanceOf[OpalLocal]) {} - if (otherVal.isInstanceOf[OpalArrayRef]) {} - val left = new OpalVal(delegate.left, method) - val right = new OpalVal(delegate.right, method) + override def uses(otherVal: Val): Boolean = { + // TODO + if (otherVal.isInstanceOf[OpalVal]) {} + if (otherVal.isInstanceOf[OpalLocal]) {} + if (otherVal.isInstanceOf[OpalArrayRef]) {} + val left = new OpalVal(delegate.left, method) + val right = new OpalVal(delegate.right, method) - otherVal.equals(left) || otherVal.equals(right) - } + otherVal.equals(left) || otherVal.equals(right) + } - override def hashCode: Int = Objects.hash(delegate) + override def hashCode: Int = Objects.hash(delegate) - private def canEqual(a: Any): Boolean = a.isInstanceOf[OpalIfStatement] + private def canEqual(a: Any): Boolean = a.isInstanceOf[OpalIfStatement] - override def equals(obj: Any): Boolean = obj match { - case other: OpalIfStatement => other.canEqual(this) && this.delegate.pc == other.delegate.pc - case _ => false - } + override def equals(obj: Any): Boolean = obj match { + case other: OpalIfStatement => + other.canEqual(this) && this.delegate.pc == other.delegate.pc + case _ => false + } - override def toString: String = delegate.toString() + override def toString: String = delegate.toString() } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalInstanceFieldRef.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalInstanceFieldRef.scala index aca96f720..7f303e95c 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalInstanceFieldRef.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalInstanceFieldRef.scala @@ -1,76 +1,126 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ package boomerang.scope.opal.tac +import boomerang.scope.ControlFlowGraph +import boomerang.scope.Method +import boomerang.scope.Pair +import boomerang.scope.Type +import boomerang.scope.Val import boomerang.scope.opal.transformation.TacLocal -import boomerang.scope.{ControlFlowGraph, Method, Pair, Type, Val} - import java.util.Objects -class OpalInstanceFieldRef(val base: TacLocal, val fieldType: org.opalj.br.Type, val fieldName: String, method: OpalMethod, unbalanced: ControlFlowGraph.Edge = null) extends Val(method, unbalanced) { +class OpalInstanceFieldRef( + val base: TacLocal, + val fieldType: org.opalj.br.Type, + val fieldName: String, + method: OpalMethod, + unbalanced: ControlFlowGraph.Edge = null +) extends Val(method, unbalanced) { - override def getType: Type = OpalType(fieldType) + override def getType: Type = OpalType(fieldType) - override def isStatic: Boolean = false + override def isStatic: Boolean = false - override def isNewExpr: Boolean = false + override def isNewExpr: Boolean = false - override def getNewExprType: Type = throw new RuntimeException("Instance field ref is not a new expression") + override def getNewExprType: Type = throw new RuntimeException( + "Instance field ref is not a new expression" + ) - override def asUnbalanced(stmt: ControlFlowGraph.Edge): Val = new OpalInstanceFieldRef(base, fieldType, fieldName, method, stmt) + override def asUnbalanced(stmt: ControlFlowGraph.Edge): Val = + new OpalInstanceFieldRef(base, fieldType, fieldName, method, stmt) - override def isLocal: Boolean = false + override def isLocal: Boolean = false - override def isArrayAllocationVal: Boolean = false + override def isArrayAllocationVal: Boolean = false - override def getArrayAllocationSize: Val = throw new RuntimeException("Instance field ref is not an array allocation val") + override def getArrayAllocationSize: Val = throw new RuntimeException( + "Instance field ref is not an array allocation val" + ) - override def isNull: Boolean = false + override def isNull: Boolean = false - override def isStringConstant: Boolean = false + override def isStringConstant: Boolean = false - override def getStringValue: String = throw new RuntimeException("Instance field ref is not a String constant") + override def getStringValue: String = throw new RuntimeException( + "Instance field ref is not a String constant" + ) - override def isStringBufferOrBuilder: Boolean = false + override def isStringBufferOrBuilder: Boolean = false - override def isThrowableAllocationType: Boolean = false + override def isThrowableAllocationType: Boolean = false - override def isCast: Boolean = false + override def isCast: Boolean = false - override def getCastOp: Val = throw new RuntimeException("Instance field ref is not a cast expression") + override def getCastOp: Val = throw new RuntimeException( + "Instance field ref is not a cast expression" + ) - override def isArrayRef: Boolean = false + override def isArrayRef: Boolean = false - override def isInstanceOfExpr: Boolean = false + override def isInstanceOfExpr: Boolean = false - override def getInstanceOfOp: Val = throw new RuntimeException("Instance field ref is not an instanceOf expression") + override def getInstanceOfOp: Val = throw new RuntimeException( + "Instance field ref is not an instanceOf expression" + ) - override def isLengthExpr: Boolean = false + override def isLengthExpr: Boolean = false - override def getLengthOp: Val = throw new RuntimeException("Instance field ref is not a length expression") + override def getLengthOp: Val = throw new RuntimeException( + "Instance field ref is not a length expression" + ) - override def isIntConstant: Boolean = false + override def isIntConstant: Boolean = false - override def isClassConstant: Boolean = false + override def isClassConstant: Boolean = false - override def getClassConstantType: Type = throw new RuntimeException("Instance field ref is not a class constant") + override def getClassConstantType: Type = throw new RuntimeException( + "Instance field ref is not a class constant" + ) - override def withNewMethod(callee: Method): Val = new OpalInstanceFieldRef(base, fieldType, fieldName, callee.asInstanceOf[OpalMethod]) + override def withNewMethod(callee: Method): Val = new OpalInstanceFieldRef( + base, + fieldType, + fieldName, + callee.asInstanceOf[OpalMethod] + ) - override def isLongConstant: Boolean = false + override def isLongConstant: Boolean = false - override def getIntValue: Int = throw new RuntimeException("Instance field ref is not an int constant") + override def getIntValue: Int = throw new RuntimeException( + "Instance field ref is not an int constant" + ) - override def getLongValue: Long = throw new RuntimeException("Instance field ref is not a long constant") + override def getLongValue: Long = throw new RuntimeException( + "Instance field ref is not a long constant" + ) - override def getArrayBase: Pair[Val, Integer] = throw new RuntimeException("Instance field ref has no array base") + override def getArrayBase: Pair[Val, Integer] = throw new RuntimeException( + "Instance field ref has no array base" + ) - override def getVariableName: String = s"$base.$fieldName" + override def getVariableName: String = s"$base.$fieldName" - override def hashCode: Int = Objects.hash(super.hashCode(), base, fieldType, fieldName) + override def hashCode: Int = + Objects.hash(super.hashCode(), base, fieldType, fieldName) - override def equals(other: Any): Boolean = other match { - case that: OpalInstanceFieldRef => super.equals(other) && this.base == that.base && this.fieldType == that.fieldType && this.fieldName == that.fieldName - case _ => false - } + override def equals(other: Any): Boolean = other match { + case that: OpalInstanceFieldRef => + super.equals( + other + ) && this.base == that.base && this.fieldType == that.fieldType && this.fieldName == that.fieldName + case _ => false + } - override def toString: String = getVariableName + override def toString: String = getVariableName } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalInvokeExpr.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalInvokeExpr.scala index d9492c44d..45573e10e 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalInvokeExpr.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalInvokeExpr.scala @@ -1,90 +1,122 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ package boomerang.scope.opal.tac +import boomerang.scope.DeclaredMethod +import boomerang.scope.InvokeExpr +import boomerang.scope.Val import boomerang.scope.opal.transformation.TacLocal -import boomerang.scope.{DeclaredMethod, InvokeExpr, Val} -import org.opalj.tac._ - import java.util import java.util.Objects +import org.opalj.tac._ -class OpalMethodInvokeExpr(val delegate: MethodCall[TacLocal], method: OpalMethod) extends InvokeExpr { +class OpalMethodInvokeExpr( + val delegate: MethodCall[TacLocal], + method: OpalMethod +) extends InvokeExpr { - override def getArg(index: Int): Val = getArgs.get(index) + override def getArg(index: Int): Val = getArgs.get(index) - override def getArgs: util.List[Val] = { - val result = new util.ArrayList[Val] + override def getArgs: util.List[Val] = { + val result = new util.ArrayList[Val] - delegate.params.foreach(param => { - result.add(new OpalLocal(param.asVar, method)) - }) + delegate.params.foreach(param => { + result.add(new OpalLocal(param.asVar, method)) + }) - result - } + result + } - override def isInstanceInvokeExpr: Boolean = delegate.isInstanceOf[InstanceMethodCall[_]] + override def isInstanceInvokeExpr: Boolean = + delegate.isInstanceOf[InstanceMethodCall[_]] - override def getBase: Val = { - if (isInstanceInvokeExpr) { - return new OpalLocal(delegate.asInstanceMethodCall.receiver.asVar, method) - } + override def getBase: Val = { + if (isInstanceInvokeExpr) { + return new OpalLocal(delegate.asInstanceMethodCall.receiver.asVar, method) + } - throw new RuntimeException("Method call is not an instance invoke expression") - } + throw new RuntimeException( + "Method call is not an instance invoke expression" + ) + } - override def getDeclaredMethod: DeclaredMethod = OpalDeclaredMethod(this, delegate) + override def getDeclaredMethod: DeclaredMethod = + OpalDeclaredMethod(this, delegate) - override def isSpecialInvokeExpr: Boolean = delegate.astID == NonVirtualMethodCall.ASTID + override def isSpecialInvokeExpr: Boolean = + delegate.astID == NonVirtualMethodCall.ASTID - override def isStaticInvokeExpr: Boolean = delegate.isStaticMethodCall + override def isStaticInvokeExpr: Boolean = delegate.isStaticMethodCall - override def hashCode: Int = Objects.hash(delegate) + override def hashCode: Int = Objects.hash(delegate) - override def equals(obj: Any): Boolean = obj match { - case other: OpalMethodInvokeExpr => this.delegate == other.delegate - case _ => false - } + override def equals(obj: Any): Boolean = obj match { + case other: OpalMethodInvokeExpr => this.delegate == other.delegate + case _ => false + } - override def toString: String = delegate.toString + override def toString: String = delegate.toString } -class OpalFunctionInvokeExpr(val delegate: FunctionCall[TacLocal], method: OpalMethod) extends InvokeExpr { +class OpalFunctionInvokeExpr( + val delegate: FunctionCall[TacLocal], + method: OpalMethod +) extends InvokeExpr { - override def getArg(index: Int): Val = getArgs.get(index) + override def getArg(index: Int): Val = getArgs.get(index) - override def getArgs: util.List[Val] = { - val result = new util.ArrayList[Val] + override def getArgs: util.List[Val] = { + val result = new util.ArrayList[Val] - delegate.params.foreach(param => { - result.add(new OpalLocal(param.asVar, method)) - }) + delegate.params.foreach(param => { + result.add(new OpalLocal(param.asVar, method)) + }) - result - } + result + } - override def isInstanceInvokeExpr: Boolean = delegate.isInstanceOf[InstanceFunctionCall[_]] + override def isInstanceInvokeExpr: Boolean = + delegate.isInstanceOf[InstanceFunctionCall[_]] - override def getBase: Val = { - if (isInstanceInvokeExpr) { - return new OpalLocal(delegate.asInstanceFunctionCall.receiver.asVar, method) - } + override def getBase: Val = { + if (isInstanceInvokeExpr) { + return new OpalLocal( + delegate.asInstanceFunctionCall.receiver.asVar, + method + ) + } - throw new RuntimeException("Function call is not an instance invoke expression") - } + throw new RuntimeException( + "Function call is not an instance invoke expression" + ) + } - override def getDeclaredMethod: DeclaredMethod = OpalDeclaredMethod(this, delegate) + override def getDeclaredMethod: DeclaredMethod = + OpalDeclaredMethod(this, delegate) - override def isSpecialInvokeExpr: Boolean = delegate.astID == NonVirtualFunctionCall.ASTID + override def isSpecialInvokeExpr: Boolean = + delegate.astID == NonVirtualFunctionCall.ASTID - override def isStaticInvokeExpr: Boolean = delegate.isStaticFunctionCall + override def isStaticInvokeExpr: Boolean = delegate.isStaticFunctionCall - override def hashCode: Int = Objects.hash(delegate) + override def hashCode: Int = Objects.hash(delegate) - private def canEqual(a: Any): Boolean = a.isInstanceOf[OpalFunctionInvokeExpr] + private def canEqual(a: Any): Boolean = a.isInstanceOf[OpalFunctionInvokeExpr] - override def equals(obj: Any): Boolean = obj match { - case other: OpalFunctionInvokeExpr => other.canEqual(this) && this.delegate == other.delegate - case _ => false - } + override def equals(obj: Any): Boolean = obj match { + case other: OpalFunctionInvokeExpr => + other.canEqual(this) && this.delegate == other.delegate + case _ => false + } - override def toString: String = delegate.toString + override def toString: String = delegate.toString } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalLocal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalLocal.scala index 7bb0c1cb8..e983db113 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalLocal.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalLocal.scala @@ -1,103 +1,139 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ package boomerang.scope.opal.tac import boomerang.scope._ import boomerang.scope.opal.transformation.TacLocal +import java.util.Objects import org.opalj.br.ObjectType import org.opalj.tac.Var -import java.util.Objects +class OpalLocal( + val delegate: Var[TacLocal], + method: OpalMethod, + unbalanced: ControlFlowGraph.Edge = null +) extends Val(method, unbalanced) { -class OpalLocal(val delegate: Var[TacLocal], method: OpalMethod, unbalanced: ControlFlowGraph.Edge = null) extends Val(method, unbalanced) { + override def getType: Type = { + val value = delegate.asVar.valueInformation - override def getType: Type = { - val value = delegate.asVar.valueInformation + if (value.isPrimitiveValue) { + return OpalType(value.asPrimitiveValue.primitiveType) + } - if (value.isPrimitiveValue) { - return OpalType(value.asPrimitiveValue.primitiveType) - } + if (value.isReferenceValue) { + if (value.asReferenceValue.isPrecise) { + if (value.asReferenceValue.isNull.isYes) { + return OpalNullType + } else { + return OpalType(value.asReferenceValue.asReferenceType) + } + } else { + return OpalType(value.asReferenceValue.upperTypeBound.head) + } + } - if (value.isReferenceValue) { - if (value.asReferenceValue.isPrecise) { - if (value.asReferenceValue.isNull.isYes) { - return OpalNullType - } else { - return OpalType(value.asReferenceValue.asReferenceType) + if (value.isVoid) { + return OpalType(ObjectType.Void) } - } else { - return OpalType(value.asReferenceValue.upperTypeBound.head) - } - } - if (value.isVoid) { - return OpalType(ObjectType.Void) + // TODO Array and illegal types + throw new RuntimeException("Type not implemented yet") } - // TODO Array and illegal types - throw new RuntimeException("Type not implemented yet") - } + override def isStatic: Boolean = false - override def isStatic: Boolean = false + override def isNewExpr: Boolean = false - override def isNewExpr: Boolean = false + override def getNewExprType: Type = throw new RuntimeException( + "Opal local is not a new expression" + ) - override def getNewExprType: Type = throw new RuntimeException("Opal local is not a new expression") + override def asUnbalanced(stmt: ControlFlowGraph.Edge): Val = + new OpalLocal(delegate, method, stmt) - override def asUnbalanced(stmt: ControlFlowGraph.Edge): Val = new OpalLocal(delegate, method, stmt) + override def isLocal: Boolean = true - override def isLocal: Boolean = true + override def isArrayAllocationVal: Boolean = false - override def isArrayAllocationVal: Boolean = false + override def getArrayAllocationSize: Val = throw new RuntimeException( + "Opal local is not an array allocation expression" + ) - override def getArrayAllocationSize: Val = throw new RuntimeException("Opal local is not an array allocation expression") + override def isNull: Boolean = false - override def isNull: Boolean = false + override def isStringConstant: Boolean = false - override def isStringConstant: Boolean = false + override def getStringValue: String = throw new RuntimeException( + "Opal local is not a String constant" + ) - override def getStringValue: String = throw new RuntimeException("Opal local is not a String constant") + override def isStringBufferOrBuilder: Boolean = false - override def isStringBufferOrBuilder: Boolean = false + override def isThrowableAllocationType: Boolean = false - override def isThrowableAllocationType: Boolean = false + override def isCast: Boolean = false - override def isCast: Boolean = false + override def getCastOp: Val = throw new RuntimeException( + "Opal local is not a cast operation" + ) - override def getCastOp: Val = throw new RuntimeException("Opal local is not a cast operation") + override def isArrayRef: Boolean = false - override def isArrayRef: Boolean = false + override def isInstanceOfExpr: Boolean = false - override def isInstanceOfExpr: Boolean = false + override def getInstanceOfOp: Val = throw new RuntimeException( + "Opal local is not an instance of operation" + ) - override def getInstanceOfOp: Val = throw new RuntimeException("Opal local is not an instance of operation") + override def isLengthExpr: Boolean = false - override def isLengthExpr: Boolean = false + override def getLengthOp: Val = throw new RuntimeException( + "Opal local is not a length operation" + ) - override def getLengthOp: Val = throw new RuntimeException("Opal local is not a length operation") + override def isIntConstant: Boolean = false - override def isIntConstant: Boolean = false + override def isClassConstant: Boolean = false - override def isClassConstant: Boolean = false + override def getClassConstantType: Type = throw new RuntimeException( + "Opal local is not a class constant" + ) - override def getClassConstantType: Type = throw new RuntimeException("Opal local is not a class constant") + override def withNewMethod(callee: Method): Val = + new OpalLocal(delegate, callee.asInstanceOf[OpalMethod]) - override def withNewMethod(callee: Method): Val = new OpalLocal(delegate, callee.asInstanceOf[OpalMethod]) + override def isLongConstant: Boolean = false - override def isLongConstant: Boolean = false + override def getIntValue: Int = throw new RuntimeException( + "Opal local is not an int constant" + ) - override def getIntValue: Int = throw new RuntimeException("Opal local is not an int constant") + override def getLongValue: Long = throw new RuntimeException( + "Opal local is not a long constant" + ) - override def getLongValue: Long = throw new RuntimeException("Opal local is not a long constant") + override def getArrayBase: Pair[Val, Integer] = throw new RuntimeException( + "Opal local is not array reference" + ) - override def getArrayBase: Pair[Val, Integer] = throw new RuntimeException("Opal local is not array reference") + override def getVariableName: String = delegate.asVar.name - override def getVariableName: String = delegate.asVar.name + override def hashCode: Int = Objects.hash(delegate.asVar) - override def hashCode: Int = Objects.hash(delegate.asVar) - - override def equals(other: Any): Boolean = other match { - case that: OpalLocal => super.equals(that) && this.delegate == that.delegate - case _ => false - } + override def equals(other: Any): Boolean = other match { + case that: OpalLocal => super.equals(that) && this.delegate == that.delegate + case _ => false + } - override def toString: String = getVariableName + override def toString: String = getVariableName } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalMethod.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalMethod.scala index 907f34fbc..868dbe274 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalMethod.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalMethod.scala @@ -1,125 +1,146 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ package boomerang.scope.opal.tac import boomerang.scope._ import boomerang.scope.opal.OpalClient -import boomerang.scope.opal.transformation.{BoomerangTACode, TacBodyBuilder} - +import boomerang.scope.opal.transformation.BoomerangTACode +import boomerang.scope.opal.transformation.TacBodyBuilder import java.util import java.util.Objects -class OpalMethod private(val delegate: org.opalj.br.Method, val tac: BoomerangTACode) extends Method { - - if (delegate.body.isEmpty) { - throw new RuntimeException("Cannot build OpalMethod without existing body") - } +class OpalMethod private ( + val delegate: org.opalj.br.Method, + val tac: BoomerangTACode +) extends Method { - private val cfg = new OpalControlFlowGraph(this) + if (delegate.body.isEmpty) { + throw new RuntimeException("Cannot build OpalMethod without existing body") + } - private var localCache: Option[util.Set[Val]] = None - private var parameterLocalCache: Option[util.List[Val]] = None + private val cfg = new OpalControlFlowGraph(this) - override def isStaticInitializer: Boolean = delegate.isStaticInitializer + private var localCache: Option[util.Set[Val]] = None + private var parameterLocalCache: Option[util.List[Val]] = None - override def isParameterLocal(value: Val): Boolean = getParameterLocals.contains(value) + override def isStaticInitializer: Boolean = delegate.isStaticInitializer - override def getParameterTypes: util.List[Type] = { - val result = new util.ArrayList[Type]() + override def isParameterLocal(value: Val): Boolean = + getParameterLocals.contains(value) - delegate.parameterTypes.foreach(paramType => { - result.add(OpalType(paramType)) - }) + override def getParameterTypes: util.List[Type] = { + val result = new util.ArrayList[Type]() - result - } + delegate.parameterTypes.foreach(paramType => { + result.add(OpalType(paramType)) + }) - override def getParameterType(index: Int): Type = getParameterTypes.get(index) + result + } - override def getReturnType: Type = OpalType(delegate.descriptor.returnType) + override def getParameterType(index: Int): Type = getParameterTypes.get(index) - override def isThisLocal(fact: Val): Boolean = { - if (isStatic) return false - if (fact.isStatic) return false + override def getReturnType: Type = OpalType(delegate.descriptor.returnType) - val thisLocal = getThisLocal - thisLocal.equals(fact) - } + override def isThisLocal(fact: Val): Boolean = { + if (isStatic) return false + if (fact.isStatic) return false - override def getThisLocal: Val = { - if (!isStatic) { - tac.statements.foreach(stmt => { - if (stmt.pc == -1) { - val targetVar = stmt.asAssignment.targetVar + val thisLocal = getThisLocal + thisLocal.equals(fact) + } - if (targetVar.id == -1) { - return new OpalLocal(targetVar, this) - } + override def getThisLocal: Val = { + if (!isStatic) { + tac.statements.foreach(stmt => { + if (stmt.pc == -1) { + val targetVar = stmt.asAssignment.targetVar + + if (targetVar.id == -1) { + return new OpalLocal(targetVar, this) + } + } + }) + + throw new RuntimeException( + "Could not determine 'this' local in method " + delegate.name + ) } - }) - throw new RuntimeException("Could not determine 'this' local in method " + delegate.name) + throw new RuntimeException("Static method does not have a 'this' local") } - throw new RuntimeException("Static method does not have a 'this' local") - } + override def getLocals: util.Set[Val] = { + if (localCache.isEmpty) { + localCache = Some(new util.HashSet[Val]()) - override def getLocals: util.Set[Val] = { - if (localCache.isEmpty) { - localCache = Some(new util.HashSet[Val]()) + tac.getLocals.foreach(l => localCache.get.add(new OpalLocal(l, this))) + } - tac.getLocals.foreach(l => localCache.get.add(new OpalLocal(l, this))) + localCache.get } - localCache.get - } - - override def getParameterLocals: util.List[Val] = { - if (parameterLocalCache.isEmpty) { - parameterLocalCache = Some(new util.ArrayList[Val]()) - - tac.getParameterLocals.foreach(l => { - // Exclude the 'this' local from the parameters if this is an instance method - if (isStatic) { - parameterLocalCache.get.add(new OpalLocal(l, this)) - } else if (l.id != -1) { - parameterLocalCache.get.add(new OpalLocal(l, this)) + override def getParameterLocals: util.List[Val] = { + if (parameterLocalCache.isEmpty) { + parameterLocalCache = Some(new util.ArrayList[Val]()) + + tac.getParameterLocals.foreach(l => { + // Exclude the 'this' local from the parameters if this is an instance method + if (isStatic) { + parameterLocalCache.get.add(new OpalLocal(l, this)) + } else if (l.id != -1) { + parameterLocalCache.get.add(new OpalLocal(l, this)) + } + }) } - }) - } - parameterLocalCache.get - } + parameterLocalCache.get + } - override def isStatic: Boolean = delegate.isStatic + override def isStatic: Boolean = delegate.isStatic - override def isDefined: Boolean = true + override def isDefined: Boolean = true - override def isPhantom: Boolean = false + override def isPhantom: Boolean = false - override def getStatements: util.List[Statement] = cfg.getStatements + override def getStatements: util.List[Statement] = cfg.getStatements - override def getDeclaringClass: WrappedClass = OpalWrappedClass(delegate.classFile) + override def getDeclaringClass: WrappedClass = OpalWrappedClass( + delegate.classFile + ) - override def getControlFlowGraph: ControlFlowGraph = cfg.get() + override def getControlFlowGraph: ControlFlowGraph = cfg.get() - override def getSubSignature: String = delegate.signature.toJava + override def getSubSignature: String = delegate.signature.toJava - override def getName: String = delegate.name + override def getName: String = delegate.name - override def isConstructor: Boolean = delegate.isConstructor + override def isConstructor: Boolean = delegate.isConstructor - override def hashCode: Int = Objects.hash(delegate) + override def hashCode: Int = Objects.hash(delegate) - override def equals(other: Any): Boolean = other match { - case that: OpalMethod => this.delegate == that.delegate - case _ => false - } + override def equals(other: Any): Boolean = other match { + case that: OpalMethod => this.delegate == that.delegate + case _ => false + } - override def toString: String = delegate.toJava + override def toString: String = delegate.toJava } object OpalMethod { - def apply(delegate: org.opalj.br.Method): OpalMethod = new OpalMethod(delegate, TacBodyBuilder(OpalClient.project.get, delegate)) + def apply(delegate: org.opalj.br.Method): OpalMethod = + new OpalMethod(delegate, TacBodyBuilder(OpalClient.project.get, delegate)) - def apply(delegate: org.opalj.br.Method, tac: BoomerangTACode): OpalMethod = new OpalMethod(delegate, tac) + def apply(delegate: org.opalj.br.Method, tac: BoomerangTACode): OpalMethod = + new OpalMethod(delegate, tac) } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalNullType.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalNullType.scala index 632fc546f..ffe24ffdd 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalNullType.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalNullType.scala @@ -1,24 +1,41 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ package boomerang.scope.opal.tac -import boomerang.scope.{Type, Val, WrappedClass} +import boomerang.scope.Type +import boomerang.scope.Val +import boomerang.scope.WrappedClass object OpalNullType extends Type { - override def isNullType: Boolean = true + override def isNullType: Boolean = true - override def isRefType: Boolean = false + override def isRefType: Boolean = false - override def isArrayType: Boolean = false + override def isArrayType: Boolean = false - override def getArrayBaseType: Type = throw new RuntimeException("Null type has no array base type") + override def getArrayBaseType: Type = throw new RuntimeException( + "Null type has no array base type" + ) - override def getWrappedClass: WrappedClass = throw new RuntimeException("Null type has no declaring class") + override def getWrappedClass: WrappedClass = throw new RuntimeException( + "Null type has no declaring class" + ) - override def doesCastFail(targetVal: Type, target: Val): Boolean = true + override def doesCastFail(targetVal: Type, target: Val): Boolean = true - override def isSubtypeOf(superType: String): Boolean = false + override def isSubtypeOf(superType: String): Boolean = false - override def isSupertypeOf(subType: String): Boolean = false + override def isSupertypeOf(subType: String): Boolean = false - override def isBooleanType: Boolean = false + override def isBooleanType: Boolean = false } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalPhantomMethod.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalPhantomMethod.scala index c320d1b98..c2341c354 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalPhantomMethod.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalPhantomMethod.scala @@ -1,57 +1,95 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ package boomerang.scope.opal.tac +import boomerang.scope.ControlFlowGraph +import boomerang.scope.Method +import boomerang.scope.Statement +import boomerang.scope.Type +import boomerang.scope.Val +import boomerang.scope.WrappedClass import boomerang.scope.opal.OpalFrameworkScope -import boomerang.scope.{ControlFlowGraph, Method, Statement, Type, Val, WrappedClass} -import org.opalj.br.{MethodDescriptor, MethodSignature, ObjectType, VirtualDeclaredMethod} - import java.util +import org.opalj.br.MethodDescriptor +import org.opalj.br.MethodSignature +import org.opalj.br.ObjectType +import org.opalj.br.VirtualDeclaredMethod -case class OpalPhantomMethod(declaringClassType: ObjectType, name: String, descriptor: MethodDescriptor, static: Boolean) extends Method { +case class OpalPhantomMethod( + declaringClassType: ObjectType, + name: String, + descriptor: MethodDescriptor, + static: Boolean +) extends Method { - override def isStaticInitializer: Boolean = name == OpalFrameworkScope.STATIC_INITIALIZER + override def isStaticInitializer: Boolean = + name == OpalFrameworkScope.STATIC_INITIALIZER - override def isParameterLocal(value: Val): Boolean = false + override def isParameterLocal(value: Val): Boolean = false - override def getParameterTypes: util.List[Type] = { - val result = new util.ArrayList[Type]() + override def getParameterTypes: util.List[Type] = { + val result = new util.ArrayList[Type]() - descriptor.parameterTypes.foreach(paramType => { - result.add(OpalType(paramType)) - }) + descriptor.parameterTypes.foreach(paramType => { + result.add(OpalType(paramType)) + }) - result - } + result + } - override def getParameterType(index: Int): Type = OpalType(descriptor.parameterType(index)) + override def getParameterType(index: Int): Type = OpalType( + descriptor.parameterType(index) + ) - override def getReturnType: Type = OpalType(descriptor.returnType) + override def getReturnType: Type = OpalType(descriptor.returnType) - override def isThisLocal(value: Val): Boolean = false + override def isThisLocal(value: Val): Boolean = false - override def getLocals: util.Collection[Val] = throw new RuntimeException("Locals of phantom method are not available") + override def getLocals: util.Collection[Val] = throw new RuntimeException( + "Locals of phantom method are not available" + ) - override def getThisLocal: Val = throw new RuntimeException("this local of phantom method is not available") + override def getThisLocal: Val = throw new RuntimeException( + "this local of phantom method is not available" + ) - override def getParameterLocals: util.List[Val] = throw new RuntimeException("Parameter locals of phantom method are not available") + override def getParameterLocals: util.List[Val] = throw new RuntimeException( + "Parameter locals of phantom method are not available" + ) - override def isStatic: Boolean = static + override def isStatic: Boolean = static - override def isDefined: Boolean = false + override def isDefined: Boolean = false - override def isPhantom: Boolean = true + override def isPhantom: Boolean = true - override def getStatements: util.List[Statement] = throw new RuntimeException("Statements of phantom method are not available") + override def getStatements: util.List[Statement] = throw new RuntimeException( + "Statements of phantom method are not available" + ) - // TODO - override def getDeclaringClass: WrappedClass = OpalPhantomWrappedClass(declaringClassType) + // TODO + override def getDeclaringClass: WrappedClass = OpalPhantomWrappedClass( + declaringClassType + ) - override def getControlFlowGraph: ControlFlowGraph = throw new RuntimeException("CFG of phantom method is not available") + override def getControlFlowGraph: ControlFlowGraph = + throw new RuntimeException("CFG of phantom method is not available") - override def getSubSignature: String = MethodSignature(name, descriptor).toJava + override def getSubSignature: String = + MethodSignature(name, descriptor).toJava - override def getName: String = name + override def getName: String = name - override def isConstructor: Boolean = name == OpalFrameworkScope.CONSTRUCTOR + override def isConstructor: Boolean = name == OpalFrameworkScope.CONSTRUCTOR - override def toString: String = s"PHANTOM: ${descriptor.toJava}" + override def toString: String = s"PHANTOM: ${descriptor.toJava}" } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalPhantomWrappedClass.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalPhantomWrappedClass.scala index 198e5ec56..045e82cc2 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalPhantomWrappedClass.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalPhantomWrappedClass.scala @@ -1,25 +1,41 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ package boomerang.scope.opal.tac -import boomerang.scope.{Method, Type, WrappedClass} -import org.opalj.br.ReferenceType - +import boomerang.scope.Method +import boomerang.scope.Type +import boomerang.scope.WrappedClass import java.util +import org.opalj.br.ReferenceType case class OpalPhantomWrappedClass(delegate: ReferenceType) extends WrappedClass { - override def getMethods: util.Set[Method] = throw new RuntimeException("Methods of class " + delegate.toString + " are not available") + override def getMethods: util.Set[Method] = throw new RuntimeException( + "Methods of class " + delegate.toString + " are not available" + ) - override def hasSuperclass: Boolean = false + override def hasSuperclass: Boolean = false - override def getSuperclass: WrappedClass = throw new RuntimeException("Super class of " + delegate.toString + " is not available") + override def getSuperclass: WrappedClass = throw new RuntimeException( + "Super class of " + delegate.toString + " is not available" + ) - override def getType: Type = OpalType(delegate) + override def getType: Type = OpalType(delegate) - override def isApplicationClass: Boolean = false + override def isApplicationClass: Boolean = false - override def getFullyQualifiedName: String = delegate.toJava + override def getFullyQualifiedName: String = delegate.toJava - override def isPhantom: Boolean = true + override def isPhantom: Boolean = true - override def toString: String = delegate.toString + override def toString: String = delegate.toString } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala index 9cee850e8..04569a51c 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala @@ -1,365 +1,446 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ package boomerang.scope.opal.tac import boomerang.scope._ import boomerang.scope.opal.transformation.TacLocal -import org.opalj.tac.{PrimitiveTypecastExpr, Stmt} - import java.util import java.util.Objects +import org.opalj.tac.PrimitiveTypecastExpr +import org.opalj.tac.Stmt class OpalStatement(val delegate: Stmt[TacLocal], m: OpalMethod) extends Statement(m) { - override def containsStaticFieldAccess(): Boolean = isStaticFieldLoad || isStaticFieldStore - - override def containsInvokeExpr(): Boolean = { - if (delegate.isMethodCall) return true - if (delegate.isAssignment && delegate.asAssignment.expr.isFunctionCall) return true - if (delegate.isExprStmt && delegate.asExprStmt.expr.isFunctionCall) return true - - false - } - - override def getInvokeExpr: InvokeExpr = { - if (containsInvokeExpr()) { - if (delegate.isMethodCall) { - return new OpalMethodInvokeExpr(delegate.asMethodCall, m) - } - - if (delegate.isAssignment && delegate.asAssignment.expr.isFunctionCall) { - return new OpalFunctionInvokeExpr(delegate.asAssignment.expr.asFunctionCall, m) - } - - if (delegate.isExprStmt && delegate.asExprStmt.expr.isFunctionCall) { - return new OpalFunctionInvokeExpr(delegate.asExprStmt.expr.asFunctionCall, m) - } - } - - throw new RuntimeException("Statement does not contain an invoke expression") - } - - override def getWrittenField: Field = { - if (isFieldStore) { - val fieldStore = delegate.asPutField - - return new OpalField(fieldStore.declaringClass, fieldStore.declaredFieldType, fieldStore.name) - } - - if (isStaticFieldStore) { - val fieldStore = delegate.asPutStatic - - return new OpalField(fieldStore.declaringClass, fieldStore.declaredFieldType, fieldStore.name) - } - - if (isArrayStore) { - return Field.array(getArrayBase.getY) - } - - throw new RuntimeException("Statement is not a field store operation") - } - - override def isFieldWriteWithBase(base: Val): Boolean = { - if (isAssignStmt && isFieldStore) { - return getFieldStore.getX.equals(base) - } - - if (isAssignStmt && isArrayStore) { - return getArrayBase.getX.equals(base) - } - - false - } + override def containsStaticFieldAccess(): Boolean = + isStaticFieldLoad || isStaticFieldStore - override def getLoadedField: Field = { - // TODO Also array? - if (isFieldLoad) { - val fieldLoad = delegate.asAssignment.expr.asGetField + override def containsInvokeExpr(): Boolean = { + if (delegate.isMethodCall) return true + if (delegate.isAssignment && delegate.asAssignment.expr.isFunctionCall) + return true + if (delegate.isExprStmt && delegate.asExprStmt.expr.isFunctionCall) + return true - return new OpalField(fieldLoad.declaringClass, fieldLoad.declaredFieldType, fieldLoad.name) + false } - throw new RuntimeException("Statement is not a field load operation") - } + override def getInvokeExpr: InvokeExpr = { + if (containsInvokeExpr()) { + if (delegate.isMethodCall) { + return new OpalMethodInvokeExpr(delegate.asMethodCall, m) + } + + if (delegate.isAssignment && delegate.asAssignment.expr.isFunctionCall) { + return new OpalFunctionInvokeExpr( + delegate.asAssignment.expr.asFunctionCall, + m + ) + } + + if (delegate.isExprStmt && delegate.asExprStmt.expr.isFunctionCall) { + return new OpalFunctionInvokeExpr( + delegate.asExprStmt.expr.asFunctionCall, + m + ) + } + } - override def isFieldLoadWithBase(base: Val): Boolean = { - // TODO Also array? - if (isFieldLoad) { - return getFieldLoad.getX.equals(base) + throw new RuntimeException( + "Statement does not contain an invoke expression" + ) } - false - } - - override def isAssignStmt: Boolean = { - if (isIdentityStmt) return false - if (delegate.isAssignment) return true - - // Store statements are no assignments in Opal - isFieldStore || isArrayStore || isStaticFieldStore - } + override def getWrittenField: Field = { + if (isFieldStore) { + val fieldStore = delegate.asPutField - override def getLeftOp: Val = { - if (isAssignStmt) { - if (delegate.isAssignment) { - return new OpalLocal(delegate.asAssignment.targetVar, m) - } - - if (isFieldStore) { - val fieldStore = delegate.asPutField - - return new OpalInstanceFieldRef(fieldStore.objRef.asVar, fieldStore.declaredFieldType, fieldStore.name, m) - } + return new OpalField( + fieldStore.declaringClass, + fieldStore.declaredFieldType, + fieldStore.name + ) + } - if (isArrayStore) { - val base = delegate.asArrayStore.arrayRef - val indexValue = delegate.asArrayStore.index + if (isStaticFieldStore) { + val fieldStore = delegate.asPutStatic - if (indexValue.isIntConst) { - return new OpalArrayRef(base.asVar, indexValue.asIntConst.value, m) + return new OpalField( + fieldStore.declaringClass, + fieldStore.declaredFieldType, + fieldStore.name + ) } - return new OpalArrayRef(base.asVar, -1, m) - } - - if (isStaticFieldStore) { - val staticFieldStore = delegate.asPutStatic + if (isArrayStore) { + return Field.array(getArrayBase.getY) + } - return new OpalStaticFieldRef(staticFieldStore.declaringClass, staticFieldStore.declaredFieldType, staticFieldStore.name, m) - } + throw new RuntimeException("Statement is not a field store operation") } - throw new RuntimeException("Statement is not an assignment") - } - - override def getRightOp: Val = { - if (isAssignStmt) { - if (delegate.isAssignment) { - val rightExpr = delegate.asAssignment.expr - - if (rightExpr.isGetField) { - val getField = rightExpr.asGetField + override def isFieldWriteWithBase(base: Val): Boolean = { + if (isAssignStmt && isFieldStore) { + return getFieldStore.getX.equals(base) + } - return new OpalInstanceFieldRef(getField.objRef.asVar, getField.declaredFieldType, getField.name, m) + if (isAssignStmt && isArrayStore) { + return getArrayBase.getX.equals(base) } - if (rightExpr.isArrayLoad) { - val base = rightExpr.asArrayLoad.arrayRef - val indexValue = rightExpr.asArrayLoad.index + false + } - if (indexValue.isIntConst) { - return new OpalArrayRef(base.asVar, indexValue.asIntConst.value, m) - } + override def getLoadedField: Field = { + // TODO Also array? + if (isFieldLoad) { + val fieldLoad = delegate.asAssignment.expr.asGetField - return new OpalArrayRef(base.asVar, -1, m) + return new OpalField( + fieldLoad.declaringClass, + fieldLoad.declaredFieldType, + fieldLoad.name + ) } - if (rightExpr.isGetStatic) { - val staticFieldLoad = rightExpr.asGetStatic + throw new RuntimeException("Statement is not a field load operation") + } - return new OpalStaticFieldRef(staticFieldLoad.declaringClass, staticFieldLoad.declaredFieldType, staticFieldLoad.name, m) + override def isFieldLoadWithBase(base: Val): Boolean = { + // TODO Also array? + if (isFieldLoad) { + return getFieldLoad.getX.equals(base) } - if (rightExpr.isVar) { - return new OpalLocal(rightExpr.asVar, m) - } + false + } - return new OpalVal(delegate.asAssignment.expr, m) - } + override def isAssignStmt: Boolean = { + if (isIdentityStmt) return false + if (delegate.isAssignment) return true - if (isFieldStore) { - val fieldStore = delegate.asPutField + // Store statements are no assignments in Opal + isFieldStore || isArrayStore || isStaticFieldStore + } - if (fieldStore.value.isVar) { - return new OpalLocal(fieldStore.value.asVar, m) - } else { - return new OpalVal(fieldStore.value, m) + override def getLeftOp: Val = { + if (isAssignStmt) { + if (delegate.isAssignment) { + return new OpalLocal(delegate.asAssignment.targetVar, m) + } + + if (isFieldStore) { + val fieldStore = delegate.asPutField + + return new OpalInstanceFieldRef( + fieldStore.objRef.asVar, + fieldStore.declaredFieldType, + fieldStore.name, + m + ) + } + + if (isArrayStore) { + val base = delegate.asArrayStore.arrayRef + val indexValue = delegate.asArrayStore.index + + if (indexValue.isIntConst) { + return new OpalArrayRef(base.asVar, indexValue.asIntConst.value, m) + } + + return new OpalArrayRef(base.asVar, -1, m) + } + + if (isStaticFieldStore) { + val staticFieldStore = delegate.asPutStatic + + return new OpalStaticFieldRef( + staticFieldStore.declaringClass, + staticFieldStore.declaredFieldType, + staticFieldStore.name, + m + ) + } } - } - if (isArrayStore) { - val arrayStore = delegate.asArrayStore + throw new RuntimeException("Statement is not an assignment") + } - if (arrayStore.value.isVar) { - return new OpalLocal(arrayStore.value.asVar, m) - } else { - return new OpalVal(arrayStore.value, m) + override def getRightOp: Val = { + if (isAssignStmt) { + if (delegate.isAssignment) { + val rightExpr = delegate.asAssignment.expr + + if (rightExpr.isGetField) { + val getField = rightExpr.asGetField + + return new OpalInstanceFieldRef( + getField.objRef.asVar, + getField.declaredFieldType, + getField.name, + m + ) + } + + if (rightExpr.isArrayLoad) { + val base = rightExpr.asArrayLoad.arrayRef + val indexValue = rightExpr.asArrayLoad.index + + if (indexValue.isIntConst) { + return new OpalArrayRef(base.asVar, indexValue.asIntConst.value, m) + } + + return new OpalArrayRef(base.asVar, -1, m) + } + + if (rightExpr.isGetStatic) { + val staticFieldLoad = rightExpr.asGetStatic + + return new OpalStaticFieldRef( + staticFieldLoad.declaringClass, + staticFieldLoad.declaredFieldType, + staticFieldLoad.name, + m + ) + } + + if (rightExpr.isVar) { + return new OpalLocal(rightExpr.asVar, m) + } + + return new OpalVal(delegate.asAssignment.expr, m) + } + + if (isFieldStore) { + val fieldStore = delegate.asPutField + + if (fieldStore.value.isVar) { + return new OpalLocal(fieldStore.value.asVar, m) + } else { + return new OpalVal(fieldStore.value, m) + } + } + + if (isArrayStore) { + val arrayStore = delegate.asArrayStore + + if (arrayStore.value.isVar) { + return new OpalLocal(arrayStore.value.asVar, m) + } else { + return new OpalVal(arrayStore.value, m) + } + } + + if (isStaticFieldStore) { + val staticFieldStore = delegate.asPutStatic + + if (staticFieldStore.value.isVar) { + return new OpalLocal(staticFieldStore.value.asVar, m) + } else { + return new OpalVal(staticFieldStore.value, m) + } + } } - } - if (isStaticFieldStore) { - val staticFieldStore = delegate.asPutStatic - - if (staticFieldStore.value.isVar) { - return new OpalLocal(staticFieldStore.value.asVar, m) - } else { - return new OpalVal(staticFieldStore.value, m) - } - } + throw new RuntimeException("Statement is not an assignment") } - throw new RuntimeException("Statement is not an assignment") - } + override def isInstanceOfStatement(fact: Val): Boolean = { + if (delegate.isAssignment) { + if (getRightOp.isInstanceOfExpr) { + val insOf = getRightOp.getInstanceOfOp - override def isInstanceOfStatement(fact: Val): Boolean = { - if (delegate.isAssignment) { - if (getRightOp.isInstanceOfExpr) { - val insOf = getRightOp.getInstanceOfOp + return insOf.equals(fact) + } + } - return insOf.equals(fact) - } + false } - false - } + override def isCast: Boolean = { + // Primitive type casts + if (delegate.isAssignment) { + val assignExpr = delegate.asAssignment.expr - override def isCast: Boolean = { - // Primitive type casts - if (delegate.isAssignment) { - val assignExpr = delegate.asAssignment.expr + if (assignExpr.astID == PrimitiveTypecastExpr.ASTID) { + return true + } + } - if (assignExpr.astID == PrimitiveTypecastExpr.ASTID) { - return true - } + // Class casts + delegate.isCheckcast } - // Class casts - delegate.isCheckcast - } + override def isPhiStatement: Boolean = false - override def isPhiStatement: Boolean = false + override def isReturnStmt: Boolean = delegate.isReturnValue - override def isReturnStmt: Boolean = delegate.isReturnValue + override def isThrowStmt: Boolean = delegate.isThrow - override def isThrowStmt: Boolean = delegate.isThrow + override def isIfStmt: Boolean = delegate.isIf - override def isIfStmt: Boolean = delegate.isIf + override def getIfStmt: IfStatement = { + if (isIfStmt) { + return new OpalIfStatement(delegate.asIf, m) + } - override def getIfStmt: IfStatement = { - if (isIfStmt) { - return new OpalIfStatement(delegate.asIf, m) + throw new RuntimeException("Statement is not an if-statement") } - throw new RuntimeException("Statement is not an if-statement") - } + override def getReturnOp: Val = { + if (isReturnStmt) { + return new OpalLocal(delegate.asReturnValue.expr.asVar, m) + } - override def getReturnOp: Val = { - if (isReturnStmt) { - return new OpalLocal(delegate.asReturnValue.expr.asVar, m) + throw new RuntimeException("Statement is not a return statement") } - throw new RuntimeException("Statement is not a return statement") - } + override def isMultiArrayAllocation: Boolean = false - override def isMultiArrayAllocation: Boolean = false + override def isFieldStore: Boolean = delegate.isPutField - override def isFieldStore: Boolean = delegate.isPutField + override def isArrayStore: Boolean = delegate.isArrayStore - override def isArrayStore: Boolean = delegate.isArrayStore + override def isArrayLoad: Boolean = + delegate.isAssignment && delegate.asAssignment.expr.isArrayLoad - override def isArrayLoad: Boolean = delegate.isAssignment && delegate.asAssignment.expr.isArrayLoad + override def isFieldLoad: Boolean = + delegate.isAssignment && delegate.asAssignment.expr.isGetField - override def isFieldLoad: Boolean = delegate.isAssignment && delegate.asAssignment.expr.isGetField + override def isIdentityStmt: Boolean = { + if (delegate.isAssignment) { + /* Difference between Soot and Opal: + * - Soot considers parameter definitions and self assignments of the this local as identity statements (no assignments) + * - Opal considers these statements as basic assignments, so we have to exclude them manually + */ + val targetVar = delegate.asAssignment.targetVar + val expr = delegate.asAssignment.expr - override def isIdentityStmt: Boolean = { - if (delegate.isAssignment) { - /* Difference between Soot and Opal: - * - Soot considers parameter definitions and self assignments of the this local as identity statements (no assignments) - * - Opal considers these statements as basic assignments, so we have to exclude them manually - */ - val targetVar = delegate.asAssignment.targetVar - val expr = delegate.asAssignment.expr + if (expr.isVar) { + if (expr.asVar.isParameterLocal) return true + if (expr.asVar.isExceptionLocal) return true + if (targetVar.isThisLocal && expr.asVar.isThisLocal) return true + } + } - if (expr.isVar) { - if (expr.asVar.isParameterLocal) return true - if (expr.asVar.isExceptionLocal) return true - if (targetVar.isThisLocal && expr.asVar.isThisLocal) return true - } + false } - false - } + override def getFieldStore: Pair[Val, Field] = { + if (isFieldStore) { + val fieldStore = delegate.asPutField - override def getFieldStore: Pair[Val, Field] = { - if (isFieldStore) { - val fieldStore = delegate.asPutField + val local = new OpalLocal(fieldStore.objRef.asVar, m) + val field = new OpalField( + fieldStore.declaringClass, + fieldStore.declaredFieldType, + fieldStore.name + ) - val local = new OpalLocal(fieldStore.objRef.asVar, m) - val field = new OpalField(fieldStore.declaringClass, fieldStore.declaredFieldType, fieldStore.name) + return new Pair(local, field) + } - return new Pair(local, field) + throw new RuntimeException("Statement is not a field store operation") } - throw new RuntimeException("Statement is not a field store operation") - } + override def getFieldLoad: Pair[Val, Field] = { + if (isFieldLoad) { + val fieldLoad = delegate.asAssignment.expr.asGetField - override def getFieldLoad: Pair[Val, Field] = { - if (isFieldLoad) { - val fieldLoad = delegate.asAssignment.expr.asGetField + val local = new OpalLocal(fieldLoad.objRef.asVar, m) + val field = new OpalField( + fieldLoad.declaringClass, + fieldLoad.declaredFieldType, + fieldLoad.name + ) - val local = new OpalLocal(fieldLoad.objRef.asVar, m) - val field = new OpalField(fieldLoad.declaringClass, fieldLoad.declaredFieldType, fieldLoad.name) + return new Pair(local, field) + } - return new Pair(local, field) + throw new RuntimeException("Statement is not a field load operation") } - throw new RuntimeException("Statement is not a field load operation") - } + override def isStaticFieldLoad: Boolean = + delegate.isAssignment && delegate.asAssignment.expr.isGetStatic - override def isStaticFieldLoad: Boolean = delegate.isAssignment && delegate.asAssignment.expr.isGetStatic + override def isStaticFieldStore: Boolean = delegate.isPutStatic - override def isStaticFieldStore: Boolean = delegate.isPutStatic + override def getStaticField: StaticFieldVal = { + if (isStaticFieldLoad) { + val staticFieldLoad = delegate.asAssignment.expr.asGetStatic - override def getStaticField: StaticFieldVal = { - if (isStaticFieldLoad) { - val staticFieldLoad = delegate.asAssignment.expr.asGetStatic + val staticField = new OpalField( + staticFieldLoad.declaringClass, + staticFieldLoad.declaredFieldType, + staticFieldLoad.name + ) + return new OpalStaticFieldVal(staticField, m) + } - val staticField = new OpalField(staticFieldLoad.declaringClass, staticFieldLoad.declaredFieldType, staticFieldLoad.name) - return new OpalStaticFieldVal(staticField, m) - } + if (isStaticFieldStore) { + val staticFieldStore = delegate.asPutStatic - if (isStaticFieldStore) { - val staticFieldStore = delegate.asPutStatic + val staticField = new OpalField( + staticFieldStore.declaringClass, + staticFieldStore.declaredFieldType, + staticFieldStore.name + ) + return new OpalStaticFieldVal(staticField, m) + } - val staticField = new OpalField(staticFieldStore.declaringClass, staticFieldStore.declaredFieldType, staticFieldStore.name) - return new OpalStaticFieldVal(staticField, m) + throw new RuntimeException( + "Statement is neither a static field load nor store operation" + ) } - throw new RuntimeException("Statement is neither a static field load nor store operation") - } + override def killAtIfStmt(fact: Val, successor: Statement): Boolean = false - override def killAtIfStmt(fact: Val, successor: Statement): Boolean = false + override def getPhiVals: util.Collection[Val] = throw new RuntimeException( + "Not supported" + ) - override def getPhiVals: util.Collection[Val] = throw new RuntimeException("Not supported") + override def getArrayBase: Pair[Val, Integer] = { + if (isArrayLoad) { + val rightOp = getRightOp + return rightOp.getArrayBase + } - override def getArrayBase: Pair[Val, Integer] = { - if (isArrayLoad) { - val rightOp = getRightOp - return rightOp.getArrayBase - } + if (isArrayStore) { + val leftOp = getLeftOp + return leftOp.getArrayBase + } - if (isArrayStore) { - val leftOp = getLeftOp - return leftOp.getArrayBase + throw new RuntimeException( + "Statement is not an array load or array store operation" + ) } - throw new RuntimeException("Statement is not an array load or array store operation") - } - - override def getStartLineNumber: Int = m.delegate.body.get.lineNumber(delegate.pc).getOrElse(-1) + override def getStartLineNumber: Int = + m.delegate.body.get.lineNumber(delegate.pc).getOrElse(-1) - override def getStartColumnNumber: Int = -1 + override def getStartColumnNumber: Int = -1 - override def getEndLineNumber: Int = -1 + override def getEndLineNumber: Int = -1 - override def getEndColumnNumber: Int = -1 + override def getEndColumnNumber: Int = -1 - override def isCatchStmt: Boolean = delegate.isCaughtException + override def isCatchStmt: Boolean = delegate.isCaughtException - override def hashCode: Int = Objects.hash(delegate, m) + override def hashCode: Int = Objects.hash(delegate, m) - override def equals(other: Any): Boolean = other match { - case that: OpalStatement => this.delegate == that.delegate && this.method == that.method - case _ => false - } + override def equals(other: Any): Boolean = other match { + case that: OpalStatement => + this.delegate == that.delegate && this.method == that.method + case _ => false + } - override def toString: String = OpalStatementFormatter(this) + override def toString: String = OpalStatementFormatter(this) } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatementFormatter.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatementFormatter.scala index f5ce57733..647b469df 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatementFormatter.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatementFormatter.scala @@ -1,72 +1,90 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ package boomerang.scope.opal.tac import com.google.common.base.Joiner -import org.opalj.tac.{Nop, Param, PutField, Return} +import org.opalj.tac.Nop +import org.opalj.tac.Param +import org.opalj.tac.PutField +import org.opalj.tac.Return object OpalStatementFormatter { - def apply(stmt: OpalStatement): String = { - val delegate = stmt.delegate - - if (stmt.containsInvokeExpr()) { - var base = "" - if (stmt.getInvokeExpr.isInstanceInvokeExpr) { - base = s"${stmt.getInvokeExpr.getBase}." - } - var assign = "" - if (stmt.isAssignStmt) { - assign = s"${stmt.getLeftOp} = " - } - - return s"$assign$base${stmt.getInvokeExpr.getDeclaredMethod.getName}(${Joiner.on(",").join(stmt.getInvokeExpr.getArgs)})" - } - - if (stmt.isAssignStmt) { - if (delegate.isAssignment) { - return s"${stmt.getLeftOp} = ${stmt.getRightOp}" - } - - if (stmt.isFieldStore) { - return s"${stmt.getLeftOp} = ${stmt.getRightOp}" - } - - if (stmt.isArrayStore) { - val base = stmt.getArrayBase - return s"${base.getX.getVariableName}[${base.getY}] = ${stmt.getRightOp}" - } - - if (stmt.isStaticFieldStore) { - return s"${stmt.getLeftOp} = ${stmt.getRightOp}" - } - } - - if (delegate.isAssignment) { - if (delegate.asAssignment.expr.isVar && delegate.asAssignment.expr.asVar.isParameterLocal) { - return s"${delegate.asAssignment.targetVar} := @${delegate.asAssignment.expr}: ${stmt.getMethod}" - } - - if (delegate.asAssignment.expr.isVar && delegate.asAssignment.expr.asVar.isExceptionLocal) { - return s"${delegate.asAssignment.targetVar} := @caughtException: ${delegate.asAssignment.expr}" - } + def apply(stmt: OpalStatement): String = { + val delegate = stmt.delegate + + if (stmt.containsInvokeExpr()) { + var base = "" + if (stmt.getInvokeExpr.isInstanceInvokeExpr) { + base = s"${stmt.getInvokeExpr.getBase}." + } + var assign = "" + if (stmt.isAssignStmt) { + assign = s"${stmt.getLeftOp} = " + } + + return s"$assign$base${stmt.getInvokeExpr.getDeclaredMethod.getName}(${Joiner.on(",").join(stmt.getInvokeExpr.getArgs)})" + } + + if (stmt.isAssignStmt) { + if (delegate.isAssignment) { + return s"${stmt.getLeftOp} = ${stmt.getRightOp}" + } + + if (stmt.isFieldStore) { + return s"${stmt.getLeftOp} = ${stmt.getRightOp}" + } + + if (stmt.isArrayStore) { + val base = stmt.getArrayBase + return s"${base.getX.getVariableName}[${base.getY}] = ${stmt.getRightOp}" + } + + if (stmt.isStaticFieldStore) { + return s"${stmt.getLeftOp} = ${stmt.getRightOp}" + } + } + + if (delegate.isAssignment) { + if ( + delegate.asAssignment.expr.isVar && delegate.asAssignment.expr.asVar.isParameterLocal + ) { + return s"${delegate.asAssignment.targetVar} := @${delegate.asAssignment.expr}: ${stmt.getMethod}" + } + + if ( + delegate.asAssignment.expr.isVar && delegate.asAssignment.expr.asVar.isExceptionLocal + ) { + return s"${delegate.asAssignment.targetVar} := @caughtException: ${delegate.asAssignment.expr}" + } + } + + if (delegate.astID == PutField.ASTID) { + return s"${stmt.getLeftOp} = ${stmt.getRightOp}" + } + + if (delegate.astID == Nop.ASTID) { + return "nop" + } + + if (delegate.astID == Return.ASTID) { + return "return" + } + + if (stmt.isReturnStmt) { + return s"return ${stmt.getReturnOp}" + } + + delegate.toString } - if (delegate.astID == PutField.ASTID) { - return s"${stmt.getLeftOp} = ${stmt.getRightOp}" - } - - if (delegate.astID == Nop.ASTID) { - return "nop" - } - - if (delegate.astID == Return.ASTID) { - return "return" - } - - if (stmt.isReturnStmt) { - return s"return ${stmt.getReturnOp}" - } - - delegate.toString - } - } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStaticFieldRef.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStaticFieldRef.scala index 23b96dd7c..477b4fbf7 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStaticFieldRef.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStaticFieldRef.scala @@ -1,76 +1,126 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ package boomerang.scope.opal.tac -import boomerang.scope.{ControlFlowGraph, Method, Pair, Type, Val} -import org.opalj.br.ObjectType - +import boomerang.scope.ControlFlowGraph +import boomerang.scope.Method +import boomerang.scope.Pair +import boomerang.scope.Type +import boomerang.scope.Val import java.util.Objects +import org.opalj.br.ObjectType -class OpalStaticFieldRef(val declaringClass: ObjectType, val fieldType: org.opalj.br.Type, val fieldName: String, method: OpalMethod, unbalanced: ControlFlowGraph.Edge = null) extends Val(method, unbalanced) { +class OpalStaticFieldRef( + val declaringClass: ObjectType, + val fieldType: org.opalj.br.Type, + val fieldName: String, + method: OpalMethod, + unbalanced: ControlFlowGraph.Edge = null +) extends Val(method, unbalanced) { - override def getType: Type = OpalType(fieldType) + override def getType: Type = OpalType(fieldType) - override def isStatic: Boolean = true + override def isStatic: Boolean = true - override def isNewExpr: Boolean = false + override def isNewExpr: Boolean = false - override def getNewExprType: Type = throw new RuntimeException("Static field ref is not a new expression") + override def getNewExprType: Type = throw new RuntimeException( + "Static field ref is not a new expression" + ) - override def asUnbalanced(stmt: ControlFlowGraph.Edge): Val = new OpalStaticFieldRef(declaringClass, fieldType, fieldName, method, stmt) + override def asUnbalanced(stmt: ControlFlowGraph.Edge): Val = + new OpalStaticFieldRef(declaringClass, fieldType, fieldName, method, stmt) - override def isLocal: Boolean = false + override def isLocal: Boolean = false - override def isArrayAllocationVal: Boolean = false + override def isArrayAllocationVal: Boolean = false - override def getArrayAllocationSize: Val = throw new RuntimeException("Static field ref is not an array allocation site") + override def getArrayAllocationSize: Val = throw new RuntimeException( + "Static field ref is not an array allocation site" + ) - override def isNull: Boolean = false + override def isNull: Boolean = false - override def isStringConstant: Boolean = false + override def isStringConstant: Boolean = false - override def getStringValue: String = throw new RuntimeException("Static field ref is not a String constant") + override def getStringValue: String = throw new RuntimeException( + "Static field ref is not a String constant" + ) - override def isStringBufferOrBuilder: Boolean = false + override def isStringBufferOrBuilder: Boolean = false - override def isThrowableAllocationType: Boolean = false + override def isThrowableAllocationType: Boolean = false - override def isCast: Boolean = false + override def isCast: Boolean = false - override def getCastOp: Val = throw new RuntimeException("Static field ref is not a cast expression") + override def getCastOp: Val = throw new RuntimeException( + "Static field ref is not a cast expression" + ) - override def isArrayRef: Boolean = false + override def isArrayRef: Boolean = false - override def isInstanceOfExpr: Boolean = false + override def isInstanceOfExpr: Boolean = false - override def getInstanceOfOp: Val = throw new RuntimeException("Static field ref is not an instanceOf expression") + override def getInstanceOfOp: Val = throw new RuntimeException( + "Static field ref is not an instanceOf expression" + ) - override def isLengthExpr: Boolean = false + override def isLengthExpr: Boolean = false - override def getLengthOp: Val = throw new RuntimeException("Static field ref is not a length expression") + override def getLengthOp: Val = throw new RuntimeException( + "Static field ref is not a length expression" + ) - override def isIntConstant: Boolean = false + override def isIntConstant: Boolean = false - override def isClassConstant: Boolean = false + override def isClassConstant: Boolean = false - override def getClassConstantType: Type = throw new RuntimeException("Static field ref is not a class constant") + override def getClassConstantType: Type = throw new RuntimeException( + "Static field ref is not a class constant" + ) - override def withNewMethod(callee: Method): Val = new OpalStaticFieldRef(declaringClass, fieldType, fieldName, callee.asInstanceOf[OpalMethod]) + override def withNewMethod(callee: Method): Val = new OpalStaticFieldRef( + declaringClass, + fieldType, + fieldName, + callee.asInstanceOf[OpalMethod] + ) - override def isLongConstant: Boolean = false + override def isLongConstant: Boolean = false - override def getIntValue: Int = throw new RuntimeException("Static field ref is not an int constant") + override def getIntValue: Int = throw new RuntimeException( + "Static field ref is not an int constant" + ) - override def getLongValue: Long = throw new RuntimeException("Static field ref is not a long constant") + override def getLongValue: Long = throw new RuntimeException( + "Static field ref is not a long constant" + ) - override def getArrayBase: Pair[Val, Integer] = throw new RuntimeException("Static field ref has no array base") + override def getArrayBase: Pair[Val, Integer] = throw new RuntimeException( + "Static field ref has no array base" + ) - override def getVariableName: String = fieldName + override def getVariableName: String = fieldName - override def hashCode: Int = Objects.hash(super.hashCode(), declaringClass, fieldType, fieldName) + override def hashCode: Int = + Objects.hash(super.hashCode(), declaringClass, fieldType, fieldName) - override def equals(other: Any): Boolean = other match { - case that: OpalStaticFieldRef => super.equals(that) && this.declaringClass == that.declaringClass && this.fieldType == that.fieldType && this.fieldName == that.fieldName - case _ => false - } + override def equals(other: Any): Boolean = other match { + case that: OpalStaticFieldRef => + super.equals( + that + ) && this.declaringClass == that.declaringClass && this.fieldType == that.fieldType && this.fieldName == that.fieldName + case _ => false + } - override def toString: String = s"${declaringClass.toJava}.$fieldName" + override def toString: String = s"${declaringClass.toJava}.$fieldName" } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStaticFieldVal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStaticFieldVal.scala index 2d9ca64e0..55c1cc985 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStaticFieldVal.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStaticFieldVal.scala @@ -1,27 +1,44 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ package boomerang.scope.opal.tac import boomerang.scope._ - import java.util.Objects -class OpalStaticFieldVal(field: OpalField, method: Method, unbalanced: ControlFlowGraph.Edge = null) extends StaticFieldVal(method, unbalanced) { +class OpalStaticFieldVal( + field: OpalField, + method: Method, + unbalanced: ControlFlowGraph.Edge = null +) extends StaticFieldVal(method, unbalanced) { - override def field: Field = field + override def field: Field = field - override def asUnbalanced(stmt: ControlFlowGraph.Edge): Val = new OpalStaticFieldVal(field, method, stmt) + override def asUnbalanced(stmt: ControlFlowGraph.Edge): Val = + new OpalStaticFieldVal(field, method, stmt) - override def getType: Type = OpalType(field.fieldType) + override def getType: Type = OpalType(field.fieldType) - override def withNewMethod(callee: Method): Val = new OpalStaticFieldVal(field, callee) + override def withNewMethod(callee: Method): Val = + new OpalStaticFieldVal(field, callee) - override def getVariableName: String = field.toString + override def getVariableName: String = field.toString - override def hashCode: Int = Objects.hash(super.hashCode(), field) + override def hashCode: Int = Objects.hash(super.hashCode(), field) - override def equals(other: Any): Boolean = other match { - case that: OpalStaticFieldVal => super.equals(that) && this.field.equals(that.field) - case _ => false - } + override def equals(other: Any): Boolean = other match { + case that: OpalStaticFieldVal => + super.equals(that) && this.field.equals(that.field) + case _ => false + } - override def toString: String = s"StaticField: $field" + override def toString: String = s"StaticField: $field" } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalType.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalType.scala index 91d85285c..97c8e820d 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalType.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalType.scala @@ -1,67 +1,90 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ package boomerang.scope.opal.tac +import boomerang.scope.AllocVal +import boomerang.scope.Type +import boomerang.scope.Val +import boomerang.scope.WrappedClass import boomerang.scope.opal.OpalClient -import boomerang.scope.{AllocVal, Type, Val, WrappedClass} import org.opalj.br.ObjectType case class OpalType(delegate: org.opalj.br.Type) extends Type { - override def isNullType: Boolean = false + override def isNullType: Boolean = false - override def isRefType: Boolean = delegate.isObjectType + override def isRefType: Boolean = delegate.isObjectType - override def isArrayType: Boolean = delegate.isArrayType + override def isArrayType: Boolean = delegate.isArrayType - override def getArrayBaseType: Type = OpalType(delegate.asArrayType) + override def getArrayBaseType: Type = OpalType(delegate.asArrayType) - override def getWrappedClass: WrappedClass = { - if (isRefType) { - val declaringClass = OpalClient.getClassFileForType(delegate.asObjectType) + override def getWrappedClass: WrappedClass = { + if (isRefType) { + val declaringClass = OpalClient.getClassFileForType(delegate.asObjectType) - if (declaringClass.isDefined) { - OpalWrappedClass(declaringClass.get) - } else { - OpalPhantomWrappedClass(delegate.asReferenceType) - } - } - - throw new RuntimeException("Cannot compute declaring class because type is not a RefType") - } + if (declaringClass.isDefined) { + OpalWrappedClass(declaringClass.get) + } else { + OpalPhantomWrappedClass(delegate.asReferenceType) + } + } - override def doesCastFail(targetValType: Type, target: Val): Boolean = { - if (!isRefType || !targetValType.isRefType) { - return false + throw new RuntimeException( + "Cannot compute declaring class because type is not a RefType" + ) } - val sourceType = delegate.asReferenceType - val targetType = targetValType.asInstanceOf[OpalType].delegate.asReferenceType + override def doesCastFail(targetValType: Type, target: Val): Boolean = { + if (!isRefType || !targetValType.isRefType) { + return false + } + + val sourceType = delegate.asReferenceType + val targetType = + targetValType.asInstanceOf[OpalType].delegate.asReferenceType - false + false - /*target match { + /*target match { case allocVal: AllocVal if allocVal.getAllocVal.isNewExpr => OpalClient.getClassHierarchy.isSubtypeOf(sourceType, targetType) case _ => OpalClient.getClassHierarchy.isSubtypeOf(sourceType, targetType) || OpalClient.getClassHierarchy.isSubtypeOf(targetType, sourceType) }*/ - } - - override def isSubtypeOf(otherType: String): Boolean = { - if (!delegate.isObjectType) { - return false } - OpalClient.getClassHierarchy.isSubtypeOf(delegate.asObjectType, ObjectType(otherType.replace(".", "/"))) - } + override def isSubtypeOf(otherType: String): Boolean = { + if (!delegate.isObjectType) { + return false + } - override def isSupertypeOf(subType: String): Boolean = { - if (!delegate.isObjectType) { - return false + OpalClient.getClassHierarchy.isSubtypeOf( + delegate.asObjectType, + ObjectType(otherType.replace(".", "/")) + ) } - OpalClient.getClassHierarchy.isSubtypeOf(ObjectType(subType), delegate.asObjectType) - } + override def isSupertypeOf(subType: String): Boolean = { + if (!delegate.isObjectType) { + return false + } + + OpalClient.getClassHierarchy.isSubtypeOf( + ObjectType(subType), + delegate.asObjectType + ) + } - override def isBooleanType: Boolean = delegate.isBooleanType + override def isBooleanType: Boolean = delegate.isBooleanType - override def toString: String = delegate.toJava + override def toString: String = delegate.toJava } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalVal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalVal.scala index d5f83e0c5..e7707bbae 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalVal.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalVal.scala @@ -1,183 +1,212 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ package boomerang.scope.opal.tac -import boomerang.scope.opal.OpalClient import boomerang.scope._ +import boomerang.scope.opal.OpalClient import boomerang.scope.opal.transformation.TacLocal +import java.util.Objects import org.opalj.br.ReferenceType import org.opalj.tac._ -import java.util.Objects +class OpalVal( + val delegate: Expr[TacLocal], + method: OpalMethod, + unbalanced: ControlFlowGraph.Edge = null +) extends Val(method, unbalanced) { -class OpalVal(val delegate: Expr[TacLocal], method: OpalMethod, unbalanced: ControlFlowGraph.Edge = null) extends Val(method, unbalanced) { - - if (delegate.isVar) { - throw new RuntimeException("OpalVal cannot hold a variable (use OpalLocal)") - } - - override def getType: Type = delegate match { - case nullExpr: NullExpr => OpalType(nullExpr.tpe) - case const: Const => OpalType(const.tpe) - case newExpr: New => OpalType(newExpr.tpe) - case newArrayExpr: NewArray[_] => OpalType(newArrayExpr.tpe) - case functionCall: FunctionCall[_] => OpalType(functionCall.descriptor.returnType) - case _ => throw new RuntimeException("Type not implemented yet") - } - - // TODO - override def isStatic: Boolean = false - - override def isNewExpr: Boolean = delegate.isNew - - override def getNewExprType: Type = { - if (isNewExpr) { - return OpalType(delegate.asNew.tpe) + if (delegate.isVar) { + throw new RuntimeException("OpalVal cannot hold a variable (use OpalLocal)") } - throw new RuntimeException("Value is not a new expression") - } + override def getType: Type = delegate match { + case nullExpr: NullExpr => OpalType(nullExpr.tpe) + case const: Const => OpalType(const.tpe) + case newExpr: New => OpalType(newExpr.tpe) + case newArrayExpr: NewArray[_] => OpalType(newArrayExpr.tpe) + case functionCall: FunctionCall[_] => + OpalType(functionCall.descriptor.returnType) + case _ => throw new RuntimeException("Type not implemented yet") + } + + // TODO + override def isStatic: Boolean = false - override def asUnbalanced(stmt: ControlFlowGraph.Edge): Val = new OpalVal(delegate, method, stmt) + override def isNewExpr: Boolean = delegate.isNew - override def isLocal: Boolean = false + override def getNewExprType: Type = { + if (isNewExpr) { + return OpalType(delegate.asNew.tpe) + } + + throw new RuntimeException("Value is not a new expression") + } - override def isArrayAllocationVal: Boolean = delegate.isNewArray + override def asUnbalanced(stmt: ControlFlowGraph.Edge): Val = + new OpalVal(delegate, method, stmt) - override def getArrayAllocationSize: Val = { - if (isArrayAllocationVal) { - val counts = delegate.asNewArray.counts + override def isLocal: Boolean = false - /* TODO - * For now, the scope just returns the size of the first dimension. - * In the future, we may change it to returning a list of values - */ - val firstIndex = counts.last - if (firstIndex.isVar) { - return new OpalLocal(firstIndex.asVar, method) - } else { - return new OpalVal(firstIndex, method) - } + override def isArrayAllocationVal: Boolean = delegate.isNewArray + + override def getArrayAllocationSize: Val = { + if (isArrayAllocationVal) { + val counts = delegate.asNewArray.counts + + /* TODO + * For now, the scope just returns the size of the first dimension. + * In the future, we may change it to returning a list of values + */ + val firstIndex = counts.last + if (firstIndex.isVar) { + return new OpalLocal(firstIndex.asVar, method) + } else { + return new OpalVal(firstIndex, method) + } + } + + throw new RuntimeException("Value is not an array allocation expression") } - throw new RuntimeException("Value is not an array allocation expression") - } + override def isNull: Boolean = delegate.isNullExpr - override def isNull: Boolean = delegate.isNullExpr + override def isStringConstant: Boolean = delegate.isStringConst - override def isStringConstant: Boolean = delegate.isStringConst + override def getStringValue: String = { + if (isStringConstant) { + return delegate.asStringConst.value + } - override def getStringValue: String = { - if (isStringConstant) { - return delegate.asStringConst.value + throw new RuntimeException("Value is not a String constant") } - throw new RuntimeException("Value is not a String constant") - } + override def isStringBufferOrBuilder: Boolean = { + val thisType = getType - override def isStringBufferOrBuilder: Boolean = { - val thisType = getType + thisType.toString.equals("java/lang/String") || thisType.toString.equals( + "java/lang/StringBuilder" + ) || thisType.toString.equals("java/lang/StringBuffer") + } - thisType.toString.equals("java/lang/String") || thisType.toString.equals("java/lang/StringBuilder") || thisType.toString.equals("java/lang/StringBuffer") - } + override def isThrowableAllocationType: Boolean = { + val thisType = getType - override def isThrowableAllocationType: Boolean = { - val thisType = getType + if (!thisType.isRefType) { + return false + } - if (!thisType.isRefType) { - return false + val opalType = thisType.asInstanceOf[OpalType].delegate + OpalClient.getClassHierarchy.isSubtypeOf( + opalType.asReferenceType, + ReferenceType("java/lang/Throwable") + ) } - val opalType = thisType.asInstanceOf[OpalType].delegate - OpalClient.getClassHierarchy.isSubtypeOf(opalType.asReferenceType, ReferenceType("java/lang/Throwable")) - } + override def isCast: Boolean = delegate.astID == PrimitiveTypecastExpr.ASTID - override def isCast: Boolean = delegate.astID == PrimitiveTypecastExpr.ASTID + override def getCastOp: Val = { + if (isCast) { + return new OpalVal(delegate.asPrimitiveTypeCastExpr.operand, method) + } - override def getCastOp: Val = { - if (isCast) { - return new OpalVal(delegate.asPrimitiveTypeCastExpr.operand, method) + throw new RuntimeException("Expression is not a cast expression") } - throw new RuntimeException("Expression is not a cast expression") - } + override def isArrayRef: Boolean = false - override def isArrayRef: Boolean = false + override def isInstanceOfExpr: Boolean = delegate.astID == InstanceOf.ASTID - override def isInstanceOfExpr: Boolean = delegate.astID == InstanceOf.ASTID + override def getInstanceOfOp: Val = { + if (isInstanceOfExpr) { + return new OpalVal(delegate.asInstanceOf.value, method) + } - override def getInstanceOfOp: Val = { - if (isInstanceOfExpr) { - return new OpalVal(delegate.asInstanceOf.value, method) + throw new RuntimeException("Expression is not an instanceOf expression") } - throw new RuntimeException("Expression is not an instanceOf expression") - } + override def isLengthExpr: Boolean = delegate.astID == ArrayLength.ASTID - override def isLengthExpr: Boolean = delegate.astID == ArrayLength.ASTID + override def getLengthOp: Val = { + if (isLengthExpr) { + return new OpalVal(delegate.asArrayLength, method) + } - override def getLengthOp: Val = { - if (isLengthExpr) { - return new OpalVal(delegate.asArrayLength, method) + throw new RuntimeException("Value is not a length expression") } - throw new RuntimeException("Value is not a length expression") - } + override def isIntConstant: Boolean = delegate.isIntConst - override def isIntConstant: Boolean = delegate.isIntConst + override def isClassConstant: Boolean = delegate.isClassConst - override def isClassConstant: Boolean = delegate.isClassConst + override def getClassConstantType: Type = { + if (isClassConstant) { + return OpalType(delegate.asClassConst.value) + } - override def getClassConstantType: Type = { - if (isClassConstant) { - return OpalType(delegate.asClassConst.value) + throw new RuntimeException("Value is not a class constant") } - throw new RuntimeException("Value is not a class constant") - } + override def withNewMethod(callee: Method): Val = + new OpalVal(delegate, callee.asInstanceOf[OpalMethod]) - override def withNewMethod(callee: Method): Val = new OpalVal(delegate, callee.asInstanceOf[OpalMethod]) + override def withSecondVal(secondVal: Val) = + new OpalDoubleVal(delegate, method, secondVal) - override def withSecondVal(secondVal: Val) = new OpalDoubleVal(delegate, method, secondVal) + override def isLongConstant: Boolean = delegate.isLongConst - override def isLongConstant: Boolean = delegate.isLongConst + override def getIntValue: Int = { + if (isIntConstant) { + return delegate.asIntConst.value + } - override def getIntValue: Int = { - if (isIntConstant) { - return delegate.asIntConst.value + throw new RuntimeException("Value is not an integer constant") } - throw new RuntimeException("Value is not an integer constant") - } + override def getLongValue: Long = { + if (isLongConstant) { + return delegate.asLongConst.value + } - override def getLongValue: Long = { - if (isLongConstant) { - return delegate.asLongConst.value + throw new RuntimeException("Value is not a long constant") } - throw new RuntimeException("Value is not a long constant") - } - - override def getArrayBase: Pair[Val, Integer] = throw new RuntimeException("Value is not an array ref") - - override def getVariableName: String = { - delegate match { - case stringConst: StringConst => "\"" + stringConst.value + "\"" - case intConst: IntConst => intConst.value.toString - case longConst: LongConst => longConst.value.toString - case newExpr: New => s"new ${newExpr.tpe.toJava}" - case newArrayExpr: NewArray[_] => s"new ${newArrayExpr.tpe.toJava}" - case _: NullExpr => "null" - case _ => delegate.toString + override def getArrayBase: Pair[Val, Integer] = throw new RuntimeException( + "Value is not an array ref" + ) + + override def getVariableName: String = { + delegate match { + case stringConst: StringConst => "\"" + stringConst.value + "\"" + case intConst: IntConst => intConst.value.toString + case longConst: LongConst => longConst.value.toString + case newExpr: New => s"new ${newExpr.tpe.toJava}" + case newArrayExpr: NewArray[_] => s"new ${newArrayExpr.tpe.toJava}" + case _: NullExpr => "null" + case _ => delegate.toString + } } - } - override def hashCode: Int = Objects.hash(super.hashCode(), delegate.hashCode()) + override def hashCode: Int = + Objects.hash(super.hashCode(), delegate.hashCode()) - private def canEqual(a: Any): Boolean = a.isInstanceOf[OpalVal] + private def canEqual(a: Any): Boolean = a.isInstanceOf[OpalVal] - override def equals(obj: Any): Boolean = obj match { - case other: OpalVal => other.canEqual(this) && super.equals(other) && this.delegate == other.delegate - case _ => false - } + override def equals(obj: Any): Boolean = obj match { + case other: OpalVal => + other.canEqual(this) && super.equals( + other + ) && this.delegate == other.delegate + case _ => false + } - override def toString: String = getVariableName + override def toString: String = getVariableName } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalWrappedClass.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalWrappedClass.scala index 2e0a43caa..7c34b482a 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalWrappedClass.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalWrappedClass.scala @@ -1,46 +1,62 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ package boomerang.scope.opal.tac +import boomerang.scope.Method +import boomerang.scope.Type +import boomerang.scope.WrappedClass import boomerang.scope.opal.OpalClient -import boomerang.scope.{Method, Type, WrappedClass} -import org.opalj.br.ClassFile - import java.util +import org.opalj.br.ClassFile case class OpalWrappedClass(delegate: ClassFile) extends WrappedClass { - override def getMethods: util.Set[Method] = { - val methods = new util.HashSet[Method] + override def getMethods: util.Set[Method] = { + val methods = new util.HashSet[Method] - delegate.methods.foreach(method => { - methods.add(OpalMethod(method)) - }) + delegate.methods.foreach(method => { + methods.add(OpalMethod(method)) + }) - methods - } + methods + } - override def hasSuperclass: Boolean = delegate.superclassType.isDefined + override def hasSuperclass: Boolean = delegate.superclassType.isDefined - override def getSuperclass: WrappedClass = { - if (hasSuperclass) { - val superClass = OpalClient.getClassFileForType(delegate.superclassType.get) + override def getSuperclass: WrappedClass = { + if (hasSuperclass) { + val superClass = + OpalClient.getClassFileForType(delegate.superclassType.get) - if (superClass.isDefined) { - return OpalWrappedClass(superClass.get) - } else { - return OpalPhantomWrappedClass(delegate.superclassType.get) - } - } + if (superClass.isDefined) { + return OpalWrappedClass(superClass.get) + } else { + return OpalPhantomWrappedClass(delegate.superclassType.get) + } + } - throw new RuntimeException("Class " + delegate.thisType.toJava + " has no super class") - } + throw new RuntimeException( + "Class " + delegate.thisType.toJava + " has no super class" + ) + } - override def getType: Type = OpalType(delegate.thisType) + override def getType: Type = OpalType(delegate.thisType) - override def isApplicationClass: Boolean = OpalClient.isApplicationClass(delegate) + override def isApplicationClass: Boolean = + OpalClient.isApplicationClass(delegate) - override def getFullyQualifiedName: String = delegate.fqn.replace("/", ".") + override def getFullyQualifiedName: String = delegate.fqn.replace("/", ".") - override def isPhantom: Boolean = false + override def isPhantom: Boolean = false - override def toString: String = delegate.toString() + override def toString: String = delegate.toString() } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/BoomerangTACode.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/BoomerangTACode.scala index 00f025bbc..11e0c4163 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/BoomerangTACode.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/BoomerangTACode.scala @@ -1,12 +1,30 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ package boomerang.scope.opal.transformation -import org.opalj.tac.{Assignment, Stmt} +import org.opalj.tac.Assignment +import org.opalj.tac.Stmt class BoomerangTACode(val cfg: StmtGraph) { - def statements: Array[Stmt[TacLocal]] = cfg.statements.toArray + def statements: Array[Stmt[TacLocal]] = cfg.statements.toArray - def getLocals: Set[TacLocal] = statements.filter(stmt => stmt.astID == Assignment.ASTID).map(stmt => stmt.asAssignment.targetVar).toSet + def getLocals: Set[TacLocal] = statements + .filter(stmt => stmt.astID == Assignment.ASTID) + .map(stmt => stmt.asAssignment.targetVar) + .toSet - def getParameterLocals: List[TacLocal] = statements.filter(stmt => stmt.pc == -1).map(stmt => stmt.asAssignment.targetVar).toList + def getParameterLocals: List[TacLocal] = statements + .filter(stmt => stmt.pc == -1) + .map(stmt => stmt.asAssignment.targetVar) + .toList } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/StmtGraph.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/StmtGraph.scala index a98894997..800504290 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/StmtGraph.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/StmtGraph.scala @@ -1,147 +1,188 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ package boomerang.scope.opal.transformation import org.opalj.br.cfg.CFG -import org.opalj.tac.{Return, Stmt, TACStmts} - +import org.opalj.tac.Return +import org.opalj.tac.Stmt +import org.opalj.tac.TACStmts import scala.collection.mutable -class StmtGraph private (val tac: Array[Stmt[TacLocal]], val heads: Set[Stmt[TacLocal]], val tails: Set[Stmt[TacLocal]], val predecessors: Map[Stmt[TacLocal], Set[Stmt[TacLocal]]], val successors: Map[Stmt[TacLocal], Set[Stmt[TacLocal]]], val statements: List[Stmt[TacLocal]]) { - - // TODO Update if and goto targets - def insertBefore(insertStmt: Stmt[TacLocal], existingStmt: Stmt[TacLocal]): StmtGraph = { - val tempSuccessor = mutable.Map.from(successors) - - // Insert s1 between s0 -> s2 - val preds = predecessors(existingStmt) - preds.foreach(pred => { - // Update succs of s0 from s2 to s1, giving s0 -> s1 ... s2 - val succsOfPred = successors(pred) - assert(succsOfPred.contains(existingStmt)) - - val newSuccs = succsOfPred - existingStmt + insertStmt - tempSuccessor.put(pred, newSuccs) - }) - - // Update preds of s2 from s0 to (only) s1, giving s0 ... s1 <- s2 - val tempPreds = mutable.Map.from(predecessors) - tempPreds.put(existingStmt, Set(insertStmt)) - - // Add the new statement - tempPreds.put(insertStmt, preds) - tempSuccessor.put(insertStmt, Set(existingStmt)) - - // Potential head statement update - var newHeads = heads.map(identity) - if (heads.contains(existingStmt)) { - newHeads = newHeads - existingStmt + insertStmt +class StmtGraph private ( + val tac: Array[Stmt[TacLocal]], + val heads: Set[Stmt[TacLocal]], + val tails: Set[Stmt[TacLocal]], + val predecessors: Map[Stmt[TacLocal], Set[Stmt[TacLocal]]], + val successors: Map[Stmt[TacLocal], Set[Stmt[TacLocal]]], + val statements: List[Stmt[TacLocal]] +) { + + // TODO Update if and goto targets + def insertBefore( + insertStmt: Stmt[TacLocal], + existingStmt: Stmt[TacLocal] + ): StmtGraph = { + val tempSuccessor = mutable.Map.from(successors) + + // Insert s1 between s0 -> s2 + val preds = predecessors(existingStmt) + preds.foreach(pred => { + // Update succs of s0 from s2 to s1, giving s0 -> s1 ... s2 + val succsOfPred = successors(pred) + assert(succsOfPred.contains(existingStmt)) + + val newSuccs = succsOfPred - existingStmt + insertStmt + tempSuccessor.put(pred, newSuccs) + }) + + // Update preds of s2 from s0 to (only) s1, giving s0 ... s1 <- s2 + val tempPreds = mutable.Map.from(predecessors) + tempPreds.put(existingStmt, Set(insertStmt)) + + // Add the new statement + tempPreds.put(insertStmt, preds) + tempSuccessor.put(insertStmt, Set(existingStmt)) + + // Potential head statement update + var newHeads = heads.map(identity) + if (heads.contains(existingStmt)) { + newHeads = newHeads - existingStmt + insertStmt + } + + val newStatements = statements.flatMap { + case `existingStmt` => List(insertStmt, existingStmt) + case x => List(x) + } + + new StmtGraph( + tac, + newHeads, + tails, + tempPreds.toMap, + tempSuccessor.toMap, + newStatements + ) } - val newStatements = statements.flatMap { - case `existingStmt` => List(insertStmt, existingStmt) - case x => List(x) - } + def remove(stmt: Stmt[TacLocal]): StmtGraph = { + if (tails.contains(stmt)) + throw new RuntimeException("Cannot remove tail statement") - new StmtGraph(tac, newHeads, tails, tempPreds.toMap, tempSuccessor.toMap, newStatements) - } + val tempPreds = mutable.Map.from(predecessors) + val tempSuccs = mutable.Map.from(successors) - def remove(stmt: Stmt[TacLocal]): StmtGraph = { - if (tails.contains(stmt)) throw new RuntimeException("Cannot remove tail statement") + val preds = predecessors(stmt) + val succs = successors(stmt) + preds.foreach(pred => { + val succsOfPred = successors(pred) - val tempPreds = mutable.Map.from(predecessors) - val tempSuccs = mutable.Map.from(successors) + assert(succsOfPred.contains(stmt), "Inconsistent state in graph") + tempSuccs.put(pred, succsOfPred ++ succs - stmt) + }) - val preds = predecessors(stmt) - val succs = successors(stmt) - preds.foreach(pred => { - val succsOfPred = successors(pred) + succs.foreach(succ => { + val predsOfSuccs = predecessors(succ) - assert(succsOfPred.contains(stmt), "Inconsistent state in graph") - tempSuccs.put(pred, succsOfPred ++ succs - stmt) - }) + assert(predsOfSuccs.contains(stmt), "Inconsistent state in graph") + tempPreds.put(succ, predsOfSuccs ++ preds - stmt) + }) - succs.foreach(succ => { - val predsOfSuccs = predecessors(succ) + var newHeads = heads.map(identity) + if (heads.contains(stmt)) { + newHeads = newHeads - stmt + newHeads = newHeads ++ succs + } - assert(predsOfSuccs.contains(stmt), "Inconsistent state in graph") - tempPreds.put(succ, predsOfSuccs ++ preds - stmt) - }) + val newStatements = statements.filter(s => s != stmt) + val newPreds = tempPreds.filter(s => s._1 != stmt).toMap + val newSuccs = tempSuccs.filter(s => s._1 != stmt).toMap - var newHeads = heads.map(identity) - if (heads.contains(stmt)) { - newHeads = newHeads - stmt - newHeads = newHeads ++ succs + assert(!newHeads.contains(stmt)) + assert(!newStatements.contains(stmt)) + assert(!newPreds.contains(stmt)) + assert(!newSuccs.contains(stmt)) + new StmtGraph(tac, newHeads, tails, newPreds, newSuccs, newStatements) } - - val newStatements = statements.filter(s => s != stmt) - val newPreds = tempPreds.filter(s => s._1 != stmt).toMap - val newSuccs = tempSuccs.filter(s => s._1 != stmt).toMap - - assert(!newHeads.contains(stmt)) - assert(!newStatements.contains(stmt)) - assert(!newPreds.contains(stmt)) - assert(!newSuccs.contains(stmt)) - new StmtGraph(tac, newHeads, tails, newPreds, newSuccs, newStatements) - } } object StmtGraph { - def apply(tac: Array[Stmt[TacLocal]], cfg: CFG[Stmt[TacLocal], TACStmts[TacLocal]], pcToIndex: Array[Int], exceptionHandlers: Array[Int]): StmtGraph = { - - def computeHead: Set[Stmt[TacLocal]] = exceptionHandlers.map(eh => tac(eh)).toSet + tac(0) - - def computeTails: Set[Stmt[TacLocal]] = { - tac.filter(stmt => stmt.pc >= 0).filter(stmt => { - val stmtIndex = pcToIndex(stmt.pc) - val successors = cfg.successors(stmtIndex) - - // No successors => tail statement - successors.isEmpty - }).toSet - } - - def computePredecessors(stmt: Stmt[TacLocal]): Set[Stmt[TacLocal]] = { - // head - if (stmt == tac(0)) return Set.empty - - // Pred of identity statements are just the previous statement - if (stmt.pc < 0) { - val stmtIndex = tac.indexOf(stmt) - return Set(tac(stmtIndex - 1)) - } - - // The first original statement - if (stmt.pc == 0) { - val stmtIndex = tac.indexOf(stmt) - return Set(tac(stmtIndex - 1)) - } - - val stmtIndex = pcToIndex(stmt.pc) - if (exceptionHandlers.contains(stmtIndex)) { - return Set() - } - - val predecessors = cfg.predecessors(stmtIndex) - predecessors.map(predecessorIndex => tac(predecessorIndex)) + def apply( + tac: Array[Stmt[TacLocal]], + cfg: CFG[Stmt[TacLocal], TACStmts[TacLocal]], + pcToIndex: Array[Int], + exceptionHandlers: Array[Int] + ): StmtGraph = { + + def computeHead: Set[Stmt[TacLocal]] = + exceptionHandlers.map(eh => tac(eh)).toSet + tac(0) + + def computeTails: Set[Stmt[TacLocal]] = { + tac + .filter(stmt => stmt.pc >= 0) + .filter(stmt => { + val stmtIndex = pcToIndex(stmt.pc) + val successors = cfg.successors(stmtIndex) + + // No successors => tail statement + successors.isEmpty + }) + .toSet + } + + def computePredecessors(stmt: Stmt[TacLocal]): Set[Stmt[TacLocal]] = { + // head + if (stmt == tac(0)) return Set.empty + + // Pred of identity statements are just the previous statement + if (stmt.pc < 0) { + val stmtIndex = tac.indexOf(stmt) + return Set(tac(stmtIndex - 1)) + } + + // The first original statement + if (stmt.pc == 0) { + val stmtIndex = tac.indexOf(stmt) + return Set(tac(stmtIndex - 1)) + } + + val stmtIndex = pcToIndex(stmt.pc) + if (exceptionHandlers.contains(stmtIndex)) { + return Set() + } + + val predecessors = cfg.predecessors(stmtIndex) + predecessors.map(predecessorIndex => tac(predecessorIndex)) + } + + def computeSuccessors(stmt: Stmt[TacLocal]): Set[Stmt[TacLocal]] = { + // Successor of identity statements is just the following statement + if (stmt.pc < 0) { + val stmtIndex = tac.indexOf(stmt) + return Set(tac(stmtIndex + 1)) + } + + val stmtIndex = pcToIndex(stmt.pc) + val successors = cfg.successors(stmtIndex) + successors + .filter(s => !exceptionHandlers.contains(s)) + .map(successorIndex => tac(successorIndex)) + } + + val heads = computeHead + val tails = computeTails + val predecessors = tac.map(stmt => stmt -> computePredecessors(stmt)).toMap + val successors = tac.map(stmt => stmt -> computeSuccessors(stmt)).toMap + + new StmtGraph(tac, heads, tails, predecessors, successors, tac.toList) } - - def computeSuccessors(stmt: Stmt[TacLocal]): Set[Stmt[TacLocal]] = { - // Successor of identity statements is just the following statement - if (stmt.pc < 0) { - val stmtIndex = tac.indexOf(stmt) - return Set(tac(stmtIndex + 1)) - } - - val stmtIndex = pcToIndex(stmt.pc) - val successors = cfg.successors(stmtIndex) - successors.filter(s => !exceptionHandlers.contains(s)).map(successorIndex => tac(successorIndex)) - } - - val heads = computeHead - val tails = computeTails - val predecessors = tac.map(stmt => stmt -> computePredecessors(stmt)).toMap - val successors = tac.map(stmt => stmt -> computeSuccessors(stmt)).toMap - - new StmtGraph(tac, heads, tails, predecessors, successors, tac.toList) - } } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacBodyBuilder.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacBodyBuilder.scala index 76f49d854..b2d0c4710 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacBodyBuilder.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacBodyBuilder.scala @@ -1,3 +1,14 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ package boomerang.scope.opal.transformation import boomerang.scope.opal.transformation.stack.OperandStackBuilder @@ -6,44 +17,64 @@ import org.opalj.ai.domain.l0.PrimitiveTACAIDomain import org.opalj.br.Method import org.opalj.br.analyses.Project import org.opalj.br.cfg.CFGFactory -import org.opalj.tac.{Stmt, TACNaive, TACStmts} +import org.opalj.tac.Stmt +import org.opalj.tac.TACNaive +import org.opalj.tac.TACStmts object TacBodyBuilder { - def apply(project: Project[_], method: Method): BoomerangTACode = { - if (method.body.isEmpty) { - throw new IllegalArgumentException("Cannot compute TAC for method without existing body: " + method) - } + def apply(project: Project[_], method: Method): BoomerangTACode = { + if (method.body.isEmpty) { + throw new IllegalArgumentException( + "Cannot compute TAC for method without existing body: " + method + ) + } - val tacNaive = TACNaive(method, project.classHierarchy) - val stackHandler = OperandStackBuilder(method, tacNaive) + val tacNaive = TACNaive(method, project.classHierarchy) + val stackHandler = OperandStackBuilder(method, tacNaive) - // TODO Use other domain to compute static type information - val domain = new PrimitiveTACAIDomain(project.classHierarchy, method) - val localTransformedTac = LocalTransformer(project, method, tacNaive, stackHandler, domain) - assert(tacNaive.stmts.length == localTransformedTac.length, "Wrong transformation") + // TODO Use other domain to compute static type information + val domain = new PrimitiveTACAIDomain(project.classHierarchy, method) + val localTransformedTac = + LocalTransformer(project, method, tacNaive, stackHandler, domain) + assert( + tacNaive.stmts.length == localTransformedTac.length, + "Wrong transformation" + ) - val inlinedTac = InlineLocalTransformer(localTransformedTac, stackHandler) - assert(tacNaive.stmts.length == inlinedTac.length, "Wrong transformation") + val inlinedTac = InlineLocalTransformer(localTransformedTac, stackHandler) + assert(tacNaive.stmts.length == inlinedTac.length, "Wrong transformation") - val propagatedTac = LocalPropagationTransformer(inlinedTac, stackHandler) - assert(tacNaive.stmts.length == propagatedTac.length, "Wrong transformation") + val propagatedTac = LocalPropagationTransformer(inlinedTac, stackHandler) + assert( + tacNaive.stmts.length == propagatedTac.length, + "Wrong transformation" + ) - // Update the CFG - val cfg = CFGFactory(method, project.classHierarchy) - if (cfg.isEmpty) { - throw new RuntimeException("Could not compute CFG for method " + method.name) - } + // Update the CFG + val cfg = CFGFactory(method, project.classHierarchy) + if (cfg.isEmpty) { + throw new RuntimeException( + "Could not compute CFG for method " + method.name + ) + } - val tacCfg = cfg.get.mapPCsToIndexes[Stmt[TacLocal], TACStmts[TacLocal]](TACStmts(propagatedTac), tacNaive.pcToIndex, i => i, propagatedTac.length) + val tacCfg = cfg.get.mapPCsToIndexes[Stmt[TacLocal], TACStmts[TacLocal]]( + TACStmts(propagatedTac), + tacNaive.pcToIndex, + i => i, + propagatedTac.length + ) - val exceptionHandlers = tacNaive.exceptionHandlers.map(eh => eh.handlerPC).toArray - var stmtGraph = StmtGraph(propagatedTac, tacCfg, tacNaive.pcToIndex, exceptionHandlers) + val exceptionHandlers = + tacNaive.exceptionHandlers.map(eh => eh.handlerPC).toArray + var stmtGraph = + StmtGraph(propagatedTac, tacCfg, tacNaive.pcToIndex, exceptionHandlers) - stmtGraph = NopTransformer(stmtGraph) - stmtGraph = NullifyFieldsTransformer(method, stmtGraph) - stmtGraph = NopEliminator(stmtGraph) + stmtGraph = NopTransformer(stmtGraph) + stmtGraph = NullifyFieldsTransformer(method, stmtGraph) + stmtGraph = NopEliminator(stmtGraph) - new BoomerangTACode(stmtGraph) - } + new BoomerangTACode(stmtGraph) + } } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacLocal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacLocal.scala index 6863345b5..e372cdba4 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacLocal.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacLocal.scala @@ -1,145 +1,181 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ package boomerang.scope.opal.transformation -import org.opalj.br.ComputationalType -import org.opalj.tac.{DUVar, Var} -import org.opalj.value.{IsNullValue, ValueInformation} - import java.util.Objects +import org.opalj.br.ComputationalType +import org.opalj.tac.DUVar +import org.opalj.tac.Var +import org.opalj.value.IsNullValue +import org.opalj.value.ValueInformation trait TacLocal extends Var[TacLocal] { - def id: Int + def id: Int - def isStackLocal: Boolean = false + def isStackLocal: Boolean = false - def isRegisterLocal: Boolean = false + def isRegisterLocal: Boolean = false - def isParameterLocal: Boolean = false + def isParameterLocal: Boolean = false - def isThisLocal: Boolean = false + def isThisLocal: Boolean = false - def isExceptionLocal: Boolean = false + def isExceptionLocal: Boolean = false - def cTpe: ComputationalType + def cTpe: ComputationalType - def valueInformation: ValueInformation + def valueInformation: ValueInformation - final def isSideEffectFree: Boolean = true + final def isSideEffectFree: Boolean = true - override def toCanonicalForm(implicit ev: TacLocal <:< DUVar[ValueInformation]): Nothing = { - throw new IncompatibleClassChangeError( - "TacLocal objects are not expected to inherit from DUVar" - ) - } + override def toCanonicalForm(implicit + ev: TacLocal <:< DUVar[ValueInformation] + ): Nothing = { + throw new IncompatibleClassChangeError( + "TacLocal objects are not expected to inherit from DUVar" + ) + } - override def toString: String = name + override def toString: String = name } -class StackLocal(identifier: Int, computationalType: ComputationalType, valueInfo: ValueInformation, isThis: Boolean = false) extends TacLocal { +class StackLocal( + identifier: Int, + computationalType: ComputationalType, + valueInfo: ValueInformation, + isThis: Boolean = false +) extends TacLocal { - override def id: Int = identifier + override def id: Int = identifier - override def isStackLocal: Boolean = true + override def isStackLocal: Boolean = true - override def isThisLocal: Boolean = isThis + override def isThisLocal: Boolean = isThis - override def name: String = if (isThis) "$this" else s"$$s$identifier" + override def name: String = if (isThis) "$this" else s"$$s$identifier" - override def cTpe: ComputationalType = computationalType + override def cTpe: ComputationalType = computationalType - override def valueInformation: ValueInformation = valueInfo + override def valueInformation: ValueInformation = valueInfo - override def hashCode: Int = Objects.hash(this.getClass.hashCode(), id) + override def hashCode: Int = Objects.hash(this.getClass.hashCode(), id) - override def equals(other: Any): Boolean = other match { - case that: StackLocal => this.id == that.id - case that: RegisterLocal => this.isThisLocal && that.isThisLocal - case _ => false - } + override def equals(other: Any): Boolean = other match { + case that: StackLocal => this.id == that.id + case that: RegisterLocal => this.isThisLocal && that.isThisLocal + case _ => false + } } -class RegisterLocal(identifier: Int, computationalType: ComputationalType, valueInfo: ValueInformation, isThis: Boolean = false, localName: Option[String] = Option.empty) extends TacLocal { +class RegisterLocal( + identifier: Int, + computationalType: ComputationalType, + valueInfo: ValueInformation, + isThis: Boolean = false, + localName: Option[String] = Option.empty +) extends TacLocal { - override def id: Int = identifier + override def id: Int = identifier - override def isRegisterLocal: Boolean = true + override def isRegisterLocal: Boolean = true - override def isThisLocal: Boolean = isThis + override def isThisLocal: Boolean = isThis - override def name: String = { - if (isThis) return "this" - if (localName.isDefined) return localName.get + override def name: String = { + if (isThis) return "this" + if (localName.isDefined) return localName.get - s"r${-identifier - 1}" - } + s"r${-identifier - 1}" + } - override def cTpe: ComputationalType = computationalType + override def cTpe: ComputationalType = computationalType - override def valueInformation: ValueInformation = valueInfo + override def valueInformation: ValueInformation = valueInfo - override def hashCode: Int = Objects.hash(this.getClass.hashCode(), id) + override def hashCode: Int = Objects.hash(this.getClass.hashCode(), id) - override def equals(other: Any): Boolean = other match { - case that: RegisterLocal => this.id == that.id - case that: StackLocal => this.isThisLocal && that.isThisLocal - case _ => false - } + override def equals(other: Any): Boolean = other match { + case that: RegisterLocal => this.id == that.id + case that: StackLocal => this.isThisLocal && that.isThisLocal + case _ => false + } } -class ParameterLocal(identifier: Int, computationalType: ComputationalType, paramName: String) extends TacLocal { +class ParameterLocal( + identifier: Int, + computationalType: ComputationalType, + paramName: String +) extends TacLocal { - override def id: Int = identifier + override def id: Int = identifier - override def isParameterLocal: Boolean = true + override def isParameterLocal: Boolean = true - override def cTpe: ComputationalType = computationalType + override def cTpe: ComputationalType = computationalType - override def valueInformation: ValueInformation = throw new UnsupportedOperationException("No value information available for parameter local") + override def valueInformation: ValueInformation = + throw new UnsupportedOperationException( + "No value information available for parameter local" + ) - override def name: String = paramName + override def name: String = paramName - override def hashCode: Int = Objects.hash(this.getClass.hashCode(), id) + override def hashCode: Int = Objects.hash(this.getClass.hashCode(), id) - override def equals(other: Any): Boolean = other match { - case that: ParameterLocal => this.id == that.id - case _ => false - } + override def equals(other: Any): Boolean = other match { + case that: ParameterLocal => this.id == that.id + case _ => false + } } class NullifiedLocal(identifier: Int, computationalType: ComputationalType) extends TacLocal { - override def id: Int = identifier + override def id: Int = identifier - override def cTpe: ComputationalType = computationalType + override def cTpe: ComputationalType = computationalType - override def valueInformation: ValueInformation = IsNullValue + override def valueInformation: ValueInformation = IsNullValue - override def name: String = s"n$identifier" + override def name: String = s"n$identifier" - override def hashCode: Int = Objects.hash(this.getClass.hashCode(), id) + override def hashCode: Int = Objects.hash(this.getClass.hashCode(), id) - override def equals(other: Any): Boolean = other match { - case that: NullifiedLocal => this.id == that.id - case _ => false - } + override def equals(other: Any): Boolean = other match { + case that: NullifiedLocal => this.id == that.id + case _ => false + } } -class ExceptionLocal(identifier: Int, computationalType: ComputationalType, valueInfo: ValueInformation) extends TacLocal { +class ExceptionLocal( + identifier: Int, + computationalType: ComputationalType, + valueInfo: ValueInformation +) extends TacLocal { - override def id: Int = identifier + override def id: Int = identifier - override def isExceptionLocal: Boolean = true + override def isExceptionLocal: Boolean = true - override def cTpe: ComputationalType = computationalType + override def cTpe: ComputationalType = computationalType - override def valueInformation: ValueInformation = valueInfo + override def valueInformation: ValueInformation = valueInfo - override def name: String = s"e$identifier" + override def name: String = s"e$identifier" - override def hashCode: Int = Objects.hash(this.getClass.hashCode(), id) + override def hashCode: Int = Objects.hash(this.getClass.hashCode(), id) - override def equals(other: Any): Boolean = other match { - case that: ExceptionLocal => this.id == that.id - case _ => false - } + override def equals(other: Any): Boolean = other match { + case that: ExceptionLocal => this.id == that.id + case _ => false + } } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/Operand.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/Operand.scala index f79a049f4..14e24672f 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/Operand.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/Operand.scala @@ -1,28 +1,42 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ package boomerang.scope.opal.transformation.stack -import org.opalj.br.ComputationalType - import java.util.Objects +import org.opalj.br.ComputationalType -class Operand(val id: Int, val cTpe: ComputationalType, private var counter: Int) { +class Operand( + val id: Int, + val cTpe: ComputationalType, + private var counter: Int +) { - private var modified = false + private var modified = false - def localId: Int = counter + def localId: Int = counter - def updateCounter(newCount: Int): Unit = { - counter = newCount - modified = true - } + def updateCounter(newCount: Int): Unit = { + counter = newCount + modified = true + } - def isBranchedOperand: Boolean = modified + def isBranchedOperand: Boolean = modified - override def hashCode: Int = Objects.hash(id) + override def hashCode: Int = Objects.hash(id) - override def equals(obj: Any): Boolean = obj match { - case that: Operand => this.id == that.id - case _ => false - } + override def equals(obj: Any): Boolean = obj match { + case that: Operand => this.id == that.id + case _ => false + } - override def toString: String = s"op$id ($counter)" + override def toString: String = s"op$id ($counter)" } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStack.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStack.scala index 718c1a4ed..63f8f3696 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStack.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStack.scala @@ -1,57 +1,80 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ package boomerang.scope.opal.transformation.stack import org.opalj.tac.IdBasedVar -class OperandStack private(stackHandler: OperandStackHandler, private var stack: List[Operand]) { +class OperandStack private ( + stackHandler: OperandStackHandler, + private var stack: List[Operand] +) { - def stackEntries: List[Operand] = stack + def stackEntries: List[Operand] = stack - def push(idBasedVar: IdBasedVar): Unit = { - val operand = new Operand(idBasedVar.id, idBasedVar.cTpe, stackHandler.nextLocalCounter) - stack = operand :: stack - } + def push(idBasedVar: IdBasedVar): Unit = { + val operand = + new Operand(idBasedVar.id, idBasedVar.cTpe, stackHandler.nextLocalCounter) + stack = operand :: stack + } - def push(operand: Operand): Unit = { - stack = operand :: stack - } + def push(operand: Operand): Unit = { + stack = operand :: stack + } - def pop(idBasedVar: IdBasedVar): Unit = { - if (stack.isEmpty) { - throw new IllegalStateException(s"Cannot pop operand $idBasedVar from empty stack") + def pop(idBasedVar: IdBasedVar): Unit = { + if (stack.isEmpty) { + throw new IllegalStateException( + s"Cannot pop operand $idBasedVar from empty stack" + ) + } + + // Check if stack is in consistent state + val top :: rest = stack + assert( + idBasedVar.id == top.id, + s"Invalid pop operation on operand $idBasedVar" + ) + + // Update stack + stack = rest } - // Check if stack is in consistent state - val top :: rest = stack - assert(idBasedVar.id == top.id, s"Invalid pop operation on operand $idBasedVar") + def pop: Operand = { + if (stack.isEmpty) { + throw new IllegalStateException(s"Cannot pop operand from empty stack") + } - // Update stack - stack = rest - } + val top :: rest = stack + stack = rest - def pop: Operand = { - if (stack.isEmpty) { - throw new IllegalStateException(s"Cannot pop operand from empty stack") + top } - val top :: rest = stack - stack = rest - - top - } + def peek: Operand = { + if (stack.isEmpty) return null - def peek: Operand = { - if (stack.isEmpty) return null - - val top :: _ = stack - top - } + val top :: _ = stack + top + } - def copy: OperandStack = new OperandStack(stackHandler, stack.map(identity)) + def copy: OperandStack = new OperandStack(stackHandler, stack.map(identity)) - override def toString: String = stack.toString() + override def toString: String = stack.toString() } object OperandStack { - def apply(stackHandler: OperandStackHandler, stack: List[Operand] = List.empty) = new OperandStack(stackHandler, stack) + def apply( + stackHandler: OperandStackHandler, + stack: List[Operand] = List.empty + ) = new OperandStack(stackHandler, stack) } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackBuilder.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackBuilder.scala index c3cc91347..5502549a9 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackBuilder.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackBuilder.scala @@ -1,309 +1,384 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ package boomerang.scope.opal.transformation.stack import org.opalj.br.Method -import org.opalj.br.instructions.{DUP, DUP2, DUP2_X1, DUP2_X2, DUP_X1, DUP_X2, NOP, POP, POP2, WIDE} +import org.opalj.br.instructions.DUP +import org.opalj.br.instructions.DUP2 +import org.opalj.br.instructions.DUP2_X1 +import org.opalj.br.instructions.DUP2_X2 +import org.opalj.br.instructions.DUP_X1 +import org.opalj.br.instructions.DUP_X2 +import org.opalj.br.instructions.NOP +import org.opalj.br.instructions.POP +import org.opalj.br.instructions.POP2 +import org.opalj.br.instructions.WIDE import org.opalj.bytecode.PC import org.opalj.tac._ object OperandStackBuilder { - def apply(method: Method, tacNaive: NaiveTACode[_]): OperandStackHandler = { - val stackHandler = new OperandStackHandler + def apply(method: Method, tacNaive: NaiveTACode[_]): OperandStackHandler = { + val stackHandler = new OperandStackHandler - // Initialize work list; we always start with pc 0 - var workList = List(0) + // Initialize work list; we always start with pc 0 + var workList = List(0) - val exceptionHandlersPc = tacNaive.exceptionHandlers.map(eh => tacNaive.stmts(eh.handlerPC).pc) - for (eh <- exceptionHandlersPc) { - workList ::= eh - } - - while (workList.nonEmpty) { - val currPc = workList.head - val currStmt = tacNaive.stmts(tacNaive.pcToIndex(currPc)) - workList = workList.tail - - processStmt(currStmt) - - def pcOfNextStatement(pc: PC): PC = method.body.get.pcOfNextInstruction(pc) - - def schedule(nextPc: PC, stack: OperandStack): Unit = { - val merged = stackHandler.mergeStack(nextPc, stack) - - if (merged) { - workList ::= nextPc + val exceptionHandlersPc = + tacNaive.exceptionHandlers.map(eh => tacNaive.stmts(eh.handlerPC).pc) + for (eh <- exceptionHandlersPc) { + workList ::= eh } - } - - def processStmt(stmt: Stmt[IdBasedVar]): Unit = { - val stack = stackHandler.getOrCreate(stmt.pc) - - stmt match { - case If(pc, left, _, right, target) => - val rightOps = processExpr(right) - rightOps.foreach(op => stack.pop(op)) - - val leftOps = processExpr(left) - leftOps.foreach(op => stack.pop(op)) - - schedule(pcOfNextStatement(pc), stack) - - val targetStmt = tacNaive.stmts(target) - schedule(targetStmt.pc, stack) - case Goto(_, target) => - val targetStmt = tacNaive.stmts(target) - schedule(targetStmt.pc, stack) - case Ret(pc, returnAddresses) => - // TODO - case JSR(_, target) => - schedule(target, stack) - case Switch(_, defaultTarget, index: IdBasedVar, nPairs) => - stack.pop(index) - - nPairs.foreach(target => { - val targetStmt = tacNaive.stmts(target.value) - schedule(targetStmt.pc, stack) - }) - - val defaultTargetStmt = tacNaive.stmts(defaultTarget) - schedule(defaultTargetStmt.pc, stack) - case Assignment(pc, targetVar: IdBasedVar, expr: Expr[IdBasedVar]) => - // Exception handlers are defined implicitly, so we cannot pop them from the stack - if (!exceptionHandlersPc.contains(pc)) { - val operands = processExpr(expr) - operands.foreach(op => stack.pop(op)) - } - - if (targetVar.id >= 0) { - stack.push(targetVar) - stackHandler.addDefSite(pc, stack.peek) - } - schedule(pcOfNextStatement(pc), stack) - case ReturnValue(_, expr: IdBasedVar) => - // TODO Bug in Opal causes to return the wrong operand (fixed but not released yet) - // stack.pop(expr) - // No scheduling since there is no next statement - case Return(_) => // No scheduling since there is no next statement - case Nop(pc) => - val instr = method.body.get.instructions(pc) - - // TODO - // Use pattern matching from stack.stackEntries to avoid having so many sequential - // operations (as done in TacNaive) - instr.opcode match { - case NOP.opcode => - schedule(pcOfNextStatement(pc), stack) - case POP.opcode => - stack.pop - - schedule(pcOfNextStatement(pc), stack) - case POP2.opcode => - val top = stack.pop - if (top.cTpe.categoryId == 1) { - stack.pop - } + while (workList.nonEmpty) { + val currPc = workList.head + val currStmt = tacNaive.stmts(tacNaive.pcToIndex(currPc)) + workList = workList.tail - schedule(pcOfNextStatement(pc), stack) - case DUP.opcode => - val dupOperand = stack.peek - stack.push(dupOperand) - - schedule(pcOfNextStatement(pc), stack) - case DUP_X1.opcode => - val v1 = stack.pop - val v2 = stack.pop - - stack.push(v1) - stack.push(v2) - stack.push(v1) - - schedule(pcOfNextStatement(pc), stack) - case DUP_X2.opcode => - val v1 = stack.pop - val v2 = stack.pop - - if (v2.cTpe.categoryId == 1) { - val v3 = stack.pop - - stack.push(v1) - stack.push(v3) - stack.push(v2) - stack.push(v1) - } else { - stack.push(v1) - stack.push(v2) - stack.push(v1) - } + processStmt(currStmt) - schedule(pcOfNextStatement(pc), stack) - case DUP2.opcode => - val v1 = stack.pop + def pcOfNextStatement(pc: PC): PC = + method.body.get.pcOfNextInstruction(pc) - if (v1.cTpe.categoryId == 1) { - val v2 = stack.pop + def schedule(nextPc: PC, stack: OperandStack): Unit = { + val merged = stackHandler.mergeStack(nextPc, stack) - stack.push(v2) - stack.push(v1) - stack.push(v2) - stack.push(v1) - } else { - stack.push(v1) - stack.push(v1) + if (merged) { + workList ::= nextPc } + } - schedule(pcOfNextStatement(pc), stack) - case DUP2_X1.opcode => - val v1 = stack.pop - val v2 = stack.pop - - if (v1.cTpe.categoryId == 1) { - val v3 = stack.pop - - stack.push(v2) - stack.push(v1) - stack.push(v3) - stack.push(v2) - stack.push(v1) - } else { - stack.push(v1) - stack.push(v2) - stack.push(v1) + def processStmt(stmt: Stmt[IdBasedVar]): Unit = { + val stack = stackHandler.getOrCreate(stmt.pc) + + stmt match { + case If(pc, left, _, right, target) => + val rightOps = processExpr(right) + rightOps.foreach(op => stack.pop(op)) + + val leftOps = processExpr(left) + leftOps.foreach(op => stack.pop(op)) + + schedule(pcOfNextStatement(pc), stack) + + val targetStmt = tacNaive.stmts(target) + schedule(targetStmt.pc, stack) + case Goto(_, target) => + val targetStmt = tacNaive.stmts(target) + schedule(targetStmt.pc, stack) + case Ret(pc, returnAddresses) => + // TODO + case JSR(_, target) => + schedule(target, stack) + case Switch(_, defaultTarget, index: IdBasedVar, nPairs) => + stack.pop(index) + + nPairs.foreach(target => { + val targetStmt = tacNaive.stmts(target.value) + schedule(targetStmt.pc, stack) + }) + + val defaultTargetStmt = tacNaive.stmts(defaultTarget) + schedule(defaultTargetStmt.pc, stack) + case Assignment(pc, targetVar: IdBasedVar, expr: Expr[IdBasedVar]) => + // Exception handlers are defined implicitly, so we cannot pop them from the stack + if (!exceptionHandlersPc.contains(pc)) { + val operands = processExpr(expr) + operands.foreach(op => stack.pop(op)) + } + + if (targetVar.id >= 0) { + stack.push(targetVar) + stackHandler.addDefSite(pc, stack.peek) + } + + schedule(pcOfNextStatement(pc), stack) + case ReturnValue(_, expr: IdBasedVar) => + // TODO Bug in Opal causes to return the wrong operand (fixed but not released yet) + // stack.pop(expr) + // No scheduling since there is no next statement + case Return(_) => // No scheduling since there is no next statement + case Nop(pc) => + val instr = method.body.get.instructions(pc) + + // TODO + // Use pattern matching from stack.stackEntries to avoid having so many sequential + // operations (as done in TacNaive) + instr.opcode match { + case NOP.opcode => + schedule(pcOfNextStatement(pc), stack) + case POP.opcode => + stack.pop + + schedule(pcOfNextStatement(pc), stack) + case POP2.opcode => + val top = stack.pop + if (top.cTpe.categoryId == 1) { + stack.pop + } + + schedule(pcOfNextStatement(pc), stack) + case DUP.opcode => + val dupOperand = stack.peek + stack.push(dupOperand) + + schedule(pcOfNextStatement(pc), stack) + case DUP_X1.opcode => + val v1 = stack.pop + val v2 = stack.pop + + stack.push(v1) + stack.push(v2) + stack.push(v1) + + schedule(pcOfNextStatement(pc), stack) + case DUP_X2.opcode => + val v1 = stack.pop + val v2 = stack.pop + + if (v2.cTpe.categoryId == 1) { + val v3 = stack.pop + + stack.push(v1) + stack.push(v3) + stack.push(v2) + stack.push(v1) + } else { + stack.push(v1) + stack.push(v2) + stack.push(v1) + } + + schedule(pcOfNextStatement(pc), stack) + case DUP2.opcode => + val v1 = stack.pop + + if (v1.cTpe.categoryId == 1) { + val v2 = stack.pop + + stack.push(v2) + stack.push(v1) + stack.push(v2) + stack.push(v1) + } else { + stack.push(v1) + stack.push(v1) + } + + schedule(pcOfNextStatement(pc), stack) + case DUP2_X1.opcode => + val v1 = stack.pop + val v2 = stack.pop + + if (v1.cTpe.categoryId == 1) { + val v3 = stack.pop + + stack.push(v2) + stack.push(v1) + stack.push(v3) + stack.push(v2) + stack.push(v1) + } else { + stack.push(v1) + stack.push(v2) + stack.push(v1) + } + + schedule(pcOfNextStatement(pc), stack) + case DUP2_X2.opcode => + val v1 = stack.pop + val v2 = stack.pop + val v3 = stack.pop + + if ( + v1.cTpe.categoryId == 1 && v2.cTpe.categoryId == 1 && v3.cTpe.categoryId == 1 + ) { + val v4 = stack.pop + + stack.push(v2) + stack.push(v1) + stack.push(v4) + stack.push(v3) + stack.push(v2) + stack.push(v1) + } else if ( + v1.cTpe.categoryId == 2 && v2.cTpe.categoryId == 1 && v3.cTpe.categoryId == 1 + ) { + stack.push(v1) + stack.push(v3) + stack.push(v2) + stack.push(v1) + } else if ( + v1.cTpe.categoryId == 1 && v2.cTpe.categoryId == 1 && v3.cTpe.categoryId == 2 + ) { + stack.push(v2) + stack.push(v1) + stack.push(v3) + stack.push(v2) + stack.push(v1) + } else { + stack.push(v3) + stack.push(v1) + stack.push(v2) + stack.push(v1) + } + + schedule(pcOfNextStatement(pc), stack) + case WIDE.opcode => + schedule(pcOfNextStatement(pc), stack) + case _ => + throw new RuntimeException( + "Unknown instruction for NOP: " + instr + ) + } + + schedule(pcOfNextStatement(pc), stack) + case MonitorEnter(pc, objRef: IdBasedVar) => + stack.pop(objRef) + + schedule(pcOfNextStatement(pc), stack) + case MonitorExit(pc, objRef: IdBasedVar) => + stack.pop(objRef) + + schedule(pcOfNextStatement(pc), stack) + case ArrayStore( + pc, + arrayRef: IdBasedVar, + index: IdBasedVar, + value: IdBasedVar + ) => + stack.pop(value) + stack.pop(index) + stack.pop(arrayRef) + + schedule(pcOfNextStatement(pc), stack) + case Throw(_, exception: IdBasedVar) => + stack.pop(exception) + // No scheduling since there is no next statement + case PutStatic(pc, _, _, _, value: IdBasedVar) => + stack.pop(value) + + schedule(pcOfNextStatement(pc), stack) + case PutField(pc, _, _, _, objRef: IdBasedVar, value: IdBasedVar) => + stack.pop(value) + stack.pop(objRef) + + schedule(pcOfNextStatement(pc), stack) + case NonVirtualMethodCall( + pc, + _, + _, + _, + _, + receiver: IdBasedVar, + params: Seq[_] + ) => + params.reverse.foreach(p => stack.pop(p.asVar)) + stack.pop(receiver) + + schedule(pcOfNextStatement(pc), stack) + case VirtualMethodCall( + pc, + _, + _, + _, + _, + receiver: IdBasedVar, + params: Seq[_] + ) => + params.reverse.foreach(p => stack.pop(p.asVar)) + stack.pop(receiver) + + schedule(pcOfNextStatement(pc), stack) + case StaticMethodCall(pc, _, _, _, _, params: Seq[_]) => + params.reverse.foreach(p => stack.pop(p.asVar)) + + schedule(pcOfNextStatement(pc), stack) + case InvokedynamicMethodCall(pc, _, _, _, params: Seq[_]) => + params.reverse.foreach(p => stack.pop(p.asVar)) + + schedule(pcOfNextStatement(pc), stack) + case ExprStmt(pc, expr) => + processExpr(expr) + + schedule(pcOfNextStatement(pc), stack) + case CaughtException(pc, _, _) => + // Only used in TACAI, so no stack manipulation is required + schedule(pcOfNextStatement(pc), stack) + case Checkcast(pc, value, _) => + // TODO Push new stack value + schedule(pcOfNextStatement(pc), stack) + case _ => throw new RuntimeException("Unknown statement: " + stmt) } + } - schedule(pcOfNextStatement(pc), stack) - case DUP2_X2.opcode => - val v1 = stack.pop - val v2 = stack.pop - val v3 = stack.pop - - if (v1.cTpe.categoryId == 1 && v2.cTpe.categoryId == 1 && v3.cTpe.categoryId == 1) { - val v4 = stack.pop - - stack.push(v2) - stack.push(v1) - stack.push(v4) - stack.push(v3) - stack.push(v2) - stack.push(v1) - } else if (v1.cTpe.categoryId == 2 && v2.cTpe.categoryId == 1 && v3.cTpe.categoryId == 1) { - stack.push(v1) - stack.push(v3) - stack.push(v2) - stack.push(v1) - } else if (v1.cTpe.categoryId == 1 && v2.cTpe.categoryId == 1 && v3.cTpe.categoryId == 2) { - stack.push(v2) - stack.push(v1) - stack.push(v3) - stack.push(v2) - stack.push(v1) - } else { - stack.push(v3) - stack.push(v1) - stack.push(v2) - stack.push(v1) + def processExpr(expr: Expr[IdBasedVar]): List[IdBasedVar] = { + expr match { + case v: IdBasedVar => if (v.id >= 0) List(v) else List() + case InstanceOf(_, value: IdBasedVar, _) => List(value) + case Compare(_, left: IdBasedVar, _, right: IdBasedVar) => + List(right, left) + case Param(_, _) => List() + case MethodTypeConst(_, _) => List() + case MethodHandleConst(_, _) => List() + case IntConst(_, _) => List() + case LongConst(_, _) => List() + case FloatConst(_, _) => List() + case DoubleConst(_, _) => List() + case StringConst(_, _) => List() + case ClassConst(_, _) => List() + case DynamicConst(_, _, _, _) => List() + case NullExpr(_) => List() + case BinaryExpr(_, _, _, left, right) => + processExpr(right) ++ processExpr(left) + case PrefixExpr(_, _, _, operand: IdBasedVar) => List(operand) + case PrimitiveTypecastExpr(_, _, operand: IdBasedVar) => List(operand) + case New(_, _) => List() + case NewArray(_, counts: Seq[_], _) => counts.map(c => c.asVar).toList + case ArrayLoad(_, index: IdBasedVar, arrayRef: IdBasedVar) => + List(index, arrayRef) + case ArrayLength(_, arrayRef: IdBasedVar) => List(arrayRef) + case GetField(_, _, _, _, objRef: IdBasedVar) => List(objRef) + case GetStatic(_, _, _, _) => List() + case InvokedynamicFunctionCall(_, _, _, _, params: Seq[_]) => + params.map(p => p.asVar).toList.reverse + case NonVirtualFunctionCall( + _, + _, + _, + _, + _, + receiver: IdBasedVar, + params: Seq[_] + ) => + params.map(p => p.asVar).toList.reverse :+ receiver + case VirtualFunctionCall( + _, + _, + _, + _, + _, + receiver: IdBasedVar, + params: Seq[_] + ) => + params.map(p => p.asVar).toList.reverse :+ receiver + case StaticFunctionCall(_, _, _, _, _, params: Seq[_]) => + params.map(p => p.asVar).toList.reverse + case _ => throw new RuntimeException("Unknown expression: " + expr) } - - schedule(pcOfNextStatement(pc), stack) - case WIDE.opcode => - schedule(pcOfNextStatement(pc), stack) - case _ => throw new RuntimeException("Unknown instruction for NOP: " + instr) } - schedule(pcOfNextStatement(pc), stack) - case MonitorEnter(pc, objRef: IdBasedVar) => - stack.pop(objRef) - - schedule(pcOfNextStatement(pc), stack) - case MonitorExit(pc, objRef: IdBasedVar) => - stack.pop(objRef) - - schedule(pcOfNextStatement(pc), stack) - case ArrayStore(pc, arrayRef: IdBasedVar, index: IdBasedVar, value: IdBasedVar) => - stack.pop(value) - stack.pop(index) - stack.pop(arrayRef) - - schedule(pcOfNextStatement(pc), stack) - case Throw(_, exception: IdBasedVar) => - stack.pop(exception) - // No scheduling since there is no next statement - case PutStatic(pc, _, _, _, value: IdBasedVar) => - stack.pop(value) - - schedule(pcOfNextStatement(pc), stack) - case PutField(pc, _, _, _, objRef: IdBasedVar, value: IdBasedVar) => - stack.pop(value) - stack.pop(objRef) - - schedule(pcOfNextStatement(pc), stack) - case NonVirtualMethodCall(pc, _, _, _, _, receiver: IdBasedVar, params: Seq[_]) => - params.reverse.foreach(p => stack.pop(p.asVar)) - stack.pop(receiver) - - schedule(pcOfNextStatement(pc), stack) - case VirtualMethodCall(pc, _, _, _, _, receiver: IdBasedVar, params: Seq[_]) => - params.reverse.foreach(p => stack.pop(p.asVar)) - stack.pop(receiver) - - schedule(pcOfNextStatement(pc), stack) - case StaticMethodCall(pc, _, _, _, _, params: Seq[_]) => - params.reverse.foreach(p => stack.pop(p.asVar)) - - schedule(pcOfNextStatement(pc), stack) - case InvokedynamicMethodCall(pc, _, _, _, params: Seq[_]) => - params.reverse.foreach(p => stack.pop(p.asVar)) - - schedule(pcOfNextStatement(pc), stack) - case ExprStmt(pc, expr) => - processExpr(expr) - - schedule(pcOfNextStatement(pc), stack) - case CaughtException(pc, _, _) => - // Only used in TACAI, so no stack manipulation is required - schedule(pcOfNextStatement(pc), stack) - case Checkcast(pc, value, _) => - // TODO Push new stack value - schedule(pcOfNextStatement(pc), stack) - case _ => throw new RuntimeException("Unknown statement: " + stmt) } - } - - def processExpr(expr: Expr[IdBasedVar]): List[IdBasedVar] = { - expr match { - case v: IdBasedVar => if (v.id >= 0) List(v) else List() - case InstanceOf(_, value: IdBasedVar, _) => List(value) - case Compare(_, left: IdBasedVar, _, right: IdBasedVar) => List(right, left) - case Param(_, _) => List() - case MethodTypeConst(_, _) => List() - case MethodHandleConst(_, _) => List() - case IntConst(_, _) => List() - case LongConst(_, _) => List() - case FloatConst(_, _) => List() - case DoubleConst(_, _) => List() - case StringConst(_, _) => List() - case ClassConst(_, _) => List() - case DynamicConst(_, _, _, _) => List() - case NullExpr(_) => List() - case BinaryExpr(_, _, _, left, right) => processExpr(right) ++ processExpr(left) - case PrefixExpr(_, _, _, operand: IdBasedVar) => List(operand) - case PrimitiveTypecastExpr(_, _, operand: IdBasedVar) => List(operand) - case New(_, _) => List() - case NewArray(_, counts: Seq[_], _) => counts.map(c => c.asVar).toList - case ArrayLoad(_, index: IdBasedVar, arrayRef: IdBasedVar) => List(index, arrayRef) - case ArrayLength(_, arrayRef: IdBasedVar) => List(arrayRef) - case GetField(_, _, _, _, objRef: IdBasedVar) => List(objRef) - case GetStatic(_, _, _, _) => List() - case InvokedynamicFunctionCall(_, _, _, _, params: Seq[_]) => params.map(p => p.asVar).toList.reverse - case NonVirtualFunctionCall(_, _, _, _, _, receiver: IdBasedVar, params: Seq[_]) => params.map(p => p.asVar).toList.reverse :+ receiver - case VirtualFunctionCall(_, _, _, _, _, receiver: IdBasedVar, params: Seq[_]) => params.map(p => p.asVar).toList.reverse :+ receiver - case StaticFunctionCall(_, _, _, _, _, params: Seq[_]) => params.map(p => p.asVar).toList.reverse - case _ => throw new RuntimeException("Unknown expression: " + expr) - } - } - + stackHandler } - stackHandler - } } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackHandler.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackHandler.scala index c08d0fcdc..13d057214 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackHandler.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackHandler.scala @@ -1,79 +1,100 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ package boomerang.scope.opal.transformation.stack import org.opalj.br.PC - import scala.collection.mutable class OperandStackHandler { - private val pcToStack = mutable.Map.empty[PC, OperandStack] - private val defSites = mutable.Map.empty[PC, Operand] - private var localCounter = -1 + private val pcToStack = mutable.Map.empty[PC, OperandStack] + private val defSites = mutable.Map.empty[PC, Operand] + private var localCounter = -1 - def getOrCreate(pc: PC): OperandStack = { - if (pcToStack.contains(pc)) { - pcToStack(pc).copy - } else { - val stack = OperandStack(this) - pcToStack.put(pc, stack) + def getOrCreate(pc: PC): OperandStack = { + if (pcToStack.contains(pc)) { + pcToStack(pc).copy + } else { + val stack = OperandStack(this) + pcToStack.put(pc, stack) - stack.copy + stack.copy + } } - } - - def addDefSite(pc: PC, operand: Operand): Unit = { - defSites.put(pc, operand) - } - - def mergeStack(nextPc: PC, incomingStack: OperandStack): Boolean = { - val existingStack = pcToStack.getOrElse(nextPc, null) - - if (existingStack == null) { - pcToStack.put(nextPc, incomingStack) - - true - } else { - var modified = false - existingStack.stackEntries.foreach(existingOp => { - incomingStack.stackEntries.foreach(incomingOp => { - if (existingOp.id == incomingOp.id) { - // Update the counter of the incoming operand s.t. both operands describe - // the same local and mark both operands as branched - existingOp.updateCounter(existingOp.localId) - incomingOp.updateCounter(existingOp.localId) - - // TODO Merge types - - modified = true - } - }) - }) - modified + + def addDefSite(pc: PC, operand: Operand): Unit = { + defSites.put(pc, operand) } - } - def nextLocalCounter: Int = { - localCounter += 1 + def mergeStack(nextPc: PC, incomingStack: OperandStack): Boolean = { + val existingStack = pcToStack.getOrElse(nextPc, null) + + if (existingStack == null) { + pcToStack.put(nextPc, incomingStack) + + true + } else { + var modified = false + existingStack.stackEntries.foreach(existingOp => { + incomingStack.stackEntries.foreach(incomingOp => { + if (existingOp.id == incomingOp.id) { + // Update the counter of the incoming operand s.t. both operands describe + // the same local and mark both operands as branched + existingOp.updateCounter(existingOp.localId) + incomingOp.updateCounter(existingOp.localId) + + // TODO Merge types + + modified = true + } + }) + }) + modified + } + } - localCounter - } + def nextLocalCounter: Int = { + localCounter += 1 - def defSiteAtPc(pc: PC): Int = defSites.getOrElse(pc, throw new RuntimeException(s"No operand definition at PC $pc")).localId + localCounter + } - def counterForOperand(pc: PC, id: Int, isReturn: Boolean = false): Int = { - val stack = pcToStack.getOrElse(pc, throw new RuntimeException(s"Stack for PC $pc not available")) - stack.stackEntries.foreach(op => if (op.id == id) return op.localId) + def defSiteAtPc(pc: PC): Int = defSites + .getOrElse( + pc, + throw new RuntimeException(s"No operand definition at PC $pc") + ) + .localId - // TODO Bug in Opal: Return always has id 0, even if it may have another id - if (isReturn) return stack.stackEntries.head.localId + def counterForOperand(pc: PC, id: Int, isReturn: Boolean = false): Int = { + val stack = pcToStack.getOrElse( + pc, + throw new RuntimeException(s"Stack for PC $pc not available") + ) + stack.stackEntries.foreach(op => if (op.id == id) return op.localId) - throw new RuntimeException(s"Could not find operand with id $id on stack") - } + // TODO Bug in Opal: Return always has id 0, even if it may have another id + if (isReturn) return stack.stackEntries.head.localId - def isBranchedOperand(pc: PC, id: Int): Boolean = { - val defSite = defSites.getOrElse(pc, throw new RuntimeException(s"No def site found at pc $pc")) + throw new RuntimeException(s"Could not find operand with id $id on stack") + } + + def isBranchedOperand(pc: PC, id: Int): Boolean = { + val defSite = defSites.getOrElse( + pc, + throw new RuntimeException(s"No def site found at pc $pc") + ) - defSite.isBranchedOperand - } + defSite.isBranchedOperand + } } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/InlineLocalTransformer.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/InlineLocalTransformer.scala index 4843ee5c7..554285e65 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/InlineLocalTransformer.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/InlineLocalTransformer.scala @@ -1,119 +1,160 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ package boomerang.scope.opal.transformation.transformer +import boomerang.scope.opal.transformation.RegisterLocal +import boomerang.scope.opal.transformation.StackLocal +import boomerang.scope.opal.transformation.TacLocal import boomerang.scope.opal.transformation.stack.OperandStackHandler -import boomerang.scope.opal.transformation.{RegisterLocal, StackLocal, TacLocal} import org.opalj.tac._ - import scala.collection.mutable object InlineLocalTransformer { - def apply(code: Array[Stmt[TacLocal]], stackHandler: OperandStackHandler): Array[Stmt[TacLocal]] = { - val statements = code.map(identity) - - val localCache = mutable.Map.empty[TacLocal, Expr[TacLocal]] - val localDefSites = mutable.Map.empty[TacLocal, (Int, Int)] - - val max = code.length - 1 - Range(0, max).foreach(i => { - statements(i) match { - // Collect all expressions that may replace stack to register assignments - case Assignment(pc, targetVar: StackLocal, c @ (_: SimpleValueConst)) => - if (!stackHandler.isBranchedOperand(pc, targetVar.id)) { - if (localCache.contains(targetVar)) { - throw new RuntimeException("Did not discover branched operand") - } - - localCache.put(targetVar, c) - localDefSites.put(targetVar, (i, pc)) - } - // Replace stack to register expressions if possible: - // r = $s becomes r = from previous assignment $s = - case Assignment(pc, targetVar: RegisterLocal, rightVar: StackLocal) => - /*if (localCache.contains(rightVar)) { + def apply( + code: Array[Stmt[TacLocal]], + stackHandler: OperandStackHandler + ): Array[Stmt[TacLocal]] = { + val statements = code.map(identity) + + val localCache = mutable.Map.empty[TacLocal, Expr[TacLocal]] + val localDefSites = mutable.Map.empty[TacLocal, (Int, Int)] + + val max = code.length - 1 + Range(0, max).foreach(i => { + statements(i) match { + // Collect all expressions that may replace stack to register assignments + case Assignment(pc, targetVar: StackLocal, c @ (_: SimpleValueConst)) => + if (!stackHandler.isBranchedOperand(pc, targetVar.id)) { + if (localCache.contains(targetVar)) { + throw new RuntimeException("Did not discover branched operand") + } + + localCache.put(targetVar, c) + localDefSites.put(targetVar, (i, pc)) + } + // Replace stack to register expressions if possible: + // r = $s becomes r = from previous assignment $s = + case Assignment(pc, targetVar: RegisterLocal, rightVar: StackLocal) => + /*if (localCache.contains(rightVar)) { val localExpr = localCache(rightVar) statements(i) = Assignment(pc, targetVar, localExpr) val localDefSite = localDefSites.getOrElse(rightVar, throw new RuntimeException("Def sites not consistent")) statements(localDefSite._1) = Nop(localDefSite._2) }*/ - // Array related assignments - case Assignment(pc, targetVar: StackLocal, expr) => - expr match { - // Replace the counts in new array creation with concrete integers if available - case NewArray(arrPc, counts, arrayType) => - var countDefSites = List.empty[(Int, Int)] - - val newCounts = counts.map(c => { - if (c.isVar && localCache.contains(c.asVar)) { - val localExpr = localCache(c.asVar) - - if (localExpr.isIntConst) { - val countDefSite = localDefSites.getOrElse(c.asVar, throw new RuntimeException("Def sites not consistent")) - countDefSites = countDefSites :+ countDefSite - - localExpr - } else { - c + // Array related assignments + case Assignment(pc, targetVar: StackLocal, expr) => + expr match { + // Replace the counts in new array creation with concrete integers if available + case NewArray(arrPc, counts, arrayType) => + var countDefSites = List.empty[(Int, Int)] + + val newCounts = counts.map(c => { + if (c.isVar && localCache.contains(c.asVar)) { + val localExpr = localCache(c.asVar) + + if (localExpr.isIntConst) { + val countDefSite = localDefSites.getOrElse( + c.asVar, + throw new RuntimeException("Def sites not consistent") + ) + countDefSites = countDefSites :+ countDefSite + + localExpr + } else { + c + } + } else { + c + } + }) + + statements(i) = + Assignment(pc, targetVar, NewArray(arrPc, newCounts, arrayType)) + countDefSites.foreach(defSite => + statements(defSite._1) = Nop(defSite._2) + ) + // Replace the index expression with the concrete integer value if available + case ArrayLoad(arrPc, arrayIndex: StackLocal, arrayRef) => + if (localCache.contains(arrayIndex)) { + val localExpr = localCache(arrayIndex) + + if (localExpr.isIntConst) { + statements(i) = Assignment( + pc, + targetVar, + ArrayLoad(arrPc, localExpr, arrayRef) + ) + + val localDefSite = localDefSites.getOrElse( + arrayIndex, + throw new RuntimeException("Def sites not consistent") + ) + statements(localDefSite._1) = Nop(localDefSite._2) + } + } + case _ => } - } else { - c - } - }) - - statements(i) = Assignment(pc, targetVar, NewArray(arrPc, newCounts, arrayType)) - countDefSites.foreach(defSite => statements(defSite._1) = Nop(defSite._2)) - // Replace the index expression with the concrete integer value if available - case ArrayLoad(arrPc, arrayIndex: StackLocal, arrayRef) => - if (localCache.contains(arrayIndex)) { - val localExpr = localCache(arrayIndex) - - if (localExpr.isIntConst) { - statements(i) = Assignment(pc, targetVar, ArrayLoad(arrPc, localExpr, arrayRef)) - - val localDefSite = localDefSites.getOrElse(arrayIndex, throw new RuntimeException("Def sites not consistent")) - statements(localDefSite._1) = Nop(localDefSite._2) - } - } - case _ => + case ArrayStore(pc, arrayRef, arrayIndex: StackLocal, value) => + if (localCache.contains(arrayIndex)) { + val localExpr = localCache(arrayIndex) + + if (localExpr.isIntConst) { + // TODO Also inline value if it is a simple constant + statements(i) = ArrayStore(pc, arrayRef, localExpr, value) + + val localDefSite = localDefSites.getOrElse( + arrayIndex, + throw new RuntimeException("Def sites not consistent") + ) + statements(localDefSite._1) = Nop(localDefSite._2) + } + } + case _ => } - case ArrayStore(pc, arrayRef, arrayIndex: StackLocal, value) => - if (localCache.contains(arrayIndex)) { - val localExpr = localCache(arrayIndex) - - if (localExpr.isIntConst) { - // TODO Also inline value if it is a simple constant - statements(i) = ArrayStore(pc, arrayRef, localExpr, value) - - val localDefSite = localDefSites.getOrElse(arrayIndex, throw new RuntimeException("Def sites not consistent")) - statements(localDefSite._1) = Nop(localDefSite._2) - } + }) + + Range(0, max).foreach(i => { + statements(i) match { + + /* Inline simple stack to register definitions: + * $s = + * r = $s + * + * becomes + * r = + */ + case Assignment( + pc, + targetVar: StackLocal, + c @ (_: SimpleValueConst | _: FunctionCall[TacLocal] | + _: NewArray[TacLocal] | _: ArrayLoad[TacLocal] | _: GetField[TacLocal] | + _: GetStatic) + ) => + statements(i + 1) match { + case Assignment( + nextPc, + nextTargetVar: RegisterLocal, + `targetVar` + ) => + statements(i) = Nop(pc) + statements(i + 1) = Assignment(nextPc, nextTargetVar, c) + case _ => + } + case _ => } - case _ => - } - }) - - Range(0, max).foreach(i => { - statements(i) match { - - /* Inline simple stack to register definitions: - * $s = - * r = $s - * - * becomes - * r = - */ - case Assignment(pc, targetVar: StackLocal, c @ (_: SimpleValueConst | _: FunctionCall[TacLocal] | _: NewArray[TacLocal] | _: ArrayLoad[TacLocal] | _: GetField[TacLocal] | _: GetStatic)) => - statements(i + 1) match { - case Assignment(nextPc, nextTargetVar: RegisterLocal, `targetVar`) => - statements(i) = Nop(pc) - statements(i + 1) = Assignment(nextPc, nextTargetVar, c) - case _ => - } - case _ => - } - }) - - statements - } + }) + + statements + } } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/LocalPropagationTransformer.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/LocalPropagationTransformer.scala index 4efb5a8cd..1ddbf4024 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/LocalPropagationTransformer.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/LocalPropagationTransformer.scala @@ -1,226 +1,521 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ package boomerang.scope.opal.transformation.transformer -import boomerang.scope.opal.transformation.{RegisterLocal, StackLocal, TacLocal} +import boomerang.scope.opal.transformation.RegisterLocal +import boomerang.scope.opal.transformation.StackLocal +import boomerang.scope.opal.transformation.TacLocal import boomerang.scope.opal.transformation.stack.OperandStackHandler import org.opalj.collection.immutable.IntIntPair -import org.opalj.tac.{ArrayLength, ArrayLoad, ArrayStore, Assignment, BinaryExpr, Checkcast, Compare, Expr, ExprStmt, GetField, If, InstanceOf, InvokedynamicFunctionCall, InvokedynamicMethodCall, MonitorEnter, MonitorExit, NewArray, NonVirtualFunctionCall, NonVirtualMethodCall, Nop, PrefixExpr, PrimitiveTypecastExpr, PutField, PutStatic, ReturnValue, StaticFunctionCall, StaticMethodCall, Stmt, Switch, Throw, VirtualFunctionCall, VirtualMethodCall} +import org.opalj.tac.ArrayLength +import org.opalj.tac.ArrayLoad +import org.opalj.tac.ArrayStore +import org.opalj.tac.Assignment +import org.opalj.tac.BinaryExpr +import org.opalj.tac.Checkcast +import org.opalj.tac.Compare +import org.opalj.tac.Expr +import org.opalj.tac.ExprStmt +import org.opalj.tac.GetField +import org.opalj.tac.If +import org.opalj.tac.InstanceOf +import org.opalj.tac.InvokedynamicFunctionCall +import org.opalj.tac.InvokedynamicMethodCall +import org.opalj.tac.MonitorEnter +import org.opalj.tac.MonitorExit +import org.opalj.tac.NewArray +import org.opalj.tac.NonVirtualFunctionCall +import org.opalj.tac.NonVirtualMethodCall +import org.opalj.tac.Nop +import org.opalj.tac.PrefixExpr +import org.opalj.tac.PrimitiveTypecastExpr +import org.opalj.tac.PutField +import org.opalj.tac.PutStatic +import org.opalj.tac.ReturnValue +import org.opalj.tac.StaticFunctionCall +import org.opalj.tac.StaticMethodCall +import org.opalj.tac.Stmt +import org.opalj.tac.Switch +import org.opalj.tac.Throw +import org.opalj.tac.VirtualFunctionCall +import org.opalj.tac.VirtualMethodCall object LocalPropagationTransformer { - def apply(code: Array[Stmt[TacLocal]], stackHandler: OperandStackHandler): Array[Stmt[TacLocal]] = { - val statements = code.map(identity) - - val max = code.length - 1 - Range(0, max).foreach(i => { - statements(i) match { - // If we have an assignment $s = r, we replace $s with r in all following statements - case Assignment(pc, stackLocal: StackLocal, registerLocal: RegisterLocal) => - if (!stackHandler.isBranchedOperand(pc, stackLocal.id)) { - Range.inclusive(i + 1, max).foreach(j => { - val currStmt = statements(j) - statements(j) = updateStatementWithLocal(currStmt, stackLocal, registerLocal) - }) - - statements(i) = Nop(pc) - } - case _ => - } - }) - - def updateStatementWithLocal(stmt: Stmt[TacLocal], stackLocal: StackLocal, registerLocal: RegisterLocal): Stmt[TacLocal] = { - stmt.astID match { - case If.ASTID => - val ifStmt = stmt.asIf - - val left = updateExpressionWithLocal(ifStmt.left, stackLocal, registerLocal) - val right = updateExpressionWithLocal(ifStmt.left, stackLocal, registerLocal) - - return If(ifStmt.pc, left, ifStmt.condition, right, ifStmt.targetStmt) - case Switch.ASTID => - val switchStmt = stmt.asSwitch - val index = updateExpressionWithLocal(switchStmt.index, stackLocal, registerLocal) - - return Switch(switchStmt.pc, switchStmt.defaultStmt, index, switchStmt.caseStmts.map(p => IntIntPair(-1, p))) - case Assignment.ASTID => - val assignStmt = stmt.asAssignment - val targetVar = updateExpressionWithLocal(assignStmt.targetVar, stackLocal, registerLocal) - val expr = updateExpressionWithLocal(assignStmt.expr, stackLocal, registerLocal) - - return Assignment(assignStmt.pc, targetVar.asVar, expr) - case ReturnValue.ASTID => - val expr = updateExpressionWithLocal(stmt.asReturnValue.expr, stackLocal, registerLocal) - - return ReturnValue(stmt.pc, expr) - case MonitorEnter.ASTID => - val objRef = updateExpressionWithLocal(stmt.asMonitorEnter.objRef, stackLocal, registerLocal) - - return MonitorEnter(stmt.pc, objRef) - case MonitorExit.ASTID => - val objRef = updateExpressionWithLocal(stmt.asMonitorExit.objRef, stackLocal, registerLocal) - - return MonitorExit(stmt.pc, objRef) - case ArrayStore.ASTID => - val arrayStore = stmt.asArrayStore - - val arrayRef = updateExpressionWithLocal(arrayStore.arrayRef, stackLocal, registerLocal) - val index = updateExpressionWithLocal(arrayStore.index, stackLocal, registerLocal) - val value = updateExpressionWithLocal(arrayStore.value, stackLocal, registerLocal) - - return ArrayStore(arrayStore.pc, arrayRef, index, value) - case Throw.ASTID => - val throwStmt = stmt.asThrow - val exception = updateExpressionWithLocal(throwStmt.exception, stackLocal, registerLocal) - - return Throw(throwStmt.pc, exception) - case PutStatic.ASTID => - - val putStatic = stmt.asPutStatic - val value = updateExpressionWithLocal(putStatic.value, stackLocal, registerLocal) - - return PutStatic(putStatic.pc, putStatic.declaringClass, putStatic.name, putStatic.declaredFieldType, value) - case PutField.ASTID => - - val putField = stmt.asPutField - - val objRef = updateExpressionWithLocal(putField.objRef, stackLocal, registerLocal) - val value = updateExpressionWithLocal(putField.value, stackLocal, registerLocal) - - return PutField(putField.pc, putField.declaringClass, putField.name, putField.declaredFieldType, objRef, value) - case NonVirtualMethodCall.ASTID => - val methodCall = stmt.asNonVirtualMethodCall - - val baseLocal = updateExpressionWithLocal(methodCall.receiver, stackLocal, registerLocal) - val paramLocals = methodCall.params.map(p => updateExpressionWithLocal(p, stackLocal, registerLocal)) - - return NonVirtualMethodCall(methodCall.pc, methodCall.declaringClass, methodCall.isInterface, methodCall.name, methodCall.descriptor, baseLocal, paramLocals) - case VirtualMethodCall.ASTID => - val methodCall = stmt.asVirtualMethodCall - - val baseLocal = updateExpressionWithLocal(methodCall.receiver, stackLocal, registerLocal) - val paramLocals = methodCall.params.map(p => updateExpressionWithLocal(p, stackLocal, registerLocal)) - - return VirtualMethodCall(methodCall.pc, methodCall.declaringClass, methodCall.isInterface, methodCall.name, methodCall.descriptor, baseLocal, paramLocals) - case StaticMethodCall.ASTID => - val methodCall = stmt.asStaticMethodCall - val params = methodCall.params.map(p => updateExpressionWithLocal(p, stackLocal, registerLocal)) - - return StaticMethodCall(methodCall.pc, methodCall.declaringClass, methodCall.isInterface, methodCall.name, methodCall.descriptor, params) - case InvokedynamicMethodCall.ASTID => - val methodCall = stmt.asInvokedynamicMethodCall - val params = methodCall.params.map(p => updateExpressionWithLocal(p, stackLocal, registerLocal)) - - return InvokedynamicMethodCall(methodCall.pc, methodCall.bootstrapMethod, methodCall.name, methodCall.descriptor, params) - case ExprStmt.ASTID => - val expr = updateExpressionWithLocal(stmt.asExprStmt.expr, stackLocal, registerLocal) - - return ExprStmt(stmt.pc, expr) - case Checkcast.ASTID => - val castExpr = stmt.asCheckcast - val value = updateExpressionWithLocal(castExpr.value, stackLocal, registerLocal) - - return Checkcast(castExpr.pc, value, castExpr.cmpTpe) - case _ => return stmt - } - - throw new RuntimeException("Could not update statement: " + stmt) - } - - def updateExpressionWithLocal(expr: Expr[TacLocal], stackLocal: StackLocal, registerLocal: RegisterLocal): Expr[TacLocal] = { - if (expr.isVar) { - if (expr.asVar.isRegisterLocal) return expr - - // Replace stack local with register local - if (expr.asVar.isStackLocal && expr.asVar == stackLocal) { - return registerLocal - } else { - return expr + def apply( + code: Array[Stmt[TacLocal]], + stackHandler: OperandStackHandler + ): Array[Stmt[TacLocal]] = { + val statements = code.map(identity) + + val max = code.length - 1 + Range(0, max).foreach(i => { + statements(i) match { + // If we have an assignment $s = r, we replace $s with r in all following statements + case Assignment( + pc, + stackLocal: StackLocal, + registerLocal: RegisterLocal + ) => + if (!stackHandler.isBranchedOperand(pc, stackLocal.id)) { + Range + .inclusive(i + 1, max) + .foreach(j => { + val currStmt = statements(j) + statements(j) = + updateStatementWithLocal(currStmt, stackLocal, registerLocal) + }) + + statements(i) = Nop(pc) + } + case _ => + } + }) + + def updateStatementWithLocal( + stmt: Stmt[TacLocal], + stackLocal: StackLocal, + registerLocal: RegisterLocal + ): Stmt[TacLocal] = { + stmt.astID match { + case If.ASTID => + val ifStmt = stmt.asIf + + val left = + updateExpressionWithLocal(ifStmt.left, stackLocal, registerLocal) + val right = + updateExpressionWithLocal(ifStmt.left, stackLocal, registerLocal) + + return If(ifStmt.pc, left, ifStmt.condition, right, ifStmt.targetStmt) + case Switch.ASTID => + val switchStmt = stmt.asSwitch + val index = updateExpressionWithLocal( + switchStmt.index, + stackLocal, + registerLocal + ) + + return Switch( + switchStmt.pc, + switchStmt.defaultStmt, + index, + switchStmt.caseStmts.map(p => IntIntPair(-1, p)) + ) + case Assignment.ASTID => + val assignStmt = stmt.asAssignment + val targetVar = updateExpressionWithLocal( + assignStmt.targetVar, + stackLocal, + registerLocal + ) + val expr = updateExpressionWithLocal( + assignStmt.expr, + stackLocal, + registerLocal + ) + + return Assignment(assignStmt.pc, targetVar.asVar, expr) + case ReturnValue.ASTID => + val expr = updateExpressionWithLocal( + stmt.asReturnValue.expr, + stackLocal, + registerLocal + ) + + return ReturnValue(stmt.pc, expr) + case MonitorEnter.ASTID => + val objRef = updateExpressionWithLocal( + stmt.asMonitorEnter.objRef, + stackLocal, + registerLocal + ) + + return MonitorEnter(stmt.pc, objRef) + case MonitorExit.ASTID => + val objRef = updateExpressionWithLocal( + stmt.asMonitorExit.objRef, + stackLocal, + registerLocal + ) + + return MonitorExit(stmt.pc, objRef) + case ArrayStore.ASTID => + val arrayStore = stmt.asArrayStore + + val arrayRef = updateExpressionWithLocal( + arrayStore.arrayRef, + stackLocal, + registerLocal + ) + val index = updateExpressionWithLocal( + arrayStore.index, + stackLocal, + registerLocal + ) + val value = updateExpressionWithLocal( + arrayStore.value, + stackLocal, + registerLocal + ) + + return ArrayStore(arrayStore.pc, arrayRef, index, value) + case Throw.ASTID => + val throwStmt = stmt.asThrow + val exception = updateExpressionWithLocal( + throwStmt.exception, + stackLocal, + registerLocal + ) + + return Throw(throwStmt.pc, exception) + case PutStatic.ASTID => + val putStatic = stmt.asPutStatic + val value = updateExpressionWithLocal( + putStatic.value, + stackLocal, + registerLocal + ) + + return PutStatic( + putStatic.pc, + putStatic.declaringClass, + putStatic.name, + putStatic.declaredFieldType, + value + ) + case PutField.ASTID => + val putField = stmt.asPutField + + val objRef = updateExpressionWithLocal( + putField.objRef, + stackLocal, + registerLocal + ) + val value = + updateExpressionWithLocal(putField.value, stackLocal, registerLocal) + + return PutField( + putField.pc, + putField.declaringClass, + putField.name, + putField.declaredFieldType, + objRef, + value + ) + case NonVirtualMethodCall.ASTID => + val methodCall = stmt.asNonVirtualMethodCall + + val baseLocal = updateExpressionWithLocal( + methodCall.receiver, + stackLocal, + registerLocal + ) + val paramLocals = methodCall.params.map(p => + updateExpressionWithLocal(p, stackLocal, registerLocal) + ) + + return NonVirtualMethodCall( + methodCall.pc, + methodCall.declaringClass, + methodCall.isInterface, + methodCall.name, + methodCall.descriptor, + baseLocal, + paramLocals + ) + case VirtualMethodCall.ASTID => + val methodCall = stmt.asVirtualMethodCall + + val baseLocal = updateExpressionWithLocal( + methodCall.receiver, + stackLocal, + registerLocal + ) + val paramLocals = methodCall.params.map(p => + updateExpressionWithLocal(p, stackLocal, registerLocal) + ) + + return VirtualMethodCall( + methodCall.pc, + methodCall.declaringClass, + methodCall.isInterface, + methodCall.name, + methodCall.descriptor, + baseLocal, + paramLocals + ) + case StaticMethodCall.ASTID => + val methodCall = stmt.asStaticMethodCall + val params = methodCall.params.map(p => + updateExpressionWithLocal(p, stackLocal, registerLocal) + ) + + return StaticMethodCall( + methodCall.pc, + methodCall.declaringClass, + methodCall.isInterface, + methodCall.name, + methodCall.descriptor, + params + ) + case InvokedynamicMethodCall.ASTID => + val methodCall = stmt.asInvokedynamicMethodCall + val params = methodCall.params.map(p => + updateExpressionWithLocal(p, stackLocal, registerLocal) + ) + + return InvokedynamicMethodCall( + methodCall.pc, + methodCall.bootstrapMethod, + methodCall.name, + methodCall.descriptor, + params + ) + case ExprStmt.ASTID => + val expr = updateExpressionWithLocal( + stmt.asExprStmt.expr, + stackLocal, + registerLocal + ) + + return ExprStmt(stmt.pc, expr) + case Checkcast.ASTID => + val castExpr = stmt.asCheckcast + val value = + updateExpressionWithLocal(castExpr.value, stackLocal, registerLocal) + + return Checkcast(castExpr.pc, value, castExpr.cmpTpe) + case _ => return stmt + } + + throw new RuntimeException("Could not update statement: " + stmt) } - } - - expr.astID match { - case InstanceOf.ASTID => - val instanceOf = expr.asInstanceOf - val value = updateExpressionWithLocal(instanceOf.value, stackLocal, registerLocal) - - return InstanceOf(instanceOf.pc, value, instanceOf.cmpTpe) - case Compare.ASTID => - val compareExpr = expr.asCompare - - val leftLocal = updateExpressionWithLocal(compareExpr.left, stackLocal, registerLocal) - val rightLocal = updateExpressionWithLocal(compareExpr.right, stackLocal, registerLocal) - - return Compare(compareExpr.pc, leftLocal, compareExpr.condition, rightLocal) - case BinaryExpr.ASTID => - val binaryExpr = expr.asBinaryExpr - - val left = updateExpressionWithLocal(binaryExpr.left, stackLocal, registerLocal) - val right = updateExpressionWithLocal(binaryExpr.right, stackLocal, registerLocal) - - return BinaryExpr(binaryExpr.pc, binaryExpr.cTpe, binaryExpr.op, left, right) - case PrefixExpr.ASTID => - val prefixExpr = expr.asPrefixExpr - val operand = updateExpressionWithLocal(prefixExpr.operand, stackLocal, registerLocal) - - return PrefixExpr(prefixExpr.pc, prefixExpr.cTpe, prefixExpr.op, operand) - case PrimitiveTypecastExpr.ASTID => - val primitiveTypecastExpr = expr.asPrimitiveTypeCastExpr - val operand = updateExpressionWithLocal(primitiveTypecastExpr.operand, stackLocal, registerLocal) - - return PrimitiveTypecastExpr(primitiveTypecastExpr.pc, primitiveTypecastExpr.targetTpe, operand) - case NewArray.ASTID => - val newArray = expr.asNewArray - val counts = newArray.counts.map(c => updateExpressionWithLocal(c, stackLocal, registerLocal)) - return NewArray(newArray.pc, counts, newArray.tpe) - case ArrayLoad.ASTID => - val arrayLoad = expr.asArrayLoad - - val index = updateExpressionWithLocal(arrayLoad.index, stackLocal, registerLocal) - val arrayRef = updateExpressionWithLocal(arrayLoad.arrayRef, stackLocal, registerLocal) - - return ArrayLoad(arrayLoad.pc, index, arrayRef) - case ArrayLength.ASTID => - val arrayLength = expr.asArrayLength - val arrayRef = updateExpressionWithLocal(arrayLength.arrayRef, stackLocal, registerLocal) - - return ArrayLength(arrayLength.pc, arrayRef) - case GetField.ASTID => - val getField = expr.asGetField - val objRef = updateExpressionWithLocal(getField.objRef, stackLocal, registerLocal) - - return GetField(getField.pc, getField.declaringClass, getField.name, getField.declaredFieldType, objRef) - case InvokedynamicFunctionCall.ASTID => - val functionCall = expr.asInvokedynamicFunctionCall - val params = functionCall.params.map(p => updateExpressionWithLocal(p, stackLocal, registerLocal)) - - return InvokedynamicFunctionCall(functionCall.pc, functionCall.bootstrapMethod, functionCall.name, functionCall.descriptor, params) - case NonVirtualFunctionCall.ASTID => - val functionCall = expr.asNonVirtualFunctionCall - - val base = updateExpressionWithLocal(functionCall.receiver, stackLocal, registerLocal) - val params = functionCall.params.map(p => updateExpressionWithLocal(p, stackLocal, registerLocal)) - - return NonVirtualFunctionCall(functionCall.pc, functionCall.declaringClass, functionCall.isInterface, functionCall.name, functionCall.descriptor, base, params) - case VirtualFunctionCall.ASTID => - val functionCall = expr.asVirtualFunctionCall - - val base = updateExpressionWithLocal(functionCall.receiver, stackLocal, registerLocal) - val params = functionCall.params.map(p => updateExpressionWithLocal(p, stackLocal, registerLocal)) - - return VirtualFunctionCall(functionCall.pc, functionCall.declaringClass, functionCall.isInterface, functionCall.name, functionCall.descriptor, base, params) - case StaticFunctionCall.ASTID => - val functionCall = expr.asStaticFunctionCall - - val params = functionCall.params - val paramLocals = params.map(p => updateExpressionWithLocal(p, stackLocal, registerLocal)) - - return StaticFunctionCall(functionCall.pc, functionCall.declaringClass, functionCall.isInterface, functionCall.name, functionCall.descriptor, paramLocals) - case _ => return expr - } + def updateExpressionWithLocal( + expr: Expr[TacLocal], + stackLocal: StackLocal, + registerLocal: RegisterLocal + ): Expr[TacLocal] = { + if (expr.isVar) { + if (expr.asVar.isRegisterLocal) return expr + + // Replace stack local with register local + if (expr.asVar.isStackLocal && expr.asVar == stackLocal) { + return registerLocal + } else { + return expr + } + } + + expr.astID match { + case InstanceOf.ASTID => + val instanceOf = expr.asInstanceOf + val value = updateExpressionWithLocal( + instanceOf.value, + stackLocal, + registerLocal + ) + + return InstanceOf(instanceOf.pc, value, instanceOf.cmpTpe) + case Compare.ASTID => + val compareExpr = expr.asCompare + + val leftLocal = updateExpressionWithLocal( + compareExpr.left, + stackLocal, + registerLocal + ) + val rightLocal = updateExpressionWithLocal( + compareExpr.right, + stackLocal, + registerLocal + ) + + return Compare( + compareExpr.pc, + leftLocal, + compareExpr.condition, + rightLocal + ) + case BinaryExpr.ASTID => + val binaryExpr = expr.asBinaryExpr + + val left = updateExpressionWithLocal( + binaryExpr.left, + stackLocal, + registerLocal + ) + val right = updateExpressionWithLocal( + binaryExpr.right, + stackLocal, + registerLocal + ) + + return BinaryExpr( + binaryExpr.pc, + binaryExpr.cTpe, + binaryExpr.op, + left, + right + ) + case PrefixExpr.ASTID => + val prefixExpr = expr.asPrefixExpr + val operand = updateExpressionWithLocal( + prefixExpr.operand, + stackLocal, + registerLocal + ) + + return PrefixExpr( + prefixExpr.pc, + prefixExpr.cTpe, + prefixExpr.op, + operand + ) + case PrimitiveTypecastExpr.ASTID => + val primitiveTypecastExpr = expr.asPrimitiveTypeCastExpr + val operand = updateExpressionWithLocal( + primitiveTypecastExpr.operand, + stackLocal, + registerLocal + ) + + return PrimitiveTypecastExpr( + primitiveTypecastExpr.pc, + primitiveTypecastExpr.targetTpe, + operand + ) + case NewArray.ASTID => + val newArray = expr.asNewArray + val counts = newArray.counts.map(c => + updateExpressionWithLocal(c, stackLocal, registerLocal) + ) + + return NewArray(newArray.pc, counts, newArray.tpe) + case ArrayLoad.ASTID => + val arrayLoad = expr.asArrayLoad + + val index = updateExpressionWithLocal( + arrayLoad.index, + stackLocal, + registerLocal + ) + val arrayRef = updateExpressionWithLocal( + arrayLoad.arrayRef, + stackLocal, + registerLocal + ) + + return ArrayLoad(arrayLoad.pc, index, arrayRef) + case ArrayLength.ASTID => + val arrayLength = expr.asArrayLength + val arrayRef = updateExpressionWithLocal( + arrayLength.arrayRef, + stackLocal, + registerLocal + ) + + return ArrayLength(arrayLength.pc, arrayRef) + case GetField.ASTID => + val getField = expr.asGetField + val objRef = updateExpressionWithLocal( + getField.objRef, + stackLocal, + registerLocal + ) + + return GetField( + getField.pc, + getField.declaringClass, + getField.name, + getField.declaredFieldType, + objRef + ) + case InvokedynamicFunctionCall.ASTID => + val functionCall = expr.asInvokedynamicFunctionCall + val params = functionCall.params.map(p => + updateExpressionWithLocal(p, stackLocal, registerLocal) + ) + + return InvokedynamicFunctionCall( + functionCall.pc, + functionCall.bootstrapMethod, + functionCall.name, + functionCall.descriptor, + params + ) + case NonVirtualFunctionCall.ASTID => + val functionCall = expr.asNonVirtualFunctionCall + + val base = updateExpressionWithLocal( + functionCall.receiver, + stackLocal, + registerLocal + ) + val params = functionCall.params.map(p => + updateExpressionWithLocal(p, stackLocal, registerLocal) + ) + + return NonVirtualFunctionCall( + functionCall.pc, + functionCall.declaringClass, + functionCall.isInterface, + functionCall.name, + functionCall.descriptor, + base, + params + ) + case VirtualFunctionCall.ASTID => + val functionCall = expr.asVirtualFunctionCall + + val base = updateExpressionWithLocal( + functionCall.receiver, + stackLocal, + registerLocal + ) + val params = functionCall.params.map(p => + updateExpressionWithLocal(p, stackLocal, registerLocal) + ) + + return VirtualFunctionCall( + functionCall.pc, + functionCall.declaringClass, + functionCall.isInterface, + functionCall.name, + functionCall.descriptor, + base, + params + ) + case StaticFunctionCall.ASTID => + val functionCall = expr.asStaticFunctionCall + + val params = functionCall.params + val paramLocals = + params.map(p => updateExpressionWithLocal(p, stackLocal, registerLocal)) + + return StaticFunctionCall( + functionCall.pc, + functionCall.declaringClass, + functionCall.isInterface, + functionCall.name, + functionCall.descriptor, + paramLocals + ) + case _ => return expr + } + + throw new RuntimeException("Could not update expression: " + expr) + } - throw new RuntimeException("Could not update expression: " + expr) + statements } - - statements - } } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/LocalTransformer.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/LocalTransformer.scala index 7fc5195a0..d38883c68 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/LocalTransformer.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/LocalTransformer.scala @@ -1,314 +1,599 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ package boomerang.scope.opal.transformation.transformer -import boomerang.scope.opal.transformation.{ExceptionLocal, ParameterLocal, RegisterLocal, StackLocal, TacLocal} +import boomerang.scope.opal.transformation.ExceptionLocal +import boomerang.scope.opal.transformation.ParameterLocal +import boomerang.scope.opal.transformation.RegisterLocal +import boomerang.scope.opal.transformation.StackLocal +import boomerang.scope.opal.transformation.TacLocal import boomerang.scope.opal.transformation.stack.OperandStackHandler -import org.opalj.ai.{AIResult, BaseAI, Domain} +import org.opalj.ai.AIResult +import org.opalj.ai.BaseAI +import org.opalj.ai.Domain +import org.opalj.br.ComputationalType +import org.opalj.br.ComputationalTypeDouble +import org.opalj.br.ComputationalTypeFloat +import org.opalj.br.ComputationalTypeInt +import org.opalj.br.ComputationalTypeLong +import org.opalj.br.ComputationalTypeReference +import org.opalj.br.ComputationalTypeReturnAddress +import org.opalj.br.DoubleType +import org.opalj.br.FieldType +import org.opalj.br.FloatType +import org.opalj.br.IntegerType +import org.opalj.br.LongType +import org.opalj.br.Method +import org.opalj.br.ObjectType +import org.opalj.br.PC import org.opalj.br.analyses.Project -import org.opalj.br.{ComputationalType, ComputationalTypeDouble, ComputationalTypeFloat, ComputationalTypeInt, ComputationalTypeLong, ComputationalTypeReference, ComputationalTypeReturnAddress, DoubleType, FieldType, FloatType, IntegerType, LongType, Method, ObjectType, PC} -import org.opalj.tac.{ArrayLength, ArrayLoad, ArrayStore, Assignment, BinaryExpr, CaughtException, Checkcast, ClassConst, Compare, DoubleConst, DynamicConst, Expr, ExprStmt, FloatConst, GetField, GetStatic, Goto, IdBasedVar, If, InstanceOf, IntConst, InvokedynamicFunctionCall, InvokedynamicMethodCall, JSR, LongConst, MethodHandleConst, MethodTypeConst, MonitorEnter, MonitorExit, NaiveTACode, New, NewArray, NonVirtualFunctionCall, NonVirtualMethodCall, Nop, NullExpr, Param, PrefixExpr, PrimitiveTypecastExpr, PutField, PutStatic, Ret, Return, ReturnValue, StaticFunctionCall, StaticMethodCall, Stmt, StringConst, Switch, Throw, VirtualFunctionCall, VirtualMethodCall} +import org.opalj.tac.ArrayLength +import org.opalj.tac.ArrayLoad +import org.opalj.tac.ArrayStore +import org.opalj.tac.Assignment +import org.opalj.tac.BinaryExpr +import org.opalj.tac.CaughtException +import org.opalj.tac.Checkcast +import org.opalj.tac.ClassConst +import org.opalj.tac.Compare +import org.opalj.tac.DoubleConst +import org.opalj.tac.DynamicConst +import org.opalj.tac.Expr +import org.opalj.tac.ExprStmt +import org.opalj.tac.FloatConst +import org.opalj.tac.GetField +import org.opalj.tac.GetStatic +import org.opalj.tac.Goto +import org.opalj.tac.IdBasedVar +import org.opalj.tac.If +import org.opalj.tac.InstanceOf +import org.opalj.tac.IntConst +import org.opalj.tac.InvokedynamicFunctionCall +import org.opalj.tac.InvokedynamicMethodCall +import org.opalj.tac.JSR +import org.opalj.tac.LongConst +import org.opalj.tac.MethodHandleConst +import org.opalj.tac.MethodTypeConst +import org.opalj.tac.MonitorEnter +import org.opalj.tac.MonitorExit +import org.opalj.tac.NaiveTACode +import org.opalj.tac.New +import org.opalj.tac.NewArray +import org.opalj.tac.NonVirtualFunctionCall +import org.opalj.tac.NonVirtualMethodCall +import org.opalj.tac.Nop +import org.opalj.tac.NullExpr +import org.opalj.tac.Param +import org.opalj.tac.PrefixExpr +import org.opalj.tac.PrimitiveTypecastExpr +import org.opalj.tac.PutField +import org.opalj.tac.PutStatic +import org.opalj.tac.Ret +import org.opalj.tac.Return +import org.opalj.tac.ReturnValue +import org.opalj.tac.StaticFunctionCall +import org.opalj.tac.StaticMethodCall +import org.opalj.tac.Stmt +import org.opalj.tac.StringConst +import org.opalj.tac.Switch +import org.opalj.tac.Throw +import org.opalj.tac.VirtualFunctionCall +import org.opalj.tac.VirtualMethodCall import org.opalj.value.ValueInformation - import scala.collection.mutable object LocalTransformer { - def apply(project: Project[_], method: Method, tac: NaiveTACode[_], stackHandler: OperandStackHandler, domain: Domain): Array[Stmt[TacLocal]] = { - var paramCount = -1 - var exceptionCount = -1 - val currentLocals = mutable.Map.empty[Int, TacLocal] - val exceptionHandlers = tac.exceptionHandlers.map(eh => eh.handlerPC) - - // Domain components - val aiResult: AIResult = BaseAI(method, domain) - val operandsArray: aiResult.domain.OperandsArray = aiResult.operandsArray - val localArray: aiResult.domain.LocalsArray = aiResult.localsArray - - def transformStmt(stmt: Stmt[IdBasedVar]): Stmt[TacLocal] = { - stmt match { - case If(pc, left, condition, right, target) => - val leftExpr = transformExpr(pc, left) - val rightExpr = transformExpr(pc, right) - - return If(pc, leftExpr, condition, rightExpr, target) - case Goto(pc, target) => return Goto(pc, target) - case Ret(pc, returnAddresses) => return Ret(pc, returnAddresses) - case JSR(pc, target) => return JSR(pc, target) - case Switch(pc, defaultTarget, index, nPairs) => - val indexExpr = transformExpr(pc, index) - - return Switch(pc, defaultTarget, indexExpr, nPairs) - case Assignment(pc, targetVar, expr) => - // Parameter definition statements - if (pc == -1) { - val transformedExpr = transformExpr(pc, expr) - - var paramName: Option[String] = None - if (transformedExpr.isVar && transformedExpr.asVar.isParameterLocal) { - paramName = Some(transformedExpr.asVar.name) + def apply( + project: Project[_], + method: Method, + tac: NaiveTACode[_], + stackHandler: OperandStackHandler, + domain: Domain + ): Array[Stmt[TacLocal]] = { + var paramCount = -1 + var exceptionCount = -1 + val currentLocals = mutable.Map.empty[Int, TacLocal] + val exceptionHandlers = tac.exceptionHandlers.map(eh => eh.handlerPC) + + // Domain components + val aiResult: AIResult = BaseAI(method, domain) + val operandsArray: aiResult.domain.OperandsArray = aiResult.operandsArray + val localArray: aiResult.domain.LocalsArray = aiResult.localsArray + + def transformStmt(stmt: Stmt[IdBasedVar]): Stmt[TacLocal] = { + stmt match { + case If(pc, left, condition, right, target) => + val leftExpr = transformExpr(pc, left) + val rightExpr = transformExpr(pc, right) + + return If(pc, leftExpr, condition, rightExpr, target) + case Goto(pc, target) => return Goto(pc, target) + case Ret(pc, returnAddresses) => return Ret(pc, returnAddresses) + case JSR(pc, target) => return JSR(pc, target) + case Switch(pc, defaultTarget, index, nPairs) => + val indexExpr = transformExpr(pc, index) + + return Switch(pc, defaultTarget, indexExpr, nPairs) + case Assignment(pc, targetVar, expr) => + // Parameter definition statements + if (pc == -1) { + val transformedExpr = transformExpr(pc, expr) + + var paramName: Option[String] = None + if (transformedExpr.isVar && transformedExpr.asVar.isParameterLocal) { + paramName = Some(transformedExpr.asVar.name) + } + + val paramLocal = createParameterLocal(targetVar, paramName) + + currentLocals(paramLocal.id) = paramLocal + return Assignment(pc, paramLocal, transformedExpr) + } + + if (targetVar.id >= 0) { + val transformedExpr = transformExpr(pc, expr) + + // Consider 'this' assignment from register to stack: s = this + val isThisAssignment = + transformedExpr.isVar && transformedExpr.asVar.isThisLocal + val targetLocal = createStackLocal(pc, targetVar, isThisAssignment) + + currentLocals(targetLocal.id) = targetLocal + return Assignment(pc, targetLocal, transformedExpr) + } + + if (targetVar.id < 0) { + val transformedExpr = transformExpr(pc, expr) + + // Consider 'this' assignment from stack to register: r0 = $this + val isThisAssignment = + transformedExpr.isVar && transformedExpr.asVar.isThisLocal + val targetLocal = + createRegisterLocal(pc, targetVar, isThisAssignment) + + currentLocals(targetLocal.id) = targetLocal + return Assignment(pc, targetLocal, transformedExpr) + } + + throw new RuntimeException("Should never be reached") + case ReturnValue(pc, expr) => + val returnExpr = transformExpr(pc, expr) + + return ReturnValue(pc, returnExpr) + case Return(pc) => return Return(pc) + case Nop(pc) => return Nop(pc) + case MonitorEnter(pc, objRef) => + val objRefExpr = transformExpr(pc, objRef) + + return MonitorEnter(pc, objRefExpr) + case MonitorExit(pc, objRef) => + val objRefExpr = transformExpr(pc, objRef) + + return MonitorExit(pc, objRefExpr) + case ArrayStore(pc, arrayRef, index, value) => + val arrayRefExpr = transformExpr(pc, arrayRef) + val indexExpr = transformExpr(pc, index) + val valueExpr = transformExpr(pc, value) + + return ArrayStore(pc, arrayRefExpr, indexExpr, valueExpr) + case Throw(pc, exception) => + val exceptionExpr = transformExpr(pc, exception) + + return Throw(pc, exceptionExpr) + case PutStatic(pc, declaringClass, name, declaredFieldType, value) => + val valueExpr = transformExpr(pc, value) + + return PutStatic( + pc, + declaringClass, + name, + declaredFieldType, + valueExpr + ) + case PutField( + pc, + declaringClass, + name, + declaredFieldType, + objRef, + value + ) => + val objRefExpr = transformExpr(pc, objRef) + val valueExpr = transformExpr(pc, value) + + return PutField( + pc, + declaringClass, + name, + declaredFieldType, + objRefExpr, + valueExpr + ) + case NonVirtualMethodCall( + pc, + declaringClass, + isInterface, + name, + descriptor, + receiver, + params + ) => + val receiverExpr = transformExpr(pc, receiver) + val paramsExpr = params.map(p => transformExpr(pc, p)) + + return NonVirtualMethodCall( + pc, + declaringClass, + isInterface, + name, + descriptor, + receiverExpr, + paramsExpr + ) + case VirtualMethodCall( + pc, + declaringClass, + isInterface, + name, + descriptor, + receiver, + params + ) => + val receiverExpr = transformExpr(pc, receiver) + val paramsExpr = params.map(p => transformExpr(pc, p)) + + return VirtualMethodCall( + pc, + declaringClass, + isInterface, + name, + descriptor, + receiverExpr, + paramsExpr + ) + case StaticMethodCall( + pc, + declaringClass, + isInterface, + name, + descriptor, + params + ) => + val paramsExpr = params.map(p => transformExpr(pc, p)) + + return StaticMethodCall( + pc, + declaringClass, + isInterface, + name, + descriptor, + paramsExpr + ) + case InvokedynamicMethodCall( + pc, + bootstrapMethod, + name, + descriptor, + params + ) => + val paramsExpr = params.map(p => transformExpr(pc, p)) + + return InvokedynamicMethodCall( + pc, + bootstrapMethod, + name, + descriptor, + paramsExpr + ) + case ExprStmt(pc, expr) => + val transformedExpr = transformExpr(pc, expr) + + return ExprStmt(pc, transformedExpr) + case CaughtException(pc, exceptionType, throwingStatements) => + return CaughtException(pc, exceptionType, throwingStatements) + case Checkcast(pc, value, cmpTpe) => + val valueExpr = transformExpr(pc, value) + // TODO Transform into assignment + return Checkcast(pc, valueExpr, cmpTpe) + case _ => throw new RuntimeException("Unknown statement: " + stmt) } - val paramLocal = createParameterLocal(targetVar, paramName) - - currentLocals(paramLocal.id) = paramLocal - return Assignment(pc, paramLocal, transformedExpr) - } - - if (targetVar.id >= 0) { - val transformedExpr = transformExpr(pc, expr) - - // Consider 'this' assignment from register to stack: s = this - val isThisAssignment = transformedExpr.isVar && transformedExpr.asVar.isThisLocal - val targetLocal = createStackLocal(pc, targetVar, isThisAssignment) - - currentLocals(targetLocal.id) = targetLocal - return Assignment(pc, targetLocal, transformedExpr) - } - - if (targetVar.id < 0) { - val transformedExpr = transformExpr(pc, expr) - - // Consider 'this' assignment from stack to register: r0 = $this - val isThisAssignment = transformedExpr.isVar && transformedExpr.asVar.isThisLocal - val targetLocal = createRegisterLocal(pc, targetVar, isThisAssignment) - - currentLocals(targetLocal.id) = targetLocal - return Assignment(pc, targetLocal, transformedExpr) - } - - throw new RuntimeException("Should never be reached") - case ReturnValue(pc, expr) => - val returnExpr = transformExpr(pc, expr) - - return ReturnValue(pc, returnExpr) - case Return(pc) => return Return(pc) - case Nop(pc) => return Nop(pc) - case MonitorEnter(pc, objRef) => - val objRefExpr = transformExpr(pc, objRef) - - return MonitorEnter(pc, objRefExpr) - case MonitorExit(pc, objRef) => - val objRefExpr = transformExpr(pc, objRef) - - return MonitorExit(pc, objRefExpr) - case ArrayStore(pc, arrayRef, index, value) => - val arrayRefExpr = transformExpr(pc, arrayRef) - val indexExpr = transformExpr(pc, index) - val valueExpr = transformExpr(pc, value) - - return ArrayStore(pc, arrayRefExpr, indexExpr, valueExpr) - case Throw(pc, exception) => - val exceptionExpr = transformExpr(pc, exception) - - return Throw(pc, exceptionExpr) - case PutStatic(pc, declaringClass, name, declaredFieldType, value) => - val valueExpr = transformExpr(pc, value) - - return PutStatic(pc, declaringClass, name, declaredFieldType, valueExpr) - case PutField(pc, declaringClass, name, declaredFieldType, objRef, value) => - val objRefExpr = transformExpr(pc, objRef) - val valueExpr = transformExpr(pc, value) - - return PutField(pc, declaringClass, name, declaredFieldType, objRefExpr, valueExpr) - case NonVirtualMethodCall(pc, declaringClass, isInterface, name, descriptor, receiver, params) => - val receiverExpr = transformExpr(pc, receiver) - val paramsExpr = params.map(p => transformExpr(pc, p)) - - return NonVirtualMethodCall(pc, declaringClass, isInterface, name, descriptor, receiverExpr, paramsExpr) - case VirtualMethodCall(pc, declaringClass, isInterface, name, descriptor, receiver, params) => - val receiverExpr = transformExpr(pc, receiver) - val paramsExpr = params.map(p => transformExpr(pc, p)) - - return VirtualMethodCall(pc, declaringClass, isInterface, name, descriptor, receiverExpr, paramsExpr) - case StaticMethodCall(pc, declaringClass, isInterface, name, descriptor, params) => - val paramsExpr = params.map(p => transformExpr(pc, p)) - - return StaticMethodCall(pc, declaringClass, isInterface, name, descriptor, paramsExpr) - case InvokedynamicMethodCall(pc, bootstrapMethod, name, descriptor, params) => - val paramsExpr = params.map(p => transformExpr(pc, p)) - - return InvokedynamicMethodCall(pc, bootstrapMethod, name, descriptor, paramsExpr) - case ExprStmt(pc, expr) => - val transformedExpr = transformExpr(pc, expr) - - return ExprStmt(pc, transformedExpr) - case CaughtException(pc, exceptionType, throwingStatements) => return CaughtException(pc, exceptionType, throwingStatements) - case Checkcast(pc, value, cmpTpe) => - val valueExpr = transformExpr(pc, value) - // TODO Transform into assignment - return Checkcast(pc, valueExpr, cmpTpe) - case _ => throw new RuntimeException("Unknown statement: " + stmt) - } - - throw new RuntimeException("Could not transform statement: " + stmt) - } - - def isThisVar(idBasedVar: IdBasedVar): Boolean = method.isNotStatic && idBasedVar.id == -1 - - def createParameterLocal(idBasedVar: IdBasedVar, paramName: Option[String] = Option.empty): TacLocal = { - val local = localArray(0) + throw new RuntimeException("Could not transform statement: " + stmt) + } - new RegisterLocal(idBasedVar.id, idBasedVar.cTpe, local(-idBasedVar.id - 1), isThisVar(idBasedVar), paramName) - } + def isThisVar(idBasedVar: IdBasedVar): Boolean = + method.isNotStatic && idBasedVar.id == -1 + + def createParameterLocal( + idBasedVar: IdBasedVar, + paramName: Option[String] = Option.empty + ): TacLocal = { + val local = localArray(0) + + new RegisterLocal( + idBasedVar.id, + idBasedVar.cTpe, + local(-idBasedVar.id - 1), + isThisVar(idBasedVar), + paramName + ) + } - def createStackLocal(pc: PC, idBasedVar: IdBasedVar, isThis: Boolean): TacLocal = { - val nextPc = method.body.get.pcOfNextInstruction(pc) - val value = operandsArray(nextPc) - val counter = stackHandler.defSiteAtPc(pc) - - if (value == null) { - val fieldType = computationalTypeToFieldType(idBasedVar.cTpe) - new StackLocal(counter, idBasedVar.cTpe, ValueInformation.forProperValue(fieldType)(project.classHierarchy), isThis) - } else { - new StackLocal(counter, idBasedVar.cTpe, value.head, isThis) - } - } + def createStackLocal( + pc: PC, + idBasedVar: IdBasedVar, + isThis: Boolean + ): TacLocal = { + val nextPc = method.body.get.pcOfNextInstruction(pc) + val value = operandsArray(nextPc) + val counter = stackHandler.defSiteAtPc(pc) + + if (value == null) { + val fieldType = computationalTypeToFieldType(idBasedVar.cTpe) + new StackLocal( + counter, + idBasedVar.cTpe, + ValueInformation.forProperValue(fieldType)(project.classHierarchy), + isThis + ) + } else { + new StackLocal(counter, idBasedVar.cTpe, value.head, isThis) + } + } - def createRegisterLocal(pc: PC, idBasedVar: IdBasedVar, isThis: Boolean): TacLocal = { - val nextPc = method.body.get.pcOfNextInstruction(pc) - val locals = localArray(nextPc) + def createRegisterLocal( + pc: PC, + idBasedVar: IdBasedVar, + isThis: Boolean + ): TacLocal = { + val nextPc = method.body.get.pcOfNextInstruction(pc) + val locals = localArray(nextPc) + + val index = -idBasedVar.id - 1 + + val local = method.body.get.localVariable(nextPc, index) + if (local.isDefined) { + if (locals == null) { + val fieldType = computationalTypeToFieldType(idBasedVar.cTpe) + return new RegisterLocal( + idBasedVar.id, + idBasedVar.cTpe, + ValueInformation.forProperValue(fieldType)(project.classHierarchy), + isThis, + Option(local.get.name) + ) + } else { + return new RegisterLocal( + idBasedVar.id, + idBasedVar.cTpe, + locals(index), + isThis, + Option(local.get.name) + ) + } + } - val index = -idBasedVar.id - 1 + if (locals == null) { + val fieldType = computationalTypeToFieldType(idBasedVar.cTpe) + new RegisterLocal( + idBasedVar.id, + idBasedVar.cTpe, + ValueInformation.forProperValue(fieldType)(project.classHierarchy), + isThis + ) + } else { + new RegisterLocal(idBasedVar.id, idBasedVar.cTpe, locals(index), isThis) + } + } - val local = method.body.get.localVariable(nextPc, index) - if (local.isDefined) { - if (locals == null) { - val fieldType = computationalTypeToFieldType(idBasedVar.cTpe) - return new RegisterLocal(idBasedVar.id, idBasedVar.cTpe, ValueInformation.forProperValue(fieldType)(project.classHierarchy), isThis, Option(local.get.name)) - } else { - return new RegisterLocal(idBasedVar.id, idBasedVar.cTpe, locals(index), isThis, Option(local.get.name)) + def createExceptionLocal( + pc: PC, + idBasedVar: IdBasedVar, + localId: Int + ): TacLocal = { + val value = operandsArray(pc) + + if (value == null) { + val fieldType = computationalTypeToFieldType(idBasedVar.cTpe) + new ExceptionLocal( + localId, + idBasedVar.cTpe, + ValueInformation.forProperValue(fieldType)(project.classHierarchy) + ) + } else { + new ExceptionLocal(localId, idBasedVar.cTpe, value.head) + } } - } - - if (locals == null) { - val fieldType = computationalTypeToFieldType(idBasedVar.cTpe) - new RegisterLocal(idBasedVar.id, idBasedVar.cTpe, ValueInformation.forProperValue(fieldType)(project.classHierarchy), isThis) - } else { - new RegisterLocal(idBasedVar.id, idBasedVar.cTpe, locals(index), isThis) - } - } - def createExceptionLocal(pc: PC, idBasedVar: IdBasedVar, localId: Int): TacLocal = { - val value = operandsArray(pc) + def computationalTypeToFieldType(cTpe: ComputationalType): FieldType = { + cTpe match { + case ComputationalTypeInt => IntegerType + case ComputationalTypeFloat => FloatType + case ComputationalTypeLong => LongType + case ComputationalTypeDouble => DoubleType + case ComputationalTypeReference => ObjectType.Object + case ComputationalTypeReturnAddress => ObjectType.Object + case _ => + throw new RuntimeException("Unknown computational type " + cTpe) + } + } - if (value == null) { - val fieldType = computationalTypeToFieldType(idBasedVar.cTpe) - new ExceptionLocal(localId, idBasedVar.cTpe, ValueInformation.forProperValue(fieldType)(project.classHierarchy)) - } else { - new ExceptionLocal(localId, idBasedVar.cTpe, value.head) - } - } + def transformExpr(pc: PC, expr: Expr[IdBasedVar]): Expr[TacLocal] = { + expr match { + case v: IdBasedVar => + // Exception locals are implicitly defined and denoted with s0. They are + // not pushed on the operand stack, so we have to define it explicitly + if (exceptionHandlers.contains(tac.pcToIndex(pc))) { + exceptionCount += 1 + + return createExceptionLocal(pc, v, exceptionCount) + } + + if (v.id >= 0) { + val stmt = tac.stmts(tac.pcToIndex(pc)) + val counter = + stackHandler.counterForOperand(pc, v.id, stmt.isReturnValue) + + return currentLocals(counter) + } + + return currentLocals(v.id) + case InstanceOf(pc, value, cmpTpe) => + val valueExpr = transformExpr(pc, value) + + return InstanceOf(pc, valueExpr, cmpTpe) + case Compare(pc, left, condition, right) => + val leftExpr = transformExpr(pc, left) + val rightExpr = transformExpr(pc, right) + + return Compare(pc, leftExpr, condition, rightExpr) + case Param(cTpe, name) => + paramCount += 1 + + return new ParameterLocal(paramCount, cTpe, name) + case MethodTypeConst(pc, value) => return MethodTypeConst(pc, value) + case MethodHandleConst(pc, value) => return MethodHandleConst(pc, value) + case IntConst(pc, value) => return IntConst(pc, value) + case LongConst(pc, value) => return LongConst(pc, value) + case FloatConst(pc, value) => return FloatConst(pc, value) + case DoubleConst(pc, value) => return DoubleConst(pc, value) + case StringConst(pc, value) => return StringConst(pc, value) + case ClassConst(pc, value) => return ClassConst(pc, value) + case DynamicConst(pc, bootstrapMethod, name, descriptor) => + return DynamicConst(pc, bootstrapMethod, name, descriptor) + case NullExpr(pc) => return NullExpr(pc) + case BinaryExpr(pc, cTpe, op, left, right) => + val leftExpr = transformExpr(pc, left) + val rightExpr = transformExpr(pc, right) + + return BinaryExpr(pc, cTpe, op, leftExpr, rightExpr) + case PrefixExpr(pc, cTpe, op, operand) => + val operandExpr = transformExpr(pc, operand) + + return PrefixExpr(pc, cTpe, op, operandExpr) + case PrimitiveTypecastExpr(pc, targetTpe, operand) => + val operandExpr = transformExpr(pc, operand) + + return PrimitiveTypecastExpr(pc, targetTpe, operandExpr) + case New(pc, tpe) => return New(pc, tpe) + case NewArray(pc, counts, tpe) => + val countsExpr = counts.map(c => transformExpr(pc, c)) + + return NewArray(pc, countsExpr, tpe) + case ArrayLoad(pc, index, arrayRef) => + val indexExpr = transformExpr(pc, index) + val arrayRefExpr = transformExpr(pc, arrayRef) + + return ArrayLoad(pc, indexExpr, arrayRefExpr) + case ArrayLength(pc, arrayRef) => + val arrayRefExpr = transformExpr(pc, arrayRef) + + return ArrayLength(pc, arrayRefExpr) + case GetField(pc, declaringClass, name, declaredFieldType, objRef) => + val objRefExpr = transformExpr(pc, objRef) + + return GetField( + pc, + declaringClass, + name, + declaredFieldType, + objRefExpr + ) + case GetStatic(pc, declaringClass, name, declaredFieldType) => + return GetStatic(pc, declaringClass, name, declaredFieldType) + case InvokedynamicFunctionCall( + pc, + bootstrapMethod, + name, + descriptor, + params + ) => + val paramsExpr = params.map(p => transformExpr(pc, p)) + + return InvokedynamicFunctionCall( + pc, + bootstrapMethod, + name, + descriptor, + paramsExpr + ) + case NonVirtualFunctionCall( + pc, + declaringClass, + isInterface, + name, + descriptor, + receiver, + params + ) => + val receiverExpr = transformExpr(pc, receiver) + val paramsExpr = params.map(p => transformExpr(pc, p)) + + return NonVirtualFunctionCall( + pc, + declaringClass, + isInterface, + name, + descriptor, + receiverExpr, + paramsExpr + ) + case VirtualFunctionCall( + pc, + declaringClass, + isInterface, + name, + descriptor, + receiver, + params + ) => + val receiverExpr = transformExpr(pc, receiver) + val paramsExpr = params.map(p => transformExpr(pc, p)) + + return VirtualFunctionCall( + pc, + declaringClass, + isInterface, + name, + descriptor, + receiverExpr, + paramsExpr + ) + case StaticFunctionCall( + pc, + declaringClass, + isInterface, + name, + descriptor, + params + ) => + val paramsExpr = params.map(p => transformExpr(pc, p)) + + return StaticFunctionCall( + pc, + declaringClass, + isInterface, + name, + descriptor, + paramsExpr + ) + case _ => throw new RuntimeException("Unknown expression: " + expr) + } - def computationalTypeToFieldType(cTpe: ComputationalType): FieldType = { - cTpe match { - case ComputationalTypeInt => IntegerType - case ComputationalTypeFloat => FloatType - case ComputationalTypeLong => LongType - case ComputationalTypeDouble => DoubleType - case ComputationalTypeReference => ObjectType.Object - case ComputationalTypeReturnAddress => ObjectType.Object - case _ => throw new RuntimeException("Unknown computational type " + cTpe) - } - } + throw new RuntimeException("Could not transform expr: " + expr) + } - def transformExpr(pc: PC, expr: Expr[IdBasedVar]): Expr[TacLocal] = { - expr match { - case v: IdBasedVar => - // Exception locals are implicitly defined and denoted with s0. They are - // not pushed on the operand stack, so we have to define it explicitly - if (exceptionHandlers.contains(tac.pcToIndex(pc))) { - exceptionCount += 1 - - return createExceptionLocal(pc, v, exceptionCount) - } - - if (v.id >= 0) { - val stmt = tac.stmts(tac.pcToIndex(pc)) - val counter = stackHandler.counterForOperand(pc, v.id, stmt.isReturnValue) - - return currentLocals(counter) - } - - return currentLocals(v.id) - case InstanceOf(pc, value, cmpTpe) => - val valueExpr = transformExpr(pc, value) - - return InstanceOf(pc, valueExpr, cmpTpe) - case Compare(pc, left, condition, right) => - val leftExpr = transformExpr(pc, left) - val rightExpr = transformExpr(pc, right) - - return Compare(pc, leftExpr, condition, rightExpr) - case Param(cTpe, name) => - paramCount += 1 - - return new ParameterLocal(paramCount, cTpe, name) - case MethodTypeConst(pc, value) => return MethodTypeConst(pc, value) - case MethodHandleConst(pc, value) => return MethodHandleConst(pc, value) - case IntConst(pc, value) => return IntConst(pc, value) - case LongConst(pc, value) => return LongConst(pc, value) - case FloatConst(pc, value) => return FloatConst(pc, value) - case DoubleConst(pc, value) => return DoubleConst(pc, value) - case StringConst(pc, value) => return StringConst(pc, value) - case ClassConst(pc, value) => return ClassConst(pc, value) - case DynamicConst(pc, bootstrapMethod, name, descriptor) => return DynamicConst(pc, bootstrapMethod, name, descriptor) - case NullExpr(pc) => return NullExpr(pc) - case BinaryExpr(pc, cTpe, op, left, right) => - val leftExpr = transformExpr(pc, left) - val rightExpr = transformExpr(pc, right) - - return BinaryExpr(pc, cTpe, op, leftExpr, rightExpr) - case PrefixExpr(pc, cTpe, op, operand) => - val operandExpr = transformExpr(pc, operand) - - return PrefixExpr(pc, cTpe, op, operandExpr) - case PrimitiveTypecastExpr(pc, targetTpe, operand) => - val operandExpr = transformExpr(pc, operand) - - return PrimitiveTypecastExpr(pc, targetTpe, operandExpr) - case New(pc, tpe) => return New(pc, tpe) - case NewArray(pc, counts, tpe) => - val countsExpr = counts.map(c => transformExpr(pc, c)) - - return NewArray(pc, countsExpr, tpe) - case ArrayLoad(pc, index, arrayRef) => - val indexExpr = transformExpr(pc, index) - val arrayRefExpr = transformExpr(pc, arrayRef) - - return ArrayLoad(pc, indexExpr, arrayRefExpr) - case ArrayLength(pc, arrayRef) => - val arrayRefExpr = transformExpr(pc, arrayRef) - - return ArrayLength(pc, arrayRefExpr) - case GetField(pc, declaringClass, name, declaredFieldType, objRef) => - val objRefExpr = transformExpr(pc, objRef) - - return GetField(pc, declaringClass, name, declaredFieldType, objRefExpr) - case GetStatic(pc, declaringClass, name, declaredFieldType) => return GetStatic(pc, declaringClass, name, declaredFieldType) - case InvokedynamicFunctionCall(pc, bootstrapMethod, name, descriptor, params) => - val paramsExpr = params.map(p => transformExpr(pc, p)) - - return InvokedynamicFunctionCall(pc, bootstrapMethod, name, descriptor, paramsExpr) - case NonVirtualFunctionCall(pc, declaringClass, isInterface, name, descriptor, receiver, params) => - val receiverExpr = transformExpr(pc, receiver) - val paramsExpr = params.map(p => transformExpr(pc, p)) - - return NonVirtualFunctionCall(pc, declaringClass, isInterface, name, descriptor, receiverExpr, paramsExpr) - case VirtualFunctionCall(pc, declaringClass, isInterface, name, descriptor, receiver, params) => - val receiverExpr = transformExpr(pc, receiver) - val paramsExpr = params.map(p => transformExpr(pc, p)) - - return VirtualFunctionCall(pc, declaringClass, isInterface, name, descriptor, receiverExpr, paramsExpr) - case StaticFunctionCall(pc, declaringClass, isInterface, name, descriptor, params) => - val paramsExpr = params.map(p => transformExpr(pc, p)) - - return StaticFunctionCall(pc, declaringClass, isInterface, name, descriptor, paramsExpr) - case _ => throw new RuntimeException("Unknown expression: " + expr) - } - - throw new RuntimeException("Could not transform expr: " + expr) + tac.stmts.map(stmt => transformStmt(stmt)) } - tac.stmts.map(stmt => transformStmt(stmt)) - } - } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/NopEliminator.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/NopEliminator.scala index b839e9c15..a64eef1cd 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/NopEliminator.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/NopEliminator.scala @@ -1,3 +1,14 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ package boomerang.scope.opal.transformation.transformer import boomerang.scope.opal.transformation.StmtGraph @@ -5,16 +16,17 @@ import org.opalj.tac.Nop object NopEliminator { - def apply(stmtGraph: StmtGraph): StmtGraph = { + def apply(stmtGraph: StmtGraph): StmtGraph = { - def removeNopStatements(stmtGraph: StmtGraph): StmtGraph = { - val nopStatements = stmtGraph.statements.filter(s => s.astID == Nop.ASTID && s.pc >= 0) - var result = stmtGraph + def removeNopStatements(stmtGraph: StmtGraph): StmtGraph = { + val nopStatements = + stmtGraph.statements.filter(s => s.astID == Nop.ASTID && s.pc >= 0) + var result = stmtGraph - nopStatements.foreach(stmt => result = result.remove(stmt)) - result - } + nopStatements.foreach(stmt => result = result.remove(stmt)) + result + } - removeNopStatements(stmtGraph) - } + removeNopStatements(stmtGraph) + } } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/NopTransformer.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/NopTransformer.scala index 8cec83803..e904e5441 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/NopTransformer.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/NopTransformer.scala @@ -1,45 +1,59 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ package boomerang.scope.opal.transformation.transformer -import boomerang.scope.opal.transformation.{StmtGraph, TacLocal} -import org.opalj.tac.{If, Nop, Stmt} +import boomerang.scope.opal.transformation.StmtGraph +import boomerang.scope.opal.transformation.TacLocal +import org.opalj.tac.If +import org.opalj.tac.Nop +import org.opalj.tac.Stmt object NopTransformer { - private final val INITIAL_NOP = Integer.MIN_VALUE - - def apply(stmtGraph: StmtGraph): StmtGraph = { - val tac = stmtGraph.tac - - def addNopStatements(stmtGraph: StmtGraph): StmtGraph = { - // Add a nop statement in the beginning - val nop = Nop(INITIAL_NOP) - var result = stmtGraph.insertBefore(nop, stmtGraph.heads.head) - - var beforeStmtInsert = List.empty[Stmt[TacLocal]] - tac.zipWithIndex.foreach(stmt => { - // TODO Switch statements - if (stmt._1.astID == If.ASTID) { - val nextStmt = tac(stmt._2 + 1) - val targetStmt = tac(stmt._1.asIf.targetStmt) - - beforeStmtInsert = beforeStmtInsert ++ List(nextStmt, targetStmt) - } - }) - - beforeStmtInsert.foreach(stmt => { - /* If one or multiple branches target the same statement, we add exactly one Nop statement - * before the target statement (represented by the negative pc). This way, important - * data flows are covered - */ - val nextStmtNop = Nop(-stmt.pc) - if (!result.statements.contains(nextStmtNop)) { - result = result.insertBefore(nextStmtNop, stmt) + private final val INITIAL_NOP = Integer.MIN_VALUE + + def apply(stmtGraph: StmtGraph): StmtGraph = { + val tac = stmtGraph.tac + + def addNopStatements(stmtGraph: StmtGraph): StmtGraph = { + // Add a nop statement in the beginning + val nop = Nop(INITIAL_NOP) + var result = stmtGraph.insertBefore(nop, stmtGraph.heads.head) + + var beforeStmtInsert = List.empty[Stmt[TacLocal]] + tac.zipWithIndex.foreach(stmt => { + // TODO Switch statements + if (stmt._1.astID == If.ASTID) { + val nextStmt = tac(stmt._2 + 1) + val targetStmt = tac(stmt._1.asIf.targetStmt) + + beforeStmtInsert = beforeStmtInsert ++ List(nextStmt, targetStmt) + } + }) + + beforeStmtInsert.foreach(stmt => { + /* If one or multiple branches target the same statement, we add exactly one Nop statement + * before the target statement (represented by the negative pc). This way, important + * data flows are covered + */ + val nextStmtNop = Nop(-stmt.pc) + if (!result.statements.contains(nextStmtNop)) { + result = result.insertBefore(nextStmtNop, stmt) + } + }) + + result } - }) - result + addNopStatements(stmtGraph) } - - addNopStatements(stmtGraph) - } } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/NullifyFieldsTransformer.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/NullifyFieldsTransformer.scala index 39a13753e..1be873aa1 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/NullifyFieldsTransformer.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/NullifyFieldsTransformer.scala @@ -1,61 +1,96 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ package boomerang.scope.opal.transformation.transformer -import boomerang.scope.opal.transformation.{NullifiedLocal, StmtGraph, TacLocal} -import org.opalj.br.{ComputationalTypeReference, Field, FieldType, Method} -import org.opalj.tac.{Assignment, Expr, NullExpr, PutField} +import boomerang.scope.opal.transformation.NullifiedLocal +import boomerang.scope.opal.transformation.StmtGraph +import boomerang.scope.opal.transformation.TacLocal +import org.opalj.br.ComputationalTypeReference +import org.opalj.br.Field +import org.opalj.br.FieldType +import org.opalj.br.Method +import org.opalj.tac.Assignment +import org.opalj.tac.Expr +import org.opalj.tac.NullExpr +import org.opalj.tac.PutField object NullifyFieldsTransformer { - private final val NULLIFIED_FIELD = -2 + private final val NULLIFIED_FIELD = -2 - def apply(method: Method, stmtGraph: StmtGraph): StmtGraph = { - if (!method.isConstructor || method.isStatic) { - return stmtGraph - } + def apply(method: Method, stmtGraph: StmtGraph): StmtGraph = { + if (!method.isConstructor || method.isStatic) { + return stmtGraph + } - val tac = stmtGraph.tac - var localCounter = 0 - - def isFieldDefined(field: Field): Boolean = { - // TODO Also consider super classes - tac.foreach { - // TODO Maybe also match 'this' local? - case PutField(_, _, field.name, field.fieldType, _, _) => return true - case _ => - } - false - } + val tac = stmtGraph.tac + var localCounter = 0 - def getThisLocal: Expr[TacLocal] = { - tac.foreach(stmt => { - if (stmt.pc == -1 && stmt.asAssignment.targetVar.id == -1) return stmt.asAssignment.targetVar - }) + def isFieldDefined(field: Field): Boolean = { + // TODO Also consider super classes + tac.foreach { + // TODO Maybe also match 'this' local? + case PutField(_, _, field.name, field.fieldType, _, _) => return true + case _ => + } + false + } - throw new RuntimeException("'this' local not found in method: " + method.name) - } + def getThisLocal: Expr[TacLocal] = { + tac.foreach(stmt => { + if (stmt.pc == -1 && stmt.asAssignment.targetVar.id == -1) + return stmt.asAssignment.targetVar + }) - def createNullifiedLocal(localCounter: Int, fieldType: FieldType): NullifiedLocal = { - // TODO Types - new NullifiedLocal(localCounter, ComputationalTypeReference) - } + throw new RuntimeException( + "'this' local not found in method: " + method.name + ) + } + + def createNullifiedLocal( + localCounter: Int, + fieldType: FieldType + ): NullifiedLocal = { + // TODO Types + new NullifiedLocal(localCounter, ComputationalTypeReference) + } - val definedFields = method.classFile.fields.filter(f => isFieldDefined(f)) - val undefinedFields = method.classFile.fields.filter(f => !definedFields.contains(f) && f.isNotStatic && f.isNotFinal) - val firstOriginalStmt = tac.find(stmt => stmt.pc >= 0).get - var result = stmtGraph + val definedFields = method.classFile.fields.filter(f => isFieldDefined(f)) + val undefinedFields = method.classFile.fields.filter(f => + !definedFields.contains(f) && f.isNotStatic && f.isNotFinal + ) + val firstOriginalStmt = tac.find(stmt => stmt.pc >= 0).get + var result = stmtGraph - undefinedFields.foreach(field => { - val local = createNullifiedLocal(localCounter, field.fieldType) - localCounter += 1 + undefinedFields.foreach(field => { + val local = createNullifiedLocal(localCounter, field.fieldType) + localCounter += 1 - val defSite = Assignment[TacLocal](NULLIFIED_FIELD, local, NullExpr(NULLIFIED_FIELD)) - val putField = PutField(NULLIFIED_FIELD, method.classFile.thisType, field.name, field.fieldType, getThisLocal, local) + val defSite = + Assignment[TacLocal](NULLIFIED_FIELD, local, NullExpr(NULLIFIED_FIELD)) + val putField = PutField( + NULLIFIED_FIELD, + method.classFile.thisType, + field.name, + field.fieldType, + getThisLocal, + local + ) - result = result.insertBefore(defSite, firstOriginalStmt) - result = result.insertBefore(putField, firstOriginalStmt) - }) + result = result.insertBefore(defSite, firstOriginalStmt) + result = result.insertBefore(putField, firstOriginalStmt) + }) - result - } + result + } } diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalArrayTest.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalArrayTest.scala index 710def675..b0c0590f6 100644 --- a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalArrayTest.scala +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalArrayTest.scala @@ -1,122 +1,146 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ package boomerang.scope.opal import boomerang.scope.opal.tac.OpalMethod import boomerang.scope.test.MethodSignature import boomerang.scope.test.targets.ArrayTarget -import org.junit.{Assert, Ignore, Test} -import org.opalj.br.IntegerType - import java.util +import org.junit.Assert +import org.junit.Ignore +import org.junit.Test +import org.opalj.br.IntegerType class OpalArrayTest { - private val integerType = IntegerType.toJVMTypeName - - @Test - def arrayLoadIndexTest(): Unit = { - val opalSetup = new OpalSetup() - opalSetup.setupOpal(classOf[ArrayTarget].getName) - - val signature = new MethodSignature(classOf[ArrayTarget].getName, "arrayIndexLoad", "V", util.List.of("[" + integerType)) - val method = opalSetup.resolveMethod(signature) - val opalMethod = OpalMethod(method) - - var arrayLoadCount = 0 - opalMethod.getStatements.forEach(stmt => { - if (stmt.isArrayLoad) { - arrayLoadCount += 1 - - val arrayBase = stmt.getArrayBase - Assert.assertFalse(arrayBase.getX.isArrayRef) - Assert.assertTrue(arrayBase.getX.isLocal) - Assert.assertEquals(1, arrayBase.getY) - - val rightOp = stmt.getRightOp - Assert.assertTrue(rightOp.isArrayRef) - } - }) - - Assert.assertEquals(1, arrayLoadCount) - } - - @Test - def arrayLoadVarTest(): Unit = { - val opalSetup = new OpalSetup() - opalSetup.setupOpal(classOf[ArrayTarget].getName) - - val signature = new MethodSignature(classOf[ArrayTarget].getName, "arrayVarLoad", "V", util.List.of("[" + integerType)) - val method = opalSetup.resolveMethod(signature) - val opalMethod = OpalMethod(method) - - var arrayLoadCount = 0 - opalMethod.getStatements.forEach(stmt => { - if (stmt.isArrayLoad) { - arrayLoadCount += 1 - - val arrayBase = stmt.getArrayBase - Assert.assertFalse(arrayBase.getX.isArrayRef) - Assert.assertTrue(arrayBase.getX.isLocal) - Assert.assertEquals(-1, arrayBase.getY) - - val rightOp = stmt.getRightOp - Assert.assertTrue(rightOp.isArrayRef) - } - }) - - Assert.assertEquals(1, arrayLoadCount) - } - - @Test - def arrayStoreIndexTest(): Unit = { - val opalSetup = new OpalSetup() - opalSetup.setupOpal(classOf[ArrayTarget].getName) - - val signature = new MethodSignature(classOf[ArrayTarget].getName, "arrayStoreIndex", "V") - val method = opalSetup.resolveMethod(signature) - val opalMethod = OpalMethod(method) - - var arrayStoreCount = 0 - opalMethod.getStatements.forEach(stmt => { - if (stmt.isArrayStore) { - arrayStoreCount += 1 - - val arrayBase = stmt.getArrayBase - Assert.assertFalse(arrayBase.getX.isArrayRef) - Assert.assertTrue(arrayBase.getX.isLocal) - Assert.assertEquals(0, arrayBase.getY) - - val leftOp = stmt.getLeftOp - Assert.assertTrue(leftOp.isArrayRef) - } - }) - - Assert.assertEquals(1, arrayStoreCount) - } - - @Test - def arrayStoreVarTest(): Unit = { - val opalSetup = new OpalSetup() - opalSetup.setupOpal(classOf[ArrayTarget].getName) - - val signature = new MethodSignature(classOf[ArrayTarget].getName, "arrayStoreVar", "V") - val method = opalSetup.resolveMethod(signature) - val opalMethod = OpalMethod(method) - - var arrayStoreCount = 0 - opalMethod.getStatements.forEach(stmt => { - if (stmt.isArrayStore) { - arrayStoreCount += 1 - - val arrayBase = stmt.getArrayBase - Assert.assertFalse(arrayBase.getX.isArrayRef) - Assert.assertTrue(arrayBase.getX.isLocal) - Assert.assertEquals(-1, arrayBase.getY) - - val leftOp = stmt.getLeftOp - Assert.assertTrue(leftOp.isArrayRef) - } - }) - - Assert.assertEquals(1, arrayStoreCount) - } + private val integerType = IntegerType.toJVMTypeName + + @Test + def arrayLoadIndexTest(): Unit = { + val opalSetup = new OpalSetup() + opalSetup.setupOpal(classOf[ArrayTarget].getName) + + val signature = new MethodSignature( + classOf[ArrayTarget].getName, + "arrayIndexLoad", + "V", + util.List.of("[" + integerType) + ) + val method = opalSetup.resolveMethod(signature) + val opalMethod = OpalMethod(method) + + var arrayLoadCount = 0 + opalMethod.getStatements.forEach(stmt => { + if (stmt.isArrayLoad) { + arrayLoadCount += 1 + + val arrayBase = stmt.getArrayBase + Assert.assertFalse(arrayBase.getX.isArrayRef) + Assert.assertTrue(arrayBase.getX.isLocal) + Assert.assertEquals(1, arrayBase.getY) + + val rightOp = stmt.getRightOp + Assert.assertTrue(rightOp.isArrayRef) + } + }) + + Assert.assertEquals(1, arrayLoadCount) + } + + @Test + def arrayLoadVarTest(): Unit = { + val opalSetup = new OpalSetup() + opalSetup.setupOpal(classOf[ArrayTarget].getName) + + val signature = new MethodSignature( + classOf[ArrayTarget].getName, + "arrayVarLoad", + "V", + util.List.of("[" + integerType) + ) + val method = opalSetup.resolveMethod(signature) + val opalMethod = OpalMethod(method) + + var arrayLoadCount = 0 + opalMethod.getStatements.forEach(stmt => { + if (stmt.isArrayLoad) { + arrayLoadCount += 1 + + val arrayBase = stmt.getArrayBase + Assert.assertFalse(arrayBase.getX.isArrayRef) + Assert.assertTrue(arrayBase.getX.isLocal) + Assert.assertEquals(-1, arrayBase.getY) + + val rightOp = stmt.getRightOp + Assert.assertTrue(rightOp.isArrayRef) + } + }) + + Assert.assertEquals(1, arrayLoadCount) + } + + @Test + def arrayStoreIndexTest(): Unit = { + val opalSetup = new OpalSetup() + opalSetup.setupOpal(classOf[ArrayTarget].getName) + + val signature = + new MethodSignature(classOf[ArrayTarget].getName, "arrayStoreIndex", "V") + val method = opalSetup.resolveMethod(signature) + val opalMethod = OpalMethod(method) + + var arrayStoreCount = 0 + opalMethod.getStatements.forEach(stmt => { + if (stmt.isArrayStore) { + arrayStoreCount += 1 + + val arrayBase = stmt.getArrayBase + Assert.assertFalse(arrayBase.getX.isArrayRef) + Assert.assertTrue(arrayBase.getX.isLocal) + Assert.assertEquals(0, arrayBase.getY) + + val leftOp = stmt.getLeftOp + Assert.assertTrue(leftOp.isArrayRef) + } + }) + + Assert.assertEquals(1, arrayStoreCount) + } + + @Test + def arrayStoreVarTest(): Unit = { + val opalSetup = new OpalSetup() + opalSetup.setupOpal(classOf[ArrayTarget].getName) + + val signature = + new MethodSignature(classOf[ArrayTarget].getName, "arrayStoreVar", "V") + val method = opalSetup.resolveMethod(signature) + val opalMethod = OpalMethod(method) + + var arrayStoreCount = 0 + opalMethod.getStatements.forEach(stmt => { + if (stmt.isArrayStore) { + arrayStoreCount += 1 + + val arrayBase = stmt.getArrayBase + Assert.assertFalse(arrayBase.getX.isArrayRef) + Assert.assertTrue(arrayBase.getX.isLocal) + Assert.assertEquals(-1, arrayBase.getY) + + val leftOp = stmt.getLeftOp + Assert.assertTrue(leftOp.isArrayRef) + } + }) + + Assert.assertEquals(1, arrayStoreCount) + } } diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalAssignmentTest.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalAssignmentTest.scala index e3d31ddd9..e62ee964f 100644 --- a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalAssignmentTest.scala +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalAssignmentTest.scala @@ -1,132 +1,160 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ package boomerang.scope.opal import boomerang.scope.opal.tac.OpalMethod import boomerang.scope.test.MethodSignature import boomerang.scope.test.targets.AssignmentTarget -import org.junit.{Assert, Test} +import org.junit.Assert +import org.junit.Test class OpalAssignmentTest { - @Test - def arrayAllocationTest(): Unit = { - val opalSetup = new OpalSetup() - opalSetup.setupOpal(classOf[AssignmentTarget].getName) - - val signature = new MethodSignature(classOf[AssignmentTarget].getName, "arrayAllocation", "V") - val method = opalSetup.resolveMethod(signature) - val opalMethod = OpalMethod(method) - - var arrayAllocationCount = 0 - opalMethod.getStatements.forEach(stmt => { - if (stmt.isAssignStmt) { - val rightOp = stmt.getRightOp - - if (rightOp.isArrayAllocationVal) { - arrayAllocationCount += 1 - - val leftOp = stmt.getLeftOp - Assert.assertTrue(leftOp.isLocal) - - Assert.assertTrue(rightOp.getArrayAllocationSize.isIntConstant) - Assert.assertEquals(2, rightOp.getArrayAllocationSize.getIntValue) - } - } - }) - - Assert.assertEquals(1, arrayAllocationCount) - } - - @Test - def multiArrayAllocationTest(): Unit = { - val opalSetup = new OpalSetup() - opalSetup.setupOpal(classOf[AssignmentTarget].getName) - - val signature = new MethodSignature(classOf[AssignmentTarget].getName, "multiArrayAllocation", "V") - val method = opalSetup.resolveMethod(signature) - val opalMethod = OpalMethod(method) - - var checked = false - opalMethod.getStatements.forEach(stmt => { - if (stmt.isAssignStmt) { - val rightOp = stmt.getRightOp - - if (rightOp.isArrayAllocationVal) { - val leftOp = stmt.getLeftOp - Assert.assertTrue(leftOp.isLocal) - - val arraySize = rightOp.getArrayAllocationSize - Assert.assertTrue(arraySize.isIntConstant) - Assert.assertEquals(2, arraySize.getIntValue) - - checked = true - } - } - }) - - Assert.assertTrue(checked) - } - - @Test - def constantAssignmentTest(): Unit = { - val opalSetup = new OpalSetup() - opalSetup.setupOpal(classOf[AssignmentTarget].getName) - - val signature = new MethodSignature(classOf[AssignmentTarget].getName, "constantAssignment", "Void") - val method = opalSetup.resolveMethod(signature) - val opalMethod = OpalMethod(method) - - var constantCount = 0 - opalMethod.getStatements.forEach(stmt => { - if (stmt.isAssignStmt) { - val leftOp = stmt.getLeftOp - val rightOp = stmt.getRightOp - - Assert.assertTrue(leftOp.isLocal) - - if (rightOp.isIntConstant) { - constantCount += 1 - - Assert.assertEquals(10, rightOp.getIntValue) - Assert.assertTrue(rightOp.getType.toString.equals("int")) - } - - if (rightOp.isLongConstant) { - constantCount += 1 - - Assert.assertEquals(1000, rightOp.getLongValue) - Assert.assertTrue(rightOp.getType.toString.equals("long")) - } - - if (rightOp.isStringConstant) { - constantCount += 1 - - Assert.assertTrue(rightOp.getStringValue.equals("test")) - Assert.assertTrue(rightOp.getType.toString.equals("java.lang.String")) - } - } - }) - - Assert.assertEquals(3, constantCount) - } - - @Test - def fieldStoreAssignmentTest(): Unit = { - val opalSetup = new OpalSetup() - opalSetup.setupOpal(classOf[AssignmentTarget].getName) - - val signature = new MethodSignature(classOf[AssignmentTarget].getName, "fieldStoreAssignment", "Void") - val method = opalSetup.resolveMethod(signature) - val opalMethod = OpalMethod(method) - - opalMethod.getStatements.forEach(stmt => { - if (stmt.isFieldStore) { - Assert.assertTrue(stmt.isAssignStmt) - - val leftOp = stmt.getLeftOp - val rightOp = stmt.getRightOp - - println() - } - }) - } + @Test + def arrayAllocationTest(): Unit = { + val opalSetup = new OpalSetup() + opalSetup.setupOpal(classOf[AssignmentTarget].getName) + + val signature = new MethodSignature( + classOf[AssignmentTarget].getName, + "arrayAllocation", + "V" + ) + val method = opalSetup.resolveMethod(signature) + val opalMethod = OpalMethod(method) + + var arrayAllocationCount = 0 + opalMethod.getStatements.forEach(stmt => { + if (stmt.isAssignStmt) { + val rightOp = stmt.getRightOp + + if (rightOp.isArrayAllocationVal) { + arrayAllocationCount += 1 + + val leftOp = stmt.getLeftOp + Assert.assertTrue(leftOp.isLocal) + + Assert.assertTrue(rightOp.getArrayAllocationSize.isIntConstant) + Assert.assertEquals(2, rightOp.getArrayAllocationSize.getIntValue) + } + } + }) + + Assert.assertEquals(1, arrayAllocationCount) + } + + @Test + def multiArrayAllocationTest(): Unit = { + val opalSetup = new OpalSetup() + opalSetup.setupOpal(classOf[AssignmentTarget].getName) + + val signature = new MethodSignature( + classOf[AssignmentTarget].getName, + "multiArrayAllocation", + "V" + ) + val method = opalSetup.resolveMethod(signature) + val opalMethod = OpalMethod(method) + + var checked = false + opalMethod.getStatements.forEach(stmt => { + if (stmt.isAssignStmt) { + val rightOp = stmt.getRightOp + + if (rightOp.isArrayAllocationVal) { + val leftOp = stmt.getLeftOp + Assert.assertTrue(leftOp.isLocal) + + val arraySize = rightOp.getArrayAllocationSize + Assert.assertTrue(arraySize.isIntConstant) + Assert.assertEquals(2, arraySize.getIntValue) + + checked = true + } + } + }) + + Assert.assertTrue(checked) + } + + @Test + def constantAssignmentTest(): Unit = { + val opalSetup = new OpalSetup() + opalSetup.setupOpal(classOf[AssignmentTarget].getName) + + val signature = new MethodSignature( + classOf[AssignmentTarget].getName, + "constantAssignment", + "Void" + ) + val method = opalSetup.resolveMethod(signature) + val opalMethod = OpalMethod(method) + + var constantCount = 0 + opalMethod.getStatements.forEach(stmt => { + if (stmt.isAssignStmt) { + val leftOp = stmt.getLeftOp + val rightOp = stmt.getRightOp + + Assert.assertTrue(leftOp.isLocal) + + if (rightOp.isIntConstant) { + constantCount += 1 + + Assert.assertEquals(10, rightOp.getIntValue) + Assert.assertTrue(rightOp.getType.toString.equals("int")) + } + + if (rightOp.isLongConstant) { + constantCount += 1 + + Assert.assertEquals(1000, rightOp.getLongValue) + Assert.assertTrue(rightOp.getType.toString.equals("long")) + } + + if (rightOp.isStringConstant) { + constantCount += 1 + + Assert.assertTrue(rightOp.getStringValue.equals("test")) + Assert.assertTrue(rightOp.getType.toString.equals("java.lang.String")) + } + } + }) + + Assert.assertEquals(3, constantCount) + } + + @Test + def fieldStoreAssignmentTest(): Unit = { + val opalSetup = new OpalSetup() + opalSetup.setupOpal(classOf[AssignmentTarget].getName) + + val signature = new MethodSignature( + classOf[AssignmentTarget].getName, + "fieldStoreAssignment", + "Void" + ) + val method = opalSetup.resolveMethod(signature) + val opalMethod = OpalMethod(method) + + opalMethod.getStatements.forEach(stmt => { + if (stmt.isFieldStore) { + Assert.assertTrue(stmt.isAssignStmt) + + val leftOp = stmt.getLeftOp + val rightOp = stmt.getRightOp + + println() + } + }) + } } diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalControlFlowGraphTest.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalControlFlowGraphTest.scala index 2e828c9fd..fba8afb07 100644 --- a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalControlFlowGraphTest.scala +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalControlFlowGraphTest.scala @@ -1,32 +1,48 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ package boomerang.scope.opal import boomerang.scope.opal.tac.OpalMethod import boomerang.scope.test.MethodSignature import boomerang.scope.test.targets.ControlFlowGraphTarget -import org.junit.{Assert, Test} +import org.junit.Assert +import org.junit.Test import org.opalj.br.IntegerType class OpalControlFlowGraphTest { - private val integerType = IntegerType.toJVMTypeName - - @Test - def controlFlowGraphTest(): Unit = { - val opalSetup = new OpalSetup() - opalSetup.setupOpal(classOf[ControlFlowGraphTarget].getName) - - val signature = new MethodSignature(classOf[ControlFlowGraphTarget].getName, "compute", integerType) - val method = opalSetup.resolveMethod(signature) - val opalMethod = OpalMethod(method) - - val cfg = opalMethod.getControlFlowGraph - Assert.assertTrue(cfg.getStatements.size() > 0) - Assert.assertEquals(1, cfg.getStartPoints.size()) - Assert.assertEquals(2, cfg.getEndPoints.size()) - - cfg.getEndPoints.forEach(stmt => { - Assert.assertTrue(stmt.isReturnStmt) - }) - } + private val integerType = IntegerType.toJVMTypeName + + @Test + def controlFlowGraphTest(): Unit = { + val opalSetup = new OpalSetup() + opalSetup.setupOpal(classOf[ControlFlowGraphTarget].getName) + + val signature = new MethodSignature( + classOf[ControlFlowGraphTarget].getName, + "compute", + integerType + ) + val method = opalSetup.resolveMethod(signature) + val opalMethod = OpalMethod(method) + + val cfg = opalMethod.getControlFlowGraph + Assert.assertTrue(cfg.getStatements.size() > 0) + Assert.assertEquals(1, cfg.getStartPoints.size()) + Assert.assertEquals(2, cfg.getEndPoints.size()) + + cfg.getEndPoints.forEach(stmt => { + Assert.assertTrue(stmt.isReturnStmt) + }) + } } diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalFieldTest.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalFieldTest.scala index 4bfd93ded..73bd36aa9 100644 --- a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalFieldTest.scala +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalFieldTest.scala @@ -1,179 +1,239 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ package boomerang.scope.opal import boomerang.scope.opal.tac.OpalMethod import boomerang.scope.test.MethodSignature -import boomerang.scope.test.targets.{A, FieldClass, FieldTarget} -import org.junit.{Assert, Test} +import boomerang.scope.test.targets.A +import boomerang.scope.test.targets.FieldClass +import boomerang.scope.test.targets.FieldTarget +import org.junit.Assert +import org.junit.Test class OpalFieldTest { - @Test - def fieldLoadTest(): Unit = { - val opalSetup = new OpalSetup() - opalSetup.setupOpal(classOf[FieldTarget].getName) - - val signature = new MethodSignature(classOf[FieldTarget].getName, "fieldLoad", "Void") - val method = opalSetup.resolveMethod(signature) - val opalMethod = OpalMethod(method) - - var fieldLoadCount = 0 - opalMethod.getStatements.forEach(stmt => { - if (stmt.isFieldLoad) { - fieldLoadCount += 1 - - val field = stmt.getLoadedField - Assert.assertFalse(field.isPredefinedField) - Assert.assertFalse(field.isInnerClassField) - - val fieldLoad = stmt.getFieldLoad - val classType = fieldLoad.getX.getType.toString - Assert.assertTrue(classType.equals("int") || classType.equals(classOf[FieldClass].getName)) - - val fieldType = fieldLoad.getY.getType.toString - Assert.assertFalse(fieldLoad.getY.isPredefinedField) - Assert.assertTrue(fieldType.equals("int") || fieldType.equals(classOf[A].getName)) - } - }) - - Assert.assertEquals(2, fieldLoadCount) - } - - @Test - def fieldStoreTest(): Unit = { - val opalSetup = new OpalSetup() - opalSetup.setupOpal(classOf[FieldTarget].getName) - - val signature = new MethodSignature(classOf[FieldTarget].getName, "fieldStore", "Void") - val method = opalSetup.resolveMethod(signature) - val opalMethod = OpalMethod(method) - - var fieldStoreCount = 0 - opalMethod.getStatements.forEach(stmt => { - if (stmt.isFieldStore) { - fieldStoreCount += 1 - - val fieldStore = stmt.getFieldStore - val fieldClass = fieldStore.getX.getType.toString - Assert.assertTrue(fieldClass.equals("int") || fieldClass.equals(classOf[FieldClass].getName)) - - val fieldType = fieldStore.getY.getType.toString - Assert.assertFalse(fieldStore.getY.isPredefinedField) - Assert.assertFalse(fieldStore.getY.isInnerClassField) - Assert.assertTrue(fieldType.equals("int") || fieldType.equals(classOf[A].getName)) - } - }) - - Assert.assertEquals(2, fieldStoreCount) - } - - @Test - def staticFieldLoadTest(): Unit = { - val opalSetup = new OpalSetup() - opalSetup.setupOpal(classOf[FieldTarget].getName) - - val signature = new MethodSignature(classOf[FieldTarget].getName, "staticFieldLoad", "Void") - val method = opalSetup.resolveMethod(signature) - val opalMethod = OpalMethod(method) - - var staticFieldLoadCount = 0 - opalMethod.getStatements.forEach(stmt => { - if (stmt.isStaticFieldLoad) { - staticFieldLoadCount += 1 - - val staticField = stmt.getStaticField - Assert.assertFalse(staticField.field().isPredefinedField) - Assert.assertFalse(staticField.field().isInnerClassField) - - val typeName = staticField.getType.toString - Assert.assertTrue(typeName.equals("int") || typeName.equals(classOf[A].getName)) - } - }) - - Assert.assertEquals(2, staticFieldLoadCount) - } - - @Test - def staticFieldStoreTest(): Unit = { - val opalSetup = new OpalSetup() - opalSetup.setupOpal(classOf[FieldTarget].getName) - - val signature = new MethodSignature(classOf[FieldTarget].getName, "staticFieldStore", "Void") - val method = opalSetup.resolveMethod(signature) - val opalMethod = OpalMethod(method) - - var staticFieldStoreCount = 0 - opalMethod.getStatements.forEach(stmt => { - if (stmt.isStaticFieldStore) { - staticFieldStoreCount += 1 - - val staticField = stmt.getStaticField - Assert.assertFalse(staticField.field().isPredefinedField) - Assert.assertFalse(staticField.field().isInnerClassField) - - val typeName = staticField.getType.toString - Assert.assertTrue(typeName.equals("int") || typeName.equals(classOf[A].getName)) - } - }) - - Assert.assertEquals(2, staticFieldStoreCount) - } - - @Test - def innerFieldLoadTest(): Unit = { - val opalSetup = new OpalSetup() - opalSetup.setupOpal(classOf[FieldTarget].getName) - - val signature = new MethodSignature(classOf[FieldTarget].getName, "innerFieldLoad", "Void") - val method = opalSetup.resolveMethod(signature) - val opalMethod = OpalMethod(method) - - var fieldLoadCount = 0 - opalMethod.getStatements.forEach(stmt => { - if (stmt.isFieldLoad) { - fieldLoadCount += 1 - - val field = stmt.getLoadedField - Assert.assertFalse(field.isPredefinedField) - Assert.assertTrue(field.isInnerClassField) - - val fieldLoad = stmt.getFieldLoad - val classType = fieldLoad.getX.getType.toString - Assert.assertTrue(classType.equals("int") || classType.equals(classOf[FieldClass.InnerFieldClass].getName)) - - val fieldType = fieldLoad.getY.getType.toString - Assert.assertFalse(fieldLoad.getY.isPredefinedField) - Assert.assertTrue(fieldType.equals("int") || fieldType.equals(classOf[A].getName)) - } - }) - - Assert.assertEquals(2, fieldLoadCount) - } - - @Test - def innerFieldStoreTest(): Unit = { - val opalSetup = new OpalSetup() - opalSetup.setupOpal(classOf[FieldTarget].getName) - - val signature = new MethodSignature(classOf[FieldTarget].getName, "innerFieldStore", "Void") - val method = opalSetup.resolveMethod(signature) - val opalMethod = OpalMethod(method) - - var fieldStoreCount = 0 - opalMethod.getStatements.forEach(stmt => { - if (stmt.isFieldStore) { - fieldStoreCount += 1 - - val fieldStore = stmt.getFieldStore - val classType = fieldStore.getX.getType.toString - Assert.assertTrue(classType.equals("int") || classType.equals(classOf[FieldClass.InnerFieldClass].getName)) - - val fieldType = fieldStore.getY.getType.toString - Assert.assertFalse(fieldStore.getY.isPredefinedField) - Assert.assertTrue(fieldStore.getY.isInnerClassField) - Assert.assertTrue(fieldType.equals("int") || fieldType.equals(classOf[A].getName)) - } - }) - - Assert.assertEquals(2, fieldStoreCount) - } + @Test + def fieldLoadTest(): Unit = { + val opalSetup = new OpalSetup() + opalSetup.setupOpal(classOf[FieldTarget].getName) + + val signature = + new MethodSignature(classOf[FieldTarget].getName, "fieldLoad", "Void") + val method = opalSetup.resolveMethod(signature) + val opalMethod = OpalMethod(method) + + var fieldLoadCount = 0 + opalMethod.getStatements.forEach(stmt => { + if (stmt.isFieldLoad) { + fieldLoadCount += 1 + + val field = stmt.getLoadedField + Assert.assertFalse(field.isPredefinedField) + Assert.assertFalse(field.isInnerClassField) + + val fieldLoad = stmt.getFieldLoad + val classType = fieldLoad.getX.getType.toString + Assert.assertTrue( + classType.equals("int") || classType.equals( + classOf[FieldClass].getName + ) + ) + + val fieldType = fieldLoad.getY.getType.toString + Assert.assertFalse(fieldLoad.getY.isPredefinedField) + Assert.assertTrue( + fieldType.equals("int") || fieldType.equals(classOf[A].getName) + ) + } + }) + + Assert.assertEquals(2, fieldLoadCount) + } + + @Test + def fieldStoreTest(): Unit = { + val opalSetup = new OpalSetup() + opalSetup.setupOpal(classOf[FieldTarget].getName) + + val signature = + new MethodSignature(classOf[FieldTarget].getName, "fieldStore", "Void") + val method = opalSetup.resolveMethod(signature) + val opalMethod = OpalMethod(method) + + var fieldStoreCount = 0 + opalMethod.getStatements.forEach(stmt => { + if (stmt.isFieldStore) { + fieldStoreCount += 1 + + val fieldStore = stmt.getFieldStore + val fieldClass = fieldStore.getX.getType.toString + Assert.assertTrue( + fieldClass.equals("int") || fieldClass.equals( + classOf[FieldClass].getName + ) + ) + + val fieldType = fieldStore.getY.getType.toString + Assert.assertFalse(fieldStore.getY.isPredefinedField) + Assert.assertFalse(fieldStore.getY.isInnerClassField) + Assert.assertTrue( + fieldType.equals("int") || fieldType.equals(classOf[A].getName) + ) + } + }) + + Assert.assertEquals(2, fieldStoreCount) + } + + @Test + def staticFieldLoadTest(): Unit = { + val opalSetup = new OpalSetup() + opalSetup.setupOpal(classOf[FieldTarget].getName) + + val signature = new MethodSignature( + classOf[FieldTarget].getName, + "staticFieldLoad", + "Void" + ) + val method = opalSetup.resolveMethod(signature) + val opalMethod = OpalMethod(method) + + var staticFieldLoadCount = 0 + opalMethod.getStatements.forEach(stmt => { + if (stmt.isStaticFieldLoad) { + staticFieldLoadCount += 1 + + val staticField = stmt.getStaticField + Assert.assertFalse(staticField.field().isPredefinedField) + Assert.assertFalse(staticField.field().isInnerClassField) + + val typeName = staticField.getType.toString + Assert.assertTrue( + typeName.equals("int") || typeName.equals(classOf[A].getName) + ) + } + }) + + Assert.assertEquals(2, staticFieldLoadCount) + } + + @Test + def staticFieldStoreTest(): Unit = { + val opalSetup = new OpalSetup() + opalSetup.setupOpal(classOf[FieldTarget].getName) + + val signature = new MethodSignature( + classOf[FieldTarget].getName, + "staticFieldStore", + "Void" + ) + val method = opalSetup.resolveMethod(signature) + val opalMethod = OpalMethod(method) + + var staticFieldStoreCount = 0 + opalMethod.getStatements.forEach(stmt => { + if (stmt.isStaticFieldStore) { + staticFieldStoreCount += 1 + + val staticField = stmt.getStaticField + Assert.assertFalse(staticField.field().isPredefinedField) + Assert.assertFalse(staticField.field().isInnerClassField) + + val typeName = staticField.getType.toString + Assert.assertTrue( + typeName.equals("int") || typeName.equals(classOf[A].getName) + ) + } + }) + + Assert.assertEquals(2, staticFieldStoreCount) + } + + @Test + def innerFieldLoadTest(): Unit = { + val opalSetup = new OpalSetup() + opalSetup.setupOpal(classOf[FieldTarget].getName) + + val signature = new MethodSignature( + classOf[FieldTarget].getName, + "innerFieldLoad", + "Void" + ) + val method = opalSetup.resolveMethod(signature) + val opalMethod = OpalMethod(method) + + var fieldLoadCount = 0 + opalMethod.getStatements.forEach(stmt => { + if (stmt.isFieldLoad) { + fieldLoadCount += 1 + + val field = stmt.getLoadedField + Assert.assertFalse(field.isPredefinedField) + Assert.assertTrue(field.isInnerClassField) + + val fieldLoad = stmt.getFieldLoad + val classType = fieldLoad.getX.getType.toString + Assert.assertTrue( + classType.equals("int") || classType.equals( + classOf[FieldClass.InnerFieldClass].getName + ) + ) + + val fieldType = fieldLoad.getY.getType.toString + Assert.assertFalse(fieldLoad.getY.isPredefinedField) + Assert.assertTrue( + fieldType.equals("int") || fieldType.equals(classOf[A].getName) + ) + } + }) + + Assert.assertEquals(2, fieldLoadCount) + } + + @Test + def innerFieldStoreTest(): Unit = { + val opalSetup = new OpalSetup() + opalSetup.setupOpal(classOf[FieldTarget].getName) + + val signature = new MethodSignature( + classOf[FieldTarget].getName, + "innerFieldStore", + "Void" + ) + val method = opalSetup.resolveMethod(signature) + val opalMethod = OpalMethod(method) + + var fieldStoreCount = 0 + opalMethod.getStatements.forEach(stmt => { + if (stmt.isFieldStore) { + fieldStoreCount += 1 + + val fieldStore = stmt.getFieldStore + val classType = fieldStore.getX.getType.toString + Assert.assertTrue( + classType.equals("int") || classType.equals( + classOf[FieldClass.InnerFieldClass].getName + ) + ) + + val fieldType = fieldStore.getY.getType.toString + Assert.assertFalse(fieldStore.getY.isPredefinedField) + Assert.assertTrue(fieldStore.getY.isInnerClassField) + Assert.assertTrue( + fieldType.equals("int") || fieldType.equals(classOf[A].getName) + ) + } + }) + + Assert.assertEquals(2, fieldStoreCount) + } } diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala index b8de09a30..58a4d855b 100644 --- a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala @@ -1,74 +1,110 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ package boomerang.scope.opal import boomerang.scope.DataFlowScope import boomerang.scope.opal.tac.OpalMethod import boomerang.scope.test.MethodSignature -import boomerang.scope.test.targets.{BranchingTarget, InvokeExprTarget, SingleTarget} +import boomerang.scope.test.targets.BranchingTarget +import boomerang.scope.test.targets.InvokeExprTarget +import boomerang.scope.test.targets.SingleTarget import com.typesafe.config.ConfigValueFactory -import org.junit.{Assert, Test} +import java.util +import org.junit.Assert +import org.junit.Test import org.opalj.br.analyses.Project import org.opalj.br.analyses.cg.InitialEntryPointsKey -import org.opalj.tac.cg.{CHACallGraphKey, CallGraph} - -import java.util +import org.opalj.tac.cg.CallGraph +import org.opalj.tac.cg.CHACallGraphKey import scala.jdk.javaapi.CollectionConverters class OpalInvokeExprTest { - @Test - def instanceInvokeExprTest(): Unit = { - val opalSetup = new OpalSetup() - opalSetup.setupOpal(classOf[SingleTarget].getName) - - val signature = new MethodSignature(classOf[SingleTarget].getName, "getAndSetField", "V") - val method = opalSetup.resolveMethod(signature) - val opalMethod = OpalMethod(method) - opalMethod.getControlFlowGraph - - // Update the project's config to set the test method as the (single) entry point. See - // https://github.com/opalj/opal/blob/ff01c1c9e696946a88b090a52881a41445cf07f1/DEVELOPING_OPAL/tools/src/main/scala/org/opalj/support/info/CallGraph.scala#L406 - var config = OpalClient.project.get.config - - val key = InitialEntryPointsKey.ConfigKeyPrefix + "entryPoints" - val currentValues = config.getList(key).unwrapped - - val configValue = new util.HashMap[String, String] - configValue.put("declaringClass", method.classFile.thisType.toJava.replace(".", "/")) - configValue.put("name", method.name) - - currentValues.add(ConfigValueFactory.fromMap(configValue)) - config = config.withValue(key, ConfigValueFactory.fromIterable(currentValues)) - config = config.withValue(InitialEntryPointsKey.ConfigKeyPrefix + "analysis", ConfigValueFactory.fromAnyRef("org.opalj.br.analyses.cg.ConfigurationEntryPointsFinder")) - val project = Project.recreate(OpalClient.project.get, config, useOldConfigAsFallback = true) - - val callGraph: CallGraph = project.get(CHACallGraphKey) - val scope = new OpalFrameworkScope(project, callGraph, CollectionConverters.asScala(util.Set.of(method)).toSet, DataFlowScope.EXCLUDE_PHANTOM_CLASSES) - - println(opalMethod.tac.statements.mkString("Array(\n\t", "\n\t", "\n)")) - } - - @Test - def staticInvokeExprTest(): Unit = { - val opalSetup = new OpalSetup() - opalSetup.setupOpal(classOf[InvokeExprTarget].getName) - - val signature = new MethodSignature(classOf[InvokeExprTarget].getName, "staticInvokeExpr", "V") - val method = opalSetup.resolveMethod(signature) - val opalMethod = OpalMethod(method) - - var checked = false - opalMethod.getStatements.forEach(stmt => { - if (stmt.containsInvokeExpr()) { - val invokeExpr = stmt.getInvokeExpr - - Assert.assertTrue(invokeExpr.isStaticInvokeExpr) - Assert.assertEquals(2, invokeExpr.getArgs.size()) - - checked = true - } - }) - - Assert.assertTrue(checked) - } + @Test + def instanceInvokeExprTest(): Unit = { + val opalSetup = new OpalSetup() + opalSetup.setupOpal(classOf[SingleTarget].getName) + + val signature = + new MethodSignature(classOf[SingleTarget].getName, "getAndSetField", "V") + val method = opalSetup.resolveMethod(signature) + val opalMethod = OpalMethod(method) + opalMethod.getControlFlowGraph + + // Update the project's config to set the test method as the (single) entry point. See + // https://github.com/opalj/opal/blob/ff01c1c9e696946a88b090a52881a41445cf07f1/DEVELOPING_OPAL/tools/src/main/scala/org/opalj/support/info/CallGraph.scala#L406 + var config = OpalClient.project.get.config + + val key = InitialEntryPointsKey.ConfigKeyPrefix + "entryPoints" + val currentValues = config.getList(key).unwrapped + + val configValue = new util.HashMap[String, String] + configValue.put( + "declaringClass", + method.classFile.thisType.toJava.replace(".", "/") + ) + configValue.put("name", method.name) + + currentValues.add(ConfigValueFactory.fromMap(configValue)) + config = config.withValue(key, ConfigValueFactory.fromIterable(currentValues)) + config = config.withValue( + InitialEntryPointsKey.ConfigKeyPrefix + "analysis", + ConfigValueFactory.fromAnyRef( + "org.opalj.br.analyses.cg.ConfigurationEntryPointsFinder" + ) + ) + val project = Project.recreate( + OpalClient.project.get, + config, + useOldConfigAsFallback = true + ) + + val callGraph: CallGraph = project.get(CHACallGraphKey) + val scope = new OpalFrameworkScope( + project, + callGraph, + CollectionConverters.asScala(util.Set.of(method)).toSet, + DataFlowScope.EXCLUDE_PHANTOM_CLASSES + ) + + println(opalMethod.tac.statements.mkString("Array(\n\t", "\n\t", "\n)")) + } + + @Test + def staticInvokeExprTest(): Unit = { + val opalSetup = new OpalSetup() + opalSetup.setupOpal(classOf[InvokeExprTarget].getName) + + val signature = new MethodSignature( + classOf[InvokeExprTarget].getName, + "staticInvokeExpr", + "V" + ) + val method = opalSetup.resolveMethod(signature) + val opalMethod = OpalMethod(method) + + var checked = false + opalMethod.getStatements.forEach(stmt => { + if (stmt.containsInvokeExpr()) { + val invokeExpr = stmt.getInvokeExpr + + Assert.assertTrue(invokeExpr.isStaticInvokeExpr) + Assert.assertEquals(2, invokeExpr.getArgs.size()) + + checked = true + } + }) + + Assert.assertTrue(checked) + } } diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalLocalTest.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalLocalTest.scala index 320edca2e..92dbff914 100644 --- a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalLocalTest.scala +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalLocalTest.scala @@ -1,70 +1,110 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ package boomerang.scope.opal import boomerang.scope.opal.tac.OpalMethod import boomerang.scope.test.MethodSignature -import boomerang.scope.test.targets.{A, ParameterLocalsTarget, ThisLocalTarget} -import org.junit.{Assert, Test} -import org.opalj.br.IntegerType - +import boomerang.scope.test.targets.A +import boomerang.scope.test.targets.ParameterLocalsTarget +import boomerang.scope.test.targets.ThisLocalTarget import java.util +import org.junit.Assert +import org.junit.Test +import org.opalj.br.IntegerType class OpalLocalTest { - private val integerType = IntegerType.toJVMTypeName - - @Test - def thisLocalTest(): Unit = { - val opalSetup = new OpalSetup() - opalSetup.setupOpal(classOf[ThisLocalTarget].getName) - - val signature = new MethodSignature(classOf[ThisLocalTarget].getName, "call", "Void") - val method = opalSetup.resolveMethod(signature) - val opalMethod = OpalMethod(method) - - var checked = false - opalMethod.getStatements.forEach(stmt => { - if (stmt.containsInvokeExpr() && stmt.getInvokeExpr.getDeclaredMethod.getName.equals("callWithThis")) { - val invokeExpr = stmt.getInvokeExpr - val base = invokeExpr.getBase - - Assert.assertTrue(opalMethod.getThisLocal.equals(base)) - Assert.assertTrue(base.equals(opalMethod.getThisLocal)) - Assert.assertTrue(opalMethod.isThisLocal(base)) - - checked = true - } - }) - - Assert.assertTrue(checked) - } - - @Test - def parameterLocalTest(): Unit = { - val opalSetup = new OpalSetup() - opalSetup.setupOpal(classOf[ParameterLocalsTarget].getName) - - // No parameters - val noArgsSignature = new MethodSignature(classOf[ParameterLocalsTarget].getName, "noParameters", "Void") - val noArgs = opalSetup.resolveMethod(noArgsSignature) - val noArgsMethod = OpalMethod(noArgs) - - Assert.assertTrue(noArgsMethod.getParameterLocals.isEmpty) - - // One parameter (primitive type) - val oneArgSignature = new MethodSignature(classOf[ParameterLocalsTarget].getName, "oneParameter", "Void", util.List.of(integerType)) - val oneArg = opalSetup.resolveMethod(oneArgSignature) - val oneArgMethod = OpalMethod(oneArg) - - Assert.assertEquals(1, oneArgMethod.getParameterLocals.size) - Assert.assertEquals("int", oneArgMethod.getParameterLocal(0).getType.toString) - - // Two parameters (primitive type + RefType) - val twoArgSignature = new MethodSignature(classOf[ParameterLocalsTarget].getName, "twoParameters", "Void", util.List.of(integerType, s"L${classOf[A].getName}L")) - val twoArgs = opalSetup.resolveMethod(twoArgSignature) - val twoArgsMethod = OpalMethod(twoArgs) - - Assert.assertEquals(2, twoArgsMethod.getParameterLocals.size) - Assert.assertEquals("int", twoArgsMethod.getParameterLocal(0).getType.toString) - Assert.assertEquals(classOf[A].getName, twoArgsMethod.getParameterLocal(1).getType.toString) - } + private val integerType = IntegerType.toJVMTypeName + + @Test + def thisLocalTest(): Unit = { + val opalSetup = new OpalSetup() + opalSetup.setupOpal(classOf[ThisLocalTarget].getName) + + val signature = + new MethodSignature(classOf[ThisLocalTarget].getName, "call", "Void") + val method = opalSetup.resolveMethod(signature) + val opalMethod = OpalMethod(method) + + var checked = false + opalMethod.getStatements.forEach(stmt => { + if (stmt + .containsInvokeExpr() && stmt.getInvokeExpr.getDeclaredMethod.getName + .equals("callWithThis") + ) { + val invokeExpr = stmt.getInvokeExpr + val base = invokeExpr.getBase + + Assert.assertTrue(opalMethod.getThisLocal.equals(base)) + Assert.assertTrue(base.equals(opalMethod.getThisLocal)) + Assert.assertTrue(opalMethod.isThisLocal(base)) + + checked = true + } + }) + + Assert.assertTrue(checked) + } + + @Test + def parameterLocalTest(): Unit = { + val opalSetup = new OpalSetup() + opalSetup.setupOpal(classOf[ParameterLocalsTarget].getName) + + // No parameters + val noArgsSignature = new MethodSignature( + classOf[ParameterLocalsTarget].getName, + "noParameters", + "Void" + ) + val noArgs = opalSetup.resolveMethod(noArgsSignature) + val noArgsMethod = OpalMethod(noArgs) + + Assert.assertTrue(noArgsMethod.getParameterLocals.isEmpty) + + // One parameter (primitive type) + val oneArgSignature = new MethodSignature( + classOf[ParameterLocalsTarget].getName, + "oneParameter", + "Void", + util.List.of(integerType) + ) + val oneArg = opalSetup.resolveMethod(oneArgSignature) + val oneArgMethod = OpalMethod(oneArg) + + Assert.assertEquals(1, oneArgMethod.getParameterLocals.size) + Assert.assertEquals( + "int", + oneArgMethod.getParameterLocal(0).getType.toString + ) + + // Two parameters (primitive type + RefType) + val twoArgSignature = new MethodSignature( + classOf[ParameterLocalsTarget].getName, + "twoParameters", + "Void", + util.List.of(integerType, s"L${classOf[A].getName}L") + ) + val twoArgs = opalSetup.resolveMethod(twoArgSignature) + val twoArgsMethod = OpalMethod(twoArgs) + + Assert.assertEquals(2, twoArgsMethod.getParameterLocals.size) + Assert.assertEquals( + "int", + twoArgsMethod.getParameterLocal(0).getType.toString + ) + Assert.assertEquals( + classOf[A].getName, + twoArgsMethod.getParameterLocal(1).getType.toString + ) + } } diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalSetup.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalSetup.scala index ecb0a6885..c4a0b8b87 100644 --- a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalSetup.scala +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalSetup.scala @@ -1,37 +1,56 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ package boomerang.scope.opal -import boomerang.scope.test.{MethodSignature, TargetClassPath} -import org.opalj.br.analyses.Project -import org.opalj.br._ -import org.opalj.log.{DevNullLogger, GlobalLogContext, OPALLogger} - +import boomerang.scope.test.MethodSignature +import boomerang.scope.test.TargetClassPath import java.io.File +import org.opalj.br._ +import org.opalj.br.analyses.Project +import org.opalj.log.DevNullLogger +import org.opalj.log.GlobalLogContext +import org.opalj.log.OPALLogger import scala.collection.immutable.ArraySeq class OpalSetup { - var targetClass: Option[ClassFile] = None - - def setupOpal(targetClassName: String): Unit = { - OPALLogger.updateLogger(GlobalLogContext, DevNullLogger) - val project = Project(new File(TargetClassPath.TARGET_CLASS_PATH)) + var targetClass: Option[ClassFile] = None - OpalClient.init(project) - targetClass = project.classFile(ObjectType(targetClassName.replace(".", "/"))) - } + def setupOpal(targetClassName: String): Unit = { + OPALLogger.updateLogger(GlobalLogContext, DevNullLogger) + val project = Project(new File(TargetClassPath.TARGET_CLASS_PATH)) - def resolveMethod(methodSignature: MethodSignature): Method = { - val parameterFields = ArraySeq.from(methodSignature.getParameters.toArray.collect({ - case p: String => FieldType(p.replace(".", "/")) - case _ => throw new IllegalArgumentException("No String") - })) - val returnType = ReturnType(methodSignature.getReturnType) - - val method = targetClass.get.findMethod(methodSignature.getMethodName, MethodDescriptor(parameterFields, returnType)) - if (method.isEmpty) { - throw new RuntimeException("Could not find method " + methodSignature.getMethodName + " in class " + methodSignature.getDeclaringClass) + OpalClient.init(project) + targetClass = project.classFile(ObjectType(targetClassName.replace(".", "/"))) } - method.get - } + def resolveMethod(methodSignature: MethodSignature): Method = { + val parameterFields = + ArraySeq.from(methodSignature.getParameters.toArray.collect({ + case p: String => FieldType(p.replace(".", "/")) + case _ => throw new IllegalArgumentException("No String") + })) + val returnType = ReturnType(methodSignature.getReturnType) + + val method = targetClass.get.findMethod( + methodSignature.getMethodName, + MethodDescriptor(parameterFields, returnType) + ) + if (method.isEmpty) { + throw new RuntimeException( + "Could not find method " + methodSignature.getMethodName + " in class " + methodSignature.getDeclaringClass + ) + } + + method.get + } } diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/TacBodyBuilderTest.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/TacBodyBuilderTest.scala index a66f9b1ff..71758a1fa 100644 --- a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/TacBodyBuilderTest.scala +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/TacBodyBuilderTest.scala @@ -1,86 +1,110 @@ +/** + * ***************************************************************************** + * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the + * accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. + * + *

    SPDX-License-Identifier: EPL-2.0 + * + *

    Contributors: Johannes Spaeth - initial API and implementation + * ***************************************************************************** + */ package boomerang.scope.opal import boomerang.scope.opal.transformation.TacBodyBuilder +import java.io.File +import java.net.URI +import java.nio.file.Files +import java.nio.file.FileSystems +import java.nio.file.Paths +import java.nio.file.StandardCopyOption import org.junit.Test import org.opalj.br.Method import org.opalj.br.analyses.Project -import org.opalj.log.{DevNullLogger, GlobalLogContext, OPALLogger} - -import java.io.File -import java.net.URI -import java.nio.file.{FileSystems, Files, Paths, StandardCopyOption} +import org.opalj.log.DevNullLogger +import org.opalj.log.GlobalLogContext +import org.opalj.log.OPALLogger import scala.collection.mutable.ArrayBuffer import scala.jdk.CollectionConverters._ class TacBodyBuilderTest { - @Test - def applyTacBodyBuilderTest(): Unit = { - OPALLogger.updateLogger(GlobalLogContext, DevNullLogger) - val jdkFiles = loadJDKFiles() - - val project = Project(jdkFiles, Array.empty[File]) - project.allProjectClassFiles.foreach(cf => { - cf.methods.foreach(method => { - if (!isOnIgnoreList(method)) { - TacBodyBuilder(project, method) - } - }) - }) - } - - def isOnIgnoreList(method: Method): Boolean = { - // No existing body -> No transformation possible - if (method.body.isEmpty) return true - - // Consider only java.lang package classes to reduce the number of classes - // TODO - // Maybe create additional tests for other packages (java.io, java.util) that run in parallel. - // Running them sequential would take too long - if (!method.toJava.startsWith("java.lang.")) return true - - // Static initializers may be very complex and take some time to compute (e.g. com.sun.crypto.provider.AESCrypt) - if (method.isStaticInitializer) return true - - // Bug in Opal causes an exception - if (method.toJava.equals("java.lang.Thread{ private static long nextThreadID() }")) return true - if (method.toJava.equals("java.util.concurrent.CompletableFuture$Signaller{ public boolean isReleasable() }")) return true - - false - } - - def loadJDKFiles(): Array[File] = { - val javaHome = sys.env("JAVA_HOME") - val jmodPath = Paths.get(javaHome, "jmods", "java.base.jmod") - - val outputDir = Paths.get("extracted_classes") - Files.createDirectories(outputDir) - - val classFiles = ArrayBuffer[File]() - - // Open the .jmod file as a zip filesystem - val uri = URI.create(s"jar:${jmodPath.toUri}") - val env = Map("create" -> "false").asJava - - val fs = FileSystems.newFileSystem(uri, env) - val rootPath = fs.getPath("/classes") - - // Walk the file tree inside the jmod's /classes directory - Files.walk(rootPath).iterator().asScala - .filter(p => Files.isRegularFile(p) && p.toString.endsWith(".class")) - .foreach { classPath => - val relativePath = rootPath.relativize(classPath) - val targetPath = outputDir.resolve(relativePath.toString) - - Files.createDirectories(targetPath.getParent) - Files.copy(classPath, targetPath, StandardCopyOption.REPLACE_EXISTING) - - classFiles += targetPath.toFile - } - - fs.close() - - classFiles.toArray - } + @Test + def applyTacBodyBuilderTest(): Unit = { + OPALLogger.updateLogger(GlobalLogContext, DevNullLogger) + val jdkFiles = loadJDKFiles() + + val project = Project(jdkFiles, Array.empty[File]) + project.allProjectClassFiles.foreach(cf => { + cf.methods.foreach(method => { + if (!isOnIgnoreList(method)) { + TacBodyBuilder(project, method) + } + }) + }) + } + + def isOnIgnoreList(method: Method): Boolean = { + // No existing body -> No transformation possible + if (method.body.isEmpty) return true + + // Consider only java.lang package classes to reduce the number of classes + // TODO + // Maybe create additional tests for other packages (java.io, java.util) that run in parallel. + // Running them sequential would take too long + if (!method.toJava.startsWith("java.lang.")) return true + + // Static initializers may be very complex and take some time to compute (e.g. com.sun.crypto.provider.AESCrypt) + if (method.isStaticInitializer) return true + + // Bug in Opal causes an exception + if (method.toJava.equals( + "java.lang.Thread{ private static long nextThreadID() }" + ) + ) return true + if (method.toJava.equals( + "java.util.concurrent.CompletableFuture$Signaller{ public boolean isReleasable() }" + ) + ) return true + + false + } + + def loadJDKFiles(): Array[File] = { + val javaHome = sys.env("JAVA_HOME") + val jmodPath = Paths.get(javaHome, "jmods", "java.base.jmod") + + val outputDir = Paths.get("extracted_classes") + Files.createDirectories(outputDir) + + val classFiles = ArrayBuffer[File]() + + // Open the .jmod file as a zip filesystem + val uri = URI.create(s"jar:${jmodPath.toUri}") + val env = Map("create" -> "false").asJava + + val fs = FileSystems.newFileSystem(uri, env) + val rootPath = fs.getPath("/classes") + + // Walk the file tree inside the jmod's /classes directory + Files + .walk(rootPath) + .iterator() + .asScala + .filter(p => Files.isRegularFile(p) && p.toString.endsWith(".class")) + .foreach { classPath => + val relativePath = rootPath.relativize(classPath) + val targetPath = outputDir.resolve(relativePath.toString) + + Files.createDirectories(targetPath.getParent) + Files.copy(classPath, targetPath, StandardCopyOption.REPLACE_EXISTING) + + classFiles += targetPath.toFile + } + + fs.close() + + classFiles.toArray + } } diff --git a/misc/.scalafmt.conf b/misc/.scalafmt.conf new file mode 100644 index 000000000..7c03480dd --- /dev/null +++ b/misc/.scalafmt.conf @@ -0,0 +1,46 @@ +# Inspired by https://github.com/opalj/opal/blob/develop/.scalafmt.conf +version = 3.8.1 + +project.git = true +maxColumn = 120 +encoding = UTF-8 +runner.dialect = scala213 + +docstrings { + style = Asterisk + forceBlankLineBefore = false + wrap = false +} + +indent { + main = 4 + callSite = 4 +} +indentOperator.exemptScope = aloneEnclosed + +rewrite { + rules = [ + SortModifiers, + Imports + ] + + sortModifiers.order = [ + "sealed", "abstract", "override", + "private", "protected", + "implicit", "final", "lazy" + ] + + imports { + expand = true + sort = scalastyle + } +} + +align { + preset = none + allowOverflow = true + openParenCtrlSite = true + multiline = false + inInterpolation = false +} + diff --git a/pom.xml b/pom.xml index 1d1d5ea99..901cdcae0 100644 --- a/pom.xml +++ b/pom.xml @@ -213,6 +213,14 @@ ${license.dir}/license_header.txt + + + ${license.dir}/misc/.scalafmt.conf + + + ${license.dir}/license_header.txt + + From 5b654a0d3028591a2773f9def3baf78743324bc0 Mon Sep 17 00:00:00 2001 From: Sven Meyer Date: Thu, 24 Apr 2025 13:25:06 +0200 Subject: [PATCH 60/61] Update license headers to correct format See https://www.eclipse.org/projects/handbook/#ip-copyright-headers --- .../main/java/de/fraunhofer/iem/Empty.java | 17 +++--- .../main/java/de/fraunhofer/iem/Location.java | 17 +++--- .../iem/wildcard/ExclusionWildcard.java | 17 +++--- .../de/fraunhofer/iem/wildcard/Wildcard.java | 17 +++--- .../java/sync/pds/solver/CastNormalRule.java | 17 +++--- .../pds/solver/EmptyStackWitnessListener.java | 17 +++--- .../sync/pds/solver/OneWeightFunctions.java | 17 +++--- .../java/sync/pds/solver/SyncPDSSolver.java | 17 +++--- .../pds/solver/SyncPDSUpdateListener.java | 17 +++--- .../solver/SyncStatePDSUpdateListener.java | 17 +++--- .../java/sync/pds/solver/WeightFunctions.java | 17 +++--- .../java/sync/pds/solver/WitnessListener.java | 17 +++--- .../sync/pds/solver/nodes/CallPopNode.java | 17 +++--- .../sync/pds/solver/nodes/ExclusionNode.java | 17 +++--- .../sync/pds/solver/nodes/GeneratedState.java | 17 +++--- .../java/sync/pds/solver/nodes/INode.java | 17 +++--- .../main/java/sync/pds/solver/nodes/Node.java | 17 +++--- .../pds/solver/nodes/NodeWithLocation.java | 17 +++--- .../java/sync/pds/solver/nodes/PopNode.java | 17 +++--- .../java/sync/pds/solver/nodes/PushNode.java | 17 +++--- .../sync/pds/solver/nodes/SingleNode.java | 17 +++--- .../main/java/sync/pds/weights/SetDomain.java | 17 +++--- .../java/sync/pds/weights/SetDomainImpl.java | 17 +++--- .../java/sync/pds/weights/SetDomainOne.java | 17 +++--- .../java/sync/pds/weights/SetDomainZero.java | 17 +++--- .../java/analysis/test/DoublePDSTest.java | 17 +++--- WPDS/src/main/java/wpds/debug/Debugger.java | 17 +++--- .../main/java/wpds/impl/Configuration.java | 17 +++--- .../java/wpds/impl/ConnectPushListener.java | 17 +++--- .../wpds/impl/NestedAutomatonListener.java | 17 +++--- .../wpds/impl/NestedWeightedPAutomatons.java | 17 +++--- WPDS/src/main/java/wpds/impl/NoWeight.java | 17 +++--- WPDS/src/main/java/wpds/impl/NormalRule.java | 17 +++--- WPDS/src/main/java/wpds/impl/PAutomaton.java | 17 +++--- WPDS/src/main/java/wpds/impl/PopRule.java | 17 +++--- WPDS/src/main/java/wpds/impl/PostStar.java | 17 +++--- WPDS/src/main/java/wpds/impl/PreStar.java | 17 +++--- .../src/main/java/wpds/impl/PrefixImport.java | 17 +++--- WPDS/src/main/java/wpds/impl/PushRule.java | 17 +++--- .../main/java/wpds/impl/PushdownSystem.java | 17 +++--- WPDS/src/main/java/wpds/impl/Rule.java | 17 +++--- .../main/java/wpds/impl/StackListener.java | 17 +++--- .../SummaryNestedWeightedPAutomatons.java | 17 +++--- WPDS/src/main/java/wpds/impl/Transition.java | 17 +++--- WPDS/src/main/java/wpds/impl/UNormalRule.java | 17 +++--- WPDS/src/main/java/wpds/impl/UPopRule.java | 17 +++--- WPDS/src/main/java/wpds/impl/UPushRule.java | 17 +++--- .../java/wpds/impl/UnbalancedPopListener.java | 17 +++--- WPDS/src/main/java/wpds/impl/Weight.java | 17 +++--- .../java/wpds/impl/WeightedPAutomaton.java | 17 +++--- .../wpds/impl/WeightedPushdownSystem.java | 17 +++--- .../interfaces/ForwardDFSEpsilonVisitor.java | 17 +++--- .../wpds/interfaces/ForwardDFSVisitor.java | 17 +++--- .../java/wpds/interfaces/IPushdownSystem.java | 17 +++--- .../wpds/interfaces/ReachabilityListener.java | 17 +++--- WPDS/src/main/java/wpds/interfaces/State.java | 17 +++--- .../wpds/interfaces/WPAStateListener.java | 17 +++--- .../wpds/interfaces/WPAUpdateListener.java | 17 +++--- .../wpds/interfaces/WPDSUpdateListener.java | 17 +++--- .../wpds/wildcard/WildcardPushdownSystem.java | 17 +++--- .../java/tests/ForwardDFSVisitorTest.java | 17 +++--- .../java/tests/MinSeminringPostStarTests.java | 17 +++--- WPDS/src/test/java/tests/MinSemiring.java | 17 +++--- WPDS/src/test/java/tests/NumWeight.java | 17 +++--- WPDS/src/test/java/tests/NumWeightImpl.java | 17 +++--- WPDS/src/test/java/tests/NumWeightOne.java | 17 +++--- WPDS/src/test/java/tests/NumWeightZero.java | 17 +++--- .../src/test/java/tests/PDSPoststarTests.java | 17 +++--- WPDS/src/test/java/tests/PDSPrestarTests.java | 17 +++--- .../test/java/tests/PrefixImportTests.java | 17 +++--- .../java/tests/SummaryPDSPostStarTests.java | 17 +++--- WPDS/src/test/java/tests/TestHelper.java | 17 +++--- .../test/java/tests/WPDSPostStarTests.java | 17 +++--- .../src/test/java/tests/WPDSPreStarTests.java | 17 +++--- .../main/java/boomerang/BackwardQuery.java | 17 +++--- .../src/main/java/boomerang/Boomerang.java | 17 +++--- .../boomerang/BoomerangTimeoutException.java | 17 +++--- .../src/main/java/boomerang/Context.java | 17 +++--- .../src/main/java/boomerang/ForwardQuery.java | 17 +++--- .../java/boomerang/ForwardQueryArray.java | 17 +++--- .../ForwardQueryMultiDimensionalArray.java | 17 +++--- .../java/boomerang/IContextRequester.java | 17 +++--- .../java/boomerang/MethodReachableQueue.java | 17 +++--- .../src/main/java/boomerang/Query.java | 17 +++--- .../src/main/java/boomerang/QueryGraph.java | 17 +++--- .../boomerang/SolverCreationListener.java | 17 +++--- .../src/main/java/boomerang/Util.java | 17 +++--- .../java/boomerang/WeightedBoomerang.java | 17 +++--- .../java/boomerang/WeightedForwardQuery.java | 17 +++--- .../java/boomerang/WholeProgramBoomerang.java | 17 +++--- .../arrays/ArrayHandlingStrategy.java | 17 +++--- .../arrays/ArrayIndexInsensitiveStrategy.java | 17 +++--- .../arrays/ArrayIndexSensitiveStrategy.java | 17 +++--- .../boomerang/arrays/IgnoreArrayStrategy.java | 17 +++--- .../callgraph/BackwardsObservableICFG.java | 17 +++--- .../callgraph/BoomerangResolver.java | 17 +++--- .../boomerang/callgraph/CallGraphOptions.java | 17 +++--- .../boomerang/callgraph/CalleeListener.java | 17 +++--- .../boomerang/callgraph/CallerListener.java | 17 +++--- .../ICallerCalleeResolutionStrategy.java | 17 +++--- .../callgraph/ObservableDynamicICFG.java | 17 +++--- .../boomerang/callgraph/ObservableICFG.java | 17 +++--- .../callgraph/ObservableStaticICFG.java | 17 +++--- .../controlflowgraph/DynamicCFG.java | 17 +++--- .../ForwardSolverSuccessorListener.java | 17 +++--- .../ObservableControlFlowGraph.java | 17 +++--- .../controlflowgraph/PredecessorListener.java | 17 +++--- .../boomerang/controlflowgraph/StaticCFG.java | 17 +++--- .../controlflowgraph/SuccessorListener.java | 17 +++--- .../boomerang/debugger/CallGraphDebugger.java | 17 +++--- .../boomerang/debugger/ConsoleDebugger.java | 17 +++--- .../java/boomerang/debugger/Debugger.java | 17 +++--- .../boomerang/debugger/IDEVizDebugger.java | 17 +++--- .../example/BoomerangExampleTarget1.java | 17 +++--- .../example/BoomerangExampleTarget2.java | 17 +++--- .../DefaultBackwardFlowFunction.java | 17 +++--- .../DefaultBackwardFlowFunctionOptions.java | 17 +++--- .../DefaultForwardFlowFunction.java | 17 +++--- .../DefaultForwardFlowFunctionOptions.java | 17 +++--- .../flowfunction/FlowFunctionUtils.java | 17 +++--- .../flowfunction/IBackwardFlowFunction.java | 17 +++--- .../flowfunction/IForwardFlowFunction.java | 17 +++--- .../guided/DemandDrivenGuidedAnalysis.java | 17 +++--- .../guided/IDemandDrivenGuidedManager.java | 17 +++--- .../SimpleSpecificationGuidedManager.java | 17 +++--- .../java/boomerang/guided/Specification.java | 17 +++--- .../boomerang/options/BoomerangOptions.java | 17 +++--- .../options/DefaultAllocationSite.java | 17 +++--- .../boomerang/options/IAllocationSite.java | 17 +++--- .../options/IntAndStringAllocationSite.java | 17 +++--- .../main/java/boomerang/poi/AbstractPOI.java | 17 +++--- .../boomerang/poi/CopyAccessPathChain.java | 17 +++--- .../poi/ExecuteImportFieldStmtPOI.java | 17 +++--- .../boomerang/poi/PointOfIndirection.java | 17 +++--- .../results/AbstractBoomerangResults.java | 17 +++--- .../boomerang/results/AffectedLocation.java | 17 +++--- .../results/BackwardBoomerangResults.java | 17 +++--- .../results/ExtractAllAliasListener.java | 17 +++--- .../ExtractAllocationSiteStateListener.java | 17 +++--- .../results/ForwardBoomerangResults.java | 17 +++--- .../results/NullPointerDereference.java | 17 +++--- .../java/boomerang/results/PathElement.java | 17 +++--- .../java/boomerang/results/QueryResults.java | 17 +++--- .../boomerang/scope/AccessPathParser.java | 17 +++--- .../java/boomerang/scope/AnalysisScope.java | 17 +++--- .../solver/AbstractBoomerangSolver.java | 17 +++--- .../solver/AllocationTypeListener.java | 17 +++--- .../solver/BackwardBoomerangSolver.java | 17 +++--- ...olFlowEdgeBasedCallTransitionListener.java | 17 +++--- ...lFlowEdgeBasedFieldTransitionListener.java | 17 +++--- .../solver/ForwardBoomerangSolver.java | 17 +++--- .../MethodBasedFieldTransitionListener.java | 17 +++--- .../solver/ReachableMethodListener.java | 17 +++--- .../java/boomerang/solver/Strategies.java | 17 +++--- .../FlowSensitiveStaticFieldStrategy.java | 17 +++--- .../IgnoreStaticFieldStrategy.java | 17 +++--- .../SingletonStaticFieldStrategy.java | 17 +++--- .../StaticFieldHandlingStrategy.java | 17 +++--- .../stats/AdvancedBoomerangStats.java | 17 +++--- .../stats/CSVBoomerangStatsWriter.java | 17 +++--- .../java/boomerang/stats/IBoomerangStats.java | 17 +++--- .../boomerang/stats/SimpleBoomerangStats.java | 17 +++--- .../main/java/boomerang/util/AccessPath.java | 17 +++--- .../java/boomerang/util/DefaultValueMap.java | 17 +++--- .../java/boomerang/util/RegExAccessPath.java | 17 +++--- .../boomerang/weights/DataFlowPathWeight.java | 17 +++--- .../weights/DataFlowPathWeightImpl.java | 17 +++--- .../weights/DataFlowPathWeightOne.java | 17 +++--- .../boomerang/weights/MinDistanceWeight.java | 17 +++--- .../weights/MinDistanceWeightFunctions.java | 17 +++--- .../weights/MinDistanceWeightImpl.java | 17 +++--- .../weights/MinDistanceWeightOne.java | 17 +++--- .../weights/PathConditionWeight.java | 17 +++--- .../weights/PathConditionWeightImpl.java | 17 +++--- .../weights/PathConditionWeightOne.java | 17 +++--- .../weights/PathTrackingBoomerang.java | 17 +++--- .../boomerang/weights/PathTrackingWeight.java | 17 +++--- .../weights/PathTrackingWeightFunctions.java | 17 +++--- .../weights/PathTrackingWeightImpl.java | 17 +++--- .../weights/PathTrackingWeightOne.java | 17 +++--- .../ArrayContainerCollectionManager.java | 17 +++--- .../guided/CustomFlowFunctionTest.java | 17 +++--- .../DemandDrivenGuidedAnalysisTest.java | 17 +++--- .../guided/SpecificationParserTest.java | 17 +++--- .../CustomBackwardFlowFunction.java | 17 +++--- .../CustomForwardFlowFunction.java | 17 +++--- .../guided/targets/ArrayContainerTarget.java | 17 +++--- .../boomerang/guided/targets/BasicTarget.java | 17 +++--- .../targets/BranchingAfterNewStringTest.java | 17 +++--- .../guided/targets/BranchingTest.java | 17 +++--- ...nsitiveAndLeftUnbalanced2StacksTarget.java | 17 +++--- ...SensitiveAndLeftUnbalancedFieldTarget.java | 17 +++--- ...ntextSensitiveAndLeftUnbalancedTarget.java | 17 +++--- ...textSensitiveAndLeftUnbalancedTarget2.java | 17 +++--- ...itiveAndLeftUnbalancedThisFieldTarget.java | 17 +++--- .../targets/ContextSensitiveTarget.java | 17 +++--- .../targets/CustomFlowFunctionIntTarget.java | 17 +++--- .../targets/CustomFlowFunctionTarget.java | 17 +++--- .../guided/targets/IntegerCastTarget.java | 17 +++--- .../guided/targets/LeftUnbalancedTarget.java | 17 +++--- .../NestedContextAndBranchingTarget.java | 17 +++--- .../guided/targets/NestedContextTarget.java | 17 +++--- .../PingPongInterproceduralTarget.java | 17 +++--- .../guided/targets/PingPongTarget.java | 17 +++--- .../java/boomerang/guided/targets/Query.java | 17 +++--- .../guided/targets/ValueOfTarget.java | 17 +++--- .../WrappedInNewStringInnerTarget.java | 17 +++--- .../targets/WrappedInNewStringTarget.java | 17 +++--- .../targets/WrappedInStringTwiceTest.java | 17 +++--- .../src/test/java/example/ExampleMain1.java | 17 +++--- .../src/test/java/example/ExampleMain2.java | 17 +++--- .../cases/accesspath/AccessPathTarget.java | 17 +++--- .../test/cases/accesspath/AccessPathTest.java | 17 +++--- .../java/test/cases/array/ArrayAlloc.java | 17 +++--- .../cases/array/ArrayContainerTarget.java | 17 +++--- .../test/cases/array/ArrayContainerTest.java | 17 +++--- .../array/ArrayIndexSensitiveTarget.java | 17 +++--- .../cases/array/ArrayIndexSensitiveTest.java | 17 +++--- .../java/test/cases/array/ArrayTarget.java | 17 +++--- .../test/java/test/cases/array/ArrayTest.java | 17 +++--- .../java/test/cases/basic/BasicAlloc.java | 17 +++--- .../test/cases/basic/FieldlessTarget.java | 17 +++--- .../java/test/cases/basic/FieldlessTest.java | 17 +++--- .../cases/basic/InterproceduralTarget.java | 17 +++--- .../test/cases/basic/InterproceduralTest.java | 17 +++--- .../UnbalancedInterproceduralTarget.java | 17 +++--- .../basic/UnbalancedInterproceduralTest.java | 17 +++--- .../java/test/cases/bugfixes/issue5/Foo.java | 17 +++--- .../cases/bugfixes/issue5/Issue5Test.java | 17 +++--- .../java/test/cases/bugfixes/issue5/Test.java | 17 +++--- .../test/cases/callgraph/CallGraphAlloc.java | 17 +++--- .../ContextSensitivityFieldTarget.java | 17 +++--- .../ContextSensitivityFieldTest.java | 17 +++--- .../ContextSensitivityMyListTarget.java | 17 +++--- .../ContextSensitivityMyListTest.java | 17 +++--- .../callgraph/ContextSensitivityTarget.java | 17 +++--- .../callgraph/ContextSensitivityTest.java | 17 +++--- .../ContextSpecificListTypeTarget.java | 17 +++--- .../ContextSpecificListTypeTest.java | 17 +++--- .../context/AliasViaParameterTarget.java | 17 +++--- .../cases/context/AliasViaParameterTest.java | 17 +++--- .../java/test/cases/context/ContextAlloc.java | 17 +++--- .../cases/context/ContextTypesTarget.java | 17 +++--- .../test/cases/context/ContextTypesTest.java | 17 +++--- .../context/LoopInContextRequesterTarget.java | 17 +++--- .../context/LoopInContextRequesterTest.java | 17 +++--- .../cases/context/OuterAllocationTarget.java | 17 +++--- .../cases/context/OuterAllocationTest.java | 17 +++--- .../context/PathingContextProblemTarget.java | 17 +++--- .../context/PathingContextProblemTest.java | 17 +++--- .../context/SimpleContextQueryTarget.java | 17 +++--- .../cases/context/SimpleContextQueryTest.java | 17 +++--- .../test/cases/exceptions/ExceptionAlloc.java | 17 +++--- .../cases/exceptions/ExceptionTarget.java | 17 +++--- .../test/cases/exceptions/ExceptionTest.java | 17 +++--- .../src/test/java/test/cases/fields/A.java | 17 +++--- .../src/test/java/test/cases/fields/B.java | 17 +++--- .../test/cases/fields/BasicFieldTarget.java | 17 +++--- .../test/cases/fields/BasicFieldTest.java | 17 +++--- .../java/test/cases/fields/CallPOITarget.java | 17 +++--- .../java/test/cases/fields/CallPOITest.java | 17 +++--- .../test/cases/fields/CastAndSetTarget.java | 17 +++--- .../test/cases/fields/CastAndSetTest.java | 17 +++--- .../cases/fields/FailOnVisitMethodTarget.java | 17 +++--- .../cases/fields/FailOnVisitMethodTest.java | 17 +++--- .../java/test/cases/fields/FieldAlloc.java | 17 +++--- .../cases/fields/FieldsBranchedTarget.java | 17 +++--- .../test/cases/fields/FieldsBranchedTest.java | 17 +++--- .../cases/fields/HiddenFieldLoadTarget.java | 17 +++--- .../cases/fields/HiddenFieldLoadTest.java | 17 +++--- .../cases/fields/InterproceduralTarget.java | 17 +++--- .../cases/fields/InterproceduralTest.java | 17 +++--- .../IntraproceduralStrongUpdateTarget.java | 17 +++--- .../IntraproceduralStrongUpdateTest.java | 17 +++--- .../java/test/cases/fields/MeetPOITarget.java | 17 +++--- .../java/test/cases/fields/MeetPOITest.java | 17 +++--- .../cases/fields/NoIndirectionTarget.java | 17 +++--- .../test/cases/fields/NoIndirectionTest.java | 17 +++--- .../NullAllocationConstructorTarget.java | 17 +++--- .../fields/NullAllocationConstructorTest.java | 17 +++--- .../cases/fields/ObjectSensitivityTarget.java | 17 +++--- .../cases/fields/ObjectSensitivityTest.java | 17 +++--- .../java/test/cases/fields/ReadPOITarget.java | 17 +++--- .../java/test/cases/fields/ReadPOITest.java | 17 +++--- .../fields/ReadTwiceSameFieldTarget.java | 17 +++--- .../cases/fields/ReadTwiceSameFieldTest.java | 17 +++--- .../test/cases/fields/ReturnPOITarget.java | 17 +++--- .../java/test/cases/fields/ReturnPOITest.java | 17 +++--- .../cases/fields/ReuseOfSummaryTarget.java | 17 +++--- .../test/cases/fields/ReuseOfSummaryTest.java | 17 +++--- .../java/test/cases/fields/SummaryTarget.java | 17 +++--- .../java/test/cases/fields/SummaryTest.java | 17 +++--- .../test/cases/fields/ThreeFieldsTarget.java | 17 +++--- .../test/cases/fields/ThreeFieldsTest.java | 17 +++--- .../test/cases/fields/TypeChangeTarget.java | 17 +++--- .../test/cases/fields/TypeChangeTest.java | 17 +++--- .../test/cases/fields/WritePOITarget.java | 17 +++--- .../java/test/cases/fields/WritePOITest.java | 17 +++--- .../fields/complexity/Fields10LongTarget.java | 17 +++--- .../fields/complexity/Fields10LongTest.java | 17 +++--- .../fields/complexity/Fields20LongTarget.java | 17 +++--- .../fields/complexity/Fields20LongTest.java | 17 +++--- .../fields/complexity/Fields2LongTarget.java | 17 +++--- .../fields/complexity/Fields2LongTest.java | 17 +++--- .../fields/complexity/Fields3LongTarget.java | 17 +++--- .../fields/complexity/Fields3LongTest.java | 17 +++--- .../fields/complexity/Fields4LongTarget.java | 17 +++--- .../fields/complexity/Fields4LongTest.java | 17 +++--- .../fields/complexity/Fields5LongTarget.java | 17 +++--- .../fields/complexity/Fields5LongTest.java | 17 +++--- .../fields/complexity/Fields6LongTarget.java | 17 +++--- .../fields/complexity/Fields6LongTest.java | 17 +++--- .../complexity/Recursion2LongTarget.java | 17 +++--- .../fields/complexity/Recursion2LongTest.java | 17 +++--- .../loops/LoopsWithFieldsInterTarget.java | 17 +++--- .../loops/LoopsWithFieldsInterTest.java | 17 +++--- .../loops/LoopsWithFieldsIntraTarget.java | 17 +++--- .../loops/LoopsWithFieldsIntraTest.java | 17 +++--- .../test/cases/generics/GenericsTarget.java | 17 +++--- .../test/cases/generics/GenericsTest.java | 17 +++--- .../cases/hashmap/AllAliasLongTarget.java | 17 +++--- .../test/cases/hashmap/AllAliasLongTest.java | 17 +++--- .../test/java/test/cases/hashmap/Entry.java | 17 +++--- .../cases/hashmap/KeySensitiveTarget.java | 17 +++--- .../test/cases/hashmap/KeySensitiveTest.java | 17 +++--- .../java/test/cases/hashmap/MapAlloc.java | 17 +++--- .../test/java/test/cases/hashmap/Node.java | 17 +++--- .../java/test/cases/hashmap/TreeNode.java | 17 +++--- .../java/test/cases/integers/IntTarget.java | 17 +++--- .../java/test/cases/integers/IntTest.java | 17 +++--- .../lists/ArrayAndLinkedListsTarget.java | 17 +++--- .../cases/lists/ArrayAndLinkedListsTest.java | 17 +++--- .../cases/lists/ArrayListsLongTarget.java | 17 +++--- .../test/cases/lists/ArrayListsLongTest.java | 17 +++--- .../cases/lists/LinkedListsLongTarget.java | 17 +++--- .../test/cases/lists/LinkedListsLongTest.java | 17 +++--- .../lists/LinkedListsTypeLongTarget.java | 17 +++--- .../cases/lists/LinkedListsTypeLongTest.java | 17 +++--- .../test/java/test/cases/lists/ListAlloc.java | 17 +++--- .../test/cases/lists/VectorsLongTarget.java | 17 +++--- .../test/cases/lists/VectorsLongTest.java | 17 +++--- .../cases/multiqueries/MultiQueryTarget.java | 17 +++--- .../cases/multiqueries/MultiQueryTests.java | 17 +++--- .../cases/realworld/FixAfterInsertion.java | 17 +++--- .../FixAfterInsertionLongTarget.java | 17 +++--- .../realworld/FixAfterInsertionLongTest.java | 17 +++--- .../ScalabilityOfBackwardAnalysisTarget.java | 17 +++--- .../ScalabilityOfBackwardAnalysisTest.java | 17 +++--- .../cases/reflection/ReflectionAlloc.java | 17 +++--- .../cases/reflection/ReflectionTarget.java | 17 +++--- .../test/cases/reflection/ReflectionTest.java | 17 +++--- .../java/test/cases/sets/CustomMapTarget.java | 17 +++--- .../java/test/cases/sets/CustomMapTest.java | 17 +++--- .../java/test/cases/sets/CustomSetTarget.java | 17 +++--- .../java/test/cases/sets/CustomSetTest.java | 17 +++--- .../test/cases/sets/HashMapGetLongTarget.java | 17 +++--- .../test/cases/sets/HashMapGetLongTest.java | 17 +++--- .../test/cases/sets/HashMapsLongTarget.java | 17 +++--- .../test/cases/sets/HashMapsLongTest.java | 17 +++--- .../test/cases/sets/HashSetsLongTarget.java | 17 +++--- .../test/cases/sets/HashSetsLongTest.java | 17 +++--- .../test/java/test/cases/sets/MyInnerMap.java | 17 +++--- .../src/test/java/test/cases/sets/MyMap.java | 17 +++--- .../test/java/test/cases/sets/SetAlloc.java | 17 +++--- .../test/cases/sets/TreeMapLongTarget.java | 17 +++--- .../java/test/cases/sets/TreeMapLongTest.java | 17 +++--- .../sets/TreeMapMultipleInstancesTarget.java | 17 +++--- .../sets/TreeMapMultipleInstancesTest.java | 17 +++--- .../test/cases/sets/TreeSetsLongTarget.java | 17 +++--- .../test/cases/sets/TreeSetsLongTest.java | 17 +++--- .../cases/statics/SimpleSingletonTarget.java | 17 +++--- .../cases/statics/SimpleSingletonTest.java | 17 +++--- .../test/cases/statics/SingletonTarget.java | 17 +++--- .../test/cases/statics/SingletonTest.java | 17 +++--- .../cases/statics/StaticFieldFlowsTarget.java | 17 +++--- .../cases/statics/StaticFieldFlowsTest.java | 17 +++--- .../statics/StaticInitializerTarget.java | 17 +++--- .../cases/statics/StaticInitializerTest.java | 17 +++--- .../statics/StaticWithSuperClassesTarget.java | 17 +++--- .../statics/StaticWithSuperClassesTest.java | 17 +++--- .../java/test/cases/statics/StaticsAlloc.java | 17 +++--- .../java/test/cases/string/StringTarget.java | 17 +++--- .../java/test/cases/string/StringTest.java | 17 +++--- .../AbstractClassWithInnerSubclassTarget.java | 17 +++--- .../AbstractClassWithInnerSubclassTest.java | 17 +++--- .../cases/subclassing/InnerClass2Target.java | 17 +++--- .../cases/subclassing/InnerClass2Test.java | 17 +++--- .../cases/subclassing/InnerClassTarget.java | 17 +++--- .../cases/subclassing/InnerClassTest.java | 17 +++--- .../cases/subclassing/SubclassingAlloc.java | 17 +++--- .../cases/subclassing/SubclassingTarget.java | 17 +++--- .../cases/subclassing/SubclassingTest.java | 17 +++--- .../test/cases/synchronizd/BlockTarget.java | 17 +++--- .../test/cases/synchronizd/BlockTest.java | 17 +++--- .../cases/synchronizd/SynchronizedAlloc.java | 17 +++--- .../threading/InnerClassWithThreadTarget.java | 17 +++--- .../threading/InnerClassWithThreadTest.java | 17 +++--- .../test/cases/threading/ThreadingAlloc.java | 17 +++--- .../typing/InterfaceInvocationTarget.java | 17 +++--- .../cases/typing/InterfaceInvocationTest.java | 17 +++--- .../cases/typing/TypeConfusionTarget.java | 17 +++--- .../test/cases/typing/TypeConfusionTest.java | 17 +++--- .../cases/unbalanced/UnbalancedAlloc.java | 17 +++--- .../unbalanced/UnbalancedScopesTarget.java | 17 +++--- .../unbalanced/UnbalancedScopesTest.java | 17 +++--- .../java/test/core/AbstractBoomerangTest.java | 17 +++--- .../test/java/test/core/AllocationSiteOf.java | 17 +++--- .../test/java/test/core/FirstArgumentOf.java | 17 +++--- .../test/core/IntegerAllocationSiteOf.java | 17 +++--- .../test/core/MultiQueryBoomerangTest.java | 17 +++--- .../src/test/java/test/core/Preanalysis.java | 17 +++--- .../test/core/QueryForCallSiteDetector.java | 17 +++--- .../src/test/java/test/core/QueryMethods.java | 17 +++--- .../java/test/core/ValueOfInterestInUnit.java | 17 +++--- .../test/options/BoomerangOptionsTest.java | 17 +++--- .../boomerang/scope/opal/OpalCallGraph.scala | 20 +++---- .../boomerang/scope/opal/OpalClient.scala | 17 +++--- .../scope/opal/OpalFrameworkScope.scala | 17 +++--- .../scope/opal/tac/OpalArrayRef.scala | 17 +++--- .../scope/opal/tac/OpalControlFlowGraph.scala | 17 +++--- .../scope/opal/tac/OpalDeclaredMethod.scala | 17 +++--- .../scope/opal/tac/OpalDoubleVal.scala | 17 +++--- .../boomerang/scope/opal/tac/OpalField.scala | 17 +++--- .../scope/opal/tac/OpalIfStatement.scala | 17 +++--- .../scope/opal/tac/OpalInstanceFieldRef.scala | 17 +++--- .../scope/opal/tac/OpalInvokeExpr.scala | 17 +++--- .../boomerang/scope/opal/tac/OpalLocal.scala | 17 +++--- .../boomerang/scope/opal/tac/OpalMethod.scala | 17 +++--- .../scope/opal/tac/OpalNullType.scala | 17 +++--- .../scope/opal/tac/OpalPhantomMethod.scala | 17 +++--- .../opal/tac/OpalPhantomWrappedClass.scala | 17 +++--- .../scope/opal/tac/OpalStatement.scala | 17 +++--- .../opal/tac/OpalStatementFormatter.scala | 25 +++++---- .../scope/opal/tac/OpalStaticFieldRef.scala | 17 +++--- .../scope/opal/tac/OpalStaticFieldVal.scala | 17 +++--- .../boomerang/scope/opal/tac/OpalType.scala | 17 +++--- .../boomerang/scope/opal/tac/OpalVal.scala | 17 +++--- .../scope/opal/tac/OpalWrappedClass.scala | 17 +++--- .../opal/transformation/BoomerangTACode.scala | 17 +++--- .../scope/opal/transformation/StmtGraph.scala | 17 +++--- .../opal/transformation/TacBodyBuilder.scala | 17 +++--- .../scope/opal/transformation/TacLocal.scala | 17 +++--- .../opal/transformation/stack/Operand.scala | 17 +++--- .../transformation/stack/OperandStack.scala | 17 +++--- .../stack/OperandStackBuilder.scala | 21 ++++---- .../stack/OperandStackHandler.scala | 17 +++--- .../transformer/InlineLocalTransformer.scala | 29 +++++----- .../LocalPropagationTransformer.scala | 54 ++++++++----------- .../transformer/LocalTransformer.scala | 17 +++--- .../transformer/NopEliminator.scala | 17 +++--- .../transformer/NopTransformer.scala | 17 +++--- .../NullifyFieldsTransformer.scala | 22 ++++---- .../boomerang/scope/opal/OpalArrayTest.scala | 17 +++--- .../scope/opal/OpalAssignmentTest.scala | 17 +++--- .../scope/opal/OpalControlFlowGraphTest.scala | 17 +++--- .../boomerang/scope/opal/OpalFieldTest.scala | 17 +++--- .../scope/opal/OpalInvokeExprTest.scala | 17 +++--- .../boomerang/scope/opal/OpalLocalTest.scala | 17 +++--- .../boomerang/scope/opal/OpalSetup.scala | 17 +++--- .../scope/opal/TacBodyBuilderTest.scala | 17 +++--- .../scope/soot/BoomerangPretransformer.java | 17 +++--- .../boomerang/scope/soot/SootCallGraph.java | 17 +++--- .../scope/soot/SootFrameworkScope.java | 17 +++--- .../soot/jimple/ExplicitNullifyFields.java | 17 +++--- .../soot/jimple/JimpleControlFlowGraph.java | 17 +++--- .../soot/jimple/JimpleDeclaredMethod.java | 17 +++--- .../scope/soot/jimple/JimpleDoubleVal.java | 17 +++--- .../scope/soot/jimple/JimpleField.java | 17 +++--- .../scope/soot/jimple/JimpleIfStatement.java | 17 +++--- .../soot/jimple/JimpleInstanceFieldRef.java | 17 +++--- .../scope/soot/jimple/JimpleInvokeExpr.java | 17 +++--- .../scope/soot/jimple/JimpleMethod.java | 17 +++--- .../soot/jimple/JimplePhantomMethod.java | 17 +++--- .../scope/soot/jimple/JimpleStatement.java | 17 +++--- .../soot/jimple/JimpleStaticFieldVal.java | 17 +++--- .../scope/soot/jimple/JimpleType.java | 17 +++--- .../scope/soot/jimple/JimpleVal.java | 17 +++--- .../scope/soot/jimple/JimpleWrappedClass.java | 17 +++--- .../scope/soot/sparse/SootAdapter.java | 17 +++--- .../scope/soot/sparse/SparseCFGBuilder.java | 17 +++--- .../AliasAwareSparseCFGBuilder.java | 17 +++--- .../aliasaware/AliasAwareSparseCFGCache.java | 17 +++--- .../sparse/aliasaware/DefinedOutside.java | 17 +++--- .../sparse/aliasaware/MStaticFieldRef.java | 17 +++--- .../typebased/TypeBasedSparseCFGBuilder.java | 17 +++--- .../typebased/TypeBasedSparseCFGCache.java | 17 +++--- .../boomerang/scope/soot/SootArrayTest.java | 17 +++--- .../boomerang/scope/soot/SootScopeTest.java | 17 +++--- .../java/boomerang/scope/soot/SootSetup.java | 17 +++--- .../scope/sootup/BoomerangPreInterceptor.java | 17 +++--- .../scope/sootup/SootUpCallGraph.java | 17 +++--- .../scope/sootup/SootUpFrameworkScope.java | 17 +++--- .../jimple/JimpleUpControlFlowGraph.java | 17 +++--- .../sootup/jimple/JimpleUpDeclaredMethod.java | 17 +++--- .../sootup/jimple/JimpleUpDoubleVal.java | 17 +++--- .../scope/sootup/jimple/JimpleUpField.java | 17 +++--- .../sootup/jimple/JimpleUpIfStatement.java | 17 +++--- .../jimple/JimpleUpInstanceFieldRef.java | 17 +++--- .../sootup/jimple/JimpleUpInvokeExpr.java | 17 +++--- .../scope/sootup/jimple/JimpleUpMethod.java | 17 +++--- .../sootup/jimple/JimpleUpStatement.java | 17 +++--- .../sootup/jimple/JimpleUpStaticFieldVal.java | 17 +++--- .../scope/sootup/jimple/JimpleUpType.java | 17 +++--- .../scope/sootup/jimple/JimpleUpVal.java | 17 +++--- .../sootup/jimple/JimpleUpWrappedClass.java | 17 +++--- .../sootup/ScopedAnalysisInputLocation.java | 17 +++--- ...rceTypeSplittingAnalysisInputLocation.java | 17 +++--- .../boomerang/scope/wala/WALACallGraph.java | 17 +++--- .../java/boomerang/scope/wala/WALAClass.java | 17 +++--- .../scope/wala/WALAControlFlowGraph.java | 17 +++--- .../scope/wala/WALADataFlowScope.java | 17 +++--- .../scope/wala/WALADeclaredMethod.java | 17 +++--- .../scope/wala/WALADummyNullStatement.java | 17 +++--- .../boomerang/scope/wala/WALADummyVal.java | 17 +++--- .../java/boomerang/scope/wala/WALAField.java | 17 +++--- .../boomerang/scope/wala/WALAIfStatement.java | 17 +++--- .../boomerang/scope/wala/WALAInvokeExpr.java | 17 +++--- .../java/boomerang/scope/wala/WALAMethod.java | 17 +++--- .../boomerang/scope/wala/WALAStatement.java | 17 +++--- .../scope/wala/WALAStaticFieldVal.java | 17 +++--- .../java/boomerang/scope/wala/WALAType.java | 17 +++--- .../wala/WALAUnitializedFieldStatement.java | 17 +++--- .../java/boomerang/scope/wala/WALAVal.java | 17 +++--- .../scope/wala/WalaFrameworkScope.java | 17 +++--- .../java/example/BoomerangExampleTarget1.java | 17 +++--- .../src/test/java/example/ExampleMain1.java | 17 +++--- .../main/java/boomerang/scope/AllocVal.java | 17 +++--- .../main/java/boomerang/scope/CallGraph.java | 17 +++--- .../boomerang/scope/ControlFlowGraph.java | 17 +++--- .../java/boomerang/scope/DataFlowScope.java | 17 +++--- .../java/boomerang/scope/DeclaredMethod.java | 17 +++--- .../src/main/java/boomerang/scope/Field.java | 17 +++--- .../java/boomerang/scope/FrameworkScope.java | 17 +++--- .../java/boomerang/scope/IfStatement.java | 17 +++--- .../boomerang/scope/InstanceFieldRef.java | 17 +++--- .../main/java/boomerang/scope/InvokeExpr.java | 17 +++--- .../src/main/java/boomerang/scope/Method.java | 17 +++--- .../src/main/java/boomerang/scope/Pair.java | 17 +++--- .../main/java/boomerang/scope/Statement.java | 17 +++--- .../java/boomerang/scope/StaticFieldVal.java | 17 +++--- .../src/main/java/boomerang/scope/Type.java | 17 +++--- .../src/main/java/boomerang/scope/Val.java | 17 +++--- .../boomerang/scope/ValWithFalseVariable.java | 17 +++--- .../java/boomerang/scope/WrappedClass.java | 17 +++--- .../java/boomerang/utils/MethodWrapper.java | 17 +++--- .../main/java/sparse/SparseAliasingCFG.java | 17 +++--- .../src/main/java/sparse/SparseCFGCache.java | 17 +++--- .../java/sparse/SparsificationStrategy.java | 17 +++--- .../main/java/sparse/eval/EvalPrinter.java | 17 +++--- .../java/sparse/eval/PropagationCounter.java | 17 +++--- .../java/sparse/eval/SparseCFGQueryLog.java | 17 +++--- .../scope/test/BoomerangScopeTests.java | 17 +++--- .../boomerang/scope/test/MethodSignature.java | 17 +++--- .../boomerang/scope/test/TargetClassPath.java | 17 +++--- .../java/boomerang/scope/test/targets/A.java | 17 +++--- .../scope/test/targets/ArrayTarget.java | 17 +++--- .../scope/test/targets/AssignmentTarget.java | 17 +++--- .../scope/test/targets/BranchingTarget.java | 17 +++--- .../scope/test/targets/ConstructorTarget.java | 17 +++--- .../test/targets/ControlFlowGraphTarget.java | 17 +++--- .../scope/test/targets/FieldClass.java | 17 +++--- .../scope/test/targets/FieldTarget.java | 17 +++--- .../targets/HashCodeEqualsLocalTarget.java | 17 +++--- .../scope/test/targets/InvokeExprTarget.java | 17 +++--- .../scope/test/targets/LocalCountTarget.java | 17 +++--- .../test/targets/ParameterLocalsTarget.java | 17 +++--- .../scope/test/targets/SingleTarget.java | 17 +++--- .../scope/test/targets/ThisLocalTarget.java | 17 +++--- .../src/main/java/ideal/IDEALAnalysis.java | 17 +++--- .../java/ideal/IDEALAnalysisDefinition.java | 17 +++--- .../main/java/ideal/IDEALResultHandler.java | 17 +++--- .../src/main/java/ideal/IDEALSeedSolver.java | 17 +++--- .../src/main/java/ideal/IDEALSeedTimeout.java | 17 +++--- .../main/java/ideal/IDEALWeightFunctions.java | 17 +++--- .../main/java/ideal/NonOneFlowListener.java | 17 +++--- .../java/ideal/StoreIDEALResultHandler.java | 17 +++--- .../main/java/inference/InferenceWeight.java | 17 +++--- .../inference/InferenceWeightFunctions.java | 17 +++--- .../java/inference/InferenceWeightImpl.java | 17 +++--- .../java/inference/InferenceWeightOne.java | 17 +++--- .../java/inference/InferenceWeightZero.java | 17 +++--- .../java/typestate/TransitionFunction.java | 17 +++--- .../typestate/TransitionFunctionImpl.java | 17 +++--- .../java/typestate/TransitionFunctionOne.java | 17 +++--- .../typestate/TransitionFunctionZero.java | 17 +++--- .../finiteautomata/MatcherTransition.java | 17 +++--- .../java/typestate/finiteautomata/State.java | 17 +++--- .../typestate/finiteautomata/Transition.java | 17 +++--- .../finiteautomata/TransitionIdentity.java | 17 +++--- .../finiteautomata/TransitionImpl.java | 17 +++--- .../TypeStateMachineWeightFunctions.java | 17 +++--- .../FileMustBeClosedStateMachine.java | 17 +++--- ...eMustBeClosedStateMachineCallToReturn.java | 17 +++--- .../statemachines/HasNextStateMachine.java | 17 +++--- .../InputStreamStateMachine.java | 17 +++--- .../statemachines/KeyStoreStateMachine.java | 17 +++--- .../OutputStreamStateMachine.java | 17 +++--- .../PipedInputStreamStateMachine.java | 17 +++--- .../PipedOutputStreamStateMachine.java | 17 +++--- .../PrintStreamStateMachine.java | 17 +++--- .../PrintWriterStateMachine.java | 17 +++--- .../statemachines/SignatureStateMachine.java | 17 +++--- .../statemachines/SocketStateMachine.java | 17 +++--- .../statemachines/URLConnStateMachine.java | 17 +++--- .../statemachines/VectorStateMachine.java | 17 +++--- .../src/test/java/assertions/Assertions.java | 17 +++--- .../assertions/MayBeInAcceptingState.java | 17 +++--- .../java/assertions/MayBeInErrorState.java | 17 +++--- .../assertions/MustBeInAcceptingState.java | 17 +++--- .../java/assertions/MustBeInErrorState.java | 17 +++--- .../java/assertions/ShouldNotBeAnalyzed.java | 17 +++--- .../src/test/java/assertions/StateResult.java | 17 +++--- .../test/java/example/InferenceExample.java | 17 +++--- idealPDS/src/test/java/example/Main.java | 17 +++--- .../test/java/test/IDEALTestingFramework.java | 17 +++--- .../test/java/test/TestingResultReporter.java | 17 +++--- .../typestate/targets/AssertionsTesting.java | 17 +++--- .../typestate/targets/FileMustBeClosed.java | 17 +++--- .../targets/FileMustBeClosedDemandDriven.java | 17 +++--- .../targets/FileMustBeClosedInterface.java | 17 +++--- .../targets/FileMustBeClosedStrongUpdate.java | 17 +++--- .../typestate/targets/FluentInterface.java | 17 +++--- .../typestate/targets/InputStreamLong.java | 17 +++--- .../typestate/targets/IteratorHasNext.java | 17 +++--- .../java/typestate/targets/KeyStoreLong.java | 17 +++--- .../typestate/targets/PrintStreamLong.java | 17 +++--- .../typestate/targets/PrintWriterLong.java | 17 +++--- .../java/typestate/targets/SocketLong.java | 17 +++--- .../typestate/targets/SootSceneSetup.java | 17 +++--- .../java/typestate/targets/StackLong.java | 17 +++--- .../test/java/typestate/targets/URLConn.java | 17 +++--- .../java/typestate/targets/VectorLong.java | 17 +++--- .../java/typestate/targets/helper/File.java | 17 +++--- .../targets/helper/ObjectWithField.java | 17 +++--- .../java/typestate/tests/AssertionsTest.java | 17 +++--- .../FileMustBeClosedDemandDrivenTest.java | 17 +++--- .../tests/FileMustBeClosedInterfaceTest.java | 17 +++--- .../FileMustBeClosedStrongUpdateTest.java | 17 +++--- .../typestate/tests/FileMustBeClosedTest.java | 17 +++--- .../typestate/tests/FluentInterfaceTest.java | 17 +++--- .../typestate/tests/InputStreamLongTest.java | 17 +++--- .../typestate/tests/IteratorHasNextTest.java | 17 +++--- .../typestate/tests/KeyStoreLongTest.java | 17 +++--- .../typestate/tests/PrintStreamLongTest.java | 17 +++--- .../typestate/tests/PrintWriterLongTest.java | 17 +++--- .../java/typestate/tests/SocketLongTest.java | 17 +++--- .../typestate/tests/SootSceneSetupTest.java | 17 +++--- .../java/typestate/tests/StackLongTest.java | 17 +++--- .../java/typestate/tests/URLConnTest.java | 17 +++--- .../java/typestate/tests/VectorLongTest.java | 17 +++--- license_header.txt | 17 +++--- pom.xml | 1 + testCore/src/main/java/test/Assertion.java | 17 +++--- testCore/src/main/java/test/TestMethod.java | 17 +++--- .../src/main/java/test/TestingFramework.java | 17 +++--- .../core/selfrunning/AllocatedObject.java | 17 +++--- .../core/selfrunning/AllocatedObject2.java | 17 +++--- .../selfrunning/ImprecisionException.java | 17 +++--- .../core/selfrunning/NoAllocatedObject.java | 17 +++--- .../test/core/selfrunning/NullableField.java | 17 +++--- .../main/java/test/setup/OpalTestSetup.java | 17 +++--- .../main/java/test/setup/SootTestSetup.java | 17 +++--- .../main/java/test/setup/SootUpTestSetup.java | 17 +++--- .../src/main/java/test/setup/TestSetup.java | 17 +++--- 664 files changed, 6652 insertions(+), 4689 deletions(-) diff --git a/PDS/src/main/java/de/fraunhofer/iem/Empty.java b/PDS/src/main/java/de/fraunhofer/iem/Empty.java index 6e0627d85..ba9d06f15 100644 --- a/PDS/src/main/java/de/fraunhofer/iem/Empty.java +++ b/PDS/src/main/java/de/fraunhofer/iem/Empty.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package de.fraunhofer.iem; diff --git a/PDS/src/main/java/de/fraunhofer/iem/Location.java b/PDS/src/main/java/de/fraunhofer/iem/Location.java index 452a10a7b..a2220000f 100644 --- a/PDS/src/main/java/de/fraunhofer/iem/Location.java +++ b/PDS/src/main/java/de/fraunhofer/iem/Location.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package de.fraunhofer.iem; diff --git a/PDS/src/main/java/de/fraunhofer/iem/wildcard/ExclusionWildcard.java b/PDS/src/main/java/de/fraunhofer/iem/wildcard/ExclusionWildcard.java index af4f740ec..370f8c074 100644 --- a/PDS/src/main/java/de/fraunhofer/iem/wildcard/ExclusionWildcard.java +++ b/PDS/src/main/java/de/fraunhofer/iem/wildcard/ExclusionWildcard.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package de.fraunhofer.iem.wildcard; diff --git a/PDS/src/main/java/de/fraunhofer/iem/wildcard/Wildcard.java b/PDS/src/main/java/de/fraunhofer/iem/wildcard/Wildcard.java index ccb6b7939..9a8f591db 100644 --- a/PDS/src/main/java/de/fraunhofer/iem/wildcard/Wildcard.java +++ b/PDS/src/main/java/de/fraunhofer/iem/wildcard/Wildcard.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package de.fraunhofer.iem.wildcard; diff --git a/SynchronizedPDS/src/main/java/sync/pds/solver/CastNormalRule.java b/SynchronizedPDS/src/main/java/sync/pds/solver/CastNormalRule.java index b20923f5a..06bb1b8ec 100644 --- a/SynchronizedPDS/src/main/java/sync/pds/solver/CastNormalRule.java +++ b/SynchronizedPDS/src/main/java/sync/pds/solver/CastNormalRule.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package sync.pds.solver; diff --git a/SynchronizedPDS/src/main/java/sync/pds/solver/EmptyStackWitnessListener.java b/SynchronizedPDS/src/main/java/sync/pds/solver/EmptyStackWitnessListener.java index 7968b8702..2398c79b4 100644 --- a/SynchronizedPDS/src/main/java/sync/pds/solver/EmptyStackWitnessListener.java +++ b/SynchronizedPDS/src/main/java/sync/pds/solver/EmptyStackWitnessListener.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package sync.pds.solver; diff --git a/SynchronizedPDS/src/main/java/sync/pds/solver/OneWeightFunctions.java b/SynchronizedPDS/src/main/java/sync/pds/solver/OneWeightFunctions.java index fdc9a1763..a11cca442 100644 --- a/SynchronizedPDS/src/main/java/sync/pds/solver/OneWeightFunctions.java +++ b/SynchronizedPDS/src/main/java/sync/pds/solver/OneWeightFunctions.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package sync.pds.solver; diff --git a/SynchronizedPDS/src/main/java/sync/pds/solver/SyncPDSSolver.java b/SynchronizedPDS/src/main/java/sync/pds/solver/SyncPDSSolver.java index cd20b0d1b..27d8583e9 100644 --- a/SynchronizedPDS/src/main/java/sync/pds/solver/SyncPDSSolver.java +++ b/SynchronizedPDS/src/main/java/sync/pds/solver/SyncPDSSolver.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package sync.pds.solver; diff --git a/SynchronizedPDS/src/main/java/sync/pds/solver/SyncPDSUpdateListener.java b/SynchronizedPDS/src/main/java/sync/pds/solver/SyncPDSUpdateListener.java index b00fc5813..6e24c7d07 100644 --- a/SynchronizedPDS/src/main/java/sync/pds/solver/SyncPDSUpdateListener.java +++ b/SynchronizedPDS/src/main/java/sync/pds/solver/SyncPDSUpdateListener.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package sync.pds.solver; diff --git a/SynchronizedPDS/src/main/java/sync/pds/solver/SyncStatePDSUpdateListener.java b/SynchronizedPDS/src/main/java/sync/pds/solver/SyncStatePDSUpdateListener.java index 0873c6b17..79e829732 100644 --- a/SynchronizedPDS/src/main/java/sync/pds/solver/SyncStatePDSUpdateListener.java +++ b/SynchronizedPDS/src/main/java/sync/pds/solver/SyncStatePDSUpdateListener.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package sync.pds.solver; diff --git a/SynchronizedPDS/src/main/java/sync/pds/solver/WeightFunctions.java b/SynchronizedPDS/src/main/java/sync/pds/solver/WeightFunctions.java index 25fb6c080..ef40a0c09 100644 --- a/SynchronizedPDS/src/main/java/sync/pds/solver/WeightFunctions.java +++ b/SynchronizedPDS/src/main/java/sync/pds/solver/WeightFunctions.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package sync.pds.solver; diff --git a/SynchronizedPDS/src/main/java/sync/pds/solver/WitnessListener.java b/SynchronizedPDS/src/main/java/sync/pds/solver/WitnessListener.java index 51e410f48..74334900d 100644 --- a/SynchronizedPDS/src/main/java/sync/pds/solver/WitnessListener.java +++ b/SynchronizedPDS/src/main/java/sync/pds/solver/WitnessListener.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package sync.pds.solver; diff --git a/SynchronizedPDS/src/main/java/sync/pds/solver/nodes/CallPopNode.java b/SynchronizedPDS/src/main/java/sync/pds/solver/nodes/CallPopNode.java index c78e15d35..ab64b66eb 100644 --- a/SynchronizedPDS/src/main/java/sync/pds/solver/nodes/CallPopNode.java +++ b/SynchronizedPDS/src/main/java/sync/pds/solver/nodes/CallPopNode.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package sync.pds.solver.nodes; diff --git a/SynchronizedPDS/src/main/java/sync/pds/solver/nodes/ExclusionNode.java b/SynchronizedPDS/src/main/java/sync/pds/solver/nodes/ExclusionNode.java index ed28eece7..bf0e97288 100644 --- a/SynchronizedPDS/src/main/java/sync/pds/solver/nodes/ExclusionNode.java +++ b/SynchronizedPDS/src/main/java/sync/pds/solver/nodes/ExclusionNode.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package sync.pds.solver.nodes; diff --git a/SynchronizedPDS/src/main/java/sync/pds/solver/nodes/GeneratedState.java b/SynchronizedPDS/src/main/java/sync/pds/solver/nodes/GeneratedState.java index 66d27577f..e16319611 100644 --- a/SynchronizedPDS/src/main/java/sync/pds/solver/nodes/GeneratedState.java +++ b/SynchronizedPDS/src/main/java/sync/pds/solver/nodes/GeneratedState.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package sync.pds.solver.nodes; diff --git a/SynchronizedPDS/src/main/java/sync/pds/solver/nodes/INode.java b/SynchronizedPDS/src/main/java/sync/pds/solver/nodes/INode.java index 6055b2cd0..3afb46c53 100644 --- a/SynchronizedPDS/src/main/java/sync/pds/solver/nodes/INode.java +++ b/SynchronizedPDS/src/main/java/sync/pds/solver/nodes/INode.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package sync.pds.solver.nodes; diff --git a/SynchronizedPDS/src/main/java/sync/pds/solver/nodes/Node.java b/SynchronizedPDS/src/main/java/sync/pds/solver/nodes/Node.java index 7bc6f1ce5..bd2717963 100644 --- a/SynchronizedPDS/src/main/java/sync/pds/solver/nodes/Node.java +++ b/SynchronizedPDS/src/main/java/sync/pds/solver/nodes/Node.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package sync.pds.solver.nodes; diff --git a/SynchronizedPDS/src/main/java/sync/pds/solver/nodes/NodeWithLocation.java b/SynchronizedPDS/src/main/java/sync/pds/solver/nodes/NodeWithLocation.java index 53c039d5d..5483e7323 100644 --- a/SynchronizedPDS/src/main/java/sync/pds/solver/nodes/NodeWithLocation.java +++ b/SynchronizedPDS/src/main/java/sync/pds/solver/nodes/NodeWithLocation.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package sync.pds.solver.nodes; diff --git a/SynchronizedPDS/src/main/java/sync/pds/solver/nodes/PopNode.java b/SynchronizedPDS/src/main/java/sync/pds/solver/nodes/PopNode.java index 6aa668544..c847a1575 100644 --- a/SynchronizedPDS/src/main/java/sync/pds/solver/nodes/PopNode.java +++ b/SynchronizedPDS/src/main/java/sync/pds/solver/nodes/PopNode.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package sync.pds.solver.nodes; diff --git a/SynchronizedPDS/src/main/java/sync/pds/solver/nodes/PushNode.java b/SynchronizedPDS/src/main/java/sync/pds/solver/nodes/PushNode.java index 9dddab8c2..2a420e357 100644 --- a/SynchronizedPDS/src/main/java/sync/pds/solver/nodes/PushNode.java +++ b/SynchronizedPDS/src/main/java/sync/pds/solver/nodes/PushNode.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package sync.pds.solver.nodes; diff --git a/SynchronizedPDS/src/main/java/sync/pds/solver/nodes/SingleNode.java b/SynchronizedPDS/src/main/java/sync/pds/solver/nodes/SingleNode.java index 7f20f3f73..77383b0f7 100644 --- a/SynchronizedPDS/src/main/java/sync/pds/solver/nodes/SingleNode.java +++ b/SynchronizedPDS/src/main/java/sync/pds/solver/nodes/SingleNode.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package sync.pds.solver.nodes; diff --git a/SynchronizedPDS/src/main/java/sync/pds/weights/SetDomain.java b/SynchronizedPDS/src/main/java/sync/pds/weights/SetDomain.java index 56e558a3e..4608b85db 100644 --- a/SynchronizedPDS/src/main/java/sync/pds/weights/SetDomain.java +++ b/SynchronizedPDS/src/main/java/sync/pds/weights/SetDomain.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package sync.pds.weights; diff --git a/SynchronizedPDS/src/main/java/sync/pds/weights/SetDomainImpl.java b/SynchronizedPDS/src/main/java/sync/pds/weights/SetDomainImpl.java index 12dd9b6bb..602074b56 100644 --- a/SynchronizedPDS/src/main/java/sync/pds/weights/SetDomainImpl.java +++ b/SynchronizedPDS/src/main/java/sync/pds/weights/SetDomainImpl.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package sync.pds.weights; diff --git a/SynchronizedPDS/src/main/java/sync/pds/weights/SetDomainOne.java b/SynchronizedPDS/src/main/java/sync/pds/weights/SetDomainOne.java index 9dc8a5e9f..806d2b1b3 100644 --- a/SynchronizedPDS/src/main/java/sync/pds/weights/SetDomainOne.java +++ b/SynchronizedPDS/src/main/java/sync/pds/weights/SetDomainOne.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package sync.pds.weights; diff --git a/SynchronizedPDS/src/main/java/sync/pds/weights/SetDomainZero.java b/SynchronizedPDS/src/main/java/sync/pds/weights/SetDomainZero.java index 289c2bbc6..fea3793e1 100644 --- a/SynchronizedPDS/src/main/java/sync/pds/weights/SetDomainZero.java +++ b/SynchronizedPDS/src/main/java/sync/pds/weights/SetDomainZero.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package sync.pds.weights; diff --git a/SynchronizedPDS/src/test/java/analysis/test/DoublePDSTest.java b/SynchronizedPDS/src/test/java/analysis/test/DoublePDSTest.java index b2a0a99d8..e2a1811c6 100644 --- a/SynchronizedPDS/src/test/java/analysis/test/DoublePDSTest.java +++ b/SynchronizedPDS/src/test/java/analysis/test/DoublePDSTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package analysis.test; diff --git a/WPDS/src/main/java/wpds/debug/Debugger.java b/WPDS/src/main/java/wpds/debug/Debugger.java index 3374688cc..3c323f629 100644 --- a/WPDS/src/main/java/wpds/debug/Debugger.java +++ b/WPDS/src/main/java/wpds/debug/Debugger.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package wpds.debug; diff --git a/WPDS/src/main/java/wpds/impl/Configuration.java b/WPDS/src/main/java/wpds/impl/Configuration.java index 9644bfc73..246f72d58 100644 --- a/WPDS/src/main/java/wpds/impl/Configuration.java +++ b/WPDS/src/main/java/wpds/impl/Configuration.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package wpds.impl; diff --git a/WPDS/src/main/java/wpds/impl/ConnectPushListener.java b/WPDS/src/main/java/wpds/impl/ConnectPushListener.java index 67df9e222..6cdb87725 100644 --- a/WPDS/src/main/java/wpds/impl/ConnectPushListener.java +++ b/WPDS/src/main/java/wpds/impl/ConnectPushListener.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package wpds.impl; diff --git a/WPDS/src/main/java/wpds/impl/NestedAutomatonListener.java b/WPDS/src/main/java/wpds/impl/NestedAutomatonListener.java index 17eff47c1..463871a9f 100644 --- a/WPDS/src/main/java/wpds/impl/NestedAutomatonListener.java +++ b/WPDS/src/main/java/wpds/impl/NestedAutomatonListener.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package wpds.impl; diff --git a/WPDS/src/main/java/wpds/impl/NestedWeightedPAutomatons.java b/WPDS/src/main/java/wpds/impl/NestedWeightedPAutomatons.java index 5e87eb4d1..f0fee1889 100644 --- a/WPDS/src/main/java/wpds/impl/NestedWeightedPAutomatons.java +++ b/WPDS/src/main/java/wpds/impl/NestedWeightedPAutomatons.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package wpds.impl; diff --git a/WPDS/src/main/java/wpds/impl/NoWeight.java b/WPDS/src/main/java/wpds/impl/NoWeight.java index 19368e6ef..8712bd659 100644 --- a/WPDS/src/main/java/wpds/impl/NoWeight.java +++ b/WPDS/src/main/java/wpds/impl/NoWeight.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package wpds.impl; diff --git a/WPDS/src/main/java/wpds/impl/NormalRule.java b/WPDS/src/main/java/wpds/impl/NormalRule.java index 68330d078..a53772283 100644 --- a/WPDS/src/main/java/wpds/impl/NormalRule.java +++ b/WPDS/src/main/java/wpds/impl/NormalRule.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package wpds.impl; diff --git a/WPDS/src/main/java/wpds/impl/PAutomaton.java b/WPDS/src/main/java/wpds/impl/PAutomaton.java index 4ac610679..ac961463d 100644 --- a/WPDS/src/main/java/wpds/impl/PAutomaton.java +++ b/WPDS/src/main/java/wpds/impl/PAutomaton.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package wpds.impl; diff --git a/WPDS/src/main/java/wpds/impl/PopRule.java b/WPDS/src/main/java/wpds/impl/PopRule.java index af9817447..8d1a6e135 100644 --- a/WPDS/src/main/java/wpds/impl/PopRule.java +++ b/WPDS/src/main/java/wpds/impl/PopRule.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package wpds.impl; diff --git a/WPDS/src/main/java/wpds/impl/PostStar.java b/WPDS/src/main/java/wpds/impl/PostStar.java index 3bf26d18c..4f5c112ad 100644 --- a/WPDS/src/main/java/wpds/impl/PostStar.java +++ b/WPDS/src/main/java/wpds/impl/PostStar.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package wpds.impl; diff --git a/WPDS/src/main/java/wpds/impl/PreStar.java b/WPDS/src/main/java/wpds/impl/PreStar.java index 476b4445a..c1960f9d5 100644 --- a/WPDS/src/main/java/wpds/impl/PreStar.java +++ b/WPDS/src/main/java/wpds/impl/PreStar.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package wpds.impl; diff --git a/WPDS/src/main/java/wpds/impl/PrefixImport.java b/WPDS/src/main/java/wpds/impl/PrefixImport.java index e4c71febd..400659055 100644 --- a/WPDS/src/main/java/wpds/impl/PrefixImport.java +++ b/WPDS/src/main/java/wpds/impl/PrefixImport.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package wpds.impl; diff --git a/WPDS/src/main/java/wpds/impl/PushRule.java b/WPDS/src/main/java/wpds/impl/PushRule.java index 248f8c530..9b3552105 100644 --- a/WPDS/src/main/java/wpds/impl/PushRule.java +++ b/WPDS/src/main/java/wpds/impl/PushRule.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package wpds.impl; diff --git a/WPDS/src/main/java/wpds/impl/PushdownSystem.java b/WPDS/src/main/java/wpds/impl/PushdownSystem.java index e1f97cd8a..df22a7b11 100644 --- a/WPDS/src/main/java/wpds/impl/PushdownSystem.java +++ b/WPDS/src/main/java/wpds/impl/PushdownSystem.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package wpds.impl; diff --git a/WPDS/src/main/java/wpds/impl/Rule.java b/WPDS/src/main/java/wpds/impl/Rule.java index 89f6f97ec..9f1e91617 100644 --- a/WPDS/src/main/java/wpds/impl/Rule.java +++ b/WPDS/src/main/java/wpds/impl/Rule.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package wpds.impl; diff --git a/WPDS/src/main/java/wpds/impl/StackListener.java b/WPDS/src/main/java/wpds/impl/StackListener.java index c47d33d34..54246592c 100644 --- a/WPDS/src/main/java/wpds/impl/StackListener.java +++ b/WPDS/src/main/java/wpds/impl/StackListener.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package wpds.impl; diff --git a/WPDS/src/main/java/wpds/impl/SummaryNestedWeightedPAutomatons.java b/WPDS/src/main/java/wpds/impl/SummaryNestedWeightedPAutomatons.java index 4d3f16d41..eb001677b 100644 --- a/WPDS/src/main/java/wpds/impl/SummaryNestedWeightedPAutomatons.java +++ b/WPDS/src/main/java/wpds/impl/SummaryNestedWeightedPAutomatons.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package wpds.impl; diff --git a/WPDS/src/main/java/wpds/impl/Transition.java b/WPDS/src/main/java/wpds/impl/Transition.java index 0af6a7e51..5828d7ade 100644 --- a/WPDS/src/main/java/wpds/impl/Transition.java +++ b/WPDS/src/main/java/wpds/impl/Transition.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package wpds.impl; diff --git a/WPDS/src/main/java/wpds/impl/UNormalRule.java b/WPDS/src/main/java/wpds/impl/UNormalRule.java index 2d90752a9..0205e7eea 100644 --- a/WPDS/src/main/java/wpds/impl/UNormalRule.java +++ b/WPDS/src/main/java/wpds/impl/UNormalRule.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package wpds.impl; diff --git a/WPDS/src/main/java/wpds/impl/UPopRule.java b/WPDS/src/main/java/wpds/impl/UPopRule.java index 0c7858420..31c174076 100644 --- a/WPDS/src/main/java/wpds/impl/UPopRule.java +++ b/WPDS/src/main/java/wpds/impl/UPopRule.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package wpds.impl; diff --git a/WPDS/src/main/java/wpds/impl/UPushRule.java b/WPDS/src/main/java/wpds/impl/UPushRule.java index cd494a3ba..79061cc13 100644 --- a/WPDS/src/main/java/wpds/impl/UPushRule.java +++ b/WPDS/src/main/java/wpds/impl/UPushRule.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package wpds.impl; diff --git a/WPDS/src/main/java/wpds/impl/UnbalancedPopListener.java b/WPDS/src/main/java/wpds/impl/UnbalancedPopListener.java index 781ca3ed3..0c32c6d80 100644 --- a/WPDS/src/main/java/wpds/impl/UnbalancedPopListener.java +++ b/WPDS/src/main/java/wpds/impl/UnbalancedPopListener.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package wpds.impl; diff --git a/WPDS/src/main/java/wpds/impl/Weight.java b/WPDS/src/main/java/wpds/impl/Weight.java index 5f749a16f..0006b177b 100644 --- a/WPDS/src/main/java/wpds/impl/Weight.java +++ b/WPDS/src/main/java/wpds/impl/Weight.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package wpds.impl; diff --git a/WPDS/src/main/java/wpds/impl/WeightedPAutomaton.java b/WPDS/src/main/java/wpds/impl/WeightedPAutomaton.java index ce9fc7985..65a5780ac 100644 --- a/WPDS/src/main/java/wpds/impl/WeightedPAutomaton.java +++ b/WPDS/src/main/java/wpds/impl/WeightedPAutomaton.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package wpds.impl; diff --git a/WPDS/src/main/java/wpds/impl/WeightedPushdownSystem.java b/WPDS/src/main/java/wpds/impl/WeightedPushdownSystem.java index b9853eea4..1c3948918 100644 --- a/WPDS/src/main/java/wpds/impl/WeightedPushdownSystem.java +++ b/WPDS/src/main/java/wpds/impl/WeightedPushdownSystem.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package wpds.impl; diff --git a/WPDS/src/main/java/wpds/interfaces/ForwardDFSEpsilonVisitor.java b/WPDS/src/main/java/wpds/interfaces/ForwardDFSEpsilonVisitor.java index 7fd7e442e..c9bcb0573 100644 --- a/WPDS/src/main/java/wpds/interfaces/ForwardDFSEpsilonVisitor.java +++ b/WPDS/src/main/java/wpds/interfaces/ForwardDFSEpsilonVisitor.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package wpds.interfaces; diff --git a/WPDS/src/main/java/wpds/interfaces/ForwardDFSVisitor.java b/WPDS/src/main/java/wpds/interfaces/ForwardDFSVisitor.java index d5cca1a3e..e1c603858 100644 --- a/WPDS/src/main/java/wpds/interfaces/ForwardDFSVisitor.java +++ b/WPDS/src/main/java/wpds/interfaces/ForwardDFSVisitor.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package wpds.interfaces; diff --git a/WPDS/src/main/java/wpds/interfaces/IPushdownSystem.java b/WPDS/src/main/java/wpds/interfaces/IPushdownSystem.java index 9b8a22474..bdb6ac3d9 100644 --- a/WPDS/src/main/java/wpds/interfaces/IPushdownSystem.java +++ b/WPDS/src/main/java/wpds/interfaces/IPushdownSystem.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package wpds.interfaces; diff --git a/WPDS/src/main/java/wpds/interfaces/ReachabilityListener.java b/WPDS/src/main/java/wpds/interfaces/ReachabilityListener.java index 820b97821..9047d1334 100644 --- a/WPDS/src/main/java/wpds/interfaces/ReachabilityListener.java +++ b/WPDS/src/main/java/wpds/interfaces/ReachabilityListener.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package wpds.interfaces; diff --git a/WPDS/src/main/java/wpds/interfaces/State.java b/WPDS/src/main/java/wpds/interfaces/State.java index 16b119ec7..61d900a5d 100644 --- a/WPDS/src/main/java/wpds/interfaces/State.java +++ b/WPDS/src/main/java/wpds/interfaces/State.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package wpds.interfaces; diff --git a/WPDS/src/main/java/wpds/interfaces/WPAStateListener.java b/WPDS/src/main/java/wpds/interfaces/WPAStateListener.java index d6ca41819..1ad33107b 100644 --- a/WPDS/src/main/java/wpds/interfaces/WPAStateListener.java +++ b/WPDS/src/main/java/wpds/interfaces/WPAStateListener.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package wpds.interfaces; diff --git a/WPDS/src/main/java/wpds/interfaces/WPAUpdateListener.java b/WPDS/src/main/java/wpds/interfaces/WPAUpdateListener.java index 1b70d96c9..88bc3980e 100644 --- a/WPDS/src/main/java/wpds/interfaces/WPAUpdateListener.java +++ b/WPDS/src/main/java/wpds/interfaces/WPAUpdateListener.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package wpds.interfaces; diff --git a/WPDS/src/main/java/wpds/interfaces/WPDSUpdateListener.java b/WPDS/src/main/java/wpds/interfaces/WPDSUpdateListener.java index ae9773129..01435574d 100644 --- a/WPDS/src/main/java/wpds/interfaces/WPDSUpdateListener.java +++ b/WPDS/src/main/java/wpds/interfaces/WPDSUpdateListener.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package wpds.interfaces; diff --git a/WPDS/src/main/java/wpds/wildcard/WildcardPushdownSystem.java b/WPDS/src/main/java/wpds/wildcard/WildcardPushdownSystem.java index 33d77e90f..5deaeb440 100644 --- a/WPDS/src/main/java/wpds/wildcard/WildcardPushdownSystem.java +++ b/WPDS/src/main/java/wpds/wildcard/WildcardPushdownSystem.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package wpds.wildcard; diff --git a/WPDS/src/test/java/tests/ForwardDFSVisitorTest.java b/WPDS/src/test/java/tests/ForwardDFSVisitorTest.java index cd24504b9..6d13877a8 100644 --- a/WPDS/src/test/java/tests/ForwardDFSVisitorTest.java +++ b/WPDS/src/test/java/tests/ForwardDFSVisitorTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package tests; diff --git a/WPDS/src/test/java/tests/MinSeminringPostStarTests.java b/WPDS/src/test/java/tests/MinSeminringPostStarTests.java index 5953049d1..b5114797e 100644 --- a/WPDS/src/test/java/tests/MinSeminringPostStarTests.java +++ b/WPDS/src/test/java/tests/MinSeminringPostStarTests.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package tests; diff --git a/WPDS/src/test/java/tests/MinSemiring.java b/WPDS/src/test/java/tests/MinSemiring.java index 5ec341977..8fe4728a3 100644 --- a/WPDS/src/test/java/tests/MinSemiring.java +++ b/WPDS/src/test/java/tests/MinSemiring.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package tests; diff --git a/WPDS/src/test/java/tests/NumWeight.java b/WPDS/src/test/java/tests/NumWeight.java index b940c3a5b..62218f5a5 100644 --- a/WPDS/src/test/java/tests/NumWeight.java +++ b/WPDS/src/test/java/tests/NumWeight.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package tests; diff --git a/WPDS/src/test/java/tests/NumWeightImpl.java b/WPDS/src/test/java/tests/NumWeightImpl.java index dbce9a1fb..eb0557fd8 100644 --- a/WPDS/src/test/java/tests/NumWeightImpl.java +++ b/WPDS/src/test/java/tests/NumWeightImpl.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package tests; diff --git a/WPDS/src/test/java/tests/NumWeightOne.java b/WPDS/src/test/java/tests/NumWeightOne.java index a32bbad59..9c1f81fab 100644 --- a/WPDS/src/test/java/tests/NumWeightOne.java +++ b/WPDS/src/test/java/tests/NumWeightOne.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package tests; diff --git a/WPDS/src/test/java/tests/NumWeightZero.java b/WPDS/src/test/java/tests/NumWeightZero.java index ab8bc3729..478daaf6d 100644 --- a/WPDS/src/test/java/tests/NumWeightZero.java +++ b/WPDS/src/test/java/tests/NumWeightZero.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package tests; diff --git a/WPDS/src/test/java/tests/PDSPoststarTests.java b/WPDS/src/test/java/tests/PDSPoststarTests.java index 246fff139..97b7a2f8a 100644 --- a/WPDS/src/test/java/tests/PDSPoststarTests.java +++ b/WPDS/src/test/java/tests/PDSPoststarTests.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package tests; diff --git a/WPDS/src/test/java/tests/PDSPrestarTests.java b/WPDS/src/test/java/tests/PDSPrestarTests.java index b744db00a..210ac0a8f 100644 --- a/WPDS/src/test/java/tests/PDSPrestarTests.java +++ b/WPDS/src/test/java/tests/PDSPrestarTests.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package tests; diff --git a/WPDS/src/test/java/tests/PrefixImportTests.java b/WPDS/src/test/java/tests/PrefixImportTests.java index 220fff2cd..0a158c031 100644 --- a/WPDS/src/test/java/tests/PrefixImportTests.java +++ b/WPDS/src/test/java/tests/PrefixImportTests.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package tests; diff --git a/WPDS/src/test/java/tests/SummaryPDSPostStarTests.java b/WPDS/src/test/java/tests/SummaryPDSPostStarTests.java index f6ab8c5eb..5e365dee3 100644 --- a/WPDS/src/test/java/tests/SummaryPDSPostStarTests.java +++ b/WPDS/src/test/java/tests/SummaryPDSPostStarTests.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package tests; diff --git a/WPDS/src/test/java/tests/TestHelper.java b/WPDS/src/test/java/tests/TestHelper.java index e946945ed..98f7e1b0f 100644 --- a/WPDS/src/test/java/tests/TestHelper.java +++ b/WPDS/src/test/java/tests/TestHelper.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package tests; diff --git a/WPDS/src/test/java/tests/WPDSPostStarTests.java b/WPDS/src/test/java/tests/WPDSPostStarTests.java index 2e7afdd08..acf3fbae2 100644 --- a/WPDS/src/test/java/tests/WPDSPostStarTests.java +++ b/WPDS/src/test/java/tests/WPDSPostStarTests.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package tests; diff --git a/WPDS/src/test/java/tests/WPDSPreStarTests.java b/WPDS/src/test/java/tests/WPDSPreStarTests.java index 866699724..058be73f9 100644 --- a/WPDS/src/test/java/tests/WPDSPreStarTests.java +++ b/WPDS/src/test/java/tests/WPDSPreStarTests.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package tests; diff --git a/boomerangPDS/src/main/java/boomerang/BackwardQuery.java b/boomerangPDS/src/main/java/boomerang/BackwardQuery.java index 687b6b218..0cc21f3bc 100644 --- a/boomerangPDS/src/main/java/boomerang/BackwardQuery.java +++ b/boomerangPDS/src/main/java/boomerang/BackwardQuery.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang; diff --git a/boomerangPDS/src/main/java/boomerang/Boomerang.java b/boomerangPDS/src/main/java/boomerang/Boomerang.java index 5a7ce08d2..95601eaa3 100644 --- a/boomerangPDS/src/main/java/boomerang/Boomerang.java +++ b/boomerangPDS/src/main/java/boomerang/Boomerang.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang; diff --git a/boomerangPDS/src/main/java/boomerang/BoomerangTimeoutException.java b/boomerangPDS/src/main/java/boomerang/BoomerangTimeoutException.java index fc8d24c79..e25895b3c 100644 --- a/boomerangPDS/src/main/java/boomerang/BoomerangTimeoutException.java +++ b/boomerangPDS/src/main/java/boomerang/BoomerangTimeoutException.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang; diff --git a/boomerangPDS/src/main/java/boomerang/Context.java b/boomerangPDS/src/main/java/boomerang/Context.java index 60ff9f7be..f72655aa1 100644 --- a/boomerangPDS/src/main/java/boomerang/Context.java +++ b/boomerangPDS/src/main/java/boomerang/Context.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang; diff --git a/boomerangPDS/src/main/java/boomerang/ForwardQuery.java b/boomerangPDS/src/main/java/boomerang/ForwardQuery.java index 7da9cd760..2d29a9d3c 100644 --- a/boomerangPDS/src/main/java/boomerang/ForwardQuery.java +++ b/boomerangPDS/src/main/java/boomerang/ForwardQuery.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang; diff --git a/boomerangPDS/src/main/java/boomerang/ForwardQueryArray.java b/boomerangPDS/src/main/java/boomerang/ForwardQueryArray.java index 085431880..8d722369e 100644 --- a/boomerangPDS/src/main/java/boomerang/ForwardQueryArray.java +++ b/boomerangPDS/src/main/java/boomerang/ForwardQueryArray.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang; diff --git a/boomerangPDS/src/main/java/boomerang/ForwardQueryMultiDimensionalArray.java b/boomerangPDS/src/main/java/boomerang/ForwardQueryMultiDimensionalArray.java index 3b6ffb36e..b30fc7bbb 100644 --- a/boomerangPDS/src/main/java/boomerang/ForwardQueryMultiDimensionalArray.java +++ b/boomerangPDS/src/main/java/boomerang/ForwardQueryMultiDimensionalArray.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang; diff --git a/boomerangPDS/src/main/java/boomerang/IContextRequester.java b/boomerangPDS/src/main/java/boomerang/IContextRequester.java index 58970dbf9..bd23bd84e 100644 --- a/boomerangPDS/src/main/java/boomerang/IContextRequester.java +++ b/boomerangPDS/src/main/java/boomerang/IContextRequester.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang; diff --git a/boomerangPDS/src/main/java/boomerang/MethodReachableQueue.java b/boomerangPDS/src/main/java/boomerang/MethodReachableQueue.java index b773cde4d..9ea1249de 100644 --- a/boomerangPDS/src/main/java/boomerang/MethodReachableQueue.java +++ b/boomerangPDS/src/main/java/boomerang/MethodReachableQueue.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang; diff --git a/boomerangPDS/src/main/java/boomerang/Query.java b/boomerangPDS/src/main/java/boomerang/Query.java index 73f6afcaf..818c8d383 100644 --- a/boomerangPDS/src/main/java/boomerang/Query.java +++ b/boomerangPDS/src/main/java/boomerang/Query.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang; diff --git a/boomerangPDS/src/main/java/boomerang/QueryGraph.java b/boomerangPDS/src/main/java/boomerang/QueryGraph.java index 182f389db..18e5880e9 100644 --- a/boomerangPDS/src/main/java/boomerang/QueryGraph.java +++ b/boomerangPDS/src/main/java/boomerang/QueryGraph.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang; diff --git a/boomerangPDS/src/main/java/boomerang/SolverCreationListener.java b/boomerangPDS/src/main/java/boomerang/SolverCreationListener.java index ecc83c03a..d31ed06d8 100644 --- a/boomerangPDS/src/main/java/boomerang/SolverCreationListener.java +++ b/boomerangPDS/src/main/java/boomerang/SolverCreationListener.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang; diff --git a/boomerangPDS/src/main/java/boomerang/Util.java b/boomerangPDS/src/main/java/boomerang/Util.java index e385697b9..fa2cbd110 100644 --- a/boomerangPDS/src/main/java/boomerang/Util.java +++ b/boomerangPDS/src/main/java/boomerang/Util.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang; diff --git a/boomerangPDS/src/main/java/boomerang/WeightedBoomerang.java b/boomerangPDS/src/main/java/boomerang/WeightedBoomerang.java index 7e3d00f67..5e1a77ed3 100644 --- a/boomerangPDS/src/main/java/boomerang/WeightedBoomerang.java +++ b/boomerangPDS/src/main/java/boomerang/WeightedBoomerang.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang; diff --git a/boomerangPDS/src/main/java/boomerang/WeightedForwardQuery.java b/boomerangPDS/src/main/java/boomerang/WeightedForwardQuery.java index 3b9eb80ca..6efde34b3 100644 --- a/boomerangPDS/src/main/java/boomerang/WeightedForwardQuery.java +++ b/boomerangPDS/src/main/java/boomerang/WeightedForwardQuery.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang; diff --git a/boomerangPDS/src/main/java/boomerang/WholeProgramBoomerang.java b/boomerangPDS/src/main/java/boomerang/WholeProgramBoomerang.java index a6f9857e1..80e496329 100644 --- a/boomerangPDS/src/main/java/boomerang/WholeProgramBoomerang.java +++ b/boomerangPDS/src/main/java/boomerang/WholeProgramBoomerang.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang; diff --git a/boomerangPDS/src/main/java/boomerang/arrays/ArrayHandlingStrategy.java b/boomerangPDS/src/main/java/boomerang/arrays/ArrayHandlingStrategy.java index 95671c374..48acce5f5 100644 --- a/boomerangPDS/src/main/java/boomerang/arrays/ArrayHandlingStrategy.java +++ b/boomerangPDS/src/main/java/boomerang/arrays/ArrayHandlingStrategy.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.arrays; diff --git a/boomerangPDS/src/main/java/boomerang/arrays/ArrayIndexInsensitiveStrategy.java b/boomerangPDS/src/main/java/boomerang/arrays/ArrayIndexInsensitiveStrategy.java index 5649f129f..b0f714fc5 100644 --- a/boomerangPDS/src/main/java/boomerang/arrays/ArrayIndexInsensitiveStrategy.java +++ b/boomerangPDS/src/main/java/boomerang/arrays/ArrayIndexInsensitiveStrategy.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.arrays; diff --git a/boomerangPDS/src/main/java/boomerang/arrays/ArrayIndexSensitiveStrategy.java b/boomerangPDS/src/main/java/boomerang/arrays/ArrayIndexSensitiveStrategy.java index 816744b3a..34a22c3ef 100644 --- a/boomerangPDS/src/main/java/boomerang/arrays/ArrayIndexSensitiveStrategy.java +++ b/boomerangPDS/src/main/java/boomerang/arrays/ArrayIndexSensitiveStrategy.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.arrays; diff --git a/boomerangPDS/src/main/java/boomerang/arrays/IgnoreArrayStrategy.java b/boomerangPDS/src/main/java/boomerang/arrays/IgnoreArrayStrategy.java index ba10c7c67..d5b9b48f0 100644 --- a/boomerangPDS/src/main/java/boomerang/arrays/IgnoreArrayStrategy.java +++ b/boomerangPDS/src/main/java/boomerang/arrays/IgnoreArrayStrategy.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.arrays; diff --git a/boomerangPDS/src/main/java/boomerang/callgraph/BackwardsObservableICFG.java b/boomerangPDS/src/main/java/boomerang/callgraph/BackwardsObservableICFG.java index 4cf6463df..2677e994b 100644 --- a/boomerangPDS/src/main/java/boomerang/callgraph/BackwardsObservableICFG.java +++ b/boomerangPDS/src/main/java/boomerang/callgraph/BackwardsObservableICFG.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.callgraph; diff --git a/boomerangPDS/src/main/java/boomerang/callgraph/BoomerangResolver.java b/boomerangPDS/src/main/java/boomerang/callgraph/BoomerangResolver.java index 4a611b68a..e8a835c90 100644 --- a/boomerangPDS/src/main/java/boomerang/callgraph/BoomerangResolver.java +++ b/boomerangPDS/src/main/java/boomerang/callgraph/BoomerangResolver.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.callgraph; diff --git a/boomerangPDS/src/main/java/boomerang/callgraph/CallGraphOptions.java b/boomerangPDS/src/main/java/boomerang/callgraph/CallGraphOptions.java index 88a889c85..a0e8e895c 100644 --- a/boomerangPDS/src/main/java/boomerang/callgraph/CallGraphOptions.java +++ b/boomerangPDS/src/main/java/boomerang/callgraph/CallGraphOptions.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.callgraph; diff --git a/boomerangPDS/src/main/java/boomerang/callgraph/CalleeListener.java b/boomerangPDS/src/main/java/boomerang/callgraph/CalleeListener.java index 378d3417d..a606d948b 100644 --- a/boomerangPDS/src/main/java/boomerang/callgraph/CalleeListener.java +++ b/boomerangPDS/src/main/java/boomerang/callgraph/CalleeListener.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.callgraph; diff --git a/boomerangPDS/src/main/java/boomerang/callgraph/CallerListener.java b/boomerangPDS/src/main/java/boomerang/callgraph/CallerListener.java index a3a8912bb..edda19f4c 100644 --- a/boomerangPDS/src/main/java/boomerang/callgraph/CallerListener.java +++ b/boomerangPDS/src/main/java/boomerang/callgraph/CallerListener.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.callgraph; diff --git a/boomerangPDS/src/main/java/boomerang/callgraph/ICallerCalleeResolutionStrategy.java b/boomerangPDS/src/main/java/boomerang/callgraph/ICallerCalleeResolutionStrategy.java index 7ff4c5087..7f07dc9ae 100644 --- a/boomerangPDS/src/main/java/boomerang/callgraph/ICallerCalleeResolutionStrategy.java +++ b/boomerangPDS/src/main/java/boomerang/callgraph/ICallerCalleeResolutionStrategy.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.callgraph; diff --git a/boomerangPDS/src/main/java/boomerang/callgraph/ObservableDynamicICFG.java b/boomerangPDS/src/main/java/boomerang/callgraph/ObservableDynamicICFG.java index bd3a7b832..a3e4dd7dc 100644 --- a/boomerangPDS/src/main/java/boomerang/callgraph/ObservableDynamicICFG.java +++ b/boomerangPDS/src/main/java/boomerang/callgraph/ObservableDynamicICFG.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.callgraph; diff --git a/boomerangPDS/src/main/java/boomerang/callgraph/ObservableICFG.java b/boomerangPDS/src/main/java/boomerang/callgraph/ObservableICFG.java index 4a33e93cd..dbd07dcd6 100644 --- a/boomerangPDS/src/main/java/boomerang/callgraph/ObservableICFG.java +++ b/boomerangPDS/src/main/java/boomerang/callgraph/ObservableICFG.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.callgraph; diff --git a/boomerangPDS/src/main/java/boomerang/callgraph/ObservableStaticICFG.java b/boomerangPDS/src/main/java/boomerang/callgraph/ObservableStaticICFG.java index 2d228c6cd..a917c0340 100644 --- a/boomerangPDS/src/main/java/boomerang/callgraph/ObservableStaticICFG.java +++ b/boomerangPDS/src/main/java/boomerang/callgraph/ObservableStaticICFG.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.callgraph; diff --git a/boomerangPDS/src/main/java/boomerang/controlflowgraph/DynamicCFG.java b/boomerangPDS/src/main/java/boomerang/controlflowgraph/DynamicCFG.java index e89b59386..6b503cfde 100644 --- a/boomerangPDS/src/main/java/boomerang/controlflowgraph/DynamicCFG.java +++ b/boomerangPDS/src/main/java/boomerang/controlflowgraph/DynamicCFG.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.controlflowgraph; diff --git a/boomerangPDS/src/main/java/boomerang/controlflowgraph/ForwardSolverSuccessorListener.java b/boomerangPDS/src/main/java/boomerang/controlflowgraph/ForwardSolverSuccessorListener.java index 5fd166c1c..9a327ad10 100644 --- a/boomerangPDS/src/main/java/boomerang/controlflowgraph/ForwardSolverSuccessorListener.java +++ b/boomerangPDS/src/main/java/boomerang/controlflowgraph/ForwardSolverSuccessorListener.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.controlflowgraph; diff --git a/boomerangPDS/src/main/java/boomerang/controlflowgraph/ObservableControlFlowGraph.java b/boomerangPDS/src/main/java/boomerang/controlflowgraph/ObservableControlFlowGraph.java index 5476bdae5..5d164dc63 100644 --- a/boomerangPDS/src/main/java/boomerang/controlflowgraph/ObservableControlFlowGraph.java +++ b/boomerangPDS/src/main/java/boomerang/controlflowgraph/ObservableControlFlowGraph.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.controlflowgraph; diff --git a/boomerangPDS/src/main/java/boomerang/controlflowgraph/PredecessorListener.java b/boomerangPDS/src/main/java/boomerang/controlflowgraph/PredecessorListener.java index 33e00fb24..6e15677b1 100644 --- a/boomerangPDS/src/main/java/boomerang/controlflowgraph/PredecessorListener.java +++ b/boomerangPDS/src/main/java/boomerang/controlflowgraph/PredecessorListener.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.controlflowgraph; diff --git a/boomerangPDS/src/main/java/boomerang/controlflowgraph/StaticCFG.java b/boomerangPDS/src/main/java/boomerang/controlflowgraph/StaticCFG.java index 128b86ce1..9f2fcbe20 100644 --- a/boomerangPDS/src/main/java/boomerang/controlflowgraph/StaticCFG.java +++ b/boomerangPDS/src/main/java/boomerang/controlflowgraph/StaticCFG.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.controlflowgraph; diff --git a/boomerangPDS/src/main/java/boomerang/controlflowgraph/SuccessorListener.java b/boomerangPDS/src/main/java/boomerang/controlflowgraph/SuccessorListener.java index e99ac85c6..b57aacfde 100644 --- a/boomerangPDS/src/main/java/boomerang/controlflowgraph/SuccessorListener.java +++ b/boomerangPDS/src/main/java/boomerang/controlflowgraph/SuccessorListener.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.controlflowgraph; diff --git a/boomerangPDS/src/main/java/boomerang/debugger/CallGraphDebugger.java b/boomerangPDS/src/main/java/boomerang/debugger/CallGraphDebugger.java index 7bcc1a113..78eade4f6 100644 --- a/boomerangPDS/src/main/java/boomerang/debugger/CallGraphDebugger.java +++ b/boomerangPDS/src/main/java/boomerang/debugger/CallGraphDebugger.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.debugger; diff --git a/boomerangPDS/src/main/java/boomerang/debugger/ConsoleDebugger.java b/boomerangPDS/src/main/java/boomerang/debugger/ConsoleDebugger.java index c79dd3582..4efb73649 100644 --- a/boomerangPDS/src/main/java/boomerang/debugger/ConsoleDebugger.java +++ b/boomerangPDS/src/main/java/boomerang/debugger/ConsoleDebugger.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.debugger; diff --git a/boomerangPDS/src/main/java/boomerang/debugger/Debugger.java b/boomerangPDS/src/main/java/boomerang/debugger/Debugger.java index 36a98654e..b6899d890 100644 --- a/boomerangPDS/src/main/java/boomerang/debugger/Debugger.java +++ b/boomerangPDS/src/main/java/boomerang/debugger/Debugger.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.debugger; diff --git a/boomerangPDS/src/main/java/boomerang/debugger/IDEVizDebugger.java b/boomerangPDS/src/main/java/boomerang/debugger/IDEVizDebugger.java index 7835c4ff1..85cdffda0 100644 --- a/boomerangPDS/src/main/java/boomerang/debugger/IDEVizDebugger.java +++ b/boomerangPDS/src/main/java/boomerang/debugger/IDEVizDebugger.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.debugger; diff --git a/boomerangPDS/src/main/java/boomerang/example/BoomerangExampleTarget1.java b/boomerangPDS/src/main/java/boomerang/example/BoomerangExampleTarget1.java index be5e8b510..ca2d3a4dd 100644 --- a/boomerangPDS/src/main/java/boomerang/example/BoomerangExampleTarget1.java +++ b/boomerangPDS/src/main/java/boomerang/example/BoomerangExampleTarget1.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.example; diff --git a/boomerangPDS/src/main/java/boomerang/example/BoomerangExampleTarget2.java b/boomerangPDS/src/main/java/boomerang/example/BoomerangExampleTarget2.java index 1a76c374b..1313f079f 100644 --- a/boomerangPDS/src/main/java/boomerang/example/BoomerangExampleTarget2.java +++ b/boomerangPDS/src/main/java/boomerang/example/BoomerangExampleTarget2.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.example; diff --git a/boomerangPDS/src/main/java/boomerang/flowfunction/DefaultBackwardFlowFunction.java b/boomerangPDS/src/main/java/boomerang/flowfunction/DefaultBackwardFlowFunction.java index 9d1eba996..5121a6cb1 100644 --- a/boomerangPDS/src/main/java/boomerang/flowfunction/DefaultBackwardFlowFunction.java +++ b/boomerangPDS/src/main/java/boomerang/flowfunction/DefaultBackwardFlowFunction.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.flowfunction; diff --git a/boomerangPDS/src/main/java/boomerang/flowfunction/DefaultBackwardFlowFunctionOptions.java b/boomerangPDS/src/main/java/boomerang/flowfunction/DefaultBackwardFlowFunctionOptions.java index 610904771..5124215b1 100644 --- a/boomerangPDS/src/main/java/boomerang/flowfunction/DefaultBackwardFlowFunctionOptions.java +++ b/boomerangPDS/src/main/java/boomerang/flowfunction/DefaultBackwardFlowFunctionOptions.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.flowfunction; diff --git a/boomerangPDS/src/main/java/boomerang/flowfunction/DefaultForwardFlowFunction.java b/boomerangPDS/src/main/java/boomerang/flowfunction/DefaultForwardFlowFunction.java index 07c792169..84381165f 100644 --- a/boomerangPDS/src/main/java/boomerang/flowfunction/DefaultForwardFlowFunction.java +++ b/boomerangPDS/src/main/java/boomerang/flowfunction/DefaultForwardFlowFunction.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.flowfunction; diff --git a/boomerangPDS/src/main/java/boomerang/flowfunction/DefaultForwardFlowFunctionOptions.java b/boomerangPDS/src/main/java/boomerang/flowfunction/DefaultForwardFlowFunctionOptions.java index 02645481e..c1fb04b7b 100644 --- a/boomerangPDS/src/main/java/boomerang/flowfunction/DefaultForwardFlowFunctionOptions.java +++ b/boomerangPDS/src/main/java/boomerang/flowfunction/DefaultForwardFlowFunctionOptions.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.flowfunction; diff --git a/boomerangPDS/src/main/java/boomerang/flowfunction/FlowFunctionUtils.java b/boomerangPDS/src/main/java/boomerang/flowfunction/FlowFunctionUtils.java index 3e8eae476..93f7c1654 100644 --- a/boomerangPDS/src/main/java/boomerang/flowfunction/FlowFunctionUtils.java +++ b/boomerangPDS/src/main/java/boomerang/flowfunction/FlowFunctionUtils.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.flowfunction; diff --git a/boomerangPDS/src/main/java/boomerang/flowfunction/IBackwardFlowFunction.java b/boomerangPDS/src/main/java/boomerang/flowfunction/IBackwardFlowFunction.java index 9b86aa928..365b77990 100644 --- a/boomerangPDS/src/main/java/boomerang/flowfunction/IBackwardFlowFunction.java +++ b/boomerangPDS/src/main/java/boomerang/flowfunction/IBackwardFlowFunction.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.flowfunction; diff --git a/boomerangPDS/src/main/java/boomerang/flowfunction/IForwardFlowFunction.java b/boomerangPDS/src/main/java/boomerang/flowfunction/IForwardFlowFunction.java index 97ac1116e..455732fd4 100644 --- a/boomerangPDS/src/main/java/boomerang/flowfunction/IForwardFlowFunction.java +++ b/boomerangPDS/src/main/java/boomerang/flowfunction/IForwardFlowFunction.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.flowfunction; diff --git a/boomerangPDS/src/main/java/boomerang/guided/DemandDrivenGuidedAnalysis.java b/boomerangPDS/src/main/java/boomerang/guided/DemandDrivenGuidedAnalysis.java index aac473091..aeea462e2 100644 --- a/boomerangPDS/src/main/java/boomerang/guided/DemandDrivenGuidedAnalysis.java +++ b/boomerangPDS/src/main/java/boomerang/guided/DemandDrivenGuidedAnalysis.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.guided; diff --git a/boomerangPDS/src/main/java/boomerang/guided/IDemandDrivenGuidedManager.java b/boomerangPDS/src/main/java/boomerang/guided/IDemandDrivenGuidedManager.java index 4a70c5b58..bc28b5728 100644 --- a/boomerangPDS/src/main/java/boomerang/guided/IDemandDrivenGuidedManager.java +++ b/boomerangPDS/src/main/java/boomerang/guided/IDemandDrivenGuidedManager.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.guided; diff --git a/boomerangPDS/src/main/java/boomerang/guided/SimpleSpecificationGuidedManager.java b/boomerangPDS/src/main/java/boomerang/guided/SimpleSpecificationGuidedManager.java index 727085a4a..10b710b26 100644 --- a/boomerangPDS/src/main/java/boomerang/guided/SimpleSpecificationGuidedManager.java +++ b/boomerangPDS/src/main/java/boomerang/guided/SimpleSpecificationGuidedManager.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.guided; diff --git a/boomerangPDS/src/main/java/boomerang/guided/Specification.java b/boomerangPDS/src/main/java/boomerang/guided/Specification.java index 13c38c8a4..58be8397f 100644 --- a/boomerangPDS/src/main/java/boomerang/guided/Specification.java +++ b/boomerangPDS/src/main/java/boomerang/guided/Specification.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.guided; diff --git a/boomerangPDS/src/main/java/boomerang/options/BoomerangOptions.java b/boomerangPDS/src/main/java/boomerang/options/BoomerangOptions.java index c4341691f..c72a128ff 100644 --- a/boomerangPDS/src/main/java/boomerang/options/BoomerangOptions.java +++ b/boomerangPDS/src/main/java/boomerang/options/BoomerangOptions.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.options; diff --git a/boomerangPDS/src/main/java/boomerang/options/DefaultAllocationSite.java b/boomerangPDS/src/main/java/boomerang/options/DefaultAllocationSite.java index c9f8b1f1d..52c4f2fd6 100644 --- a/boomerangPDS/src/main/java/boomerang/options/DefaultAllocationSite.java +++ b/boomerangPDS/src/main/java/boomerang/options/DefaultAllocationSite.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.options; diff --git a/boomerangPDS/src/main/java/boomerang/options/IAllocationSite.java b/boomerangPDS/src/main/java/boomerang/options/IAllocationSite.java index 9baf3ed12..1dc143f5f 100644 --- a/boomerangPDS/src/main/java/boomerang/options/IAllocationSite.java +++ b/boomerangPDS/src/main/java/boomerang/options/IAllocationSite.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.options; diff --git a/boomerangPDS/src/main/java/boomerang/options/IntAndStringAllocationSite.java b/boomerangPDS/src/main/java/boomerang/options/IntAndStringAllocationSite.java index 8f7567a47..55d7355df 100644 --- a/boomerangPDS/src/main/java/boomerang/options/IntAndStringAllocationSite.java +++ b/boomerangPDS/src/main/java/boomerang/options/IntAndStringAllocationSite.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.options; diff --git a/boomerangPDS/src/main/java/boomerang/poi/AbstractPOI.java b/boomerangPDS/src/main/java/boomerang/poi/AbstractPOI.java index 4baf8b1ae..eba7850dd 100644 --- a/boomerangPDS/src/main/java/boomerang/poi/AbstractPOI.java +++ b/boomerangPDS/src/main/java/boomerang/poi/AbstractPOI.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.poi; diff --git a/boomerangPDS/src/main/java/boomerang/poi/CopyAccessPathChain.java b/boomerangPDS/src/main/java/boomerang/poi/CopyAccessPathChain.java index 27466111a..b9948b7ad 100644 --- a/boomerangPDS/src/main/java/boomerang/poi/CopyAccessPathChain.java +++ b/boomerangPDS/src/main/java/boomerang/poi/CopyAccessPathChain.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.poi; diff --git a/boomerangPDS/src/main/java/boomerang/poi/ExecuteImportFieldStmtPOI.java b/boomerangPDS/src/main/java/boomerang/poi/ExecuteImportFieldStmtPOI.java index 26b2ebe39..1ba9a4211 100644 --- a/boomerangPDS/src/main/java/boomerang/poi/ExecuteImportFieldStmtPOI.java +++ b/boomerangPDS/src/main/java/boomerang/poi/ExecuteImportFieldStmtPOI.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.poi; diff --git a/boomerangPDS/src/main/java/boomerang/poi/PointOfIndirection.java b/boomerangPDS/src/main/java/boomerang/poi/PointOfIndirection.java index 1e4364bcb..86c39d007 100644 --- a/boomerangPDS/src/main/java/boomerang/poi/PointOfIndirection.java +++ b/boomerangPDS/src/main/java/boomerang/poi/PointOfIndirection.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.poi; diff --git a/boomerangPDS/src/main/java/boomerang/results/AbstractBoomerangResults.java b/boomerangPDS/src/main/java/boomerang/results/AbstractBoomerangResults.java index 27b3e6658..f5c2cfc40 100644 --- a/boomerangPDS/src/main/java/boomerang/results/AbstractBoomerangResults.java +++ b/boomerangPDS/src/main/java/boomerang/results/AbstractBoomerangResults.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.results; diff --git a/boomerangPDS/src/main/java/boomerang/results/AffectedLocation.java b/boomerangPDS/src/main/java/boomerang/results/AffectedLocation.java index 66e904b3c..b5ad75ad3 100644 --- a/boomerangPDS/src/main/java/boomerang/results/AffectedLocation.java +++ b/boomerangPDS/src/main/java/boomerang/results/AffectedLocation.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.results; diff --git a/boomerangPDS/src/main/java/boomerang/results/BackwardBoomerangResults.java b/boomerangPDS/src/main/java/boomerang/results/BackwardBoomerangResults.java index d19e15a79..1359d8254 100644 --- a/boomerangPDS/src/main/java/boomerang/results/BackwardBoomerangResults.java +++ b/boomerangPDS/src/main/java/boomerang/results/BackwardBoomerangResults.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.results; diff --git a/boomerangPDS/src/main/java/boomerang/results/ExtractAllAliasListener.java b/boomerangPDS/src/main/java/boomerang/results/ExtractAllAliasListener.java index 7883cb2cc..2882b2064 100644 --- a/boomerangPDS/src/main/java/boomerang/results/ExtractAllAliasListener.java +++ b/boomerangPDS/src/main/java/boomerang/results/ExtractAllAliasListener.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.results; diff --git a/boomerangPDS/src/main/java/boomerang/results/ExtractAllocationSiteStateListener.java b/boomerangPDS/src/main/java/boomerang/results/ExtractAllocationSiteStateListener.java index f86b6c32d..895b15d6f 100644 --- a/boomerangPDS/src/main/java/boomerang/results/ExtractAllocationSiteStateListener.java +++ b/boomerangPDS/src/main/java/boomerang/results/ExtractAllocationSiteStateListener.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.results; diff --git a/boomerangPDS/src/main/java/boomerang/results/ForwardBoomerangResults.java b/boomerangPDS/src/main/java/boomerang/results/ForwardBoomerangResults.java index 7929a6d60..a74c3ed61 100644 --- a/boomerangPDS/src/main/java/boomerang/results/ForwardBoomerangResults.java +++ b/boomerangPDS/src/main/java/boomerang/results/ForwardBoomerangResults.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.results; diff --git a/boomerangPDS/src/main/java/boomerang/results/NullPointerDereference.java b/boomerangPDS/src/main/java/boomerang/results/NullPointerDereference.java index c50340c1b..9626c8fff 100644 --- a/boomerangPDS/src/main/java/boomerang/results/NullPointerDereference.java +++ b/boomerangPDS/src/main/java/boomerang/results/NullPointerDereference.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.results; diff --git a/boomerangPDS/src/main/java/boomerang/results/PathElement.java b/boomerangPDS/src/main/java/boomerang/results/PathElement.java index bb34b8086..1e6548c04 100644 --- a/boomerangPDS/src/main/java/boomerang/results/PathElement.java +++ b/boomerangPDS/src/main/java/boomerang/results/PathElement.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.results; diff --git a/boomerangPDS/src/main/java/boomerang/results/QueryResults.java b/boomerangPDS/src/main/java/boomerang/results/QueryResults.java index e6a50e1a6..11d236622 100644 --- a/boomerangPDS/src/main/java/boomerang/results/QueryResults.java +++ b/boomerangPDS/src/main/java/boomerang/results/QueryResults.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.results; diff --git a/boomerangPDS/src/main/java/boomerang/scope/AccessPathParser.java b/boomerangPDS/src/main/java/boomerang/scope/AccessPathParser.java index 91056902d..5d1be8301 100644 --- a/boomerangPDS/src/main/java/boomerang/scope/AccessPathParser.java +++ b/boomerangPDS/src/main/java/boomerang/scope/AccessPathParser.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope; diff --git a/boomerangPDS/src/main/java/boomerang/scope/AnalysisScope.java b/boomerangPDS/src/main/java/boomerang/scope/AnalysisScope.java index 793b8756a..d6022b1e0 100644 --- a/boomerangPDS/src/main/java/boomerang/scope/AnalysisScope.java +++ b/boomerangPDS/src/main/java/boomerang/scope/AnalysisScope.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope; diff --git a/boomerangPDS/src/main/java/boomerang/solver/AbstractBoomerangSolver.java b/boomerangPDS/src/main/java/boomerang/solver/AbstractBoomerangSolver.java index fec9f4de9..8ca58b0da 100644 --- a/boomerangPDS/src/main/java/boomerang/solver/AbstractBoomerangSolver.java +++ b/boomerangPDS/src/main/java/boomerang/solver/AbstractBoomerangSolver.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.solver; diff --git a/boomerangPDS/src/main/java/boomerang/solver/AllocationTypeListener.java b/boomerangPDS/src/main/java/boomerang/solver/AllocationTypeListener.java index bb3eb462a..36c2ebbc6 100644 --- a/boomerangPDS/src/main/java/boomerang/solver/AllocationTypeListener.java +++ b/boomerangPDS/src/main/java/boomerang/solver/AllocationTypeListener.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.solver; diff --git a/boomerangPDS/src/main/java/boomerang/solver/BackwardBoomerangSolver.java b/boomerangPDS/src/main/java/boomerang/solver/BackwardBoomerangSolver.java index 3e8691e92..c79c252e5 100644 --- a/boomerangPDS/src/main/java/boomerang/solver/BackwardBoomerangSolver.java +++ b/boomerangPDS/src/main/java/boomerang/solver/BackwardBoomerangSolver.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.solver; diff --git a/boomerangPDS/src/main/java/boomerang/solver/ControlFlowEdgeBasedCallTransitionListener.java b/boomerangPDS/src/main/java/boomerang/solver/ControlFlowEdgeBasedCallTransitionListener.java index 4d3bbe1c0..8de6681e0 100644 --- a/boomerangPDS/src/main/java/boomerang/solver/ControlFlowEdgeBasedCallTransitionListener.java +++ b/boomerangPDS/src/main/java/boomerang/solver/ControlFlowEdgeBasedCallTransitionListener.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.solver; diff --git a/boomerangPDS/src/main/java/boomerang/solver/ControlFlowEdgeBasedFieldTransitionListener.java b/boomerangPDS/src/main/java/boomerang/solver/ControlFlowEdgeBasedFieldTransitionListener.java index 34c9687c3..8bb664147 100644 --- a/boomerangPDS/src/main/java/boomerang/solver/ControlFlowEdgeBasedFieldTransitionListener.java +++ b/boomerangPDS/src/main/java/boomerang/solver/ControlFlowEdgeBasedFieldTransitionListener.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.solver; diff --git a/boomerangPDS/src/main/java/boomerang/solver/ForwardBoomerangSolver.java b/boomerangPDS/src/main/java/boomerang/solver/ForwardBoomerangSolver.java index 953551949..f825434ff 100644 --- a/boomerangPDS/src/main/java/boomerang/solver/ForwardBoomerangSolver.java +++ b/boomerangPDS/src/main/java/boomerang/solver/ForwardBoomerangSolver.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.solver; diff --git a/boomerangPDS/src/main/java/boomerang/solver/MethodBasedFieldTransitionListener.java b/boomerangPDS/src/main/java/boomerang/solver/MethodBasedFieldTransitionListener.java index 3bfb18105..9fb9d706e 100644 --- a/boomerangPDS/src/main/java/boomerang/solver/MethodBasedFieldTransitionListener.java +++ b/boomerangPDS/src/main/java/boomerang/solver/MethodBasedFieldTransitionListener.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.solver; diff --git a/boomerangPDS/src/main/java/boomerang/solver/ReachableMethodListener.java b/boomerangPDS/src/main/java/boomerang/solver/ReachableMethodListener.java index 88164c547..f6692144e 100644 --- a/boomerangPDS/src/main/java/boomerang/solver/ReachableMethodListener.java +++ b/boomerangPDS/src/main/java/boomerang/solver/ReachableMethodListener.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.solver; diff --git a/boomerangPDS/src/main/java/boomerang/solver/Strategies.java b/boomerangPDS/src/main/java/boomerang/solver/Strategies.java index 0357a99b2..73359ac8d 100644 --- a/boomerangPDS/src/main/java/boomerang/solver/Strategies.java +++ b/boomerangPDS/src/main/java/boomerang/solver/Strategies.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.solver; diff --git a/boomerangPDS/src/main/java/boomerang/staticfields/FlowSensitiveStaticFieldStrategy.java b/boomerangPDS/src/main/java/boomerang/staticfields/FlowSensitiveStaticFieldStrategy.java index c8a3145fd..f8c0cd393 100644 --- a/boomerangPDS/src/main/java/boomerang/staticfields/FlowSensitiveStaticFieldStrategy.java +++ b/boomerangPDS/src/main/java/boomerang/staticfields/FlowSensitiveStaticFieldStrategy.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.staticfields; diff --git a/boomerangPDS/src/main/java/boomerang/staticfields/IgnoreStaticFieldStrategy.java b/boomerangPDS/src/main/java/boomerang/staticfields/IgnoreStaticFieldStrategy.java index 07ec4c162..462d1533a 100644 --- a/boomerangPDS/src/main/java/boomerang/staticfields/IgnoreStaticFieldStrategy.java +++ b/boomerangPDS/src/main/java/boomerang/staticfields/IgnoreStaticFieldStrategy.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.staticfields; diff --git a/boomerangPDS/src/main/java/boomerang/staticfields/SingletonStaticFieldStrategy.java b/boomerangPDS/src/main/java/boomerang/staticfields/SingletonStaticFieldStrategy.java index c372e3e88..08194baa8 100644 --- a/boomerangPDS/src/main/java/boomerang/staticfields/SingletonStaticFieldStrategy.java +++ b/boomerangPDS/src/main/java/boomerang/staticfields/SingletonStaticFieldStrategy.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.staticfields; diff --git a/boomerangPDS/src/main/java/boomerang/staticfields/StaticFieldHandlingStrategy.java b/boomerangPDS/src/main/java/boomerang/staticfields/StaticFieldHandlingStrategy.java index c675f011a..96dc9ae5c 100644 --- a/boomerangPDS/src/main/java/boomerang/staticfields/StaticFieldHandlingStrategy.java +++ b/boomerangPDS/src/main/java/boomerang/staticfields/StaticFieldHandlingStrategy.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.staticfields; diff --git a/boomerangPDS/src/main/java/boomerang/stats/AdvancedBoomerangStats.java b/boomerangPDS/src/main/java/boomerang/stats/AdvancedBoomerangStats.java index ff9234430..683280768 100644 --- a/boomerangPDS/src/main/java/boomerang/stats/AdvancedBoomerangStats.java +++ b/boomerangPDS/src/main/java/boomerang/stats/AdvancedBoomerangStats.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.stats; diff --git a/boomerangPDS/src/main/java/boomerang/stats/CSVBoomerangStatsWriter.java b/boomerangPDS/src/main/java/boomerang/stats/CSVBoomerangStatsWriter.java index 9ae173692..c084e76fe 100644 --- a/boomerangPDS/src/main/java/boomerang/stats/CSVBoomerangStatsWriter.java +++ b/boomerangPDS/src/main/java/boomerang/stats/CSVBoomerangStatsWriter.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.stats; diff --git a/boomerangPDS/src/main/java/boomerang/stats/IBoomerangStats.java b/boomerangPDS/src/main/java/boomerang/stats/IBoomerangStats.java index c4c2c4f8b..a44754416 100644 --- a/boomerangPDS/src/main/java/boomerang/stats/IBoomerangStats.java +++ b/boomerangPDS/src/main/java/boomerang/stats/IBoomerangStats.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.stats; diff --git a/boomerangPDS/src/main/java/boomerang/stats/SimpleBoomerangStats.java b/boomerangPDS/src/main/java/boomerang/stats/SimpleBoomerangStats.java index c8c5e70e1..73d80791e 100644 --- a/boomerangPDS/src/main/java/boomerang/stats/SimpleBoomerangStats.java +++ b/boomerangPDS/src/main/java/boomerang/stats/SimpleBoomerangStats.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.stats; diff --git a/boomerangPDS/src/main/java/boomerang/util/AccessPath.java b/boomerangPDS/src/main/java/boomerang/util/AccessPath.java index ec333d1b8..8840ffd71 100644 --- a/boomerangPDS/src/main/java/boomerang/util/AccessPath.java +++ b/boomerangPDS/src/main/java/boomerang/util/AccessPath.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.util; diff --git a/boomerangPDS/src/main/java/boomerang/util/DefaultValueMap.java b/boomerangPDS/src/main/java/boomerang/util/DefaultValueMap.java index 6718f0340..5ce928d15 100644 --- a/boomerangPDS/src/main/java/boomerang/util/DefaultValueMap.java +++ b/boomerangPDS/src/main/java/boomerang/util/DefaultValueMap.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.util; diff --git a/boomerangPDS/src/main/java/boomerang/util/RegExAccessPath.java b/boomerangPDS/src/main/java/boomerang/util/RegExAccessPath.java index 02178421d..f622930ee 100644 --- a/boomerangPDS/src/main/java/boomerang/util/RegExAccessPath.java +++ b/boomerangPDS/src/main/java/boomerang/util/RegExAccessPath.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.util; diff --git a/boomerangPDS/src/main/java/boomerang/weights/DataFlowPathWeight.java b/boomerangPDS/src/main/java/boomerang/weights/DataFlowPathWeight.java index 7b049c4fe..a32e49eca 100644 --- a/boomerangPDS/src/main/java/boomerang/weights/DataFlowPathWeight.java +++ b/boomerangPDS/src/main/java/boomerang/weights/DataFlowPathWeight.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.weights; diff --git a/boomerangPDS/src/main/java/boomerang/weights/DataFlowPathWeightImpl.java b/boomerangPDS/src/main/java/boomerang/weights/DataFlowPathWeightImpl.java index b5c5b7250..b51b2a8d3 100644 --- a/boomerangPDS/src/main/java/boomerang/weights/DataFlowPathWeightImpl.java +++ b/boomerangPDS/src/main/java/boomerang/weights/DataFlowPathWeightImpl.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.weights; diff --git a/boomerangPDS/src/main/java/boomerang/weights/DataFlowPathWeightOne.java b/boomerangPDS/src/main/java/boomerang/weights/DataFlowPathWeightOne.java index 37f807150..4d11722d9 100644 --- a/boomerangPDS/src/main/java/boomerang/weights/DataFlowPathWeightOne.java +++ b/boomerangPDS/src/main/java/boomerang/weights/DataFlowPathWeightOne.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.weights; diff --git a/boomerangPDS/src/main/java/boomerang/weights/MinDistanceWeight.java b/boomerangPDS/src/main/java/boomerang/weights/MinDistanceWeight.java index 173187c84..15767139c 100644 --- a/boomerangPDS/src/main/java/boomerang/weights/MinDistanceWeight.java +++ b/boomerangPDS/src/main/java/boomerang/weights/MinDistanceWeight.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.weights; diff --git a/boomerangPDS/src/main/java/boomerang/weights/MinDistanceWeightFunctions.java b/boomerangPDS/src/main/java/boomerang/weights/MinDistanceWeightFunctions.java index 784c83da2..c66f2c109 100644 --- a/boomerangPDS/src/main/java/boomerang/weights/MinDistanceWeightFunctions.java +++ b/boomerangPDS/src/main/java/boomerang/weights/MinDistanceWeightFunctions.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.weights; diff --git a/boomerangPDS/src/main/java/boomerang/weights/MinDistanceWeightImpl.java b/boomerangPDS/src/main/java/boomerang/weights/MinDistanceWeightImpl.java index 930af2a17..08ddf4e68 100644 --- a/boomerangPDS/src/main/java/boomerang/weights/MinDistanceWeightImpl.java +++ b/boomerangPDS/src/main/java/boomerang/weights/MinDistanceWeightImpl.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.weights; diff --git a/boomerangPDS/src/main/java/boomerang/weights/MinDistanceWeightOne.java b/boomerangPDS/src/main/java/boomerang/weights/MinDistanceWeightOne.java index 67ab7c488..5dfcfd677 100644 --- a/boomerangPDS/src/main/java/boomerang/weights/MinDistanceWeightOne.java +++ b/boomerangPDS/src/main/java/boomerang/weights/MinDistanceWeightOne.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.weights; diff --git a/boomerangPDS/src/main/java/boomerang/weights/PathConditionWeight.java b/boomerangPDS/src/main/java/boomerang/weights/PathConditionWeight.java index 0b072a42d..18534574f 100644 --- a/boomerangPDS/src/main/java/boomerang/weights/PathConditionWeight.java +++ b/boomerangPDS/src/main/java/boomerang/weights/PathConditionWeight.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.weights; diff --git a/boomerangPDS/src/main/java/boomerang/weights/PathConditionWeightImpl.java b/boomerangPDS/src/main/java/boomerang/weights/PathConditionWeightImpl.java index c061f183e..904199563 100644 --- a/boomerangPDS/src/main/java/boomerang/weights/PathConditionWeightImpl.java +++ b/boomerangPDS/src/main/java/boomerang/weights/PathConditionWeightImpl.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.weights; diff --git a/boomerangPDS/src/main/java/boomerang/weights/PathConditionWeightOne.java b/boomerangPDS/src/main/java/boomerang/weights/PathConditionWeightOne.java index 0bfcbd65a..dad7ea251 100644 --- a/boomerangPDS/src/main/java/boomerang/weights/PathConditionWeightOne.java +++ b/boomerangPDS/src/main/java/boomerang/weights/PathConditionWeightOne.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.weights; diff --git a/boomerangPDS/src/main/java/boomerang/weights/PathTrackingBoomerang.java b/boomerangPDS/src/main/java/boomerang/weights/PathTrackingBoomerang.java index c604a3bb0..3aa870ec5 100644 --- a/boomerangPDS/src/main/java/boomerang/weights/PathTrackingBoomerang.java +++ b/boomerangPDS/src/main/java/boomerang/weights/PathTrackingBoomerang.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.weights; diff --git a/boomerangPDS/src/main/java/boomerang/weights/PathTrackingWeight.java b/boomerangPDS/src/main/java/boomerang/weights/PathTrackingWeight.java index 7d0e74e66..955564cf2 100644 --- a/boomerangPDS/src/main/java/boomerang/weights/PathTrackingWeight.java +++ b/boomerangPDS/src/main/java/boomerang/weights/PathTrackingWeight.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.weights; diff --git a/boomerangPDS/src/main/java/boomerang/weights/PathTrackingWeightFunctions.java b/boomerangPDS/src/main/java/boomerang/weights/PathTrackingWeightFunctions.java index 76e644951..2740c350c 100644 --- a/boomerangPDS/src/main/java/boomerang/weights/PathTrackingWeightFunctions.java +++ b/boomerangPDS/src/main/java/boomerang/weights/PathTrackingWeightFunctions.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.weights; diff --git a/boomerangPDS/src/main/java/boomerang/weights/PathTrackingWeightImpl.java b/boomerangPDS/src/main/java/boomerang/weights/PathTrackingWeightImpl.java index a75b768f4..061367864 100644 --- a/boomerangPDS/src/main/java/boomerang/weights/PathTrackingWeightImpl.java +++ b/boomerangPDS/src/main/java/boomerang/weights/PathTrackingWeightImpl.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.weights; diff --git a/boomerangPDS/src/main/java/boomerang/weights/PathTrackingWeightOne.java b/boomerangPDS/src/main/java/boomerang/weights/PathTrackingWeightOne.java index 14dc1a443..4e75249a6 100644 --- a/boomerangPDS/src/main/java/boomerang/weights/PathTrackingWeightOne.java +++ b/boomerangPDS/src/main/java/boomerang/weights/PathTrackingWeightOne.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.weights; diff --git a/boomerangPDS/src/test/java/boomerang/guided/ArrayContainerCollectionManager.java b/boomerangPDS/src/test/java/boomerang/guided/ArrayContainerCollectionManager.java index f8ef4f72f..3439fa27e 100644 --- a/boomerangPDS/src/test/java/boomerang/guided/ArrayContainerCollectionManager.java +++ b/boomerangPDS/src/test/java/boomerang/guided/ArrayContainerCollectionManager.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.guided; diff --git a/boomerangPDS/src/test/java/boomerang/guided/CustomFlowFunctionTest.java b/boomerangPDS/src/test/java/boomerang/guided/CustomFlowFunctionTest.java index 6be7e2ba1..3cc25afc1 100644 --- a/boomerangPDS/src/test/java/boomerang/guided/CustomFlowFunctionTest.java +++ b/boomerangPDS/src/test/java/boomerang/guided/CustomFlowFunctionTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.guided; diff --git a/boomerangPDS/src/test/java/boomerang/guided/DemandDrivenGuidedAnalysisTest.java b/boomerangPDS/src/test/java/boomerang/guided/DemandDrivenGuidedAnalysisTest.java index 4739b3713..2e4681a99 100644 --- a/boomerangPDS/src/test/java/boomerang/guided/DemandDrivenGuidedAnalysisTest.java +++ b/boomerangPDS/src/test/java/boomerang/guided/DemandDrivenGuidedAnalysisTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.guided; diff --git a/boomerangPDS/src/test/java/boomerang/guided/SpecificationParserTest.java b/boomerangPDS/src/test/java/boomerang/guided/SpecificationParserTest.java index e822986aa..52c8525da 100644 --- a/boomerangPDS/src/test/java/boomerang/guided/SpecificationParserTest.java +++ b/boomerangPDS/src/test/java/boomerang/guided/SpecificationParserTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.guided; diff --git a/boomerangPDS/src/test/java/boomerang/guided/flowfunction/CustomBackwardFlowFunction.java b/boomerangPDS/src/test/java/boomerang/guided/flowfunction/CustomBackwardFlowFunction.java index 437ea3c15..e38451e20 100644 --- a/boomerangPDS/src/test/java/boomerang/guided/flowfunction/CustomBackwardFlowFunction.java +++ b/boomerangPDS/src/test/java/boomerang/guided/flowfunction/CustomBackwardFlowFunction.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.guided.flowfunction; diff --git a/boomerangPDS/src/test/java/boomerang/guided/flowfunction/CustomForwardFlowFunction.java b/boomerangPDS/src/test/java/boomerang/guided/flowfunction/CustomForwardFlowFunction.java index f144f6c20..186be9712 100644 --- a/boomerangPDS/src/test/java/boomerang/guided/flowfunction/CustomForwardFlowFunction.java +++ b/boomerangPDS/src/test/java/boomerang/guided/flowfunction/CustomForwardFlowFunction.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.guided.flowfunction; diff --git a/boomerangPDS/src/test/java/boomerang/guided/targets/ArrayContainerTarget.java b/boomerangPDS/src/test/java/boomerang/guided/targets/ArrayContainerTarget.java index db2a601e2..12d236014 100644 --- a/boomerangPDS/src/test/java/boomerang/guided/targets/ArrayContainerTarget.java +++ b/boomerangPDS/src/test/java/boomerang/guided/targets/ArrayContainerTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.guided.targets; diff --git a/boomerangPDS/src/test/java/boomerang/guided/targets/BasicTarget.java b/boomerangPDS/src/test/java/boomerang/guided/targets/BasicTarget.java index 33c398b59..6b22a77a5 100644 --- a/boomerangPDS/src/test/java/boomerang/guided/targets/BasicTarget.java +++ b/boomerangPDS/src/test/java/boomerang/guided/targets/BasicTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.guided.targets; diff --git a/boomerangPDS/src/test/java/boomerang/guided/targets/BranchingAfterNewStringTest.java b/boomerangPDS/src/test/java/boomerang/guided/targets/BranchingAfterNewStringTest.java index 101a8c918..5e5f6204a 100644 --- a/boomerangPDS/src/test/java/boomerang/guided/targets/BranchingAfterNewStringTest.java +++ b/boomerangPDS/src/test/java/boomerang/guided/targets/BranchingAfterNewStringTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.guided.targets; diff --git a/boomerangPDS/src/test/java/boomerang/guided/targets/BranchingTest.java b/boomerangPDS/src/test/java/boomerang/guided/targets/BranchingTest.java index 7ac2f4f52..9926c3ad5 100644 --- a/boomerangPDS/src/test/java/boomerang/guided/targets/BranchingTest.java +++ b/boomerangPDS/src/test/java/boomerang/guided/targets/BranchingTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.guided.targets; diff --git a/boomerangPDS/src/test/java/boomerang/guided/targets/ContextSensitiveAndLeftUnbalanced2StacksTarget.java b/boomerangPDS/src/test/java/boomerang/guided/targets/ContextSensitiveAndLeftUnbalanced2StacksTarget.java index f18333240..f96d6ec6b 100644 --- a/boomerangPDS/src/test/java/boomerang/guided/targets/ContextSensitiveAndLeftUnbalanced2StacksTarget.java +++ b/boomerangPDS/src/test/java/boomerang/guided/targets/ContextSensitiveAndLeftUnbalanced2StacksTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.guided.targets; diff --git a/boomerangPDS/src/test/java/boomerang/guided/targets/ContextSensitiveAndLeftUnbalancedFieldTarget.java b/boomerangPDS/src/test/java/boomerang/guided/targets/ContextSensitiveAndLeftUnbalancedFieldTarget.java index 809394949..6f24c7fde 100644 --- a/boomerangPDS/src/test/java/boomerang/guided/targets/ContextSensitiveAndLeftUnbalancedFieldTarget.java +++ b/boomerangPDS/src/test/java/boomerang/guided/targets/ContextSensitiveAndLeftUnbalancedFieldTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.guided.targets; diff --git a/boomerangPDS/src/test/java/boomerang/guided/targets/ContextSensitiveAndLeftUnbalancedTarget.java b/boomerangPDS/src/test/java/boomerang/guided/targets/ContextSensitiveAndLeftUnbalancedTarget.java index 64d16402d..4f54bb714 100644 --- a/boomerangPDS/src/test/java/boomerang/guided/targets/ContextSensitiveAndLeftUnbalancedTarget.java +++ b/boomerangPDS/src/test/java/boomerang/guided/targets/ContextSensitiveAndLeftUnbalancedTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.guided.targets; diff --git a/boomerangPDS/src/test/java/boomerang/guided/targets/ContextSensitiveAndLeftUnbalancedTarget2.java b/boomerangPDS/src/test/java/boomerang/guided/targets/ContextSensitiveAndLeftUnbalancedTarget2.java index 80a8b143c..c7abe8edc 100644 --- a/boomerangPDS/src/test/java/boomerang/guided/targets/ContextSensitiveAndLeftUnbalancedTarget2.java +++ b/boomerangPDS/src/test/java/boomerang/guided/targets/ContextSensitiveAndLeftUnbalancedTarget2.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.guided.targets; diff --git a/boomerangPDS/src/test/java/boomerang/guided/targets/ContextSensitiveAndLeftUnbalancedThisFieldTarget.java b/boomerangPDS/src/test/java/boomerang/guided/targets/ContextSensitiveAndLeftUnbalancedThisFieldTarget.java index 26a5d7df8..8b5af3c2d 100644 --- a/boomerangPDS/src/test/java/boomerang/guided/targets/ContextSensitiveAndLeftUnbalancedThisFieldTarget.java +++ b/boomerangPDS/src/test/java/boomerang/guided/targets/ContextSensitiveAndLeftUnbalancedThisFieldTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.guided.targets; diff --git a/boomerangPDS/src/test/java/boomerang/guided/targets/ContextSensitiveTarget.java b/boomerangPDS/src/test/java/boomerang/guided/targets/ContextSensitiveTarget.java index 50ba2c48b..58020b2d0 100644 --- a/boomerangPDS/src/test/java/boomerang/guided/targets/ContextSensitiveTarget.java +++ b/boomerangPDS/src/test/java/boomerang/guided/targets/ContextSensitiveTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.guided.targets; diff --git a/boomerangPDS/src/test/java/boomerang/guided/targets/CustomFlowFunctionIntTarget.java b/boomerangPDS/src/test/java/boomerang/guided/targets/CustomFlowFunctionIntTarget.java index b78c7e312..cf3d7a1fc 100644 --- a/boomerangPDS/src/test/java/boomerang/guided/targets/CustomFlowFunctionIntTarget.java +++ b/boomerangPDS/src/test/java/boomerang/guided/targets/CustomFlowFunctionIntTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.guided.targets; diff --git a/boomerangPDS/src/test/java/boomerang/guided/targets/CustomFlowFunctionTarget.java b/boomerangPDS/src/test/java/boomerang/guided/targets/CustomFlowFunctionTarget.java index 4149d2789..b57fcee7a 100644 --- a/boomerangPDS/src/test/java/boomerang/guided/targets/CustomFlowFunctionTarget.java +++ b/boomerangPDS/src/test/java/boomerang/guided/targets/CustomFlowFunctionTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.guided.targets; diff --git a/boomerangPDS/src/test/java/boomerang/guided/targets/IntegerCastTarget.java b/boomerangPDS/src/test/java/boomerang/guided/targets/IntegerCastTarget.java index 05ec45200..0563da9dc 100644 --- a/boomerangPDS/src/test/java/boomerang/guided/targets/IntegerCastTarget.java +++ b/boomerangPDS/src/test/java/boomerang/guided/targets/IntegerCastTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.guided.targets; diff --git a/boomerangPDS/src/test/java/boomerang/guided/targets/LeftUnbalancedTarget.java b/boomerangPDS/src/test/java/boomerang/guided/targets/LeftUnbalancedTarget.java index 32c3b4b40..b99596d64 100644 --- a/boomerangPDS/src/test/java/boomerang/guided/targets/LeftUnbalancedTarget.java +++ b/boomerangPDS/src/test/java/boomerang/guided/targets/LeftUnbalancedTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.guided.targets; diff --git a/boomerangPDS/src/test/java/boomerang/guided/targets/NestedContextAndBranchingTarget.java b/boomerangPDS/src/test/java/boomerang/guided/targets/NestedContextAndBranchingTarget.java index adc078416..9a76346f5 100644 --- a/boomerangPDS/src/test/java/boomerang/guided/targets/NestedContextAndBranchingTarget.java +++ b/boomerangPDS/src/test/java/boomerang/guided/targets/NestedContextAndBranchingTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.guided.targets; diff --git a/boomerangPDS/src/test/java/boomerang/guided/targets/NestedContextTarget.java b/boomerangPDS/src/test/java/boomerang/guided/targets/NestedContextTarget.java index 47eaaadd5..7d37fba89 100644 --- a/boomerangPDS/src/test/java/boomerang/guided/targets/NestedContextTarget.java +++ b/boomerangPDS/src/test/java/boomerang/guided/targets/NestedContextTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.guided.targets; diff --git a/boomerangPDS/src/test/java/boomerang/guided/targets/PingPongInterproceduralTarget.java b/boomerangPDS/src/test/java/boomerang/guided/targets/PingPongInterproceduralTarget.java index 3a4e3c929..6d622c546 100644 --- a/boomerangPDS/src/test/java/boomerang/guided/targets/PingPongInterproceduralTarget.java +++ b/boomerangPDS/src/test/java/boomerang/guided/targets/PingPongInterproceduralTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.guided.targets; diff --git a/boomerangPDS/src/test/java/boomerang/guided/targets/PingPongTarget.java b/boomerangPDS/src/test/java/boomerang/guided/targets/PingPongTarget.java index 63a20e221..d6451f4ec 100644 --- a/boomerangPDS/src/test/java/boomerang/guided/targets/PingPongTarget.java +++ b/boomerangPDS/src/test/java/boomerang/guided/targets/PingPongTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.guided.targets; diff --git a/boomerangPDS/src/test/java/boomerang/guided/targets/Query.java b/boomerangPDS/src/test/java/boomerang/guided/targets/Query.java index 57d813bb0..c5a9e2baa 100644 --- a/boomerangPDS/src/test/java/boomerang/guided/targets/Query.java +++ b/boomerangPDS/src/test/java/boomerang/guided/targets/Query.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.guided.targets; diff --git a/boomerangPDS/src/test/java/boomerang/guided/targets/ValueOfTarget.java b/boomerangPDS/src/test/java/boomerang/guided/targets/ValueOfTarget.java index e3dab1790..3dafc7eb4 100644 --- a/boomerangPDS/src/test/java/boomerang/guided/targets/ValueOfTarget.java +++ b/boomerangPDS/src/test/java/boomerang/guided/targets/ValueOfTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.guided.targets; diff --git a/boomerangPDS/src/test/java/boomerang/guided/targets/WrappedInNewStringInnerTarget.java b/boomerangPDS/src/test/java/boomerang/guided/targets/WrappedInNewStringInnerTarget.java index 0cc078156..204ca60f0 100644 --- a/boomerangPDS/src/test/java/boomerang/guided/targets/WrappedInNewStringInnerTarget.java +++ b/boomerangPDS/src/test/java/boomerang/guided/targets/WrappedInNewStringInnerTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.guided.targets; diff --git a/boomerangPDS/src/test/java/boomerang/guided/targets/WrappedInNewStringTarget.java b/boomerangPDS/src/test/java/boomerang/guided/targets/WrappedInNewStringTarget.java index 35813508e..ec508cef5 100644 --- a/boomerangPDS/src/test/java/boomerang/guided/targets/WrappedInNewStringTarget.java +++ b/boomerangPDS/src/test/java/boomerang/guided/targets/WrappedInNewStringTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.guided.targets; diff --git a/boomerangPDS/src/test/java/boomerang/guided/targets/WrappedInStringTwiceTest.java b/boomerangPDS/src/test/java/boomerang/guided/targets/WrappedInStringTwiceTest.java index ea96c65d1..52d7d674a 100644 --- a/boomerangPDS/src/test/java/boomerang/guided/targets/WrappedInStringTwiceTest.java +++ b/boomerangPDS/src/test/java/boomerang/guided/targets/WrappedInStringTwiceTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.guided.targets; diff --git a/boomerangPDS/src/test/java/example/ExampleMain1.java b/boomerangPDS/src/test/java/example/ExampleMain1.java index 609205e19..87a851148 100644 --- a/boomerangPDS/src/test/java/example/ExampleMain1.java +++ b/boomerangPDS/src/test/java/example/ExampleMain1.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package example; diff --git a/boomerangPDS/src/test/java/example/ExampleMain2.java b/boomerangPDS/src/test/java/example/ExampleMain2.java index 790ea8a40..2cb0d8cea 100644 --- a/boomerangPDS/src/test/java/example/ExampleMain2.java +++ b/boomerangPDS/src/test/java/example/ExampleMain2.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package example; diff --git a/boomerangPDS/src/test/java/test/cases/accesspath/AccessPathTarget.java b/boomerangPDS/src/test/java/test/cases/accesspath/AccessPathTarget.java index f86788e94..073b52740 100644 --- a/boomerangPDS/src/test/java/test/cases/accesspath/AccessPathTarget.java +++ b/boomerangPDS/src/test/java/test/cases/accesspath/AccessPathTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.accesspath; diff --git a/boomerangPDS/src/test/java/test/cases/accesspath/AccessPathTest.java b/boomerangPDS/src/test/java/test/cases/accesspath/AccessPathTest.java index 4132bb9fb..05eca2f4d 100644 --- a/boomerangPDS/src/test/java/test/cases/accesspath/AccessPathTest.java +++ b/boomerangPDS/src/test/java/test/cases/accesspath/AccessPathTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.accesspath; diff --git a/boomerangPDS/src/test/java/test/cases/array/ArrayAlloc.java b/boomerangPDS/src/test/java/test/cases/array/ArrayAlloc.java index 465c6e203..3014ef1f4 100644 --- a/boomerangPDS/src/test/java/test/cases/array/ArrayAlloc.java +++ b/boomerangPDS/src/test/java/test/cases/array/ArrayAlloc.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.array; diff --git a/boomerangPDS/src/test/java/test/cases/array/ArrayContainerTarget.java b/boomerangPDS/src/test/java/test/cases/array/ArrayContainerTarget.java index 36a9dffb2..9afcb83c1 100644 --- a/boomerangPDS/src/test/java/test/cases/array/ArrayContainerTarget.java +++ b/boomerangPDS/src/test/java/test/cases/array/ArrayContainerTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.array; diff --git a/boomerangPDS/src/test/java/test/cases/array/ArrayContainerTest.java b/boomerangPDS/src/test/java/test/cases/array/ArrayContainerTest.java index 7e9a3bfb9..2e46ee20b 100644 --- a/boomerangPDS/src/test/java/test/cases/array/ArrayContainerTest.java +++ b/boomerangPDS/src/test/java/test/cases/array/ArrayContainerTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.array; diff --git a/boomerangPDS/src/test/java/test/cases/array/ArrayIndexSensitiveTarget.java b/boomerangPDS/src/test/java/test/cases/array/ArrayIndexSensitiveTarget.java index 6554d6551..f165327f4 100644 --- a/boomerangPDS/src/test/java/test/cases/array/ArrayIndexSensitiveTarget.java +++ b/boomerangPDS/src/test/java/test/cases/array/ArrayIndexSensitiveTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.array; diff --git a/boomerangPDS/src/test/java/test/cases/array/ArrayIndexSensitiveTest.java b/boomerangPDS/src/test/java/test/cases/array/ArrayIndexSensitiveTest.java index 04adfa081..7cdd9165f 100644 --- a/boomerangPDS/src/test/java/test/cases/array/ArrayIndexSensitiveTest.java +++ b/boomerangPDS/src/test/java/test/cases/array/ArrayIndexSensitiveTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.array; diff --git a/boomerangPDS/src/test/java/test/cases/array/ArrayTarget.java b/boomerangPDS/src/test/java/test/cases/array/ArrayTarget.java index 98489be11..d29aa03c6 100644 --- a/boomerangPDS/src/test/java/test/cases/array/ArrayTarget.java +++ b/boomerangPDS/src/test/java/test/cases/array/ArrayTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.array; diff --git a/boomerangPDS/src/test/java/test/cases/array/ArrayTest.java b/boomerangPDS/src/test/java/test/cases/array/ArrayTest.java index e50a6a809..556dca11f 100644 --- a/boomerangPDS/src/test/java/test/cases/array/ArrayTest.java +++ b/boomerangPDS/src/test/java/test/cases/array/ArrayTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.array; diff --git a/boomerangPDS/src/test/java/test/cases/basic/BasicAlloc.java b/boomerangPDS/src/test/java/test/cases/basic/BasicAlloc.java index bd50b1a25..ec63d590d 100644 --- a/boomerangPDS/src/test/java/test/cases/basic/BasicAlloc.java +++ b/boomerangPDS/src/test/java/test/cases/basic/BasicAlloc.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.basic; diff --git a/boomerangPDS/src/test/java/test/cases/basic/FieldlessTarget.java b/boomerangPDS/src/test/java/test/cases/basic/FieldlessTarget.java index 388088b1c..da4b28dd7 100644 --- a/boomerangPDS/src/test/java/test/cases/basic/FieldlessTarget.java +++ b/boomerangPDS/src/test/java/test/cases/basic/FieldlessTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.basic; diff --git a/boomerangPDS/src/test/java/test/cases/basic/FieldlessTest.java b/boomerangPDS/src/test/java/test/cases/basic/FieldlessTest.java index 27128aba8..60ba72218 100644 --- a/boomerangPDS/src/test/java/test/cases/basic/FieldlessTest.java +++ b/boomerangPDS/src/test/java/test/cases/basic/FieldlessTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.basic; diff --git a/boomerangPDS/src/test/java/test/cases/basic/InterproceduralTarget.java b/boomerangPDS/src/test/java/test/cases/basic/InterproceduralTarget.java index d382b443a..7a6f591b2 100644 --- a/boomerangPDS/src/test/java/test/cases/basic/InterproceduralTarget.java +++ b/boomerangPDS/src/test/java/test/cases/basic/InterproceduralTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.basic; diff --git a/boomerangPDS/src/test/java/test/cases/basic/InterproceduralTest.java b/boomerangPDS/src/test/java/test/cases/basic/InterproceduralTest.java index 33d571471..cccc9ee11 100644 --- a/boomerangPDS/src/test/java/test/cases/basic/InterproceduralTest.java +++ b/boomerangPDS/src/test/java/test/cases/basic/InterproceduralTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.basic; diff --git a/boomerangPDS/src/test/java/test/cases/basic/UnbalancedInterproceduralTarget.java b/boomerangPDS/src/test/java/test/cases/basic/UnbalancedInterproceduralTarget.java index abd0f3419..dbbef2e71 100644 --- a/boomerangPDS/src/test/java/test/cases/basic/UnbalancedInterproceduralTarget.java +++ b/boomerangPDS/src/test/java/test/cases/basic/UnbalancedInterproceduralTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.basic; diff --git a/boomerangPDS/src/test/java/test/cases/basic/UnbalancedInterproceduralTest.java b/boomerangPDS/src/test/java/test/cases/basic/UnbalancedInterproceduralTest.java index 61c2a0156..08d57914e 100644 --- a/boomerangPDS/src/test/java/test/cases/basic/UnbalancedInterproceduralTest.java +++ b/boomerangPDS/src/test/java/test/cases/basic/UnbalancedInterproceduralTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.basic; diff --git a/boomerangPDS/src/test/java/test/cases/bugfixes/issue5/Foo.java b/boomerangPDS/src/test/java/test/cases/bugfixes/issue5/Foo.java index 9e4380b5b..cba8246c7 100644 --- a/boomerangPDS/src/test/java/test/cases/bugfixes/issue5/Foo.java +++ b/boomerangPDS/src/test/java/test/cases/bugfixes/issue5/Foo.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.bugfixes.issue5; diff --git a/boomerangPDS/src/test/java/test/cases/bugfixes/issue5/Issue5Test.java b/boomerangPDS/src/test/java/test/cases/bugfixes/issue5/Issue5Test.java index 057f9cf27..f78d0d235 100644 --- a/boomerangPDS/src/test/java/test/cases/bugfixes/issue5/Issue5Test.java +++ b/boomerangPDS/src/test/java/test/cases/bugfixes/issue5/Issue5Test.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.bugfixes.issue5; diff --git a/boomerangPDS/src/test/java/test/cases/bugfixes/issue5/Test.java b/boomerangPDS/src/test/java/test/cases/bugfixes/issue5/Test.java index c1379e1df..6b649f03a 100644 --- a/boomerangPDS/src/test/java/test/cases/bugfixes/issue5/Test.java +++ b/boomerangPDS/src/test/java/test/cases/bugfixes/issue5/Test.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.bugfixes.issue5; diff --git a/boomerangPDS/src/test/java/test/cases/callgraph/CallGraphAlloc.java b/boomerangPDS/src/test/java/test/cases/callgraph/CallGraphAlloc.java index 3752e5e7b..444792644 100644 --- a/boomerangPDS/src/test/java/test/cases/callgraph/CallGraphAlloc.java +++ b/boomerangPDS/src/test/java/test/cases/callgraph/CallGraphAlloc.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.callgraph; diff --git a/boomerangPDS/src/test/java/test/cases/callgraph/ContextSensitivityFieldTarget.java b/boomerangPDS/src/test/java/test/cases/callgraph/ContextSensitivityFieldTarget.java index bd8d0339c..f1dc0c948 100644 --- a/boomerangPDS/src/test/java/test/cases/callgraph/ContextSensitivityFieldTarget.java +++ b/boomerangPDS/src/test/java/test/cases/callgraph/ContextSensitivityFieldTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.callgraph; diff --git a/boomerangPDS/src/test/java/test/cases/callgraph/ContextSensitivityFieldTest.java b/boomerangPDS/src/test/java/test/cases/callgraph/ContextSensitivityFieldTest.java index 39a6eeb39..c072f9430 100644 --- a/boomerangPDS/src/test/java/test/cases/callgraph/ContextSensitivityFieldTest.java +++ b/boomerangPDS/src/test/java/test/cases/callgraph/ContextSensitivityFieldTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.callgraph; diff --git a/boomerangPDS/src/test/java/test/cases/callgraph/ContextSensitivityMyListTarget.java b/boomerangPDS/src/test/java/test/cases/callgraph/ContextSensitivityMyListTarget.java index 6048bb396..f7e703124 100644 --- a/boomerangPDS/src/test/java/test/cases/callgraph/ContextSensitivityMyListTarget.java +++ b/boomerangPDS/src/test/java/test/cases/callgraph/ContextSensitivityMyListTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.callgraph; diff --git a/boomerangPDS/src/test/java/test/cases/callgraph/ContextSensitivityMyListTest.java b/boomerangPDS/src/test/java/test/cases/callgraph/ContextSensitivityMyListTest.java index a2097175c..f627c28c4 100644 --- a/boomerangPDS/src/test/java/test/cases/callgraph/ContextSensitivityMyListTest.java +++ b/boomerangPDS/src/test/java/test/cases/callgraph/ContextSensitivityMyListTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.callgraph; diff --git a/boomerangPDS/src/test/java/test/cases/callgraph/ContextSensitivityTarget.java b/boomerangPDS/src/test/java/test/cases/callgraph/ContextSensitivityTarget.java index 43fbe5780..9582824a1 100644 --- a/boomerangPDS/src/test/java/test/cases/callgraph/ContextSensitivityTarget.java +++ b/boomerangPDS/src/test/java/test/cases/callgraph/ContextSensitivityTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.callgraph; diff --git a/boomerangPDS/src/test/java/test/cases/callgraph/ContextSensitivityTest.java b/boomerangPDS/src/test/java/test/cases/callgraph/ContextSensitivityTest.java index fa4edc1c7..f1f3682e8 100644 --- a/boomerangPDS/src/test/java/test/cases/callgraph/ContextSensitivityTest.java +++ b/boomerangPDS/src/test/java/test/cases/callgraph/ContextSensitivityTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.callgraph; diff --git a/boomerangPDS/src/test/java/test/cases/callgraph/ContextSpecificListTypeTarget.java b/boomerangPDS/src/test/java/test/cases/callgraph/ContextSpecificListTypeTarget.java index ce5937610..13ed5db52 100644 --- a/boomerangPDS/src/test/java/test/cases/callgraph/ContextSpecificListTypeTarget.java +++ b/boomerangPDS/src/test/java/test/cases/callgraph/ContextSpecificListTypeTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.callgraph; diff --git a/boomerangPDS/src/test/java/test/cases/callgraph/ContextSpecificListTypeTest.java b/boomerangPDS/src/test/java/test/cases/callgraph/ContextSpecificListTypeTest.java index 1cf3d1c07..b728e1186 100644 --- a/boomerangPDS/src/test/java/test/cases/callgraph/ContextSpecificListTypeTest.java +++ b/boomerangPDS/src/test/java/test/cases/callgraph/ContextSpecificListTypeTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.callgraph; diff --git a/boomerangPDS/src/test/java/test/cases/context/AliasViaParameterTarget.java b/boomerangPDS/src/test/java/test/cases/context/AliasViaParameterTarget.java index 8269f8580..ab61a7e65 100644 --- a/boomerangPDS/src/test/java/test/cases/context/AliasViaParameterTarget.java +++ b/boomerangPDS/src/test/java/test/cases/context/AliasViaParameterTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.context; diff --git a/boomerangPDS/src/test/java/test/cases/context/AliasViaParameterTest.java b/boomerangPDS/src/test/java/test/cases/context/AliasViaParameterTest.java index b4e04a19d..e4e826f88 100644 --- a/boomerangPDS/src/test/java/test/cases/context/AliasViaParameterTest.java +++ b/boomerangPDS/src/test/java/test/cases/context/AliasViaParameterTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.context; diff --git a/boomerangPDS/src/test/java/test/cases/context/ContextAlloc.java b/boomerangPDS/src/test/java/test/cases/context/ContextAlloc.java index e3269dcfb..471adf790 100644 --- a/boomerangPDS/src/test/java/test/cases/context/ContextAlloc.java +++ b/boomerangPDS/src/test/java/test/cases/context/ContextAlloc.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.context; diff --git a/boomerangPDS/src/test/java/test/cases/context/ContextTypesTarget.java b/boomerangPDS/src/test/java/test/cases/context/ContextTypesTarget.java index ebf203a07..2175f03e0 100644 --- a/boomerangPDS/src/test/java/test/cases/context/ContextTypesTarget.java +++ b/boomerangPDS/src/test/java/test/cases/context/ContextTypesTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.context; diff --git a/boomerangPDS/src/test/java/test/cases/context/ContextTypesTest.java b/boomerangPDS/src/test/java/test/cases/context/ContextTypesTest.java index b60495b0f..7eae4f203 100644 --- a/boomerangPDS/src/test/java/test/cases/context/ContextTypesTest.java +++ b/boomerangPDS/src/test/java/test/cases/context/ContextTypesTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.context; diff --git a/boomerangPDS/src/test/java/test/cases/context/LoopInContextRequesterTarget.java b/boomerangPDS/src/test/java/test/cases/context/LoopInContextRequesterTarget.java index 895724e26..968dcbfb6 100644 --- a/boomerangPDS/src/test/java/test/cases/context/LoopInContextRequesterTarget.java +++ b/boomerangPDS/src/test/java/test/cases/context/LoopInContextRequesterTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.context; diff --git a/boomerangPDS/src/test/java/test/cases/context/LoopInContextRequesterTest.java b/boomerangPDS/src/test/java/test/cases/context/LoopInContextRequesterTest.java index 5992ce9b3..bdb3ebe7f 100644 --- a/boomerangPDS/src/test/java/test/cases/context/LoopInContextRequesterTest.java +++ b/boomerangPDS/src/test/java/test/cases/context/LoopInContextRequesterTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.context; diff --git a/boomerangPDS/src/test/java/test/cases/context/OuterAllocationTarget.java b/boomerangPDS/src/test/java/test/cases/context/OuterAllocationTarget.java index db733a1df..6aedb29bd 100644 --- a/boomerangPDS/src/test/java/test/cases/context/OuterAllocationTarget.java +++ b/boomerangPDS/src/test/java/test/cases/context/OuterAllocationTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.context; diff --git a/boomerangPDS/src/test/java/test/cases/context/OuterAllocationTest.java b/boomerangPDS/src/test/java/test/cases/context/OuterAllocationTest.java index f783f1b97..8a62eaa1a 100644 --- a/boomerangPDS/src/test/java/test/cases/context/OuterAllocationTest.java +++ b/boomerangPDS/src/test/java/test/cases/context/OuterAllocationTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.context; diff --git a/boomerangPDS/src/test/java/test/cases/context/PathingContextProblemTarget.java b/boomerangPDS/src/test/java/test/cases/context/PathingContextProblemTarget.java index 2c4599f15..c594f8453 100644 --- a/boomerangPDS/src/test/java/test/cases/context/PathingContextProblemTarget.java +++ b/boomerangPDS/src/test/java/test/cases/context/PathingContextProblemTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.context; diff --git a/boomerangPDS/src/test/java/test/cases/context/PathingContextProblemTest.java b/boomerangPDS/src/test/java/test/cases/context/PathingContextProblemTest.java index 9670c71e0..61b13bfa9 100644 --- a/boomerangPDS/src/test/java/test/cases/context/PathingContextProblemTest.java +++ b/boomerangPDS/src/test/java/test/cases/context/PathingContextProblemTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.context; diff --git a/boomerangPDS/src/test/java/test/cases/context/SimpleContextQueryTarget.java b/boomerangPDS/src/test/java/test/cases/context/SimpleContextQueryTarget.java index d4994ed79..7e5d6d5ae 100644 --- a/boomerangPDS/src/test/java/test/cases/context/SimpleContextQueryTarget.java +++ b/boomerangPDS/src/test/java/test/cases/context/SimpleContextQueryTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.context; diff --git a/boomerangPDS/src/test/java/test/cases/context/SimpleContextQueryTest.java b/boomerangPDS/src/test/java/test/cases/context/SimpleContextQueryTest.java index e7eb64d27..ff09ff721 100644 --- a/boomerangPDS/src/test/java/test/cases/context/SimpleContextQueryTest.java +++ b/boomerangPDS/src/test/java/test/cases/context/SimpleContextQueryTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.context; diff --git a/boomerangPDS/src/test/java/test/cases/exceptions/ExceptionAlloc.java b/boomerangPDS/src/test/java/test/cases/exceptions/ExceptionAlloc.java index c28ab6645..4557621bb 100644 --- a/boomerangPDS/src/test/java/test/cases/exceptions/ExceptionAlloc.java +++ b/boomerangPDS/src/test/java/test/cases/exceptions/ExceptionAlloc.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.exceptions; diff --git a/boomerangPDS/src/test/java/test/cases/exceptions/ExceptionTarget.java b/boomerangPDS/src/test/java/test/cases/exceptions/ExceptionTarget.java index e74c88a2a..a9bbee577 100644 --- a/boomerangPDS/src/test/java/test/cases/exceptions/ExceptionTarget.java +++ b/boomerangPDS/src/test/java/test/cases/exceptions/ExceptionTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.exceptions; diff --git a/boomerangPDS/src/test/java/test/cases/exceptions/ExceptionTest.java b/boomerangPDS/src/test/java/test/cases/exceptions/ExceptionTest.java index 8a0869a3a..2bf8942a1 100644 --- a/boomerangPDS/src/test/java/test/cases/exceptions/ExceptionTest.java +++ b/boomerangPDS/src/test/java/test/cases/exceptions/ExceptionTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.exceptions; diff --git a/boomerangPDS/src/test/java/test/cases/fields/A.java b/boomerangPDS/src/test/java/test/cases/fields/A.java index 3dd0f4df2..59d8bbcf7 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/A.java +++ b/boomerangPDS/src/test/java/test/cases/fields/A.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.fields; diff --git a/boomerangPDS/src/test/java/test/cases/fields/B.java b/boomerangPDS/src/test/java/test/cases/fields/B.java index 51486bfc2..fead57ba9 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/B.java +++ b/boomerangPDS/src/test/java/test/cases/fields/B.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.fields; diff --git a/boomerangPDS/src/test/java/test/cases/fields/BasicFieldTarget.java b/boomerangPDS/src/test/java/test/cases/fields/BasicFieldTarget.java index 03cde1ecc..7c2acc030 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/BasicFieldTarget.java +++ b/boomerangPDS/src/test/java/test/cases/fields/BasicFieldTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.fields; diff --git a/boomerangPDS/src/test/java/test/cases/fields/BasicFieldTest.java b/boomerangPDS/src/test/java/test/cases/fields/BasicFieldTest.java index a6b01e5e5..62bdadb1a 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/BasicFieldTest.java +++ b/boomerangPDS/src/test/java/test/cases/fields/BasicFieldTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.fields; diff --git a/boomerangPDS/src/test/java/test/cases/fields/CallPOITarget.java b/boomerangPDS/src/test/java/test/cases/fields/CallPOITarget.java index 2d296f25b..b6ee92461 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/CallPOITarget.java +++ b/boomerangPDS/src/test/java/test/cases/fields/CallPOITarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.fields; diff --git a/boomerangPDS/src/test/java/test/cases/fields/CallPOITest.java b/boomerangPDS/src/test/java/test/cases/fields/CallPOITest.java index fe9966da9..db1203527 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/CallPOITest.java +++ b/boomerangPDS/src/test/java/test/cases/fields/CallPOITest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.fields; diff --git a/boomerangPDS/src/test/java/test/cases/fields/CastAndSetTarget.java b/boomerangPDS/src/test/java/test/cases/fields/CastAndSetTarget.java index 8c59b6819..73bf95f6e 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/CastAndSetTarget.java +++ b/boomerangPDS/src/test/java/test/cases/fields/CastAndSetTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.fields; diff --git a/boomerangPDS/src/test/java/test/cases/fields/CastAndSetTest.java b/boomerangPDS/src/test/java/test/cases/fields/CastAndSetTest.java index 5ad95e277..a8395218e 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/CastAndSetTest.java +++ b/boomerangPDS/src/test/java/test/cases/fields/CastAndSetTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.fields; diff --git a/boomerangPDS/src/test/java/test/cases/fields/FailOnVisitMethodTarget.java b/boomerangPDS/src/test/java/test/cases/fields/FailOnVisitMethodTarget.java index 1aca48b64..98a1a2a19 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/FailOnVisitMethodTarget.java +++ b/boomerangPDS/src/test/java/test/cases/fields/FailOnVisitMethodTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.fields; diff --git a/boomerangPDS/src/test/java/test/cases/fields/FailOnVisitMethodTest.java b/boomerangPDS/src/test/java/test/cases/fields/FailOnVisitMethodTest.java index 67bad73a4..85b7171ea 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/FailOnVisitMethodTest.java +++ b/boomerangPDS/src/test/java/test/cases/fields/FailOnVisitMethodTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.fields; diff --git a/boomerangPDS/src/test/java/test/cases/fields/FieldAlloc.java b/boomerangPDS/src/test/java/test/cases/fields/FieldAlloc.java index ec16c7578..e43e905c3 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/FieldAlloc.java +++ b/boomerangPDS/src/test/java/test/cases/fields/FieldAlloc.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.fields; diff --git a/boomerangPDS/src/test/java/test/cases/fields/FieldsBranchedTarget.java b/boomerangPDS/src/test/java/test/cases/fields/FieldsBranchedTarget.java index cf2c37dfc..f844b7add 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/FieldsBranchedTarget.java +++ b/boomerangPDS/src/test/java/test/cases/fields/FieldsBranchedTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.fields; diff --git a/boomerangPDS/src/test/java/test/cases/fields/FieldsBranchedTest.java b/boomerangPDS/src/test/java/test/cases/fields/FieldsBranchedTest.java index cb241ffc5..c54b86c86 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/FieldsBranchedTest.java +++ b/boomerangPDS/src/test/java/test/cases/fields/FieldsBranchedTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.fields; diff --git a/boomerangPDS/src/test/java/test/cases/fields/HiddenFieldLoadTarget.java b/boomerangPDS/src/test/java/test/cases/fields/HiddenFieldLoadTarget.java index 693f7ad0f..ad7bb53a3 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/HiddenFieldLoadTarget.java +++ b/boomerangPDS/src/test/java/test/cases/fields/HiddenFieldLoadTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.fields; diff --git a/boomerangPDS/src/test/java/test/cases/fields/HiddenFieldLoadTest.java b/boomerangPDS/src/test/java/test/cases/fields/HiddenFieldLoadTest.java index ad7b47c91..fbc8bde4b 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/HiddenFieldLoadTest.java +++ b/boomerangPDS/src/test/java/test/cases/fields/HiddenFieldLoadTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.fields; diff --git a/boomerangPDS/src/test/java/test/cases/fields/InterproceduralTarget.java b/boomerangPDS/src/test/java/test/cases/fields/InterproceduralTarget.java index 638438666..a5daf089d 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/InterproceduralTarget.java +++ b/boomerangPDS/src/test/java/test/cases/fields/InterproceduralTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.fields; diff --git a/boomerangPDS/src/test/java/test/cases/fields/InterproceduralTest.java b/boomerangPDS/src/test/java/test/cases/fields/InterproceduralTest.java index b78969d68..5781affa3 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/InterproceduralTest.java +++ b/boomerangPDS/src/test/java/test/cases/fields/InterproceduralTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.fields; diff --git a/boomerangPDS/src/test/java/test/cases/fields/IntraproceduralStrongUpdateTarget.java b/boomerangPDS/src/test/java/test/cases/fields/IntraproceduralStrongUpdateTarget.java index b48a4e171..073287a15 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/IntraproceduralStrongUpdateTarget.java +++ b/boomerangPDS/src/test/java/test/cases/fields/IntraproceduralStrongUpdateTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.fields; diff --git a/boomerangPDS/src/test/java/test/cases/fields/IntraproceduralStrongUpdateTest.java b/boomerangPDS/src/test/java/test/cases/fields/IntraproceduralStrongUpdateTest.java index a0ccd58d2..012f6237d 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/IntraproceduralStrongUpdateTest.java +++ b/boomerangPDS/src/test/java/test/cases/fields/IntraproceduralStrongUpdateTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.fields; diff --git a/boomerangPDS/src/test/java/test/cases/fields/MeetPOITarget.java b/boomerangPDS/src/test/java/test/cases/fields/MeetPOITarget.java index a4d23edff..305c3d2a1 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/MeetPOITarget.java +++ b/boomerangPDS/src/test/java/test/cases/fields/MeetPOITarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.fields; diff --git a/boomerangPDS/src/test/java/test/cases/fields/MeetPOITest.java b/boomerangPDS/src/test/java/test/cases/fields/MeetPOITest.java index 2d0e55c48..fe720fa51 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/MeetPOITest.java +++ b/boomerangPDS/src/test/java/test/cases/fields/MeetPOITest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.fields; diff --git a/boomerangPDS/src/test/java/test/cases/fields/NoIndirectionTarget.java b/boomerangPDS/src/test/java/test/cases/fields/NoIndirectionTarget.java index 9a51c8232..7c29c4bc1 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/NoIndirectionTarget.java +++ b/boomerangPDS/src/test/java/test/cases/fields/NoIndirectionTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.fields; diff --git a/boomerangPDS/src/test/java/test/cases/fields/NoIndirectionTest.java b/boomerangPDS/src/test/java/test/cases/fields/NoIndirectionTest.java index 0121fe7d8..4fcddcb72 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/NoIndirectionTest.java +++ b/boomerangPDS/src/test/java/test/cases/fields/NoIndirectionTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.fields; diff --git a/boomerangPDS/src/test/java/test/cases/fields/NullAllocationConstructorTarget.java b/boomerangPDS/src/test/java/test/cases/fields/NullAllocationConstructorTarget.java index 5e75e7d45..c2f48bfd6 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/NullAllocationConstructorTarget.java +++ b/boomerangPDS/src/test/java/test/cases/fields/NullAllocationConstructorTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.fields; diff --git a/boomerangPDS/src/test/java/test/cases/fields/NullAllocationConstructorTest.java b/boomerangPDS/src/test/java/test/cases/fields/NullAllocationConstructorTest.java index ff2a64a52..6b2be018e 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/NullAllocationConstructorTest.java +++ b/boomerangPDS/src/test/java/test/cases/fields/NullAllocationConstructorTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.fields; diff --git a/boomerangPDS/src/test/java/test/cases/fields/ObjectSensitivityTarget.java b/boomerangPDS/src/test/java/test/cases/fields/ObjectSensitivityTarget.java index f83346985..5ca489d6d 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/ObjectSensitivityTarget.java +++ b/boomerangPDS/src/test/java/test/cases/fields/ObjectSensitivityTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.fields; diff --git a/boomerangPDS/src/test/java/test/cases/fields/ObjectSensitivityTest.java b/boomerangPDS/src/test/java/test/cases/fields/ObjectSensitivityTest.java index 79f59d8db..f1a199a71 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/ObjectSensitivityTest.java +++ b/boomerangPDS/src/test/java/test/cases/fields/ObjectSensitivityTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.fields; diff --git a/boomerangPDS/src/test/java/test/cases/fields/ReadPOITarget.java b/boomerangPDS/src/test/java/test/cases/fields/ReadPOITarget.java index 3e41f20d1..3a1605362 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/ReadPOITarget.java +++ b/boomerangPDS/src/test/java/test/cases/fields/ReadPOITarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.fields; diff --git a/boomerangPDS/src/test/java/test/cases/fields/ReadPOITest.java b/boomerangPDS/src/test/java/test/cases/fields/ReadPOITest.java index 880d1d2a9..2daa418ee 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/ReadPOITest.java +++ b/boomerangPDS/src/test/java/test/cases/fields/ReadPOITest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.fields; diff --git a/boomerangPDS/src/test/java/test/cases/fields/ReadTwiceSameFieldTarget.java b/boomerangPDS/src/test/java/test/cases/fields/ReadTwiceSameFieldTarget.java index 2236d9fb7..9b5357a5a 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/ReadTwiceSameFieldTarget.java +++ b/boomerangPDS/src/test/java/test/cases/fields/ReadTwiceSameFieldTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.fields; diff --git a/boomerangPDS/src/test/java/test/cases/fields/ReadTwiceSameFieldTest.java b/boomerangPDS/src/test/java/test/cases/fields/ReadTwiceSameFieldTest.java index 379b96150..43d2cc735 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/ReadTwiceSameFieldTest.java +++ b/boomerangPDS/src/test/java/test/cases/fields/ReadTwiceSameFieldTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.fields; diff --git a/boomerangPDS/src/test/java/test/cases/fields/ReturnPOITarget.java b/boomerangPDS/src/test/java/test/cases/fields/ReturnPOITarget.java index 340b0d1c0..6dbd25319 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/ReturnPOITarget.java +++ b/boomerangPDS/src/test/java/test/cases/fields/ReturnPOITarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.fields; diff --git a/boomerangPDS/src/test/java/test/cases/fields/ReturnPOITest.java b/boomerangPDS/src/test/java/test/cases/fields/ReturnPOITest.java index 89ebe627b..93a803491 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/ReturnPOITest.java +++ b/boomerangPDS/src/test/java/test/cases/fields/ReturnPOITest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.fields; diff --git a/boomerangPDS/src/test/java/test/cases/fields/ReuseOfSummaryTarget.java b/boomerangPDS/src/test/java/test/cases/fields/ReuseOfSummaryTarget.java index 1c93d84d4..dd030cf3b 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/ReuseOfSummaryTarget.java +++ b/boomerangPDS/src/test/java/test/cases/fields/ReuseOfSummaryTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.fields; diff --git a/boomerangPDS/src/test/java/test/cases/fields/ReuseOfSummaryTest.java b/boomerangPDS/src/test/java/test/cases/fields/ReuseOfSummaryTest.java index aff415222..1cb33d204 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/ReuseOfSummaryTest.java +++ b/boomerangPDS/src/test/java/test/cases/fields/ReuseOfSummaryTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.fields; diff --git a/boomerangPDS/src/test/java/test/cases/fields/SummaryTarget.java b/boomerangPDS/src/test/java/test/cases/fields/SummaryTarget.java index cf436e61e..1900af6bf 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/SummaryTarget.java +++ b/boomerangPDS/src/test/java/test/cases/fields/SummaryTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.fields; diff --git a/boomerangPDS/src/test/java/test/cases/fields/SummaryTest.java b/boomerangPDS/src/test/java/test/cases/fields/SummaryTest.java index 091b7e0b2..ea212e257 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/SummaryTest.java +++ b/boomerangPDS/src/test/java/test/cases/fields/SummaryTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.fields; diff --git a/boomerangPDS/src/test/java/test/cases/fields/ThreeFieldsTarget.java b/boomerangPDS/src/test/java/test/cases/fields/ThreeFieldsTarget.java index 0827c28e6..de33c1238 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/ThreeFieldsTarget.java +++ b/boomerangPDS/src/test/java/test/cases/fields/ThreeFieldsTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.fields; diff --git a/boomerangPDS/src/test/java/test/cases/fields/ThreeFieldsTest.java b/boomerangPDS/src/test/java/test/cases/fields/ThreeFieldsTest.java index 781ec4931..2d87ddb13 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/ThreeFieldsTest.java +++ b/boomerangPDS/src/test/java/test/cases/fields/ThreeFieldsTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.fields; diff --git a/boomerangPDS/src/test/java/test/cases/fields/TypeChangeTarget.java b/boomerangPDS/src/test/java/test/cases/fields/TypeChangeTarget.java index e7835b383..dc6c43c07 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/TypeChangeTarget.java +++ b/boomerangPDS/src/test/java/test/cases/fields/TypeChangeTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.fields; diff --git a/boomerangPDS/src/test/java/test/cases/fields/TypeChangeTest.java b/boomerangPDS/src/test/java/test/cases/fields/TypeChangeTest.java index 11e3d1de4..0b33e055c 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/TypeChangeTest.java +++ b/boomerangPDS/src/test/java/test/cases/fields/TypeChangeTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.fields; diff --git a/boomerangPDS/src/test/java/test/cases/fields/WritePOITarget.java b/boomerangPDS/src/test/java/test/cases/fields/WritePOITarget.java index b4adc4d2c..26b7125c0 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/WritePOITarget.java +++ b/boomerangPDS/src/test/java/test/cases/fields/WritePOITarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.fields; diff --git a/boomerangPDS/src/test/java/test/cases/fields/WritePOITest.java b/boomerangPDS/src/test/java/test/cases/fields/WritePOITest.java index 8ba182136..c48771ff6 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/WritePOITest.java +++ b/boomerangPDS/src/test/java/test/cases/fields/WritePOITest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.fields; diff --git a/boomerangPDS/src/test/java/test/cases/fields/complexity/Fields10LongTarget.java b/boomerangPDS/src/test/java/test/cases/fields/complexity/Fields10LongTarget.java index b4017589f..89a752548 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/complexity/Fields10LongTarget.java +++ b/boomerangPDS/src/test/java/test/cases/fields/complexity/Fields10LongTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.fields.complexity; diff --git a/boomerangPDS/src/test/java/test/cases/fields/complexity/Fields10LongTest.java b/boomerangPDS/src/test/java/test/cases/fields/complexity/Fields10LongTest.java index 7f8da4f40..cded9a28b 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/complexity/Fields10LongTest.java +++ b/boomerangPDS/src/test/java/test/cases/fields/complexity/Fields10LongTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.fields.complexity; diff --git a/boomerangPDS/src/test/java/test/cases/fields/complexity/Fields20LongTarget.java b/boomerangPDS/src/test/java/test/cases/fields/complexity/Fields20LongTarget.java index 7579b7f0e..3bbf06a7e 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/complexity/Fields20LongTarget.java +++ b/boomerangPDS/src/test/java/test/cases/fields/complexity/Fields20LongTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.fields.complexity; diff --git a/boomerangPDS/src/test/java/test/cases/fields/complexity/Fields20LongTest.java b/boomerangPDS/src/test/java/test/cases/fields/complexity/Fields20LongTest.java index 16d261472..b7a4054e4 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/complexity/Fields20LongTest.java +++ b/boomerangPDS/src/test/java/test/cases/fields/complexity/Fields20LongTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.fields.complexity; diff --git a/boomerangPDS/src/test/java/test/cases/fields/complexity/Fields2LongTarget.java b/boomerangPDS/src/test/java/test/cases/fields/complexity/Fields2LongTarget.java index 2dd93601f..72af075a1 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/complexity/Fields2LongTarget.java +++ b/boomerangPDS/src/test/java/test/cases/fields/complexity/Fields2LongTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.fields.complexity; diff --git a/boomerangPDS/src/test/java/test/cases/fields/complexity/Fields2LongTest.java b/boomerangPDS/src/test/java/test/cases/fields/complexity/Fields2LongTest.java index df7a81faf..d8364e938 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/complexity/Fields2LongTest.java +++ b/boomerangPDS/src/test/java/test/cases/fields/complexity/Fields2LongTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.fields.complexity; diff --git a/boomerangPDS/src/test/java/test/cases/fields/complexity/Fields3LongTarget.java b/boomerangPDS/src/test/java/test/cases/fields/complexity/Fields3LongTarget.java index edcd52a68..7a7bd189b 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/complexity/Fields3LongTarget.java +++ b/boomerangPDS/src/test/java/test/cases/fields/complexity/Fields3LongTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.fields.complexity; diff --git a/boomerangPDS/src/test/java/test/cases/fields/complexity/Fields3LongTest.java b/boomerangPDS/src/test/java/test/cases/fields/complexity/Fields3LongTest.java index ba088628e..71cce4584 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/complexity/Fields3LongTest.java +++ b/boomerangPDS/src/test/java/test/cases/fields/complexity/Fields3LongTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.fields.complexity; diff --git a/boomerangPDS/src/test/java/test/cases/fields/complexity/Fields4LongTarget.java b/boomerangPDS/src/test/java/test/cases/fields/complexity/Fields4LongTarget.java index ddf4d2869..4709ce092 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/complexity/Fields4LongTarget.java +++ b/boomerangPDS/src/test/java/test/cases/fields/complexity/Fields4LongTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.fields.complexity; diff --git a/boomerangPDS/src/test/java/test/cases/fields/complexity/Fields4LongTest.java b/boomerangPDS/src/test/java/test/cases/fields/complexity/Fields4LongTest.java index 93bdc2b36..043fc7419 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/complexity/Fields4LongTest.java +++ b/boomerangPDS/src/test/java/test/cases/fields/complexity/Fields4LongTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.fields.complexity; diff --git a/boomerangPDS/src/test/java/test/cases/fields/complexity/Fields5LongTarget.java b/boomerangPDS/src/test/java/test/cases/fields/complexity/Fields5LongTarget.java index 484528cf4..34ee709ef 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/complexity/Fields5LongTarget.java +++ b/boomerangPDS/src/test/java/test/cases/fields/complexity/Fields5LongTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.fields.complexity; diff --git a/boomerangPDS/src/test/java/test/cases/fields/complexity/Fields5LongTest.java b/boomerangPDS/src/test/java/test/cases/fields/complexity/Fields5LongTest.java index 6b35af9f2..07cbd84d0 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/complexity/Fields5LongTest.java +++ b/boomerangPDS/src/test/java/test/cases/fields/complexity/Fields5LongTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.fields.complexity; diff --git a/boomerangPDS/src/test/java/test/cases/fields/complexity/Fields6LongTarget.java b/boomerangPDS/src/test/java/test/cases/fields/complexity/Fields6LongTarget.java index 30dfe2993..4ee7a8ca3 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/complexity/Fields6LongTarget.java +++ b/boomerangPDS/src/test/java/test/cases/fields/complexity/Fields6LongTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.fields.complexity; diff --git a/boomerangPDS/src/test/java/test/cases/fields/complexity/Fields6LongTest.java b/boomerangPDS/src/test/java/test/cases/fields/complexity/Fields6LongTest.java index 7456ed9fc..fdb1c9098 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/complexity/Fields6LongTest.java +++ b/boomerangPDS/src/test/java/test/cases/fields/complexity/Fields6LongTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.fields.complexity; diff --git a/boomerangPDS/src/test/java/test/cases/fields/complexity/Recursion2LongTarget.java b/boomerangPDS/src/test/java/test/cases/fields/complexity/Recursion2LongTarget.java index 4e5f0830a..5780116b7 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/complexity/Recursion2LongTarget.java +++ b/boomerangPDS/src/test/java/test/cases/fields/complexity/Recursion2LongTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.fields.complexity; diff --git a/boomerangPDS/src/test/java/test/cases/fields/complexity/Recursion2LongTest.java b/boomerangPDS/src/test/java/test/cases/fields/complexity/Recursion2LongTest.java index 168d96690..e34caef51 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/complexity/Recursion2LongTest.java +++ b/boomerangPDS/src/test/java/test/cases/fields/complexity/Recursion2LongTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.fields.complexity; diff --git a/boomerangPDS/src/test/java/test/cases/fields/loops/LoopsWithFieldsInterTarget.java b/boomerangPDS/src/test/java/test/cases/fields/loops/LoopsWithFieldsInterTarget.java index a772d579c..8f06a7500 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/loops/LoopsWithFieldsInterTarget.java +++ b/boomerangPDS/src/test/java/test/cases/fields/loops/LoopsWithFieldsInterTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.fields.loops; diff --git a/boomerangPDS/src/test/java/test/cases/fields/loops/LoopsWithFieldsInterTest.java b/boomerangPDS/src/test/java/test/cases/fields/loops/LoopsWithFieldsInterTest.java index 4057c663f..5261dd51b 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/loops/LoopsWithFieldsInterTest.java +++ b/boomerangPDS/src/test/java/test/cases/fields/loops/LoopsWithFieldsInterTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.fields.loops; diff --git a/boomerangPDS/src/test/java/test/cases/fields/loops/LoopsWithFieldsIntraTarget.java b/boomerangPDS/src/test/java/test/cases/fields/loops/LoopsWithFieldsIntraTarget.java index 20ee8ca02..12291cd4e 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/loops/LoopsWithFieldsIntraTarget.java +++ b/boomerangPDS/src/test/java/test/cases/fields/loops/LoopsWithFieldsIntraTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.fields.loops; diff --git a/boomerangPDS/src/test/java/test/cases/fields/loops/LoopsWithFieldsIntraTest.java b/boomerangPDS/src/test/java/test/cases/fields/loops/LoopsWithFieldsIntraTest.java index 997317632..1b43fbcb0 100644 --- a/boomerangPDS/src/test/java/test/cases/fields/loops/LoopsWithFieldsIntraTest.java +++ b/boomerangPDS/src/test/java/test/cases/fields/loops/LoopsWithFieldsIntraTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.fields.loops; diff --git a/boomerangPDS/src/test/java/test/cases/generics/GenericsTarget.java b/boomerangPDS/src/test/java/test/cases/generics/GenericsTarget.java index 108f247f1..5a6088cae 100644 --- a/boomerangPDS/src/test/java/test/cases/generics/GenericsTarget.java +++ b/boomerangPDS/src/test/java/test/cases/generics/GenericsTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.generics; diff --git a/boomerangPDS/src/test/java/test/cases/generics/GenericsTest.java b/boomerangPDS/src/test/java/test/cases/generics/GenericsTest.java index 899f74b45..b48430d41 100644 --- a/boomerangPDS/src/test/java/test/cases/generics/GenericsTest.java +++ b/boomerangPDS/src/test/java/test/cases/generics/GenericsTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.generics; diff --git a/boomerangPDS/src/test/java/test/cases/hashmap/AllAliasLongTarget.java b/boomerangPDS/src/test/java/test/cases/hashmap/AllAliasLongTarget.java index 265efe340..efc65920e 100644 --- a/boomerangPDS/src/test/java/test/cases/hashmap/AllAliasLongTarget.java +++ b/boomerangPDS/src/test/java/test/cases/hashmap/AllAliasLongTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.hashmap; diff --git a/boomerangPDS/src/test/java/test/cases/hashmap/AllAliasLongTest.java b/boomerangPDS/src/test/java/test/cases/hashmap/AllAliasLongTest.java index d9cec6a8c..879ded72e 100644 --- a/boomerangPDS/src/test/java/test/cases/hashmap/AllAliasLongTest.java +++ b/boomerangPDS/src/test/java/test/cases/hashmap/AllAliasLongTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.hashmap; diff --git a/boomerangPDS/src/test/java/test/cases/hashmap/Entry.java b/boomerangPDS/src/test/java/test/cases/hashmap/Entry.java index 08dd5d49f..52ab588f3 100644 --- a/boomerangPDS/src/test/java/test/cases/hashmap/Entry.java +++ b/boomerangPDS/src/test/java/test/cases/hashmap/Entry.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.hashmap; diff --git a/boomerangPDS/src/test/java/test/cases/hashmap/KeySensitiveTarget.java b/boomerangPDS/src/test/java/test/cases/hashmap/KeySensitiveTarget.java index a8369f29a..450f9fcc4 100644 --- a/boomerangPDS/src/test/java/test/cases/hashmap/KeySensitiveTarget.java +++ b/boomerangPDS/src/test/java/test/cases/hashmap/KeySensitiveTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.hashmap; diff --git a/boomerangPDS/src/test/java/test/cases/hashmap/KeySensitiveTest.java b/boomerangPDS/src/test/java/test/cases/hashmap/KeySensitiveTest.java index 2cb7760ea..24e72dafd 100644 --- a/boomerangPDS/src/test/java/test/cases/hashmap/KeySensitiveTest.java +++ b/boomerangPDS/src/test/java/test/cases/hashmap/KeySensitiveTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.hashmap; diff --git a/boomerangPDS/src/test/java/test/cases/hashmap/MapAlloc.java b/boomerangPDS/src/test/java/test/cases/hashmap/MapAlloc.java index 00ad2c8a4..d67e689b2 100644 --- a/boomerangPDS/src/test/java/test/cases/hashmap/MapAlloc.java +++ b/boomerangPDS/src/test/java/test/cases/hashmap/MapAlloc.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.hashmap; diff --git a/boomerangPDS/src/test/java/test/cases/hashmap/Node.java b/boomerangPDS/src/test/java/test/cases/hashmap/Node.java index a39535b7e..e664bbd59 100644 --- a/boomerangPDS/src/test/java/test/cases/hashmap/Node.java +++ b/boomerangPDS/src/test/java/test/cases/hashmap/Node.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.hashmap; diff --git a/boomerangPDS/src/test/java/test/cases/hashmap/TreeNode.java b/boomerangPDS/src/test/java/test/cases/hashmap/TreeNode.java index 81e59c9b3..e3d8f3edb 100644 --- a/boomerangPDS/src/test/java/test/cases/hashmap/TreeNode.java +++ b/boomerangPDS/src/test/java/test/cases/hashmap/TreeNode.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.hashmap; diff --git a/boomerangPDS/src/test/java/test/cases/integers/IntTarget.java b/boomerangPDS/src/test/java/test/cases/integers/IntTarget.java index 5aa0d6be5..850aa4a9e 100644 --- a/boomerangPDS/src/test/java/test/cases/integers/IntTarget.java +++ b/boomerangPDS/src/test/java/test/cases/integers/IntTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.integers; diff --git a/boomerangPDS/src/test/java/test/cases/integers/IntTest.java b/boomerangPDS/src/test/java/test/cases/integers/IntTest.java index a96ac2974..885039a62 100644 --- a/boomerangPDS/src/test/java/test/cases/integers/IntTest.java +++ b/boomerangPDS/src/test/java/test/cases/integers/IntTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.integers; diff --git a/boomerangPDS/src/test/java/test/cases/lists/ArrayAndLinkedListsTarget.java b/boomerangPDS/src/test/java/test/cases/lists/ArrayAndLinkedListsTarget.java index 7ce7e1629..939b2e0ee 100644 --- a/boomerangPDS/src/test/java/test/cases/lists/ArrayAndLinkedListsTarget.java +++ b/boomerangPDS/src/test/java/test/cases/lists/ArrayAndLinkedListsTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.lists; diff --git a/boomerangPDS/src/test/java/test/cases/lists/ArrayAndLinkedListsTest.java b/boomerangPDS/src/test/java/test/cases/lists/ArrayAndLinkedListsTest.java index 7fb904734..1c6c01914 100644 --- a/boomerangPDS/src/test/java/test/cases/lists/ArrayAndLinkedListsTest.java +++ b/boomerangPDS/src/test/java/test/cases/lists/ArrayAndLinkedListsTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.lists; diff --git a/boomerangPDS/src/test/java/test/cases/lists/ArrayListsLongTarget.java b/boomerangPDS/src/test/java/test/cases/lists/ArrayListsLongTarget.java index e848f70f3..bb4d13683 100644 --- a/boomerangPDS/src/test/java/test/cases/lists/ArrayListsLongTarget.java +++ b/boomerangPDS/src/test/java/test/cases/lists/ArrayListsLongTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.lists; diff --git a/boomerangPDS/src/test/java/test/cases/lists/ArrayListsLongTest.java b/boomerangPDS/src/test/java/test/cases/lists/ArrayListsLongTest.java index 6384f935c..c53711cdb 100644 --- a/boomerangPDS/src/test/java/test/cases/lists/ArrayListsLongTest.java +++ b/boomerangPDS/src/test/java/test/cases/lists/ArrayListsLongTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.lists; diff --git a/boomerangPDS/src/test/java/test/cases/lists/LinkedListsLongTarget.java b/boomerangPDS/src/test/java/test/cases/lists/LinkedListsLongTarget.java index 8d90136cc..fe2ad5413 100644 --- a/boomerangPDS/src/test/java/test/cases/lists/LinkedListsLongTarget.java +++ b/boomerangPDS/src/test/java/test/cases/lists/LinkedListsLongTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.lists; diff --git a/boomerangPDS/src/test/java/test/cases/lists/LinkedListsLongTest.java b/boomerangPDS/src/test/java/test/cases/lists/LinkedListsLongTest.java index 7f2c81c1e..bddbafca0 100644 --- a/boomerangPDS/src/test/java/test/cases/lists/LinkedListsLongTest.java +++ b/boomerangPDS/src/test/java/test/cases/lists/LinkedListsLongTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.lists; diff --git a/boomerangPDS/src/test/java/test/cases/lists/LinkedListsTypeLongTarget.java b/boomerangPDS/src/test/java/test/cases/lists/LinkedListsTypeLongTarget.java index 99e32e508..6f71a70af 100644 --- a/boomerangPDS/src/test/java/test/cases/lists/LinkedListsTypeLongTarget.java +++ b/boomerangPDS/src/test/java/test/cases/lists/LinkedListsTypeLongTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.lists; diff --git a/boomerangPDS/src/test/java/test/cases/lists/LinkedListsTypeLongTest.java b/boomerangPDS/src/test/java/test/cases/lists/LinkedListsTypeLongTest.java index 66865fe66..71fcd11d0 100644 --- a/boomerangPDS/src/test/java/test/cases/lists/LinkedListsTypeLongTest.java +++ b/boomerangPDS/src/test/java/test/cases/lists/LinkedListsTypeLongTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.lists; diff --git a/boomerangPDS/src/test/java/test/cases/lists/ListAlloc.java b/boomerangPDS/src/test/java/test/cases/lists/ListAlloc.java index 3a762bb6e..8356e2efd 100644 --- a/boomerangPDS/src/test/java/test/cases/lists/ListAlloc.java +++ b/boomerangPDS/src/test/java/test/cases/lists/ListAlloc.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.lists; diff --git a/boomerangPDS/src/test/java/test/cases/lists/VectorsLongTarget.java b/boomerangPDS/src/test/java/test/cases/lists/VectorsLongTarget.java index 96476a02e..9af0e8666 100644 --- a/boomerangPDS/src/test/java/test/cases/lists/VectorsLongTarget.java +++ b/boomerangPDS/src/test/java/test/cases/lists/VectorsLongTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.lists; diff --git a/boomerangPDS/src/test/java/test/cases/lists/VectorsLongTest.java b/boomerangPDS/src/test/java/test/cases/lists/VectorsLongTest.java index 9505f340c..773073aef 100644 --- a/boomerangPDS/src/test/java/test/cases/lists/VectorsLongTest.java +++ b/boomerangPDS/src/test/java/test/cases/lists/VectorsLongTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.lists; diff --git a/boomerangPDS/src/test/java/test/cases/multiqueries/MultiQueryTarget.java b/boomerangPDS/src/test/java/test/cases/multiqueries/MultiQueryTarget.java index 419549532..e332ef21b 100644 --- a/boomerangPDS/src/test/java/test/cases/multiqueries/MultiQueryTarget.java +++ b/boomerangPDS/src/test/java/test/cases/multiqueries/MultiQueryTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.multiqueries; diff --git a/boomerangPDS/src/test/java/test/cases/multiqueries/MultiQueryTests.java b/boomerangPDS/src/test/java/test/cases/multiqueries/MultiQueryTests.java index f581b9025..2ff085eda 100644 --- a/boomerangPDS/src/test/java/test/cases/multiqueries/MultiQueryTests.java +++ b/boomerangPDS/src/test/java/test/cases/multiqueries/MultiQueryTests.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.multiqueries; diff --git a/boomerangPDS/src/test/java/test/cases/realworld/FixAfterInsertion.java b/boomerangPDS/src/test/java/test/cases/realworld/FixAfterInsertion.java index 40ab3d638..13cefae22 100644 --- a/boomerangPDS/src/test/java/test/cases/realworld/FixAfterInsertion.java +++ b/boomerangPDS/src/test/java/test/cases/realworld/FixAfterInsertion.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.realworld; diff --git a/boomerangPDS/src/test/java/test/cases/realworld/FixAfterInsertionLongTarget.java b/boomerangPDS/src/test/java/test/cases/realworld/FixAfterInsertionLongTarget.java index e48401515..5ffbaec6c 100644 --- a/boomerangPDS/src/test/java/test/cases/realworld/FixAfterInsertionLongTarget.java +++ b/boomerangPDS/src/test/java/test/cases/realworld/FixAfterInsertionLongTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.realworld; diff --git a/boomerangPDS/src/test/java/test/cases/realworld/FixAfterInsertionLongTest.java b/boomerangPDS/src/test/java/test/cases/realworld/FixAfterInsertionLongTest.java index 24307b0d6..261932abd 100644 --- a/boomerangPDS/src/test/java/test/cases/realworld/FixAfterInsertionLongTest.java +++ b/boomerangPDS/src/test/java/test/cases/realworld/FixAfterInsertionLongTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.realworld; diff --git a/boomerangPDS/src/test/java/test/cases/realworld/ScalabilityOfBackwardAnalysisTarget.java b/boomerangPDS/src/test/java/test/cases/realworld/ScalabilityOfBackwardAnalysisTarget.java index e78dd91d5..008025a4e 100644 --- a/boomerangPDS/src/test/java/test/cases/realworld/ScalabilityOfBackwardAnalysisTarget.java +++ b/boomerangPDS/src/test/java/test/cases/realworld/ScalabilityOfBackwardAnalysisTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.realworld; diff --git a/boomerangPDS/src/test/java/test/cases/realworld/ScalabilityOfBackwardAnalysisTest.java b/boomerangPDS/src/test/java/test/cases/realworld/ScalabilityOfBackwardAnalysisTest.java index a57fca959..1fc2904fb 100644 --- a/boomerangPDS/src/test/java/test/cases/realworld/ScalabilityOfBackwardAnalysisTest.java +++ b/boomerangPDS/src/test/java/test/cases/realworld/ScalabilityOfBackwardAnalysisTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.realworld; diff --git a/boomerangPDS/src/test/java/test/cases/reflection/ReflectionAlloc.java b/boomerangPDS/src/test/java/test/cases/reflection/ReflectionAlloc.java index f194cfc74..19f5a2657 100644 --- a/boomerangPDS/src/test/java/test/cases/reflection/ReflectionAlloc.java +++ b/boomerangPDS/src/test/java/test/cases/reflection/ReflectionAlloc.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.reflection; diff --git a/boomerangPDS/src/test/java/test/cases/reflection/ReflectionTarget.java b/boomerangPDS/src/test/java/test/cases/reflection/ReflectionTarget.java index 6d9e3ff1c..82e25f877 100644 --- a/boomerangPDS/src/test/java/test/cases/reflection/ReflectionTarget.java +++ b/boomerangPDS/src/test/java/test/cases/reflection/ReflectionTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.reflection; diff --git a/boomerangPDS/src/test/java/test/cases/reflection/ReflectionTest.java b/boomerangPDS/src/test/java/test/cases/reflection/ReflectionTest.java index 746741347..6806ad622 100644 --- a/boomerangPDS/src/test/java/test/cases/reflection/ReflectionTest.java +++ b/boomerangPDS/src/test/java/test/cases/reflection/ReflectionTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.reflection; diff --git a/boomerangPDS/src/test/java/test/cases/sets/CustomMapTarget.java b/boomerangPDS/src/test/java/test/cases/sets/CustomMapTarget.java index 88cbb7a47..c714a1e85 100644 --- a/boomerangPDS/src/test/java/test/cases/sets/CustomMapTarget.java +++ b/boomerangPDS/src/test/java/test/cases/sets/CustomMapTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.sets; diff --git a/boomerangPDS/src/test/java/test/cases/sets/CustomMapTest.java b/boomerangPDS/src/test/java/test/cases/sets/CustomMapTest.java index d6bbf398c..8c3719f2d 100644 --- a/boomerangPDS/src/test/java/test/cases/sets/CustomMapTest.java +++ b/boomerangPDS/src/test/java/test/cases/sets/CustomMapTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.sets; diff --git a/boomerangPDS/src/test/java/test/cases/sets/CustomSetTarget.java b/boomerangPDS/src/test/java/test/cases/sets/CustomSetTarget.java index 2063956e3..42d28cfaf 100644 --- a/boomerangPDS/src/test/java/test/cases/sets/CustomSetTarget.java +++ b/boomerangPDS/src/test/java/test/cases/sets/CustomSetTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.sets; diff --git a/boomerangPDS/src/test/java/test/cases/sets/CustomSetTest.java b/boomerangPDS/src/test/java/test/cases/sets/CustomSetTest.java index 76aede697..84be5e62f 100644 --- a/boomerangPDS/src/test/java/test/cases/sets/CustomSetTest.java +++ b/boomerangPDS/src/test/java/test/cases/sets/CustomSetTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.sets; diff --git a/boomerangPDS/src/test/java/test/cases/sets/HashMapGetLongTarget.java b/boomerangPDS/src/test/java/test/cases/sets/HashMapGetLongTarget.java index 65dea1ec6..f9ae11220 100644 --- a/boomerangPDS/src/test/java/test/cases/sets/HashMapGetLongTarget.java +++ b/boomerangPDS/src/test/java/test/cases/sets/HashMapGetLongTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.sets; diff --git a/boomerangPDS/src/test/java/test/cases/sets/HashMapGetLongTest.java b/boomerangPDS/src/test/java/test/cases/sets/HashMapGetLongTest.java index 6d0e89ea9..dffaed338 100644 --- a/boomerangPDS/src/test/java/test/cases/sets/HashMapGetLongTest.java +++ b/boomerangPDS/src/test/java/test/cases/sets/HashMapGetLongTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.sets; diff --git a/boomerangPDS/src/test/java/test/cases/sets/HashMapsLongTarget.java b/boomerangPDS/src/test/java/test/cases/sets/HashMapsLongTarget.java index 3a4d2cc9d..73b727eb9 100644 --- a/boomerangPDS/src/test/java/test/cases/sets/HashMapsLongTarget.java +++ b/boomerangPDS/src/test/java/test/cases/sets/HashMapsLongTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.sets; diff --git a/boomerangPDS/src/test/java/test/cases/sets/HashMapsLongTest.java b/boomerangPDS/src/test/java/test/cases/sets/HashMapsLongTest.java index 9cd896662..b3f2927e3 100644 --- a/boomerangPDS/src/test/java/test/cases/sets/HashMapsLongTest.java +++ b/boomerangPDS/src/test/java/test/cases/sets/HashMapsLongTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.sets; diff --git a/boomerangPDS/src/test/java/test/cases/sets/HashSetsLongTarget.java b/boomerangPDS/src/test/java/test/cases/sets/HashSetsLongTarget.java index fa816f0d3..458b9b0a1 100644 --- a/boomerangPDS/src/test/java/test/cases/sets/HashSetsLongTarget.java +++ b/boomerangPDS/src/test/java/test/cases/sets/HashSetsLongTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.sets; diff --git a/boomerangPDS/src/test/java/test/cases/sets/HashSetsLongTest.java b/boomerangPDS/src/test/java/test/cases/sets/HashSetsLongTest.java index 0fea01b73..c856206de 100644 --- a/boomerangPDS/src/test/java/test/cases/sets/HashSetsLongTest.java +++ b/boomerangPDS/src/test/java/test/cases/sets/HashSetsLongTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.sets; diff --git a/boomerangPDS/src/test/java/test/cases/sets/MyInnerMap.java b/boomerangPDS/src/test/java/test/cases/sets/MyInnerMap.java index 9a82b0109..138559f0c 100644 --- a/boomerangPDS/src/test/java/test/cases/sets/MyInnerMap.java +++ b/boomerangPDS/src/test/java/test/cases/sets/MyInnerMap.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.sets; diff --git a/boomerangPDS/src/test/java/test/cases/sets/MyMap.java b/boomerangPDS/src/test/java/test/cases/sets/MyMap.java index 6971f06e9..4269b3b41 100644 --- a/boomerangPDS/src/test/java/test/cases/sets/MyMap.java +++ b/boomerangPDS/src/test/java/test/cases/sets/MyMap.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.sets; diff --git a/boomerangPDS/src/test/java/test/cases/sets/SetAlloc.java b/boomerangPDS/src/test/java/test/cases/sets/SetAlloc.java index 6efb8731e..5512aef0f 100644 --- a/boomerangPDS/src/test/java/test/cases/sets/SetAlloc.java +++ b/boomerangPDS/src/test/java/test/cases/sets/SetAlloc.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.sets; diff --git a/boomerangPDS/src/test/java/test/cases/sets/TreeMapLongTarget.java b/boomerangPDS/src/test/java/test/cases/sets/TreeMapLongTarget.java index eb2ad07b8..1b8a86a67 100644 --- a/boomerangPDS/src/test/java/test/cases/sets/TreeMapLongTarget.java +++ b/boomerangPDS/src/test/java/test/cases/sets/TreeMapLongTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.sets; diff --git a/boomerangPDS/src/test/java/test/cases/sets/TreeMapLongTest.java b/boomerangPDS/src/test/java/test/cases/sets/TreeMapLongTest.java index ce25a7e19..6718a9dcf 100644 --- a/boomerangPDS/src/test/java/test/cases/sets/TreeMapLongTest.java +++ b/boomerangPDS/src/test/java/test/cases/sets/TreeMapLongTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.sets; diff --git a/boomerangPDS/src/test/java/test/cases/sets/TreeMapMultipleInstancesTarget.java b/boomerangPDS/src/test/java/test/cases/sets/TreeMapMultipleInstancesTarget.java index 396a82947..35ae38edc 100644 --- a/boomerangPDS/src/test/java/test/cases/sets/TreeMapMultipleInstancesTarget.java +++ b/boomerangPDS/src/test/java/test/cases/sets/TreeMapMultipleInstancesTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.sets; diff --git a/boomerangPDS/src/test/java/test/cases/sets/TreeMapMultipleInstancesTest.java b/boomerangPDS/src/test/java/test/cases/sets/TreeMapMultipleInstancesTest.java index ec4465d3e..10f939917 100644 --- a/boomerangPDS/src/test/java/test/cases/sets/TreeMapMultipleInstancesTest.java +++ b/boomerangPDS/src/test/java/test/cases/sets/TreeMapMultipleInstancesTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.sets; diff --git a/boomerangPDS/src/test/java/test/cases/sets/TreeSetsLongTarget.java b/boomerangPDS/src/test/java/test/cases/sets/TreeSetsLongTarget.java index ca4862737..6a7279b9f 100644 --- a/boomerangPDS/src/test/java/test/cases/sets/TreeSetsLongTarget.java +++ b/boomerangPDS/src/test/java/test/cases/sets/TreeSetsLongTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.sets; diff --git a/boomerangPDS/src/test/java/test/cases/sets/TreeSetsLongTest.java b/boomerangPDS/src/test/java/test/cases/sets/TreeSetsLongTest.java index 97a3dda55..11df99321 100644 --- a/boomerangPDS/src/test/java/test/cases/sets/TreeSetsLongTest.java +++ b/boomerangPDS/src/test/java/test/cases/sets/TreeSetsLongTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.sets; diff --git a/boomerangPDS/src/test/java/test/cases/statics/SimpleSingletonTarget.java b/boomerangPDS/src/test/java/test/cases/statics/SimpleSingletonTarget.java index dddc6c5fd..5a46932cc 100644 --- a/boomerangPDS/src/test/java/test/cases/statics/SimpleSingletonTarget.java +++ b/boomerangPDS/src/test/java/test/cases/statics/SimpleSingletonTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.statics; diff --git a/boomerangPDS/src/test/java/test/cases/statics/SimpleSingletonTest.java b/boomerangPDS/src/test/java/test/cases/statics/SimpleSingletonTest.java index 1930e3a61..82b43b5a9 100644 --- a/boomerangPDS/src/test/java/test/cases/statics/SimpleSingletonTest.java +++ b/boomerangPDS/src/test/java/test/cases/statics/SimpleSingletonTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.statics; diff --git a/boomerangPDS/src/test/java/test/cases/statics/SingletonTarget.java b/boomerangPDS/src/test/java/test/cases/statics/SingletonTarget.java index e2c8f1618..c78b323c3 100644 --- a/boomerangPDS/src/test/java/test/cases/statics/SingletonTarget.java +++ b/boomerangPDS/src/test/java/test/cases/statics/SingletonTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.statics; diff --git a/boomerangPDS/src/test/java/test/cases/statics/SingletonTest.java b/boomerangPDS/src/test/java/test/cases/statics/SingletonTest.java index 8f5e71fe0..a4ece4259 100644 --- a/boomerangPDS/src/test/java/test/cases/statics/SingletonTest.java +++ b/boomerangPDS/src/test/java/test/cases/statics/SingletonTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.statics; diff --git a/boomerangPDS/src/test/java/test/cases/statics/StaticFieldFlowsTarget.java b/boomerangPDS/src/test/java/test/cases/statics/StaticFieldFlowsTarget.java index 204662af6..71a81e55e 100644 --- a/boomerangPDS/src/test/java/test/cases/statics/StaticFieldFlowsTarget.java +++ b/boomerangPDS/src/test/java/test/cases/statics/StaticFieldFlowsTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.statics; diff --git a/boomerangPDS/src/test/java/test/cases/statics/StaticFieldFlowsTest.java b/boomerangPDS/src/test/java/test/cases/statics/StaticFieldFlowsTest.java index 0e72d3f8f..1ca3769b4 100644 --- a/boomerangPDS/src/test/java/test/cases/statics/StaticFieldFlowsTest.java +++ b/boomerangPDS/src/test/java/test/cases/statics/StaticFieldFlowsTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.statics; diff --git a/boomerangPDS/src/test/java/test/cases/statics/StaticInitializerTarget.java b/boomerangPDS/src/test/java/test/cases/statics/StaticInitializerTarget.java index 0f1f9f067..e69b3941e 100644 --- a/boomerangPDS/src/test/java/test/cases/statics/StaticInitializerTarget.java +++ b/boomerangPDS/src/test/java/test/cases/statics/StaticInitializerTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.statics; diff --git a/boomerangPDS/src/test/java/test/cases/statics/StaticInitializerTest.java b/boomerangPDS/src/test/java/test/cases/statics/StaticInitializerTest.java index 73bb7b96f..1761e4d54 100644 --- a/boomerangPDS/src/test/java/test/cases/statics/StaticInitializerTest.java +++ b/boomerangPDS/src/test/java/test/cases/statics/StaticInitializerTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.statics; diff --git a/boomerangPDS/src/test/java/test/cases/statics/StaticWithSuperClassesTarget.java b/boomerangPDS/src/test/java/test/cases/statics/StaticWithSuperClassesTarget.java index c7e636c0e..659ce6367 100644 --- a/boomerangPDS/src/test/java/test/cases/statics/StaticWithSuperClassesTarget.java +++ b/boomerangPDS/src/test/java/test/cases/statics/StaticWithSuperClassesTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.statics; diff --git a/boomerangPDS/src/test/java/test/cases/statics/StaticWithSuperClassesTest.java b/boomerangPDS/src/test/java/test/cases/statics/StaticWithSuperClassesTest.java index caa5903e8..8c85caa67 100644 --- a/boomerangPDS/src/test/java/test/cases/statics/StaticWithSuperClassesTest.java +++ b/boomerangPDS/src/test/java/test/cases/statics/StaticWithSuperClassesTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.statics; diff --git a/boomerangPDS/src/test/java/test/cases/statics/StaticsAlloc.java b/boomerangPDS/src/test/java/test/cases/statics/StaticsAlloc.java index e9ba28c0d..38b112732 100644 --- a/boomerangPDS/src/test/java/test/cases/statics/StaticsAlloc.java +++ b/boomerangPDS/src/test/java/test/cases/statics/StaticsAlloc.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.statics; diff --git a/boomerangPDS/src/test/java/test/cases/string/StringTarget.java b/boomerangPDS/src/test/java/test/cases/string/StringTarget.java index 074874526..a561b6c39 100644 --- a/boomerangPDS/src/test/java/test/cases/string/StringTarget.java +++ b/boomerangPDS/src/test/java/test/cases/string/StringTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.string; diff --git a/boomerangPDS/src/test/java/test/cases/string/StringTest.java b/boomerangPDS/src/test/java/test/cases/string/StringTest.java index 262c6c106..29af82abb 100644 --- a/boomerangPDS/src/test/java/test/cases/string/StringTest.java +++ b/boomerangPDS/src/test/java/test/cases/string/StringTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.string; diff --git a/boomerangPDS/src/test/java/test/cases/subclassing/AbstractClassWithInnerSubclassTarget.java b/boomerangPDS/src/test/java/test/cases/subclassing/AbstractClassWithInnerSubclassTarget.java index 99fffeacf..b89b8771c 100644 --- a/boomerangPDS/src/test/java/test/cases/subclassing/AbstractClassWithInnerSubclassTarget.java +++ b/boomerangPDS/src/test/java/test/cases/subclassing/AbstractClassWithInnerSubclassTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.subclassing; diff --git a/boomerangPDS/src/test/java/test/cases/subclassing/AbstractClassWithInnerSubclassTest.java b/boomerangPDS/src/test/java/test/cases/subclassing/AbstractClassWithInnerSubclassTest.java index 8ebec603f..5087086de 100644 --- a/boomerangPDS/src/test/java/test/cases/subclassing/AbstractClassWithInnerSubclassTest.java +++ b/boomerangPDS/src/test/java/test/cases/subclassing/AbstractClassWithInnerSubclassTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.subclassing; diff --git a/boomerangPDS/src/test/java/test/cases/subclassing/InnerClass2Target.java b/boomerangPDS/src/test/java/test/cases/subclassing/InnerClass2Target.java index 5f47c4786..b107a2698 100644 --- a/boomerangPDS/src/test/java/test/cases/subclassing/InnerClass2Target.java +++ b/boomerangPDS/src/test/java/test/cases/subclassing/InnerClass2Target.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.subclassing; diff --git a/boomerangPDS/src/test/java/test/cases/subclassing/InnerClass2Test.java b/boomerangPDS/src/test/java/test/cases/subclassing/InnerClass2Test.java index 8098ab15a..66109a0c2 100644 --- a/boomerangPDS/src/test/java/test/cases/subclassing/InnerClass2Test.java +++ b/boomerangPDS/src/test/java/test/cases/subclassing/InnerClass2Test.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.subclassing; diff --git a/boomerangPDS/src/test/java/test/cases/subclassing/InnerClassTarget.java b/boomerangPDS/src/test/java/test/cases/subclassing/InnerClassTarget.java index 46d3c1712..82aed7faa 100644 --- a/boomerangPDS/src/test/java/test/cases/subclassing/InnerClassTarget.java +++ b/boomerangPDS/src/test/java/test/cases/subclassing/InnerClassTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.subclassing; diff --git a/boomerangPDS/src/test/java/test/cases/subclassing/InnerClassTest.java b/boomerangPDS/src/test/java/test/cases/subclassing/InnerClassTest.java index 615227025..52f5aa59e 100644 --- a/boomerangPDS/src/test/java/test/cases/subclassing/InnerClassTest.java +++ b/boomerangPDS/src/test/java/test/cases/subclassing/InnerClassTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.subclassing; diff --git a/boomerangPDS/src/test/java/test/cases/subclassing/SubclassingAlloc.java b/boomerangPDS/src/test/java/test/cases/subclassing/SubclassingAlloc.java index eee514046..85636c786 100644 --- a/boomerangPDS/src/test/java/test/cases/subclassing/SubclassingAlloc.java +++ b/boomerangPDS/src/test/java/test/cases/subclassing/SubclassingAlloc.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.subclassing; diff --git a/boomerangPDS/src/test/java/test/cases/subclassing/SubclassingTarget.java b/boomerangPDS/src/test/java/test/cases/subclassing/SubclassingTarget.java index 512b32f4f..fb51459b4 100644 --- a/boomerangPDS/src/test/java/test/cases/subclassing/SubclassingTarget.java +++ b/boomerangPDS/src/test/java/test/cases/subclassing/SubclassingTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.subclassing; diff --git a/boomerangPDS/src/test/java/test/cases/subclassing/SubclassingTest.java b/boomerangPDS/src/test/java/test/cases/subclassing/SubclassingTest.java index 22ee65c1d..b041570c0 100644 --- a/boomerangPDS/src/test/java/test/cases/subclassing/SubclassingTest.java +++ b/boomerangPDS/src/test/java/test/cases/subclassing/SubclassingTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.subclassing; diff --git a/boomerangPDS/src/test/java/test/cases/synchronizd/BlockTarget.java b/boomerangPDS/src/test/java/test/cases/synchronizd/BlockTarget.java index ed77bd674..c668189f4 100644 --- a/boomerangPDS/src/test/java/test/cases/synchronizd/BlockTarget.java +++ b/boomerangPDS/src/test/java/test/cases/synchronizd/BlockTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.synchronizd; diff --git a/boomerangPDS/src/test/java/test/cases/synchronizd/BlockTest.java b/boomerangPDS/src/test/java/test/cases/synchronizd/BlockTest.java index c27c837ab..b4588f578 100644 --- a/boomerangPDS/src/test/java/test/cases/synchronizd/BlockTest.java +++ b/boomerangPDS/src/test/java/test/cases/synchronizd/BlockTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.synchronizd; diff --git a/boomerangPDS/src/test/java/test/cases/synchronizd/SynchronizedAlloc.java b/boomerangPDS/src/test/java/test/cases/synchronizd/SynchronizedAlloc.java index 3b71ea988..940fb65c9 100644 --- a/boomerangPDS/src/test/java/test/cases/synchronizd/SynchronizedAlloc.java +++ b/boomerangPDS/src/test/java/test/cases/synchronizd/SynchronizedAlloc.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.synchronizd; diff --git a/boomerangPDS/src/test/java/test/cases/threading/InnerClassWithThreadTarget.java b/boomerangPDS/src/test/java/test/cases/threading/InnerClassWithThreadTarget.java index f044651e3..d9de6d836 100644 --- a/boomerangPDS/src/test/java/test/cases/threading/InnerClassWithThreadTarget.java +++ b/boomerangPDS/src/test/java/test/cases/threading/InnerClassWithThreadTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.threading; diff --git a/boomerangPDS/src/test/java/test/cases/threading/InnerClassWithThreadTest.java b/boomerangPDS/src/test/java/test/cases/threading/InnerClassWithThreadTest.java index c44b64bde..1b06f6e4b 100644 --- a/boomerangPDS/src/test/java/test/cases/threading/InnerClassWithThreadTest.java +++ b/boomerangPDS/src/test/java/test/cases/threading/InnerClassWithThreadTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.threading; diff --git a/boomerangPDS/src/test/java/test/cases/threading/ThreadingAlloc.java b/boomerangPDS/src/test/java/test/cases/threading/ThreadingAlloc.java index b80869ad5..33b2a816e 100644 --- a/boomerangPDS/src/test/java/test/cases/threading/ThreadingAlloc.java +++ b/boomerangPDS/src/test/java/test/cases/threading/ThreadingAlloc.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.threading; diff --git a/boomerangPDS/src/test/java/test/cases/typing/InterfaceInvocationTarget.java b/boomerangPDS/src/test/java/test/cases/typing/InterfaceInvocationTarget.java index c08b63c6d..174c9c05d 100644 --- a/boomerangPDS/src/test/java/test/cases/typing/InterfaceInvocationTarget.java +++ b/boomerangPDS/src/test/java/test/cases/typing/InterfaceInvocationTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.typing; diff --git a/boomerangPDS/src/test/java/test/cases/typing/InterfaceInvocationTest.java b/boomerangPDS/src/test/java/test/cases/typing/InterfaceInvocationTest.java index b9edd7ff4..047a46c64 100644 --- a/boomerangPDS/src/test/java/test/cases/typing/InterfaceInvocationTest.java +++ b/boomerangPDS/src/test/java/test/cases/typing/InterfaceInvocationTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.typing; diff --git a/boomerangPDS/src/test/java/test/cases/typing/TypeConfusionTarget.java b/boomerangPDS/src/test/java/test/cases/typing/TypeConfusionTarget.java index ef139229a..15e8c5827 100644 --- a/boomerangPDS/src/test/java/test/cases/typing/TypeConfusionTarget.java +++ b/boomerangPDS/src/test/java/test/cases/typing/TypeConfusionTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.typing; diff --git a/boomerangPDS/src/test/java/test/cases/typing/TypeConfusionTest.java b/boomerangPDS/src/test/java/test/cases/typing/TypeConfusionTest.java index 358fdfbe1..ad5220902 100644 --- a/boomerangPDS/src/test/java/test/cases/typing/TypeConfusionTest.java +++ b/boomerangPDS/src/test/java/test/cases/typing/TypeConfusionTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.typing; diff --git a/boomerangPDS/src/test/java/test/cases/unbalanced/UnbalancedAlloc.java b/boomerangPDS/src/test/java/test/cases/unbalanced/UnbalancedAlloc.java index ffc25967a..7f1eff664 100644 --- a/boomerangPDS/src/test/java/test/cases/unbalanced/UnbalancedAlloc.java +++ b/boomerangPDS/src/test/java/test/cases/unbalanced/UnbalancedAlloc.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.unbalanced; diff --git a/boomerangPDS/src/test/java/test/cases/unbalanced/UnbalancedScopesTarget.java b/boomerangPDS/src/test/java/test/cases/unbalanced/UnbalancedScopesTarget.java index 379f477c7..a85204cd0 100644 --- a/boomerangPDS/src/test/java/test/cases/unbalanced/UnbalancedScopesTarget.java +++ b/boomerangPDS/src/test/java/test/cases/unbalanced/UnbalancedScopesTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.unbalanced; diff --git a/boomerangPDS/src/test/java/test/cases/unbalanced/UnbalancedScopesTest.java b/boomerangPDS/src/test/java/test/cases/unbalanced/UnbalancedScopesTest.java index 4b72e63c0..6b59275f3 100644 --- a/boomerangPDS/src/test/java/test/cases/unbalanced/UnbalancedScopesTest.java +++ b/boomerangPDS/src/test/java/test/cases/unbalanced/UnbalancedScopesTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.cases.unbalanced; diff --git a/boomerangPDS/src/test/java/test/core/AbstractBoomerangTest.java b/boomerangPDS/src/test/java/test/core/AbstractBoomerangTest.java index dd7858607..896ca3690 100644 --- a/boomerangPDS/src/test/java/test/core/AbstractBoomerangTest.java +++ b/boomerangPDS/src/test/java/test/core/AbstractBoomerangTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.core; diff --git a/boomerangPDS/src/test/java/test/core/AllocationSiteOf.java b/boomerangPDS/src/test/java/test/core/AllocationSiteOf.java index 73cbe5e5c..24cf429a9 100644 --- a/boomerangPDS/src/test/java/test/core/AllocationSiteOf.java +++ b/boomerangPDS/src/test/java/test/core/AllocationSiteOf.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.core; diff --git a/boomerangPDS/src/test/java/test/core/FirstArgumentOf.java b/boomerangPDS/src/test/java/test/core/FirstArgumentOf.java index 564db64f7..9fce93306 100644 --- a/boomerangPDS/src/test/java/test/core/FirstArgumentOf.java +++ b/boomerangPDS/src/test/java/test/core/FirstArgumentOf.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.core; diff --git a/boomerangPDS/src/test/java/test/core/IntegerAllocationSiteOf.java b/boomerangPDS/src/test/java/test/core/IntegerAllocationSiteOf.java index 65c2eb7e1..097f5c950 100644 --- a/boomerangPDS/src/test/java/test/core/IntegerAllocationSiteOf.java +++ b/boomerangPDS/src/test/java/test/core/IntegerAllocationSiteOf.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.core; diff --git a/boomerangPDS/src/test/java/test/core/MultiQueryBoomerangTest.java b/boomerangPDS/src/test/java/test/core/MultiQueryBoomerangTest.java index 308a14c7e..d60af935a 100644 --- a/boomerangPDS/src/test/java/test/core/MultiQueryBoomerangTest.java +++ b/boomerangPDS/src/test/java/test/core/MultiQueryBoomerangTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.core; diff --git a/boomerangPDS/src/test/java/test/core/Preanalysis.java b/boomerangPDS/src/test/java/test/core/Preanalysis.java index 9c3b9ed6d..fd8e04622 100644 --- a/boomerangPDS/src/test/java/test/core/Preanalysis.java +++ b/boomerangPDS/src/test/java/test/core/Preanalysis.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.core; diff --git a/boomerangPDS/src/test/java/test/core/QueryForCallSiteDetector.java b/boomerangPDS/src/test/java/test/core/QueryForCallSiteDetector.java index c9f71c3da..90f31eaaf 100644 --- a/boomerangPDS/src/test/java/test/core/QueryForCallSiteDetector.java +++ b/boomerangPDS/src/test/java/test/core/QueryForCallSiteDetector.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.core; diff --git a/boomerangPDS/src/test/java/test/core/QueryMethods.java b/boomerangPDS/src/test/java/test/core/QueryMethods.java index b20ed0531..9b174e5d8 100644 --- a/boomerangPDS/src/test/java/test/core/QueryMethods.java +++ b/boomerangPDS/src/test/java/test/core/QueryMethods.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.core; diff --git a/boomerangPDS/src/test/java/test/core/ValueOfInterestInUnit.java b/boomerangPDS/src/test/java/test/core/ValueOfInterestInUnit.java index bdaa42a53..b8b7f318e 100644 --- a/boomerangPDS/src/test/java/test/core/ValueOfInterestInUnit.java +++ b/boomerangPDS/src/test/java/test/core/ValueOfInterestInUnit.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.core; diff --git a/boomerangPDS/src/test/java/test/options/BoomerangOptionsTest.java b/boomerangPDS/src/test/java/test/options/BoomerangOptionsTest.java index a7c9ad4f2..172278e6f 100644 --- a/boomerangPDS/src/test/java/test/options/BoomerangOptionsTest.java +++ b/boomerangPDS/src/test/java/test/options/BoomerangOptionsTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.options; diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalCallGraph.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalCallGraph.scala index a3a49f21b..e7fdfa987 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalCallGraph.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalCallGraph.scala @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.opal @@ -127,8 +130,7 @@ class OpalCallGraph( .reachableMethods() .foreach(method => { method.method match { - case definedMethod: DefinedMethod - if definedMethod.definedMethod.isStaticInitializer => + case definedMethod: DefinedMethod if definedMethod.definedMethod.isStaticInitializer => if (definedMethod.definedMethod.body.isDefined) { addEntryPoint(OpalMethod(definedMethod.definedMethod)) } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalClient.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalClient.scala index 5085bc8de..409bdcad0 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalClient.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalClient.scala @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.opal diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalFrameworkScope.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalFrameworkScope.scala index d76317d75..a63c2d5d6 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalFrameworkScope.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalFrameworkScope.scala @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.opal diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalArrayRef.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalArrayRef.scala index 30af01cf3..262d895c3 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalArrayRef.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalArrayRef.scala @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.opal.tac diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalControlFlowGraph.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalControlFlowGraph.scala index 8a4824b2b..2a0cc2f1a 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalControlFlowGraph.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalControlFlowGraph.scala @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.opal.tac diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalDeclaredMethod.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalDeclaredMethod.scala index a9b99a2e6..f5a417cb9 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalDeclaredMethod.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalDeclaredMethod.scala @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.opal.tac diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalDoubleVal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalDoubleVal.scala index 5bb003a77..84d697755 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalDoubleVal.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalDoubleVal.scala @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.opal.tac diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalField.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalField.scala index d686c9868..0bdeff459 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalField.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalField.scala @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.opal.tac diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalIfStatement.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalIfStatement.scala index 9b229b49d..23bf00db0 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalIfStatement.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalIfStatement.scala @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.opal.tac diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalInstanceFieldRef.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalInstanceFieldRef.scala index 7f303e95c..a319334da 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalInstanceFieldRef.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalInstanceFieldRef.scala @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.opal.tac diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalInvokeExpr.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalInvokeExpr.scala index 45573e10e..bbac976dc 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalInvokeExpr.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalInvokeExpr.scala @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.opal.tac diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalLocal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalLocal.scala index e983db113..a5a61992d 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalLocal.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalLocal.scala @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.opal.tac diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalMethod.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalMethod.scala index 868dbe274..2a1c44948 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalMethod.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalMethod.scala @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.opal.tac diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalNullType.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalNullType.scala index ffe24ffdd..78c9f5143 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalNullType.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalNullType.scala @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.opal.tac diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalPhantomMethod.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalPhantomMethod.scala index c2341c354..fb381d3d4 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalPhantomMethod.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalPhantomMethod.scala @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.opal.tac diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalPhantomWrappedClass.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalPhantomWrappedClass.scala index 045e82cc2..47aa37612 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalPhantomWrappedClass.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalPhantomWrappedClass.scala @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.opal.tac diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala index 04569a51c..fdb3498c2 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.opal.tac diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatementFormatter.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatementFormatter.scala index 647b469df..28bb294f4 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatementFormatter.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatementFormatter.scala @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.opal.tac @@ -55,15 +58,11 @@ object OpalStatementFormatter { } if (delegate.isAssignment) { - if ( - delegate.asAssignment.expr.isVar && delegate.asAssignment.expr.asVar.isParameterLocal - ) { + if (delegate.asAssignment.expr.isVar && delegate.asAssignment.expr.asVar.isParameterLocal) { return s"${delegate.asAssignment.targetVar} := @${delegate.asAssignment.expr}: ${stmt.getMethod}" } - if ( - delegate.asAssignment.expr.isVar && delegate.asAssignment.expr.asVar.isExceptionLocal - ) { + if (delegate.asAssignment.expr.isVar && delegate.asAssignment.expr.asVar.isExceptionLocal) { return s"${delegate.asAssignment.targetVar} := @caughtException: ${delegate.asAssignment.expr}" } } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStaticFieldRef.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStaticFieldRef.scala index 477b4fbf7..3595e1a0f 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStaticFieldRef.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStaticFieldRef.scala @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.opal.tac diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStaticFieldVal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStaticFieldVal.scala index 55c1cc985..7df95733d 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStaticFieldVal.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStaticFieldVal.scala @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.opal.tac diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalType.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalType.scala index 97c8e820d..b062491bb 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalType.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalType.scala @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.opal.tac diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalVal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalVal.scala index e7707bbae..57b15dcdc 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalVal.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalVal.scala @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.opal.tac diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalWrappedClass.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalWrappedClass.scala index 7c34b482a..e94d9644f 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalWrappedClass.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalWrappedClass.scala @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.opal.tac diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/BoomerangTACode.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/BoomerangTACode.scala index 11e0c4163..db50199ff 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/BoomerangTACode.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/BoomerangTACode.scala @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.opal.transformation diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/StmtGraph.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/StmtGraph.scala index 800504290..b879bf555 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/StmtGraph.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/StmtGraph.scala @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.opal.transformation diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacBodyBuilder.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacBodyBuilder.scala index b2d0c4710..23ea3dd34 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacBodyBuilder.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacBodyBuilder.scala @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.opal.transformation diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacLocal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacLocal.scala index e372cdba4..d19c9b29e 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacLocal.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacLocal.scala @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.opal.transformation diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/Operand.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/Operand.scala index 14e24672f..e45106b49 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/Operand.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/Operand.scala @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.opal.transformation.stack diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStack.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStack.scala index 63f8f3696..90a83db81 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStack.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStack.scala @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.opal.transformation.stack diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackBuilder.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackBuilder.scala index 5502549a9..aaf8a4e8b 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackBuilder.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackBuilder.scala @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.opal.transformation.stack @@ -199,9 +202,7 @@ object OperandStackBuilder { val v2 = stack.pop val v3 = stack.pop - if ( - v1.cTpe.categoryId == 1 && v2.cTpe.categoryId == 1 && v3.cTpe.categoryId == 1 - ) { + if (v1.cTpe.categoryId == 1 && v2.cTpe.categoryId == 1 && v3.cTpe.categoryId == 1) { val v4 = stack.pop stack.push(v2) diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackHandler.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackHandler.scala index 13d057214..662c790e6 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackHandler.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackHandler.scala @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.opal.transformation.stack diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/InlineLocalTransformer.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/InlineLocalTransformer.scala index 554285e65..19e69618c 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/InlineLocalTransformer.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/InlineLocalTransformer.scala @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.opal.transformation.transformer @@ -79,11 +82,8 @@ object InlineLocalTransformer { } }) - statements(i) = - Assignment(pc, targetVar, NewArray(arrPc, newCounts, arrayType)) - countDefSites.foreach(defSite => - statements(defSite._1) = Nop(defSite._2) - ) + statements(i) = Assignment(pc, targetVar, NewArray(arrPc, newCounts, arrayType)) + countDefSites.foreach(defSite => statements(defSite._1) = Nop(defSite._2)) // Replace the index expression with the concrete integer value if available case ArrayLoad(arrPc, arrayIndex: StackLocal, arrayRef) => if (localCache.contains(arrayIndex)) { @@ -137,9 +137,8 @@ object InlineLocalTransformer { case Assignment( pc, targetVar: StackLocal, - c @ (_: SimpleValueConst | _: FunctionCall[TacLocal] | - _: NewArray[TacLocal] | _: ArrayLoad[TacLocal] | _: GetField[TacLocal] | - _: GetStatic) + c @ (_: SimpleValueConst | _: FunctionCall[TacLocal] | _: NewArray[TacLocal] | + _: ArrayLoad[TacLocal] | _: GetField[TacLocal] | _: GetStatic) ) => statements(i + 1) match { case Assignment( diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/LocalPropagationTransformer.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/LocalPropagationTransformer.scala index 1ddbf4024..9685f188d 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/LocalPropagationTransformer.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/LocalPropagationTransformer.scala @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.opal.transformation.transformer @@ -71,8 +74,7 @@ object LocalPropagationTransformer { .inclusive(i + 1, max) .foreach(j => { val currStmt = statements(j) - statements(j) = - updateStatementWithLocal(currStmt, stackLocal, registerLocal) + statements(j) = updateStatementWithLocal(currStmt, stackLocal, registerLocal) }) statements(i) = Nop(pc) @@ -219,9 +221,8 @@ object LocalPropagationTransformer { stackLocal, registerLocal ) - val paramLocals = methodCall.params.map(p => - updateExpressionWithLocal(p, stackLocal, registerLocal) - ) + val paramLocals = + methodCall.params.map(p => updateExpressionWithLocal(p, stackLocal, registerLocal)) return NonVirtualMethodCall( methodCall.pc, @@ -240,9 +241,8 @@ object LocalPropagationTransformer { stackLocal, registerLocal ) - val paramLocals = methodCall.params.map(p => - updateExpressionWithLocal(p, stackLocal, registerLocal) - ) + val paramLocals = + methodCall.params.map(p => updateExpressionWithLocal(p, stackLocal, registerLocal)) return VirtualMethodCall( methodCall.pc, @@ -255,9 +255,7 @@ object LocalPropagationTransformer { ) case StaticMethodCall.ASTID => val methodCall = stmt.asStaticMethodCall - val params = methodCall.params.map(p => - updateExpressionWithLocal(p, stackLocal, registerLocal) - ) + val params = methodCall.params.map(p => updateExpressionWithLocal(p, stackLocal, registerLocal)) return StaticMethodCall( methodCall.pc, @@ -269,9 +267,7 @@ object LocalPropagationTransformer { ) case InvokedynamicMethodCall.ASTID => val methodCall = stmt.asInvokedynamicMethodCall - val params = methodCall.params.map(p => - updateExpressionWithLocal(p, stackLocal, registerLocal) - ) + val params = methodCall.params.map(p => updateExpressionWithLocal(p, stackLocal, registerLocal)) return InvokedynamicMethodCall( methodCall.pc, @@ -396,9 +392,7 @@ object LocalPropagationTransformer { ) case NewArray.ASTID => val newArray = expr.asNewArray - val counts = newArray.counts.map(c => - updateExpressionWithLocal(c, stackLocal, registerLocal) - ) + val counts = newArray.counts.map(c => updateExpressionWithLocal(c, stackLocal, registerLocal)) return NewArray(newArray.pc, counts, newArray.tpe) case ArrayLoad.ASTID => @@ -442,9 +436,7 @@ object LocalPropagationTransformer { ) case InvokedynamicFunctionCall.ASTID => val functionCall = expr.asInvokedynamicFunctionCall - val params = functionCall.params.map(p => - updateExpressionWithLocal(p, stackLocal, registerLocal) - ) + val params = functionCall.params.map(p => updateExpressionWithLocal(p, stackLocal, registerLocal)) return InvokedynamicFunctionCall( functionCall.pc, @@ -461,9 +453,7 @@ object LocalPropagationTransformer { stackLocal, registerLocal ) - val params = functionCall.params.map(p => - updateExpressionWithLocal(p, stackLocal, registerLocal) - ) + val params = functionCall.params.map(p => updateExpressionWithLocal(p, stackLocal, registerLocal)) return NonVirtualFunctionCall( functionCall.pc, @@ -482,9 +472,7 @@ object LocalPropagationTransformer { stackLocal, registerLocal ) - val params = functionCall.params.map(p => - updateExpressionWithLocal(p, stackLocal, registerLocal) - ) + val params = functionCall.params.map(p => updateExpressionWithLocal(p, stackLocal, registerLocal)) return VirtualFunctionCall( functionCall.pc, diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/LocalTransformer.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/LocalTransformer.scala index d38883c68..2dc83d053 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/LocalTransformer.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/LocalTransformer.scala @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.opal.transformation.transformer diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/NopEliminator.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/NopEliminator.scala index a64eef1cd..10f2ab737 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/NopEliminator.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/NopEliminator.scala @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.opal.transformation.transformer diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/NopTransformer.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/NopTransformer.scala index e904e5441..56081f96f 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/NopTransformer.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/NopTransformer.scala @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.opal.transformation.transformer diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/NullifyFieldsTransformer.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/NullifyFieldsTransformer.scala index 1be873aa1..6a7067659 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/NullifyFieldsTransformer.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/NullifyFieldsTransformer.scala @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.opal.transformation.transformer @@ -65,9 +68,8 @@ object NullifyFieldsTransformer { } val definedFields = method.classFile.fields.filter(f => isFieldDefined(f)) - val undefinedFields = method.classFile.fields.filter(f => - !definedFields.contains(f) && f.isNotStatic && f.isNotFinal - ) + val undefinedFields = + method.classFile.fields.filter(f => !definedFields.contains(f) && f.isNotStatic && f.isNotFinal) val firstOriginalStmt = tac.find(stmt => stmt.pc >= 0).get var result = stmtGraph diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalArrayTest.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalArrayTest.scala index b0c0590f6..fb86f4dcd 100644 --- a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalArrayTest.scala +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalArrayTest.scala @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.opal diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalAssignmentTest.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalAssignmentTest.scala index e62ee964f..7d13d6a27 100644 --- a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalAssignmentTest.scala +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalAssignmentTest.scala @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.opal diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalControlFlowGraphTest.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalControlFlowGraphTest.scala index fba8afb07..98160d299 100644 --- a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalControlFlowGraphTest.scala +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalControlFlowGraphTest.scala @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.opal diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalFieldTest.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalFieldTest.scala index 73bd36aa9..bfc711448 100644 --- a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalFieldTest.scala +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalFieldTest.scala @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.opal diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala index 58a4d855b..7d134b236 100644 --- a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.opal diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalLocalTest.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalLocalTest.scala index 92dbff914..bbdf05c10 100644 --- a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalLocalTest.scala +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalLocalTest.scala @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.opal diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalSetup.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalSetup.scala index c4a0b8b87..ab8d49ebd 100644 --- a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalSetup.scala +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalSetup.scala @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.opal diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/TacBodyBuilderTest.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/TacBodyBuilderTest.scala index 71758a1fa..439fca712 100644 --- a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/TacBodyBuilderTest.scala +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/TacBodyBuilderTest.scala @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.opal diff --git a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/BoomerangPretransformer.java b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/BoomerangPretransformer.java index df4b0eb60..5e328d28b 100644 --- a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/BoomerangPretransformer.java +++ b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/BoomerangPretransformer.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.soot; diff --git a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/SootCallGraph.java b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/SootCallGraph.java index af8648c7b..5b1b06192 100644 --- a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/SootCallGraph.java +++ b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/SootCallGraph.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.soot; diff --git a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/SootFrameworkScope.java b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/SootFrameworkScope.java index 03e383543..1e1a67f76 100644 --- a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/SootFrameworkScope.java +++ b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/SootFrameworkScope.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.soot; diff --git a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/ExplicitNullifyFields.java b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/ExplicitNullifyFields.java index bf25e6cc8..6cb8ea955 100644 --- a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/ExplicitNullifyFields.java +++ b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/ExplicitNullifyFields.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.soot.jimple; diff --git a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleControlFlowGraph.java b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleControlFlowGraph.java index e5d2f7a9e..c09d8dcc7 100644 --- a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleControlFlowGraph.java +++ b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleControlFlowGraph.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.soot.jimple; diff --git a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleDeclaredMethod.java b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleDeclaredMethod.java index 205042994..0d49e04ac 100644 --- a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleDeclaredMethod.java +++ b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleDeclaredMethod.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.soot.jimple; diff --git a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleDoubleVal.java b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleDoubleVal.java index c3d95e650..7a8ea9980 100644 --- a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleDoubleVal.java +++ b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleDoubleVal.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.soot.jimple; diff --git a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleField.java b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleField.java index 2517e31b3..9175e4ed0 100644 --- a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleField.java +++ b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleField.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.soot.jimple; diff --git a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleIfStatement.java b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleIfStatement.java index 8076cf913..f70876ba2 100644 --- a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleIfStatement.java +++ b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleIfStatement.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.soot.jimple; diff --git a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleInstanceFieldRef.java b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleInstanceFieldRef.java index 68d070912..5d19876c6 100644 --- a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleInstanceFieldRef.java +++ b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleInstanceFieldRef.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.soot.jimple; diff --git a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleInvokeExpr.java b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleInvokeExpr.java index be3ecf432..2f5cf8fa4 100644 --- a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleInvokeExpr.java +++ b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleInvokeExpr.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.soot.jimple; diff --git a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleMethod.java b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleMethod.java index 51935f687..1b880be37 100644 --- a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleMethod.java +++ b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleMethod.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.soot.jimple; diff --git a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimplePhantomMethod.java b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimplePhantomMethod.java index 7328710dc..908e18527 100644 --- a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimplePhantomMethod.java +++ b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimplePhantomMethod.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.soot.jimple; diff --git a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleStatement.java b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleStatement.java index 673b6a26d..ac096155b 100644 --- a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleStatement.java +++ b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleStatement.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.soot.jimple; diff --git a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleStaticFieldVal.java b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleStaticFieldVal.java index 5aa14675d..8f7f354ee 100644 --- a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleStaticFieldVal.java +++ b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleStaticFieldVal.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.soot.jimple; diff --git a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleType.java b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleType.java index 5e412d6c3..12eb3afd6 100644 --- a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleType.java +++ b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleType.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.soot.jimple; diff --git a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleVal.java b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleVal.java index 5f09ebe4b..be68c8bff 100644 --- a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleVal.java +++ b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleVal.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.soot.jimple; diff --git a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleWrappedClass.java b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleWrappedClass.java index 0ba85e8ec..d18ba173d 100644 --- a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleWrappedClass.java +++ b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/jimple/JimpleWrappedClass.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.soot.jimple; diff --git a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/sparse/SootAdapter.java b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/sparse/SootAdapter.java index a454b8946..9dc1bac13 100644 --- a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/sparse/SootAdapter.java +++ b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/sparse/SootAdapter.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.soot.sparse; diff --git a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/sparse/SparseCFGBuilder.java b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/sparse/SparseCFGBuilder.java index 5a36d022b..9b5109847 100644 --- a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/sparse/SparseCFGBuilder.java +++ b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/sparse/SparseCFGBuilder.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.soot.sparse; diff --git a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/sparse/aliasaware/AliasAwareSparseCFGBuilder.java b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/sparse/aliasaware/AliasAwareSparseCFGBuilder.java index e298d9241..cb758159a 100644 --- a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/sparse/aliasaware/AliasAwareSparseCFGBuilder.java +++ b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/sparse/aliasaware/AliasAwareSparseCFGBuilder.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.soot.sparse.aliasaware; diff --git a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/sparse/aliasaware/AliasAwareSparseCFGCache.java b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/sparse/aliasaware/AliasAwareSparseCFGCache.java index c66115fd5..89b4b777f 100644 --- a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/sparse/aliasaware/AliasAwareSparseCFGCache.java +++ b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/sparse/aliasaware/AliasAwareSparseCFGCache.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.soot.sparse.aliasaware; diff --git a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/sparse/aliasaware/DefinedOutside.java b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/sparse/aliasaware/DefinedOutside.java index 485de4c93..0f1d2536d 100644 --- a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/sparse/aliasaware/DefinedOutside.java +++ b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/sparse/aliasaware/DefinedOutside.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.soot.sparse.aliasaware; diff --git a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/sparse/aliasaware/MStaticFieldRef.java b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/sparse/aliasaware/MStaticFieldRef.java index 409045410..905275600 100644 --- a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/sparse/aliasaware/MStaticFieldRef.java +++ b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/sparse/aliasaware/MStaticFieldRef.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.soot.sparse.aliasaware; diff --git a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/sparse/typebased/TypeBasedSparseCFGBuilder.java b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/sparse/typebased/TypeBasedSparseCFGBuilder.java index 481329334..7df7b4522 100644 --- a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/sparse/typebased/TypeBasedSparseCFGBuilder.java +++ b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/sparse/typebased/TypeBasedSparseCFGBuilder.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.soot.sparse.typebased; diff --git a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/sparse/typebased/TypeBasedSparseCFGCache.java b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/sparse/typebased/TypeBasedSparseCFGCache.java index b2104dc80..618069a44 100644 --- a/boomerangScope-Soot/src/main/java/boomerang/scope/soot/sparse/typebased/TypeBasedSparseCFGCache.java +++ b/boomerangScope-Soot/src/main/java/boomerang/scope/soot/sparse/typebased/TypeBasedSparseCFGCache.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.soot.sparse.typebased; diff --git a/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootArrayTest.java b/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootArrayTest.java index cd813ed04..f1f6304f1 100644 --- a/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootArrayTest.java +++ b/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootArrayTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.soot; diff --git a/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootScopeTest.java b/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootScopeTest.java index cc82ef76c..95727bc40 100644 --- a/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootScopeTest.java +++ b/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootScopeTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.soot; diff --git a/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootSetup.java b/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootSetup.java index eb02f9a3d..d8059c48d 100644 --- a/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootSetup.java +++ b/boomerangScope-Soot/src/test/java/boomerang/scope/soot/SootSetup.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.soot; diff --git a/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/BoomerangPreInterceptor.java b/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/BoomerangPreInterceptor.java index ba0d3a14f..a4f72d9b5 100644 --- a/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/BoomerangPreInterceptor.java +++ b/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/BoomerangPreInterceptor.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.sootup; diff --git a/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/SootUpCallGraph.java b/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/SootUpCallGraph.java index 539226c46..1486bafb3 100644 --- a/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/SootUpCallGraph.java +++ b/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/SootUpCallGraph.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.sootup; diff --git a/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/SootUpFrameworkScope.java b/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/SootUpFrameworkScope.java index d0f7bed4b..78db79a39 100644 --- a/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/SootUpFrameworkScope.java +++ b/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/SootUpFrameworkScope.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.sootup; diff --git a/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpControlFlowGraph.java b/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpControlFlowGraph.java index b009e9760..fbbc93499 100644 --- a/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpControlFlowGraph.java +++ b/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpControlFlowGraph.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.sootup.jimple; diff --git a/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpDeclaredMethod.java b/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpDeclaredMethod.java index 2fbcc54a0..fc06239e4 100644 --- a/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpDeclaredMethod.java +++ b/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpDeclaredMethod.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.sootup.jimple; diff --git a/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpDoubleVal.java b/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpDoubleVal.java index 69aa9c0fd..5200fe09b 100644 --- a/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpDoubleVal.java +++ b/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpDoubleVal.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.sootup.jimple; diff --git a/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpField.java b/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpField.java index 5f2f3ecc6..790c0d544 100644 --- a/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpField.java +++ b/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpField.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.sootup.jimple; diff --git a/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpIfStatement.java b/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpIfStatement.java index 293ee7362..69a169ab0 100644 --- a/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpIfStatement.java +++ b/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpIfStatement.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.sootup.jimple; diff --git a/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpInstanceFieldRef.java b/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpInstanceFieldRef.java index 46ebac12a..a46551d34 100644 --- a/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpInstanceFieldRef.java +++ b/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpInstanceFieldRef.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.sootup.jimple; diff --git a/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpInvokeExpr.java b/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpInvokeExpr.java index 9e10e7078..75a434aef 100644 --- a/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpInvokeExpr.java +++ b/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpInvokeExpr.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.sootup.jimple; diff --git a/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpMethod.java b/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpMethod.java index 98f801f11..275ab3b88 100644 --- a/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpMethod.java +++ b/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpMethod.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.sootup.jimple; diff --git a/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpStatement.java b/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpStatement.java index 2d4fee358..bd58a8ad7 100644 --- a/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpStatement.java +++ b/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpStatement.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.sootup.jimple; diff --git a/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpStaticFieldVal.java b/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpStaticFieldVal.java index 5f5b384bc..857f0000d 100644 --- a/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpStaticFieldVal.java +++ b/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpStaticFieldVal.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.sootup.jimple; diff --git a/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpType.java b/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpType.java index d7590d769..3fc32d12f 100644 --- a/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpType.java +++ b/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpType.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.sootup.jimple; diff --git a/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpVal.java b/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpVal.java index 6431eae2d..3a9eb36da 100644 --- a/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpVal.java +++ b/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpVal.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.sootup.jimple; diff --git a/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpWrappedClass.java b/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpWrappedClass.java index 23277935c..cd2fc7b90 100644 --- a/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpWrappedClass.java +++ b/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/jimple/JimpleUpWrappedClass.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.sootup.jimple; diff --git a/boomerangScope-SootUp/src/main/java/sootup/ScopedAnalysisInputLocation.java b/boomerangScope-SootUp/src/main/java/sootup/ScopedAnalysisInputLocation.java index 75b1f6300..afd6e617b 100644 --- a/boomerangScope-SootUp/src/main/java/sootup/ScopedAnalysisInputLocation.java +++ b/boomerangScope-SootUp/src/main/java/sootup/ScopedAnalysisInputLocation.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package sootup; diff --git a/boomerangScope-SootUp/src/main/java/sootup/SourceTypeSplittingAnalysisInputLocation.java b/boomerangScope-SootUp/src/main/java/sootup/SourceTypeSplittingAnalysisInputLocation.java index 79a3f5f06..4b170290f 100644 --- a/boomerangScope-SootUp/src/main/java/sootup/SourceTypeSplittingAnalysisInputLocation.java +++ b/boomerangScope-SootUp/src/main/java/sootup/SourceTypeSplittingAnalysisInputLocation.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package sootup; diff --git a/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALACallGraph.java b/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALACallGraph.java index 0a5e3568e..180eaee4a 100644 --- a/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALACallGraph.java +++ b/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALACallGraph.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.wala; diff --git a/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALAClass.java b/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALAClass.java index 20f62243f..9f27d6b24 100644 --- a/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALAClass.java +++ b/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALAClass.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.wala; diff --git a/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALAControlFlowGraph.java b/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALAControlFlowGraph.java index e15ca16a3..dc3352a88 100644 --- a/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALAControlFlowGraph.java +++ b/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALAControlFlowGraph.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.wala; diff --git a/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALADataFlowScope.java b/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALADataFlowScope.java index 12d142d00..684feaeae 100644 --- a/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALADataFlowScope.java +++ b/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALADataFlowScope.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.wala; diff --git a/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALADeclaredMethod.java b/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALADeclaredMethod.java index 668a18d75..f30b310e2 100644 --- a/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALADeclaredMethod.java +++ b/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALADeclaredMethod.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.wala; diff --git a/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALADummyNullStatement.java b/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALADummyNullStatement.java index 05fc77df0..c0679df9a 100644 --- a/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALADummyNullStatement.java +++ b/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALADummyNullStatement.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.wala; diff --git a/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALADummyVal.java b/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALADummyVal.java index 620f53042..9cb757e19 100644 --- a/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALADummyVal.java +++ b/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALADummyVal.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.wala; diff --git a/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALAField.java b/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALAField.java index cb25f92ac..60d2d1424 100644 --- a/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALAField.java +++ b/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALAField.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.wala; diff --git a/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALAIfStatement.java b/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALAIfStatement.java index 738e966cd..d89e4a5f5 100644 --- a/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALAIfStatement.java +++ b/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALAIfStatement.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.wala; diff --git a/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALAInvokeExpr.java b/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALAInvokeExpr.java index f02032586..e1101649f 100644 --- a/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALAInvokeExpr.java +++ b/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALAInvokeExpr.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.wala; diff --git a/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALAMethod.java b/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALAMethod.java index dbfd0551c..e01716061 100644 --- a/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALAMethod.java +++ b/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALAMethod.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.wala; diff --git a/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALAStatement.java b/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALAStatement.java index 299f754cf..d35704dab 100644 --- a/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALAStatement.java +++ b/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALAStatement.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.wala; diff --git a/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALAStaticFieldVal.java b/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALAStaticFieldVal.java index e5f66cb79..39b6f9112 100644 --- a/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALAStaticFieldVal.java +++ b/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALAStaticFieldVal.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.wala; diff --git a/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALAType.java b/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALAType.java index 53dbcd231..66ce11a0f 100644 --- a/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALAType.java +++ b/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALAType.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.wala; diff --git a/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALAUnitializedFieldStatement.java b/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALAUnitializedFieldStatement.java index f444b9035..9dd78ed98 100644 --- a/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALAUnitializedFieldStatement.java +++ b/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALAUnitializedFieldStatement.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.wala; diff --git a/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALAVal.java b/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALAVal.java index dd37115f7..86b364ae3 100644 --- a/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALAVal.java +++ b/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WALAVal.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.wala; diff --git a/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WalaFrameworkScope.java b/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WalaFrameworkScope.java index 63e31af76..809fe1760 100644 --- a/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WalaFrameworkScope.java +++ b/boomerangScope-WALA/src/main/java/boomerang/scope/wala/WalaFrameworkScope.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.wala; diff --git a/boomerangScope-WALA/src/test/java/example/BoomerangExampleTarget1.java b/boomerangScope-WALA/src/test/java/example/BoomerangExampleTarget1.java index 72e86807a..6287cde1a 100644 --- a/boomerangScope-WALA/src/test/java/example/BoomerangExampleTarget1.java +++ b/boomerangScope-WALA/src/test/java/example/BoomerangExampleTarget1.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package example; diff --git a/boomerangScope-WALA/src/test/java/example/ExampleMain1.java b/boomerangScope-WALA/src/test/java/example/ExampleMain1.java index fcfa1a3dd..384724ccd 100644 --- a/boomerangScope-WALA/src/test/java/example/ExampleMain1.java +++ b/boomerangScope-WALA/src/test/java/example/ExampleMain1.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package example; diff --git a/boomerangScope/src/main/java/boomerang/scope/AllocVal.java b/boomerangScope/src/main/java/boomerang/scope/AllocVal.java index ac95960f2..9fbe49961 100644 --- a/boomerangScope/src/main/java/boomerang/scope/AllocVal.java +++ b/boomerangScope/src/main/java/boomerang/scope/AllocVal.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope; diff --git a/boomerangScope/src/main/java/boomerang/scope/CallGraph.java b/boomerangScope/src/main/java/boomerang/scope/CallGraph.java index 67a660b0b..7146d5b32 100644 --- a/boomerangScope/src/main/java/boomerang/scope/CallGraph.java +++ b/boomerangScope/src/main/java/boomerang/scope/CallGraph.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope; diff --git a/boomerangScope/src/main/java/boomerang/scope/ControlFlowGraph.java b/boomerangScope/src/main/java/boomerang/scope/ControlFlowGraph.java index 00f4eba4f..d1d76a88c 100644 --- a/boomerangScope/src/main/java/boomerang/scope/ControlFlowGraph.java +++ b/boomerangScope/src/main/java/boomerang/scope/ControlFlowGraph.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope; diff --git a/boomerangScope/src/main/java/boomerang/scope/DataFlowScope.java b/boomerangScope/src/main/java/boomerang/scope/DataFlowScope.java index 40e4cca03..ce503b1f0 100644 --- a/boomerangScope/src/main/java/boomerang/scope/DataFlowScope.java +++ b/boomerangScope/src/main/java/boomerang/scope/DataFlowScope.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope; diff --git a/boomerangScope/src/main/java/boomerang/scope/DeclaredMethod.java b/boomerangScope/src/main/java/boomerang/scope/DeclaredMethod.java index 8308623b5..69080942d 100644 --- a/boomerangScope/src/main/java/boomerang/scope/DeclaredMethod.java +++ b/boomerangScope/src/main/java/boomerang/scope/DeclaredMethod.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope; diff --git a/boomerangScope/src/main/java/boomerang/scope/Field.java b/boomerangScope/src/main/java/boomerang/scope/Field.java index 413171cfb..5fa24eb4c 100644 --- a/boomerangScope/src/main/java/boomerang/scope/Field.java +++ b/boomerangScope/src/main/java/boomerang/scope/Field.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope; diff --git a/boomerangScope/src/main/java/boomerang/scope/FrameworkScope.java b/boomerangScope/src/main/java/boomerang/scope/FrameworkScope.java index d2b0a1122..5129decb3 100644 --- a/boomerangScope/src/main/java/boomerang/scope/FrameworkScope.java +++ b/boomerangScope/src/main/java/boomerang/scope/FrameworkScope.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope; diff --git a/boomerangScope/src/main/java/boomerang/scope/IfStatement.java b/boomerangScope/src/main/java/boomerang/scope/IfStatement.java index 900524cbd..cff993eb3 100644 --- a/boomerangScope/src/main/java/boomerang/scope/IfStatement.java +++ b/boomerangScope/src/main/java/boomerang/scope/IfStatement.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope; diff --git a/boomerangScope/src/main/java/boomerang/scope/InstanceFieldRef.java b/boomerangScope/src/main/java/boomerang/scope/InstanceFieldRef.java index a629d6bf9..7df2cbf9c 100644 --- a/boomerangScope/src/main/java/boomerang/scope/InstanceFieldRef.java +++ b/boomerangScope/src/main/java/boomerang/scope/InstanceFieldRef.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope; diff --git a/boomerangScope/src/main/java/boomerang/scope/InvokeExpr.java b/boomerangScope/src/main/java/boomerang/scope/InvokeExpr.java index 42789ae8a..3da2282e6 100644 --- a/boomerangScope/src/main/java/boomerang/scope/InvokeExpr.java +++ b/boomerangScope/src/main/java/boomerang/scope/InvokeExpr.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope; diff --git a/boomerangScope/src/main/java/boomerang/scope/Method.java b/boomerangScope/src/main/java/boomerang/scope/Method.java index be7d1a124..7bdd920b2 100644 --- a/boomerangScope/src/main/java/boomerang/scope/Method.java +++ b/boomerangScope/src/main/java/boomerang/scope/Method.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope; diff --git a/boomerangScope/src/main/java/boomerang/scope/Pair.java b/boomerangScope/src/main/java/boomerang/scope/Pair.java index 432491648..0a4829a16 100644 --- a/boomerangScope/src/main/java/boomerang/scope/Pair.java +++ b/boomerangScope/src/main/java/boomerang/scope/Pair.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope; diff --git a/boomerangScope/src/main/java/boomerang/scope/Statement.java b/boomerangScope/src/main/java/boomerang/scope/Statement.java index 1baa2723a..24c66056e 100644 --- a/boomerangScope/src/main/java/boomerang/scope/Statement.java +++ b/boomerangScope/src/main/java/boomerang/scope/Statement.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope; diff --git a/boomerangScope/src/main/java/boomerang/scope/StaticFieldVal.java b/boomerangScope/src/main/java/boomerang/scope/StaticFieldVal.java index f5405c58a..9e485ffe5 100644 --- a/boomerangScope/src/main/java/boomerang/scope/StaticFieldVal.java +++ b/boomerangScope/src/main/java/boomerang/scope/StaticFieldVal.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope; diff --git a/boomerangScope/src/main/java/boomerang/scope/Type.java b/boomerangScope/src/main/java/boomerang/scope/Type.java index 9fcfbbe1f..471f7eb42 100644 --- a/boomerangScope/src/main/java/boomerang/scope/Type.java +++ b/boomerangScope/src/main/java/boomerang/scope/Type.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope; diff --git a/boomerangScope/src/main/java/boomerang/scope/Val.java b/boomerangScope/src/main/java/boomerang/scope/Val.java index b63b81ba3..9f5ff2d22 100644 --- a/boomerangScope/src/main/java/boomerang/scope/Val.java +++ b/boomerangScope/src/main/java/boomerang/scope/Val.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope; diff --git a/boomerangScope/src/main/java/boomerang/scope/ValWithFalseVariable.java b/boomerangScope/src/main/java/boomerang/scope/ValWithFalseVariable.java index 22285d216..eff5a3f80 100644 --- a/boomerangScope/src/main/java/boomerang/scope/ValWithFalseVariable.java +++ b/boomerangScope/src/main/java/boomerang/scope/ValWithFalseVariable.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope; diff --git a/boomerangScope/src/main/java/boomerang/scope/WrappedClass.java b/boomerangScope/src/main/java/boomerang/scope/WrappedClass.java index 145297699..7ed130b53 100644 --- a/boomerangScope/src/main/java/boomerang/scope/WrappedClass.java +++ b/boomerangScope/src/main/java/boomerang/scope/WrappedClass.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope; diff --git a/boomerangScope/src/main/java/boomerang/utils/MethodWrapper.java b/boomerangScope/src/main/java/boomerang/utils/MethodWrapper.java index 5f25fd862..2121264a2 100644 --- a/boomerangScope/src/main/java/boomerang/utils/MethodWrapper.java +++ b/boomerangScope/src/main/java/boomerang/utils/MethodWrapper.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.utils; diff --git a/boomerangScope/src/main/java/sparse/SparseAliasingCFG.java b/boomerangScope/src/main/java/sparse/SparseAliasingCFG.java index 18100d8b1..4130675f8 100644 --- a/boomerangScope/src/main/java/sparse/SparseAliasingCFG.java +++ b/boomerangScope/src/main/java/sparse/SparseAliasingCFG.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package sparse; diff --git a/boomerangScope/src/main/java/sparse/SparseCFGCache.java b/boomerangScope/src/main/java/sparse/SparseCFGCache.java index 78c114d34..5fcfbf229 100644 --- a/boomerangScope/src/main/java/sparse/SparseCFGCache.java +++ b/boomerangScope/src/main/java/sparse/SparseCFGCache.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package sparse; diff --git a/boomerangScope/src/main/java/sparse/SparsificationStrategy.java b/boomerangScope/src/main/java/sparse/SparsificationStrategy.java index 05d5ac75e..69bde1831 100644 --- a/boomerangScope/src/main/java/sparse/SparsificationStrategy.java +++ b/boomerangScope/src/main/java/sparse/SparsificationStrategy.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package sparse; diff --git a/boomerangScope/src/main/java/sparse/eval/EvalPrinter.java b/boomerangScope/src/main/java/sparse/eval/EvalPrinter.java index 49b7c6f09..678c0b20d 100644 --- a/boomerangScope/src/main/java/sparse/eval/EvalPrinter.java +++ b/boomerangScope/src/main/java/sparse/eval/EvalPrinter.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package sparse.eval; diff --git a/boomerangScope/src/main/java/sparse/eval/PropagationCounter.java b/boomerangScope/src/main/java/sparse/eval/PropagationCounter.java index 4fbfd830c..6e841363a 100644 --- a/boomerangScope/src/main/java/sparse/eval/PropagationCounter.java +++ b/boomerangScope/src/main/java/sparse/eval/PropagationCounter.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package sparse.eval; diff --git a/boomerangScope/src/main/java/sparse/eval/SparseCFGQueryLog.java b/boomerangScope/src/main/java/sparse/eval/SparseCFGQueryLog.java index e8f7bf8da..e968222cc 100644 --- a/boomerangScope/src/main/java/sparse/eval/SparseCFGQueryLog.java +++ b/boomerangScope/src/main/java/sparse/eval/SparseCFGQueryLog.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package sparse.eval; diff --git a/boomerangScope/src/test/java/boomerang/scope/test/BoomerangScopeTests.java b/boomerangScope/src/test/java/boomerang/scope/test/BoomerangScopeTests.java index ff3492ca6..4edac6439 100644 --- a/boomerangScope/src/test/java/boomerang/scope/test/BoomerangScopeTests.java +++ b/boomerangScope/src/test/java/boomerang/scope/test/BoomerangScopeTests.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.test; diff --git a/boomerangScope/src/test/java/boomerang/scope/test/MethodSignature.java b/boomerangScope/src/test/java/boomerang/scope/test/MethodSignature.java index f154e974a..48d0a5d49 100644 --- a/boomerangScope/src/test/java/boomerang/scope/test/MethodSignature.java +++ b/boomerangScope/src/test/java/boomerang/scope/test/MethodSignature.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.test; diff --git a/boomerangScope/src/test/java/boomerang/scope/test/TargetClassPath.java b/boomerangScope/src/test/java/boomerang/scope/test/TargetClassPath.java index 34fcaa487..4d468c849 100644 --- a/boomerangScope/src/test/java/boomerang/scope/test/TargetClassPath.java +++ b/boomerangScope/src/test/java/boomerang/scope/test/TargetClassPath.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.test; diff --git a/boomerangScope/src/test/java/boomerang/scope/test/targets/A.java b/boomerangScope/src/test/java/boomerang/scope/test/targets/A.java index fac46905a..1df313cc1 100644 --- a/boomerangScope/src/test/java/boomerang/scope/test/targets/A.java +++ b/boomerangScope/src/test/java/boomerang/scope/test/targets/A.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.test.targets; diff --git a/boomerangScope/src/test/java/boomerang/scope/test/targets/ArrayTarget.java b/boomerangScope/src/test/java/boomerang/scope/test/targets/ArrayTarget.java index 94660c089..94fffd531 100644 --- a/boomerangScope/src/test/java/boomerang/scope/test/targets/ArrayTarget.java +++ b/boomerangScope/src/test/java/boomerang/scope/test/targets/ArrayTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.test.targets; diff --git a/boomerangScope/src/test/java/boomerang/scope/test/targets/AssignmentTarget.java b/boomerangScope/src/test/java/boomerang/scope/test/targets/AssignmentTarget.java index 2140a54d0..8aaa04bfb 100644 --- a/boomerangScope/src/test/java/boomerang/scope/test/targets/AssignmentTarget.java +++ b/boomerangScope/src/test/java/boomerang/scope/test/targets/AssignmentTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.test.targets; diff --git a/boomerangScope/src/test/java/boomerang/scope/test/targets/BranchingTarget.java b/boomerangScope/src/test/java/boomerang/scope/test/targets/BranchingTarget.java index 7f7f52536..08181c43a 100644 --- a/boomerangScope/src/test/java/boomerang/scope/test/targets/BranchingTarget.java +++ b/boomerangScope/src/test/java/boomerang/scope/test/targets/BranchingTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.test.targets; diff --git a/boomerangScope/src/test/java/boomerang/scope/test/targets/ConstructorTarget.java b/boomerangScope/src/test/java/boomerang/scope/test/targets/ConstructorTarget.java index 0b7e9ffc1..01aab6f45 100644 --- a/boomerangScope/src/test/java/boomerang/scope/test/targets/ConstructorTarget.java +++ b/boomerangScope/src/test/java/boomerang/scope/test/targets/ConstructorTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.test.targets; diff --git a/boomerangScope/src/test/java/boomerang/scope/test/targets/ControlFlowGraphTarget.java b/boomerangScope/src/test/java/boomerang/scope/test/targets/ControlFlowGraphTarget.java index ee89368c9..5e402bedd 100644 --- a/boomerangScope/src/test/java/boomerang/scope/test/targets/ControlFlowGraphTarget.java +++ b/boomerangScope/src/test/java/boomerang/scope/test/targets/ControlFlowGraphTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.test.targets; diff --git a/boomerangScope/src/test/java/boomerang/scope/test/targets/FieldClass.java b/boomerangScope/src/test/java/boomerang/scope/test/targets/FieldClass.java index 480e1e88c..57e6a1725 100644 --- a/boomerangScope/src/test/java/boomerang/scope/test/targets/FieldClass.java +++ b/boomerangScope/src/test/java/boomerang/scope/test/targets/FieldClass.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.test.targets; diff --git a/boomerangScope/src/test/java/boomerang/scope/test/targets/FieldTarget.java b/boomerangScope/src/test/java/boomerang/scope/test/targets/FieldTarget.java index c4620da13..5e49c5a70 100644 --- a/boomerangScope/src/test/java/boomerang/scope/test/targets/FieldTarget.java +++ b/boomerangScope/src/test/java/boomerang/scope/test/targets/FieldTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.test.targets; diff --git a/boomerangScope/src/test/java/boomerang/scope/test/targets/HashCodeEqualsLocalTarget.java b/boomerangScope/src/test/java/boomerang/scope/test/targets/HashCodeEqualsLocalTarget.java index f912d2ff5..8a1a2d61f 100644 --- a/boomerangScope/src/test/java/boomerang/scope/test/targets/HashCodeEqualsLocalTarget.java +++ b/boomerangScope/src/test/java/boomerang/scope/test/targets/HashCodeEqualsLocalTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.test.targets; diff --git a/boomerangScope/src/test/java/boomerang/scope/test/targets/InvokeExprTarget.java b/boomerangScope/src/test/java/boomerang/scope/test/targets/InvokeExprTarget.java index 03d20af31..a11022537 100644 --- a/boomerangScope/src/test/java/boomerang/scope/test/targets/InvokeExprTarget.java +++ b/boomerangScope/src/test/java/boomerang/scope/test/targets/InvokeExprTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.test.targets; diff --git a/boomerangScope/src/test/java/boomerang/scope/test/targets/LocalCountTarget.java b/boomerangScope/src/test/java/boomerang/scope/test/targets/LocalCountTarget.java index 46d0082c7..674c678cb 100644 --- a/boomerangScope/src/test/java/boomerang/scope/test/targets/LocalCountTarget.java +++ b/boomerangScope/src/test/java/boomerang/scope/test/targets/LocalCountTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.test.targets; diff --git a/boomerangScope/src/test/java/boomerang/scope/test/targets/ParameterLocalsTarget.java b/boomerangScope/src/test/java/boomerang/scope/test/targets/ParameterLocalsTarget.java index acb808398..8c5223de4 100644 --- a/boomerangScope/src/test/java/boomerang/scope/test/targets/ParameterLocalsTarget.java +++ b/boomerangScope/src/test/java/boomerang/scope/test/targets/ParameterLocalsTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.test.targets; diff --git a/boomerangScope/src/test/java/boomerang/scope/test/targets/SingleTarget.java b/boomerangScope/src/test/java/boomerang/scope/test/targets/SingleTarget.java index 1885d0ab0..b536dedf0 100644 --- a/boomerangScope/src/test/java/boomerang/scope/test/targets/SingleTarget.java +++ b/boomerangScope/src/test/java/boomerang/scope/test/targets/SingleTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.test.targets; diff --git a/boomerangScope/src/test/java/boomerang/scope/test/targets/ThisLocalTarget.java b/boomerangScope/src/test/java/boomerang/scope/test/targets/ThisLocalTarget.java index b81ccfe9f..e58ae7d91 100644 --- a/boomerangScope/src/test/java/boomerang/scope/test/targets/ThisLocalTarget.java +++ b/boomerangScope/src/test/java/boomerang/scope/test/targets/ThisLocalTarget.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scope.test.targets; diff --git a/idealPDS/src/main/java/ideal/IDEALAnalysis.java b/idealPDS/src/main/java/ideal/IDEALAnalysis.java index 425171be3..f1b447134 100644 --- a/idealPDS/src/main/java/ideal/IDEALAnalysis.java +++ b/idealPDS/src/main/java/ideal/IDEALAnalysis.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package ideal; diff --git a/idealPDS/src/main/java/ideal/IDEALAnalysisDefinition.java b/idealPDS/src/main/java/ideal/IDEALAnalysisDefinition.java index 62b8a929b..767c710b9 100644 --- a/idealPDS/src/main/java/ideal/IDEALAnalysisDefinition.java +++ b/idealPDS/src/main/java/ideal/IDEALAnalysisDefinition.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package ideal; diff --git a/idealPDS/src/main/java/ideal/IDEALResultHandler.java b/idealPDS/src/main/java/ideal/IDEALResultHandler.java index 81aaccf18..a58b7850d 100644 --- a/idealPDS/src/main/java/ideal/IDEALResultHandler.java +++ b/idealPDS/src/main/java/ideal/IDEALResultHandler.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package ideal; diff --git a/idealPDS/src/main/java/ideal/IDEALSeedSolver.java b/idealPDS/src/main/java/ideal/IDEALSeedSolver.java index 35dedd3df..1200d1310 100644 --- a/idealPDS/src/main/java/ideal/IDEALSeedSolver.java +++ b/idealPDS/src/main/java/ideal/IDEALSeedSolver.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package ideal; diff --git a/idealPDS/src/main/java/ideal/IDEALSeedTimeout.java b/idealPDS/src/main/java/ideal/IDEALSeedTimeout.java index 1bc08763b..f67c22087 100644 --- a/idealPDS/src/main/java/ideal/IDEALSeedTimeout.java +++ b/idealPDS/src/main/java/ideal/IDEALSeedTimeout.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package ideal; diff --git a/idealPDS/src/main/java/ideal/IDEALWeightFunctions.java b/idealPDS/src/main/java/ideal/IDEALWeightFunctions.java index 9d974acd8..8c199963d 100644 --- a/idealPDS/src/main/java/ideal/IDEALWeightFunctions.java +++ b/idealPDS/src/main/java/ideal/IDEALWeightFunctions.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package ideal; diff --git a/idealPDS/src/main/java/ideal/NonOneFlowListener.java b/idealPDS/src/main/java/ideal/NonOneFlowListener.java index 81ac08171..23d93d462 100644 --- a/idealPDS/src/main/java/ideal/NonOneFlowListener.java +++ b/idealPDS/src/main/java/ideal/NonOneFlowListener.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package ideal; diff --git a/idealPDS/src/main/java/ideal/StoreIDEALResultHandler.java b/idealPDS/src/main/java/ideal/StoreIDEALResultHandler.java index 439fe66d5..2432022d1 100644 --- a/idealPDS/src/main/java/ideal/StoreIDEALResultHandler.java +++ b/idealPDS/src/main/java/ideal/StoreIDEALResultHandler.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package ideal; diff --git a/idealPDS/src/main/java/inference/InferenceWeight.java b/idealPDS/src/main/java/inference/InferenceWeight.java index 73d398cb4..621c0f531 100644 --- a/idealPDS/src/main/java/inference/InferenceWeight.java +++ b/idealPDS/src/main/java/inference/InferenceWeight.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package inference; diff --git a/idealPDS/src/main/java/inference/InferenceWeightFunctions.java b/idealPDS/src/main/java/inference/InferenceWeightFunctions.java index 738804e76..d6b8d339f 100644 --- a/idealPDS/src/main/java/inference/InferenceWeightFunctions.java +++ b/idealPDS/src/main/java/inference/InferenceWeightFunctions.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package inference; diff --git a/idealPDS/src/main/java/inference/InferenceWeightImpl.java b/idealPDS/src/main/java/inference/InferenceWeightImpl.java index c9f31750f..65871f6de 100644 --- a/idealPDS/src/main/java/inference/InferenceWeightImpl.java +++ b/idealPDS/src/main/java/inference/InferenceWeightImpl.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package inference; diff --git a/idealPDS/src/main/java/inference/InferenceWeightOne.java b/idealPDS/src/main/java/inference/InferenceWeightOne.java index 448be4a2e..4fc34297e 100644 --- a/idealPDS/src/main/java/inference/InferenceWeightOne.java +++ b/idealPDS/src/main/java/inference/InferenceWeightOne.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package inference; diff --git a/idealPDS/src/main/java/inference/InferenceWeightZero.java b/idealPDS/src/main/java/inference/InferenceWeightZero.java index 7463665f0..5c74b3441 100644 --- a/idealPDS/src/main/java/inference/InferenceWeightZero.java +++ b/idealPDS/src/main/java/inference/InferenceWeightZero.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package inference; diff --git a/idealPDS/src/main/java/typestate/TransitionFunction.java b/idealPDS/src/main/java/typestate/TransitionFunction.java index c6e8677af..7aeb4e91e 100644 --- a/idealPDS/src/main/java/typestate/TransitionFunction.java +++ b/idealPDS/src/main/java/typestate/TransitionFunction.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package typestate; diff --git a/idealPDS/src/main/java/typestate/TransitionFunctionImpl.java b/idealPDS/src/main/java/typestate/TransitionFunctionImpl.java index cfad49afd..6f984796d 100644 --- a/idealPDS/src/main/java/typestate/TransitionFunctionImpl.java +++ b/idealPDS/src/main/java/typestate/TransitionFunctionImpl.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package typestate; diff --git a/idealPDS/src/main/java/typestate/TransitionFunctionOne.java b/idealPDS/src/main/java/typestate/TransitionFunctionOne.java index e5234a491..4ca7befa6 100644 --- a/idealPDS/src/main/java/typestate/TransitionFunctionOne.java +++ b/idealPDS/src/main/java/typestate/TransitionFunctionOne.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package typestate; diff --git a/idealPDS/src/main/java/typestate/TransitionFunctionZero.java b/idealPDS/src/main/java/typestate/TransitionFunctionZero.java index 16752c258..fb7793d89 100644 --- a/idealPDS/src/main/java/typestate/TransitionFunctionZero.java +++ b/idealPDS/src/main/java/typestate/TransitionFunctionZero.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package typestate; diff --git a/idealPDS/src/main/java/typestate/finiteautomata/MatcherTransition.java b/idealPDS/src/main/java/typestate/finiteautomata/MatcherTransition.java index 186b1eecc..88d2c3307 100644 --- a/idealPDS/src/main/java/typestate/finiteautomata/MatcherTransition.java +++ b/idealPDS/src/main/java/typestate/finiteautomata/MatcherTransition.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package typestate.finiteautomata; diff --git a/idealPDS/src/main/java/typestate/finiteautomata/State.java b/idealPDS/src/main/java/typestate/finiteautomata/State.java index dc19d083d..1978ff091 100644 --- a/idealPDS/src/main/java/typestate/finiteautomata/State.java +++ b/idealPDS/src/main/java/typestate/finiteautomata/State.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package typestate.finiteautomata; diff --git a/idealPDS/src/main/java/typestate/finiteautomata/Transition.java b/idealPDS/src/main/java/typestate/finiteautomata/Transition.java index ef8817036..ac41509cf 100644 --- a/idealPDS/src/main/java/typestate/finiteautomata/Transition.java +++ b/idealPDS/src/main/java/typestate/finiteautomata/Transition.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package typestate.finiteautomata; diff --git a/idealPDS/src/main/java/typestate/finiteautomata/TransitionIdentity.java b/idealPDS/src/main/java/typestate/finiteautomata/TransitionIdentity.java index 49171ce86..08cae9e4b 100644 --- a/idealPDS/src/main/java/typestate/finiteautomata/TransitionIdentity.java +++ b/idealPDS/src/main/java/typestate/finiteautomata/TransitionIdentity.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package typestate.finiteautomata; diff --git a/idealPDS/src/main/java/typestate/finiteautomata/TransitionImpl.java b/idealPDS/src/main/java/typestate/finiteautomata/TransitionImpl.java index becaebb3b..246cd48cf 100644 --- a/idealPDS/src/main/java/typestate/finiteautomata/TransitionImpl.java +++ b/idealPDS/src/main/java/typestate/finiteautomata/TransitionImpl.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package typestate.finiteautomata; diff --git a/idealPDS/src/main/java/typestate/finiteautomata/TypeStateMachineWeightFunctions.java b/idealPDS/src/main/java/typestate/finiteautomata/TypeStateMachineWeightFunctions.java index ac3821929..413684cf4 100644 --- a/idealPDS/src/main/java/typestate/finiteautomata/TypeStateMachineWeightFunctions.java +++ b/idealPDS/src/main/java/typestate/finiteautomata/TypeStateMachineWeightFunctions.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package typestate.finiteautomata; diff --git a/idealPDS/src/main/java/typestate/impl/statemachines/FileMustBeClosedStateMachine.java b/idealPDS/src/main/java/typestate/impl/statemachines/FileMustBeClosedStateMachine.java index dfb87d2bb..3c99e8be3 100644 --- a/idealPDS/src/main/java/typestate/impl/statemachines/FileMustBeClosedStateMachine.java +++ b/idealPDS/src/main/java/typestate/impl/statemachines/FileMustBeClosedStateMachine.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package typestate.impl.statemachines; diff --git a/idealPDS/src/main/java/typestate/impl/statemachines/FileMustBeClosedStateMachineCallToReturn.java b/idealPDS/src/main/java/typestate/impl/statemachines/FileMustBeClosedStateMachineCallToReturn.java index 612b9a66f..3664a7f94 100644 --- a/idealPDS/src/main/java/typestate/impl/statemachines/FileMustBeClosedStateMachineCallToReturn.java +++ b/idealPDS/src/main/java/typestate/impl/statemachines/FileMustBeClosedStateMachineCallToReturn.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package typestate.impl.statemachines; diff --git a/idealPDS/src/main/java/typestate/impl/statemachines/HasNextStateMachine.java b/idealPDS/src/main/java/typestate/impl/statemachines/HasNextStateMachine.java index e7ef4f87b..ea8c02c0f 100644 --- a/idealPDS/src/main/java/typestate/impl/statemachines/HasNextStateMachine.java +++ b/idealPDS/src/main/java/typestate/impl/statemachines/HasNextStateMachine.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package typestate.impl.statemachines; diff --git a/idealPDS/src/main/java/typestate/impl/statemachines/InputStreamStateMachine.java b/idealPDS/src/main/java/typestate/impl/statemachines/InputStreamStateMachine.java index 8fb110b33..2731d70bb 100644 --- a/idealPDS/src/main/java/typestate/impl/statemachines/InputStreamStateMachine.java +++ b/idealPDS/src/main/java/typestate/impl/statemachines/InputStreamStateMachine.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package typestate.impl.statemachines; diff --git a/idealPDS/src/main/java/typestate/impl/statemachines/KeyStoreStateMachine.java b/idealPDS/src/main/java/typestate/impl/statemachines/KeyStoreStateMachine.java index 013930868..9807f21df 100644 --- a/idealPDS/src/main/java/typestate/impl/statemachines/KeyStoreStateMachine.java +++ b/idealPDS/src/main/java/typestate/impl/statemachines/KeyStoreStateMachine.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package typestate.impl.statemachines; diff --git a/idealPDS/src/main/java/typestate/impl/statemachines/OutputStreamStateMachine.java b/idealPDS/src/main/java/typestate/impl/statemachines/OutputStreamStateMachine.java index 07e9e2760..a97b9506d 100644 --- a/idealPDS/src/main/java/typestate/impl/statemachines/OutputStreamStateMachine.java +++ b/idealPDS/src/main/java/typestate/impl/statemachines/OutputStreamStateMachine.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package typestate.impl.statemachines; diff --git a/idealPDS/src/main/java/typestate/impl/statemachines/PipedInputStreamStateMachine.java b/idealPDS/src/main/java/typestate/impl/statemachines/PipedInputStreamStateMachine.java index f6ecb7c26..569acb103 100644 --- a/idealPDS/src/main/java/typestate/impl/statemachines/PipedInputStreamStateMachine.java +++ b/idealPDS/src/main/java/typestate/impl/statemachines/PipedInputStreamStateMachine.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package typestate.impl.statemachines; diff --git a/idealPDS/src/main/java/typestate/impl/statemachines/PipedOutputStreamStateMachine.java b/idealPDS/src/main/java/typestate/impl/statemachines/PipedOutputStreamStateMachine.java index 5e45dce03..a3d28989d 100644 --- a/idealPDS/src/main/java/typestate/impl/statemachines/PipedOutputStreamStateMachine.java +++ b/idealPDS/src/main/java/typestate/impl/statemachines/PipedOutputStreamStateMachine.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package typestate.impl.statemachines; diff --git a/idealPDS/src/main/java/typestate/impl/statemachines/PrintStreamStateMachine.java b/idealPDS/src/main/java/typestate/impl/statemachines/PrintStreamStateMachine.java index deca3df50..b0f770c0f 100644 --- a/idealPDS/src/main/java/typestate/impl/statemachines/PrintStreamStateMachine.java +++ b/idealPDS/src/main/java/typestate/impl/statemachines/PrintStreamStateMachine.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package typestate.impl.statemachines; diff --git a/idealPDS/src/main/java/typestate/impl/statemachines/PrintWriterStateMachine.java b/idealPDS/src/main/java/typestate/impl/statemachines/PrintWriterStateMachine.java index 40559f482..689e002bf 100644 --- a/idealPDS/src/main/java/typestate/impl/statemachines/PrintWriterStateMachine.java +++ b/idealPDS/src/main/java/typestate/impl/statemachines/PrintWriterStateMachine.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package typestate.impl.statemachines; diff --git a/idealPDS/src/main/java/typestate/impl/statemachines/SignatureStateMachine.java b/idealPDS/src/main/java/typestate/impl/statemachines/SignatureStateMachine.java index 7fa3e52d9..3f577c7bf 100644 --- a/idealPDS/src/main/java/typestate/impl/statemachines/SignatureStateMachine.java +++ b/idealPDS/src/main/java/typestate/impl/statemachines/SignatureStateMachine.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package typestate.impl.statemachines; diff --git a/idealPDS/src/main/java/typestate/impl/statemachines/SocketStateMachine.java b/idealPDS/src/main/java/typestate/impl/statemachines/SocketStateMachine.java index cd7adc716..99b409276 100644 --- a/idealPDS/src/main/java/typestate/impl/statemachines/SocketStateMachine.java +++ b/idealPDS/src/main/java/typestate/impl/statemachines/SocketStateMachine.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package typestate.impl.statemachines; diff --git a/idealPDS/src/main/java/typestate/impl/statemachines/URLConnStateMachine.java b/idealPDS/src/main/java/typestate/impl/statemachines/URLConnStateMachine.java index 9cf12d460..e45d79f41 100644 --- a/idealPDS/src/main/java/typestate/impl/statemachines/URLConnStateMachine.java +++ b/idealPDS/src/main/java/typestate/impl/statemachines/URLConnStateMachine.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package typestate.impl.statemachines; diff --git a/idealPDS/src/main/java/typestate/impl/statemachines/VectorStateMachine.java b/idealPDS/src/main/java/typestate/impl/statemachines/VectorStateMachine.java index 07c65615d..6f0708b4a 100644 --- a/idealPDS/src/main/java/typestate/impl/statemachines/VectorStateMachine.java +++ b/idealPDS/src/main/java/typestate/impl/statemachines/VectorStateMachine.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package typestate.impl.statemachines; diff --git a/idealPDS/src/test/java/assertions/Assertions.java b/idealPDS/src/test/java/assertions/Assertions.java index abd827256..f04ad23ad 100644 --- a/idealPDS/src/test/java/assertions/Assertions.java +++ b/idealPDS/src/test/java/assertions/Assertions.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package assertions; diff --git a/idealPDS/src/test/java/assertions/MayBeInAcceptingState.java b/idealPDS/src/test/java/assertions/MayBeInAcceptingState.java index 6e58820e1..2a503a40d 100644 --- a/idealPDS/src/test/java/assertions/MayBeInAcceptingState.java +++ b/idealPDS/src/test/java/assertions/MayBeInAcceptingState.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package assertions; diff --git a/idealPDS/src/test/java/assertions/MayBeInErrorState.java b/idealPDS/src/test/java/assertions/MayBeInErrorState.java index 3962aad24..8963d92fe 100644 --- a/idealPDS/src/test/java/assertions/MayBeInErrorState.java +++ b/idealPDS/src/test/java/assertions/MayBeInErrorState.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package assertions; diff --git a/idealPDS/src/test/java/assertions/MustBeInAcceptingState.java b/idealPDS/src/test/java/assertions/MustBeInAcceptingState.java index 1d02914c7..2705a81b8 100644 --- a/idealPDS/src/test/java/assertions/MustBeInAcceptingState.java +++ b/idealPDS/src/test/java/assertions/MustBeInAcceptingState.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package assertions; diff --git a/idealPDS/src/test/java/assertions/MustBeInErrorState.java b/idealPDS/src/test/java/assertions/MustBeInErrorState.java index 2f062265a..c63725229 100644 --- a/idealPDS/src/test/java/assertions/MustBeInErrorState.java +++ b/idealPDS/src/test/java/assertions/MustBeInErrorState.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package assertions; diff --git a/idealPDS/src/test/java/assertions/ShouldNotBeAnalyzed.java b/idealPDS/src/test/java/assertions/ShouldNotBeAnalyzed.java index 8b4b5f9c6..5a43b509a 100644 --- a/idealPDS/src/test/java/assertions/ShouldNotBeAnalyzed.java +++ b/idealPDS/src/test/java/assertions/ShouldNotBeAnalyzed.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package assertions; diff --git a/idealPDS/src/test/java/assertions/StateResult.java b/idealPDS/src/test/java/assertions/StateResult.java index 31f4442a9..87e83794b 100644 --- a/idealPDS/src/test/java/assertions/StateResult.java +++ b/idealPDS/src/test/java/assertions/StateResult.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package assertions; diff --git a/idealPDS/src/test/java/example/InferenceExample.java b/idealPDS/src/test/java/example/InferenceExample.java index 0bb22a02b..a204dda23 100644 --- a/idealPDS/src/test/java/example/InferenceExample.java +++ b/idealPDS/src/test/java/example/InferenceExample.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package example; diff --git a/idealPDS/src/test/java/example/Main.java b/idealPDS/src/test/java/example/Main.java index 21697fd54..ea71c37cf 100644 --- a/idealPDS/src/test/java/example/Main.java +++ b/idealPDS/src/test/java/example/Main.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package example; diff --git a/idealPDS/src/test/java/test/IDEALTestingFramework.java b/idealPDS/src/test/java/test/IDEALTestingFramework.java index 9c22f5dc3..8569efa84 100644 --- a/idealPDS/src/test/java/test/IDEALTestingFramework.java +++ b/idealPDS/src/test/java/test/IDEALTestingFramework.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test; diff --git a/idealPDS/src/test/java/test/TestingResultReporter.java b/idealPDS/src/test/java/test/TestingResultReporter.java index 8112e01d9..16593789a 100644 --- a/idealPDS/src/test/java/test/TestingResultReporter.java +++ b/idealPDS/src/test/java/test/TestingResultReporter.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test; diff --git a/idealPDS/src/test/java/typestate/targets/AssertionsTesting.java b/idealPDS/src/test/java/typestate/targets/AssertionsTesting.java index 86ec756f6..5f8ef8421 100644 --- a/idealPDS/src/test/java/typestate/targets/AssertionsTesting.java +++ b/idealPDS/src/test/java/typestate/targets/AssertionsTesting.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package typestate.targets; diff --git a/idealPDS/src/test/java/typestate/targets/FileMustBeClosed.java b/idealPDS/src/test/java/typestate/targets/FileMustBeClosed.java index afb989789..8b31e8c77 100644 --- a/idealPDS/src/test/java/typestate/targets/FileMustBeClosed.java +++ b/idealPDS/src/test/java/typestate/targets/FileMustBeClosed.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package typestate.targets; diff --git a/idealPDS/src/test/java/typestate/targets/FileMustBeClosedDemandDriven.java b/idealPDS/src/test/java/typestate/targets/FileMustBeClosedDemandDriven.java index 3ab00ed2a..58211bf31 100644 --- a/idealPDS/src/test/java/typestate/targets/FileMustBeClosedDemandDriven.java +++ b/idealPDS/src/test/java/typestate/targets/FileMustBeClosedDemandDriven.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package typestate.targets; diff --git a/idealPDS/src/test/java/typestate/targets/FileMustBeClosedInterface.java b/idealPDS/src/test/java/typestate/targets/FileMustBeClosedInterface.java index 399d20278..0dff21eeb 100644 --- a/idealPDS/src/test/java/typestate/targets/FileMustBeClosedInterface.java +++ b/idealPDS/src/test/java/typestate/targets/FileMustBeClosedInterface.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package typestate.targets; diff --git a/idealPDS/src/test/java/typestate/targets/FileMustBeClosedStrongUpdate.java b/idealPDS/src/test/java/typestate/targets/FileMustBeClosedStrongUpdate.java index a1636b588..a094c2852 100644 --- a/idealPDS/src/test/java/typestate/targets/FileMustBeClosedStrongUpdate.java +++ b/idealPDS/src/test/java/typestate/targets/FileMustBeClosedStrongUpdate.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package typestate.targets; diff --git a/idealPDS/src/test/java/typestate/targets/FluentInterface.java b/idealPDS/src/test/java/typestate/targets/FluentInterface.java index 15a341593..0a375bee7 100644 --- a/idealPDS/src/test/java/typestate/targets/FluentInterface.java +++ b/idealPDS/src/test/java/typestate/targets/FluentInterface.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package typestate.targets; diff --git a/idealPDS/src/test/java/typestate/targets/InputStreamLong.java b/idealPDS/src/test/java/typestate/targets/InputStreamLong.java index 647b5ee06..3b282ffec 100644 --- a/idealPDS/src/test/java/typestate/targets/InputStreamLong.java +++ b/idealPDS/src/test/java/typestate/targets/InputStreamLong.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package typestate.targets; diff --git a/idealPDS/src/test/java/typestate/targets/IteratorHasNext.java b/idealPDS/src/test/java/typestate/targets/IteratorHasNext.java index 1b7e811fa..b88dd3509 100644 --- a/idealPDS/src/test/java/typestate/targets/IteratorHasNext.java +++ b/idealPDS/src/test/java/typestate/targets/IteratorHasNext.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package typestate.targets; diff --git a/idealPDS/src/test/java/typestate/targets/KeyStoreLong.java b/idealPDS/src/test/java/typestate/targets/KeyStoreLong.java index ebdf3ca5e..600c4116e 100644 --- a/idealPDS/src/test/java/typestate/targets/KeyStoreLong.java +++ b/idealPDS/src/test/java/typestate/targets/KeyStoreLong.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package typestate.targets; diff --git a/idealPDS/src/test/java/typestate/targets/PrintStreamLong.java b/idealPDS/src/test/java/typestate/targets/PrintStreamLong.java index f19f06fbe..f014684f0 100644 --- a/idealPDS/src/test/java/typestate/targets/PrintStreamLong.java +++ b/idealPDS/src/test/java/typestate/targets/PrintStreamLong.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package typestate.targets; diff --git a/idealPDS/src/test/java/typestate/targets/PrintWriterLong.java b/idealPDS/src/test/java/typestate/targets/PrintWriterLong.java index 8bac27e7c..85c70a8d3 100644 --- a/idealPDS/src/test/java/typestate/targets/PrintWriterLong.java +++ b/idealPDS/src/test/java/typestate/targets/PrintWriterLong.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package typestate.targets; diff --git a/idealPDS/src/test/java/typestate/targets/SocketLong.java b/idealPDS/src/test/java/typestate/targets/SocketLong.java index acc52aa6a..d0378d250 100644 --- a/idealPDS/src/test/java/typestate/targets/SocketLong.java +++ b/idealPDS/src/test/java/typestate/targets/SocketLong.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package typestate.targets; diff --git a/idealPDS/src/test/java/typestate/targets/SootSceneSetup.java b/idealPDS/src/test/java/typestate/targets/SootSceneSetup.java index 7cbb04918..617716d6c 100644 --- a/idealPDS/src/test/java/typestate/targets/SootSceneSetup.java +++ b/idealPDS/src/test/java/typestate/targets/SootSceneSetup.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package typestate.targets; diff --git a/idealPDS/src/test/java/typestate/targets/StackLong.java b/idealPDS/src/test/java/typestate/targets/StackLong.java index 7a6622cbd..03ce11cf3 100644 --- a/idealPDS/src/test/java/typestate/targets/StackLong.java +++ b/idealPDS/src/test/java/typestate/targets/StackLong.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package typestate.targets; diff --git a/idealPDS/src/test/java/typestate/targets/URLConn.java b/idealPDS/src/test/java/typestate/targets/URLConn.java index 96d305474..f735d0a4a 100644 --- a/idealPDS/src/test/java/typestate/targets/URLConn.java +++ b/idealPDS/src/test/java/typestate/targets/URLConn.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package typestate.targets; diff --git a/idealPDS/src/test/java/typestate/targets/VectorLong.java b/idealPDS/src/test/java/typestate/targets/VectorLong.java index 669c5affb..2066e55ee 100644 --- a/idealPDS/src/test/java/typestate/targets/VectorLong.java +++ b/idealPDS/src/test/java/typestate/targets/VectorLong.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package typestate.targets; diff --git a/idealPDS/src/test/java/typestate/targets/helper/File.java b/idealPDS/src/test/java/typestate/targets/helper/File.java index 99cd5ccad..8f2baabb3 100644 --- a/idealPDS/src/test/java/typestate/targets/helper/File.java +++ b/idealPDS/src/test/java/typestate/targets/helper/File.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package typestate.targets.helper; diff --git a/idealPDS/src/test/java/typestate/targets/helper/ObjectWithField.java b/idealPDS/src/test/java/typestate/targets/helper/ObjectWithField.java index 1cc3f72a7..95e50f9f9 100644 --- a/idealPDS/src/test/java/typestate/targets/helper/ObjectWithField.java +++ b/idealPDS/src/test/java/typestate/targets/helper/ObjectWithField.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package typestate.targets.helper; diff --git a/idealPDS/src/test/java/typestate/tests/AssertionsTest.java b/idealPDS/src/test/java/typestate/tests/AssertionsTest.java index fc7a3dcd6..50ec3e41b 100644 --- a/idealPDS/src/test/java/typestate/tests/AssertionsTest.java +++ b/idealPDS/src/test/java/typestate/tests/AssertionsTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package typestate.tests; diff --git a/idealPDS/src/test/java/typestate/tests/FileMustBeClosedDemandDrivenTest.java b/idealPDS/src/test/java/typestate/tests/FileMustBeClosedDemandDrivenTest.java index 5b809233f..a9813a9b3 100644 --- a/idealPDS/src/test/java/typestate/tests/FileMustBeClosedDemandDrivenTest.java +++ b/idealPDS/src/test/java/typestate/tests/FileMustBeClosedDemandDrivenTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package typestate.tests; diff --git a/idealPDS/src/test/java/typestate/tests/FileMustBeClosedInterfaceTest.java b/idealPDS/src/test/java/typestate/tests/FileMustBeClosedInterfaceTest.java index 2a8169a9f..b98fb7c37 100644 --- a/idealPDS/src/test/java/typestate/tests/FileMustBeClosedInterfaceTest.java +++ b/idealPDS/src/test/java/typestate/tests/FileMustBeClosedInterfaceTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package typestate.tests; diff --git a/idealPDS/src/test/java/typestate/tests/FileMustBeClosedStrongUpdateTest.java b/idealPDS/src/test/java/typestate/tests/FileMustBeClosedStrongUpdateTest.java index c99820b2e..a307c15d5 100644 --- a/idealPDS/src/test/java/typestate/tests/FileMustBeClosedStrongUpdateTest.java +++ b/idealPDS/src/test/java/typestate/tests/FileMustBeClosedStrongUpdateTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package typestate.tests; diff --git a/idealPDS/src/test/java/typestate/tests/FileMustBeClosedTest.java b/idealPDS/src/test/java/typestate/tests/FileMustBeClosedTest.java index cf28898ee..1878a46f1 100644 --- a/idealPDS/src/test/java/typestate/tests/FileMustBeClosedTest.java +++ b/idealPDS/src/test/java/typestate/tests/FileMustBeClosedTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package typestate.tests; diff --git a/idealPDS/src/test/java/typestate/tests/FluentInterfaceTest.java b/idealPDS/src/test/java/typestate/tests/FluentInterfaceTest.java index 45f764759..9611ae535 100644 --- a/idealPDS/src/test/java/typestate/tests/FluentInterfaceTest.java +++ b/idealPDS/src/test/java/typestate/tests/FluentInterfaceTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package typestate.tests; diff --git a/idealPDS/src/test/java/typestate/tests/InputStreamLongTest.java b/idealPDS/src/test/java/typestate/tests/InputStreamLongTest.java index a4aa7a755..2f8abd91e 100644 --- a/idealPDS/src/test/java/typestate/tests/InputStreamLongTest.java +++ b/idealPDS/src/test/java/typestate/tests/InputStreamLongTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package typestate.tests; diff --git a/idealPDS/src/test/java/typestate/tests/IteratorHasNextTest.java b/idealPDS/src/test/java/typestate/tests/IteratorHasNextTest.java index 3d1d0740b..f8cb85e71 100644 --- a/idealPDS/src/test/java/typestate/tests/IteratorHasNextTest.java +++ b/idealPDS/src/test/java/typestate/tests/IteratorHasNextTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package typestate.tests; diff --git a/idealPDS/src/test/java/typestate/tests/KeyStoreLongTest.java b/idealPDS/src/test/java/typestate/tests/KeyStoreLongTest.java index 95280d3d4..b96833357 100644 --- a/idealPDS/src/test/java/typestate/tests/KeyStoreLongTest.java +++ b/idealPDS/src/test/java/typestate/tests/KeyStoreLongTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package typestate.tests; diff --git a/idealPDS/src/test/java/typestate/tests/PrintStreamLongTest.java b/idealPDS/src/test/java/typestate/tests/PrintStreamLongTest.java index b3e1b9494..4d26aacb2 100644 --- a/idealPDS/src/test/java/typestate/tests/PrintStreamLongTest.java +++ b/idealPDS/src/test/java/typestate/tests/PrintStreamLongTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package typestate.tests; diff --git a/idealPDS/src/test/java/typestate/tests/PrintWriterLongTest.java b/idealPDS/src/test/java/typestate/tests/PrintWriterLongTest.java index a3ab700cb..da20ccce5 100644 --- a/idealPDS/src/test/java/typestate/tests/PrintWriterLongTest.java +++ b/idealPDS/src/test/java/typestate/tests/PrintWriterLongTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package typestate.tests; diff --git a/idealPDS/src/test/java/typestate/tests/SocketLongTest.java b/idealPDS/src/test/java/typestate/tests/SocketLongTest.java index b87aed192..865526477 100644 --- a/idealPDS/src/test/java/typestate/tests/SocketLongTest.java +++ b/idealPDS/src/test/java/typestate/tests/SocketLongTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package typestate.tests; diff --git a/idealPDS/src/test/java/typestate/tests/SootSceneSetupTest.java b/idealPDS/src/test/java/typestate/tests/SootSceneSetupTest.java index ff07cf4ec..7dc9d6467 100644 --- a/idealPDS/src/test/java/typestate/tests/SootSceneSetupTest.java +++ b/idealPDS/src/test/java/typestate/tests/SootSceneSetupTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package typestate.tests; diff --git a/idealPDS/src/test/java/typestate/tests/StackLongTest.java b/idealPDS/src/test/java/typestate/tests/StackLongTest.java index c98a9d298..ff337acc4 100644 --- a/idealPDS/src/test/java/typestate/tests/StackLongTest.java +++ b/idealPDS/src/test/java/typestate/tests/StackLongTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package typestate.tests; diff --git a/idealPDS/src/test/java/typestate/tests/URLConnTest.java b/idealPDS/src/test/java/typestate/tests/URLConnTest.java index b215bc381..fc51337a0 100644 --- a/idealPDS/src/test/java/typestate/tests/URLConnTest.java +++ b/idealPDS/src/test/java/typestate/tests/URLConnTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package typestate.tests; diff --git a/idealPDS/src/test/java/typestate/tests/VectorLongTest.java b/idealPDS/src/test/java/typestate/tests/VectorLongTest.java index bc980ac15..e54919b27 100644 --- a/idealPDS/src/test/java/typestate/tests/VectorLongTest.java +++ b/idealPDS/src/test/java/typestate/tests/VectorLongTest.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package typestate.tests; diff --git a/license_header.txt b/license_header.txt index 3d9185056..ef1f6a414 100644 --- a/license_header.txt +++ b/license_header.txt @@ -1,11 +1,14 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ diff --git a/pom.xml b/pom.xml index 901cdcae0..a7795eb94 100644 --- a/pom.xml +++ b/pom.xml @@ -81,6 +81,7 @@ 11 2.13.16 3.6.1 + ${project.basedir} diff --git a/testCore/src/main/java/test/Assertion.java b/testCore/src/main/java/test/Assertion.java index 3dc0b9275..1669c003e 100644 --- a/testCore/src/main/java/test/Assertion.java +++ b/testCore/src/main/java/test/Assertion.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test; diff --git a/testCore/src/main/java/test/TestMethod.java b/testCore/src/main/java/test/TestMethod.java index 9c10b6296..3e51d70d3 100644 --- a/testCore/src/main/java/test/TestMethod.java +++ b/testCore/src/main/java/test/TestMethod.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test; diff --git a/testCore/src/main/java/test/TestingFramework.java b/testCore/src/main/java/test/TestingFramework.java index c3dc1aa25..ca185243b 100644 --- a/testCore/src/main/java/test/TestingFramework.java +++ b/testCore/src/main/java/test/TestingFramework.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test; diff --git a/testCore/src/main/java/test/core/selfrunning/AllocatedObject.java b/testCore/src/main/java/test/core/selfrunning/AllocatedObject.java index 4bf4eb6e9..7c45da5cf 100644 --- a/testCore/src/main/java/test/core/selfrunning/AllocatedObject.java +++ b/testCore/src/main/java/test/core/selfrunning/AllocatedObject.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.core.selfrunning; diff --git a/testCore/src/main/java/test/core/selfrunning/AllocatedObject2.java b/testCore/src/main/java/test/core/selfrunning/AllocatedObject2.java index 9642634b1..c60ff3bff 100644 --- a/testCore/src/main/java/test/core/selfrunning/AllocatedObject2.java +++ b/testCore/src/main/java/test/core/selfrunning/AllocatedObject2.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.core.selfrunning; diff --git a/testCore/src/main/java/test/core/selfrunning/ImprecisionException.java b/testCore/src/main/java/test/core/selfrunning/ImprecisionException.java index 0c1ad294b..f49c28ea6 100644 --- a/testCore/src/main/java/test/core/selfrunning/ImprecisionException.java +++ b/testCore/src/main/java/test/core/selfrunning/ImprecisionException.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.core.selfrunning; diff --git a/testCore/src/main/java/test/core/selfrunning/NoAllocatedObject.java b/testCore/src/main/java/test/core/selfrunning/NoAllocatedObject.java index a686738d5..14a285e63 100644 --- a/testCore/src/main/java/test/core/selfrunning/NoAllocatedObject.java +++ b/testCore/src/main/java/test/core/selfrunning/NoAllocatedObject.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.core.selfrunning; diff --git a/testCore/src/main/java/test/core/selfrunning/NullableField.java b/testCore/src/main/java/test/core/selfrunning/NullableField.java index b4f47e5f7..80e88c8d1 100644 --- a/testCore/src/main/java/test/core/selfrunning/NullableField.java +++ b/testCore/src/main/java/test/core/selfrunning/NullableField.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.core.selfrunning; diff --git a/testCore/src/main/java/test/setup/OpalTestSetup.java b/testCore/src/main/java/test/setup/OpalTestSetup.java index d3866a185..50feb89ac 100644 --- a/testCore/src/main/java/test/setup/OpalTestSetup.java +++ b/testCore/src/main/java/test/setup/OpalTestSetup.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.setup; diff --git a/testCore/src/main/java/test/setup/SootTestSetup.java b/testCore/src/main/java/test/setup/SootTestSetup.java index a9c4a27ae..97837b017 100644 --- a/testCore/src/main/java/test/setup/SootTestSetup.java +++ b/testCore/src/main/java/test/setup/SootTestSetup.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.setup; diff --git a/testCore/src/main/java/test/setup/SootUpTestSetup.java b/testCore/src/main/java/test/setup/SootUpTestSetup.java index 675da126d..757b1840b 100644 --- a/testCore/src/main/java/test/setup/SootUpTestSetup.java +++ b/testCore/src/main/java/test/setup/SootUpTestSetup.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.setup; diff --git a/testCore/src/main/java/test/setup/TestSetup.java b/testCore/src/main/java/test/setup/TestSetup.java index 262e6a977..2377a8355 100644 --- a/testCore/src/main/java/test/setup/TestSetup.java +++ b/testCore/src/main/java/test/setup/TestSetup.java @@ -1,12 +1,15 @@ /** * ***************************************************************************** - * Copyright (c) 2025 Fraunhofer IEM, Paderborn, Germany. This program and the - * accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. - * - *

    SPDX-License-Identifier: EPL-2.0 - * - *

    Contributors: Johannes Spaeth - initial API and implementation + * Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany + *

    + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + *

    + * SPDX-License-Identifier: EPL-2.0 + *

    + * Contributors: + * Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package test.setup; From b4740823d8ecc6ce1d3bf607956ef44e72bfd953 Mon Sep 17 00:00:00 2001 From: Sven Meyer Date: Thu, 24 Apr 2025 14:23:25 +0200 Subject: [PATCH 61/61] Fix formatting --- .../java/test/core/AbstractBoomerangTest.java | 1 + .../boomerang/scope/opal/OpalCallGraph.scala | 179 ++-- .../boomerang/scope/opal/OpalClient.scala | 18 +- .../scope/opal/OpalFrameworkScope.scala | 22 +- .../scope/opal/tac/OpalArrayRef.scala | 124 +-- .../scope/opal/tac/OpalControlFlowGraph.scala | 154 +-- .../scope/opal/tac/OpalDeclaredMethod.scala | 64 +- .../scope/opal/tac/OpalDoubleVal.scala | 24 +- .../boomerang/scope/opal/tac/OpalField.scala | 20 +- .../scope/opal/tac/OpalIfStatement.scala | 48 +- .../scope/opal/tac/OpalInstanceFieldRef.scala | 130 +-- .../scope/opal/tac/OpalInvokeExpr.scala | 126 +-- .../boomerang/scope/opal/tac/OpalLocal.scala | 154 +-- .../boomerang/scope/opal/tac/OpalMethod.scala | 162 +-- .../scope/opal/tac/OpalNullType.scala | 26 +- .../scope/opal/tac/OpalPhantomMethod.scala | 81 +- .../opal/tac/OpalPhantomWrappedClass.scala | 24 +- .../scope/opal/tac/OpalStatement.scala | 664 ++++++------ .../opal/tac/OpalStatementFormatter.scala | 124 +-- .../scope/opal/tac/OpalStaticFieldRef.scala | 130 +-- .../scope/opal/tac/OpalStaticFieldVal.scala | 28 +- .../boomerang/scope/opal/tac/OpalType.scala | 92 +- .../boomerang/scope/opal/tac/OpalVal.scala | 265 +++-- .../scope/opal/tac/OpalWrappedClass.scala | 56 +- .../opal/transformation/BoomerangTACode.scala | 18 +- .../scope/opal/transformation/StmtGraph.scala | 297 +++--- .../opal/transformation/TacBodyBuilder.scala | 92 +- .../scope/opal/transformation/TacLocal.scala | 157 +-- .../opal/transformation/stack/Operand.scala | 26 +- .../transformation/stack/OperandStack.scala | 90 +- .../stack/OperandStackBuilder.scala | 670 ++++++------ .../stack/OperandStackHandler.scala | 156 +-- .../transformer/InlineLocalTransformer.scala | 252 ++--- .../LocalPropagationTransformer.scala | 898 ++++++++-------- .../transformer/LocalTransformer.scala | 984 +++++++++--------- .../transformer/NopEliminator.scala | 20 +- .../transformer/NopTransformer.scala | 68 +- .../NullifyFieldsTransformer.scala | 115 +- .../boomerang/scope/opal/OpalArrayTest.scala | 242 ++--- .../scope/opal/OpalAssignmentTest.scala | 276 ++--- .../scope/opal/OpalControlFlowGraphTest.scala | 48 +- .../boomerang/scope/opal/OpalFieldTest.scala | 422 ++++---- .../scope/opal/OpalInvokeExprTest.scala | 154 +-- .../boomerang/scope/opal/OpalLocalTest.scala | 168 +-- .../boomerang/scope/opal/OpalSetup.scala | 56 +- .../scope/opal/TacBodyBuilderTest.scala | 154 +-- misc/.scalafmt.conf | 4 +- .../src/main/java/test/TestingFramework.java | 2 +- 48 files changed, 4050 insertions(+), 4035 deletions(-) diff --git a/boomerangPDS/src/test/java/test/core/AbstractBoomerangTest.java b/boomerangPDS/src/test/java/test/core/AbstractBoomerangTest.java index 896ca3690..59dadfb95 100644 --- a/boomerangPDS/src/test/java/test/core/AbstractBoomerangTest.java +++ b/boomerangPDS/src/test/java/test/core/AbstractBoomerangTest.java @@ -128,6 +128,7 @@ protected void analyze( } private void analyzeWithCallGraph(FrameworkScope frameworkScope, boolean ignoreAllocSites) { + LOGGER.info("Running test method " + testName.getMethodName()); CallGraph callGraph = frameworkScope.getCallGraph(); queryDetector = new QueryForCallSiteDetector(callGraph); queryForCallSites = queryDetector.computeSeeds(); diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalCallGraph.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalCallGraph.scala index e7fdfa987..90098e86d 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalCallGraph.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalCallGraph.scala @@ -38,109 +38,108 @@ class OpalCallGraph( entryPoints: Set[Method] ) extends CallGraph { - // TODO Deal with - callGraph - .reachableMethods() - .foreach(method => { - method.method match { - case definedMethod: DefinedMethod => - if (definedMethod.definedMethod.body.isDefined) { - addEdgesFromMethod(definedMethod) - } - // TODO Should this case be considered? - // case definedMethods: MultipleDefinedMethods => - // definedMethods.foreachDefinedMethod(m => addEdgesFromMethod(m)) - case _ => - } - }) + callGraph + .reachableMethods() + .foreach(method => { + method.method match { + case definedMethod: DefinedMethod => + if (definedMethod.definedMethod.body.isDefined) { + addEdgesFromMethod(definedMethod) + } + // TODO Should this case be considered? + // case definedMethods: MultipleDefinedMethods => + // definedMethods.foreachDefinedMethod(m => addEdgesFromMethod(m)) + case _ => + } + }) - private def addEdgesFromMethod(method: DefinedMethod): Unit = { - val tacCode = TacBodyBuilder(project, method.definedMethod) + private def addEdgesFromMethod(method: DefinedMethod): Unit = { + val tacCode = TacBodyBuilder(project, method.definedMethod) - tacCode.statements.foreach(stmt => { - val srcStatement = - new OpalStatement(stmt, OpalMethod(method.definedMethod, tacCode)) + tacCode.statements.foreach(stmt => { + val srcStatement = + new OpalStatement(stmt, OpalMethod(method.definedMethod, tacCode)) - if (srcStatement.containsInvokeExpr()) { - // Due to inlining variables, the PC's of statements and invoke expressions may differ - val invokeExprPc = getPcForInvokeExpr(srcStatement.getInvokeExpr) - val callees = callGraph.directCalleesOf(method, invokeExprPc) + if (srcStatement.containsInvokeExpr()) { + // Due to inlining variables, the PC's of statements and invoke expressions may differ + val invokeExprPc = getPcForInvokeExpr(srcStatement.getInvokeExpr) + val callees = callGraph.directCalleesOf(method, invokeExprPc) - callees.foreach(callee => { - callee.method match { - case definedMethod: DefinedMethod => - val method = definedMethod.definedMethod + callees.foreach(callee => { + callee.method match { + case definedMethod: DefinedMethod => + val method = definedMethod.definedMethod - if (method.body.isDefined) { - val targetMethod = OpalMethod(method) + if (method.body.isDefined) { + val targetMethod = OpalMethod(method) - addEdge(new Edge(srcStatement, targetMethod)) - } else { - val targetMethod = OpalPhantomMethod( - definedMethod.declaringClassType, - definedMethod.name, - definedMethod.descriptor, - method.isStatic - ) + addEdge(new Edge(srcStatement, targetMethod)) + } else { + val targetMethod = OpalPhantomMethod( + definedMethod.declaringClassType, + definedMethod.name, + definedMethod.descriptor, + method.isStatic + ) - addEdge(new Edge(srcStatement, targetMethod)) - } - case virtualMethod: VirtualDeclaredMethod => - val targetMethod = OpalPhantomMethod( - virtualMethod.declaringClassType, - virtualMethod.name, - virtualMethod.descriptor, - srcStatement.getInvokeExpr.isStaticInvokeExpr - ) + addEdge(new Edge(srcStatement, targetMethod)) + } + case virtualMethod: VirtualDeclaredMethod => + val targetMethod = OpalPhantomMethod( + virtualMethod.declaringClassType, + virtualMethod.name, + virtualMethod.descriptor, + srcStatement.getInvokeExpr.isStaticInvokeExpr + ) - addEdge(new Edge(srcStatement, targetMethod)) - case definedMethods: MultipleDefinedMethods => - definedMethods.foreachDefinedMethod(method => { - val targetMethod = OpalMethod(method) + addEdge(new Edge(srcStatement, targetMethod)) + case definedMethods: MultipleDefinedMethods => + definedMethods.foreachDefinedMethod(method => { + val targetMethod = OpalMethod(method) - addEdge(new Edge(srcStatement, targetMethod)) - }) - } - }) - } + addEdge(new Edge(srcStatement, targetMethod)) + }) + } }) - } + } + }) + } - private def getPcForInvokeExpr(invokeExpr: InvokeExpr): Int = { - invokeExpr match { - case methodInvokeExpr: OpalMethodInvokeExpr => - methodInvokeExpr.delegate.pc - case functionInvokeExpr: OpalFunctionInvokeExpr => - functionInvokeExpr.delegate match { - case call: NonVirtualFunctionCall[_] => call.pc - case call: VirtualFunctionCall[_] => call.pc - case call: StaticFunctionCall[_] => call.pc - case _ => - throw new RuntimeException( - "Unknown function call: " + functionInvokeExpr - ) - } - case _ => - throw new RuntimeException("Unknown invoke expression: " + invokeExpr) + private def getPcForInvokeExpr(invokeExpr: InvokeExpr): Int = { + invokeExpr match { + case methodInvokeExpr: OpalMethodInvokeExpr => + methodInvokeExpr.delegate.pc + case functionInvokeExpr: OpalFunctionInvokeExpr => + functionInvokeExpr.delegate match { + case call: NonVirtualFunctionCall[_] => call.pc + case call: VirtualFunctionCall[_] => call.pc + case call: StaticFunctionCall[_] => call.pc + case _ => + throw new RuntimeException( + "Unknown function call: " + functionInvokeExpr + ) } + case _ => + throw new RuntimeException("Unknown invoke expression: " + invokeExpr) } + } - // Explicitly add static initializers () as they are called only implicitly - callGraph - .reachableMethods() - .foreach(method => { - method.method match { - case definedMethod: DefinedMethod if definedMethod.definedMethod.isStaticInitializer => - if (definedMethod.definedMethod.body.isDefined) { - addEntryPoint(OpalMethod(definedMethod.definedMethod)) - } - case _ => - } - }) - - entryPoints.foreach(entryPoint => { - if (entryPoint.body.isDefined) { - addEntryPoint(OpalMethod(entryPoint)) - } + // Explicitly add static initializers () as they are called only implicitly + callGraph + .reachableMethods() + .foreach(method => { + method.method match { + case definedMethod: DefinedMethod if definedMethod.definedMethod.isStaticInitializer => + if (definedMethod.definedMethod.body.isDefined) { + addEntryPoint(OpalMethod(definedMethod.definedMethod)) + } + case _ => + } }) + + entryPoints.foreach(entryPoint => { + if (entryPoint.body.isDefined) { + addEntryPoint(OpalMethod(entryPoint)) + } + }) } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalClient.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalClient.scala index 409bdcad0..df8fa83bb 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalClient.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalClient.scala @@ -28,18 +28,18 @@ import org.opalj.br.analyses.Project object OpalClient { - var project: Option[Project[_]] = None + var project: Option[Project[_]] = None - def init(p: Project[_]): Unit = { - project = Some(p) - } + def init(p: Project[_]): Unit = { + project = Some(p) + } - def getClassHierarchy: ClassHierarchy = project.get.classHierarchy + def getClassHierarchy: ClassHierarchy = project.get.classHierarchy - def getClassFileForType(objectType: ObjectType): Option[ClassFile] = - project.get.classFile(objectType) + def getClassFileForType(objectType: ObjectType): Option[ClassFile] = + project.get.classFile(objectType) - def isApplicationClass(classFile: ClassFile): Boolean = - project.get.allProjectClassFiles.toSet.contains(classFile) + def isApplicationClass(classFile: ClassFile): Boolean = + project.get.allProjectClassFiles.toSet.contains(classFile) } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalFrameworkScope.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalFrameworkScope.scala index a63c2d5d6..12d607341 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalFrameworkScope.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/OpalFrameworkScope.scala @@ -25,24 +25,24 @@ class OpalFrameworkScope( dataFlowScope: DataFlowScope ) extends FrameworkScope { - OpalClient.init(project) - private val opalCallGraph = new OpalCallGraph(project, callGraph, entryPoints) + OpalClient.init(project) + private val opalCallGraph = new OpalCallGraph(project, callGraph, entryPoints) - override def getCallGraph: CallGraph = opalCallGraph + override def getCallGraph: CallGraph = opalCallGraph - override def getDataFlowScope: DataFlowScope = dataFlowScope + override def getDataFlowScope: DataFlowScope = dataFlowScope - override def getTrueValue(m: Method): Val = ??? + override def getTrueValue(m: Method): Val = ??? - override def getFalseValue(m: Method): Val = ??? + override def getFalseValue(m: Method): Val = ??? - override def handleStaticFieldInitializers(fact: Val): stream.Stream[Method] = - ??? + override def handleStaticFieldInitializers(fact: Val): stream.Stream[Method] = + ??? - override def newStaticFieldVal(field: Field, m: Method): StaticFieldVal = ??? + override def newStaticFieldVal(field: Field, m: Method): StaticFieldVal = ??? } object OpalFrameworkScope { - final val STATIC_INITIALIZER: String = "" - final val CONSTRUCTOR: String = "" + final val STATIC_INITIALIZER: String = "" + final val CONSTRUCTOR: String = "" } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalArrayRef.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalArrayRef.scala index 262d895c3..8149f921e 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalArrayRef.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalArrayRef.scala @@ -26,98 +26,98 @@ class OpalArrayRef( unbalanced: ControlFlowGraph.Edge = null ) extends Val(method, unbalanced) { - // TODO Type - override def getType: Type = OpalType(ObjectType.Array) + // TODO Which type is expected? int[] or int? + override def getType: Type = OpalType(ObjectType.Array) - override def isStatic: Boolean = false + override def isStatic: Boolean = false - override def isNewExpr: Boolean = false + override def isNewExpr: Boolean = false - override def getNewExprType: Type = throw new RuntimeException( - "Array Value is not a new expression" - ) + override def getNewExprType: Type = throw new RuntimeException( + "Array Value is not a new expression" + ) - override def asUnbalanced(stmt: ControlFlowGraph.Edge): Val = - new OpalArrayRef(arrayRef, index, method, stmt) + override def asUnbalanced(stmt: ControlFlowGraph.Edge): Val = + new OpalArrayRef(arrayRef, index, method, stmt) - override def isLocal: Boolean = true + override def isLocal: Boolean = true - override def isArrayAllocationVal: Boolean = false + override def isArrayAllocationVal: Boolean = false - override def getArrayAllocationSize: Val = throw new RuntimeException( - "Array Value has no allocation size" - ) + override def getArrayAllocationSize: Val = throw new RuntimeException( + "Array Value has no allocation size" + ) - override def isNull: Boolean = false + override def isNull: Boolean = false - override def isStringConstant: Boolean = false + override def isStringConstant: Boolean = false - override def getStringValue: String = throw new RuntimeException( - "Array Value is not a String constant" - ) + override def getStringValue: String = throw new RuntimeException( + "Array Value is not a String constant" + ) - override def isStringBufferOrBuilder: Boolean = false + override def isStringBufferOrBuilder: Boolean = false - override def isThrowableAllocationType: Boolean = false + override def isThrowableAllocationType: Boolean = false - override def isCast: Boolean = false + override def isCast: Boolean = false - override def getCastOp: Val = throw new RuntimeException( - "Array Value is not a cast operation" - ) + override def getCastOp: Val = throw new RuntimeException( + "Array Value is not a cast operation" + ) - override def isArrayRef: Boolean = true + override def isArrayRef: Boolean = true - override def isInstanceOfExpr: Boolean = false + override def isInstanceOfExpr: Boolean = false - override def getInstanceOfOp: Val = throw new RuntimeException( - "Array Value is not an instance of operation" - ) + override def getInstanceOfOp: Val = throw new RuntimeException( + "Array Value is not an instance of operation" + ) - override def isLengthExpr: Boolean = false + override def isLengthExpr: Boolean = false - override def getLengthOp: Val = throw new RuntimeException( - "Array Value is not a length operation" - ) + override def getLengthOp: Val = throw new RuntimeException( + "Array Value is not a length operation" + ) - override def isIntConstant: Boolean = false + override def isIntConstant: Boolean = false - override def isClassConstant: Boolean = false + override def isClassConstant: Boolean = false - override def getClassConstantType: Type = throw new RuntimeException( - "Array Value is not a class constant" - ) + override def getClassConstantType: Type = throw new RuntimeException( + "Array Value is not a class constant" + ) - override def withNewMethod(callee: Method): Val = - new OpalArrayRef(arrayRef, index, callee.asInstanceOf[OpalMethod]) + override def withNewMethod(callee: Method): Val = + new OpalArrayRef(arrayRef, index, callee.asInstanceOf[OpalMethod]) - override def isLongConstant: Boolean = false + override def isLongConstant: Boolean = false - override def getIntValue: Int = throw new RuntimeException( - "Array Value is not an integer constant" - ) + override def getIntValue: Int = throw new RuntimeException( + "Array Value is not an integer constant" + ) - override def getLongValue: Long = throw new RuntimeException( - "Array Value is not a long constant" - ) + override def getLongValue: Long = throw new RuntimeException( + "Array Value is not a long constant" + ) - override def getArrayBase: Pair[Val, Integer] = { - val base = new OpalLocal(arrayRef, method) + override def getArrayBase: Pair[Val, Integer] = { + val base = new OpalLocal(arrayRef, method) - new Pair[Val, Integer](base, index) - } + new Pair[Val, Integer](base, index) + } - override def getVariableName: String = s"$arrayRef[$index]" + override def getVariableName: String = s"$arrayRef[$index]" - override def hashCode: Int = Objects.hash(super.hashCode(), arrayRef, index) + override def hashCode: Int = Objects.hash(super.hashCode(), arrayRef, index) - override def equals(other: Any): Boolean = other match { - case that: OpalArrayRef => - super.equals( - that - ) && this.arrayRef == that.arrayRef && this.index == that.index - case _ => false - } + override def equals(other: Any): Boolean = other match { + case that: OpalArrayRef => + super.equals( + that + ) && this.arrayRef == that.arrayRef && this.index == that.index + case _ => false + } - override def toString: String = getVariableName + override def toString: String = getVariableName } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalControlFlowGraph.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalControlFlowGraph.scala index 2a0cc2f1a..0c9638c7d 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalControlFlowGraph.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalControlFlowGraph.scala @@ -23,85 +23,85 @@ import org.opalj.tac.Nop class OpalControlFlowGraph(method: OpalMethod) extends ControlFlowGraph { - private var cacheBuilt = false - - private val startPointCache: util.List[Statement] = - new util.ArrayList[Statement] - private val endPointCache: util.List[Statement] = - new util.ArrayList[Statement] - private val predsOfCache: Multimap[Statement, Statement] = - HashMultimap.create() - private val succsOfCache: Multimap[Statement, Statement] = - HashMultimap.create() - private val statements: util.List[Statement] = new util.ArrayList[Statement]() - - def get(): OpalControlFlowGraph = { - buildCache() - - this - } - - override def getStartPoints: util.Collection[Statement] = { - buildCache() - startPointCache - } - - override def getEndPoints: util.Collection[Statement] = { - buildCache() - endPointCache - } - - override def getSuccsOf(curr: Statement): util.Collection[Statement] = { - buildCache() - succsOfCache.get(curr) - } - - override def getPredsOf(curr: Statement): util.Collection[Statement] = { - buildCache() - predsOfCache.get(curr) - } - - override def getStatements: util.List[Statement] = { - buildCache() - statements - } - - private def buildCache(): Unit = { - if (cacheBuilt) return - - val graph = method.tac.cfg - - graph.heads.foreach(stmt => { - val headStmt = new OpalStatement(stmt, method) - - startPointCache.add(headStmt) + private var cacheBuilt = false + + private val startPointCache: util.List[Statement] = + new util.ArrayList[Statement] + private val endPointCache: util.List[Statement] = + new util.ArrayList[Statement] + private val predsOfCache: Multimap[Statement, Statement] = + HashMultimap.create() + private val succsOfCache: Multimap[Statement, Statement] = + HashMultimap.create() + private val statements: util.List[Statement] = new util.ArrayList[Statement]() + + def get(): OpalControlFlowGraph = { + buildCache() + + this + } + + override def getStartPoints: util.Collection[Statement] = { + buildCache() + startPointCache + } + + override def getEndPoints: util.Collection[Statement] = { + buildCache() + endPointCache + } + + override def getSuccsOf(curr: Statement): util.Collection[Statement] = { + buildCache() + succsOfCache.get(curr) + } + + override def getPredsOf(curr: Statement): util.Collection[Statement] = { + buildCache() + predsOfCache.get(curr) + } + + override def getStatements: util.List[Statement] = { + buildCache() + statements + } + + private def buildCache(): Unit = { + if (cacheBuilt) return + + val graph = method.tac.cfg + + graph.heads.foreach(stmt => { + val headStmt = new OpalStatement(stmt, method) + + startPointCache.add(headStmt) + }) + + graph.tails.foreach(stmt => { + val tailStmt = new OpalStatement(stmt, method) + + endPointCache.add(tailStmt) + }) + + method.tac.statements.foreach(stmt => { + val statement = new OpalStatement(stmt, method) + statements.add(statement) + + graph + .predecessors(stmt) + .foreach(pred => { + val predStmt = new OpalStatement(pred, method) + predsOfCache.put(statement, predStmt) }) - graph.tails.foreach(stmt => { - val tailStmt = new OpalStatement(stmt, method) - - endPointCache.add(tailStmt) - }) - - method.tac.statements.foreach(stmt => { - val statement = new OpalStatement(stmt, method) - statements.add(statement) - - graph - .predecessors(stmt) - .foreach(pred => { - val predStmt = new OpalStatement(pred, method) - predsOfCache.put(statement, predStmt) - }) - - graph - .successors(stmt) - .foreach(succ => { - val succStmt = new OpalStatement(succ, method) - succsOfCache.put(statement, succStmt) - }) + graph + .successors(stmt) + .foreach(succ => { + val succStmt = new OpalStatement(succ, method) + succsOfCache.put(statement, succStmt) }) + }) - cacheBuilt = true - } + cacheBuilt = true + } } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalDeclaredMethod.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalDeclaredMethod.scala index f5a417cb9..10e0d64e6 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalDeclaredMethod.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalDeclaredMethod.scala @@ -32,49 +32,49 @@ case class OpalDeclaredMethod[+V <: Var[V]]( delegate: Call[V] ) extends DeclaredMethod(invokeExpr) { - override def getSubSignature: String = - MethodSignature(delegate.name, delegate.descriptor).toJava + override def getSubSignature: String = + MethodSignature(delegate.name, delegate.descriptor).toJava - override def getName: String = delegate.name + override def getName: String = delegate.name - override def isConstructor: Boolean = - delegate.name == OpalFrameworkScope.CONSTRUCTOR + override def isConstructor: Boolean = + delegate.name == OpalFrameworkScope.CONSTRUCTOR - override def getSignature: String = delegate.descriptor.toJava( - s"${delegate.declaringClass.toJava}.${delegate.name}" - ) + override def getSignature: String = delegate.descriptor.toJava( + s"${delegate.declaringClass.toJava}.${delegate.name}" + ) - override def getDeclaringClass: WrappedClass = { - val decClass = - OpalClient.getClassFileForType(delegate.declaringClass.asObjectType) + override def getDeclaringClass: WrappedClass = { + val decClass = + OpalClient.getClassFileForType(delegate.declaringClass.asObjectType) - if (decClass.isDefined) { - OpalWrappedClass(decClass.get) - } else { - OpalPhantomWrappedClass(delegate.declaringClass) - } + if (decClass.isDefined) { + OpalWrappedClass(decClass.get) + } else { + OpalPhantomWrappedClass(delegate.declaringClass) } + } - override def getParameterTypes: util.List[Type] = { - val result = new util.ArrayList[Type]() + override def getParameterTypes: util.List[Type] = { + val result = new util.ArrayList[Type]() - delegate.descriptor.parameterTypes.foreach(paramType => { - result.add(OpalType(paramType)) - }) + delegate.descriptor.parameterTypes.foreach(paramType => { + result.add(OpalType(paramType)) + }) - result - } + result + } - override def getParameterType(index: Int): Type = getParameterTypes.get(index) + override def getParameterType(index: Int): Type = getParameterTypes.get(index) - override def getReturnType: Type = OpalType(delegate.descriptor.returnType) + override def getReturnType: Type = OpalType(delegate.descriptor.returnType) - override def toMethodWrapper: MethodWrapper = new MethodWrapper( - delegate.declaringClass.toJava, - delegate.name, - delegate.descriptor.returnType.toJava, - delegate.descriptor.parameterTypes.map(p => p.toJava).toList.asJava - ) + override def toMethodWrapper: MethodWrapper = new MethodWrapper( + delegate.declaringClass.toJava, + delegate.name, + delegate.descriptor.returnType.toJava, + delegate.descriptor.parameterTypes.map(p => p.toJava).toList.asJava + ) - override def toString: String = delegate.descriptor.toJava + override def toString: String = delegate.descriptor.toJava } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalDoubleVal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalDoubleVal.scala index 84d697755..2dad077e9 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalDoubleVal.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalDoubleVal.scala @@ -28,20 +28,20 @@ class OpalDoubleVal(delegate: Expr[TacLocal], method: OpalMethod, falseVal: Val) extends OpalVal(delegate, method) with ValWithFalseVariable { - override def getFalseVariable: Val = falseVal + override def getFalseVariable: Val = falseVal - override def hashCode: Int = Objects.hash(super.hashCode, falseVal) + override def hashCode: Int = Objects.hash(super.hashCode, falseVal) - private def canEqual(a: Any): Boolean = a.isInstanceOf[OpalDoubleVal] + private def canEqual(a: Any): Boolean = a.isInstanceOf[OpalDoubleVal] - override def equals(obj: Any): Boolean = obj match { - case other: OpalDoubleVal => - other.canEqual(this) && super.equals(other) && falseVal.equals( - other.getFalseVariable - ) - case _ => false - } + override def equals(obj: Any): Boolean = obj match { + case other: OpalDoubleVal => + other.canEqual(this) && super.equals(other) && falseVal.equals( + other.getFalseVariable + ) + case _ => false + } - override def toString: String = - "FalseVal: " + falseVal + " from " + super.toString + override def toString: String = + "FalseVal: " + falseVal + " from " + super.toString } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalField.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalField.scala index 0bdeff459..20d17a4b5 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalField.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalField.scala @@ -26,19 +26,19 @@ class OpalField( val name: String ) extends Field { - override def isPredefinedField: Boolean = false + override def isPredefinedField: Boolean = false - override def isInnerClassField: Boolean = declaringClass.fqn.contains("$") + override def isInnerClassField: Boolean = declaringClass.fqn.contains("$") - override def getType: Type = OpalType(fieldType) + override def getType: Type = OpalType(fieldType) - override def hashCode: Int = Objects.hash(super.hashCode(), fieldType, name) + override def hashCode: Int = Objects.hash(super.hashCode(), fieldType, name) - override def equals(other: Any): Boolean = other match { - case that: OpalField => - this.fieldType == that.fieldType && this.name == that.name - case _ => false - } + override def equals(other: Any): Boolean = other match { + case that: OpalField => + this.fieldType == that.fieldType && this.name == that.name + case _ => false + } - override def toString: String = s"$name" + override def toString: String = s"$name" } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalIfStatement.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalIfStatement.scala index 23bf00db0..da87008e7 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalIfStatement.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalIfStatement.scala @@ -28,37 +28,39 @@ import org.opalj.value.ValueInformation class OpalIfStatement(val delegate: If[TacLocal], method: OpalMethod) extends IfStatement { - override def getTarget: Statement = { - /*val tac = OpalClient.getTacForMethod(method.delegate) + override def getTarget: Statement = { + /*val tac = OpalClient.getTacForMethod(method.delegate) val target = delegate.targetStmt new OpalStatement(tac.stmts(target), method)*/ - ??? - } + ??? + } - override def evaluate(otherVal: Val): IfStatement.Evaluation = - IfStatement.Evaluation.UNKNOWN + override def evaluate(otherVal: Val): IfStatement.Evaluation = + IfStatement.Evaluation.UNKNOWN - override def uses(otherVal: Val): Boolean = { - // TODO - if (otherVal.isInstanceOf[OpalVal]) {} - if (otherVal.isInstanceOf[OpalLocal]) {} - if (otherVal.isInstanceOf[OpalArrayRef]) {} - val left = new OpalVal(delegate.left, method) - val right = new OpalVal(delegate.right, method) + override def uses(otherVal: Val): Boolean = { + // TODO + // Only relevant for PathTrackingBoomerang that is not used and tested; + // has to be implemented when used + if (otherVal.isInstanceOf[OpalVal]) {} + if (otherVal.isInstanceOf[OpalLocal]) {} + if (otherVal.isInstanceOf[OpalArrayRef]) {} + val left = new OpalVal(delegate.left, method) + val right = new OpalVal(delegate.right, method) - otherVal.equals(left) || otherVal.equals(right) - } + otherVal.equals(left) || otherVal.equals(right) + } - override def hashCode: Int = Objects.hash(delegate) + override def hashCode: Int = Objects.hash(delegate) - private def canEqual(a: Any): Boolean = a.isInstanceOf[OpalIfStatement] + private def canEqual(a: Any): Boolean = a.isInstanceOf[OpalIfStatement] - override def equals(obj: Any): Boolean = obj match { - case other: OpalIfStatement => - other.canEqual(this) && this.delegate.pc == other.delegate.pc - case _ => false - } + override def equals(obj: Any): Boolean = obj match { + case other: OpalIfStatement => + other.canEqual(this) && this.delegate.pc == other.delegate.pc + case _ => false + } - override def toString: String = delegate.toString() + override def toString: String = delegate.toString() } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalInstanceFieldRef.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalInstanceFieldRef.scala index a319334da..0a78ff112 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalInstanceFieldRef.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalInstanceFieldRef.scala @@ -30,100 +30,100 @@ class OpalInstanceFieldRef( unbalanced: ControlFlowGraph.Edge = null ) extends Val(method, unbalanced) { - override def getType: Type = OpalType(fieldType) + override def getType: Type = OpalType(fieldType) - override def isStatic: Boolean = false + override def isStatic: Boolean = false - override def isNewExpr: Boolean = false + override def isNewExpr: Boolean = false - override def getNewExprType: Type = throw new RuntimeException( - "Instance field ref is not a new expression" - ) + override def getNewExprType: Type = throw new RuntimeException( + "Instance field ref is not a new expression" + ) - override def asUnbalanced(stmt: ControlFlowGraph.Edge): Val = - new OpalInstanceFieldRef(base, fieldType, fieldName, method, stmt) + override def asUnbalanced(stmt: ControlFlowGraph.Edge): Val = + new OpalInstanceFieldRef(base, fieldType, fieldName, method, stmt) - override def isLocal: Boolean = false + override def isLocal: Boolean = false - override def isArrayAllocationVal: Boolean = false + override def isArrayAllocationVal: Boolean = false - override def getArrayAllocationSize: Val = throw new RuntimeException( - "Instance field ref is not an array allocation val" - ) + override def getArrayAllocationSize: Val = throw new RuntimeException( + "Instance field ref is not an array allocation val" + ) - override def isNull: Boolean = false + override def isNull: Boolean = false - override def isStringConstant: Boolean = false + override def isStringConstant: Boolean = false - override def getStringValue: String = throw new RuntimeException( - "Instance field ref is not a String constant" - ) + override def getStringValue: String = throw new RuntimeException( + "Instance field ref is not a String constant" + ) - override def isStringBufferOrBuilder: Boolean = false + override def isStringBufferOrBuilder: Boolean = false - override def isThrowableAllocationType: Boolean = false + override def isThrowableAllocationType: Boolean = false - override def isCast: Boolean = false + override def isCast: Boolean = false - override def getCastOp: Val = throw new RuntimeException( - "Instance field ref is not a cast expression" - ) + override def getCastOp: Val = throw new RuntimeException( + "Instance field ref is not a cast expression" + ) - override def isArrayRef: Boolean = false + override def isArrayRef: Boolean = false - override def isInstanceOfExpr: Boolean = false + override def isInstanceOfExpr: Boolean = false - override def getInstanceOfOp: Val = throw new RuntimeException( - "Instance field ref is not an instanceOf expression" - ) + override def getInstanceOfOp: Val = throw new RuntimeException( + "Instance field ref is not an instanceOf expression" + ) - override def isLengthExpr: Boolean = false + override def isLengthExpr: Boolean = false - override def getLengthOp: Val = throw new RuntimeException( - "Instance field ref is not a length expression" - ) + override def getLengthOp: Val = throw new RuntimeException( + "Instance field ref is not a length expression" + ) - override def isIntConstant: Boolean = false + override def isIntConstant: Boolean = false - override def isClassConstant: Boolean = false + override def isClassConstant: Boolean = false - override def getClassConstantType: Type = throw new RuntimeException( - "Instance field ref is not a class constant" - ) + override def getClassConstantType: Type = throw new RuntimeException( + "Instance field ref is not a class constant" + ) - override def withNewMethod(callee: Method): Val = new OpalInstanceFieldRef( - base, - fieldType, - fieldName, - callee.asInstanceOf[OpalMethod] - ) + override def withNewMethod(callee: Method): Val = new OpalInstanceFieldRef( + base, + fieldType, + fieldName, + callee.asInstanceOf[OpalMethod] + ) - override def isLongConstant: Boolean = false + override def isLongConstant: Boolean = false - override def getIntValue: Int = throw new RuntimeException( - "Instance field ref is not an int constant" - ) + override def getIntValue: Int = throw new RuntimeException( + "Instance field ref is not an int constant" + ) - override def getLongValue: Long = throw new RuntimeException( - "Instance field ref is not a long constant" - ) + override def getLongValue: Long = throw new RuntimeException( + "Instance field ref is not a long constant" + ) - override def getArrayBase: Pair[Val, Integer] = throw new RuntimeException( - "Instance field ref has no array base" - ) + override def getArrayBase: Pair[Val, Integer] = throw new RuntimeException( + "Instance field ref has no array base" + ) - override def getVariableName: String = s"$base.$fieldName" + override def getVariableName: String = s"$base.$fieldName" - override def hashCode: Int = - Objects.hash(super.hashCode(), base, fieldType, fieldName) + override def hashCode: Int = + Objects.hash(super.hashCode(), base, fieldType, fieldName) - override def equals(other: Any): Boolean = other match { - case that: OpalInstanceFieldRef => - super.equals( - other - ) && this.base == that.base && this.fieldType == that.fieldType && this.fieldName == that.fieldName - case _ => false - } + override def equals(other: Any): Boolean = other match { + case that: OpalInstanceFieldRef => + super.equals( + other + ) && this.base == that.base && this.fieldType == that.fieldType && this.fieldName == that.fieldName + case _ => false + } - override def toString: String = getVariableName + override def toString: String = getVariableName } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalInvokeExpr.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalInvokeExpr.scala index bbac976dc..361525c20 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalInvokeExpr.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalInvokeExpr.scala @@ -27,47 +27,47 @@ class OpalMethodInvokeExpr( method: OpalMethod ) extends InvokeExpr { - override def getArg(index: Int): Val = getArgs.get(index) + override def getArg(index: Int): Val = getArgs.get(index) - override def getArgs: util.List[Val] = { - val result = new util.ArrayList[Val] + override def getArgs: util.List[Val] = { + val result = new util.ArrayList[Val] - delegate.params.foreach(param => { - result.add(new OpalLocal(param.asVar, method)) - }) + delegate.params.foreach(param => { + result.add(new OpalLocal(param.asVar, method)) + }) - result - } - - override def isInstanceInvokeExpr: Boolean = - delegate.isInstanceOf[InstanceMethodCall[_]] + result + } - override def getBase: Val = { - if (isInstanceInvokeExpr) { - return new OpalLocal(delegate.asInstanceMethodCall.receiver.asVar, method) - } + override def isInstanceInvokeExpr: Boolean = + delegate.isInstanceOf[InstanceMethodCall[_]] - throw new RuntimeException( - "Method call is not an instance invoke expression" - ) + override def getBase: Val = { + if (isInstanceInvokeExpr) { + return new OpalLocal(delegate.asInstanceMethodCall.receiver.asVar, method) } - override def getDeclaredMethod: DeclaredMethod = - OpalDeclaredMethod(this, delegate) + throw new RuntimeException( + "Method call is not an instance invoke expression" + ) + } - override def isSpecialInvokeExpr: Boolean = - delegate.astID == NonVirtualMethodCall.ASTID + override def getDeclaredMethod: DeclaredMethod = + OpalDeclaredMethod(this, delegate) - override def isStaticInvokeExpr: Boolean = delegate.isStaticMethodCall + override def isSpecialInvokeExpr: Boolean = + delegate.astID == NonVirtualMethodCall.ASTID - override def hashCode: Int = Objects.hash(delegate) + override def isStaticInvokeExpr: Boolean = delegate.isStaticMethodCall - override def equals(obj: Any): Boolean = obj match { - case other: OpalMethodInvokeExpr => this.delegate == other.delegate - case _ => false - } + override def hashCode: Int = Objects.hash(delegate) + + override def equals(obj: Any): Boolean = obj match { + case other: OpalMethodInvokeExpr => this.delegate == other.delegate + case _ => false + } - override def toString: String = delegate.toString + override def toString: String = delegate.toString } class OpalFunctionInvokeExpr( @@ -75,51 +75,51 @@ class OpalFunctionInvokeExpr( method: OpalMethod ) extends InvokeExpr { - override def getArg(index: Int): Val = getArgs.get(index) + override def getArg(index: Int): Val = getArgs.get(index) - override def getArgs: util.List[Val] = { - val result = new util.ArrayList[Val] + override def getArgs: util.List[Val] = { + val result = new util.ArrayList[Val] - delegate.params.foreach(param => { - result.add(new OpalLocal(param.asVar, method)) - }) + delegate.params.foreach(param => { + result.add(new OpalLocal(param.asVar, method)) + }) - result - } - - override def isInstanceInvokeExpr: Boolean = - delegate.isInstanceOf[InstanceFunctionCall[_]] + result + } - override def getBase: Val = { - if (isInstanceInvokeExpr) { - return new OpalLocal( - delegate.asInstanceFunctionCall.receiver.asVar, - method - ) - } + override def isInstanceInvokeExpr: Boolean = + delegate.isInstanceOf[InstanceFunctionCall[_]] - throw new RuntimeException( - "Function call is not an instance invoke expression" - ) + override def getBase: Val = { + if (isInstanceInvokeExpr) { + return new OpalLocal( + delegate.asInstanceFunctionCall.receiver.asVar, + method + ) } - override def getDeclaredMethod: DeclaredMethod = - OpalDeclaredMethod(this, delegate) + throw new RuntimeException( + "Function call is not an instance invoke expression" + ) + } - override def isSpecialInvokeExpr: Boolean = - delegate.astID == NonVirtualFunctionCall.ASTID + override def getDeclaredMethod: DeclaredMethod = + OpalDeclaredMethod(this, delegate) - override def isStaticInvokeExpr: Boolean = delegate.isStaticFunctionCall + override def isSpecialInvokeExpr: Boolean = + delegate.astID == NonVirtualFunctionCall.ASTID - override def hashCode: Int = Objects.hash(delegate) + override def isStaticInvokeExpr: Boolean = delegate.isStaticFunctionCall - private def canEqual(a: Any): Boolean = a.isInstanceOf[OpalFunctionInvokeExpr] + override def hashCode: Int = Objects.hash(delegate) - override def equals(obj: Any): Boolean = obj match { - case other: OpalFunctionInvokeExpr => - other.canEqual(this) && this.delegate == other.delegate - case _ => false - } + private def canEqual(a: Any): Boolean = a.isInstanceOf[OpalFunctionInvokeExpr] + + override def equals(obj: Any): Boolean = obj match { + case other: OpalFunctionInvokeExpr => + other.canEqual(this) && this.delegate == other.delegate + case _ => false + } - override def toString: String = delegate.toString + override def toString: String = delegate.toString } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalLocal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalLocal.scala index a5a61992d..4b3d2abcb 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalLocal.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalLocal.scala @@ -26,117 +26,117 @@ class OpalLocal( unbalanced: ControlFlowGraph.Edge = null ) extends Val(method, unbalanced) { - override def getType: Type = { - val value = delegate.asVar.valueInformation + override def getType: Type = { + val value = delegate.asVar.valueInformation - if (value.isPrimitiveValue) { - return OpalType(value.asPrimitiveValue.primitiveType) - } - - if (value.isReferenceValue) { - if (value.asReferenceValue.isPrecise) { - if (value.asReferenceValue.isNull.isYes) { - return OpalNullType - } else { - return OpalType(value.asReferenceValue.asReferenceType) - } - } else { - return OpalType(value.asReferenceValue.upperTypeBound.head) - } - } + if (value.isPrimitiveValue) { + return OpalType(value.asPrimitiveValue.primitiveType) + } - if (value.isVoid) { - return OpalType(ObjectType.Void) + if (value.isReferenceValue) { + if (value.asReferenceValue.isPrecise) { + if (value.asReferenceValue.isNull.isYes) { + return OpalNullType + } else { + return OpalType(value.asReferenceValue.asReferenceType) } + } else { + return OpalType(value.asReferenceValue.upperTypeBound.head) + } + } - // TODO Array and illegal types - throw new RuntimeException("Type not implemented yet") + if (value.isVoid) { + return OpalType(ObjectType.Void) } - override def isStatic: Boolean = false + // TODO Array and illegal types (not sure if they ever occur) + throw new RuntimeException("Type not implemented yet") + } - override def isNewExpr: Boolean = false + override def isStatic: Boolean = false - override def getNewExprType: Type = throw new RuntimeException( - "Opal local is not a new expression" - ) + override def isNewExpr: Boolean = false - override def asUnbalanced(stmt: ControlFlowGraph.Edge): Val = - new OpalLocal(delegate, method, stmt) + override def getNewExprType: Type = throw new RuntimeException( + "Opal local is not a new expression" + ) - override def isLocal: Boolean = true + override def asUnbalanced(stmt: ControlFlowGraph.Edge): Val = + new OpalLocal(delegate, method, stmt) - override def isArrayAllocationVal: Boolean = false + override def isLocal: Boolean = true - override def getArrayAllocationSize: Val = throw new RuntimeException( - "Opal local is not an array allocation expression" - ) + override def isArrayAllocationVal: Boolean = false - override def isNull: Boolean = false + override def getArrayAllocationSize: Val = throw new RuntimeException( + "Opal local is not an array allocation expression" + ) - override def isStringConstant: Boolean = false + override def isNull: Boolean = false - override def getStringValue: String = throw new RuntimeException( - "Opal local is not a String constant" - ) + override def isStringConstant: Boolean = false - override def isStringBufferOrBuilder: Boolean = false + override def getStringValue: String = throw new RuntimeException( + "Opal local is not a String constant" + ) - override def isThrowableAllocationType: Boolean = false + override def isStringBufferOrBuilder: Boolean = false - override def isCast: Boolean = false + override def isThrowableAllocationType: Boolean = false - override def getCastOp: Val = throw new RuntimeException( - "Opal local is not a cast operation" - ) + override def isCast: Boolean = false - override def isArrayRef: Boolean = false + override def getCastOp: Val = throw new RuntimeException( + "Opal local is not a cast operation" + ) - override def isInstanceOfExpr: Boolean = false + override def isArrayRef: Boolean = false - override def getInstanceOfOp: Val = throw new RuntimeException( - "Opal local is not an instance of operation" - ) + override def isInstanceOfExpr: Boolean = false - override def isLengthExpr: Boolean = false + override def getInstanceOfOp: Val = throw new RuntimeException( + "Opal local is not an instance of operation" + ) - override def getLengthOp: Val = throw new RuntimeException( - "Opal local is not a length operation" - ) + override def isLengthExpr: Boolean = false - override def isIntConstant: Boolean = false + override def getLengthOp: Val = throw new RuntimeException( + "Opal local is not a length operation" + ) - override def isClassConstant: Boolean = false + override def isIntConstant: Boolean = false - override def getClassConstantType: Type = throw new RuntimeException( - "Opal local is not a class constant" - ) + override def isClassConstant: Boolean = false - override def withNewMethod(callee: Method): Val = - new OpalLocal(delegate, callee.asInstanceOf[OpalMethod]) + override def getClassConstantType: Type = throw new RuntimeException( + "Opal local is not a class constant" + ) - override def isLongConstant: Boolean = false + override def withNewMethod(callee: Method): Val = + new OpalLocal(delegate, callee.asInstanceOf[OpalMethod]) - override def getIntValue: Int = throw new RuntimeException( - "Opal local is not an int constant" - ) + override def isLongConstant: Boolean = false - override def getLongValue: Long = throw new RuntimeException( - "Opal local is not a long constant" - ) + override def getIntValue: Int = throw new RuntimeException( + "Opal local is not an int constant" + ) - override def getArrayBase: Pair[Val, Integer] = throw new RuntimeException( - "Opal local is not array reference" - ) + override def getLongValue: Long = throw new RuntimeException( + "Opal local is not a long constant" + ) - override def getVariableName: String = delegate.asVar.name + override def getArrayBase: Pair[Val, Integer] = throw new RuntimeException( + "Opal local is not array reference" + ) - override def hashCode: Int = Objects.hash(delegate.asVar) + override def getVariableName: String = delegate.asVar.name - override def equals(other: Any): Boolean = other match { - case that: OpalLocal => super.equals(that) && this.delegate == that.delegate - case _ => false - } + override def hashCode: Int = Objects.hash(delegate.asVar) + + override def equals(other: Any): Boolean = other match { + case that: OpalLocal => super.equals(that) && this.delegate == that.delegate + case _ => false + } - override def toString: String = getVariableName + override def toString: String = getVariableName } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalMethod.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalMethod.scala index 2a1c44948..ff9675c5c 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalMethod.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalMethod.scala @@ -26,124 +26,124 @@ class OpalMethod private ( val tac: BoomerangTACode ) extends Method { - if (delegate.body.isEmpty) { - throw new RuntimeException("Cannot build OpalMethod without existing body") - } + if (delegate.body.isEmpty) { + throw new RuntimeException("Cannot build OpalMethod without existing body") + } - private val cfg = new OpalControlFlowGraph(this) + private val cfg = new OpalControlFlowGraph(this) - private var localCache: Option[util.Set[Val]] = None - private var parameterLocalCache: Option[util.List[Val]] = None + private var localCache: Option[util.Set[Val]] = None + private var parameterLocalCache: Option[util.List[Val]] = None - override def isStaticInitializer: Boolean = delegate.isStaticInitializer + override def isStaticInitializer: Boolean = delegate.isStaticInitializer - override def isParameterLocal(value: Val): Boolean = - getParameterLocals.contains(value) + override def isParameterLocal(value: Val): Boolean = + getParameterLocals.contains(value) - override def getParameterTypes: util.List[Type] = { - val result = new util.ArrayList[Type]() + override def getParameterTypes: util.List[Type] = { + val result = new util.ArrayList[Type]() - delegate.parameterTypes.foreach(paramType => { - result.add(OpalType(paramType)) - }) + delegate.parameterTypes.foreach(paramType => { + result.add(OpalType(paramType)) + }) - result - } + result + } - override def getParameterType(index: Int): Type = getParameterTypes.get(index) + override def getParameterType(index: Int): Type = getParameterTypes.get(index) - override def getReturnType: Type = OpalType(delegate.descriptor.returnType) + override def getReturnType: Type = OpalType(delegate.descriptor.returnType) - override def isThisLocal(fact: Val): Boolean = { - if (isStatic) return false - if (fact.isStatic) return false + override def isThisLocal(fact: Val): Boolean = { + if (isStatic) return false + if (fact.isStatic) return false - val thisLocal = getThisLocal - thisLocal.equals(fact) - } + val thisLocal = getThisLocal + thisLocal.equals(fact) + } - override def getThisLocal: Val = { - if (!isStatic) { - tac.statements.foreach(stmt => { - if (stmt.pc == -1) { - val targetVar = stmt.asAssignment.targetVar - - if (targetVar.id == -1) { - return new OpalLocal(targetVar, this) - } - } - }) - - throw new RuntimeException( - "Could not determine 'this' local in method " + delegate.name - ) + override def getThisLocal: Val = { + if (!isStatic) { + tac.statements.foreach(stmt => { + if (stmt.pc == -1) { + val targetVar = stmt.asAssignment.targetVar + + if (targetVar.id == -1) { + return new OpalLocal(targetVar, this) + } } + }) - throw new RuntimeException("Static method does not have a 'this' local") + throw new RuntimeException( + "Could not determine 'this' local in method " + delegate.name + ) } - override def getLocals: util.Set[Val] = { - if (localCache.isEmpty) { - localCache = Some(new util.HashSet[Val]()) + throw new RuntimeException("Static method does not have a 'this' local") + } - tac.getLocals.foreach(l => localCache.get.add(new OpalLocal(l, this))) - } + override def getLocals: util.Set[Val] = { + if (localCache.isEmpty) { + localCache = Some(new util.HashSet[Val]()) - localCache.get + tac.getLocals.foreach(l => localCache.get.add(new OpalLocal(l, this))) } - override def getParameterLocals: util.List[Val] = { - if (parameterLocalCache.isEmpty) { - parameterLocalCache = Some(new util.ArrayList[Val]()) - - tac.getParameterLocals.foreach(l => { - // Exclude the 'this' local from the parameters if this is an instance method - if (isStatic) { - parameterLocalCache.get.add(new OpalLocal(l, this)) - } else if (l.id != -1) { - parameterLocalCache.get.add(new OpalLocal(l, this)) - } - }) - } + localCache.get + } + + override def getParameterLocals: util.List[Val] = { + if (parameterLocalCache.isEmpty) { + parameterLocalCache = Some(new util.ArrayList[Val]()) - parameterLocalCache.get + tac.getParameterLocals.foreach(l => { + // Exclude the 'this' local from the parameters if this is an instance method + if (isStatic) { + parameterLocalCache.get.add(new OpalLocal(l, this)) + } else if (l.id != -1) { + parameterLocalCache.get.add(new OpalLocal(l, this)) + } + }) } - override def isStatic: Boolean = delegate.isStatic + parameterLocalCache.get + } - override def isDefined: Boolean = true + override def isStatic: Boolean = delegate.isStatic - override def isPhantom: Boolean = false + override def isDefined: Boolean = true - override def getStatements: util.List[Statement] = cfg.getStatements + override def isPhantom: Boolean = false - override def getDeclaringClass: WrappedClass = OpalWrappedClass( - delegate.classFile - ) + override def getStatements: util.List[Statement] = cfg.getStatements - override def getControlFlowGraph: ControlFlowGraph = cfg.get() + override def getDeclaringClass: WrappedClass = OpalWrappedClass( + delegate.classFile + ) - override def getSubSignature: String = delegate.signature.toJava + override def getControlFlowGraph: ControlFlowGraph = cfg.get() - override def getName: String = delegate.name + override def getSubSignature: String = delegate.signature.toJava - override def isConstructor: Boolean = delegate.isConstructor + override def getName: String = delegate.name - override def hashCode: Int = Objects.hash(delegate) + override def isConstructor: Boolean = delegate.isConstructor - override def equals(other: Any): Boolean = other match { - case that: OpalMethod => this.delegate == that.delegate - case _ => false - } + override def hashCode: Int = Objects.hash(delegate) + + override def equals(other: Any): Boolean = other match { + case that: OpalMethod => this.delegate == that.delegate + case _ => false + } - override def toString: String = delegate.toJava + override def toString: String = delegate.toJava } object OpalMethod { - def apply(delegate: org.opalj.br.Method): OpalMethod = - new OpalMethod(delegate, TacBodyBuilder(OpalClient.project.get, delegate)) + def apply(delegate: org.opalj.br.Method): OpalMethod = + new OpalMethod(delegate, TacBodyBuilder(OpalClient.project.get, delegate)) - def apply(delegate: org.opalj.br.Method, tac: BoomerangTACode): OpalMethod = - new OpalMethod(delegate, tac) + def apply(delegate: org.opalj.br.Method, tac: BoomerangTACode): OpalMethod = + new OpalMethod(delegate, tac) } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalNullType.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalNullType.scala index 78c9f5143..497afae8b 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalNullType.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalNullType.scala @@ -20,25 +20,25 @@ import boomerang.scope.WrappedClass object OpalNullType extends Type { - override def isNullType: Boolean = true + override def isNullType: Boolean = true - override def isRefType: Boolean = false + override def isRefType: Boolean = false - override def isArrayType: Boolean = false + override def isArrayType: Boolean = false - override def getArrayBaseType: Type = throw new RuntimeException( - "Null type has no array base type" - ) + override def getArrayBaseType: Type = throw new RuntimeException( + "Null type has no array base type" + ) - override def getWrappedClass: WrappedClass = throw new RuntimeException( - "Null type has no declaring class" - ) + override def getWrappedClass: WrappedClass = throw new RuntimeException( + "Null type has no declaring class" + ) - override def doesCastFail(targetVal: Type, target: Val): Boolean = true + override def doesCastFail(targetVal: Type, target: Val): Boolean = true - override def isSubtypeOf(superType: String): Boolean = false + override def isSubtypeOf(superType: String): Boolean = false - override def isSupertypeOf(subType: String): Boolean = false + override def isSupertypeOf(subType: String): Boolean = false - override def isBooleanType: Boolean = false + override def isBooleanType: Boolean = false } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalPhantomMethod.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalPhantomMethod.scala index fb381d3d4..39606f1f5 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalPhantomMethod.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalPhantomMethod.scala @@ -34,65 +34,64 @@ case class OpalPhantomMethod( static: Boolean ) extends Method { - override def isStaticInitializer: Boolean = - name == OpalFrameworkScope.STATIC_INITIALIZER + override def isStaticInitializer: Boolean = + name == OpalFrameworkScope.STATIC_INITIALIZER - override def isParameterLocal(value: Val): Boolean = false + override def isParameterLocal(value: Val): Boolean = false - override def getParameterTypes: util.List[Type] = { - val result = new util.ArrayList[Type]() + override def getParameterTypes: util.List[Type] = { + val result = new util.ArrayList[Type]() - descriptor.parameterTypes.foreach(paramType => { - result.add(OpalType(paramType)) - }) + descriptor.parameterTypes.foreach(paramType => { + result.add(OpalType(paramType)) + }) - result - } + result + } - override def getParameterType(index: Int): Type = OpalType( - descriptor.parameterType(index) - ) + override def getParameterType(index: Int): Type = OpalType( + descriptor.parameterType(index) + ) - override def getReturnType: Type = OpalType(descriptor.returnType) + override def getReturnType: Type = OpalType(descriptor.returnType) - override def isThisLocal(value: Val): Boolean = false + override def isThisLocal(value: Val): Boolean = false - override def getLocals: util.Collection[Val] = throw new RuntimeException( - "Locals of phantom method are not available" - ) + override def getLocals: util.Collection[Val] = throw new RuntimeException( + "Locals of phantom method are not available" + ) - override def getThisLocal: Val = throw new RuntimeException( - "this local of phantom method is not available" - ) + override def getThisLocal: Val = throw new RuntimeException( + "this local of phantom method is not available" + ) - override def getParameterLocals: util.List[Val] = throw new RuntimeException( - "Parameter locals of phantom method are not available" - ) + override def getParameterLocals: util.List[Val] = throw new RuntimeException( + "Parameter locals of phantom method are not available" + ) - override def isStatic: Boolean = static + override def isStatic: Boolean = static - override def isDefined: Boolean = false + override def isDefined: Boolean = false - override def isPhantom: Boolean = true + override def isPhantom: Boolean = true - override def getStatements: util.List[Statement] = throw new RuntimeException( - "Statements of phantom method are not available" - ) + override def getStatements: util.List[Statement] = throw new RuntimeException( + "Statements of phantom method are not available" + ) - // TODO - override def getDeclaringClass: WrappedClass = OpalPhantomWrappedClass( - declaringClassType - ) + override def getDeclaringClass: WrappedClass = OpalPhantomWrappedClass( + declaringClassType + ) - override def getControlFlowGraph: ControlFlowGraph = - throw new RuntimeException("CFG of phantom method is not available") + override def getControlFlowGraph: ControlFlowGraph = + throw new RuntimeException("CFG of phantom method is not available") - override def getSubSignature: String = - MethodSignature(name, descriptor).toJava + override def getSubSignature: String = + MethodSignature(name, descriptor).toJava - override def getName: String = name + override def getName: String = name - override def isConstructor: Boolean = name == OpalFrameworkScope.CONSTRUCTOR + override def isConstructor: Boolean = name == OpalFrameworkScope.CONSTRUCTOR - override def toString: String = s"PHANTOM: ${descriptor.toJava}" + override def toString: String = s"PHANTOM: ${descriptor.toJava}" } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalPhantomWrappedClass.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalPhantomWrappedClass.scala index 47aa37612..e98b89171 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalPhantomWrappedClass.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalPhantomWrappedClass.scala @@ -22,23 +22,23 @@ import org.opalj.br.ReferenceType case class OpalPhantomWrappedClass(delegate: ReferenceType) extends WrappedClass { - override def getMethods: util.Set[Method] = throw new RuntimeException( - "Methods of class " + delegate.toString + " are not available" - ) + override def getMethods: util.Set[Method] = throw new RuntimeException( + "Methods of class " + delegate.toString + " are not available" + ) - override def hasSuperclass: Boolean = false + override def hasSuperclass: Boolean = false - override def getSuperclass: WrappedClass = throw new RuntimeException( - "Super class of " + delegate.toString + " is not available" - ) + override def getSuperclass: WrappedClass = throw new RuntimeException( + "Super class of " + delegate.toString + " is not available" + ) - override def getType: Type = OpalType(delegate) + override def getType: Type = OpalType(delegate) - override def isApplicationClass: Boolean = false + override def isApplicationClass: Boolean = false - override def getFullyQualifiedName: String = delegate.toJava + override def getFullyQualifiedName: String = delegate.toJava - override def isPhantom: Boolean = true + override def isPhantom: Boolean = true - override def toString: String = delegate.toString + override def toString: String = delegate.toString } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala index fdb3498c2..ebff53ab8 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatement.scala @@ -23,427 +23,431 @@ import org.opalj.tac.Stmt class OpalStatement(val delegate: Stmt[TacLocal], m: OpalMethod) extends Statement(m) { - override def containsStaticFieldAccess(): Boolean = - isStaticFieldLoad || isStaticFieldStore + override def containsStaticFieldAccess(): Boolean = + isStaticFieldLoad || isStaticFieldStore + + override def containsInvokeExpr(): Boolean = { + if (delegate.isMethodCall) return true + if (delegate.isAssignment && delegate.asAssignment.expr.isFunctionCall) + return true + if (delegate.isExprStmt && delegate.asExprStmt.expr.isFunctionCall) + return true + + false + } + + override def getInvokeExpr: InvokeExpr = { + if (containsInvokeExpr()) { + if (delegate.isMethodCall) { + return new OpalMethodInvokeExpr(delegate.asMethodCall, m) + } + + if (delegate.isAssignment && delegate.asAssignment.expr.isFunctionCall) { + return new OpalFunctionInvokeExpr( + delegate.asAssignment.expr.asFunctionCall, + m + ) + } + + if (delegate.isExprStmt && delegate.asExprStmt.expr.isFunctionCall) { + return new OpalFunctionInvokeExpr( + delegate.asExprStmt.expr.asFunctionCall, + m + ) + } + } - override def containsInvokeExpr(): Boolean = { - if (delegate.isMethodCall) return true - if (delegate.isAssignment && delegate.asAssignment.expr.isFunctionCall) - return true - if (delegate.isExprStmt && delegate.asExprStmt.expr.isFunctionCall) - return true + throw new RuntimeException( + "Statement does not contain an invoke expression" + ) + } + + override def getWrittenField: Field = { + if (isFieldStore) { + val fieldStore = delegate.asPutField - false + return new OpalField( + fieldStore.declaringClass, + fieldStore.declaredFieldType, + fieldStore.name + ) } - override def getInvokeExpr: InvokeExpr = { - if (containsInvokeExpr()) { - if (delegate.isMethodCall) { - return new OpalMethodInvokeExpr(delegate.asMethodCall, m) - } - - if (delegate.isAssignment && delegate.asAssignment.expr.isFunctionCall) { - return new OpalFunctionInvokeExpr( - delegate.asAssignment.expr.asFunctionCall, - m - ) - } - - if (delegate.isExprStmt && delegate.asExprStmt.expr.isFunctionCall) { - return new OpalFunctionInvokeExpr( - delegate.asExprStmt.expr.asFunctionCall, - m - ) - } - } + if (isStaticFieldStore) { + val fieldStore = delegate.asPutStatic - throw new RuntimeException( - "Statement does not contain an invoke expression" - ) + return new OpalField( + fieldStore.declaringClass, + fieldStore.declaredFieldType, + fieldStore.name + ) } - override def getWrittenField: Field = { - if (isFieldStore) { - val fieldStore = delegate.asPutField + if (isArrayStore) { + return Field.array(getArrayBase.getY) + } - return new OpalField( - fieldStore.declaringClass, - fieldStore.declaredFieldType, - fieldStore.name - ) - } + throw new RuntimeException("Statement is not a field store operation") + } - if (isStaticFieldStore) { - val fieldStore = delegate.asPutStatic + override def isFieldWriteWithBase(base: Val): Boolean = { + if (isAssignStmt && isFieldStore) { + return getFieldStore.getX.equals(base) + } - return new OpalField( - fieldStore.declaringClass, - fieldStore.declaredFieldType, - fieldStore.name - ) - } + if (isAssignStmt && isArrayStore) { + return getArrayBase.getX.equals(base) + } - if (isArrayStore) { - return Field.array(getArrayBase.getY) - } + false + } + + override def getLoadedField: Field = { + // TODO + // Also consider arrays? Soot does not consider them, but they + // are considered in field store operations + if (isFieldLoad) { + val fieldLoad = delegate.asAssignment.expr.asGetField + + return new OpalField( + fieldLoad.declaringClass, + fieldLoad.declaredFieldType, + fieldLoad.name + ) + } - throw new RuntimeException("Statement is not a field store operation") + throw new RuntimeException("Statement is not a field load operation") + } + + override def isFieldLoadWithBase(base: Val): Boolean = { + // TODO + // Also consider arrays? Soot does not consider them, but they + // are considered in field store operations + if (isFieldLoad) { + return getFieldLoad.getX.equals(base) } - override def isFieldWriteWithBase(base: Val): Boolean = { - if (isAssignStmt && isFieldStore) { - return getFieldStore.getX.equals(base) - } + false + } + + override def isAssignStmt: Boolean = { + if (isIdentityStmt) return false + if (delegate.isAssignment) return true + + // Store statements are no assignments in Opal + isFieldStore || isArrayStore || isStaticFieldStore + } + + override def getLeftOp: Val = { + if (isAssignStmt) { + if (delegate.isAssignment) { + return new OpalLocal(delegate.asAssignment.targetVar, m) + } + + if (isFieldStore) { + val fieldStore = delegate.asPutField + + return new OpalInstanceFieldRef( + fieldStore.objRef.asVar, + fieldStore.declaredFieldType, + fieldStore.name, + m + ) + } - if (isAssignStmt && isArrayStore) { - return getArrayBase.getX.equals(base) + if (isArrayStore) { + val base = delegate.asArrayStore.arrayRef + val indexValue = delegate.asArrayStore.index + + if (indexValue.isIntConst) { + return new OpalArrayRef(base.asVar, indexValue.asIntConst.value, m) } - false + return new OpalArrayRef(base.asVar, -1, m) + } + + if (isStaticFieldStore) { + val staticFieldStore = delegate.asPutStatic + + return new OpalStaticFieldRef( + staticFieldStore.declaringClass, + staticFieldStore.declaredFieldType, + staticFieldStore.name, + m + ) + } } - override def getLoadedField: Field = { - // TODO Also array? - if (isFieldLoad) { - val fieldLoad = delegate.asAssignment.expr.asGetField + throw new RuntimeException("Statement is not an assignment") + } - return new OpalField( - fieldLoad.declaringClass, - fieldLoad.declaredFieldType, - fieldLoad.name - ) + override def getRightOp: Val = { + if (isAssignStmt) { + if (delegate.isAssignment) { + val rightExpr = delegate.asAssignment.expr + + if (rightExpr.isGetField) { + val getField = rightExpr.asGetField + + return new OpalInstanceFieldRef( + getField.objRef.asVar, + getField.declaredFieldType, + getField.name, + m + ) } - throw new RuntimeException("Statement is not a field load operation") - } + if (rightExpr.isArrayLoad) { + val base = rightExpr.asArrayLoad.arrayRef + val indexValue = rightExpr.asArrayLoad.index - override def isFieldLoadWithBase(base: Val): Boolean = { - // TODO Also array? - if (isFieldLoad) { - return getFieldLoad.getX.equals(base) + if (indexValue.isIntConst) { + return new OpalArrayRef(base.asVar, indexValue.asIntConst.value, m) + } + + return new OpalArrayRef(base.asVar, -1, m) } - false - } + if (rightExpr.isGetStatic) { + val staticFieldLoad = rightExpr.asGetStatic - override def isAssignStmt: Boolean = { - if (isIdentityStmt) return false - if (delegate.isAssignment) return true + return new OpalStaticFieldRef( + staticFieldLoad.declaringClass, + staticFieldLoad.declaredFieldType, + staticFieldLoad.name, + m + ) + } - // Store statements are no assignments in Opal - isFieldStore || isArrayStore || isStaticFieldStore - } + if (rightExpr.isVar) { + return new OpalLocal(rightExpr.asVar, m) + } + + return new OpalVal(delegate.asAssignment.expr, m) + } - override def getLeftOp: Val = { - if (isAssignStmt) { - if (delegate.isAssignment) { - return new OpalLocal(delegate.asAssignment.targetVar, m) - } - - if (isFieldStore) { - val fieldStore = delegate.asPutField - - return new OpalInstanceFieldRef( - fieldStore.objRef.asVar, - fieldStore.declaredFieldType, - fieldStore.name, - m - ) - } - - if (isArrayStore) { - val base = delegate.asArrayStore.arrayRef - val indexValue = delegate.asArrayStore.index - - if (indexValue.isIntConst) { - return new OpalArrayRef(base.asVar, indexValue.asIntConst.value, m) - } - - return new OpalArrayRef(base.asVar, -1, m) - } - - if (isStaticFieldStore) { - val staticFieldStore = delegate.asPutStatic - - return new OpalStaticFieldRef( - staticFieldStore.declaringClass, - staticFieldStore.declaredFieldType, - staticFieldStore.name, - m - ) - } + if (isFieldStore) { + val fieldStore = delegate.asPutField + + if (fieldStore.value.isVar) { + return new OpalLocal(fieldStore.value.asVar, m) + } else { + return new OpalVal(fieldStore.value, m) } + } - throw new RuntimeException("Statement is not an assignment") - } + if (isArrayStore) { + val arrayStore = delegate.asArrayStore - override def getRightOp: Val = { - if (isAssignStmt) { - if (delegate.isAssignment) { - val rightExpr = delegate.asAssignment.expr - - if (rightExpr.isGetField) { - val getField = rightExpr.asGetField - - return new OpalInstanceFieldRef( - getField.objRef.asVar, - getField.declaredFieldType, - getField.name, - m - ) - } - - if (rightExpr.isArrayLoad) { - val base = rightExpr.asArrayLoad.arrayRef - val indexValue = rightExpr.asArrayLoad.index - - if (indexValue.isIntConst) { - return new OpalArrayRef(base.asVar, indexValue.asIntConst.value, m) - } - - return new OpalArrayRef(base.asVar, -1, m) - } - - if (rightExpr.isGetStatic) { - val staticFieldLoad = rightExpr.asGetStatic - - return new OpalStaticFieldRef( - staticFieldLoad.declaringClass, - staticFieldLoad.declaredFieldType, - staticFieldLoad.name, - m - ) - } - - if (rightExpr.isVar) { - return new OpalLocal(rightExpr.asVar, m) - } - - return new OpalVal(delegate.asAssignment.expr, m) - } - - if (isFieldStore) { - val fieldStore = delegate.asPutField - - if (fieldStore.value.isVar) { - return new OpalLocal(fieldStore.value.asVar, m) - } else { - return new OpalVal(fieldStore.value, m) - } - } - - if (isArrayStore) { - val arrayStore = delegate.asArrayStore - - if (arrayStore.value.isVar) { - return new OpalLocal(arrayStore.value.asVar, m) - } else { - return new OpalVal(arrayStore.value, m) - } - } - - if (isStaticFieldStore) { - val staticFieldStore = delegate.asPutStatic - - if (staticFieldStore.value.isVar) { - return new OpalLocal(staticFieldStore.value.asVar, m) - } else { - return new OpalVal(staticFieldStore.value, m) - } - } + if (arrayStore.value.isVar) { + return new OpalLocal(arrayStore.value.asVar, m) + } else { + return new OpalVal(arrayStore.value, m) } + } - throw new RuntimeException("Statement is not an assignment") + if (isStaticFieldStore) { + val staticFieldStore = delegate.asPutStatic + + if (staticFieldStore.value.isVar) { + return new OpalLocal(staticFieldStore.value.asVar, m) + } else { + return new OpalVal(staticFieldStore.value, m) + } + } } - override def isInstanceOfStatement(fact: Val): Boolean = { - if (delegate.isAssignment) { - if (getRightOp.isInstanceOfExpr) { - val insOf = getRightOp.getInstanceOfOp + throw new RuntimeException("Statement is not an assignment") + } - return insOf.equals(fact) - } - } + override def isInstanceOfStatement(fact: Val): Boolean = { + if (delegate.isAssignment) { + if (getRightOp.isInstanceOfExpr) { + val insOf = getRightOp.getInstanceOfOp - false + return insOf.equals(fact) + } } - override def isCast: Boolean = { - // Primitive type casts - if (delegate.isAssignment) { - val assignExpr = delegate.asAssignment.expr + false + } - if (assignExpr.astID == PrimitiveTypecastExpr.ASTID) { - return true - } - } + override def isCast: Boolean = { + // Primitive type casts + if (delegate.isAssignment) { + val assignExpr = delegate.asAssignment.expr - // Class casts - delegate.isCheckcast + if (assignExpr.astID == PrimitiveTypecastExpr.ASTID) { + return true + } } - override def isPhiStatement: Boolean = false + // Class casts + delegate.isCheckcast + } - override def isReturnStmt: Boolean = delegate.isReturnValue + override def isPhiStatement: Boolean = false - override def isThrowStmt: Boolean = delegate.isThrow + override def isReturnStmt: Boolean = delegate.isReturnValue - override def isIfStmt: Boolean = delegate.isIf + override def isThrowStmt: Boolean = delegate.isThrow - override def getIfStmt: IfStatement = { - if (isIfStmt) { - return new OpalIfStatement(delegate.asIf, m) - } + override def isIfStmt: Boolean = delegate.isIf - throw new RuntimeException("Statement is not an if-statement") + override def getIfStmt: IfStatement = { + if (isIfStmt) { + return new OpalIfStatement(delegate.asIf, m) } - override def getReturnOp: Val = { - if (isReturnStmt) { - return new OpalLocal(delegate.asReturnValue.expr.asVar, m) - } + throw new RuntimeException("Statement is not an if-statement") + } - throw new RuntimeException("Statement is not a return statement") + override def getReturnOp: Val = { + if (isReturnStmt) { + return new OpalLocal(delegate.asReturnValue.expr.asVar, m) } - override def isMultiArrayAllocation: Boolean = false + throw new RuntimeException("Statement is not a return statement") + } - override def isFieldStore: Boolean = delegate.isPutField + override def isMultiArrayAllocation: Boolean = false - override def isArrayStore: Boolean = delegate.isArrayStore + override def isFieldStore: Boolean = delegate.isPutField - override def isArrayLoad: Boolean = - delegate.isAssignment && delegate.asAssignment.expr.isArrayLoad + override def isArrayStore: Boolean = delegate.isArrayStore - override def isFieldLoad: Boolean = - delegate.isAssignment && delegate.asAssignment.expr.isGetField + override def isArrayLoad: Boolean = + delegate.isAssignment && delegate.asAssignment.expr.isArrayLoad - override def isIdentityStmt: Boolean = { - if (delegate.isAssignment) { - /* Difference between Soot and Opal: - * - Soot considers parameter definitions and self assignments of the this local as identity statements (no assignments) - * - Opal considers these statements as basic assignments, so we have to exclude them manually - */ - val targetVar = delegate.asAssignment.targetVar - val expr = delegate.asAssignment.expr + override def isFieldLoad: Boolean = + delegate.isAssignment && delegate.asAssignment.expr.isGetField - if (expr.isVar) { - if (expr.asVar.isParameterLocal) return true - if (expr.asVar.isExceptionLocal) return true - if (targetVar.isThisLocal && expr.asVar.isThisLocal) return true - } - } + override def isIdentityStmt: Boolean = { + if (delegate.isAssignment) { + /* Difference between Soot and Opal: + * - Soot considers parameter definitions and self assignments of the this local as identity statements (no assignments) + * - Opal considers these statements as basic assignments, so we have to exclude them manually + */ + val targetVar = delegate.asAssignment.targetVar + val expr = delegate.asAssignment.expr - false + if (expr.isVar) { + if (expr.asVar.isParameterLocal) return true + if (expr.asVar.isExceptionLocal) return true + if (targetVar.isThisLocal && expr.asVar.isThisLocal) return true + } } - override def getFieldStore: Pair[Val, Field] = { - if (isFieldStore) { - val fieldStore = delegate.asPutField + false + } - val local = new OpalLocal(fieldStore.objRef.asVar, m) - val field = new OpalField( - fieldStore.declaringClass, - fieldStore.declaredFieldType, - fieldStore.name - ) + override def getFieldStore: Pair[Val, Field] = { + if (isFieldStore) { + val fieldStore = delegate.asPutField - return new Pair(local, field) - } + val local = new OpalLocal(fieldStore.objRef.asVar, m) + val field = new OpalField( + fieldStore.declaringClass, + fieldStore.declaredFieldType, + fieldStore.name + ) - throw new RuntimeException("Statement is not a field store operation") + return new Pair(local, field) } - override def getFieldLoad: Pair[Val, Field] = { - if (isFieldLoad) { - val fieldLoad = delegate.asAssignment.expr.asGetField + throw new RuntimeException("Statement is not a field store operation") + } - val local = new OpalLocal(fieldLoad.objRef.asVar, m) - val field = new OpalField( - fieldLoad.declaringClass, - fieldLoad.declaredFieldType, - fieldLoad.name - ) + override def getFieldLoad: Pair[Val, Field] = { + if (isFieldLoad) { + val fieldLoad = delegate.asAssignment.expr.asGetField - return new Pair(local, field) - } + val local = new OpalLocal(fieldLoad.objRef.asVar, m) + val field = new OpalField( + fieldLoad.declaringClass, + fieldLoad.declaredFieldType, + fieldLoad.name + ) - throw new RuntimeException("Statement is not a field load operation") + return new Pair(local, field) } - override def isStaticFieldLoad: Boolean = - delegate.isAssignment && delegate.asAssignment.expr.isGetStatic + throw new RuntimeException("Statement is not a field load operation") + } - override def isStaticFieldStore: Boolean = delegate.isPutStatic + override def isStaticFieldLoad: Boolean = + delegate.isAssignment && delegate.asAssignment.expr.isGetStatic - override def getStaticField: StaticFieldVal = { - if (isStaticFieldLoad) { - val staticFieldLoad = delegate.asAssignment.expr.asGetStatic + override def isStaticFieldStore: Boolean = delegate.isPutStatic - val staticField = new OpalField( - staticFieldLoad.declaringClass, - staticFieldLoad.declaredFieldType, - staticFieldLoad.name - ) - return new OpalStaticFieldVal(staticField, m) - } + override def getStaticField: StaticFieldVal = { + if (isStaticFieldLoad) { + val staticFieldLoad = delegate.asAssignment.expr.asGetStatic - if (isStaticFieldStore) { - val staticFieldStore = delegate.asPutStatic + val staticField = new OpalField( + staticFieldLoad.declaringClass, + staticFieldLoad.declaredFieldType, + staticFieldLoad.name + ) + return new OpalStaticFieldVal(staticField, m) + } - val staticField = new OpalField( - staticFieldStore.declaringClass, - staticFieldStore.declaredFieldType, - staticFieldStore.name - ) - return new OpalStaticFieldVal(staticField, m) - } + if (isStaticFieldStore) { + val staticFieldStore = delegate.asPutStatic - throw new RuntimeException( - "Statement is neither a static field load nor store operation" - ) + val staticField = new OpalField( + staticFieldStore.declaringClass, + staticFieldStore.declaredFieldType, + staticFieldStore.name + ) + return new OpalStaticFieldVal(staticField, m) } - override def killAtIfStmt(fact: Val, successor: Statement): Boolean = false - - override def getPhiVals: util.Collection[Val] = throw new RuntimeException( - "Not supported" + throw new RuntimeException( + "Statement is neither a static field load nor store operation" ) + } - override def getArrayBase: Pair[Val, Integer] = { - if (isArrayLoad) { - val rightOp = getRightOp - return rightOp.getArrayBase - } + override def killAtIfStmt(fact: Val, successor: Statement): Boolean = false - if (isArrayStore) { - val leftOp = getLeftOp - return leftOp.getArrayBase - } + override def getPhiVals: util.Collection[Val] = throw new RuntimeException( + "Not supported" + ) - throw new RuntimeException( - "Statement is not an array load or array store operation" - ) + override def getArrayBase: Pair[Val, Integer] = { + if (isArrayLoad) { + val rightOp = getRightOp + return rightOp.getArrayBase } - override def getStartLineNumber: Int = - m.delegate.body.get.lineNumber(delegate.pc).getOrElse(-1) + if (isArrayStore) { + val leftOp = getLeftOp + return leftOp.getArrayBase + } - override def getStartColumnNumber: Int = -1 + throw new RuntimeException( + "Statement is not an array load or array store operation" + ) + } - override def getEndLineNumber: Int = -1 + override def getStartLineNumber: Int = + m.delegate.body.get.lineNumber(delegate.pc).getOrElse(-1) - override def getEndColumnNumber: Int = -1 + override def getStartColumnNumber: Int = -1 - override def isCatchStmt: Boolean = delegate.isCaughtException + override def getEndLineNumber: Int = -1 - override def hashCode: Int = Objects.hash(delegate, m) + override def getEndColumnNumber: Int = -1 - override def equals(other: Any): Boolean = other match { - case that: OpalStatement => - this.delegate == that.delegate && this.method == that.method - case _ => false - } + override def isCatchStmt: Boolean = delegate.isCaughtException + + override def hashCode: Int = Objects.hash(delegate, m) + + override def equals(other: Any): Boolean = other match { + case that: OpalStatement => + this.delegate == that.delegate && this.method == that.method + case _ => false + } - override def toString: String = OpalStatementFormatter(this) + override def toString: String = OpalStatementFormatter(this) } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatementFormatter.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatementFormatter.scala index 28bb294f4..66f247643 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatementFormatter.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStatementFormatter.scala @@ -22,68 +22,68 @@ import org.opalj.tac.Return object OpalStatementFormatter { - def apply(stmt: OpalStatement): String = { - val delegate = stmt.delegate - - if (stmt.containsInvokeExpr()) { - var base = "" - if (stmt.getInvokeExpr.isInstanceInvokeExpr) { - base = s"${stmt.getInvokeExpr.getBase}." - } - var assign = "" - if (stmt.isAssignStmt) { - assign = s"${stmt.getLeftOp} = " - } - - return s"$assign$base${stmt.getInvokeExpr.getDeclaredMethod.getName}(${Joiner.on(",").join(stmt.getInvokeExpr.getArgs)})" - } - - if (stmt.isAssignStmt) { - if (delegate.isAssignment) { - return s"${stmt.getLeftOp} = ${stmt.getRightOp}" - } - - if (stmt.isFieldStore) { - return s"${stmt.getLeftOp} = ${stmt.getRightOp}" - } - - if (stmt.isArrayStore) { - val base = stmt.getArrayBase - return s"${base.getX.getVariableName}[${base.getY}] = ${stmt.getRightOp}" - } - - if (stmt.isStaticFieldStore) { - return s"${stmt.getLeftOp} = ${stmt.getRightOp}" - } - } - - if (delegate.isAssignment) { - if (delegate.asAssignment.expr.isVar && delegate.asAssignment.expr.asVar.isParameterLocal) { - return s"${delegate.asAssignment.targetVar} := @${delegate.asAssignment.expr}: ${stmt.getMethod}" - } - - if (delegate.asAssignment.expr.isVar && delegate.asAssignment.expr.asVar.isExceptionLocal) { - return s"${delegate.asAssignment.targetVar} := @caughtException: ${delegate.asAssignment.expr}" - } - } - - if (delegate.astID == PutField.ASTID) { - return s"${stmt.getLeftOp} = ${stmt.getRightOp}" - } - - if (delegate.astID == Nop.ASTID) { - return "nop" - } - - if (delegate.astID == Return.ASTID) { - return "return" - } - - if (stmt.isReturnStmt) { - return s"return ${stmt.getReturnOp}" - } - - delegate.toString + def apply(stmt: OpalStatement): String = { + val delegate = stmt.delegate + + if (stmt.containsInvokeExpr()) { + var base = "" + if (stmt.getInvokeExpr.isInstanceInvokeExpr) { + base = s"${stmt.getInvokeExpr.getBase}." + } + var assign = "" + if (stmt.isAssignStmt) { + assign = s"${stmt.getLeftOp} = " + } + + return s"$assign$base${stmt.getInvokeExpr.getDeclaredMethod.getName}(${Joiner.on(",").join(stmt.getInvokeExpr.getArgs)})" } + if (stmt.isAssignStmt) { + if (delegate.isAssignment) { + return s"${stmt.getLeftOp} = ${stmt.getRightOp}" + } + + if (stmt.isFieldStore) { + return s"${stmt.getLeftOp} = ${stmt.getRightOp}" + } + + if (stmt.isArrayStore) { + val base = stmt.getArrayBase + return s"${base.getX.getVariableName}[${base.getY}] = ${stmt.getRightOp}" + } + + if (stmt.isStaticFieldStore) { + return s"${stmt.getLeftOp} = ${stmt.getRightOp}" + } + } + + if (delegate.isAssignment) { + if (delegate.asAssignment.expr.isVar && delegate.asAssignment.expr.asVar.isParameterLocal) { + return s"${delegate.asAssignment.targetVar} := @${delegate.asAssignment.expr}: ${stmt.getMethod}" + } + + if (delegate.asAssignment.expr.isVar && delegate.asAssignment.expr.asVar.isExceptionLocal) { + return s"${delegate.asAssignment.targetVar} := @caughtException: ${delegate.asAssignment.expr}" + } + } + + if (delegate.astID == PutField.ASTID) { + return s"${stmt.getLeftOp} = ${stmt.getRightOp}" + } + + if (delegate.astID == Nop.ASTID) { + return "nop" + } + + if (delegate.astID == Return.ASTID) { + return "return" + } + + if (stmt.isReturnStmt) { + return s"return ${stmt.getReturnOp}" + } + + delegate.toString + } + } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStaticFieldRef.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStaticFieldRef.scala index 3595e1a0f..f355a2dbd 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStaticFieldRef.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStaticFieldRef.scala @@ -30,100 +30,100 @@ class OpalStaticFieldRef( unbalanced: ControlFlowGraph.Edge = null ) extends Val(method, unbalanced) { - override def getType: Type = OpalType(fieldType) + override def getType: Type = OpalType(fieldType) - override def isStatic: Boolean = true + override def isStatic: Boolean = true - override def isNewExpr: Boolean = false + override def isNewExpr: Boolean = false - override def getNewExprType: Type = throw new RuntimeException( - "Static field ref is not a new expression" - ) + override def getNewExprType: Type = throw new RuntimeException( + "Static field ref is not a new expression" + ) - override def asUnbalanced(stmt: ControlFlowGraph.Edge): Val = - new OpalStaticFieldRef(declaringClass, fieldType, fieldName, method, stmt) + override def asUnbalanced(stmt: ControlFlowGraph.Edge): Val = + new OpalStaticFieldRef(declaringClass, fieldType, fieldName, method, stmt) - override def isLocal: Boolean = false + override def isLocal: Boolean = false - override def isArrayAllocationVal: Boolean = false + override def isArrayAllocationVal: Boolean = false - override def getArrayAllocationSize: Val = throw new RuntimeException( - "Static field ref is not an array allocation site" - ) + override def getArrayAllocationSize: Val = throw new RuntimeException( + "Static field ref is not an array allocation site" + ) - override def isNull: Boolean = false + override def isNull: Boolean = false - override def isStringConstant: Boolean = false + override def isStringConstant: Boolean = false - override def getStringValue: String = throw new RuntimeException( - "Static field ref is not a String constant" - ) + override def getStringValue: String = throw new RuntimeException( + "Static field ref is not a String constant" + ) - override def isStringBufferOrBuilder: Boolean = false + override def isStringBufferOrBuilder: Boolean = false - override def isThrowableAllocationType: Boolean = false + override def isThrowableAllocationType: Boolean = false - override def isCast: Boolean = false + override def isCast: Boolean = false - override def getCastOp: Val = throw new RuntimeException( - "Static field ref is not a cast expression" - ) + override def getCastOp: Val = throw new RuntimeException( + "Static field ref is not a cast expression" + ) - override def isArrayRef: Boolean = false + override def isArrayRef: Boolean = false - override def isInstanceOfExpr: Boolean = false + override def isInstanceOfExpr: Boolean = false - override def getInstanceOfOp: Val = throw new RuntimeException( - "Static field ref is not an instanceOf expression" - ) + override def getInstanceOfOp: Val = throw new RuntimeException( + "Static field ref is not an instanceOf expression" + ) - override def isLengthExpr: Boolean = false + override def isLengthExpr: Boolean = false - override def getLengthOp: Val = throw new RuntimeException( - "Static field ref is not a length expression" - ) + override def getLengthOp: Val = throw new RuntimeException( + "Static field ref is not a length expression" + ) - override def isIntConstant: Boolean = false + override def isIntConstant: Boolean = false - override def isClassConstant: Boolean = false + override def isClassConstant: Boolean = false - override def getClassConstantType: Type = throw new RuntimeException( - "Static field ref is not a class constant" - ) + override def getClassConstantType: Type = throw new RuntimeException( + "Static field ref is not a class constant" + ) - override def withNewMethod(callee: Method): Val = new OpalStaticFieldRef( - declaringClass, - fieldType, - fieldName, - callee.asInstanceOf[OpalMethod] - ) + override def withNewMethod(callee: Method): Val = new OpalStaticFieldRef( + declaringClass, + fieldType, + fieldName, + callee.asInstanceOf[OpalMethod] + ) - override def isLongConstant: Boolean = false + override def isLongConstant: Boolean = false - override def getIntValue: Int = throw new RuntimeException( - "Static field ref is not an int constant" - ) + override def getIntValue: Int = throw new RuntimeException( + "Static field ref is not an int constant" + ) - override def getLongValue: Long = throw new RuntimeException( - "Static field ref is not a long constant" - ) + override def getLongValue: Long = throw new RuntimeException( + "Static field ref is not a long constant" + ) - override def getArrayBase: Pair[Val, Integer] = throw new RuntimeException( - "Static field ref has no array base" - ) + override def getArrayBase: Pair[Val, Integer] = throw new RuntimeException( + "Static field ref has no array base" + ) - override def getVariableName: String = fieldName + override def getVariableName: String = fieldName - override def hashCode: Int = - Objects.hash(super.hashCode(), declaringClass, fieldType, fieldName) + override def hashCode: Int = + Objects.hash(super.hashCode(), declaringClass, fieldType, fieldName) - override def equals(other: Any): Boolean = other match { - case that: OpalStaticFieldRef => - super.equals( - that - ) && this.declaringClass == that.declaringClass && this.fieldType == that.fieldType && this.fieldName == that.fieldName - case _ => false - } + override def equals(other: Any): Boolean = other match { + case that: OpalStaticFieldRef => + super.equals( + that + ) && this.declaringClass == that.declaringClass && this.fieldType == that.fieldType && this.fieldName == that.fieldName + case _ => false + } - override def toString: String = s"${declaringClass.toJava}.$fieldName" + override def toString: String = s"${declaringClass.toJava}.$fieldName" } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStaticFieldVal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStaticFieldVal.scala index 7df95733d..59a664414 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStaticFieldVal.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalStaticFieldVal.scala @@ -23,25 +23,25 @@ class OpalStaticFieldVal( unbalanced: ControlFlowGraph.Edge = null ) extends StaticFieldVal(method, unbalanced) { - override def field: Field = field + override def field: Field = field - override def asUnbalanced(stmt: ControlFlowGraph.Edge): Val = - new OpalStaticFieldVal(field, method, stmt) + override def asUnbalanced(stmt: ControlFlowGraph.Edge): Val = + new OpalStaticFieldVal(field, method, stmt) - override def getType: Type = OpalType(field.fieldType) + override def getType: Type = OpalType(field.fieldType) - override def withNewMethod(callee: Method): Val = - new OpalStaticFieldVal(field, callee) + override def withNewMethod(callee: Method): Val = + new OpalStaticFieldVal(field, callee) - override def getVariableName: String = field.toString + override def getVariableName: String = field.toString - override def hashCode: Int = Objects.hash(super.hashCode(), field) + override def hashCode: Int = Objects.hash(super.hashCode(), field) - override def equals(other: Any): Boolean = other match { - case that: OpalStaticFieldVal => - super.equals(that) && this.field.equals(that.field) - case _ => false - } + override def equals(other: Any): Boolean = other match { + case that: OpalStaticFieldVal => + super.equals(that) && this.field.equals(that.field) + case _ => false + } - override def toString: String = s"StaticField: $field" + override def toString: String = s"StaticField: $field" } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalType.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalType.scala index b062491bb..20aabe24e 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalType.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalType.scala @@ -23,71 +23,71 @@ import org.opalj.br.ObjectType case class OpalType(delegate: org.opalj.br.Type) extends Type { - override def isNullType: Boolean = false + override def isNullType: Boolean = false - override def isRefType: Boolean = delegate.isObjectType + override def isRefType: Boolean = delegate.isObjectType - override def isArrayType: Boolean = delegate.isArrayType + override def isArrayType: Boolean = delegate.isArrayType - override def getArrayBaseType: Type = OpalType(delegate.asArrayType) + override def getArrayBaseType: Type = OpalType(delegate.asArrayType) - override def getWrappedClass: WrappedClass = { - if (isRefType) { - val declaringClass = OpalClient.getClassFileForType(delegate.asObjectType) + override def getWrappedClass: WrappedClass = { + if (isRefType) { + val declaringClass = OpalClient.getClassFileForType(delegate.asObjectType) - if (declaringClass.isDefined) { - OpalWrappedClass(declaringClass.get) - } else { - OpalPhantomWrappedClass(delegate.asReferenceType) - } - } - - throw new RuntimeException( - "Cannot compute declaring class because type is not a RefType" - ) + if (declaringClass.isDefined) { + OpalWrappedClass(declaringClass.get) + } else { + OpalPhantomWrappedClass(delegate.asReferenceType) + } } - override def doesCastFail(targetValType: Type, target: Val): Boolean = { - if (!isRefType || !targetValType.isRefType) { - return false - } + throw new RuntimeException( + "Cannot compute declaring class because type is not a RefType" + ) + } + + override def doesCastFail(targetValType: Type, target: Val): Boolean = { + if (!isRefType || !targetValType.isRefType) { + return false + } - val sourceType = delegate.asReferenceType - val targetType = - targetValType.asInstanceOf[OpalType].delegate.asReferenceType + val sourceType = delegate.asReferenceType + val targetType = + targetValType.asInstanceOf[OpalType].delegate.asReferenceType - false + false - /*target match { + /*target match { case allocVal: AllocVal if allocVal.getAllocVal.isNewExpr => OpalClient.getClassHierarchy.isSubtypeOf(sourceType, targetType) case _ => OpalClient.getClassHierarchy.isSubtypeOf(sourceType, targetType) || OpalClient.getClassHierarchy.isSubtypeOf(targetType, sourceType) }*/ - } - - override def isSubtypeOf(otherType: String): Boolean = { - if (!delegate.isObjectType) { - return false - } + } - OpalClient.getClassHierarchy.isSubtypeOf( - delegate.asObjectType, - ObjectType(otherType.replace(".", "/")) - ) + override def isSubtypeOf(otherType: String): Boolean = { + if (!delegate.isObjectType) { + return false } - override def isSupertypeOf(subType: String): Boolean = { - if (!delegate.isObjectType) { - return false - } + OpalClient.getClassHierarchy.isSubtypeOf( + delegate.asObjectType, + ObjectType(otherType.replace(".", "/")) + ) + } - OpalClient.getClassHierarchy.isSubtypeOf( - ObjectType(subType), - delegate.asObjectType - ) + override def isSupertypeOf(subType: String): Boolean = { + if (!delegate.isObjectType) { + return false } - override def isBooleanType: Boolean = delegate.isBooleanType + OpalClient.getClassHierarchy.isSubtypeOf( + ObjectType(subType), + delegate.asObjectType + ) + } + + override def isBooleanType: Boolean = delegate.isBooleanType - override def toString: String = delegate.toJava + override def toString: String = delegate.toJava } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalVal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalVal.scala index 57b15dcdc..b5b291315 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalVal.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalVal.scala @@ -27,189 +27,188 @@ class OpalVal( unbalanced: ControlFlowGraph.Edge = null ) extends Val(method, unbalanced) { - if (delegate.isVar) { - throw new RuntimeException("OpalVal cannot hold a variable (use OpalLocal)") + if (delegate.isVar) { + throw new RuntimeException("OpalVal cannot hold a variable (use OpalLocal)") + } + + override def getType: Type = delegate match { + case nullExpr: NullExpr => OpalType(nullExpr.tpe) + case const: Const => OpalType(const.tpe) + case newExpr: New => OpalType(newExpr.tpe) + case newArrayExpr: NewArray[_] => OpalType(newArrayExpr.tpe) + case functionCall: FunctionCall[_] => + OpalType(functionCall.descriptor.returnType) + case _ => throw new RuntimeException("Type not implemented yet") + } + + override def isStatic: Boolean = false + + override def isNewExpr: Boolean = delegate.isNew + + override def getNewExprType: Type = { + if (isNewExpr) { + return OpalType(delegate.asNew.tpe) } - override def getType: Type = delegate match { - case nullExpr: NullExpr => OpalType(nullExpr.tpe) - case const: Const => OpalType(const.tpe) - case newExpr: New => OpalType(newExpr.tpe) - case newArrayExpr: NewArray[_] => OpalType(newArrayExpr.tpe) - case functionCall: FunctionCall[_] => - OpalType(functionCall.descriptor.returnType) - case _ => throw new RuntimeException("Type not implemented yet") - } - - // TODO - override def isStatic: Boolean = false - - override def isNewExpr: Boolean = delegate.isNew - - override def getNewExprType: Type = { - if (isNewExpr) { - return OpalType(delegate.asNew.tpe) - } - - throw new RuntimeException("Value is not a new expression") - } + throw new RuntimeException("Value is not a new expression") + } - override def asUnbalanced(stmt: ControlFlowGraph.Edge): Val = - new OpalVal(delegate, method, stmt) + override def asUnbalanced(stmt: ControlFlowGraph.Edge): Val = + new OpalVal(delegate, method, stmt) - override def isLocal: Boolean = false + override def isLocal: Boolean = false - override def isArrayAllocationVal: Boolean = delegate.isNewArray + override def isArrayAllocationVal: Boolean = delegate.isNewArray - override def getArrayAllocationSize: Val = { - if (isArrayAllocationVal) { - val counts = delegate.asNewArray.counts + override def getArrayAllocationSize: Val = { + if (isArrayAllocationVal) { + val counts = delegate.asNewArray.counts - /* TODO - * For now, the scope just returns the size of the first dimension. - * In the future, we may change it to returning a list of values - */ - val firstIndex = counts.last - if (firstIndex.isVar) { - return new OpalLocal(firstIndex.asVar, method) - } else { - return new OpalVal(firstIndex, method) - } - } - - throw new RuntimeException("Value is not an array allocation expression") + /* TODO + * For now, the scope just returns the size of the first dimension. + * In the future, we may change it to returning a list of values + */ + val firstIndex = counts.last + if (firstIndex.isVar) { + return new OpalLocal(firstIndex.asVar, method) + } else { + return new OpalVal(firstIndex, method) + } } - override def isNull: Boolean = delegate.isNullExpr + throw new RuntimeException("Value is not an array allocation expression") + } - override def isStringConstant: Boolean = delegate.isStringConst + override def isNull: Boolean = delegate.isNullExpr - override def getStringValue: String = { - if (isStringConstant) { - return delegate.asStringConst.value - } + override def isStringConstant: Boolean = delegate.isStringConst - throw new RuntimeException("Value is not a String constant") + override def getStringValue: String = { + if (isStringConstant) { + return delegate.asStringConst.value } - override def isStringBufferOrBuilder: Boolean = { - val thisType = getType + throw new RuntimeException("Value is not a String constant") + } - thisType.toString.equals("java/lang/String") || thisType.toString.equals( - "java/lang/StringBuilder" - ) || thisType.toString.equals("java/lang/StringBuffer") - } + override def isStringBufferOrBuilder: Boolean = { + val thisType = getType - override def isThrowableAllocationType: Boolean = { - val thisType = getType + thisType.toString.equals("java/lang/String") || thisType.toString.equals( + "java/lang/StringBuilder" + ) || thisType.toString.equals("java/lang/StringBuffer") + } - if (!thisType.isRefType) { - return false - } + override def isThrowableAllocationType: Boolean = { + val thisType = getType - val opalType = thisType.asInstanceOf[OpalType].delegate - OpalClient.getClassHierarchy.isSubtypeOf( - opalType.asReferenceType, - ReferenceType("java/lang/Throwable") - ) + if (!thisType.isRefType) { + return false } - override def isCast: Boolean = delegate.astID == PrimitiveTypecastExpr.ASTID + val opalType = thisType.asInstanceOf[OpalType].delegate + OpalClient.getClassHierarchy.isSubtypeOf( + opalType.asReferenceType, + ReferenceType("java/lang/Throwable") + ) + } - override def getCastOp: Val = { - if (isCast) { - return new OpalVal(delegate.asPrimitiveTypeCastExpr.operand, method) - } + override def isCast: Boolean = delegate.astID == PrimitiveTypecastExpr.ASTID - throw new RuntimeException("Expression is not a cast expression") + override def getCastOp: Val = { + if (isCast) { + return new OpalVal(delegate.asPrimitiveTypeCastExpr.operand, method) } - override def isArrayRef: Boolean = false + throw new RuntimeException("Expression is not a cast expression") + } - override def isInstanceOfExpr: Boolean = delegate.astID == InstanceOf.ASTID + override def isArrayRef: Boolean = false - override def getInstanceOfOp: Val = { - if (isInstanceOfExpr) { - return new OpalVal(delegate.asInstanceOf.value, method) - } + override def isInstanceOfExpr: Boolean = delegate.astID == InstanceOf.ASTID - throw new RuntimeException("Expression is not an instanceOf expression") + override def getInstanceOfOp: Val = { + if (isInstanceOfExpr) { + return new OpalVal(delegate.asInstanceOf.value, method) } - override def isLengthExpr: Boolean = delegate.astID == ArrayLength.ASTID + throw new RuntimeException("Expression is not an instanceOf expression") + } - override def getLengthOp: Val = { - if (isLengthExpr) { - return new OpalVal(delegate.asArrayLength, method) - } + override def isLengthExpr: Boolean = delegate.astID == ArrayLength.ASTID - throw new RuntimeException("Value is not a length expression") + override def getLengthOp: Val = { + if (isLengthExpr) { + return new OpalVal(delegate.asArrayLength, method) } - override def isIntConstant: Boolean = delegate.isIntConst + throw new RuntimeException("Value is not a length expression") + } - override def isClassConstant: Boolean = delegate.isClassConst + override def isIntConstant: Boolean = delegate.isIntConst - override def getClassConstantType: Type = { - if (isClassConstant) { - return OpalType(delegate.asClassConst.value) - } + override def isClassConstant: Boolean = delegate.isClassConst - throw new RuntimeException("Value is not a class constant") + override def getClassConstantType: Type = { + if (isClassConstant) { + return OpalType(delegate.asClassConst.value) } - override def withNewMethod(callee: Method): Val = - new OpalVal(delegate, callee.asInstanceOf[OpalMethod]) + throw new RuntimeException("Value is not a class constant") + } - override def withSecondVal(secondVal: Val) = - new OpalDoubleVal(delegate, method, secondVal) + override def withNewMethod(callee: Method): Val = + new OpalVal(delegate, callee.asInstanceOf[OpalMethod]) - override def isLongConstant: Boolean = delegate.isLongConst + override def withSecondVal(secondVal: Val) = + new OpalDoubleVal(delegate, method, secondVal) - override def getIntValue: Int = { - if (isIntConstant) { - return delegate.asIntConst.value - } + override def isLongConstant: Boolean = delegate.isLongConst - throw new RuntimeException("Value is not an integer constant") + override def getIntValue: Int = { + if (isIntConstant) { + return delegate.asIntConst.value } - override def getLongValue: Long = { - if (isLongConstant) { - return delegate.asLongConst.value - } + throw new RuntimeException("Value is not an integer constant") + } - throw new RuntimeException("Value is not a long constant") + override def getLongValue: Long = { + if (isLongConstant) { + return delegate.asLongConst.value } - override def getArrayBase: Pair[Val, Integer] = throw new RuntimeException( - "Value is not an array ref" - ) - - override def getVariableName: String = { - delegate match { - case stringConst: StringConst => "\"" + stringConst.value + "\"" - case intConst: IntConst => intConst.value.toString - case longConst: LongConst => longConst.value.toString - case newExpr: New => s"new ${newExpr.tpe.toJava}" - case newArrayExpr: NewArray[_] => s"new ${newArrayExpr.tpe.toJava}" - case _: NullExpr => "null" - case _ => delegate.toString - } + throw new RuntimeException("Value is not a long constant") + } + + override def getArrayBase: Pair[Val, Integer] = throw new RuntimeException( + "Value is not an array ref" + ) + + override def getVariableName: String = { + delegate match { + case stringConst: StringConst => "\"" + stringConst.value + "\"" + case intConst: IntConst => intConst.value.toString + case longConst: LongConst => longConst.value.toString + case newExpr: New => s"new ${newExpr.tpe.toJava}" + case newArrayExpr: NewArray[_] => s"new ${newArrayExpr.tpe.toJava}" + case _: NullExpr => "null" + case _ => delegate.toString } + } - override def hashCode: Int = - Objects.hash(super.hashCode(), delegate.hashCode()) + override def hashCode: Int = + Objects.hash(super.hashCode(), delegate.hashCode()) - private def canEqual(a: Any): Boolean = a.isInstanceOf[OpalVal] + private def canEqual(a: Any): Boolean = a.isInstanceOf[OpalVal] - override def equals(obj: Any): Boolean = obj match { - case other: OpalVal => - other.canEqual(this) && super.equals( - other - ) && this.delegate == other.delegate - case _ => false - } + override def equals(obj: Any): Boolean = obj match { + case other: OpalVal => + other.canEqual(this) && super.equals( + other + ) && this.delegate == other.delegate + case _ => false + } - override def toString: String = getVariableName + override def toString: String = getVariableName } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalWrappedClass.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalWrappedClass.scala index e94d9644f..c1b488944 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalWrappedClass.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/tac/OpalWrappedClass.scala @@ -23,43 +23,43 @@ import org.opalj.br.ClassFile case class OpalWrappedClass(delegate: ClassFile) extends WrappedClass { - override def getMethods: util.Set[Method] = { - val methods = new util.HashSet[Method] + override def getMethods: util.Set[Method] = { + val methods = new util.HashSet[Method] - delegate.methods.foreach(method => { - methods.add(OpalMethod(method)) - }) + delegate.methods.foreach(method => { + methods.add(OpalMethod(method)) + }) - methods - } - - override def hasSuperclass: Boolean = delegate.superclassType.isDefined + methods + } - override def getSuperclass: WrappedClass = { - if (hasSuperclass) { - val superClass = - OpalClient.getClassFileForType(delegate.superclassType.get) + override def hasSuperclass: Boolean = delegate.superclassType.isDefined - if (superClass.isDefined) { - return OpalWrappedClass(superClass.get) - } else { - return OpalPhantomWrappedClass(delegate.superclassType.get) - } - } + override def getSuperclass: WrappedClass = { + if (hasSuperclass) { + val superClass = + OpalClient.getClassFileForType(delegate.superclassType.get) - throw new RuntimeException( - "Class " + delegate.thisType.toJava + " has no super class" - ) + if (superClass.isDefined) { + return OpalWrappedClass(superClass.get) + } else { + return OpalPhantomWrappedClass(delegate.superclassType.get) + } } - override def getType: Type = OpalType(delegate.thisType) + throw new RuntimeException( + "Class " + delegate.thisType.toJava + " has no super class" + ) + } + + override def getType: Type = OpalType(delegate.thisType) - override def isApplicationClass: Boolean = - OpalClient.isApplicationClass(delegate) + override def isApplicationClass: Boolean = + OpalClient.isApplicationClass(delegate) - override def getFullyQualifiedName: String = delegate.fqn.replace("/", ".") + override def getFullyQualifiedName: String = delegate.fqn.replace("/", ".") - override def isPhantom: Boolean = false + override def isPhantom: Boolean = false - override def toString: String = delegate.toString() + override def toString: String = delegate.toString() } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/BoomerangTACode.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/BoomerangTACode.scala index db50199ff..097825fb9 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/BoomerangTACode.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/BoomerangTACode.scala @@ -19,15 +19,15 @@ import org.opalj.tac.Stmt class BoomerangTACode(val cfg: StmtGraph) { - def statements: Array[Stmt[TacLocal]] = cfg.statements.toArray + def statements: Array[Stmt[TacLocal]] = cfg.statements.toArray - def getLocals: Set[TacLocal] = statements - .filter(stmt => stmt.astID == Assignment.ASTID) - .map(stmt => stmt.asAssignment.targetVar) - .toSet + def getLocals: Set[TacLocal] = statements + .filter(stmt => stmt.astID == Assignment.ASTID) + .map(stmt => stmt.asAssignment.targetVar) + .toSet - def getParameterLocals: List[TacLocal] = statements - .filter(stmt => stmt.pc == -1) - .map(stmt => stmt.asAssignment.targetVar) - .toList + def getParameterLocals: List[TacLocal] = statements + .filter(stmt => stmt.pc == -1) + .map(stmt => stmt.asAssignment.targetVar) + .toList } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/StmtGraph.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/StmtGraph.scala index b879bf555..73fa4bfcd 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/StmtGraph.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/StmtGraph.scala @@ -29,163 +29,166 @@ class StmtGraph private ( val statements: List[Stmt[TacLocal]] ) { - // TODO Update if and goto targets - def insertBefore( - insertStmt: Stmt[TacLocal], - existingStmt: Stmt[TacLocal] - ): StmtGraph = { - val tempSuccessor = mutable.Map.from(successors) - - // Insert s1 between s0 -> s2 - val preds = predecessors(existingStmt) - preds.foreach(pred => { - // Update succs of s0 from s2 to s1, giving s0 -> s1 ... s2 - val succsOfPred = successors(pred) - assert(succsOfPred.contains(existingStmt)) - - val newSuccs = succsOfPred - existingStmt + insertStmt - tempSuccessor.put(pred, newSuccs) - }) - - // Update preds of s2 from s0 to (only) s1, giving s0 ... s1 <- s2 - val tempPreds = mutable.Map.from(predecessors) - tempPreds.put(existingStmt, Set(insertStmt)) - - // Add the new statement - tempPreds.put(insertStmt, preds) - tempSuccessor.put(insertStmt, Set(existingStmt)) - - // Potential head statement update - var newHeads = heads.map(identity) - if (heads.contains(existingStmt)) { - newHeads = newHeads - existingStmt + insertStmt - } - - val newStatements = statements.flatMap { - case `existingStmt` => List(insertStmt, existingStmt) - case x => List(x) - } - - new StmtGraph( - tac, - newHeads, - tails, - tempPreds.toMap, - tempSuccessor.toMap, - newStatements - ) + // TODO + // Update if and goto targets: The concrete targets are not + // relevant for Boomerang, but it would be nice to have them + // correct + def insertBefore( + insertStmt: Stmt[TacLocal], + existingStmt: Stmt[TacLocal] + ): StmtGraph = { + val tempSuccessor = mutable.Map.from(successors) + + // Insert s1 between s0 -> s2 + val preds = predecessors(existingStmt) + preds.foreach(pred => { + // Update succs of s0 from s2 to s1, giving s0 -> s1 ... s2 + val succsOfPred = successors(pred) + assert(succsOfPred.contains(existingStmt)) + + val newSuccs = succsOfPred - existingStmt + insertStmt + tempSuccessor.put(pred, newSuccs) + }) + + // Update preds of s2 from s0 to (only) s1, giving s0 ... s1 <- s2 + val tempPreds = mutable.Map.from(predecessors) + tempPreds.put(existingStmt, Set(insertStmt)) + + // Add the new statement + tempPreds.put(insertStmt, preds) + tempSuccessor.put(insertStmt, Set(existingStmt)) + + // Potential head statement update + var newHeads = heads.map(identity) + if (heads.contains(existingStmt)) { + newHeads = newHeads - existingStmt + insertStmt } - def remove(stmt: Stmt[TacLocal]): StmtGraph = { - if (tails.contains(stmt)) - throw new RuntimeException("Cannot remove tail statement") + val newStatements = statements.flatMap { + case `existingStmt` => List(insertStmt, existingStmt) + case x => List(x) + } - val tempPreds = mutable.Map.from(predecessors) - val tempSuccs = mutable.Map.from(successors) + new StmtGraph( + tac, + newHeads, + tails, + tempPreds.toMap, + tempSuccessor.toMap, + newStatements + ) + } + + def remove(stmt: Stmt[TacLocal]): StmtGraph = { + if (tails.contains(stmt)) + throw new RuntimeException("Cannot remove tail statement") + + val tempPreds = mutable.Map.from(predecessors) + val tempSuccs = mutable.Map.from(successors) + + val preds = predecessors(stmt) + val succs = successors(stmt) + preds.foreach(pred => { + val succsOfPred = successors(pred) + + assert(succsOfPred.contains(stmt), "Inconsistent state in graph") + tempSuccs.put(pred, succsOfPred ++ succs - stmt) + }) + + succs.foreach(succ => { + val predsOfSuccs = predecessors(succ) + + assert(predsOfSuccs.contains(stmt), "Inconsistent state in graph") + tempPreds.put(succ, predsOfSuccs ++ preds - stmt) + }) + + var newHeads = heads.map(identity) + if (heads.contains(stmt)) { + newHeads = newHeads - stmt + newHeads = newHeads ++ succs + } - val preds = predecessors(stmt) - val succs = successors(stmt) - preds.foreach(pred => { - val succsOfPred = successors(pred) + val newStatements = statements.filter(s => s != stmt) + val newPreds = tempPreds.filter(s => s._1 != stmt).toMap + val newSuccs = tempSuccs.filter(s => s._1 != stmt).toMap - assert(succsOfPred.contains(stmt), "Inconsistent state in graph") - tempSuccs.put(pred, succsOfPred ++ succs - stmt) - }) + assert(!newHeads.contains(stmt)) + assert(!newStatements.contains(stmt)) + assert(!newPreds.contains(stmt)) + assert(!newSuccs.contains(stmt)) + new StmtGraph(tac, newHeads, tails, newPreds, newSuccs, newStatements) + } +} - succs.foreach(succ => { - val predsOfSuccs = predecessors(succ) +object StmtGraph { - assert(predsOfSuccs.contains(stmt), "Inconsistent state in graph") - tempPreds.put(succ, predsOfSuccs ++ preds - stmt) + def apply( + tac: Array[Stmt[TacLocal]], + cfg: CFG[Stmt[TacLocal], TACStmts[TacLocal]], + pcToIndex: Array[Int], + exceptionHandlers: Array[Int] + ): StmtGraph = { + + def computeHead: Set[Stmt[TacLocal]] = + exceptionHandlers.map(eh => tac(eh)).toSet + tac(0) + + def computeTails: Set[Stmt[TacLocal]] = { + tac + .filter(stmt => stmt.pc >= 0) + .filter(stmt => { + val stmtIndex = pcToIndex(stmt.pc) + val successors = cfg.successors(stmtIndex) + + // No successors => tail statement + successors.isEmpty }) - - var newHeads = heads.map(identity) - if (heads.contains(stmt)) { - newHeads = newHeads - stmt - newHeads = newHeads ++ succs - } - - val newStatements = statements.filter(s => s != stmt) - val newPreds = tempPreds.filter(s => s._1 != stmt).toMap - val newSuccs = tempSuccs.filter(s => s._1 != stmt).toMap - - assert(!newHeads.contains(stmt)) - assert(!newStatements.contains(stmt)) - assert(!newPreds.contains(stmt)) - assert(!newSuccs.contains(stmt)) - new StmtGraph(tac, newHeads, tails, newPreds, newSuccs, newStatements) + .toSet } -} -object StmtGraph { + def computePredecessors(stmt: Stmt[TacLocal]): Set[Stmt[TacLocal]] = { + // head + if (stmt == tac(0)) return Set.empty + + // Pred of identity statements are just the previous statement + if (stmt.pc < 0) { + val stmtIndex = tac.indexOf(stmt) + return Set(tac(stmtIndex - 1)) + } + + // The first original statement + if (stmt.pc == 0) { + val stmtIndex = tac.indexOf(stmt) + return Set(tac(stmtIndex - 1)) + } + + val stmtIndex = pcToIndex(stmt.pc) + if (exceptionHandlers.contains(stmtIndex)) { + return Set() + } + + val predecessors = cfg.predecessors(stmtIndex) + predecessors.map(predecessorIndex => tac(predecessorIndex)) + } - def apply( - tac: Array[Stmt[TacLocal]], - cfg: CFG[Stmt[TacLocal], TACStmts[TacLocal]], - pcToIndex: Array[Int], - exceptionHandlers: Array[Int] - ): StmtGraph = { - - def computeHead: Set[Stmt[TacLocal]] = - exceptionHandlers.map(eh => tac(eh)).toSet + tac(0) - - def computeTails: Set[Stmt[TacLocal]] = { - tac - .filter(stmt => stmt.pc >= 0) - .filter(stmt => { - val stmtIndex = pcToIndex(stmt.pc) - val successors = cfg.successors(stmtIndex) - - // No successors => tail statement - successors.isEmpty - }) - .toSet - } - - def computePredecessors(stmt: Stmt[TacLocal]): Set[Stmt[TacLocal]] = { - // head - if (stmt == tac(0)) return Set.empty - - // Pred of identity statements are just the previous statement - if (stmt.pc < 0) { - val stmtIndex = tac.indexOf(stmt) - return Set(tac(stmtIndex - 1)) - } - - // The first original statement - if (stmt.pc == 0) { - val stmtIndex = tac.indexOf(stmt) - return Set(tac(stmtIndex - 1)) - } - - val stmtIndex = pcToIndex(stmt.pc) - if (exceptionHandlers.contains(stmtIndex)) { - return Set() - } - - val predecessors = cfg.predecessors(stmtIndex) - predecessors.map(predecessorIndex => tac(predecessorIndex)) - } - - def computeSuccessors(stmt: Stmt[TacLocal]): Set[Stmt[TacLocal]] = { - // Successor of identity statements is just the following statement - if (stmt.pc < 0) { - val stmtIndex = tac.indexOf(stmt) - return Set(tac(stmtIndex + 1)) - } - - val stmtIndex = pcToIndex(stmt.pc) - val successors = cfg.successors(stmtIndex) - successors - .filter(s => !exceptionHandlers.contains(s)) - .map(successorIndex => tac(successorIndex)) - } - - val heads = computeHead - val tails = computeTails - val predecessors = tac.map(stmt => stmt -> computePredecessors(stmt)).toMap - val successors = tac.map(stmt => stmt -> computeSuccessors(stmt)).toMap - - new StmtGraph(tac, heads, tails, predecessors, successors, tac.toList) + def computeSuccessors(stmt: Stmt[TacLocal]): Set[Stmt[TacLocal]] = { + // Successor of identity statements is just the following statement + if (stmt.pc < 0) { + val stmtIndex = tac.indexOf(stmt) + return Set(tac(stmtIndex + 1)) + } + + val stmtIndex = pcToIndex(stmt.pc) + val successors = cfg.successors(stmtIndex) + successors + .filter(s => !exceptionHandlers.contains(s)) + .map(successorIndex => tac(successorIndex)) } + + val heads = computeHead + val tails = computeTails + val predecessors = tac.map(stmt => stmt -> computePredecessors(stmt)).toMap + val successors = tac.map(stmt => stmt -> computeSuccessors(stmt)).toMap + + new StmtGraph(tac, heads, tails, predecessors, successors, tac.toList) + } } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacBodyBuilder.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacBodyBuilder.scala index 23ea3dd34..d7b934239 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacBodyBuilder.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacBodyBuilder.scala @@ -26,58 +26,60 @@ import org.opalj.tac.TACStmts object TacBodyBuilder { - def apply(project: Project[_], method: Method): BoomerangTACode = { - if (method.body.isEmpty) { - throw new IllegalArgumentException( - "Cannot compute TAC for method without existing body: " + method - ) - } + def apply(project: Project[_], method: Method): BoomerangTACode = { + if (method.body.isEmpty) { + throw new IllegalArgumentException( + "Cannot compute TAC for method without existing body: " + method + ) + } - val tacNaive = TACNaive(method, project.classHierarchy) - val stackHandler = OperandStackBuilder(method, tacNaive) + val tacNaive = TACNaive(method, project.classHierarchy) + val stackHandler = OperandStackBuilder(method, tacNaive) - // TODO Use other domain to compute static type information - val domain = new PrimitiveTACAIDomain(project.classHierarchy, method) - val localTransformedTac = - LocalTransformer(project, method, tacNaive, stackHandler, domain) - assert( - tacNaive.stmts.length == localTransformedTac.length, - "Wrong transformation" - ) + // TODO + // We are only interested in the type information, so there may be + // a more suitable domain + val domain = new PrimitiveTACAIDomain(project.classHierarchy, method) + val localTransformedTac = + LocalTransformer(project, method, tacNaive, stackHandler, domain) + assert( + tacNaive.stmts.length == localTransformedTac.length, + "Wrong transformation" + ) - val inlinedTac = InlineLocalTransformer(localTransformedTac, stackHandler) - assert(tacNaive.stmts.length == inlinedTac.length, "Wrong transformation") + val inlinedTac = InlineLocalTransformer(localTransformedTac, stackHandler) + assert(tacNaive.stmts.length == inlinedTac.length, "Wrong transformation") - val propagatedTac = LocalPropagationTransformer(inlinedTac, stackHandler) - assert( - tacNaive.stmts.length == propagatedTac.length, - "Wrong transformation" - ) + val propagatedTac = LocalPropagationTransformer(inlinedTac, stackHandler) + assert( + tacNaive.stmts.length == propagatedTac.length, + "Wrong transformation" + ) - // Update the CFG - val cfg = CFGFactory(method, project.classHierarchy) - if (cfg.isEmpty) { - throw new RuntimeException( - "Could not compute CFG for method " + method.name - ) - } + // Update the CFG + val cfg = CFGFactory(method, project.classHierarchy) + if (cfg.isEmpty) { + throw new RuntimeException( + "Could not compute CFG for method " + method.name + ) + } - val tacCfg = cfg.get.mapPCsToIndexes[Stmt[TacLocal], TACStmts[TacLocal]]( - TACStmts(propagatedTac), - tacNaive.pcToIndex, - i => i, - propagatedTac.length - ) + val tacCfg = cfg.get.mapPCsToIndexes[Stmt[TacLocal], TACStmts[TacLocal]]( + TACStmts(propagatedTac), + tacNaive.pcToIndex, + i => i, + propagatedTac.length + ) - val exceptionHandlers = - tacNaive.exceptionHandlers.map(eh => eh.handlerPC).toArray - var stmtGraph = - StmtGraph(propagatedTac, tacCfg, tacNaive.pcToIndex, exceptionHandlers) + val exceptionHandlers = + tacNaive.exceptionHandlers.map(eh => eh.handlerPC).toArray + var stmtGraph = + StmtGraph(propagatedTac, tacCfg, tacNaive.pcToIndex, exceptionHandlers) - stmtGraph = NopTransformer(stmtGraph) - stmtGraph = NullifyFieldsTransformer(method, stmtGraph) - stmtGraph = NopEliminator(stmtGraph) + stmtGraph = NopTransformer(stmtGraph) + stmtGraph = NullifyFieldsTransformer(project, method, stmtGraph) + stmtGraph = NopEliminator(stmtGraph) - new BoomerangTACode(stmtGraph) - } + new BoomerangTACode(stmtGraph) + } } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacLocal.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacLocal.scala index d19c9b29e..0a38cc983 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacLocal.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/TacLocal.scala @@ -23,33 +23,33 @@ import org.opalj.value.ValueInformation trait TacLocal extends Var[TacLocal] { - def id: Int + def id: Int - def isStackLocal: Boolean = false + def isStackLocal: Boolean = false - def isRegisterLocal: Boolean = false + def isRegisterLocal: Boolean = false - def isParameterLocal: Boolean = false + def isParameterLocal: Boolean = false - def isThisLocal: Boolean = false + def isThisLocal: Boolean = false - def isExceptionLocal: Boolean = false + def isExceptionLocal: Boolean = false - def cTpe: ComputationalType + def cTpe: ComputationalType - def valueInformation: ValueInformation + def valueInformation: ValueInformation - final def isSideEffectFree: Boolean = true + final def isSideEffectFree: Boolean = true - override def toCanonicalForm(implicit - ev: TacLocal <:< DUVar[ValueInformation] - ): Nothing = { - throw new IncompatibleClassChangeError( - "TacLocal objects are not expected to inherit from DUVar" - ) - } + override def toCanonicalForm(implicit + ev: TacLocal <:< DUVar[ValueInformation] + ): Nothing = { + throw new IncompatibleClassChangeError( + "TacLocal objects are not expected to inherit from DUVar" + ) + } - override def toString: String = name + override def toString: String = name } class StackLocal( @@ -59,25 +59,25 @@ class StackLocal( isThis: Boolean = false ) extends TacLocal { - override def id: Int = identifier + override def id: Int = identifier - override def isStackLocal: Boolean = true + override def isStackLocal: Boolean = true - override def isThisLocal: Boolean = isThis + override def isThisLocal: Boolean = isThis - override def name: String = if (isThis) "$this" else s"$$s$identifier" + override def name: String = if (isThis) "$this" else s"$$s$identifier" - override def cTpe: ComputationalType = computationalType + override def cTpe: ComputationalType = computationalType - override def valueInformation: ValueInformation = valueInfo + override def valueInformation: ValueInformation = valueInfo - override def hashCode: Int = Objects.hash(this.getClass.hashCode(), id) + override def hashCode: Int = Objects.hash(this.getClass.hashCode(), id) - override def equals(other: Any): Boolean = other match { - case that: StackLocal => this.id == that.id - case that: RegisterLocal => this.isThisLocal && that.isThisLocal - case _ => false - } + override def equals(other: Any): Boolean = other match { + case that: StackLocal => this.id == that.id + case that: RegisterLocal => this.isThisLocal && that.isThisLocal + case _ => false + } } class RegisterLocal( @@ -88,30 +88,30 @@ class RegisterLocal( localName: Option[String] = Option.empty ) extends TacLocal { - override def id: Int = identifier + override def id: Int = identifier - override def isRegisterLocal: Boolean = true + override def isRegisterLocal: Boolean = true - override def isThisLocal: Boolean = isThis + override def isThisLocal: Boolean = isThis - override def name: String = { - if (isThis) return "this" - if (localName.isDefined) return localName.get + override def name: String = { + if (isThis) return "this" + if (localName.isDefined) return localName.get - s"r${-identifier - 1}" - } + s"r${-identifier - 1}" + } - override def cTpe: ComputationalType = computationalType + override def cTpe: ComputationalType = computationalType - override def valueInformation: ValueInformation = valueInfo + override def valueInformation: ValueInformation = valueInfo - override def hashCode: Int = Objects.hash(this.getClass.hashCode(), id) + override def hashCode: Int = Objects.hash(this.getClass.hashCode(), id) - override def equals(other: Any): Boolean = other match { - case that: RegisterLocal => this.id == that.id - case that: StackLocal => this.isThisLocal && that.isThisLocal - case _ => false - } + override def equals(other: Any): Boolean = other match { + case that: RegisterLocal => this.id == that.id + case that: StackLocal => this.isThisLocal && that.isThisLocal + case _ => false + } } class ParameterLocal( @@ -120,43 +120,44 @@ class ParameterLocal( paramName: String ) extends TacLocal { - override def id: Int = identifier + override def id: Int = identifier - override def isParameterLocal: Boolean = true + override def isParameterLocal: Boolean = true - override def cTpe: ComputationalType = computationalType + override def cTpe: ComputationalType = computationalType - override def valueInformation: ValueInformation = - throw new UnsupportedOperationException( - "No value information available for parameter local" - ) + override def valueInformation: ValueInformation = + throw new UnsupportedOperationException( + "No value information available for parameter local" + ) - override def name: String = paramName + override def name: String = paramName - override def hashCode: Int = Objects.hash(this.getClass.hashCode(), id) + override def hashCode: Int = Objects.hash(this.getClass.hashCode(), id) - override def equals(other: Any): Boolean = other match { - case that: ParameterLocal => this.id == that.id - case _ => false - } + override def equals(other: Any): Boolean = other match { + case that: ParameterLocal => this.id == that.id + case _ => false + } } -class NullifiedLocal(identifier: Int, computationalType: ComputationalType) extends TacLocal { +class NullifiedLocal(identifier: Int, computationalType: ComputationalType, valueInfo: ValueInformation) + extends TacLocal { - override def id: Int = identifier + override def id: Int = identifier - override def cTpe: ComputationalType = computationalType + override def cTpe: ComputationalType = computationalType - override def valueInformation: ValueInformation = IsNullValue + override def valueInformation: ValueInformation = valueInfo - override def name: String = s"n$identifier" + override def name: String = s"n$identifier" - override def hashCode: Int = Objects.hash(this.getClass.hashCode(), id) + override def hashCode: Int = Objects.hash(this.getClass.hashCode(), id) - override def equals(other: Any): Boolean = other match { - case that: NullifiedLocal => this.id == that.id - case _ => false - } + override def equals(other: Any): Boolean = other match { + case that: NullifiedLocal => this.id == that.id + case _ => false + } } class ExceptionLocal( @@ -165,20 +166,20 @@ class ExceptionLocal( valueInfo: ValueInformation ) extends TacLocal { - override def id: Int = identifier + override def id: Int = identifier - override def isExceptionLocal: Boolean = true + override def isExceptionLocal: Boolean = true - override def cTpe: ComputationalType = computationalType + override def cTpe: ComputationalType = computationalType - override def valueInformation: ValueInformation = valueInfo + override def valueInformation: ValueInformation = valueInfo - override def name: String = s"e$identifier" + override def name: String = s"e$identifier" - override def hashCode: Int = Objects.hash(this.getClass.hashCode(), id) + override def hashCode: Int = Objects.hash(this.getClass.hashCode(), id) - override def equals(other: Any): Boolean = other match { - case that: ExceptionLocal => this.id == that.id - case _ => false - } + override def equals(other: Any): Boolean = other match { + case that: ExceptionLocal => this.id == that.id + case _ => false + } } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/Operand.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/Operand.scala index e45106b49..c995c7b2c 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/Operand.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/Operand.scala @@ -23,23 +23,23 @@ class Operand( private var counter: Int ) { - private var modified = false + private var modified = false - def localId: Int = counter + def localId: Int = counter - def updateCounter(newCount: Int): Unit = { - counter = newCount - modified = true - } + def updateCounter(newCount: Int): Unit = { + counter = newCount + modified = true + } - def isBranchedOperand: Boolean = modified + def isBranchedOperand: Boolean = modified - override def hashCode: Int = Objects.hash(id) + override def hashCode: Int = Objects.hash(id) - override def equals(obj: Any): Boolean = obj match { - case that: Operand => this.id == that.id - case _ => false - } + override def equals(obj: Any): Boolean = obj match { + case that: Operand => this.id == that.id + case _ => false + } - override def toString: String = s"op$id ($counter)" + override def toString: String = s"op$id ($counter)" } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStack.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStack.scala index 90a83db81..6a2e10aa5 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStack.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStack.scala @@ -21,63 +21,63 @@ class OperandStack private ( private var stack: List[Operand] ) { - def stackEntries: List[Operand] = stack - - def push(idBasedVar: IdBasedVar): Unit = { - val operand = - new Operand(idBasedVar.id, idBasedVar.cTpe, stackHandler.nextLocalCounter) - stack = operand :: stack + def stackEntries: List[Operand] = stack + + def push(idBasedVar: IdBasedVar): Unit = { + val operand = + new Operand(idBasedVar.id, idBasedVar.cTpe, stackHandler.nextLocalCounter) + stack = operand :: stack + } + + def push(operand: Operand): Unit = { + stack = operand :: stack + } + + def pop(idBasedVar: IdBasedVar): Unit = { + if (stack.isEmpty) { + throw new IllegalStateException( + s"Cannot pop operand $idBasedVar from empty stack" + ) } - def push(operand: Operand): Unit = { - stack = operand :: stack - } + // Check if stack is in consistent state + val top :: rest = stack + assert( + idBasedVar.id == top.id, + s"Invalid pop operation on operand $idBasedVar" + ) - def pop(idBasedVar: IdBasedVar): Unit = { - if (stack.isEmpty) { - throw new IllegalStateException( - s"Cannot pop operand $idBasedVar from empty stack" - ) - } - - // Check if stack is in consistent state - val top :: rest = stack - assert( - idBasedVar.id == top.id, - s"Invalid pop operation on operand $idBasedVar" - ) - - // Update stack - stack = rest - } + // Update stack + stack = rest + } - def pop: Operand = { - if (stack.isEmpty) { - throw new IllegalStateException(s"Cannot pop operand from empty stack") - } + def pop: Operand = { + if (stack.isEmpty) { + throw new IllegalStateException(s"Cannot pop operand from empty stack") + } - val top :: rest = stack - stack = rest + val top :: rest = stack + stack = rest - top - } + top + } - def peek: Operand = { - if (stack.isEmpty) return null + def peek: Operand = { + if (stack.isEmpty) return null - val top :: _ = stack - top - } + val top :: _ = stack + top + } - def copy: OperandStack = new OperandStack(stackHandler, stack.map(identity)) + def copy: OperandStack = new OperandStack(stackHandler, stack.map(identity)) - override def toString: String = stack.toString() + override def toString: String = stack.toString() } object OperandStack { - def apply( - stackHandler: OperandStackHandler, - stack: List[Operand] = List.empty - ) = new OperandStack(stackHandler, stack) + def apply( + stackHandler: OperandStackHandler, + stack: List[Operand] = List.empty + ) = new OperandStack(stackHandler, stack) } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackBuilder.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackBuilder.scala index aaf8a4e8b..f30ef874f 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackBuilder.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackBuilder.scala @@ -30,356 +30,356 @@ import org.opalj.tac._ object OperandStackBuilder { - def apply(method: Method, tacNaive: NaiveTACode[_]): OperandStackHandler = { - val stackHandler = new OperandStackHandler + def apply(method: Method, tacNaive: NaiveTACode[_]): OperandStackHandler = { + val stackHandler = new OperandStackHandler - // Initialize work list; we always start with pc 0 - var workList = List(0) + // Initialize work list; we always start with pc 0 + var workList = List(0) - val exceptionHandlersPc = - tacNaive.exceptionHandlers.map(eh => tacNaive.stmts(eh.handlerPC).pc) - for (eh <- exceptionHandlersPc) { - workList ::= eh + val exceptionHandlersPc = + tacNaive.exceptionHandlers.map(eh => tacNaive.stmts(eh.handlerPC).pc) + for (eh <- exceptionHandlersPc) { + workList ::= eh + } + + if (method.toJava.contains("indirectAllocationSiteTwoFields3Address2()")) { + println() + } + + while (workList.nonEmpty) { + val currPc = workList.head + val currStmt = tacNaive.stmts(tacNaive.pcToIndex(currPc)) + workList = workList.tail + + processStmt(currStmt) + + def pcOfNextStatement(pc: PC): PC = + method.body.get.pcOfNextInstruction(pc) + + def schedule(nextPc: PC, stack: OperandStack): Unit = { + val merged = stackHandler.mergeStack(nextPc, stack) + + if (merged) { + workList ::= nextPc } + } + + def processStmt(stmt: Stmt[IdBasedVar]): Unit = { + val stack = stackHandler.getOrCreate(stmt.pc) + + stmt match { + case If(pc, left, _, right, target) => + val rightOps = processExpr(right) + rightOps.foreach(op => stack.pop(op)) + + val leftOps = processExpr(left) + leftOps.foreach(op => stack.pop(op)) + + schedule(pcOfNextStatement(pc), stack) + + val targetStmt = tacNaive.stmts(target) + schedule(targetStmt.pc, stack) + case Goto(_, target) => + val targetStmt = tacNaive.stmts(target) + schedule(targetStmt.pc, stack) + case Ret(pc, returnAddresses) => + // TODO Not sure how to implement it (not relevant for Java 6+) + case JSR(_, target) => + schedule(target, stack) + case Switch(_, defaultTarget, index: IdBasedVar, nPairs) => + stack.pop(index) + + nPairs.foreach(target => { + val targetStmt = tacNaive.stmts(target.value) + schedule(targetStmt.pc, stack) + }) + + val defaultTargetStmt = tacNaive.stmts(defaultTarget) + schedule(defaultTargetStmt.pc, stack) + case Assignment(pc, targetVar: IdBasedVar, expr: Expr[IdBasedVar]) => + // Exception handlers are defined implicitly, so we cannot pop them from the stack + if (!exceptionHandlersPc.contains(pc)) { + val operands = processExpr(expr) + operands.foreach(op => stack.pop(op)) + } - while (workList.nonEmpty) { - val currPc = workList.head - val currStmt = tacNaive.stmts(tacNaive.pcToIndex(currPc)) - workList = workList.tail + if (targetVar.id >= 0) { + stack.push(targetVar) + stackHandler.addDefSite(pc, stack.peek) + } - processStmt(currStmt) + schedule(pcOfNextStatement(pc), stack) + case ReturnValue(_, expr: IdBasedVar) => + // TODO Bug in Opal causes to return the wrong operand (fixed but not released yet) + // stack.pop(expr) + // No scheduling since there is no next statement + case Return(_) => // No scheduling since there is no next statement + case Nop(pc) => + val instr = method.body.get.instructions(pc) + + // TODO + // Use pattern matching from stack.stackEntries to avoid having so many sequential + // operations (as done in TacNaive) + instr.opcode match { + case NOP.opcode => + schedule(pcOfNextStatement(pc), stack) + case POP.opcode => + stack.pop + + schedule(pcOfNextStatement(pc), stack) + case POP2.opcode => + val top = stack.pop + if (top.cTpe.categoryId == 1) { + stack.pop + } + + schedule(pcOfNextStatement(pc), stack) + case DUP.opcode => + val dupOperand = stack.peek + stack.push(dupOperand) + + schedule(pcOfNextStatement(pc), stack) + case DUP_X1.opcode => + val v1 = stack.pop + val v2 = stack.pop + + stack.push(v1) + stack.push(v2) + stack.push(v1) + + schedule(pcOfNextStatement(pc), stack) + case DUP_X2.opcode => + val v1 = stack.pop + val v2 = stack.pop + + if (v2.cTpe.categoryId == 1) { + val v3 = stack.pop + + stack.push(v1) + stack.push(v3) + stack.push(v2) + stack.push(v1) + } else { + stack.push(v1) + stack.push(v2) + stack.push(v1) + } - def pcOfNextStatement(pc: PC): PC = - method.body.get.pcOfNextInstruction(pc) + schedule(pcOfNextStatement(pc), stack) + case DUP2.opcode => + val v1 = stack.pop - def schedule(nextPc: PC, stack: OperandStack): Unit = { - val merged = stackHandler.mergeStack(nextPc, stack) + if (v1.cTpe.categoryId == 1) { + val v2 = stack.pop - if (merged) { - workList ::= nextPc + stack.push(v2) + stack.push(v1) + stack.push(v2) + stack.push(v1) + } else { + stack.push(v1) + stack.push(v1) } - } - def processStmt(stmt: Stmt[IdBasedVar]): Unit = { - val stack = stackHandler.getOrCreate(stmt.pc) - - stmt match { - case If(pc, left, _, right, target) => - val rightOps = processExpr(right) - rightOps.foreach(op => stack.pop(op)) - - val leftOps = processExpr(left) - leftOps.foreach(op => stack.pop(op)) - - schedule(pcOfNextStatement(pc), stack) - - val targetStmt = tacNaive.stmts(target) - schedule(targetStmt.pc, stack) - case Goto(_, target) => - val targetStmt = tacNaive.stmts(target) - schedule(targetStmt.pc, stack) - case Ret(pc, returnAddresses) => - // TODO - case JSR(_, target) => - schedule(target, stack) - case Switch(_, defaultTarget, index: IdBasedVar, nPairs) => - stack.pop(index) - - nPairs.foreach(target => { - val targetStmt = tacNaive.stmts(target.value) - schedule(targetStmt.pc, stack) - }) - - val defaultTargetStmt = tacNaive.stmts(defaultTarget) - schedule(defaultTargetStmt.pc, stack) - case Assignment(pc, targetVar: IdBasedVar, expr: Expr[IdBasedVar]) => - // Exception handlers are defined implicitly, so we cannot pop them from the stack - if (!exceptionHandlersPc.contains(pc)) { - val operands = processExpr(expr) - operands.foreach(op => stack.pop(op)) - } - - if (targetVar.id >= 0) { - stack.push(targetVar) - stackHandler.addDefSite(pc, stack.peek) - } - - schedule(pcOfNextStatement(pc), stack) - case ReturnValue(_, expr: IdBasedVar) => - // TODO Bug in Opal causes to return the wrong operand (fixed but not released yet) - // stack.pop(expr) - // No scheduling since there is no next statement - case Return(_) => // No scheduling since there is no next statement - case Nop(pc) => - val instr = method.body.get.instructions(pc) - - // TODO - // Use pattern matching from stack.stackEntries to avoid having so many sequential - // operations (as done in TacNaive) - instr.opcode match { - case NOP.opcode => - schedule(pcOfNextStatement(pc), stack) - case POP.opcode => - stack.pop - - schedule(pcOfNextStatement(pc), stack) - case POP2.opcode => - val top = stack.pop - if (top.cTpe.categoryId == 1) { - stack.pop - } - - schedule(pcOfNextStatement(pc), stack) - case DUP.opcode => - val dupOperand = stack.peek - stack.push(dupOperand) - - schedule(pcOfNextStatement(pc), stack) - case DUP_X1.opcode => - val v1 = stack.pop - val v2 = stack.pop - - stack.push(v1) - stack.push(v2) - stack.push(v1) - - schedule(pcOfNextStatement(pc), stack) - case DUP_X2.opcode => - val v1 = stack.pop - val v2 = stack.pop - - if (v2.cTpe.categoryId == 1) { - val v3 = stack.pop - - stack.push(v1) - stack.push(v3) - stack.push(v2) - stack.push(v1) - } else { - stack.push(v1) - stack.push(v2) - stack.push(v1) - } - - schedule(pcOfNextStatement(pc), stack) - case DUP2.opcode => - val v1 = stack.pop - - if (v1.cTpe.categoryId == 1) { - val v2 = stack.pop - - stack.push(v2) - stack.push(v1) - stack.push(v2) - stack.push(v1) - } else { - stack.push(v1) - stack.push(v1) - } - - schedule(pcOfNextStatement(pc), stack) - case DUP2_X1.opcode => - val v1 = stack.pop - val v2 = stack.pop - - if (v1.cTpe.categoryId == 1) { - val v3 = stack.pop - - stack.push(v2) - stack.push(v1) - stack.push(v3) - stack.push(v2) - stack.push(v1) - } else { - stack.push(v1) - stack.push(v2) - stack.push(v1) - } - - schedule(pcOfNextStatement(pc), stack) - case DUP2_X2.opcode => - val v1 = stack.pop - val v2 = stack.pop - val v3 = stack.pop - - if (v1.cTpe.categoryId == 1 && v2.cTpe.categoryId == 1 && v3.cTpe.categoryId == 1) { - val v4 = stack.pop - - stack.push(v2) - stack.push(v1) - stack.push(v4) - stack.push(v3) - stack.push(v2) - stack.push(v1) - } else if ( - v1.cTpe.categoryId == 2 && v2.cTpe.categoryId == 1 && v3.cTpe.categoryId == 1 - ) { - stack.push(v1) - stack.push(v3) - stack.push(v2) - stack.push(v1) - } else if ( - v1.cTpe.categoryId == 1 && v2.cTpe.categoryId == 1 && v3.cTpe.categoryId == 2 - ) { - stack.push(v2) - stack.push(v1) - stack.push(v3) - stack.push(v2) - stack.push(v1) - } else { - stack.push(v3) - stack.push(v1) - stack.push(v2) - stack.push(v1) - } - - schedule(pcOfNextStatement(pc), stack) - case WIDE.opcode => - schedule(pcOfNextStatement(pc), stack) - case _ => - throw new RuntimeException( - "Unknown instruction for NOP: " + instr - ) - } - - schedule(pcOfNextStatement(pc), stack) - case MonitorEnter(pc, objRef: IdBasedVar) => - stack.pop(objRef) - - schedule(pcOfNextStatement(pc), stack) - case MonitorExit(pc, objRef: IdBasedVar) => - stack.pop(objRef) - - schedule(pcOfNextStatement(pc), stack) - case ArrayStore( - pc, - arrayRef: IdBasedVar, - index: IdBasedVar, - value: IdBasedVar - ) => - stack.pop(value) - stack.pop(index) - stack.pop(arrayRef) - - schedule(pcOfNextStatement(pc), stack) - case Throw(_, exception: IdBasedVar) => - stack.pop(exception) - // No scheduling since there is no next statement - case PutStatic(pc, _, _, _, value: IdBasedVar) => - stack.pop(value) - - schedule(pcOfNextStatement(pc), stack) - case PutField(pc, _, _, _, objRef: IdBasedVar, value: IdBasedVar) => - stack.pop(value) - stack.pop(objRef) - - schedule(pcOfNextStatement(pc), stack) - case NonVirtualMethodCall( - pc, - _, - _, - _, - _, - receiver: IdBasedVar, - params: Seq[_] - ) => - params.reverse.foreach(p => stack.pop(p.asVar)) - stack.pop(receiver) - - schedule(pcOfNextStatement(pc), stack) - case VirtualMethodCall( - pc, - _, - _, - _, - _, - receiver: IdBasedVar, - params: Seq[_] - ) => - params.reverse.foreach(p => stack.pop(p.asVar)) - stack.pop(receiver) - - schedule(pcOfNextStatement(pc), stack) - case StaticMethodCall(pc, _, _, _, _, params: Seq[_]) => - params.reverse.foreach(p => stack.pop(p.asVar)) - - schedule(pcOfNextStatement(pc), stack) - case InvokedynamicMethodCall(pc, _, _, _, params: Seq[_]) => - params.reverse.foreach(p => stack.pop(p.asVar)) - - schedule(pcOfNextStatement(pc), stack) - case ExprStmt(pc, expr) => - processExpr(expr) - - schedule(pcOfNextStatement(pc), stack) - case CaughtException(pc, _, _) => - // Only used in TACAI, so no stack manipulation is required - schedule(pcOfNextStatement(pc), stack) - case Checkcast(pc, value, _) => - // TODO Push new stack value - schedule(pcOfNextStatement(pc), stack) - case _ => throw new RuntimeException("Unknown statement: " + stmt) + schedule(pcOfNextStatement(pc), stack) + case DUP2_X1.opcode => + val v1 = stack.pop + val v2 = stack.pop + + if (v1.cTpe.categoryId == 1) { + val v3 = stack.pop + + stack.push(v2) + stack.push(v1) + stack.push(v3) + stack.push(v2) + stack.push(v1) + } else { + stack.push(v1) + stack.push(v2) + stack.push(v1) } - } - def processExpr(expr: Expr[IdBasedVar]): List[IdBasedVar] = { - expr match { - case v: IdBasedVar => if (v.id >= 0) List(v) else List() - case InstanceOf(_, value: IdBasedVar, _) => List(value) - case Compare(_, left: IdBasedVar, _, right: IdBasedVar) => - List(right, left) - case Param(_, _) => List() - case MethodTypeConst(_, _) => List() - case MethodHandleConst(_, _) => List() - case IntConst(_, _) => List() - case LongConst(_, _) => List() - case FloatConst(_, _) => List() - case DoubleConst(_, _) => List() - case StringConst(_, _) => List() - case ClassConst(_, _) => List() - case DynamicConst(_, _, _, _) => List() - case NullExpr(_) => List() - case BinaryExpr(_, _, _, left, right) => - processExpr(right) ++ processExpr(left) - case PrefixExpr(_, _, _, operand: IdBasedVar) => List(operand) - case PrimitiveTypecastExpr(_, _, operand: IdBasedVar) => List(operand) - case New(_, _) => List() - case NewArray(_, counts: Seq[_], _) => counts.map(c => c.asVar).toList - case ArrayLoad(_, index: IdBasedVar, arrayRef: IdBasedVar) => - List(index, arrayRef) - case ArrayLength(_, arrayRef: IdBasedVar) => List(arrayRef) - case GetField(_, _, _, _, objRef: IdBasedVar) => List(objRef) - case GetStatic(_, _, _, _) => List() - case InvokedynamicFunctionCall(_, _, _, _, params: Seq[_]) => - params.map(p => p.asVar).toList.reverse - case NonVirtualFunctionCall( - _, - _, - _, - _, - _, - receiver: IdBasedVar, - params: Seq[_] - ) => - params.map(p => p.asVar).toList.reverse :+ receiver - case VirtualFunctionCall( - _, - _, - _, - _, - _, - receiver: IdBasedVar, - params: Seq[_] - ) => - params.map(p => p.asVar).toList.reverse :+ receiver - case StaticFunctionCall(_, _, _, _, _, params: Seq[_]) => - params.map(p => p.asVar).toList.reverse - case _ => throw new RuntimeException("Unknown expression: " + expr) + schedule(pcOfNextStatement(pc), stack) + case DUP2_X2.opcode => + val v1 = stack.pop + val v2 = stack.pop + val v3 = stack.pop + + if (v1.cTpe.categoryId == 1 && v2.cTpe.categoryId == 1 && v3.cTpe.categoryId == 1) { + val v4 = stack.pop + + stack.push(v2) + stack.push(v1) + stack.push(v4) + stack.push(v3) + stack.push(v2) + stack.push(v1) + } else if (v1.cTpe.categoryId == 2 && v2.cTpe.categoryId == 1 && v3.cTpe.categoryId == 1) { + stack.push(v1) + stack.push(v3) + stack.push(v2) + stack.push(v1) + } else if (v1.cTpe.categoryId == 1 && v2.cTpe.categoryId == 1 && v3.cTpe.categoryId == 2) { + stack.push(v2) + stack.push(v1) + stack.push(v3) + stack.push(v2) + stack.push(v1) + } else { + stack.push(v3) + stack.push(v1) + stack.push(v2) + stack.push(v1) } - } + schedule(pcOfNextStatement(pc), stack) + case WIDE.opcode => + schedule(pcOfNextStatement(pc), stack) + case _ => + throw new RuntimeException( + "Unknown instruction for NOP: " + instr + ) + } + case MonitorEnter(pc, objRef: IdBasedVar) => + stack.pop(objRef) + + schedule(pcOfNextStatement(pc), stack) + case MonitorExit(pc, objRef: IdBasedVar) => + stack.pop(objRef) + + schedule(pcOfNextStatement(pc), stack) + case ArrayStore( + pc, + arrayRef: IdBasedVar, + index: IdBasedVar, + value: IdBasedVar + ) => + stack.pop(value) + stack.pop(index) + stack.pop(arrayRef) + + schedule(pcOfNextStatement(pc), stack) + case Throw(_, exception: IdBasedVar) => + stack.pop(exception) + // No scheduling since there is no next statement + case PutStatic(pc, _, _, _, value: IdBasedVar) => + stack.pop(value) + + schedule(pcOfNextStatement(pc), stack) + case PutField(pc, _, _, _, objRef: IdBasedVar, value: IdBasedVar) => + stack.pop(value) + stack.pop(objRef) + + schedule(pcOfNextStatement(pc), stack) + case NonVirtualMethodCall( + pc, + _, + _, + _, + _, + receiver: IdBasedVar, + params: Seq[_] + ) => + params.reverse.foreach(p => stack.pop(p.asVar)) + stack.pop(receiver) + + schedule(pcOfNextStatement(pc), stack) + case VirtualMethodCall( + pc, + _, + _, + _, + _, + receiver: IdBasedVar, + params: Seq[_] + ) => + params.reverse.foreach(p => stack.pop(p.asVar)) + stack.pop(receiver) + + schedule(pcOfNextStatement(pc), stack) + case StaticMethodCall(pc, _, _, _, _, params: Seq[_]) => + params.reverse.foreach(p => stack.pop(p.asVar)) + + schedule(pcOfNextStatement(pc), stack) + case InvokedynamicMethodCall(pc, _, _, _, params: Seq[_]) => + params.reverse.foreach(p => stack.pop(p.asVar)) + + schedule(pcOfNextStatement(pc), stack) + case ExprStmt(pc, expr) => + processExpr(expr) + + schedule(pcOfNextStatement(pc), stack) + case CaughtException(pc, _, _) => + // Only used in TACAI, so no stack manipulation is required + schedule(pcOfNextStatement(pc), stack) + case Checkcast(pc, value, _) => + // TODO + // Soot transforms casts into assignments (s0 = (Class) s0), so + // we may do the same (not relevant for Boomerang + schedule(pcOfNextStatement(pc), stack) + case _ => throw new RuntimeException("Unknown statement: " + stmt) } - stackHandler + } + + def processExpr(expr: Expr[IdBasedVar]): List[IdBasedVar] = { + expr match { + case v: IdBasedVar => if (v.id >= 0) List(v) else List() + case InstanceOf(_, value: IdBasedVar, _) => List(value) + case Compare(_, left: IdBasedVar, _, right: IdBasedVar) => + List(right, left) + case Param(_, _) => List() + case MethodTypeConst(_, _) => List() + case MethodHandleConst(_, _) => List() + case IntConst(_, _) => List() + case LongConst(_, _) => List() + case FloatConst(_, _) => List() + case DoubleConst(_, _) => List() + case StringConst(_, _) => List() + case ClassConst(_, _) => List() + case DynamicConst(_, _, _, _) => List() + case NullExpr(_) => List() + case BinaryExpr(_, _, _, left, right) => + processExpr(right) ++ processExpr(left) + case PrefixExpr(_, _, _, operand: IdBasedVar) => List(operand) + case PrimitiveTypecastExpr(_, _, operand: IdBasedVar) => List(operand) + case New(_, _) => List() + case NewArray(_, counts: Seq[_], _) => counts.map(c => c.asVar).toList + case ArrayLoad(_, index: IdBasedVar, arrayRef: IdBasedVar) => + List(index, arrayRef) + case ArrayLength(_, arrayRef: IdBasedVar) => List(arrayRef) + case GetField(_, _, _, _, objRef: IdBasedVar) => List(objRef) + case GetStatic(_, _, _, _) => List() + case InvokedynamicFunctionCall(_, _, _, _, params: Seq[_]) => + params.map(p => p.asVar).toList.reverse + case NonVirtualFunctionCall( + _, + _, + _, + _, + _, + receiver: IdBasedVar, + params: Seq[_] + ) => + params.map(p => p.asVar).toList.reverse :+ receiver + case VirtualFunctionCall( + _, + _, + _, + _, + _, + receiver: IdBasedVar, + params: Seq[_] + ) => + params.map(p => p.asVar).toList.reverse :+ receiver + case StaticFunctionCall(_, _, _, _, _, params: Seq[_]) => + params.map(p => p.asVar).toList.reverse + case _ => throw new RuntimeException("Unknown expression: " + expr) + } + } + } + stackHandler + } } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackHandler.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackHandler.scala index 662c790e6..b69173cb2 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackHandler.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/stack/OperandStackHandler.scala @@ -19,85 +19,85 @@ import scala.collection.mutable class OperandStackHandler { - private val pcToStack = mutable.Map.empty[PC, OperandStack] - private val defSites = mutable.Map.empty[PC, Operand] - private var localCounter = -1 - - def getOrCreate(pc: PC): OperandStack = { - if (pcToStack.contains(pc)) { - pcToStack(pc).copy - } else { - val stack = OperandStack(this) - pcToStack.put(pc, stack) - - stack.copy - } + private val pcToStack = mutable.Map.empty[PC, OperandStack] + private val defSites = mutable.Map.empty[PC, Operand] + private var localCounter = -1 + + def getOrCreate(pc: PC): OperandStack = { + if (pcToStack.contains(pc)) { + pcToStack(pc).copy + } else { + val stack = OperandStack(this) + pcToStack.put(pc, stack) + + stack.copy } - - def addDefSite(pc: PC, operand: Operand): Unit = { - defSites.put(pc, operand) - } - - def mergeStack(nextPc: PC, incomingStack: OperandStack): Boolean = { - val existingStack = pcToStack.getOrElse(nextPc, null) - - if (existingStack == null) { - pcToStack.put(nextPc, incomingStack) - - true - } else { - var modified = false - existingStack.stackEntries.foreach(existingOp => { - incomingStack.stackEntries.foreach(incomingOp => { - if (existingOp.id == incomingOp.id) { - // Update the counter of the incoming operand s.t. both operands describe - // the same local and mark both operands as branched - existingOp.updateCounter(existingOp.localId) - incomingOp.updateCounter(existingOp.localId) - - // TODO Merge types - - modified = true - } - }) - }) - modified - } - } - - def nextLocalCounter: Int = { - localCounter += 1 - - localCounter - } - - def defSiteAtPc(pc: PC): Int = defSites - .getOrElse( - pc, - throw new RuntimeException(s"No operand definition at PC $pc") - ) - .localId - - def counterForOperand(pc: PC, id: Int, isReturn: Boolean = false): Int = { - val stack = pcToStack.getOrElse( - pc, - throw new RuntimeException(s"Stack for PC $pc not available") - ) - stack.stackEntries.foreach(op => if (op.id == id) return op.localId) - - // TODO Bug in Opal: Return always has id 0, even if it may have another id - if (isReturn) return stack.stackEntries.head.localId - - throw new RuntimeException(s"Could not find operand with id $id on stack") - } - - def isBranchedOperand(pc: PC, id: Int): Boolean = { - val defSite = defSites.getOrElse( - pc, - throw new RuntimeException(s"No def site found at pc $pc") - ) - - defSite.isBranchedOperand + } + + def addDefSite(pc: PC, operand: Operand): Unit = { + defSites.put(pc, operand) + } + + def mergeStack(nextPc: PC, incomingStack: OperandStack): Boolean = { + val existingStack = pcToStack.getOrElse(nextPc, null) + + if (existingStack == null) { + pcToStack.put(nextPc, incomingStack) + + true + } else { + var modified = false + existingStack.stackEntries.foreach(existingOp => { + incomingStack.stackEntries.foreach(incomingOp => { + if (existingOp.id == incomingOp.id) { + // Update the counter of the incoming operand s.t. both operands describe + // the same local and mark both operands as branched + existingOp.updateCounter(existingOp.localId) + incomingOp.updateCounter(existingOp.localId) + + // TODO Merge types + + modified = true + } + }) + }) + modified } + } + + def nextLocalCounter: Int = { + localCounter += 1 + + localCounter + } + + def defSiteAtPc(pc: PC): Int = defSites + .getOrElse( + pc, + throw new RuntimeException(s"No operand definition at PC $pc") + ) + .localId + + def counterForOperand(pc: PC, id: Int, isReturn: Boolean = false): Int = { + val stack = pcToStack.getOrElse( + pc, + throw new RuntimeException(s"Stack for PC $pc not available") + ) + stack.stackEntries.foreach(op => if (op.id == id) return op.localId) + + // TODO Bug in Opal: Return always has id 0, even if it may have another id + if (isReturn) return stack.stackEntries.head.localId + + throw new RuntimeException(s"Could not find operand with id $id on stack") + } + + def isBranchedOperand(pc: PC, id: Int): Boolean = { + val defSite = defSites.getOrElse( + pc, + throw new RuntimeException(s"No def site found at pc $pc") + ) + + defSite.isBranchedOperand + } } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/InlineLocalTransformer.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/InlineLocalTransformer.scala index 19e69618c..cf41ffd93 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/InlineLocalTransformer.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/InlineLocalTransformer.scala @@ -23,137 +23,137 @@ import scala.collection.mutable object InlineLocalTransformer { - def apply( - code: Array[Stmt[TacLocal]], - stackHandler: OperandStackHandler - ): Array[Stmt[TacLocal]] = { - val statements = code.map(identity) - - val localCache = mutable.Map.empty[TacLocal, Expr[TacLocal]] - val localDefSites = mutable.Map.empty[TacLocal, (Int, Int)] - - val max = code.length - 1 - Range(0, max).foreach(i => { - statements(i) match { - // Collect all expressions that may replace stack to register assignments - case Assignment(pc, targetVar: StackLocal, c @ (_: SimpleValueConst)) => - if (!stackHandler.isBranchedOperand(pc, targetVar.id)) { - if (localCache.contains(targetVar)) { - throw new RuntimeException("Did not discover branched operand") - } - - localCache.put(targetVar, c) - localDefSites.put(targetVar, (i, pc)) - } - // Replace stack to register expressions if possible: - // r = $s becomes r = from previous assignment $s = - case Assignment(pc, targetVar: RegisterLocal, rightVar: StackLocal) => - /*if (localCache.contains(rightVar)) { + def apply( + code: Array[Stmt[TacLocal]], + stackHandler: OperandStackHandler + ): Array[Stmt[TacLocal]] = { + val statements = code.map(identity) + + val localCache = mutable.Map.empty[TacLocal, Expr[TacLocal]] + val localDefSites = mutable.Map.empty[TacLocal, (Int, Int)] + + val max = code.length - 1 + Range(0, max).foreach(i => { + statements(i) match { + // Collect all expressions that may replace stack to register assignments + case Assignment(pc, targetVar: StackLocal, c @ (_: SimpleValueConst)) => + if (!stackHandler.isBranchedOperand(pc, targetVar.id)) { + if (localCache.contains(targetVar)) { + throw new RuntimeException("Did not discover branched operand") + } + + localCache.put(targetVar, c) + localDefSites.put(targetVar, (i, pc)) + } + // Replace stack to register expressions if possible: + // r = $s becomes r = from previous assignment $s = + case Assignment(pc, targetVar: RegisterLocal, rightVar: StackLocal) => + /*if (localCache.contains(rightVar)) { val localExpr = localCache(rightVar) statements(i) = Assignment(pc, targetVar, localExpr) val localDefSite = localDefSites.getOrElse(rightVar, throw new RuntimeException("Def sites not consistent")) statements(localDefSite._1) = Nop(localDefSite._2) }*/ - // Array related assignments - case Assignment(pc, targetVar: StackLocal, expr) => - expr match { - // Replace the counts in new array creation with concrete integers if available - case NewArray(arrPc, counts, arrayType) => - var countDefSites = List.empty[(Int, Int)] - - val newCounts = counts.map(c => { - if (c.isVar && localCache.contains(c.asVar)) { - val localExpr = localCache(c.asVar) - - if (localExpr.isIntConst) { - val countDefSite = localDefSites.getOrElse( - c.asVar, - throw new RuntimeException("Def sites not consistent") - ) - countDefSites = countDefSites :+ countDefSite - - localExpr - } else { - c - } - } else { - c - } - }) - - statements(i) = Assignment(pc, targetVar, NewArray(arrPc, newCounts, arrayType)) - countDefSites.foreach(defSite => statements(defSite._1) = Nop(defSite._2)) - // Replace the index expression with the concrete integer value if available - case ArrayLoad(arrPc, arrayIndex: StackLocal, arrayRef) => - if (localCache.contains(arrayIndex)) { - val localExpr = localCache(arrayIndex) - - if (localExpr.isIntConst) { - statements(i) = Assignment( - pc, - targetVar, - ArrayLoad(arrPc, localExpr, arrayRef) - ) - - val localDefSite = localDefSites.getOrElse( - arrayIndex, - throw new RuntimeException("Def sites not consistent") - ) - statements(localDefSite._1) = Nop(localDefSite._2) - } - } - case _ => - } - case ArrayStore(pc, arrayRef, arrayIndex: StackLocal, value) => - if (localCache.contains(arrayIndex)) { - val localExpr = localCache(arrayIndex) - - if (localExpr.isIntConst) { - // TODO Also inline value if it is a simple constant - statements(i) = ArrayStore(pc, arrayRef, localExpr, value) - - val localDefSite = localDefSites.getOrElse( - arrayIndex, - throw new RuntimeException("Def sites not consistent") - ) - statements(localDefSite._1) = Nop(localDefSite._2) - } - } - case _ => - } - }) - - Range(0, max).foreach(i => { - statements(i) match { - - /* Inline simple stack to register definitions: - * $s = - * r = $s - * - * becomes - * r = - */ - case Assignment( - pc, - targetVar: StackLocal, - c @ (_: SimpleValueConst | _: FunctionCall[TacLocal] | _: NewArray[TacLocal] | - _: ArrayLoad[TacLocal] | _: GetField[TacLocal] | _: GetStatic) - ) => - statements(i + 1) match { - case Assignment( - nextPc, - nextTargetVar: RegisterLocal, - `targetVar` - ) => - statements(i) = Nop(pc) - statements(i + 1) = Assignment(nextPc, nextTargetVar, c) - case _ => - } - case _ => + // Array related assignments + case Assignment(pc, targetVar: StackLocal, expr) => + expr match { + // Replace the counts in new array creation with concrete integers if available + case NewArray(arrPc, counts, arrayType) => + var countDefSites = List.empty[(Int, Int)] + + val newCounts = counts.map(c => { + if (c.isVar && localCache.contains(c.asVar)) { + val localExpr = localCache(c.asVar) + + if (localExpr.isIntConst) { + val countDefSite = localDefSites.getOrElse( + c.asVar, + throw new RuntimeException("Def sites not consistent") + ) + countDefSites = countDefSites :+ countDefSite + + localExpr + } else { + c + } + } else { + c + } + }) + + statements(i) = Assignment(pc, targetVar, NewArray(arrPc, newCounts, arrayType)) + countDefSites.foreach(defSite => statements(defSite._1) = Nop(defSite._2)) + // Replace the index expression with the concrete integer value if available + case ArrayLoad(arrPc, arrayIndex: StackLocal, arrayRef) => + if (localCache.contains(arrayIndex)) { + val localExpr = localCache(arrayIndex) + + if (localExpr.isIntConst) { + statements(i) = Assignment( + pc, + targetVar, + ArrayLoad(arrPc, localExpr, arrayRef) + ) + + val localDefSite = localDefSites.getOrElse( + arrayIndex, + throw new RuntimeException("Def sites not consistent") + ) + statements(localDefSite._1) = Nop(localDefSite._2) + } + } + case _ => + } + case ArrayStore(pc, arrayRef, arrayIndex: StackLocal, value) => + if (localCache.contains(arrayIndex)) { + val localExpr = localCache(arrayIndex) + + if (localExpr.isIntConst) { + // TODO Also inline value if it is a simple constant + statements(i) = ArrayStore(pc, arrayRef, localExpr, value) + + val localDefSite = localDefSites.getOrElse( + arrayIndex, + throw new RuntimeException("Def sites not consistent") + ) + statements(localDefSite._1) = Nop(localDefSite._2) } - }) - - statements - } + } + case _ => + } + }) + + Range(0, max).foreach(i => { + statements(i) match { + + /* Inline simple stack to register definitions: + * $s = + * r = $s + * + * becomes + * r = + */ + case Assignment( + pc, + targetVar: StackLocal, + c @ (_: SimpleValueConst | _: FunctionCall[TacLocal] | _: NewArray[TacLocal] | _: ArrayLoad[TacLocal] | + _: GetField[TacLocal] | _: GetStatic) + ) => + statements(i + 1) match { + case Assignment( + nextPc, + nextTargetVar: RegisterLocal, + `targetVar` + ) => + statements(i) = Nop(pc) + statements(i + 1) = Assignment(nextPc, nextTargetVar, c) + case _ => + } + case _ => + } + }) + + statements + } } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/LocalPropagationTransformer.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/LocalPropagationTransformer.scala index 9685f188d..cfbf92cdd 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/LocalPropagationTransformer.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/LocalPropagationTransformer.scala @@ -54,456 +54,456 @@ import org.opalj.tac.VirtualMethodCall object LocalPropagationTransformer { - def apply( - code: Array[Stmt[TacLocal]], - stackHandler: OperandStackHandler - ): Array[Stmt[TacLocal]] = { - val statements = code.map(identity) - - val max = code.length - 1 - Range(0, max).foreach(i => { - statements(i) match { - // If we have an assignment $s = r, we replace $s with r in all following statements - case Assignment( - pc, - stackLocal: StackLocal, - registerLocal: RegisterLocal - ) => - if (!stackHandler.isBranchedOperand(pc, stackLocal.id)) { - Range - .inclusive(i + 1, max) - .foreach(j => { - val currStmt = statements(j) - statements(j) = updateStatementWithLocal(currStmt, stackLocal, registerLocal) - }) - - statements(i) = Nop(pc) - } - case _ => - } - }) - - def updateStatementWithLocal( - stmt: Stmt[TacLocal], - stackLocal: StackLocal, - registerLocal: RegisterLocal - ): Stmt[TacLocal] = { - stmt.astID match { - case If.ASTID => - val ifStmt = stmt.asIf - - val left = - updateExpressionWithLocal(ifStmt.left, stackLocal, registerLocal) - val right = - updateExpressionWithLocal(ifStmt.left, stackLocal, registerLocal) - - return If(ifStmt.pc, left, ifStmt.condition, right, ifStmt.targetStmt) - case Switch.ASTID => - val switchStmt = stmt.asSwitch - val index = updateExpressionWithLocal( - switchStmt.index, - stackLocal, - registerLocal - ) - - return Switch( - switchStmt.pc, - switchStmt.defaultStmt, - index, - switchStmt.caseStmts.map(p => IntIntPair(-1, p)) - ) - case Assignment.ASTID => - val assignStmt = stmt.asAssignment - val targetVar = updateExpressionWithLocal( - assignStmt.targetVar, - stackLocal, - registerLocal - ) - val expr = updateExpressionWithLocal( - assignStmt.expr, - stackLocal, - registerLocal - ) - - return Assignment(assignStmt.pc, targetVar.asVar, expr) - case ReturnValue.ASTID => - val expr = updateExpressionWithLocal( - stmt.asReturnValue.expr, - stackLocal, - registerLocal - ) - - return ReturnValue(stmt.pc, expr) - case MonitorEnter.ASTID => - val objRef = updateExpressionWithLocal( - stmt.asMonitorEnter.objRef, - stackLocal, - registerLocal - ) - - return MonitorEnter(stmt.pc, objRef) - case MonitorExit.ASTID => - val objRef = updateExpressionWithLocal( - stmt.asMonitorExit.objRef, - stackLocal, - registerLocal - ) - - return MonitorExit(stmt.pc, objRef) - case ArrayStore.ASTID => - val arrayStore = stmt.asArrayStore - - val arrayRef = updateExpressionWithLocal( - arrayStore.arrayRef, - stackLocal, - registerLocal - ) - val index = updateExpressionWithLocal( - arrayStore.index, - stackLocal, - registerLocal - ) - val value = updateExpressionWithLocal( - arrayStore.value, - stackLocal, - registerLocal - ) - - return ArrayStore(arrayStore.pc, arrayRef, index, value) - case Throw.ASTID => - val throwStmt = stmt.asThrow - val exception = updateExpressionWithLocal( - throwStmt.exception, - stackLocal, - registerLocal - ) - - return Throw(throwStmt.pc, exception) - case PutStatic.ASTID => - val putStatic = stmt.asPutStatic - val value = updateExpressionWithLocal( - putStatic.value, - stackLocal, - registerLocal - ) - - return PutStatic( - putStatic.pc, - putStatic.declaringClass, - putStatic.name, - putStatic.declaredFieldType, - value - ) - case PutField.ASTID => - val putField = stmt.asPutField - - val objRef = updateExpressionWithLocal( - putField.objRef, - stackLocal, - registerLocal - ) - val value = - updateExpressionWithLocal(putField.value, stackLocal, registerLocal) - - return PutField( - putField.pc, - putField.declaringClass, - putField.name, - putField.declaredFieldType, - objRef, - value - ) - case NonVirtualMethodCall.ASTID => - val methodCall = stmt.asNonVirtualMethodCall - - val baseLocal = updateExpressionWithLocal( - methodCall.receiver, - stackLocal, - registerLocal - ) - val paramLocals = - methodCall.params.map(p => updateExpressionWithLocal(p, stackLocal, registerLocal)) - - return NonVirtualMethodCall( - methodCall.pc, - methodCall.declaringClass, - methodCall.isInterface, - methodCall.name, - methodCall.descriptor, - baseLocal, - paramLocals - ) - case VirtualMethodCall.ASTID => - val methodCall = stmt.asVirtualMethodCall - - val baseLocal = updateExpressionWithLocal( - methodCall.receiver, - stackLocal, - registerLocal - ) - val paramLocals = - methodCall.params.map(p => updateExpressionWithLocal(p, stackLocal, registerLocal)) - - return VirtualMethodCall( - methodCall.pc, - methodCall.declaringClass, - methodCall.isInterface, - methodCall.name, - methodCall.descriptor, - baseLocal, - paramLocals - ) - case StaticMethodCall.ASTID => - val methodCall = stmt.asStaticMethodCall - val params = methodCall.params.map(p => updateExpressionWithLocal(p, stackLocal, registerLocal)) - - return StaticMethodCall( - methodCall.pc, - methodCall.declaringClass, - methodCall.isInterface, - methodCall.name, - methodCall.descriptor, - params - ) - case InvokedynamicMethodCall.ASTID => - val methodCall = stmt.asInvokedynamicMethodCall - val params = methodCall.params.map(p => updateExpressionWithLocal(p, stackLocal, registerLocal)) - - return InvokedynamicMethodCall( - methodCall.pc, - methodCall.bootstrapMethod, - methodCall.name, - methodCall.descriptor, - params - ) - case ExprStmt.ASTID => - val expr = updateExpressionWithLocal( - stmt.asExprStmt.expr, - stackLocal, - registerLocal - ) - - return ExprStmt(stmt.pc, expr) - case Checkcast.ASTID => - val castExpr = stmt.asCheckcast - val value = - updateExpressionWithLocal(castExpr.value, stackLocal, registerLocal) - - return Checkcast(castExpr.pc, value, castExpr.cmpTpe) - case _ => return stmt - } - - throw new RuntimeException("Could not update statement: " + stmt) - } + def apply( + code: Array[Stmt[TacLocal]], + stackHandler: OperandStackHandler + ): Array[Stmt[TacLocal]] = { + val statements = code.map(identity) + + val max = code.length - 1 + Range(0, max).foreach(i => { + statements(i) match { + // If we have an assignment $s = r, we replace $s with r in all following statements + case Assignment( + pc, + stackLocal: StackLocal, + registerLocal: RegisterLocal + ) => + if (!stackHandler.isBranchedOperand(pc, stackLocal.id)) { + Range + .inclusive(i + 1, max) + .foreach(j => { + val currStmt = statements(j) + statements(j) = updateStatementWithLocal(currStmt, stackLocal, registerLocal) + }) + + statements(i) = Nop(pc) + } + case _ => + } + }) + + def updateStatementWithLocal( + stmt: Stmt[TacLocal], + stackLocal: StackLocal, + registerLocal: RegisterLocal + ): Stmt[TacLocal] = { + stmt.astID match { + case If.ASTID => + val ifStmt = stmt.asIf + + val left = + updateExpressionWithLocal(ifStmt.left, stackLocal, registerLocal) + val right = + updateExpressionWithLocal(ifStmt.left, stackLocal, registerLocal) + + return If(ifStmt.pc, left, ifStmt.condition, right, ifStmt.targetStmt) + case Switch.ASTID => + val switchStmt = stmt.asSwitch + val index = updateExpressionWithLocal( + switchStmt.index, + stackLocal, + registerLocal + ) + + return Switch( + switchStmt.pc, + switchStmt.defaultStmt, + index, + switchStmt.caseStmts.map(p => IntIntPair(-1, p)) + ) + case Assignment.ASTID => + val assignStmt = stmt.asAssignment + val targetVar = updateExpressionWithLocal( + assignStmt.targetVar, + stackLocal, + registerLocal + ) + val expr = updateExpressionWithLocal( + assignStmt.expr, + stackLocal, + registerLocal + ) + + return Assignment(assignStmt.pc, targetVar.asVar, expr) + case ReturnValue.ASTID => + val expr = updateExpressionWithLocal( + stmt.asReturnValue.expr, + stackLocal, + registerLocal + ) + + return ReturnValue(stmt.pc, expr) + case MonitorEnter.ASTID => + val objRef = updateExpressionWithLocal( + stmt.asMonitorEnter.objRef, + stackLocal, + registerLocal + ) + + return MonitorEnter(stmt.pc, objRef) + case MonitorExit.ASTID => + val objRef = updateExpressionWithLocal( + stmt.asMonitorExit.objRef, + stackLocal, + registerLocal + ) + + return MonitorExit(stmt.pc, objRef) + case ArrayStore.ASTID => + val arrayStore = stmt.asArrayStore + + val arrayRef = updateExpressionWithLocal( + arrayStore.arrayRef, + stackLocal, + registerLocal + ) + val index = updateExpressionWithLocal( + arrayStore.index, + stackLocal, + registerLocal + ) + val value = updateExpressionWithLocal( + arrayStore.value, + stackLocal, + registerLocal + ) + + return ArrayStore(arrayStore.pc, arrayRef, index, value) + case Throw.ASTID => + val throwStmt = stmt.asThrow + val exception = updateExpressionWithLocal( + throwStmt.exception, + stackLocal, + registerLocal + ) + + return Throw(throwStmt.pc, exception) + case PutStatic.ASTID => + val putStatic = stmt.asPutStatic + val value = updateExpressionWithLocal( + putStatic.value, + stackLocal, + registerLocal + ) + + return PutStatic( + putStatic.pc, + putStatic.declaringClass, + putStatic.name, + putStatic.declaredFieldType, + value + ) + case PutField.ASTID => + val putField = stmt.asPutField + + val objRef = updateExpressionWithLocal( + putField.objRef, + stackLocal, + registerLocal + ) + val value = + updateExpressionWithLocal(putField.value, stackLocal, registerLocal) + + return PutField( + putField.pc, + putField.declaringClass, + putField.name, + putField.declaredFieldType, + objRef, + value + ) + case NonVirtualMethodCall.ASTID => + val methodCall = stmt.asNonVirtualMethodCall + + val baseLocal = updateExpressionWithLocal( + methodCall.receiver, + stackLocal, + registerLocal + ) + val paramLocals = + methodCall.params.map(p => updateExpressionWithLocal(p, stackLocal, registerLocal)) + + return NonVirtualMethodCall( + methodCall.pc, + methodCall.declaringClass, + methodCall.isInterface, + methodCall.name, + methodCall.descriptor, + baseLocal, + paramLocals + ) + case VirtualMethodCall.ASTID => + val methodCall = stmt.asVirtualMethodCall + + val baseLocal = updateExpressionWithLocal( + methodCall.receiver, + stackLocal, + registerLocal + ) + val paramLocals = + methodCall.params.map(p => updateExpressionWithLocal(p, stackLocal, registerLocal)) + + return VirtualMethodCall( + methodCall.pc, + methodCall.declaringClass, + methodCall.isInterface, + methodCall.name, + methodCall.descriptor, + baseLocal, + paramLocals + ) + case StaticMethodCall.ASTID => + val methodCall = stmt.asStaticMethodCall + val params = methodCall.params.map(p => updateExpressionWithLocal(p, stackLocal, registerLocal)) + + return StaticMethodCall( + methodCall.pc, + methodCall.declaringClass, + methodCall.isInterface, + methodCall.name, + methodCall.descriptor, + params + ) + case InvokedynamicMethodCall.ASTID => + val methodCall = stmt.asInvokedynamicMethodCall + val params = methodCall.params.map(p => updateExpressionWithLocal(p, stackLocal, registerLocal)) + + return InvokedynamicMethodCall( + methodCall.pc, + methodCall.bootstrapMethod, + methodCall.name, + methodCall.descriptor, + params + ) + case ExprStmt.ASTID => + val expr = updateExpressionWithLocal( + stmt.asExprStmt.expr, + stackLocal, + registerLocal + ) + + return ExprStmt(stmt.pc, expr) + case Checkcast.ASTID => + val castExpr = stmt.asCheckcast + val value = + updateExpressionWithLocal(castExpr.value, stackLocal, registerLocal) + + return Checkcast(castExpr.pc, value, castExpr.cmpTpe) + case _ => return stmt + } + + throw new RuntimeException("Could not update statement: " + stmt) + } - def updateExpressionWithLocal( - expr: Expr[TacLocal], - stackLocal: StackLocal, - registerLocal: RegisterLocal - ): Expr[TacLocal] = { - if (expr.isVar) { - if (expr.asVar.isRegisterLocal) return expr - - // Replace stack local with register local - if (expr.asVar.isStackLocal && expr.asVar == stackLocal) { - return registerLocal - } else { - return expr - } - } - - expr.astID match { - case InstanceOf.ASTID => - val instanceOf = expr.asInstanceOf - val value = updateExpressionWithLocal( - instanceOf.value, - stackLocal, - registerLocal - ) - - return InstanceOf(instanceOf.pc, value, instanceOf.cmpTpe) - case Compare.ASTID => - val compareExpr = expr.asCompare - - val leftLocal = updateExpressionWithLocal( - compareExpr.left, - stackLocal, - registerLocal - ) - val rightLocal = updateExpressionWithLocal( - compareExpr.right, - stackLocal, - registerLocal - ) - - return Compare( - compareExpr.pc, - leftLocal, - compareExpr.condition, - rightLocal - ) - case BinaryExpr.ASTID => - val binaryExpr = expr.asBinaryExpr - - val left = updateExpressionWithLocal( - binaryExpr.left, - stackLocal, - registerLocal - ) - val right = updateExpressionWithLocal( - binaryExpr.right, - stackLocal, - registerLocal - ) - - return BinaryExpr( - binaryExpr.pc, - binaryExpr.cTpe, - binaryExpr.op, - left, - right - ) - case PrefixExpr.ASTID => - val prefixExpr = expr.asPrefixExpr - val operand = updateExpressionWithLocal( - prefixExpr.operand, - stackLocal, - registerLocal - ) - - return PrefixExpr( - prefixExpr.pc, - prefixExpr.cTpe, - prefixExpr.op, - operand - ) - case PrimitiveTypecastExpr.ASTID => - val primitiveTypecastExpr = expr.asPrimitiveTypeCastExpr - val operand = updateExpressionWithLocal( - primitiveTypecastExpr.operand, - stackLocal, - registerLocal - ) - - return PrimitiveTypecastExpr( - primitiveTypecastExpr.pc, - primitiveTypecastExpr.targetTpe, - operand - ) - case NewArray.ASTID => - val newArray = expr.asNewArray - val counts = newArray.counts.map(c => updateExpressionWithLocal(c, stackLocal, registerLocal)) - - return NewArray(newArray.pc, counts, newArray.tpe) - case ArrayLoad.ASTID => - val arrayLoad = expr.asArrayLoad - - val index = updateExpressionWithLocal( - arrayLoad.index, - stackLocal, - registerLocal - ) - val arrayRef = updateExpressionWithLocal( - arrayLoad.arrayRef, - stackLocal, - registerLocal - ) - - return ArrayLoad(arrayLoad.pc, index, arrayRef) - case ArrayLength.ASTID => - val arrayLength = expr.asArrayLength - val arrayRef = updateExpressionWithLocal( - arrayLength.arrayRef, - stackLocal, - registerLocal - ) - - return ArrayLength(arrayLength.pc, arrayRef) - case GetField.ASTID => - val getField = expr.asGetField - val objRef = updateExpressionWithLocal( - getField.objRef, - stackLocal, - registerLocal - ) - - return GetField( - getField.pc, - getField.declaringClass, - getField.name, - getField.declaredFieldType, - objRef - ) - case InvokedynamicFunctionCall.ASTID => - val functionCall = expr.asInvokedynamicFunctionCall - val params = functionCall.params.map(p => updateExpressionWithLocal(p, stackLocal, registerLocal)) - - return InvokedynamicFunctionCall( - functionCall.pc, - functionCall.bootstrapMethod, - functionCall.name, - functionCall.descriptor, - params - ) - case NonVirtualFunctionCall.ASTID => - val functionCall = expr.asNonVirtualFunctionCall - - val base = updateExpressionWithLocal( - functionCall.receiver, - stackLocal, - registerLocal - ) - val params = functionCall.params.map(p => updateExpressionWithLocal(p, stackLocal, registerLocal)) - - return NonVirtualFunctionCall( - functionCall.pc, - functionCall.declaringClass, - functionCall.isInterface, - functionCall.name, - functionCall.descriptor, - base, - params - ) - case VirtualFunctionCall.ASTID => - val functionCall = expr.asVirtualFunctionCall - - val base = updateExpressionWithLocal( - functionCall.receiver, - stackLocal, - registerLocal - ) - val params = functionCall.params.map(p => updateExpressionWithLocal(p, stackLocal, registerLocal)) - - return VirtualFunctionCall( - functionCall.pc, - functionCall.declaringClass, - functionCall.isInterface, - functionCall.name, - functionCall.descriptor, - base, - params - ) - case StaticFunctionCall.ASTID => - val functionCall = expr.asStaticFunctionCall - - val params = functionCall.params - val paramLocals = - params.map(p => updateExpressionWithLocal(p, stackLocal, registerLocal)) - - return StaticFunctionCall( - functionCall.pc, - functionCall.declaringClass, - functionCall.isInterface, - functionCall.name, - functionCall.descriptor, - paramLocals - ) - case _ => return expr - } - - throw new RuntimeException("Could not update expression: " + expr) + def updateExpressionWithLocal( + expr: Expr[TacLocal], + stackLocal: StackLocal, + registerLocal: RegisterLocal + ): Expr[TacLocal] = { + if (expr.isVar) { + if (expr.asVar.isRegisterLocal) return expr + + // Replace stack local with register local + if (expr.asVar.isStackLocal && expr.asVar == stackLocal) { + return registerLocal + } else { + return expr } - - statements + } + + expr.astID match { + case InstanceOf.ASTID => + val instanceOf = expr.asInstanceOf + val value = updateExpressionWithLocal( + instanceOf.value, + stackLocal, + registerLocal + ) + + return InstanceOf(instanceOf.pc, value, instanceOf.cmpTpe) + case Compare.ASTID => + val compareExpr = expr.asCompare + + val leftLocal = updateExpressionWithLocal( + compareExpr.left, + stackLocal, + registerLocal + ) + val rightLocal = updateExpressionWithLocal( + compareExpr.right, + stackLocal, + registerLocal + ) + + return Compare( + compareExpr.pc, + leftLocal, + compareExpr.condition, + rightLocal + ) + case BinaryExpr.ASTID => + val binaryExpr = expr.asBinaryExpr + + val left = updateExpressionWithLocal( + binaryExpr.left, + stackLocal, + registerLocal + ) + val right = updateExpressionWithLocal( + binaryExpr.right, + stackLocal, + registerLocal + ) + + return BinaryExpr( + binaryExpr.pc, + binaryExpr.cTpe, + binaryExpr.op, + left, + right + ) + case PrefixExpr.ASTID => + val prefixExpr = expr.asPrefixExpr + val operand = updateExpressionWithLocal( + prefixExpr.operand, + stackLocal, + registerLocal + ) + + return PrefixExpr( + prefixExpr.pc, + prefixExpr.cTpe, + prefixExpr.op, + operand + ) + case PrimitiveTypecastExpr.ASTID => + val primitiveTypecastExpr = expr.asPrimitiveTypeCastExpr + val operand = updateExpressionWithLocal( + primitiveTypecastExpr.operand, + stackLocal, + registerLocal + ) + + return PrimitiveTypecastExpr( + primitiveTypecastExpr.pc, + primitiveTypecastExpr.targetTpe, + operand + ) + case NewArray.ASTID => + val newArray = expr.asNewArray + val counts = newArray.counts.map(c => updateExpressionWithLocal(c, stackLocal, registerLocal)) + + return NewArray(newArray.pc, counts, newArray.tpe) + case ArrayLoad.ASTID => + val arrayLoad = expr.asArrayLoad + + val index = updateExpressionWithLocal( + arrayLoad.index, + stackLocal, + registerLocal + ) + val arrayRef = updateExpressionWithLocal( + arrayLoad.arrayRef, + stackLocal, + registerLocal + ) + + return ArrayLoad(arrayLoad.pc, index, arrayRef) + case ArrayLength.ASTID => + val arrayLength = expr.asArrayLength + val arrayRef = updateExpressionWithLocal( + arrayLength.arrayRef, + stackLocal, + registerLocal + ) + + return ArrayLength(arrayLength.pc, arrayRef) + case GetField.ASTID => + val getField = expr.asGetField + val objRef = updateExpressionWithLocal( + getField.objRef, + stackLocal, + registerLocal + ) + + return GetField( + getField.pc, + getField.declaringClass, + getField.name, + getField.declaredFieldType, + objRef + ) + case InvokedynamicFunctionCall.ASTID => + val functionCall = expr.asInvokedynamicFunctionCall + val params = functionCall.params.map(p => updateExpressionWithLocal(p, stackLocal, registerLocal)) + + return InvokedynamicFunctionCall( + functionCall.pc, + functionCall.bootstrapMethod, + functionCall.name, + functionCall.descriptor, + params + ) + case NonVirtualFunctionCall.ASTID => + val functionCall = expr.asNonVirtualFunctionCall + + val base = updateExpressionWithLocal( + functionCall.receiver, + stackLocal, + registerLocal + ) + val params = functionCall.params.map(p => updateExpressionWithLocal(p, stackLocal, registerLocal)) + + return NonVirtualFunctionCall( + functionCall.pc, + functionCall.declaringClass, + functionCall.isInterface, + functionCall.name, + functionCall.descriptor, + base, + params + ) + case VirtualFunctionCall.ASTID => + val functionCall = expr.asVirtualFunctionCall + + val base = updateExpressionWithLocal( + functionCall.receiver, + stackLocal, + registerLocal + ) + val params = functionCall.params.map(p => updateExpressionWithLocal(p, stackLocal, registerLocal)) + + return VirtualFunctionCall( + functionCall.pc, + functionCall.declaringClass, + functionCall.isInterface, + functionCall.name, + functionCall.descriptor, + base, + params + ) + case StaticFunctionCall.ASTID => + val functionCall = expr.asStaticFunctionCall + + val params = functionCall.params + val paramLocals = + params.map(p => updateExpressionWithLocal(p, stackLocal, registerLocal)) + + return StaticFunctionCall( + functionCall.pc, + functionCall.declaringClass, + functionCall.isInterface, + functionCall.name, + functionCall.descriptor, + paramLocals + ) + case _ => return expr + } + + throw new RuntimeException("Could not update expression: " + expr) } + + statements + } } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/LocalTransformer.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/LocalTransformer.scala index 2dc83d053..29056b213 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/LocalTransformer.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/LocalTransformer.scala @@ -96,507 +96,507 @@ import scala.collection.mutable object LocalTransformer { - def apply( - project: Project[_], - method: Method, - tac: NaiveTACode[_], - stackHandler: OperandStackHandler, - domain: Domain - ): Array[Stmt[TacLocal]] = { - var paramCount = -1 - var exceptionCount = -1 - val currentLocals = mutable.Map.empty[Int, TacLocal] - val exceptionHandlers = tac.exceptionHandlers.map(eh => eh.handlerPC) - - // Domain components - val aiResult: AIResult = BaseAI(method, domain) - val operandsArray: aiResult.domain.OperandsArray = aiResult.operandsArray - val localArray: aiResult.domain.LocalsArray = aiResult.localsArray - - def transformStmt(stmt: Stmt[IdBasedVar]): Stmt[TacLocal] = { - stmt match { - case If(pc, left, condition, right, target) => - val leftExpr = transformExpr(pc, left) - val rightExpr = transformExpr(pc, right) - - return If(pc, leftExpr, condition, rightExpr, target) - case Goto(pc, target) => return Goto(pc, target) - case Ret(pc, returnAddresses) => return Ret(pc, returnAddresses) - case JSR(pc, target) => return JSR(pc, target) - case Switch(pc, defaultTarget, index, nPairs) => - val indexExpr = transformExpr(pc, index) - - return Switch(pc, defaultTarget, indexExpr, nPairs) - case Assignment(pc, targetVar, expr) => - // Parameter definition statements - if (pc == -1) { - val transformedExpr = transformExpr(pc, expr) - - var paramName: Option[String] = None - if (transformedExpr.isVar && transformedExpr.asVar.isParameterLocal) { - paramName = Some(transformedExpr.asVar.name) - } - - val paramLocal = createParameterLocal(targetVar, paramName) - - currentLocals(paramLocal.id) = paramLocal - return Assignment(pc, paramLocal, transformedExpr) - } - - if (targetVar.id >= 0) { - val transformedExpr = transformExpr(pc, expr) - - // Consider 'this' assignment from register to stack: s = this - val isThisAssignment = - transformedExpr.isVar && transformedExpr.asVar.isThisLocal - val targetLocal = createStackLocal(pc, targetVar, isThisAssignment) - - currentLocals(targetLocal.id) = targetLocal - return Assignment(pc, targetLocal, transformedExpr) - } - - if (targetVar.id < 0) { - val transformedExpr = transformExpr(pc, expr) - - // Consider 'this' assignment from stack to register: r0 = $this - val isThisAssignment = - transformedExpr.isVar && transformedExpr.asVar.isThisLocal - val targetLocal = - createRegisterLocal(pc, targetVar, isThisAssignment) - - currentLocals(targetLocal.id) = targetLocal - return Assignment(pc, targetLocal, transformedExpr) - } - - throw new RuntimeException("Should never be reached") - case ReturnValue(pc, expr) => - val returnExpr = transformExpr(pc, expr) - - return ReturnValue(pc, returnExpr) - case Return(pc) => return Return(pc) - case Nop(pc) => return Nop(pc) - case MonitorEnter(pc, objRef) => - val objRefExpr = transformExpr(pc, objRef) - - return MonitorEnter(pc, objRefExpr) - case MonitorExit(pc, objRef) => - val objRefExpr = transformExpr(pc, objRef) - - return MonitorExit(pc, objRefExpr) - case ArrayStore(pc, arrayRef, index, value) => - val arrayRefExpr = transformExpr(pc, arrayRef) - val indexExpr = transformExpr(pc, index) - val valueExpr = transformExpr(pc, value) - - return ArrayStore(pc, arrayRefExpr, indexExpr, valueExpr) - case Throw(pc, exception) => - val exceptionExpr = transformExpr(pc, exception) - - return Throw(pc, exceptionExpr) - case PutStatic(pc, declaringClass, name, declaredFieldType, value) => - val valueExpr = transformExpr(pc, value) - - return PutStatic( - pc, - declaringClass, - name, - declaredFieldType, - valueExpr - ) - case PutField( - pc, - declaringClass, - name, - declaredFieldType, - objRef, - value - ) => - val objRefExpr = transformExpr(pc, objRef) - val valueExpr = transformExpr(pc, value) - - return PutField( - pc, - declaringClass, - name, - declaredFieldType, - objRefExpr, - valueExpr - ) - case NonVirtualMethodCall( - pc, - declaringClass, - isInterface, - name, - descriptor, - receiver, - params - ) => - val receiverExpr = transformExpr(pc, receiver) - val paramsExpr = params.map(p => transformExpr(pc, p)) - - return NonVirtualMethodCall( - pc, - declaringClass, - isInterface, - name, - descriptor, - receiverExpr, - paramsExpr - ) - case VirtualMethodCall( - pc, - declaringClass, - isInterface, - name, - descriptor, - receiver, - params - ) => - val receiverExpr = transformExpr(pc, receiver) - val paramsExpr = params.map(p => transformExpr(pc, p)) - - return VirtualMethodCall( - pc, - declaringClass, - isInterface, - name, - descriptor, - receiverExpr, - paramsExpr - ) - case StaticMethodCall( - pc, - declaringClass, - isInterface, - name, - descriptor, - params - ) => - val paramsExpr = params.map(p => transformExpr(pc, p)) - - return StaticMethodCall( - pc, - declaringClass, - isInterface, - name, - descriptor, - paramsExpr - ) - case InvokedynamicMethodCall( - pc, - bootstrapMethod, - name, - descriptor, - params - ) => - val paramsExpr = params.map(p => transformExpr(pc, p)) - - return InvokedynamicMethodCall( - pc, - bootstrapMethod, - name, - descriptor, - paramsExpr - ) - case ExprStmt(pc, expr) => - val transformedExpr = transformExpr(pc, expr) - - return ExprStmt(pc, transformedExpr) - case CaughtException(pc, exceptionType, throwingStatements) => - return CaughtException(pc, exceptionType, throwingStatements) - case Checkcast(pc, value, cmpTpe) => - val valueExpr = transformExpr(pc, value) - // TODO Transform into assignment - return Checkcast(pc, valueExpr, cmpTpe) - case _ => throw new RuntimeException("Unknown statement: " + stmt) + def apply( + project: Project[_], + method: Method, + tac: NaiveTACode[_], + stackHandler: OperandStackHandler, + domain: Domain + ): Array[Stmt[TacLocal]] = { + var paramCount = -1 + var exceptionCount = -1 + val currentLocals = mutable.Map.empty[Int, TacLocal] + val exceptionHandlers = tac.exceptionHandlers.map(eh => eh.handlerPC) + + // Domain components + val aiResult: AIResult = BaseAI(method, domain) + val operandsArray: aiResult.domain.OperandsArray = aiResult.operandsArray + val localArray: aiResult.domain.LocalsArray = aiResult.localsArray + + def transformStmt(stmt: Stmt[IdBasedVar]): Stmt[TacLocal] = { + stmt match { + case If(pc, left, condition, right, target) => + val leftExpr = transformExpr(pc, left) + val rightExpr = transformExpr(pc, right) + + return If(pc, leftExpr, condition, rightExpr, target) + case Goto(pc, target) => return Goto(pc, target) + case Ret(pc, returnAddresses) => return Ret(pc, returnAddresses) + case JSR(pc, target) => return JSR(pc, target) + case Switch(pc, defaultTarget, index, nPairs) => + val indexExpr = transformExpr(pc, index) + + return Switch(pc, defaultTarget, indexExpr, nPairs) + case Assignment(pc, targetVar, expr) => + // Parameter definition statements + if (pc == -1) { + val transformedExpr = transformExpr(pc, expr) + + var paramName: Option[String] = None + if (transformedExpr.isVar && transformedExpr.asVar.isParameterLocal) { + paramName = Some(transformedExpr.asVar.name) } - throw new RuntimeException("Could not transform statement: " + stmt) - } - - def isThisVar(idBasedVar: IdBasedVar): Boolean = - method.isNotStatic && idBasedVar.id == -1 - - def createParameterLocal( - idBasedVar: IdBasedVar, - paramName: Option[String] = Option.empty - ): TacLocal = { - val local = localArray(0) - - new RegisterLocal( - idBasedVar.id, - idBasedVar.cTpe, - local(-idBasedVar.id - 1), - isThisVar(idBasedVar), - paramName - ) - } - - def createStackLocal( - pc: PC, - idBasedVar: IdBasedVar, - isThis: Boolean - ): TacLocal = { - val nextPc = method.body.get.pcOfNextInstruction(pc) - val value = operandsArray(nextPc) - val counter = stackHandler.defSiteAtPc(pc) - - if (value == null) { - val fieldType = computationalTypeToFieldType(idBasedVar.cTpe) - new StackLocal( - counter, - idBasedVar.cTpe, - ValueInformation.forProperValue(fieldType)(project.classHierarchy), - isThis - ) - } else { - new StackLocal(counter, idBasedVar.cTpe, value.head, isThis) - } - } - - def createRegisterLocal( - pc: PC, - idBasedVar: IdBasedVar, - isThis: Boolean - ): TacLocal = { - val nextPc = method.body.get.pcOfNextInstruction(pc) - val locals = localArray(nextPc) - - val index = -idBasedVar.id - 1 - - val local = method.body.get.localVariable(nextPc, index) - if (local.isDefined) { - if (locals == null) { - val fieldType = computationalTypeToFieldType(idBasedVar.cTpe) - return new RegisterLocal( - idBasedVar.id, - idBasedVar.cTpe, - ValueInformation.forProperValue(fieldType)(project.classHierarchy), - isThis, - Option(local.get.name) - ) - } else { - return new RegisterLocal( - idBasedVar.id, - idBasedVar.cTpe, - locals(index), - isThis, - Option(local.get.name) - ) - } - } + val paramLocal = createParameterLocal(targetVar, paramName) + + currentLocals(paramLocal.id) = paramLocal + return Assignment(pc, paramLocal, transformedExpr) + } + + if (targetVar.id >= 0) { + val transformedExpr = transformExpr(pc, expr) + + // Consider 'this' assignment from register to stack: s = this + val isThisAssignment = + transformedExpr.isVar && transformedExpr.asVar.isThisLocal + val targetLocal = createStackLocal(pc, targetVar, isThisAssignment) + + currentLocals(targetLocal.id) = targetLocal + return Assignment(pc, targetLocal, transformedExpr) + } + + if (targetVar.id < 0) { + val transformedExpr = transformExpr(pc, expr) + + // Consider 'this' assignment from stack to register: r0 = $this + val isThisAssignment = + transformedExpr.isVar && transformedExpr.asVar.isThisLocal + val targetLocal = + createRegisterLocal(pc, targetVar, isThisAssignment) + + currentLocals(targetLocal.id) = targetLocal + return Assignment(pc, targetLocal, transformedExpr) + } + + throw new RuntimeException("Should never be reached") + case ReturnValue(pc, expr) => + val returnExpr = transformExpr(pc, expr) + + return ReturnValue(pc, returnExpr) + case Return(pc) => return Return(pc) + case Nop(pc) => return Nop(pc) + case MonitorEnter(pc, objRef) => + val objRefExpr = transformExpr(pc, objRef) + + return MonitorEnter(pc, objRefExpr) + case MonitorExit(pc, objRef) => + val objRefExpr = transformExpr(pc, objRef) + + return MonitorExit(pc, objRefExpr) + case ArrayStore(pc, arrayRef, index, value) => + val arrayRefExpr = transformExpr(pc, arrayRef) + val indexExpr = transformExpr(pc, index) + val valueExpr = transformExpr(pc, value) + + return ArrayStore(pc, arrayRefExpr, indexExpr, valueExpr) + case Throw(pc, exception) => + val exceptionExpr = transformExpr(pc, exception) + + return Throw(pc, exceptionExpr) + case PutStatic(pc, declaringClass, name, declaredFieldType, value) => + val valueExpr = transformExpr(pc, value) + + return PutStatic( + pc, + declaringClass, + name, + declaredFieldType, + valueExpr + ) + case PutField( + pc, + declaringClass, + name, + declaredFieldType, + objRef, + value + ) => + val objRefExpr = transformExpr(pc, objRef) + val valueExpr = transformExpr(pc, value) + + return PutField( + pc, + declaringClass, + name, + declaredFieldType, + objRefExpr, + valueExpr + ) + case NonVirtualMethodCall( + pc, + declaringClass, + isInterface, + name, + descriptor, + receiver, + params + ) => + val receiverExpr = transformExpr(pc, receiver) + val paramsExpr = params.map(p => transformExpr(pc, p)) + + return NonVirtualMethodCall( + pc, + declaringClass, + isInterface, + name, + descriptor, + receiverExpr, + paramsExpr + ) + case VirtualMethodCall( + pc, + declaringClass, + isInterface, + name, + descriptor, + receiver, + params + ) => + val receiverExpr = transformExpr(pc, receiver) + val paramsExpr = params.map(p => transformExpr(pc, p)) + + return VirtualMethodCall( + pc, + declaringClass, + isInterface, + name, + descriptor, + receiverExpr, + paramsExpr + ) + case StaticMethodCall( + pc, + declaringClass, + isInterface, + name, + descriptor, + params + ) => + val paramsExpr = params.map(p => transformExpr(pc, p)) + + return StaticMethodCall( + pc, + declaringClass, + isInterface, + name, + descriptor, + paramsExpr + ) + case InvokedynamicMethodCall( + pc, + bootstrapMethod, + name, + descriptor, + params + ) => + val paramsExpr = params.map(p => transformExpr(pc, p)) + + return InvokedynamicMethodCall( + pc, + bootstrapMethod, + name, + descriptor, + paramsExpr + ) + case ExprStmt(pc, expr) => + val transformedExpr = transformExpr(pc, expr) + + return ExprStmt(pc, transformedExpr) + case CaughtException(pc, exceptionType, throwingStatements) => + return CaughtException(pc, exceptionType, throwingStatements) + case Checkcast(pc, value, cmpTpe) => + val valueExpr = transformExpr(pc, value) + // TODO Transform into assignment + return Checkcast(pc, valueExpr, cmpTpe) + case _ => throw new RuntimeException("Unknown statement: " + stmt) + } + + throw new RuntimeException("Could not transform statement: " + stmt) + } - if (locals == null) { - val fieldType = computationalTypeToFieldType(idBasedVar.cTpe) - new RegisterLocal( - idBasedVar.id, - idBasedVar.cTpe, - ValueInformation.forProperValue(fieldType)(project.classHierarchy), - isThis - ) - } else { - new RegisterLocal(idBasedVar.id, idBasedVar.cTpe, locals(index), isThis) - } - } + def isThisVar(idBasedVar: IdBasedVar): Boolean = + method.isNotStatic && idBasedVar.id == -1 + + def createParameterLocal( + idBasedVar: IdBasedVar, + paramName: Option[String] = Option.empty + ): TacLocal = { + val local = localArray(0) + + new RegisterLocal( + idBasedVar.id, + idBasedVar.cTpe, + local(-idBasedVar.id - 1), + isThisVar(idBasedVar), + paramName + ) + } - def createExceptionLocal( - pc: PC, - idBasedVar: IdBasedVar, - localId: Int - ): TacLocal = { - val value = operandsArray(pc) - - if (value == null) { - val fieldType = computationalTypeToFieldType(idBasedVar.cTpe) - new ExceptionLocal( - localId, - idBasedVar.cTpe, - ValueInformation.forProperValue(fieldType)(project.classHierarchy) - ) - } else { - new ExceptionLocal(localId, idBasedVar.cTpe, value.head) - } - } + def createStackLocal( + pc: PC, + idBasedVar: IdBasedVar, + isThis: Boolean + ): TacLocal = { + val nextPc = method.body.get.pcOfNextInstruction(pc) + val value = operandsArray(nextPc) + val counter = stackHandler.defSiteAtPc(pc) + + if (value == null) { + val fieldType = computationalTypeToFieldType(idBasedVar.cTpe) + new StackLocal( + counter, + idBasedVar.cTpe, + ValueInformation.forProperValue(fieldType)(project.classHierarchy), + isThis + ) + } else { + new StackLocal(counter, idBasedVar.cTpe, value.head, isThis) + } + } - def computationalTypeToFieldType(cTpe: ComputationalType): FieldType = { - cTpe match { - case ComputationalTypeInt => IntegerType - case ComputationalTypeFloat => FloatType - case ComputationalTypeLong => LongType - case ComputationalTypeDouble => DoubleType - case ComputationalTypeReference => ObjectType.Object - case ComputationalTypeReturnAddress => ObjectType.Object - case _ => - throw new RuntimeException("Unknown computational type " + cTpe) - } + def createRegisterLocal( + pc: PC, + idBasedVar: IdBasedVar, + isThis: Boolean + ): TacLocal = { + val nextPc = method.body.get.pcOfNextInstruction(pc) + val locals = localArray(nextPc) + + val index = -idBasedVar.id - 1 + + val local = method.body.get.localVariable(nextPc, index) + if (local.isDefined) { + if (locals == null) { + val fieldType = computationalTypeToFieldType(idBasedVar.cTpe) + return new RegisterLocal( + idBasedVar.id, + idBasedVar.cTpe, + ValueInformation.forProperValue(fieldType)(project.classHierarchy), + isThis, + Option(local.get.name) + ) + } else { + return new RegisterLocal( + idBasedVar.id, + idBasedVar.cTpe, + locals(index), + isThis, + Option(local.get.name) + ) } + } + + if (locals == null) { + val fieldType = computationalTypeToFieldType(idBasedVar.cTpe) + new RegisterLocal( + idBasedVar.id, + idBasedVar.cTpe, + ValueInformation.forProperValue(fieldType)(project.classHierarchy), + isThis + ) + } else { + new RegisterLocal(idBasedVar.id, idBasedVar.cTpe, locals(index), isThis) + } + } - def transformExpr(pc: PC, expr: Expr[IdBasedVar]): Expr[TacLocal] = { - expr match { - case v: IdBasedVar => - // Exception locals are implicitly defined and denoted with s0. They are - // not pushed on the operand stack, so we have to define it explicitly - if (exceptionHandlers.contains(tac.pcToIndex(pc))) { - exceptionCount += 1 - - return createExceptionLocal(pc, v, exceptionCount) - } - - if (v.id >= 0) { - val stmt = tac.stmts(tac.pcToIndex(pc)) - val counter = - stackHandler.counterForOperand(pc, v.id, stmt.isReturnValue) - - return currentLocals(counter) - } - - return currentLocals(v.id) - case InstanceOf(pc, value, cmpTpe) => - val valueExpr = transformExpr(pc, value) - - return InstanceOf(pc, valueExpr, cmpTpe) - case Compare(pc, left, condition, right) => - val leftExpr = transformExpr(pc, left) - val rightExpr = transformExpr(pc, right) - - return Compare(pc, leftExpr, condition, rightExpr) - case Param(cTpe, name) => - paramCount += 1 - - return new ParameterLocal(paramCount, cTpe, name) - case MethodTypeConst(pc, value) => return MethodTypeConst(pc, value) - case MethodHandleConst(pc, value) => return MethodHandleConst(pc, value) - case IntConst(pc, value) => return IntConst(pc, value) - case LongConst(pc, value) => return LongConst(pc, value) - case FloatConst(pc, value) => return FloatConst(pc, value) - case DoubleConst(pc, value) => return DoubleConst(pc, value) - case StringConst(pc, value) => return StringConst(pc, value) - case ClassConst(pc, value) => return ClassConst(pc, value) - case DynamicConst(pc, bootstrapMethod, name, descriptor) => - return DynamicConst(pc, bootstrapMethod, name, descriptor) - case NullExpr(pc) => return NullExpr(pc) - case BinaryExpr(pc, cTpe, op, left, right) => - val leftExpr = transformExpr(pc, left) - val rightExpr = transformExpr(pc, right) - - return BinaryExpr(pc, cTpe, op, leftExpr, rightExpr) - case PrefixExpr(pc, cTpe, op, operand) => - val operandExpr = transformExpr(pc, operand) - - return PrefixExpr(pc, cTpe, op, operandExpr) - case PrimitiveTypecastExpr(pc, targetTpe, operand) => - val operandExpr = transformExpr(pc, operand) - - return PrimitiveTypecastExpr(pc, targetTpe, operandExpr) - case New(pc, tpe) => return New(pc, tpe) - case NewArray(pc, counts, tpe) => - val countsExpr = counts.map(c => transformExpr(pc, c)) - - return NewArray(pc, countsExpr, tpe) - case ArrayLoad(pc, index, arrayRef) => - val indexExpr = transformExpr(pc, index) - val arrayRefExpr = transformExpr(pc, arrayRef) - - return ArrayLoad(pc, indexExpr, arrayRefExpr) - case ArrayLength(pc, arrayRef) => - val arrayRefExpr = transformExpr(pc, arrayRef) - - return ArrayLength(pc, arrayRefExpr) - case GetField(pc, declaringClass, name, declaredFieldType, objRef) => - val objRefExpr = transformExpr(pc, objRef) - - return GetField( - pc, - declaringClass, - name, - declaredFieldType, - objRefExpr - ) - case GetStatic(pc, declaringClass, name, declaredFieldType) => - return GetStatic(pc, declaringClass, name, declaredFieldType) - case InvokedynamicFunctionCall( - pc, - bootstrapMethod, - name, - descriptor, - params - ) => - val paramsExpr = params.map(p => transformExpr(pc, p)) - - return InvokedynamicFunctionCall( - pc, - bootstrapMethod, - name, - descriptor, - paramsExpr - ) - case NonVirtualFunctionCall( - pc, - declaringClass, - isInterface, - name, - descriptor, - receiver, - params - ) => - val receiverExpr = transformExpr(pc, receiver) - val paramsExpr = params.map(p => transformExpr(pc, p)) - - return NonVirtualFunctionCall( - pc, - declaringClass, - isInterface, - name, - descriptor, - receiverExpr, - paramsExpr - ) - case VirtualFunctionCall( - pc, - declaringClass, - isInterface, - name, - descriptor, - receiver, - params - ) => - val receiverExpr = transformExpr(pc, receiver) - val paramsExpr = params.map(p => transformExpr(pc, p)) - - return VirtualFunctionCall( - pc, - declaringClass, - isInterface, - name, - descriptor, - receiverExpr, - paramsExpr - ) - case StaticFunctionCall( - pc, - declaringClass, - isInterface, - name, - descriptor, - params - ) => - val paramsExpr = params.map(p => transformExpr(pc, p)) - - return StaticFunctionCall( - pc, - declaringClass, - isInterface, - name, - descriptor, - paramsExpr - ) - case _ => throw new RuntimeException("Unknown expression: " + expr) - } + def createExceptionLocal( + pc: PC, + idBasedVar: IdBasedVar, + localId: Int + ): TacLocal = { + val value = operandsArray(pc) + + if (value == null) { + val fieldType = computationalTypeToFieldType(idBasedVar.cTpe) + new ExceptionLocal( + localId, + idBasedVar.cTpe, + ValueInformation.forProperValue(fieldType)(project.classHierarchy) + ) + } else { + new ExceptionLocal(localId, idBasedVar.cTpe, value.head) + } + } - throw new RuntimeException("Could not transform expr: " + expr) - } + def computationalTypeToFieldType(cTpe: ComputationalType): FieldType = { + cTpe match { + case ComputationalTypeInt => IntegerType + case ComputationalTypeFloat => FloatType + case ComputationalTypeLong => LongType + case ComputationalTypeDouble => DoubleType + case ComputationalTypeReference => ObjectType.Object + case ComputationalTypeReturnAddress => ObjectType.Object + case _ => + throw new RuntimeException("Unknown computational type " + cTpe) + } + } - tac.stmts.map(stmt => transformStmt(stmt)) + def transformExpr(pc: PC, expr: Expr[IdBasedVar]): Expr[TacLocal] = { + expr match { + case v: IdBasedVar => + // Exception locals are implicitly defined and denoted with s0. They are + // not pushed on the operand stack, so we have to define it explicitly + if (exceptionHandlers.contains(tac.pcToIndex(pc))) { + exceptionCount += 1 + + return createExceptionLocal(pc, v, exceptionCount) + } + + if (v.id >= 0) { + val stmt = tac.stmts(tac.pcToIndex(pc)) + val counter = + stackHandler.counterForOperand(pc, v.id, stmt.isReturnValue) + + return currentLocals(counter) + } + + return currentLocals(v.id) + case InstanceOf(pc, value, cmpTpe) => + val valueExpr = transformExpr(pc, value) + + return InstanceOf(pc, valueExpr, cmpTpe) + case Compare(pc, left, condition, right) => + val leftExpr = transformExpr(pc, left) + val rightExpr = transformExpr(pc, right) + + return Compare(pc, leftExpr, condition, rightExpr) + case Param(cTpe, name) => + paramCount += 1 + + return new ParameterLocal(paramCount, cTpe, name) + case MethodTypeConst(pc, value) => return MethodTypeConst(pc, value) + case MethodHandleConst(pc, value) => return MethodHandleConst(pc, value) + case IntConst(pc, value) => return IntConst(pc, value) + case LongConst(pc, value) => return LongConst(pc, value) + case FloatConst(pc, value) => return FloatConst(pc, value) + case DoubleConst(pc, value) => return DoubleConst(pc, value) + case StringConst(pc, value) => return StringConst(pc, value) + case ClassConst(pc, value) => return ClassConst(pc, value) + case DynamicConst(pc, bootstrapMethod, name, descriptor) => + return DynamicConst(pc, bootstrapMethod, name, descriptor) + case NullExpr(pc) => return NullExpr(pc) + case BinaryExpr(pc, cTpe, op, left, right) => + val leftExpr = transformExpr(pc, left) + val rightExpr = transformExpr(pc, right) + + return BinaryExpr(pc, cTpe, op, leftExpr, rightExpr) + case PrefixExpr(pc, cTpe, op, operand) => + val operandExpr = transformExpr(pc, operand) + + return PrefixExpr(pc, cTpe, op, operandExpr) + case PrimitiveTypecastExpr(pc, targetTpe, operand) => + val operandExpr = transformExpr(pc, operand) + + return PrimitiveTypecastExpr(pc, targetTpe, operandExpr) + case New(pc, tpe) => return New(pc, tpe) + case NewArray(pc, counts, tpe) => + val countsExpr = counts.map(c => transformExpr(pc, c)) + + return NewArray(pc, countsExpr, tpe) + case ArrayLoad(pc, index, arrayRef) => + val indexExpr = transformExpr(pc, index) + val arrayRefExpr = transformExpr(pc, arrayRef) + + return ArrayLoad(pc, indexExpr, arrayRefExpr) + case ArrayLength(pc, arrayRef) => + val arrayRefExpr = transformExpr(pc, arrayRef) + + return ArrayLength(pc, arrayRefExpr) + case GetField(pc, declaringClass, name, declaredFieldType, objRef) => + val objRefExpr = transformExpr(pc, objRef) + + return GetField( + pc, + declaringClass, + name, + declaredFieldType, + objRefExpr + ) + case GetStatic(pc, declaringClass, name, declaredFieldType) => + return GetStatic(pc, declaringClass, name, declaredFieldType) + case InvokedynamicFunctionCall( + pc, + bootstrapMethod, + name, + descriptor, + params + ) => + val paramsExpr = params.map(p => transformExpr(pc, p)) + + return InvokedynamicFunctionCall( + pc, + bootstrapMethod, + name, + descriptor, + paramsExpr + ) + case NonVirtualFunctionCall( + pc, + declaringClass, + isInterface, + name, + descriptor, + receiver, + params + ) => + val receiverExpr = transformExpr(pc, receiver) + val paramsExpr = params.map(p => transformExpr(pc, p)) + + return NonVirtualFunctionCall( + pc, + declaringClass, + isInterface, + name, + descriptor, + receiverExpr, + paramsExpr + ) + case VirtualFunctionCall( + pc, + declaringClass, + isInterface, + name, + descriptor, + receiver, + params + ) => + val receiverExpr = transformExpr(pc, receiver) + val paramsExpr = params.map(p => transformExpr(pc, p)) + + return VirtualFunctionCall( + pc, + declaringClass, + isInterface, + name, + descriptor, + receiverExpr, + paramsExpr + ) + case StaticFunctionCall( + pc, + declaringClass, + isInterface, + name, + descriptor, + params + ) => + val paramsExpr = params.map(p => transformExpr(pc, p)) + + return StaticFunctionCall( + pc, + declaringClass, + isInterface, + name, + descriptor, + paramsExpr + ) + case _ => throw new RuntimeException("Unknown expression: " + expr) + } + + throw new RuntimeException("Could not transform expr: " + expr) } + tac.stmts.map(stmt => transformStmt(stmt)) + } + } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/NopEliminator.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/NopEliminator.scala index 10f2ab737..ba5290491 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/NopEliminator.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/NopEliminator.scala @@ -19,17 +19,17 @@ import org.opalj.tac.Nop object NopEliminator { - def apply(stmtGraph: StmtGraph): StmtGraph = { + def apply(stmtGraph: StmtGraph): StmtGraph = { - def removeNopStatements(stmtGraph: StmtGraph): StmtGraph = { - val nopStatements = - stmtGraph.statements.filter(s => s.astID == Nop.ASTID && s.pc >= 0) - var result = stmtGraph + def removeNopStatements(stmtGraph: StmtGraph): StmtGraph = { + val nopStatements = + stmtGraph.statements.filter(s => s.astID == Nop.ASTID && s.pc >= 0) + var result = stmtGraph - nopStatements.foreach(stmt => result = result.remove(stmt)) - result - } - - removeNopStatements(stmtGraph) + nopStatements.foreach(stmt => result = result.remove(stmt)) + result } + + removeNopStatements(stmtGraph) + } } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/NopTransformer.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/NopTransformer.scala index 56081f96f..c3b6da706 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/NopTransformer.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/NopTransformer.scala @@ -22,41 +22,41 @@ import org.opalj.tac.Stmt object NopTransformer { - private final val INITIAL_NOP = Integer.MIN_VALUE - - def apply(stmtGraph: StmtGraph): StmtGraph = { - val tac = stmtGraph.tac - - def addNopStatements(stmtGraph: StmtGraph): StmtGraph = { - // Add a nop statement in the beginning - val nop = Nop(INITIAL_NOP) - var result = stmtGraph.insertBefore(nop, stmtGraph.heads.head) - - var beforeStmtInsert = List.empty[Stmt[TacLocal]] - tac.zipWithIndex.foreach(stmt => { - // TODO Switch statements - if (stmt._1.astID == If.ASTID) { - val nextStmt = tac(stmt._2 + 1) - val targetStmt = tac(stmt._1.asIf.targetStmt) - - beforeStmtInsert = beforeStmtInsert ++ List(nextStmt, targetStmt) - } - }) - - beforeStmtInsert.foreach(stmt => { - /* If one or multiple branches target the same statement, we add exactly one Nop statement - * before the target statement (represented by the negative pc). This way, important - * data flows are covered - */ - val nextStmtNop = Nop(-stmt.pc) - if (!result.statements.contains(nextStmtNop)) { - result = result.insertBefore(nextStmtNop, stmt) - } - }) - - result + private final val INITIAL_NOP = Integer.MIN_VALUE + + def apply(stmtGraph: StmtGraph): StmtGraph = { + val tac = stmtGraph.tac + + def addNopStatements(stmtGraph: StmtGraph): StmtGraph = { + // Add a nop statement in the beginning + val nop = Nop(INITIAL_NOP) + var result = stmtGraph.insertBefore(nop, stmtGraph.heads.head) + + var beforeStmtInsert = List.empty[Stmt[TacLocal]] + tac.zipWithIndex.foreach(stmt => { + // TODO Switch statements + if (stmt._1.astID == If.ASTID) { + val nextStmt = tac(stmt._2 + 1) + val targetStmt = tac(stmt._1.asIf.targetStmt) + + beforeStmtInsert = beforeStmtInsert ++ List(nextStmt, targetStmt) + } + }) + + beforeStmtInsert.foreach(stmt => { + /* If one or multiple branches target the same statement, we add exactly one Nop statement + * before the target statement (represented by the negative pc). This way, important + * data flows are covered + */ + val nextStmtNop = Nop(-stmt.pc) + if (!result.statements.contains(nextStmtNop)) { + result = result.insertBefore(nextStmtNop, stmt) } + }) - addNopStatements(stmtGraph) + result } + + addNopStatements(stmtGraph) + } } diff --git a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/NullifyFieldsTransformer.scala b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/NullifyFieldsTransformer.scala index 6a7067659..bb06d488f 100644 --- a/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/NullifyFieldsTransformer.scala +++ b/boomerangScope-Opal/src/main/scala/boomerang/scope/opal/transformation/transformer/NullifyFieldsTransformer.scala @@ -21,78 +21,83 @@ import org.opalj.br.ComputationalTypeReference import org.opalj.br.Field import org.opalj.br.FieldType import org.opalj.br.Method +import org.opalj.br.analyses.Project import org.opalj.tac.Assignment import org.opalj.tac.Expr import org.opalj.tac.NullExpr import org.opalj.tac.PutField +import org.opalj.value.ValueInformation object NullifyFieldsTransformer { - private final val NULLIFIED_FIELD = -2 + private final val NULLIFIED_FIELD = -2 - def apply(method: Method, stmtGraph: StmtGraph): StmtGraph = { - if (!method.isConstructor || method.isStatic) { - return stmtGraph - } + def apply(project: Project[_], method: Method, stmtGraph: StmtGraph): StmtGraph = { + if (!method.isConstructor || method.isStatic) { + return stmtGraph + } - val tac = stmtGraph.tac - var localCounter = 0 + val tac = stmtGraph.tac + var localCounter = 0 - def isFieldDefined(field: Field): Boolean = { - // TODO Also consider super classes - tac.foreach { - // TODO Maybe also match 'this' local? - case PutField(_, _, field.name, field.fieldType, _, _) => return true - case _ => - } - false - } + def isFieldDefined(field: Field): Boolean = { + // TODO Soot considers super classes, too (not sure if required + tac.foreach { + // TODO Maybe also match 'this' local? + case PutField(_, _, field.name, field.fieldType, _, _) => return true + case _ => + } + false + } - def getThisLocal: Expr[TacLocal] = { - tac.foreach(stmt => { - if (stmt.pc == -1 && stmt.asAssignment.targetVar.id == -1) - return stmt.asAssignment.targetVar - }) + def getThisLocal: Expr[TacLocal] = { + tac.foreach(stmt => { + if (stmt.pc == -1 && stmt.asAssignment.targetVar.id == -1) + return stmt.asAssignment.targetVar + }) - throw new RuntimeException( - "'this' local not found in method: " + method.name - ) - } + throw new RuntimeException( + "'this' local not found in method: " + method.name + ) + } - def createNullifiedLocal( - localCounter: Int, - fieldType: FieldType - ): NullifiedLocal = { - // TODO Types - new NullifiedLocal(localCounter, ComputationalTypeReference) - } + def createNullifiedLocal( + localCounter: Int, + fieldType: FieldType + ): NullifiedLocal = { + new NullifiedLocal( + localCounter, + ComputationalTypeReference, + ValueInformation.forProperValue(fieldType)(project.classHierarchy) + ) + } - val definedFields = method.classFile.fields.filter(f => isFieldDefined(f)) - val undefinedFields = - method.classFile.fields.filter(f => !definedFields.contains(f) && f.isNotStatic && f.isNotFinal) - val firstOriginalStmt = tac.find(stmt => stmt.pc >= 0).get - var result = stmtGraph + val definedFields = method.classFile.fields.filter(f => isFieldDefined(f)) + val undefinedFields = + method.classFile.fields.filter(f => !definedFields.contains(f) && f.isNotStatic && f.isNotFinal) + val firstOriginalStmt = tac.find(stmt => stmt.pc >= 0).get + var result = stmtGraph - undefinedFields.foreach(field => { - val local = createNullifiedLocal(localCounter, field.fieldType) - localCounter += 1 + undefinedFields.foreach(field => { + val local = createNullifiedLocal(localCounter, field.fieldType) + localCounter += 1 - val defSite = - Assignment[TacLocal](NULLIFIED_FIELD, local, NullExpr(NULLIFIED_FIELD)) - val putField = PutField( - NULLIFIED_FIELD, - method.classFile.thisType, - field.name, - field.fieldType, - getThisLocal, - local - ) + val defSite = + Assignment[TacLocal](NULLIFIED_FIELD, local, NullExpr(NULLIFIED_FIELD)) + val putField = PutField( + NULLIFIED_FIELD, + method.classFile.thisType, + field.name, + field.fieldType, + getThisLocal, + local + ) - result = result.insertBefore(defSite, firstOriginalStmt) - result = result.insertBefore(putField, firstOriginalStmt) - }) + result = result.insertBefore(defSite, firstOriginalStmt) + result = result.insertBefore(putField, firstOriginalStmt) + }) - result - } + result + } } diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalArrayTest.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalArrayTest.scala index fb86f4dcd..ea988b3c7 100644 --- a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalArrayTest.scala +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalArrayTest.scala @@ -25,125 +25,125 @@ import org.opalj.br.IntegerType class OpalArrayTest { - private val integerType = IntegerType.toJVMTypeName - - @Test - def arrayLoadIndexTest(): Unit = { - val opalSetup = new OpalSetup() - opalSetup.setupOpal(classOf[ArrayTarget].getName) - - val signature = new MethodSignature( - classOf[ArrayTarget].getName, - "arrayIndexLoad", - "V", - util.List.of("[" + integerType) - ) - val method = opalSetup.resolveMethod(signature) - val opalMethod = OpalMethod(method) - - var arrayLoadCount = 0 - opalMethod.getStatements.forEach(stmt => { - if (stmt.isArrayLoad) { - arrayLoadCount += 1 - - val arrayBase = stmt.getArrayBase - Assert.assertFalse(arrayBase.getX.isArrayRef) - Assert.assertTrue(arrayBase.getX.isLocal) - Assert.assertEquals(1, arrayBase.getY) - - val rightOp = stmt.getRightOp - Assert.assertTrue(rightOp.isArrayRef) - } - }) - - Assert.assertEquals(1, arrayLoadCount) - } - - @Test - def arrayLoadVarTest(): Unit = { - val opalSetup = new OpalSetup() - opalSetup.setupOpal(classOf[ArrayTarget].getName) - - val signature = new MethodSignature( - classOf[ArrayTarget].getName, - "arrayVarLoad", - "V", - util.List.of("[" + integerType) - ) - val method = opalSetup.resolveMethod(signature) - val opalMethod = OpalMethod(method) - - var arrayLoadCount = 0 - opalMethod.getStatements.forEach(stmt => { - if (stmt.isArrayLoad) { - arrayLoadCount += 1 - - val arrayBase = stmt.getArrayBase - Assert.assertFalse(arrayBase.getX.isArrayRef) - Assert.assertTrue(arrayBase.getX.isLocal) - Assert.assertEquals(-1, arrayBase.getY) - - val rightOp = stmt.getRightOp - Assert.assertTrue(rightOp.isArrayRef) - } - }) - - Assert.assertEquals(1, arrayLoadCount) - } - - @Test - def arrayStoreIndexTest(): Unit = { - val opalSetup = new OpalSetup() - opalSetup.setupOpal(classOf[ArrayTarget].getName) - - val signature = - new MethodSignature(classOf[ArrayTarget].getName, "arrayStoreIndex", "V") - val method = opalSetup.resolveMethod(signature) - val opalMethod = OpalMethod(method) - - var arrayStoreCount = 0 - opalMethod.getStatements.forEach(stmt => { - if (stmt.isArrayStore) { - arrayStoreCount += 1 - - val arrayBase = stmt.getArrayBase - Assert.assertFalse(arrayBase.getX.isArrayRef) - Assert.assertTrue(arrayBase.getX.isLocal) - Assert.assertEquals(0, arrayBase.getY) - - val leftOp = stmt.getLeftOp - Assert.assertTrue(leftOp.isArrayRef) - } - }) - - Assert.assertEquals(1, arrayStoreCount) - } - - @Test - def arrayStoreVarTest(): Unit = { - val opalSetup = new OpalSetup() - opalSetup.setupOpal(classOf[ArrayTarget].getName) - - val signature = - new MethodSignature(classOf[ArrayTarget].getName, "arrayStoreVar", "V") - val method = opalSetup.resolveMethod(signature) - val opalMethod = OpalMethod(method) - - var arrayStoreCount = 0 - opalMethod.getStatements.forEach(stmt => { - if (stmt.isArrayStore) { - arrayStoreCount += 1 - - val arrayBase = stmt.getArrayBase - Assert.assertFalse(arrayBase.getX.isArrayRef) - Assert.assertTrue(arrayBase.getX.isLocal) - Assert.assertEquals(-1, arrayBase.getY) - - val leftOp = stmt.getLeftOp - Assert.assertTrue(leftOp.isArrayRef) - } - }) - - Assert.assertEquals(1, arrayStoreCount) - } + private val integerType = IntegerType.toJVMTypeName + + @Test + def arrayLoadIndexTest(): Unit = { + val opalSetup = new OpalSetup() + opalSetup.setupOpal(classOf[ArrayTarget].getName) + + val signature = new MethodSignature( + classOf[ArrayTarget].getName, + "arrayIndexLoad", + "V", + util.List.of("[" + integerType) + ) + val method = opalSetup.resolveMethod(signature) + val opalMethod = OpalMethod(method) + + var arrayLoadCount = 0 + opalMethod.getStatements.forEach(stmt => { + if (stmt.isArrayLoad) { + arrayLoadCount += 1 + + val arrayBase = stmt.getArrayBase + Assert.assertFalse(arrayBase.getX.isArrayRef) + Assert.assertTrue(arrayBase.getX.isLocal) + Assert.assertEquals(1, arrayBase.getY) + + val rightOp = stmt.getRightOp + Assert.assertTrue(rightOp.isArrayRef) + } + }) + + Assert.assertEquals(1, arrayLoadCount) + } + + @Test + def arrayLoadVarTest(): Unit = { + val opalSetup = new OpalSetup() + opalSetup.setupOpal(classOf[ArrayTarget].getName) + + val signature = new MethodSignature( + classOf[ArrayTarget].getName, + "arrayVarLoad", + "V", + util.List.of("[" + integerType) + ) + val method = opalSetup.resolveMethod(signature) + val opalMethod = OpalMethod(method) + + var arrayLoadCount = 0 + opalMethod.getStatements.forEach(stmt => { + if (stmt.isArrayLoad) { + arrayLoadCount += 1 + + val arrayBase = stmt.getArrayBase + Assert.assertFalse(arrayBase.getX.isArrayRef) + Assert.assertTrue(arrayBase.getX.isLocal) + Assert.assertEquals(-1, arrayBase.getY) + + val rightOp = stmt.getRightOp + Assert.assertTrue(rightOp.isArrayRef) + } + }) + + Assert.assertEquals(1, arrayLoadCount) + } + + @Test + def arrayStoreIndexTest(): Unit = { + val opalSetup = new OpalSetup() + opalSetup.setupOpal(classOf[ArrayTarget].getName) + + val signature = + new MethodSignature(classOf[ArrayTarget].getName, "arrayStoreIndex", "V") + val method = opalSetup.resolveMethod(signature) + val opalMethod = OpalMethod(method) + + var arrayStoreCount = 0 + opalMethod.getStatements.forEach(stmt => { + if (stmt.isArrayStore) { + arrayStoreCount += 1 + + val arrayBase = stmt.getArrayBase + Assert.assertFalse(arrayBase.getX.isArrayRef) + Assert.assertTrue(arrayBase.getX.isLocal) + Assert.assertEquals(0, arrayBase.getY) + + val leftOp = stmt.getLeftOp + Assert.assertTrue(leftOp.isArrayRef) + } + }) + + Assert.assertEquals(1, arrayStoreCount) + } + + @Test + def arrayStoreVarTest(): Unit = { + val opalSetup = new OpalSetup() + opalSetup.setupOpal(classOf[ArrayTarget].getName) + + val signature = + new MethodSignature(classOf[ArrayTarget].getName, "arrayStoreVar", "V") + val method = opalSetup.resolveMethod(signature) + val opalMethod = OpalMethod(method) + + var arrayStoreCount = 0 + opalMethod.getStatements.forEach(stmt => { + if (stmt.isArrayStore) { + arrayStoreCount += 1 + + val arrayBase = stmt.getArrayBase + Assert.assertFalse(arrayBase.getX.isArrayRef) + Assert.assertTrue(arrayBase.getX.isLocal) + Assert.assertEquals(-1, arrayBase.getY) + + val leftOp = stmt.getLeftOp + Assert.assertTrue(leftOp.isArrayRef) + } + }) + + Assert.assertEquals(1, arrayStoreCount) + } } diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalAssignmentTest.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalAssignmentTest.scala index 7d13d6a27..022e8299e 100644 --- a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalAssignmentTest.scala +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalAssignmentTest.scala @@ -22,142 +22,142 @@ import org.junit.Test class OpalAssignmentTest { - @Test - def arrayAllocationTest(): Unit = { - val opalSetup = new OpalSetup() - opalSetup.setupOpal(classOf[AssignmentTarget].getName) - - val signature = new MethodSignature( - classOf[AssignmentTarget].getName, - "arrayAllocation", - "V" - ) - val method = opalSetup.resolveMethod(signature) - val opalMethod = OpalMethod(method) - - var arrayAllocationCount = 0 - opalMethod.getStatements.forEach(stmt => { - if (stmt.isAssignStmt) { - val rightOp = stmt.getRightOp - - if (rightOp.isArrayAllocationVal) { - arrayAllocationCount += 1 - - val leftOp = stmt.getLeftOp - Assert.assertTrue(leftOp.isLocal) - - Assert.assertTrue(rightOp.getArrayAllocationSize.isIntConstant) - Assert.assertEquals(2, rightOp.getArrayAllocationSize.getIntValue) - } - } - }) - - Assert.assertEquals(1, arrayAllocationCount) - } - - @Test - def multiArrayAllocationTest(): Unit = { - val opalSetup = new OpalSetup() - opalSetup.setupOpal(classOf[AssignmentTarget].getName) - - val signature = new MethodSignature( - classOf[AssignmentTarget].getName, - "multiArrayAllocation", - "V" - ) - val method = opalSetup.resolveMethod(signature) - val opalMethod = OpalMethod(method) - - var checked = false - opalMethod.getStatements.forEach(stmt => { - if (stmt.isAssignStmt) { - val rightOp = stmt.getRightOp - - if (rightOp.isArrayAllocationVal) { - val leftOp = stmt.getLeftOp - Assert.assertTrue(leftOp.isLocal) - - val arraySize = rightOp.getArrayAllocationSize - Assert.assertTrue(arraySize.isIntConstant) - Assert.assertEquals(2, arraySize.getIntValue) - - checked = true - } - } - }) - - Assert.assertTrue(checked) - } - - @Test - def constantAssignmentTest(): Unit = { - val opalSetup = new OpalSetup() - opalSetup.setupOpal(classOf[AssignmentTarget].getName) - - val signature = new MethodSignature( - classOf[AssignmentTarget].getName, - "constantAssignment", - "Void" - ) - val method = opalSetup.resolveMethod(signature) - val opalMethod = OpalMethod(method) - - var constantCount = 0 - opalMethod.getStatements.forEach(stmt => { - if (stmt.isAssignStmt) { - val leftOp = stmt.getLeftOp - val rightOp = stmt.getRightOp - - Assert.assertTrue(leftOp.isLocal) - - if (rightOp.isIntConstant) { - constantCount += 1 - - Assert.assertEquals(10, rightOp.getIntValue) - Assert.assertTrue(rightOp.getType.toString.equals("int")) - } - - if (rightOp.isLongConstant) { - constantCount += 1 - - Assert.assertEquals(1000, rightOp.getLongValue) - Assert.assertTrue(rightOp.getType.toString.equals("long")) - } - - if (rightOp.isStringConstant) { - constantCount += 1 - - Assert.assertTrue(rightOp.getStringValue.equals("test")) - Assert.assertTrue(rightOp.getType.toString.equals("java.lang.String")) - } - } - }) - - Assert.assertEquals(3, constantCount) - } - - @Test - def fieldStoreAssignmentTest(): Unit = { - val opalSetup = new OpalSetup() - opalSetup.setupOpal(classOf[AssignmentTarget].getName) - - val signature = new MethodSignature( - classOf[AssignmentTarget].getName, - "fieldStoreAssignment", - "Void" - ) - val method = opalSetup.resolveMethod(signature) - val opalMethod = OpalMethod(method) - - opalMethod.getStatements.forEach(stmt => { - if (stmt.isFieldStore) { - Assert.assertTrue(stmt.isAssignStmt) - - val leftOp = stmt.getLeftOp - val rightOp = stmt.getRightOp - - println() - } - }) - } + @Test + def arrayAllocationTest(): Unit = { + val opalSetup = new OpalSetup() + opalSetup.setupOpal(classOf[AssignmentTarget].getName) + + val signature = new MethodSignature( + classOf[AssignmentTarget].getName, + "arrayAllocation", + "V" + ) + val method = opalSetup.resolveMethod(signature) + val opalMethod = OpalMethod(method) + + var arrayAllocationCount = 0 + opalMethod.getStatements.forEach(stmt => { + if (stmt.isAssignStmt) { + val rightOp = stmt.getRightOp + + if (rightOp.isArrayAllocationVal) { + arrayAllocationCount += 1 + + val leftOp = stmt.getLeftOp + Assert.assertTrue(leftOp.isLocal) + + Assert.assertTrue(rightOp.getArrayAllocationSize.isIntConstant) + Assert.assertEquals(2, rightOp.getArrayAllocationSize.getIntValue) + } + } + }) + + Assert.assertEquals(1, arrayAllocationCount) + } + + @Test + def multiArrayAllocationTest(): Unit = { + val opalSetup = new OpalSetup() + opalSetup.setupOpal(classOf[AssignmentTarget].getName) + + val signature = new MethodSignature( + classOf[AssignmentTarget].getName, + "multiArrayAllocation", + "V" + ) + val method = opalSetup.resolveMethod(signature) + val opalMethod = OpalMethod(method) + + var checked = false + opalMethod.getStatements.forEach(stmt => { + if (stmt.isAssignStmt) { + val rightOp = stmt.getRightOp + + if (rightOp.isArrayAllocationVal) { + val leftOp = stmt.getLeftOp + Assert.assertTrue(leftOp.isLocal) + + val arraySize = rightOp.getArrayAllocationSize + Assert.assertTrue(arraySize.isIntConstant) + Assert.assertEquals(2, arraySize.getIntValue) + + checked = true + } + } + }) + + Assert.assertTrue(checked) + } + + @Test + def constantAssignmentTest(): Unit = { + val opalSetup = new OpalSetup() + opalSetup.setupOpal(classOf[AssignmentTarget].getName) + + val signature = new MethodSignature( + classOf[AssignmentTarget].getName, + "constantAssignment", + "Void" + ) + val method = opalSetup.resolveMethod(signature) + val opalMethod = OpalMethod(method) + + var constantCount = 0 + opalMethod.getStatements.forEach(stmt => { + if (stmt.isAssignStmt) { + val leftOp = stmt.getLeftOp + val rightOp = stmt.getRightOp + + Assert.assertTrue(leftOp.isLocal) + + if (rightOp.isIntConstant) { + constantCount += 1 + + Assert.assertEquals(10, rightOp.getIntValue) + Assert.assertTrue(rightOp.getType.toString.equals("int")) + } + + if (rightOp.isLongConstant) { + constantCount += 1 + + Assert.assertEquals(1000, rightOp.getLongValue) + Assert.assertTrue(rightOp.getType.toString.equals("long")) + } + + if (rightOp.isStringConstant) { + constantCount += 1 + + Assert.assertTrue(rightOp.getStringValue.equals("test")) + Assert.assertTrue(rightOp.getType.toString.equals("java.lang.String")) + } + } + }) + + Assert.assertEquals(3, constantCount) + } + + @Test + def fieldStoreAssignmentTest(): Unit = { + val opalSetup = new OpalSetup() + opalSetup.setupOpal(classOf[AssignmentTarget].getName) + + val signature = new MethodSignature( + classOf[AssignmentTarget].getName, + "fieldStoreAssignment", + "Void" + ) + val method = opalSetup.resolveMethod(signature) + val opalMethod = OpalMethod(method) + + opalMethod.getStatements.forEach(stmt => { + if (stmt.isFieldStore) { + Assert.assertTrue(stmt.isAssignStmt) + + val leftOp = stmt.getLeftOp + val rightOp = stmt.getRightOp + + println() + } + }) + } } diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalControlFlowGraphTest.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalControlFlowGraphTest.scala index 98160d299..965c9191b 100644 --- a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalControlFlowGraphTest.scala +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalControlFlowGraphTest.scala @@ -23,29 +23,29 @@ import org.opalj.br.IntegerType class OpalControlFlowGraphTest { - private val integerType = IntegerType.toJVMTypeName - - @Test - def controlFlowGraphTest(): Unit = { - val opalSetup = new OpalSetup() - opalSetup.setupOpal(classOf[ControlFlowGraphTarget].getName) - - val signature = new MethodSignature( - classOf[ControlFlowGraphTarget].getName, - "compute", - integerType - ) - val method = opalSetup.resolveMethod(signature) - val opalMethod = OpalMethod(method) - - val cfg = opalMethod.getControlFlowGraph - Assert.assertTrue(cfg.getStatements.size() > 0) - Assert.assertEquals(1, cfg.getStartPoints.size()) - Assert.assertEquals(2, cfg.getEndPoints.size()) - - cfg.getEndPoints.forEach(stmt => { - Assert.assertTrue(stmt.isReturnStmt) - }) - } + private val integerType = IntegerType.toJVMTypeName + + @Test + def controlFlowGraphTest(): Unit = { + val opalSetup = new OpalSetup() + opalSetup.setupOpal(classOf[ControlFlowGraphTarget].getName) + + val signature = new MethodSignature( + classOf[ControlFlowGraphTarget].getName, + "compute", + integerType + ) + val method = opalSetup.resolveMethod(signature) + val opalMethod = OpalMethod(method) + + val cfg = opalMethod.getControlFlowGraph + Assert.assertTrue(cfg.getStatements.size() > 0) + Assert.assertEquals(1, cfg.getStartPoints.size()) + Assert.assertEquals(2, cfg.getEndPoints.size()) + + cfg.getEndPoints.forEach(stmt => { + Assert.assertTrue(stmt.isReturnStmt) + }) + } } diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalFieldTest.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalFieldTest.scala index bfc711448..7eb5cbf1b 100644 --- a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalFieldTest.scala +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalFieldTest.scala @@ -24,219 +24,219 @@ import org.junit.Test class OpalFieldTest { - @Test - def fieldLoadTest(): Unit = { - val opalSetup = new OpalSetup() - opalSetup.setupOpal(classOf[FieldTarget].getName) - - val signature = - new MethodSignature(classOf[FieldTarget].getName, "fieldLoad", "Void") - val method = opalSetup.resolveMethod(signature) - val opalMethod = OpalMethod(method) - - var fieldLoadCount = 0 - opalMethod.getStatements.forEach(stmt => { - if (stmt.isFieldLoad) { - fieldLoadCount += 1 - - val field = stmt.getLoadedField - Assert.assertFalse(field.isPredefinedField) - Assert.assertFalse(field.isInnerClassField) - - val fieldLoad = stmt.getFieldLoad - val classType = fieldLoad.getX.getType.toString - Assert.assertTrue( - classType.equals("int") || classType.equals( - classOf[FieldClass].getName - ) - ) - - val fieldType = fieldLoad.getY.getType.toString - Assert.assertFalse(fieldLoad.getY.isPredefinedField) - Assert.assertTrue( - fieldType.equals("int") || fieldType.equals(classOf[A].getName) - ) - } - }) - - Assert.assertEquals(2, fieldLoadCount) - } - - @Test - def fieldStoreTest(): Unit = { - val opalSetup = new OpalSetup() - opalSetup.setupOpal(classOf[FieldTarget].getName) - - val signature = - new MethodSignature(classOf[FieldTarget].getName, "fieldStore", "Void") - val method = opalSetup.resolveMethod(signature) - val opalMethod = OpalMethod(method) - - var fieldStoreCount = 0 - opalMethod.getStatements.forEach(stmt => { - if (stmt.isFieldStore) { - fieldStoreCount += 1 - - val fieldStore = stmt.getFieldStore - val fieldClass = fieldStore.getX.getType.toString - Assert.assertTrue( - fieldClass.equals("int") || fieldClass.equals( - classOf[FieldClass].getName - ) - ) - - val fieldType = fieldStore.getY.getType.toString - Assert.assertFalse(fieldStore.getY.isPredefinedField) - Assert.assertFalse(fieldStore.getY.isInnerClassField) - Assert.assertTrue( - fieldType.equals("int") || fieldType.equals(classOf[A].getName) - ) - } - }) - - Assert.assertEquals(2, fieldStoreCount) - } - - @Test - def staticFieldLoadTest(): Unit = { - val opalSetup = new OpalSetup() - opalSetup.setupOpal(classOf[FieldTarget].getName) - - val signature = new MethodSignature( - classOf[FieldTarget].getName, - "staticFieldLoad", - "Void" + @Test + def fieldLoadTest(): Unit = { + val opalSetup = new OpalSetup() + opalSetup.setupOpal(classOf[FieldTarget].getName) + + val signature = + new MethodSignature(classOf[FieldTarget].getName, "fieldLoad", "Void") + val method = opalSetup.resolveMethod(signature) + val opalMethod = OpalMethod(method) + + var fieldLoadCount = 0 + opalMethod.getStatements.forEach(stmt => { + if (stmt.isFieldLoad) { + fieldLoadCount += 1 + + val field = stmt.getLoadedField + Assert.assertFalse(field.isPredefinedField) + Assert.assertFalse(field.isInnerClassField) + + val fieldLoad = stmt.getFieldLoad + val classType = fieldLoad.getX.getType.toString + Assert.assertTrue( + classType.equals("int") || classType.equals( + classOf[FieldClass].getName + ) ) - val method = opalSetup.resolveMethod(signature) - val opalMethod = OpalMethod(method) - - var staticFieldLoadCount = 0 - opalMethod.getStatements.forEach(stmt => { - if (stmt.isStaticFieldLoad) { - staticFieldLoadCount += 1 - - val staticField = stmt.getStaticField - Assert.assertFalse(staticField.field().isPredefinedField) - Assert.assertFalse(staticField.field().isInnerClassField) - - val typeName = staticField.getType.toString - Assert.assertTrue( - typeName.equals("int") || typeName.equals(classOf[A].getName) - ) - } - }) - - Assert.assertEquals(2, staticFieldLoadCount) - } - - @Test - def staticFieldStoreTest(): Unit = { - val opalSetup = new OpalSetup() - opalSetup.setupOpal(classOf[FieldTarget].getName) - - val signature = new MethodSignature( - classOf[FieldTarget].getName, - "staticFieldStore", - "Void" + + val fieldType = fieldLoad.getY.getType.toString + Assert.assertFalse(fieldLoad.getY.isPredefinedField) + Assert.assertTrue( + fieldType.equals("int") || fieldType.equals(classOf[A].getName) + ) + } + }) + + Assert.assertEquals(2, fieldLoadCount) + } + + @Test + def fieldStoreTest(): Unit = { + val opalSetup = new OpalSetup() + opalSetup.setupOpal(classOf[FieldTarget].getName) + + val signature = + new MethodSignature(classOf[FieldTarget].getName, "fieldStore", "Void") + val method = opalSetup.resolveMethod(signature) + val opalMethod = OpalMethod(method) + + var fieldStoreCount = 0 + opalMethod.getStatements.forEach(stmt => { + if (stmt.isFieldStore) { + fieldStoreCount += 1 + + val fieldStore = stmt.getFieldStore + val fieldClass = fieldStore.getX.getType.toString + Assert.assertTrue( + fieldClass.equals("int") || fieldClass.equals( + classOf[FieldClass].getName + ) + ) + + val fieldType = fieldStore.getY.getType.toString + Assert.assertFalse(fieldStore.getY.isPredefinedField) + Assert.assertFalse(fieldStore.getY.isInnerClassField) + Assert.assertTrue( + fieldType.equals("int") || fieldType.equals(classOf[A].getName) + ) + } + }) + + Assert.assertEquals(2, fieldStoreCount) + } + + @Test + def staticFieldLoadTest(): Unit = { + val opalSetup = new OpalSetup() + opalSetup.setupOpal(classOf[FieldTarget].getName) + + val signature = new MethodSignature( + classOf[FieldTarget].getName, + "staticFieldLoad", + "Void" + ) + val method = opalSetup.resolveMethod(signature) + val opalMethod = OpalMethod(method) + + var staticFieldLoadCount = 0 + opalMethod.getStatements.forEach(stmt => { + if (stmt.isStaticFieldLoad) { + staticFieldLoadCount += 1 + + val staticField = stmt.getStaticField + Assert.assertFalse(staticField.field().isPredefinedField) + Assert.assertFalse(staticField.field().isInnerClassField) + + val typeName = staticField.getType.toString + Assert.assertTrue( + typeName.equals("int") || typeName.equals(classOf[A].getName) ) - val method = opalSetup.resolveMethod(signature) - val opalMethod = OpalMethod(method) - - var staticFieldStoreCount = 0 - opalMethod.getStatements.forEach(stmt => { - if (stmt.isStaticFieldStore) { - staticFieldStoreCount += 1 - - val staticField = stmt.getStaticField - Assert.assertFalse(staticField.field().isPredefinedField) - Assert.assertFalse(staticField.field().isInnerClassField) - - val typeName = staticField.getType.toString - Assert.assertTrue( - typeName.equals("int") || typeName.equals(classOf[A].getName) - ) - } - }) - - Assert.assertEquals(2, staticFieldStoreCount) - } - - @Test - def innerFieldLoadTest(): Unit = { - val opalSetup = new OpalSetup() - opalSetup.setupOpal(classOf[FieldTarget].getName) - - val signature = new MethodSignature( - classOf[FieldTarget].getName, - "innerFieldLoad", - "Void" + } + }) + + Assert.assertEquals(2, staticFieldLoadCount) + } + + @Test + def staticFieldStoreTest(): Unit = { + val opalSetup = new OpalSetup() + opalSetup.setupOpal(classOf[FieldTarget].getName) + + val signature = new MethodSignature( + classOf[FieldTarget].getName, + "staticFieldStore", + "Void" + ) + val method = opalSetup.resolveMethod(signature) + val opalMethod = OpalMethod(method) + + var staticFieldStoreCount = 0 + opalMethod.getStatements.forEach(stmt => { + if (stmt.isStaticFieldStore) { + staticFieldStoreCount += 1 + + val staticField = stmt.getStaticField + Assert.assertFalse(staticField.field().isPredefinedField) + Assert.assertFalse(staticField.field().isInnerClassField) + + val typeName = staticField.getType.toString + Assert.assertTrue( + typeName.equals("int") || typeName.equals(classOf[A].getName) ) - val method = opalSetup.resolveMethod(signature) - val opalMethod = OpalMethod(method) - - var fieldLoadCount = 0 - opalMethod.getStatements.forEach(stmt => { - if (stmt.isFieldLoad) { - fieldLoadCount += 1 - - val field = stmt.getLoadedField - Assert.assertFalse(field.isPredefinedField) - Assert.assertTrue(field.isInnerClassField) - - val fieldLoad = stmt.getFieldLoad - val classType = fieldLoad.getX.getType.toString - Assert.assertTrue( - classType.equals("int") || classType.equals( - classOf[FieldClass.InnerFieldClass].getName - ) - ) - - val fieldType = fieldLoad.getY.getType.toString - Assert.assertFalse(fieldLoad.getY.isPredefinedField) - Assert.assertTrue( - fieldType.equals("int") || fieldType.equals(classOf[A].getName) - ) - } - }) - - Assert.assertEquals(2, fieldLoadCount) - } - - @Test - def innerFieldStoreTest(): Unit = { - val opalSetup = new OpalSetup() - opalSetup.setupOpal(classOf[FieldTarget].getName) - - val signature = new MethodSignature( - classOf[FieldTarget].getName, - "innerFieldStore", - "Void" + } + }) + + Assert.assertEquals(2, staticFieldStoreCount) + } + + @Test + def innerFieldLoadTest(): Unit = { + val opalSetup = new OpalSetup() + opalSetup.setupOpal(classOf[FieldTarget].getName) + + val signature = new MethodSignature( + classOf[FieldTarget].getName, + "innerFieldLoad", + "Void" + ) + val method = opalSetup.resolveMethod(signature) + val opalMethod = OpalMethod(method) + + var fieldLoadCount = 0 + opalMethod.getStatements.forEach(stmt => { + if (stmt.isFieldLoad) { + fieldLoadCount += 1 + + val field = stmt.getLoadedField + Assert.assertFalse(field.isPredefinedField) + Assert.assertTrue(field.isInnerClassField) + + val fieldLoad = stmt.getFieldLoad + val classType = fieldLoad.getX.getType.toString + Assert.assertTrue( + classType.equals("int") || classType.equals( + classOf[FieldClass.InnerFieldClass].getName + ) ) - val method = opalSetup.resolveMethod(signature) - val opalMethod = OpalMethod(method) - - var fieldStoreCount = 0 - opalMethod.getStatements.forEach(stmt => { - if (stmt.isFieldStore) { - fieldStoreCount += 1 - - val fieldStore = stmt.getFieldStore - val classType = fieldStore.getX.getType.toString - Assert.assertTrue( - classType.equals("int") || classType.equals( - classOf[FieldClass.InnerFieldClass].getName - ) - ) - - val fieldType = fieldStore.getY.getType.toString - Assert.assertFalse(fieldStore.getY.isPredefinedField) - Assert.assertTrue(fieldStore.getY.isInnerClassField) - Assert.assertTrue( - fieldType.equals("int") || fieldType.equals(classOf[A].getName) - ) - } - }) - - Assert.assertEquals(2, fieldStoreCount) - } + + val fieldType = fieldLoad.getY.getType.toString + Assert.assertFalse(fieldLoad.getY.isPredefinedField) + Assert.assertTrue( + fieldType.equals("int") || fieldType.equals(classOf[A].getName) + ) + } + }) + + Assert.assertEquals(2, fieldLoadCount) + } + + @Test + def innerFieldStoreTest(): Unit = { + val opalSetup = new OpalSetup() + opalSetup.setupOpal(classOf[FieldTarget].getName) + + val signature = new MethodSignature( + classOf[FieldTarget].getName, + "innerFieldStore", + "Void" + ) + val method = opalSetup.resolveMethod(signature) + val opalMethod = OpalMethod(method) + + var fieldStoreCount = 0 + opalMethod.getStatements.forEach(stmt => { + if (stmt.isFieldStore) { + fieldStoreCount += 1 + + val fieldStore = stmt.getFieldStore + val classType = fieldStore.getX.getType.toString + Assert.assertTrue( + classType.equals("int") || classType.equals( + classOf[FieldClass.InnerFieldClass].getName + ) + ) + + val fieldType = fieldStore.getY.getType.toString + Assert.assertFalse(fieldStore.getY.isPredefinedField) + Assert.assertTrue(fieldStore.getY.isInnerClassField) + Assert.assertTrue( + fieldType.equals("int") || fieldType.equals(classOf[A].getName) + ) + } + }) + + Assert.assertEquals(2, fieldStoreCount) + } } diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala index 7d134b236..1b30fa6f2 100644 --- a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalInvokeExprTest.scala @@ -32,82 +32,82 @@ import scala.jdk.javaapi.CollectionConverters class OpalInvokeExprTest { - @Test - def instanceInvokeExprTest(): Unit = { - val opalSetup = new OpalSetup() - opalSetup.setupOpal(classOf[SingleTarget].getName) - - val signature = - new MethodSignature(classOf[SingleTarget].getName, "getAndSetField", "V") - val method = opalSetup.resolveMethod(signature) - val opalMethod = OpalMethod(method) - opalMethod.getControlFlowGraph - - // Update the project's config to set the test method as the (single) entry point. See - // https://github.com/opalj/opal/blob/ff01c1c9e696946a88b090a52881a41445cf07f1/DEVELOPING_OPAL/tools/src/main/scala/org/opalj/support/info/CallGraph.scala#L406 - var config = OpalClient.project.get.config - - val key = InitialEntryPointsKey.ConfigKeyPrefix + "entryPoints" - val currentValues = config.getList(key).unwrapped - - val configValue = new util.HashMap[String, String] - configValue.put( - "declaringClass", - method.classFile.thisType.toJava.replace(".", "/") - ) - configValue.put("name", method.name) - - currentValues.add(ConfigValueFactory.fromMap(configValue)) - config = config.withValue(key, ConfigValueFactory.fromIterable(currentValues)) - config = config.withValue( - InitialEntryPointsKey.ConfigKeyPrefix + "analysis", - ConfigValueFactory.fromAnyRef( - "org.opalj.br.analyses.cg.ConfigurationEntryPointsFinder" - ) - ) - val project = Project.recreate( - OpalClient.project.get, - config, - useOldConfigAsFallback = true - ) - - val callGraph: CallGraph = project.get(CHACallGraphKey) - val scope = new OpalFrameworkScope( - project, - callGraph, - CollectionConverters.asScala(util.Set.of(method)).toSet, - DataFlowScope.EXCLUDE_PHANTOM_CLASSES - ) - - println(opalMethod.tac.statements.mkString("Array(\n\t", "\n\t", "\n)")) - } - - @Test - def staticInvokeExprTest(): Unit = { - val opalSetup = new OpalSetup() - opalSetup.setupOpal(classOf[InvokeExprTarget].getName) - - val signature = new MethodSignature( - classOf[InvokeExprTarget].getName, - "staticInvokeExpr", - "V" - ) - val method = opalSetup.resolveMethod(signature) - val opalMethod = OpalMethod(method) - - var checked = false - opalMethod.getStatements.forEach(stmt => { - if (stmt.containsInvokeExpr()) { - val invokeExpr = stmt.getInvokeExpr - - Assert.assertTrue(invokeExpr.isStaticInvokeExpr) - Assert.assertEquals(2, invokeExpr.getArgs.size()) - - checked = true - } - }) - - Assert.assertTrue(checked) - } + @Test + def instanceInvokeExprTest(): Unit = { + val opalSetup = new OpalSetup() + opalSetup.setupOpal(classOf[SingleTarget].getName) + + val signature = + new MethodSignature(classOf[SingleTarget].getName, "getAndSetField", "V") + val method = opalSetup.resolveMethod(signature) + val opalMethod = OpalMethod(method) + opalMethod.getControlFlowGraph + + // Update the project's config to set the test method as the (single) entry point. See + // https://github.com/opalj/opal/blob/ff01c1c9e696946a88b090a52881a41445cf07f1/DEVELOPING_OPAL/tools/src/main/scala/org/opalj/support/info/CallGraph.scala#L406 + var config = OpalClient.project.get.config + + val key = InitialEntryPointsKey.ConfigKeyPrefix + "entryPoints" + val currentValues = config.getList(key).unwrapped + + val configValue = new util.HashMap[String, String] + configValue.put( + "declaringClass", + method.classFile.thisType.toJava.replace(".", "/") + ) + configValue.put("name", method.name) + + currentValues.add(ConfigValueFactory.fromMap(configValue)) + config = config.withValue(key, ConfigValueFactory.fromIterable(currentValues)) + config = config.withValue( + InitialEntryPointsKey.ConfigKeyPrefix + "analysis", + ConfigValueFactory.fromAnyRef( + "org.opalj.br.analyses.cg.ConfigurationEntryPointsFinder" + ) + ) + val project = Project.recreate( + OpalClient.project.get, + config, + useOldConfigAsFallback = true + ) + + val callGraph: CallGraph = project.get(CHACallGraphKey) + val scope = new OpalFrameworkScope( + project, + callGraph, + CollectionConverters.asScala(util.Set.of(method)).toSet, + DataFlowScope.EXCLUDE_PHANTOM_CLASSES + ) + + println(opalMethod.tac.statements.mkString("Array(\n\t", "\n\t", "\n)")) + } + + @Test + def staticInvokeExprTest(): Unit = { + val opalSetup = new OpalSetup() + opalSetup.setupOpal(classOf[InvokeExprTarget].getName) + + val signature = new MethodSignature( + classOf[InvokeExprTarget].getName, + "staticInvokeExpr", + "V" + ) + val method = opalSetup.resolveMethod(signature) + val opalMethod = OpalMethod(method) + + var checked = false + opalMethod.getStatements.forEach(stmt => { + if (stmt.containsInvokeExpr()) { + val invokeExpr = stmt.getInvokeExpr + + Assert.assertTrue(invokeExpr.isStaticInvokeExpr) + Assert.assertEquals(2, invokeExpr.getArgs.size()) + + checked = true + } + }) + + Assert.assertTrue(checked) + } } diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalLocalTest.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalLocalTest.scala index bbdf05c10..f4482cfe6 100644 --- a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalLocalTest.scala +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalLocalTest.scala @@ -26,88 +26,88 @@ import org.opalj.br.IntegerType class OpalLocalTest { - private val integerType = IntegerType.toJVMTypeName - - @Test - def thisLocalTest(): Unit = { - val opalSetup = new OpalSetup() - opalSetup.setupOpal(classOf[ThisLocalTarget].getName) - - val signature = - new MethodSignature(classOf[ThisLocalTarget].getName, "call", "Void") - val method = opalSetup.resolveMethod(signature) - val opalMethod = OpalMethod(method) - - var checked = false - opalMethod.getStatements.forEach(stmt => { - if (stmt - .containsInvokeExpr() && stmt.getInvokeExpr.getDeclaredMethod.getName - .equals("callWithThis") - ) { - val invokeExpr = stmt.getInvokeExpr - val base = invokeExpr.getBase - - Assert.assertTrue(opalMethod.getThisLocal.equals(base)) - Assert.assertTrue(base.equals(opalMethod.getThisLocal)) - Assert.assertTrue(opalMethod.isThisLocal(base)) - - checked = true - } - }) - - Assert.assertTrue(checked) - } - - @Test - def parameterLocalTest(): Unit = { - val opalSetup = new OpalSetup() - opalSetup.setupOpal(classOf[ParameterLocalsTarget].getName) - - // No parameters - val noArgsSignature = new MethodSignature( - classOf[ParameterLocalsTarget].getName, - "noParameters", - "Void" - ) - val noArgs = opalSetup.resolveMethod(noArgsSignature) - val noArgsMethod = OpalMethod(noArgs) - - Assert.assertTrue(noArgsMethod.getParameterLocals.isEmpty) - - // One parameter (primitive type) - val oneArgSignature = new MethodSignature( - classOf[ParameterLocalsTarget].getName, - "oneParameter", - "Void", - util.List.of(integerType) - ) - val oneArg = opalSetup.resolveMethod(oneArgSignature) - val oneArgMethod = OpalMethod(oneArg) - - Assert.assertEquals(1, oneArgMethod.getParameterLocals.size) - Assert.assertEquals( - "int", - oneArgMethod.getParameterLocal(0).getType.toString - ) - - // Two parameters (primitive type + RefType) - val twoArgSignature = new MethodSignature( - classOf[ParameterLocalsTarget].getName, - "twoParameters", - "Void", - util.List.of(integerType, s"L${classOf[A].getName}L") - ) - val twoArgs = opalSetup.resolveMethod(twoArgSignature) - val twoArgsMethod = OpalMethod(twoArgs) - - Assert.assertEquals(2, twoArgsMethod.getParameterLocals.size) - Assert.assertEquals( - "int", - twoArgsMethod.getParameterLocal(0).getType.toString - ) - Assert.assertEquals( - classOf[A].getName, - twoArgsMethod.getParameterLocal(1).getType.toString - ) - } + private val integerType = IntegerType.toJVMTypeName + + @Test + def thisLocalTest(): Unit = { + val opalSetup = new OpalSetup() + opalSetup.setupOpal(classOf[ThisLocalTarget].getName) + + val signature = + new MethodSignature(classOf[ThisLocalTarget].getName, "call", "Void") + val method = opalSetup.resolveMethod(signature) + val opalMethod = OpalMethod(method) + + var checked = false + opalMethod.getStatements.forEach(stmt => { + if (stmt + .containsInvokeExpr() && stmt.getInvokeExpr.getDeclaredMethod.getName + .equals("callWithThis") + ) { + val invokeExpr = stmt.getInvokeExpr + val base = invokeExpr.getBase + + Assert.assertTrue(opalMethod.getThisLocal.equals(base)) + Assert.assertTrue(base.equals(opalMethod.getThisLocal)) + Assert.assertTrue(opalMethod.isThisLocal(base)) + + checked = true + } + }) + + Assert.assertTrue(checked) + } + + @Test + def parameterLocalTest(): Unit = { + val opalSetup = new OpalSetup() + opalSetup.setupOpal(classOf[ParameterLocalsTarget].getName) + + // No parameters + val noArgsSignature = new MethodSignature( + classOf[ParameterLocalsTarget].getName, + "noParameters", + "Void" + ) + val noArgs = opalSetup.resolveMethod(noArgsSignature) + val noArgsMethod = OpalMethod(noArgs) + + Assert.assertTrue(noArgsMethod.getParameterLocals.isEmpty) + + // One parameter (primitive type) + val oneArgSignature = new MethodSignature( + classOf[ParameterLocalsTarget].getName, + "oneParameter", + "Void", + util.List.of(integerType) + ) + val oneArg = opalSetup.resolveMethod(oneArgSignature) + val oneArgMethod = OpalMethod(oneArg) + + Assert.assertEquals(1, oneArgMethod.getParameterLocals.size) + Assert.assertEquals( + "int", + oneArgMethod.getParameterLocal(0).getType.toString + ) + + // Two parameters (primitive type + RefType) + val twoArgSignature = new MethodSignature( + classOf[ParameterLocalsTarget].getName, + "twoParameters", + "Void", + util.List.of(integerType, s"L${classOf[A].getName}L") + ) + val twoArgs = opalSetup.resolveMethod(twoArgSignature) + val twoArgsMethod = OpalMethod(twoArgs) + + Assert.assertEquals(2, twoArgsMethod.getParameterLocals.size) + Assert.assertEquals( + "int", + twoArgsMethod.getParameterLocal(0).getType.toString + ) + Assert.assertEquals( + classOf[A].getName, + twoArgsMethod.getParameterLocal(1).getType.toString + ) + } } diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalSetup.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalSetup.scala index ab8d49ebd..6881fc594 100644 --- a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalSetup.scala +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/OpalSetup.scala @@ -26,34 +26,34 @@ import scala.collection.immutable.ArraySeq class OpalSetup { - var targetClass: Option[ClassFile] = None - - def setupOpal(targetClassName: String): Unit = { - OPALLogger.updateLogger(GlobalLogContext, DevNullLogger) - val project = Project(new File(TargetClassPath.TARGET_CLASS_PATH)) - - OpalClient.init(project) - targetClass = project.classFile(ObjectType(targetClassName.replace(".", "/"))) + var targetClass: Option[ClassFile] = None + + def setupOpal(targetClassName: String): Unit = { + OPALLogger.updateLogger(GlobalLogContext, DevNullLogger) + val project = Project(new File(TargetClassPath.TARGET_CLASS_PATH)) + + OpalClient.init(project) + targetClass = project.classFile(ObjectType(targetClassName.replace(".", "/"))) + } + + def resolveMethod(methodSignature: MethodSignature): Method = { + val parameterFields = + ArraySeq.from(methodSignature.getParameters.toArray.collect({ + case p: String => FieldType(p.replace(".", "/")) + case _ => throw new IllegalArgumentException("No String") + })) + val returnType = ReturnType(methodSignature.getReturnType) + + val method = targetClass.get.findMethod( + methodSignature.getMethodName, + MethodDescriptor(parameterFields, returnType) + ) + if (method.isEmpty) { + throw new RuntimeException( + "Could not find method " + methodSignature.getMethodName + " in class " + methodSignature.getDeclaringClass + ) } - def resolveMethod(methodSignature: MethodSignature): Method = { - val parameterFields = - ArraySeq.from(methodSignature.getParameters.toArray.collect({ - case p: String => FieldType(p.replace(".", "/")) - case _ => throw new IllegalArgumentException("No String") - })) - val returnType = ReturnType(methodSignature.getReturnType) - - val method = targetClass.get.findMethod( - methodSignature.getMethodName, - MethodDescriptor(parameterFields, returnType) - ) - if (method.isEmpty) { - throw new RuntimeException( - "Could not find method " + methodSignature.getMethodName + " in class " + methodSignature.getDeclaringClass - ) - } - - method.get - } + method.get + } } diff --git a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/TacBodyBuilderTest.scala b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/TacBodyBuilderTest.scala index 439fca712..a155d05e9 100644 --- a/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/TacBodyBuilderTest.scala +++ b/boomerangScope-Opal/src/test/scala/boomerang/scope/opal/TacBodyBuilderTest.scala @@ -32,82 +32,82 @@ import scala.jdk.CollectionConverters._ class TacBodyBuilderTest { - @Test - def applyTacBodyBuilderTest(): Unit = { - OPALLogger.updateLogger(GlobalLogContext, DevNullLogger) - val jdkFiles = loadJDKFiles() - - val project = Project(jdkFiles, Array.empty[File]) - project.allProjectClassFiles.foreach(cf => { - cf.methods.foreach(method => { - if (!isOnIgnoreList(method)) { - TacBodyBuilder(project, method) - } - }) - }) - } - - def isOnIgnoreList(method: Method): Boolean = { - // No existing body -> No transformation possible - if (method.body.isEmpty) return true - - // Consider only java.lang package classes to reduce the number of classes - // TODO - // Maybe create additional tests for other packages (java.io, java.util) that run in parallel. - // Running them sequential would take too long - if (!method.toJava.startsWith("java.lang.")) return true - - // Static initializers may be very complex and take some time to compute (e.g. com.sun.crypto.provider.AESCrypt) - if (method.isStaticInitializer) return true - - // Bug in Opal causes an exception - if (method.toJava.equals( - "java.lang.Thread{ private static long nextThreadID() }" - ) - ) return true - if (method.toJava.equals( - "java.util.concurrent.CompletableFuture$Signaller{ public boolean isReleasable() }" - ) - ) return true - - false - } - - def loadJDKFiles(): Array[File] = { - val javaHome = sys.env("JAVA_HOME") - val jmodPath = Paths.get(javaHome, "jmods", "java.base.jmod") - - val outputDir = Paths.get("extracted_classes") - Files.createDirectories(outputDir) - - val classFiles = ArrayBuffer[File]() - - // Open the .jmod file as a zip filesystem - val uri = URI.create(s"jar:${jmodPath.toUri}") - val env = Map("create" -> "false").asJava - - val fs = FileSystems.newFileSystem(uri, env) - val rootPath = fs.getPath("/classes") - - // Walk the file tree inside the jmod's /classes directory - Files - .walk(rootPath) - .iterator() - .asScala - .filter(p => Files.isRegularFile(p) && p.toString.endsWith(".class")) - .foreach { classPath => - val relativePath = rootPath.relativize(classPath) - val targetPath = outputDir.resolve(relativePath.toString) - - Files.createDirectories(targetPath.getParent) - Files.copy(classPath, targetPath, StandardCopyOption.REPLACE_EXISTING) - - classFiles += targetPath.toFile - } - - fs.close() - - classFiles.toArray - } + @Test + def applyTacBodyBuilderTest(): Unit = { + OPALLogger.updateLogger(GlobalLogContext, DevNullLogger) + val jdkFiles = loadJDKFiles() + + val project = Project(jdkFiles, Array.empty[File]) + project.allProjectClassFiles.foreach(cf => { + cf.methods.foreach(method => { + if (!isOnIgnoreList(method)) { + TacBodyBuilder(project, method) + } + }) + }) + } + + def isOnIgnoreList(method: Method): Boolean = { + // No existing body -> No transformation possible + if (method.body.isEmpty) return true + + // Consider only java.lang package classes to reduce the number of classes + // TODO + // Maybe create additional tests for other packages (java.io, java.util) that run in parallel. + // Running them sequential would take too long + if (!method.toJava.startsWith("java.lang.")) return true + + // Static initializers may be very complex and take some time to compute (e.g. com.sun.crypto.provider.AESCrypt) + if (method.isStaticInitializer) return true + + // Bug in Opal causes an exception + if (method.toJava.equals( + "java.lang.Thread{ private static long nextThreadID() }" + ) + ) return true + if (method.toJava.equals( + "java.util.concurrent.CompletableFuture$Signaller{ public boolean isReleasable() }" + ) + ) return true + + false + } + + def loadJDKFiles(): Array[File] = { + val javaHome = sys.env("JAVA_HOME") + val jmodPath = Paths.get(javaHome, "jmods", "java.base.jmod") + + val outputDir = Paths.get("extracted_classes") + Files.createDirectories(outputDir) + + val classFiles = ArrayBuffer[File]() + + // Open the .jmod file as a zip filesystem + val uri = URI.create(s"jar:${jmodPath.toUri}") + val env = Map("create" -> "false").asJava + + val fs = FileSystems.newFileSystem(uri, env) + val rootPath = fs.getPath("/classes") + + // Walk the file tree inside the jmod's /classes directory + Files + .walk(rootPath) + .iterator() + .asScala + .filter(p => Files.isRegularFile(p) && p.toString.endsWith(".class")) + .foreach { classPath => + val relativePath = rootPath.relativize(classPath) + val targetPath = outputDir.resolve(relativePath.toString) + + Files.createDirectories(targetPath.getParent) + Files.copy(classPath, targetPath, StandardCopyOption.REPLACE_EXISTING) + + classFiles += targetPath.toFile + } + + fs.close() + + classFiles.toArray + } } diff --git a/misc/.scalafmt.conf b/misc/.scalafmt.conf index 7c03480dd..ea73903db 100644 --- a/misc/.scalafmt.conf +++ b/misc/.scalafmt.conf @@ -13,8 +13,8 @@ docstrings { } indent { - main = 4 - callSite = 4 + main = 2 + callSite = 2 } indentOperator.exemptScope = aloneEnclosed diff --git a/testCore/src/main/java/test/TestingFramework.java b/testCore/src/main/java/test/TestingFramework.java index ca185243b..847fb3f94 100644 --- a/testCore/src/main/java/test/TestingFramework.java +++ b/testCore/src/main/java/test/TestingFramework.java @@ -45,7 +45,7 @@ private TestSetup getTestSetup() { String framework = System.getProperty("testSetup"); if (framework == null) { // This can be changed when executing tests locally - return new SootTestSetup(); + return new OpalTestSetup(); } switch (framework.toLowerCase()) {