├── .bettercodehub.yml ├── .gitignore ├── CREDITS.txt ├── LICENSE ├── LICENSE-Paulscode IBXM Library.txt ├── LICENSE-Paulscode SoundSystem CodecIBXM.txt ├── LICENSE.txt ├── META-INF ├── MANIFEST.MF └── RASCAL.MF ├── README.md ├── _config.yml ├── build.gradle ├── build.properties ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── logs ├── 2018-12-05-1.log.gz ├── 2018-12-05-2.log.gz ├── 2018-12-05-3.log.gz ├── 2018-12-10-1.log.gz ├── 2018-12-10-2.log.gz ├── 2018-12-10-3.log.gz ├── 2018-12-10-4.log.gz ├── 2018-12-11-1.log.gz ├── 2018-12-11-2.log.gz ├── 2018-12-11-3.log.gz ├── 2018-12-11-4.log.gz ├── 2018-12-11-5.log.gz ├── 2018-12-11-6.log.gz ├── 2018-12-11-7.log.gz ├── 2018-12-13-1.log.gz ├── 2018-12-13-2.log.gz ├── debug-1.log.gz ├── debug-2.log.gz ├── debug-3.log.gz ├── debug-4.log.gz ├── debug-5.log.gz ├── debug.log └── latest.log ├── papers ├── Course_Report.pdf ├── ICTOpen_Baars_Meester.pdf └── TechDebt_Paper.pdf └── src └── main ├── java └── com │ └── simonbaars │ ├── clonerefactor │ ├── Main.java │ ├── SequenceObservable.java │ ├── SequenceObserver.java │ ├── ast │ │ ├── CloneParser.java │ │ ├── NodeParser.java │ │ ├── NodeType.java │ │ └── interfaces │ │ │ ├── DeterminesNodeTokens.java │ │ │ ├── HasCompareList.java │ │ │ ├── Parser.java │ │ │ └── RequiresNodeOperations.java │ ├── compare │ │ ├── Compare.java │ │ ├── CompareFalse.java │ │ ├── CompareLiteral.java │ │ ├── CompareMethodCall.java │ │ ├── CompareName.java │ │ ├── CompareToken.java │ │ ├── CompareType.java │ │ ├── CompareVariable.java │ │ └── HasRange.java │ ├── datatype │ │ ├── CountMap.java │ │ ├── DoubleMap.java │ │ ├── FlattenedList.java │ │ ├── IndexedVector.java │ │ ├── ListMap.java │ │ └── SetMap.java │ ├── detection │ │ ├── CloneDetection.java │ │ ├── interfaces │ │ │ ├── CalculatesPercentages.java │ │ │ ├── ChecksThresholds.java │ │ │ └── RemovesDuplicates.java │ │ ├── type2 │ │ │ ├── Graph.java │ │ │ ├── Type2Variability.java │ │ │ └── WeightedPercentage.java │ │ └── type3 │ │ │ ├── FileLocations.java │ │ │ ├── Type3Calculation.java │ │ │ ├── Type3Location.java │ │ │ └── Type3Opportunities.java │ ├── metrics │ │ ├── MetricCollector.java │ │ ├── Metrics.java │ │ ├── ProblemType.java │ │ ├── collectors │ │ │ ├── Calculator.java │ │ │ ├── CyclomaticComplexityCalculator.java │ │ │ ├── NumberOfParametersCalculator.java │ │ │ └── UnitSizeCalculator.java │ │ └── enums │ │ │ ├── CloneContents.java │ │ │ ├── CloneLocation.java │ │ │ ├── CloneRefactorability.java │ │ │ ├── CloneRelation.java │ │ │ ├── MetricEnum.java │ │ │ └── RequiresNodeContext.java │ ├── model │ │ ├── DetectionResults.java │ │ ├── FiltersTokens.java │ │ ├── Sequence.java │ │ ├── location │ │ │ ├── Location.java │ │ │ ├── LocationContents.java │ │ │ └── LocationHolder.java │ │ └── simple │ │ │ ├── AbstractCloneInstance.java │ │ │ └── AbstractClonedStatement.java │ ├── scripts │ │ ├── RunAllConfigurations.java │ │ ├── RunOnCorpus.java │ │ ├── TryThresholds.java │ │ └── prepare │ │ │ ├── PrepareProjectsFolder.java │ │ │ └── ValidateCorpus.java │ ├── settings │ │ ├── CloneType.java │ │ ├── Scope.java │ │ └── Settings.java │ ├── thread │ │ ├── CorpusThread.java │ │ ├── ThreadPool.java │ │ └── WritesErrors.java │ └── util │ │ ├── FileUtils.java │ │ ├── NoJavaFilesFoundException.java │ │ ├── OperatingSystem.java │ │ ├── SavePaths.java │ │ └── Wait.java │ └── codearena │ ├── CloneCommand.java │ ├── CloneDetection.java │ ├── EndCommand.java │ ├── challenge │ ├── Challenges.java │ └── CodeArena.java │ ├── common │ ├── FormatsText.java │ ├── OperatingSystem.java │ ├── ResourceCommons.java │ └── SavePaths.java │ ├── editor │ ├── CodeEditor.java │ ├── CodeEditorMaker.java │ ├── GetTip.java │ ├── SaveFile.java │ └── TipViewer.java │ ├── minecraft │ ├── CDEventHandler.java │ ├── CreatorBlocks.java │ ├── ForgeEventHandler.java │ ├── ICreatorBlock.java │ ├── ModEntities.java │ ├── gui │ │ ├── CloneMenuKey.java │ │ ├── EndChallengeGUI.java │ │ ├── GUISetupCloneFinding.java │ │ └── OpenCloneGUI.java │ ├── proxy │ │ ├── ClientProxy.java │ │ ├── CommonProxy.java │ │ ├── GuiProxy.java │ │ └── ServerProxy.java │ └── structureloader │ │ ├── BlockPlaceHandler.java │ │ ├── BlockPlacer.java │ │ ├── DropFuncBlock.java │ │ ├── LightUpdateCheck.java │ │ ├── OutlineCreator.java │ │ ├── SchematicStructure.java │ │ ├── Structure.java │ │ └── StructureUtils.java │ ├── model │ ├── MetricProblem.java │ └── ProblemScore.java │ ├── monster │ ├── CodeEntity.java │ ├── UsesCustomScaleFactors.java │ ├── codecreeper │ │ ├── CodeCreeperFactory.java │ │ ├── EntityCodeCreeper.java │ │ └── RenderCodeCreeper.java │ ├── codeskeleton │ │ ├── AbstractCodeSkeleton.java │ │ ├── CodeSkeletonFactory.java │ │ ├── EntityCodeSkeleton.java │ │ ├── ModelCodeSkeleton.java │ │ └── RenderCodeSkeleton.java │ ├── codespider │ │ ├── CodeSpiderFactory.java │ │ ├── EntityCodeSpider.java │ │ ├── LayerCodeSpiderEyes.java │ │ └── RenderCodeSpider.java │ └── codezombie │ │ ├── CodeZombieFactory.java │ │ ├── EntityCodeZombie.java │ │ └── RenderCodeZombie.java │ └── thread │ ├── ProblemDetectionGoal.java │ └── ProblemDetectionThread.java ├── resources ├── assets │ ├── clonedetection │ │ ├── lang │ │ │ └── en_us.lang │ │ ├── models │ │ │ └── item │ │ │ │ ├── checkmark.json │ │ │ │ └── crossmark.json │ │ └── sounds.json │ └── minecraft │ │ ├── endchallenge.png │ │ ├── setupclonefinding.png │ │ ├── setupclonefinding.png~ │ │ └── textures │ │ └── items │ │ ├── checkbox.png │ │ └── cross.png ├── clonerefactor.properties ├── mcmod.info ├── mobs │ ├── spider.png │ └── spider_eyes.png ├── pack.mcmeta ├── structures │ ├── arena.structure │ ├── arenacheck.structure │ ├── coliseum.structure │ ├── colloseum.structure │ └── watchtower.structure └── tips │ ├── duplication.html │ ├── longmethod.html │ └── unitinterface.html └── test ├── EditorTest.java ├── EditorTest2.java ├── PackageTest.java ├── ProjectParseTest.java ├── TestConsole.java └── TestLocConverter.java /.bettercodehub.yml: -------------------------------------------------------------------------------- 1 | component_depth: 6 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # eclipse 2 | bin 3 | *.launch 4 | .settings 5 | .metadata 6 | .classpath 7 | .project 8 | 9 | # idea 10 | out 11 | *.ipr 12 | *.iws 13 | *.iml 14 | .idea 15 | 16 | # gradle 17 | build 18 | .gradle 19 | 20 | # other 21 | eclipse 22 | run 23 | -------------------------------------------------------------------------------- /CREDITS.txt: -------------------------------------------------------------------------------- 1 | Minecraft Forge: Credits/Thank You 2 | 3 | Forge is a set of tools and modifications to the Minecraft base game code to assist 4 | mod developers in creating new and exciting content. It has been in development for 5 | several years now, but I would like to take this time thank a few people who have 6 | helped it along it's way. 7 | 8 | First, the people who originally created the Forge projects way back in Minecraft 9 | alpha. Eloraam of RedPower, and SpaceToad of Buildcraft, without their acceptiance 10 | of me taking over the project, who knows what Minecraft modding would be today. 11 | 12 | Secondly, someone who has worked with me, and developed some of the core features 13 | that allow modding to he as functional, and as simple as it is, cpw. For developing 14 | FML, which stabelized the client and server modding ecosystem. As well as the base 15 | loading system that allows us to modify Minecraft's code as elegently as possible. 16 | 17 | Mezz, who has stepped up as the issue and pull request manager. Helping to keep me 18 | sane as well as guiding the community into creating better additions to Forge. 19 | 20 | Searge, Bspks, Fesh0r, ProfMobious, and all the rest over on the MCP team {of which 21 | I am a part}. For creating some of the core tools needed to make Minecraft modding 22 | both possible, and as stable as can be. 23 | On that note, here is some specific information of the MCP data we use: 24 | * Minecraft Coder Pack (MCP) * 25 | Forge Mod Loader and Minecraft Forge have permission to distribute and automatically 26 | download components of MCP and distribute MCP data files. This permission is not 27 | transitive and others wishing to redistribute the Minecraft Forge source independently 28 | should seek permission of MCP or remove the MCP data files and request their users 29 | to download MCP separately. 30 | 31 | And lastly, the countless community members who have spent time submitting bug reports, 32 | pull requests, and just helping out the community in general. Thank you. 33 | 34 | --LexManos 35 | 36 | ========================================================================= 37 | 38 | This is Forge Mod Loader. 39 | 40 | You can find the source code at all times at https://github.com/MinecraftForge/MinecraftForge/tree/1.12.x/src/main/java/net/minecraftforge/fml 41 | 42 | This minecraft mod is a clean open source implementation of a mod loader for minecraft servers 43 | and minecraft clients. 44 | 45 | The code is authored by cpw. 46 | 47 | It began by partially implementing an API defined by the client side ModLoader, authored by Risugami. 48 | http://www.minecraftforum.net/topic/75440- 49 | This support has been dropped as of Minecraft release 1.7, as Risugami no longer maintains ModLoader. 50 | 51 | It also contains suggestions and hints and generous helpings of code from LexManos, author of MinecraftForge. 52 | http://www.minecraftforge.net/ 53 | 54 | Additionally, it contains an implementation of topological sort based on that 55 | published at http://keithschwarz.com/interesting/code/?dir=topological-sort 56 | 57 | It also contains code from the Maven project for performing versioned dependency 58 | resolution. http://maven.apache.org/ 59 | 60 | It also contains a partial repackaging of the javaxdelta library from http://sourceforge.net/projects/javaxdelta/ 61 | with credit to it's authors. 62 | 63 | Forge Mod Loader downloads components from the Minecraft Coder Pack 64 | (http://mcp.ocean-labs.de/index.php/Main_Page) with kind permission from the MCP team. 65 | 66 | -------------------------------------------------------------------------------- /LICENSE-Paulscode IBXM Library.txt: -------------------------------------------------------------------------------- 1 | IBXM is copyright (c) 2007, Martin Cameron, and is licensed under the BSD License. 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 5 | 6 | Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 7 | Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 8 | Neither the name of mumart nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 9 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 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 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 10 | 11 | -------------------------------------------------------------------------------- /LICENSE-Paulscode SoundSystem CodecIBXM.txt: -------------------------------------------------------------------------------- 1 | SoundSystem CodecIBXM Class License: 2 | 3 | You are free to use this class for any purpose, commercial or otherwise. 4 | You may modify this class or source code, and distribute it any way you 5 | like, provided the following conditions are met: 6 | 7 | 1) You may not falsely claim to be the author of this class or any 8 | unmodified portion of it. 9 | 2) You may not copyright this class or a modified version of it and then 10 | sue me for copyright infringement. 11 | 3) If you modify the source code, you must clearly document the changes 12 | made before redistributing the modified source code, so other users know 13 | it is not the original code. 14 | 4) You are not required to give me credit for this class in any derived 15 | work, but if you do, you must also mention my website: 16 | http://www.paulscode.com 17 | 5) I the author will not be responsible for any damages (physical, 18 | financial, or otherwise) caused by the use if this class or any 19 | portion of it. 20 | 6) I the author do not guarantee, warrant, or make any representations, 21 | either expressed or implied, regarding the use of this class or any 22 | portion of it. 23 | 24 | Author: Paul Lamb 25 | http://www.paulscode.com 26 | 27 | 28 | This software is based on or using the IBXM library available from 29 | http://www.geocities.com/sunet2000/ 30 | 31 | 32 | IBXM is copyright (c) 2007, Martin Cameron, and is licensed under the BSD License. 33 | All rights reserved. 34 | 35 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 36 | 37 | Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 38 | Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 39 | Neither the name of mumart nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 40 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 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 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 41 | -------------------------------------------------------------------------------- /META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Bundle-ManifestVersion: 2 3 | Bundle-Name: CodeDuplication 4 | Bundle-SymbolicName: CodeDuplication 5 | Bundle-Version: 1.0.0 6 | Require-Bundle: rascal_eclipse 7 | Bundle-RequiredExecutionEnvironment: JavaSE-1.8 8 | Import-Package: org.eclipse.jgit.api 9 | -------------------------------------------------------------------------------- /META-INF/RASCAL.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 0.0.1 2 | Main-Function: main 3 | Main-Module: Plugin 4 | Source: src 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CodeArena 2 | ## Summary 3 | To make programmers aware of harmful coding practises and how they can improve their code, we propose CodeArena. CodeArena is an extension to the popular 3D sandbox game called Minecraft. It allows developers to experience incremental changes in the quality of their code and gain progressive insight in the causes of hard-to-maintain code. This tool translates features of a codebase that are considered harmful to monsters in Minecraft, which can then be "fought" to improve the codebase. Fighting the monsters will trace the user back to the source code. If the developer succeeds in solving the issue, the monster will die and the developer will be rewarded in-game. This way, the developer can gradually improve the quality of the code, while learning about code quality in an engaging way. 4 | 5 | The developer can advance between different levels and gain experience points for each metric that has been improved. Each level represents a component in the codebase. The metrics to be improved consist of code duplication, unit complexity, unit size and interface size. Points are also awarded for a decrease in code volume. Points will be subtracted if the code quality is decreased. 6 | 7 | ## Installation 8 | There are two ways to setup CodeArena: 9 | 1. **Install CodeArena as Minecraft Forge Mod:** This requires a paid Minecraft account. However, a single Minecraft account can be used for any number of CodeArena users. 10 | 2. **Run CodeArena from your IDE:** This does not require a Minecraft account, but does require to install an IDE. I will outline the installation using the Eclipse IDE here. 11 | 12 | ### Install CodeArena as Minecraft Forge Mod 13 | Download the CodeArena jar from the [Releases section of GitHub](https://github.com/SimonBaars/CodeArena/releases) (or by clicking [here](https://github.com/SimonBaars/CodeArena/releases/download/v1.2/CodeArena-1.2.jar)). Follow [this guide](https://www.minecraftmods.com/how-to-install-minecraft-forge/) to install Minecraft Forge. Make sure you install Forge for Minecraft version **1.12**. Then, follow [this guide](https://www.minecraftmods.com/how-to-install-mods-for-minecraft-forge/) to install CodeArena as a Minecraft mod. 14 | 15 | ### Run CodeArena from your IDE 16 | Download and install Eclipse from [here](https://www.eclipse.org/downloads/). Clone the CodeArena repo, and import it as a Gradle project into Eclipse. In the file explorer of Eclipse, right click the `CloneDetection_Client.launch` file in the root of the CodeArena project. In the menu, choose `Run as` and choose the first option. This will start CodeArena. 17 | 18 | ## Turning a Java project into a CodeArena 19 | To start using CodeArena, open a single player world using Minecraft. In game, press `c`. This will open the CodeArena dialog. In this window, the arena can be configured. 20 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | jcenter() 4 | maven { url = "http://files.minecraftforge.net/maven" } 5 | } 6 | dependencies { 7 | classpath 'net.minecraftforge.gradle:ForgeGradle:2.3-SNAPSHOT' 8 | } 9 | } 10 | apply plugin: 'net.minecraftforge.gradle.forge' 11 | //Only edit below this line, the above code adds and enables the necessary things for Forge to be setup. 12 | 13 | 14 | version = "1.0" 15 | group = "nl.sandersimon.clonedetection" // http://maven.apache.org/guides/mini/guide-naming-conventions.html 16 | archivesBaseName = "clonedetection" 17 | 18 | sourceCompatibility = targetCompatibility = '1.8' // Need this here so eclipse task generates correctly. 19 | compileJava { 20 | sourceCompatibility = targetCompatibility = '1.8' 21 | } 22 | 23 | minecraft { 24 | version = "1.12.2-14.23.5.2768" 25 | runDir = "run" 26 | 27 | // the mappings can be changed at any time, and must be in the following format. 28 | // snapshot_YYYYMMDD snapshot are built nightly. 29 | // stable_# stables are built at the discretion of the MCP team. 30 | // Use non-default mappings at your own risk. they may not always work. 31 | // simply re-run your setup task after changing the mappings to update your workspace. 32 | mappings = "snapshot_20171003" 33 | // makeObfSourceJar = false // an Srg named sources jar is made by default. uncomment this to disable. 34 | } 35 | 36 | dependencies { 37 | // you may put jars on which you depend on in ./libs 38 | // or you may define them like so.. 39 | //compile "some.group:artifact:version:classifier" 40 | //compile "some.group:artifact:version" 41 | 42 | // real examples 43 | //compile 'com.mod-buildcraft:buildcraft:6.0.8:dev' // adds buildcraft to the dev env 44 | //compile 'com.googlecode.efficient-java-matrix-library:ejml:0.24' // adds ejml to the dev env 45 | 46 | // the 'provided' configuration is for optional dependencies that exist at compile-time but might not at runtime. 47 | //provided 'com.mod-buildcraft:buildcraft:6.0.8:dev' 48 | 49 | // the deobf configurations: 'deobfCompile' and 'deobfProvided' are the same as the normal compile and provided, 50 | // except that these dependencies get remapped to your current MCP mappings 51 | //deobfCompile 'com.mod-buildcraft:buildcraft:6.0.8:dev' 52 | //deobfProvided 'com.mod-buildcraft:buildcraft:6.0.8:dev' 53 | 54 | // for more info... 55 | // http://www.gradle.org/docs/current/userguide/artifact_dependencies_tutorial.html 56 | // http://www.gradle.org/docs/current/userguide/dependency_management.html 57 | compile 'com.fifesoft:rsyntaxtextarea:2.6.1' 58 | compile 'com.fifesoft:rstaui:2.6.1' 59 | compile ('com.github.javaparser:javaparser-symbol-solver-core:3.14.1'){ 60 | exclude group: 'com.google.guava', module: 'guava' 61 | } 62 | compile 'com.google.code.gson:gson:2.8.2' 63 | compile 'com.google.guava:guava:23.0' 64 | compile 'org.eclipse.jgit:org.eclipse.jgit:4.5.0.201609210915-r' 65 | compile 'me.tongfei:progressbar:0.7.3' 66 | } 67 | 68 | processResources { 69 | // this will ensure that this task is redone when the versions change. 70 | inputs.property "version", project.version 71 | inputs.property "mcversion", project.minecraft.version 72 | 73 | // replace stuff in mcmod.info, nothing else 74 | from(sourceSets.main.resources.srcDirs) { 75 | include 'mcmod.info' 76 | 77 | // replace version and mcversion 78 | expand 'version':project.version, 'mcversion':project.minecraft.version 79 | } 80 | 81 | // copy everything else except the mcmod.info 82 | from(sourceSets.main.resources.srcDirs) { 83 | exclude 'mcmod.info' 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /build.properties: -------------------------------------------------------------------------------- 1 | bin.includes = META-INF/ 2 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Sets default memory used for gradle commands. Can be overridden by user or command line properties. 2 | # This is required to provide enough memory for the Minecraft decompilation process. 3 | org.gradle.jvmargs=-Xmx3G 4 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimonBaars/CodeArena/bc0c6bf90fd19ccc0f0f11c6b37f8c3163b16c4b/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Sep 14 12:28:28 PDT 2015 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.14-bin.zip 7 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /logs/2018-12-05-1.log.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimonBaars/CodeArena/bc0c6bf90fd19ccc0f0f11c6b37f8c3163b16c4b/logs/2018-12-05-1.log.gz -------------------------------------------------------------------------------- /logs/2018-12-05-2.log.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimonBaars/CodeArena/bc0c6bf90fd19ccc0f0f11c6b37f8c3163b16c4b/logs/2018-12-05-2.log.gz -------------------------------------------------------------------------------- /logs/2018-12-05-3.log.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimonBaars/CodeArena/bc0c6bf90fd19ccc0f0f11c6b37f8c3163b16c4b/logs/2018-12-05-3.log.gz -------------------------------------------------------------------------------- /logs/2018-12-10-1.log.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimonBaars/CodeArena/bc0c6bf90fd19ccc0f0f11c6b37f8c3163b16c4b/logs/2018-12-10-1.log.gz -------------------------------------------------------------------------------- /logs/2018-12-10-2.log.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimonBaars/CodeArena/bc0c6bf90fd19ccc0f0f11c6b37f8c3163b16c4b/logs/2018-12-10-2.log.gz -------------------------------------------------------------------------------- /logs/2018-12-10-3.log.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimonBaars/CodeArena/bc0c6bf90fd19ccc0f0f11c6b37f8c3163b16c4b/logs/2018-12-10-3.log.gz -------------------------------------------------------------------------------- /logs/2018-12-10-4.log.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimonBaars/CodeArena/bc0c6bf90fd19ccc0f0f11c6b37f8c3163b16c4b/logs/2018-12-10-4.log.gz -------------------------------------------------------------------------------- /logs/2018-12-11-1.log.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimonBaars/CodeArena/bc0c6bf90fd19ccc0f0f11c6b37f8c3163b16c4b/logs/2018-12-11-1.log.gz -------------------------------------------------------------------------------- /logs/2018-12-11-2.log.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimonBaars/CodeArena/bc0c6bf90fd19ccc0f0f11c6b37f8c3163b16c4b/logs/2018-12-11-2.log.gz -------------------------------------------------------------------------------- /logs/2018-12-11-3.log.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimonBaars/CodeArena/bc0c6bf90fd19ccc0f0f11c6b37f8c3163b16c4b/logs/2018-12-11-3.log.gz -------------------------------------------------------------------------------- /logs/2018-12-11-4.log.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimonBaars/CodeArena/bc0c6bf90fd19ccc0f0f11c6b37f8c3163b16c4b/logs/2018-12-11-4.log.gz -------------------------------------------------------------------------------- /logs/2018-12-11-5.log.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimonBaars/CodeArena/bc0c6bf90fd19ccc0f0f11c6b37f8c3163b16c4b/logs/2018-12-11-5.log.gz -------------------------------------------------------------------------------- /logs/2018-12-11-6.log.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimonBaars/CodeArena/bc0c6bf90fd19ccc0f0f11c6b37f8c3163b16c4b/logs/2018-12-11-6.log.gz -------------------------------------------------------------------------------- /logs/2018-12-11-7.log.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimonBaars/CodeArena/bc0c6bf90fd19ccc0f0f11c6b37f8c3163b16c4b/logs/2018-12-11-7.log.gz -------------------------------------------------------------------------------- /logs/2018-12-13-1.log.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimonBaars/CodeArena/bc0c6bf90fd19ccc0f0f11c6b37f8c3163b16c4b/logs/2018-12-13-1.log.gz -------------------------------------------------------------------------------- /logs/2018-12-13-2.log.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimonBaars/CodeArena/bc0c6bf90fd19ccc0f0f11c6b37f8c3163b16c4b/logs/2018-12-13-2.log.gz -------------------------------------------------------------------------------- /logs/debug-1.log.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimonBaars/CodeArena/bc0c6bf90fd19ccc0f0f11c6b37f8c3163b16c4b/logs/debug-1.log.gz -------------------------------------------------------------------------------- /logs/debug-2.log.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimonBaars/CodeArena/bc0c6bf90fd19ccc0f0f11c6b37f8c3163b16c4b/logs/debug-2.log.gz -------------------------------------------------------------------------------- /logs/debug-3.log.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimonBaars/CodeArena/bc0c6bf90fd19ccc0f0f11c6b37f8c3163b16c4b/logs/debug-3.log.gz -------------------------------------------------------------------------------- /logs/debug-4.log.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimonBaars/CodeArena/bc0c6bf90fd19ccc0f0f11c6b37f8c3163b16c4b/logs/debug-4.log.gz -------------------------------------------------------------------------------- /logs/debug-5.log.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimonBaars/CodeArena/bc0c6bf90fd19ccc0f0f11c6b37f8c3163b16c4b/logs/debug-5.log.gz -------------------------------------------------------------------------------- /papers/Course_Report.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimonBaars/CodeArena/bc0c6bf90fd19ccc0f0f11c6b37f8c3163b16c4b/papers/Course_Report.pdf -------------------------------------------------------------------------------- /papers/ICTOpen_Baars_Meester.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimonBaars/CodeArena/bc0c6bf90fd19ccc0f0f11c6b37f8c3163b16c4b/papers/ICTOpen_Baars_Meester.pdf -------------------------------------------------------------------------------- /papers/TechDebt_Paper.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimonBaars/CodeArena/bc0c6bf90fd19ccc0f0f11c6b37f8c3163b16c4b/papers/TechDebt_Paper.pdf -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/clonerefactor/Main.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.clonerefactor; 2 | 3 | import java.io.File; 4 | import java.io.FilenameFilter; 5 | import java.io.IOException; 6 | import java.nio.file.Path; 7 | import java.nio.file.Paths; 8 | import java.time.LocalDateTime; 9 | import java.time.format.DateTimeFormatter; 10 | 11 | import com.github.javaparser.ParserConfiguration; 12 | import com.github.javaparser.symbolsolver.JavaSymbolSolver; 13 | import com.github.javaparser.symbolsolver.resolution.typesolvers.CombinedTypeSolver; 14 | import com.github.javaparser.symbolsolver.resolution.typesolvers.JarTypeSolver; 15 | import com.github.javaparser.symbolsolver.resolution.typesolvers.JavaParserTypeSolver; 16 | import com.github.javaparser.symbolsolver.resolution.typesolvers.ReflectionTypeSolver; 17 | import com.github.javaparser.utils.SourceRoot; 18 | import com.simonbaars.clonerefactor.ast.CloneParser; 19 | import com.simonbaars.clonerefactor.model.DetectionResults; 20 | import com.simonbaars.clonerefactor.util.NoJavaFilesFoundException; 21 | 22 | public class Main { 23 | 24 | public static void main(String[] args) { 25 | System.out.println("Start parse at "+DateTimeFormatter.ofPattern("HH:mm:ss.SSS").format(LocalDateTime.now())); 26 | if(args.length == 0) 27 | new NoJavaFilesFoundException(); 28 | 29 | System.out.println(cloneDetection(args[0])); 30 | } 31 | 32 | public static DetectionResults cloneDetection(String path) { 33 | return cloneDetection(Paths.get(path)); 34 | } 35 | 36 | public static DetectionResults cloneDetection(Path path) { 37 | return cloneDetection(path, path); 38 | } 39 | 40 | public static DetectionResults cloneDetection(Path path, Path sourceRoot) { 41 | CombinedTypeSolver combinedTypeSolver = new CombinedTypeSolver(); 42 | combinedTypeSolver.add(new ReflectionTypeSolver()); 43 | combinedTypeSolver.add(new JavaParserTypeSolver(sourceRoot)); 44 | 45 | addLibrariesToTypeSolver(path, combinedTypeSolver); 46 | 47 | final ParserConfiguration config = new ParserConfiguration() 48 | .setLexicalPreservationEnabled(false) //Disabled for now, we'll enable it when we start refactoring. 49 | .setStoreTokens(true) 50 | .setSymbolResolver(new JavaSymbolSolver(combinedTypeSolver)); 51 | SourceRoot root = new SourceRoot(sourceRoot); 52 | return new CloneParser().parse(root, config); 53 | } 54 | 55 | private static void addLibrariesToTypeSolver(Path path, CombinedTypeSolver combinedTypeSolver) { 56 | File file = new File(path.toString()+File.separator+"lib"); 57 | if(file.exists()) { 58 | for(File f : file.listFiles(new FilenameFilter() { 59 | @Override 60 | public boolean accept(File dir, String name) { 61 | return name.toLowerCase().endsWith(".jar"); 62 | } 63 | })) { 64 | try { 65 | combinedTypeSolver.add(new JarTypeSolver(f)); 66 | } catch (IOException e) { 67 | e.printStackTrace(); 68 | } 69 | } 70 | } 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/clonerefactor/SequenceObservable.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.clonerefactor; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import com.simonbaars.clonerefactor.metrics.ProblemType; 7 | import com.simonbaars.clonerefactor.model.Sequence; 8 | 9 | public class SequenceObservable { 10 | private final List observers = new ArrayList<>(); 11 | private static final SequenceObservable singleton = new SequenceObservable(); 12 | 13 | public static SequenceObservable get() { 14 | return singleton; 15 | } 16 | 17 | public void sendUpdate(ProblemType problem, Sequence sequence, int problemSize) { 18 | observers.forEach(e -> e.update(problem, sequence, problemSize)); 19 | } 20 | 21 | public boolean isActive() { 22 | return !observers.isEmpty(); 23 | } 24 | 25 | public void subscribe(SequenceObserver observer) { 26 | observers.add(observer); 27 | } 28 | 29 | public void unsubscribe(SequenceObserver observer) { 30 | observers.remove(observer); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/clonerefactor/SequenceObserver.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.clonerefactor; 2 | 3 | import com.simonbaars.clonerefactor.metrics.ProblemType; 4 | import com.simonbaars.clonerefactor.model.Sequence; 5 | 6 | public interface SequenceObserver { 7 | public void update(ProblemType problem, Sequence sequence, int problemSize); 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/clonerefactor/ast/NodeParser.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.clonerefactor.ast; 2 | 3 | import java.util.Collections; 4 | import java.util.HashMap; 5 | import java.util.Map; 6 | 7 | import com.github.javaparser.ast.CompilationUnit; 8 | import com.github.javaparser.ast.ImportDeclaration; 9 | import com.github.javaparser.ast.Node; 10 | import com.github.javaparser.ast.PackageDeclaration; 11 | import com.github.javaparser.ast.body.MethodDeclaration; 12 | import com.github.javaparser.ast.stmt.BlockStmt; 13 | import com.github.javaparser.ast.stmt.LocalClassDeclarationStmt; 14 | import com.simonbaars.clonerefactor.SequenceObservable; 15 | import com.simonbaars.clonerefactor.ast.interfaces.DeterminesNodeTokens; 16 | import com.simonbaars.clonerefactor.ast.interfaces.Parser; 17 | import com.simonbaars.clonerefactor.metrics.MetricCollector; 18 | import com.simonbaars.clonerefactor.metrics.ProblemType; 19 | import com.simonbaars.clonerefactor.metrics.collectors.CyclomaticComplexityCalculator; 20 | import com.simonbaars.clonerefactor.metrics.collectors.NumberOfParametersCalculator; 21 | import com.simonbaars.clonerefactor.metrics.collectors.UnitSizeCalculator; 22 | import com.simonbaars.clonerefactor.model.Sequence; 23 | import com.simonbaars.clonerefactor.model.location.Location; 24 | import com.simonbaars.clonerefactor.model.location.LocationContents; 25 | import com.simonbaars.clonerefactor.settings.Settings; 26 | 27 | public class NodeParser implements Parser, DeterminesNodeTokens { 28 | final Map lineReg = new HashMap<>(); 29 | private final MetricCollector metricCollector; 30 | 31 | public NodeParser(MetricCollector metricCollector) { 32 | this.metricCollector = metricCollector; 33 | } 34 | 35 | public Location extractLinesFromAST(Location prevLocation, CompilationUnit cu, Node n) { 36 | if(n instanceof ImportDeclaration || n instanceof PackageDeclaration || isExcluded(n)) 37 | return prevLocation; 38 | if(n instanceof MethodDeclaration && SequenceObservable.get().isActive()) { 39 | collectAlternateMetrics((MethodDeclaration)n, cu); 40 | } 41 | if(!(n instanceof CompilationUnit || n instanceof BlockStmt || n instanceof LocalClassDeclarationStmt)) 42 | prevLocation = setIfNotNull(prevLocation, parseToken(prevLocation, cu, n)); 43 | for (Node child : childrenToParse(n)) { 44 | prevLocation = setIfNotNull(prevLocation, extractLinesFromAST(prevLocation, cu, child)); 45 | } 46 | return prevLocation; 47 | } 48 | 49 | 50 | private void collectAlternateMetrics(MethodDeclaration n, CompilationUnit cu) { 51 | final Location l = new Location(cu.getStorage().get().getPath(), n.getRange().get()); 52 | Sequence sequence = new Sequence(Collections.singletonList(l)); 53 | l.getContents().getNodes().add(n); 54 | l.getContents().setTokens(n.getTokenRange().get()); 55 | 56 | int cc = new CyclomaticComplexityCalculator().calculate(n); 57 | int methodSize = new UnitSizeCalculator().calculate(n); 58 | int parameters = new NumberOfParametersCalculator().calculate(n); 59 | if(cc >= Settings.get().getCyclomaticComplexity()) 60 | SequenceObservable.get().sendUpdate(ProblemType.UNITCOMPLEXITY, sequence, cc); 61 | if(methodSize >= Settings.get().getUnitSize()) 62 | SequenceObservable.get().sendUpdate(ProblemType.UNITVOLUME, sequence, methodSize); 63 | if(parameters >= Settings.get().getUnitInterfaceParameters()) { 64 | sequence = new Sequence(Collections.singletonList(new Location(l).setRange(getRange(n)))); 65 | SequenceObservable.get().sendUpdate(ProblemType.UNITINTERFACESIZE, sequence, parameters); 66 | } 67 | } 68 | 69 | public Location parseToken(Location prevLocation, CompilationUnit cu, Node n) { 70 | Location thisLocation = new Location(cu.getStorage().get().getPath(), prevLocation, n); 71 | if(prevLocation!=null) prevLocation.setNextLine(thisLocation); 72 | addLineTokensToReg(thisLocation); 73 | return thisLocation; 74 | } 75 | 76 | public Location addLineTokensToReg(Location location) { 77 | if(lineReg.containsKey(location.getContents())) { 78 | location.setClone(lineReg.get(location.getContents())); 79 | lineReg.put(location.getContents(), location); 80 | } else { 81 | lineReg.put(location.getContents(), location); 82 | } 83 | metricCollector.reportFoundNode(location); 84 | return location; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/clonerefactor/ast/NodeType.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.clonerefactor.ast; 2 | 3 | import com.github.javaparser.ast.Node; 4 | import com.github.javaparser.ast.body.AnnotationDeclaration; 5 | import com.github.javaparser.ast.body.BodyDeclaration; 6 | import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; 7 | import com.github.javaparser.ast.body.EnumConstantDeclaration; 8 | import com.github.javaparser.ast.body.EnumDeclaration; 9 | import com.github.javaparser.ast.body.MethodDeclaration; 10 | import com.github.javaparser.ast.expr.LambdaExpr; 11 | import com.github.javaparser.ast.expr.VariableDeclarationExpr; 12 | import com.github.javaparser.ast.stmt.CatchClause; 13 | import com.github.javaparser.ast.stmt.ForEachStmt; 14 | import com.github.javaparser.ast.stmt.ForStmt; 15 | import com.github.javaparser.ast.stmt.TryStmt; 16 | import com.github.javaparser.ast.stmt.WhileStmt; 17 | 18 | public enum NodeType { 19 | METHODHEADER, 20 | METHODBODY, 21 | CLASSHEADER, 22 | INTERFACEHEADER, 23 | VARIABLEDECLARATION, 24 | LAMBDA, 25 | ENUMFIELD, 26 | ENUMHEADER, 27 | ANNOTATION, 28 | FORLOOPHEADER, 29 | WHILELOOPHEADER, 30 | TRY, 31 | CATCH, 32 | OTHER; 33 | 34 | public static NodeType getNodeType(Node n) { 35 | if(n instanceof ForEachStmt || n instanceof ForStmt) 36 | return FORLOOPHEADER; 37 | else if(n instanceof WhileStmt) 38 | return WHILELOOPHEADER; 39 | else if(n instanceof CatchClause) 40 | return CATCH; 41 | else if(n instanceof TryStmt) 42 | return TRY; 43 | else if (n instanceof AnnotationDeclaration) 44 | return ANNOTATION; 45 | else if(n instanceof EnumDeclaration) 46 | return ENUMHEADER; 47 | else if(n instanceof EnumConstantDeclaration) 48 | return ENUMFIELD; 49 | else if(n instanceof LambdaExpr) 50 | return LAMBDA; 51 | else if (n instanceof VariableDeclarationExpr) 52 | return VARIABLEDECLARATION; 53 | else if(n instanceof ClassOrInterfaceDeclaration) 54 | return ((ClassOrInterfaceDeclaration)n).isInterface() ? INTERFACEHEADER : CLASSHEADER; 55 | else if(n instanceof BodyDeclaration) 56 | return METHODBODY; 57 | else if(n instanceof MethodDeclaration) 58 | return METHODHEADER; 59 | return OTHER; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/clonerefactor/ast/interfaces/DeterminesNodeTokens.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.clonerefactor.ast.interfaces; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.ListIterator; 6 | import java.util.Optional; 7 | 8 | import com.github.javaparser.JavaToken; 9 | import com.github.javaparser.Position; 10 | import com.github.javaparser.Range; 11 | import com.github.javaparser.ast.Node; 12 | import com.github.javaparser.ast.nodeTypes.NodeWithImplements; 13 | import com.simonbaars.clonerefactor.model.FiltersTokens; 14 | 15 | public interface DeterminesNodeTokens extends FiltersTokens, RequiresNodeOperations { 16 | public default List calculateTokensFromNode(Node n) { 17 | Range validRange = getValidRange(n); 18 | List tokens = new ArrayList<>(); 19 | for(JavaToken token : n.getTokenRange().get()) { 20 | Optional r = token.getRange(); 21 | if(r.isPresent()) { 22 | if(!validRange.contains(r.get())) break; 23 | if(isComparableToken(token)) tokens.add(token); 24 | if(n instanceof NodeWithImplements && token.asString().equals("{")) break; // We cannot exclude the body of class files, this is a workaround. 25 | } 26 | } 27 | return tokens; 28 | } 29 | 30 | public default Range getValidRange(Node n) { 31 | Range nodeRange = n.getRange().get(); 32 | for(ListIterator it = n.getChildNodes().listIterator(n.getChildNodes().size()); it.hasPrevious(); ) { 33 | Node node = it.previous(); 34 | if(!isExcluded(node) && node.getRange().isPresent()) { 35 | nodeRange = new Range(nodeRange.begin, getPosition(node.getRange().get().begin, nodeRange.begin)); 36 | } else break; 37 | } 38 | return nodeRange; 39 | } 40 | 41 | public default Position getPosition(Position pos, Position begin) { 42 | if(pos.equals(begin)) 43 | return pos; 44 | return new Position(pos.line, pos.column-1); 45 | } 46 | 47 | public default Range getRange(List tokens) { 48 | return new Range(tokens.get(0).getRange().get().begin, tokens.get(tokens.size()-1).getRange().get().end); 49 | } 50 | 51 | public default Range getRange(Node n) { 52 | return getRange(calculateTokensFromNode(n)); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/clonerefactor/ast/interfaces/HasCompareList.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.clonerefactor.ast.interfaces; 2 | 3 | import java.util.Collections; 4 | import java.util.HashMap; 5 | import java.util.List; 6 | import java.util.Map; 7 | import java.util.Map.Entry; 8 | import java.util.Optional; 9 | 10 | import com.github.javaparser.JavaToken; 11 | import com.github.javaparser.Range; 12 | import com.github.javaparser.ast.Node; 13 | import com.simonbaars.clonerefactor.compare.Compare; 14 | import com.simonbaars.clonerefactor.compare.CompareToken; 15 | import com.simonbaars.clonerefactor.settings.Settings; 16 | 17 | public interface HasCompareList extends DeterminesNodeTokens { 18 | public List getCompare(); 19 | 20 | public default void createComparablesByNode(List myTokens, Node statement) { 21 | Map compareMap = getNodesForCompare(Collections.singletonList(statement), getRange(myTokens)); 22 | myTokens.forEach(token -> { 23 | Optional> thisNodeOptional = compareMap.entrySet().stream().filter(e -> e.getKey().contains(token.getRange().get())).findAny(); 24 | if(thisNodeOptional.isPresent()) { 25 | if(thisNodeOptional.get().getValue()!=null) 26 | createCompareFromNode(compareMap, token, thisNodeOptional.get()); 27 | } else getCompare().add(Compare.create(token, token, Settings.get().getCloneType())); 28 | }); 29 | } 30 | 31 | public default void createCompareFromNode(Map compareMap, JavaToken token, Entry thisNode) { 32 | Compare createdNode = Compare.create(thisNode.getValue(), token, Settings.get().getCloneType()); 33 | getCompare().add(createdNode); 34 | getCompare().addAll(createdNode.relevantChildren(this)); 35 | if(createdNode instanceof CompareToken) compareMap.remove(thisNode.getKey()); 36 | else thisNode.setValue(null); 37 | } 38 | 39 | public default Map getNodesForCompare(List parents, Range r){ 40 | return getNodesForCompare(parents, new HashMap<>(), r); 41 | } 42 | 43 | public default Map getNodesForCompare(List parents, Map nodes, Range range){ 44 | for(Node node : parents) { 45 | if(node.getRange().isPresent()) { 46 | Range r = node.getRange().get(); 47 | if(range.contains(r) && Compare.comparingNode(node)) 48 | nodes.put(r, node); 49 | else if (r.begin.isAfter(range.end)) 50 | return nodes; 51 | if(!nodes.containsKey(r)) 52 | getNodesForCompare(node.getChildNodes(), nodes, range); 53 | } 54 | } 55 | return nodes; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/clonerefactor/ast/interfaces/Parser.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.clonerefactor.ast.interfaces; 2 | 3 | public interface Parser { 4 | public default T setIfNotNull(T oldObject, T newObject) { 5 | return newObject == null ? oldObject : newObject; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/clonerefactor/ast/interfaces/RequiresNodeOperations.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.clonerefactor.ast.interfaces; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.Optional; 6 | 7 | import com.github.javaparser.ast.Modifier; 8 | import com.github.javaparser.ast.Node; 9 | import com.github.javaparser.ast.body.AnnotationMemberDeclaration; 10 | import com.github.javaparser.ast.body.FieldDeclaration; 11 | import com.github.javaparser.ast.body.MethodDeclaration; 12 | import com.github.javaparser.ast.body.Parameter; 13 | import com.github.javaparser.ast.body.ReceiverParameter; 14 | import com.github.javaparser.ast.body.VariableDeclarator; 15 | import com.github.javaparser.ast.comments.Comment; 16 | import com.github.javaparser.ast.expr.Expression; 17 | import com.github.javaparser.ast.nodeTypes.NodeWithBlockStmt; 18 | import com.github.javaparser.ast.nodeTypes.NodeWithBody; 19 | import com.github.javaparser.ast.nodeTypes.NodeWithIdentifier; 20 | import com.github.javaparser.ast.stmt.BlockStmt; 21 | import com.github.javaparser.ast.type.Type; 22 | 23 | public interface RequiresNodeOperations { 24 | @SuppressWarnings("rawtypes") 25 | public default List childrenToParse(Node parent){ 26 | if(parent instanceof MethodDeclaration) { 27 | Optional body = ((MethodDeclaration)parent).getBody(); 28 | return body.isPresent() ? body.get().getChildNodes() : new ArrayList<>(0); 29 | } else if(parent instanceof NodeWithBody) 30 | return ((NodeWithBody)parent).getBody().getChildNodes(); 31 | else if (parent instanceof NodeWithBlockStmt) 32 | return ((NodeWithBlockStmt)parent).getBody().getChildNodes(); 33 | return parent.getChildNodes(); 34 | } 35 | 36 | public default boolean isExcluded(Node n) { 37 | return n instanceof Expression || n instanceof Modifier || n instanceof NodeWithIdentifier || n instanceof Comment || n instanceof Type || n instanceof AnnotationMemberDeclaration || n instanceof Parameter || n instanceof ReceiverParameter || (n instanceof VariableDeclarator && n.getParentNode().get() instanceof FieldDeclaration); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/clonerefactor/compare/Compare.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.clonerefactor.compare; 2 | 3 | import java.util.Collections; 4 | import java.util.List; 5 | 6 | import com.github.javaparser.JavaToken; 7 | import com.github.javaparser.Range; 8 | import com.github.javaparser.ast.Node; 9 | import com.github.javaparser.ast.expr.LiteralExpr; 10 | import com.github.javaparser.ast.expr.MethodCallExpr; 11 | import com.github.javaparser.ast.expr.NameExpr; 12 | import com.github.javaparser.ast.expr.SimpleName; 13 | import com.github.javaparser.ast.type.ReferenceType; 14 | import com.simonbaars.clonerefactor.ast.interfaces.HasCompareList; 15 | import com.simonbaars.clonerefactor.settings.CloneType; 16 | 17 | public abstract class Compare implements HasRange { 18 | protected CloneType cloneType; 19 | private final Range range; 20 | 21 | protected Compare(CloneType cloneType, Range range) { 22 | this.cloneType=cloneType; 23 | this.range = range; 24 | } 25 | 26 | public abstract int getHashCode(); 27 | 28 | public static Compare create(Object tokenOrNode, JavaToken e, CloneType cloneType) { 29 | if(tokenOrNode instanceof ReferenceType) 30 | return new CompareType(cloneType, (ReferenceType)tokenOrNode); 31 | else if(tokenOrNode instanceof NameExpr) 32 | return new CompareVariable(cloneType, (NameExpr)tokenOrNode); 33 | else if(tokenOrNode instanceof LiteralExpr) 34 | return new CompareLiteral(cloneType, e); 35 | else if(tokenOrNode instanceof SimpleName) 36 | return new CompareName(cloneType, e); 37 | else if(tokenOrNode instanceof MethodCallExpr) 38 | return new CompareMethodCall(cloneType, (MethodCallExpr)tokenOrNode); 39 | return new CompareToken(cloneType, e); 40 | } 41 | 42 | /** 43 | * These nodes are compared by node rather than token. 44 | * @return 45 | */ 46 | public static boolean comparingNode(Node node) { 47 | return node instanceof ReferenceType || node instanceof NameExpr || node instanceof LiteralExpr || node instanceof SimpleName || node instanceof MethodCallExpr; 48 | } 49 | 50 | public boolean equals(Object o) { 51 | if(this.getClass() != o.getClass()) 52 | return false; 53 | return true; 54 | } 55 | 56 | public void setCloneType(CloneType type) { 57 | this.cloneType = type; 58 | } 59 | 60 | public List relevantChildren(HasCompareList locationContents){ 61 | return Collections.emptyList(); 62 | } 63 | 64 | public Range getRange() { 65 | return range; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/clonerefactor/compare/CompareFalse.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.clonerefactor.compare; 2 | 3 | import com.simonbaars.clonerefactor.settings.CloneType; 4 | 5 | public class CompareFalse extends Compare { 6 | 7 | private static int x = Integer.MIN_VALUE; 8 | 9 | public CompareFalse() { 10 | super(CloneType.TYPE1, null); 11 | } 12 | 13 | @Override 14 | public boolean equals(Object o) { 15 | return false; // Whatever clones we'll find, I won't be a part of it. 16 | } 17 | 18 | @Override 19 | public int getHashCode() { 20 | return x++; 21 | } 22 | 23 | @Override 24 | public String toString() { 25 | return "CompareFalse"; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/clonerefactor/compare/CompareLiteral.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.clonerefactor.compare; 2 | 3 | import com.github.javaparser.JavaToken; 4 | import com.simonbaars.clonerefactor.settings.CloneType; 5 | 6 | public class CompareLiteral extends Compare { 7 | final JavaToken t; 8 | 9 | public CompareLiteral(CloneType cloneType, JavaToken t) { 10 | super(cloneType, t.getRange().get()); 11 | this.t=t; 12 | } 13 | 14 | @Override 15 | public boolean equals(Object o) { 16 | return super.equals(o) && (cloneType.isNotTypeOne() || t.equals(((CompareLiteral)o).t)); 17 | } 18 | 19 | @Override 20 | public int getHashCode() { 21 | return cloneType.isNotTypeOne() ? -1 : t.hashCode(); 22 | } 23 | 24 | @Override 25 | public String toString() { 26 | return "CompareLiteral [t=" + t + "]"; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/clonerefactor/compare/CompareMethodCall.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.clonerefactor.compare; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.stream.Collectors; 6 | 7 | import com.github.javaparser.JavaToken; 8 | import com.github.javaparser.ast.expr.MethodCallExpr; 9 | import com.github.javaparser.ast.expr.NameExpr; 10 | import com.github.javaparser.resolution.declarations.ResolvedMethodDeclaration; 11 | import com.simonbaars.clonerefactor.ast.interfaces.HasCompareList; 12 | import com.simonbaars.clonerefactor.model.FiltersTokens; 13 | import com.simonbaars.clonerefactor.settings.CloneType; 14 | 15 | public class CompareMethodCall extends Compare implements FiltersTokens { 16 | private final MethodCallExpr methodCall; 17 | private final ResolvedMethodDeclaration type; 18 | private final List myTokens; 19 | private final List estimatedTypes = new ArrayList<>(); 20 | 21 | public CompareMethodCall(CloneType cloneType, MethodCallExpr t) { 22 | super(cloneType, t.getRange().get()); 23 | methodCall = t; 24 | ResolvedMethodDeclaration refType = null; 25 | try { 26 | refType = t.resolve(); 27 | } catch (Exception e) {} 28 | type = refType; 29 | estimateTypes(t); 30 | myTokens = getEffectiveTokenList(t.getTokenRange().get()); 31 | } 32 | 33 | /* 34 | * I'm not so sure about this whole estimateTypes thing. The problem is that JavaParser cannot resolve everything. In essence, we cannot guarantee equality, thus this can result in invalid refactorings. Because of that, we *should* remove this estimateTypes thing, and just mark the equality `false` for all null types. 35 | */ 36 | private void estimateTypes(MethodCallExpr t) { 37 | estimatedTypes.addAll(t.getArguments().stream().map(e -> { 38 | if(e instanceof NameExpr) 39 | try { 40 | return ((NameExpr)e).resolve().getType(); 41 | } catch (Exception ex) {} 42 | return e.getClass(); 43 | }).collect(Collectors.toList())); 44 | } 45 | 46 | public boolean equals(Object c) { 47 | if(!super.equals(c)) 48 | return false; 49 | CompareMethodCall other = (CompareMethodCall)c; 50 | if(cloneType == CloneType.TYPE1 && !myTokens.equals(other.myTokens)) 51 | return false; 52 | if(type!=null && other.type !=null) { 53 | String methodSignature = type.getQualifiedSignature(); 54 | String compareMethodSignature = other.type.getQualifiedSignature(); 55 | if(cloneType.isNotTypeOne()) 56 | return getOnlyArguments(methodSignature).equals(getOnlyArguments(compareMethodSignature)); 57 | return methodSignature.equals(compareMethodSignature); 58 | } 59 | return estimatedTypes.equals(other.estimatedTypes); 60 | } 61 | 62 | private String getOnlyArguments(String methodSignature) { 63 | return methodSignature.substring(methodSignature.indexOf('(')); 64 | } 65 | 66 | @Override 67 | public int getHashCode() { 68 | int hashCode = 0; 69 | if(cloneType == CloneType.TYPE1) 70 | hashCode += myTokens.hashCode(); 71 | if(type!=null) 72 | return hashCode + type.getTypeParameters().hashCode(); 73 | return hashCode + estimatedTypes.hashCode(); 74 | } 75 | 76 | @Override 77 | public String toString() { 78 | return "CompareMethodCall [type=" + type + "]"; 79 | } 80 | 81 | @Override 82 | public List relevantChildren(HasCompareList c){ 83 | return c.getNodesForCompare(methodCall.getArguments(), methodCall.getRange().get()).values().stream().map(e -> Compare.create(e, e.getTokenRange().get().getBegin(), cloneType)).collect(Collectors.toList()); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/clonerefactor/compare/CompareName.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.clonerefactor.compare; 2 | 3 | import com.github.javaparser.JavaToken; 4 | import com.simonbaars.clonerefactor.settings.CloneType; 5 | 6 | public class CompareName extends Compare { 7 | JavaToken t; 8 | 9 | public CompareName(CloneType type, JavaToken t) { 10 | super(type, t.getRange().get()); 11 | this.t = t; 12 | } 13 | 14 | @Override 15 | public boolean equals(Object o) { 16 | return super.equals(o) && (cloneType.isNotTypeOne() || t.equals(((CompareName)o).t)); //Type two names will always be flagged as equals, as we don't take them into account. 17 | } 18 | 19 | @Override 20 | public int getHashCode() { 21 | return cloneType.isNotTypeOne() ? -2 : t.hashCode(); 22 | } 23 | 24 | @Override 25 | public String toString() { 26 | return "CompareName [t=" + t + "]"; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/clonerefactor/compare/CompareToken.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.clonerefactor.compare; 2 | 3 | import com.github.javaparser.JavaToken; 4 | import com.simonbaars.clonerefactor.settings.CloneType; 5 | 6 | public class CompareToken extends Compare { 7 | 8 | private final JavaToken token; 9 | 10 | public CompareToken(CloneType cloneType, JavaToken token) { 11 | super(cloneType, token.getRange().get()); 12 | this.token = token; 13 | } 14 | 15 | @Override 16 | public boolean equals(Object o) { 17 | return super.equals(o) && token.equals(((CompareToken)o).token); 18 | } 19 | 20 | @Override 21 | public int getHashCode() { 22 | return token.hashCode(); 23 | } 24 | 25 | @Override 26 | public String toString() { 27 | return "CompareToken [token=" + token.asString() + "]"; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/clonerefactor/compare/CompareType.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.clonerefactor.compare; 2 | 3 | import com.github.javaparser.ast.type.ReferenceType; 4 | import com.github.javaparser.resolution.types.ResolvedReferenceType; 5 | import com.simonbaars.clonerefactor.settings.CloneType; 6 | 7 | public class CompareType extends Compare { 8 | private final ReferenceType referenceType; 9 | private final ResolvedReferenceType type; 10 | 11 | public CompareType(CloneType cloneType, ReferenceType t) { 12 | super(cloneType, t.getRange().get()); 13 | this.referenceType = t; 14 | ResolvedReferenceType refType = null; 15 | try { 16 | refType = (ResolvedReferenceType)t.resolve(); 17 | } catch (Exception e) {} 18 | type = refType; 19 | } 20 | 21 | public boolean equals(Object o) { 22 | if(!super.equals(o)) 23 | return false; 24 | CompareType other = ((CompareType)o); 25 | if(type!=null) 26 | return type.equals(other.type); 27 | return referenceType.equals(other.referenceType); 28 | } 29 | 30 | @Override 31 | public int getHashCode() { 32 | if(type==null) 33 | return referenceType.hashCode(); 34 | return type.hashCode(); 35 | } 36 | 37 | @Override 38 | public String toString() { 39 | return "CompareType [type=" + type + "]"; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/clonerefactor/compare/CompareVariable.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.clonerefactor.compare; 2 | 3 | import com.github.javaparser.ast.expr.NameExpr; 4 | import com.github.javaparser.resolution.declarations.ResolvedValueDeclaration; 5 | import com.github.javaparser.resolution.types.ResolvedType; 6 | import com.simonbaars.clonerefactor.settings.CloneType; 7 | 8 | public class CompareVariable extends Compare { 9 | private final NameExpr variableName; 10 | private final ResolvedValueDeclaration dec; 11 | private final ResolvedType type; 12 | 13 | public CompareVariable(CloneType cloneType, NameExpr t) { 14 | super(cloneType, t.getRange().get()); 15 | variableName = t; 16 | ResolvedValueDeclaration refType = null; 17 | ResolvedType resolvedType = null; 18 | try { 19 | refType = t.resolve(); 20 | resolvedType = refType.getType(); 21 | } catch (Exception e) {} 22 | dec = refType; 23 | type = resolvedType; 24 | } 25 | 26 | @Override 27 | public boolean equals(Object o) { 28 | if(!super.equals(o)) 29 | return false; 30 | CompareVariable compareDec = ((CompareVariable)o); 31 | if(cloneType == CloneType.TYPE1 && !variableName.equals(compareDec.variableName)) 32 | return false; 33 | return type == null || type.equals(compareDec.type); 34 | } 35 | 36 | @Override 37 | public int getHashCode() { 38 | return (cloneType == CloneType.TYPE1 ? variableName.hashCode() : 0) + (type == null ? -3 : type.hashCode()); 39 | } 40 | 41 | @Override 42 | public String toString() { 43 | return "CompareVariable [dec=" + dec.getName() + ", type=" + type + "]"; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/clonerefactor/compare/HasRange.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.clonerefactor.compare; 2 | 3 | import com.github.javaparser.Range; 4 | 5 | public interface HasRange { 6 | public Range getRange(); 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/clonerefactor/datatype/CountMap.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.clonerefactor.datatype; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | import java.util.stream.Collectors; 6 | 7 | public class CountMap extends HashMap { 8 | /** 9 | * 10 | */ 11 | private static final long serialVersionUID = 1L; 12 | 13 | public CountMap() { 14 | } 15 | 16 | public CountMap(int initialCapacity, float loadFactor) { 17 | super(initialCapacity, loadFactor); 18 | } 19 | 20 | public CountMap(int initialCapacity) { 21 | super(initialCapacity); 22 | } 23 | 24 | public CountMap(Map m) { 25 | super(m); 26 | } 27 | 28 | public Integer increment(K key) { 29 | return super.put(key, super.containsKey(key) ? super.get(key) + 1 : 1); 30 | } 31 | 32 | public Integer increment(K key, int amount) { 33 | return super.put(key, super.containsKey(key) ? super.get(key) + amount : amount); 34 | } 35 | 36 | @SuppressWarnings("unchecked") 37 | @Override 38 | public Integer get(Object key){ 39 | if(!super.containsKey(key)) 40 | super.put((K) key, 0); 41 | return super.get(key); 42 | } 43 | 44 | @Override 45 | public String toString() { 46 | return keySet().stream().sorted().map(e -> e+"\t"+get(e)).collect(Collectors.joining(System.lineSeparator())); 47 | } 48 | 49 | public void addAll(CountMap amountPerCloneClassSize) { 50 | amountPerCloneClassSize.entrySet().stream().forEach(e -> this.increment(e.getKey(), e.getValue())); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/clonerefactor/datatype/DoubleMap.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.clonerefactor.datatype; 2 | 3 | import java.util.HashMap; 4 | 5 | public class DoubleMap extends HashMap> { 6 | /** 7 | * 8 | */ 9 | private static final long serialVersionUID = 1L; 10 | 11 | public DoubleMap() { 12 | } 13 | 14 | public DoubleMap(int initialCapacity, float loadFactor) { 15 | super(initialCapacity, loadFactor); 16 | } 17 | 18 | public DoubleMap(int initialCapacity) { 19 | super(initialCapacity); 20 | } 21 | 22 | public V get(K1 key1, K2 key2){ 23 | return super.get(key1).get(key2); 24 | } 25 | 26 | public boolean containsKey(K1 key1, K2 key2){ 27 | if(!super.containsKey(key1)) 28 | super.put(key1, new HashMap<>()); 29 | return super.get(key1).containsKey(key2); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/clonerefactor/datatype/FlattenedList.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.clonerefactor.datatype; 2 | 3 | import java.util.Collection; 4 | import java.util.Iterator; 5 | import java.util.List; 6 | import java.util.ListIterator; 7 | import java.util.stream.Collectors; 8 | import java.util.stream.IntStream; 9 | import java.util.stream.Stream; 10 | 11 | public class FlattenedList implements List { 12 | 13 | private final List> listToFlatten; 14 | private final int[] listSize; 15 | 16 | 17 | public FlattenedList(List> listToFlatten) { 18 | super(); 19 | this.listToFlatten = listToFlatten; 20 | this.listSize = new int[listToFlatten.size()]; 21 | for(int i = 0; i e.contains(o)); 39 | } 40 | 41 | @Override 42 | public Iterator iterator() { 43 | return flatList().iterator(); 44 | } 45 | 46 | private Stream flatList() { 47 | return listToFlatten.stream().flatMap(List::stream); 48 | } 49 | 50 | @Override 51 | public Object[] toArray() { 52 | return flatList().toArray(); 53 | } 54 | 55 | @SuppressWarnings("unchecked") 56 | @Override 57 | public T[] toArray(T[] a) { 58 | return (T[])toArray(); 59 | } 60 | 61 | @Override 62 | public boolean add(E e) { 63 | throw new UnsupportedOperationException(); 64 | } 65 | 66 | @Override 67 | public boolean remove(Object o) { 68 | throw new UnsupportedOperationException(); 69 | } 70 | 71 | @Override 72 | public boolean containsAll(Collection c) { 73 | return combinedList().containsAll(c); 74 | } 75 | 76 | private List combinedList() { 77 | return flatList().collect(Collectors.toList()); 78 | } 79 | 80 | @Override 81 | public boolean addAll(Collection c) { 82 | throw new UnsupportedOperationException(); 83 | } 84 | 85 | @Override 86 | public boolean addAll(int index, Collection c) { 87 | throw new UnsupportedOperationException(); 88 | } 89 | 90 | @Override 91 | public boolean removeAll(Collection c) { 92 | throw new UnsupportedOperationException(); 93 | } 94 | 95 | @Override 96 | public boolean retainAll(Collection c) { 97 | throw new UnsupportedOperationException(); 98 | } 99 | 100 | @Override 101 | public void clear() { 102 | throw new UnsupportedOperationException(); 103 | } 104 | 105 | @Override 106 | public E get(int index) { 107 | int total = 0; 108 | for(int i = 0; i listIterator() { 153 | return combinedList().listIterator(); 154 | } 155 | 156 | @Override 157 | public ListIterator listIterator(int index) { 158 | return combinedList().listIterator(index); 159 | } 160 | 161 | @Override 162 | public List subList(int fromIndex, int toIndex) { 163 | return combinedList().subList(fromIndex, toIndex); 164 | } 165 | 166 | } 167 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/clonerefactor/datatype/IndexedVector.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.clonerefactor.datatype; 2 | 3 | import java.util.Vector; 4 | 5 | public class IndexedVector extends Vector { 6 | 7 | /** 8 | * 9 | */ 10 | private static final long serialVersionUID = 9150447915872304886L; 11 | 12 | public synchronized int getIndex(E element) { 13 | int size = size(); 14 | add(element); 15 | if(indexOf(element)!=size) 16 | throw new IllegalStateException("Synchronization error!"); 17 | return size; 18 | } 19 | 20 | } -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/clonerefactor/datatype/ListMap.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.clonerefactor.datatype; 2 | 3 | import java.util.ArrayList; 4 | import java.util.HashMap; 5 | import java.util.List; 6 | import java.util.Map; 7 | 8 | public class ListMap extends HashMap> { 9 | /** 10 | * 11 | */ 12 | private static final long serialVersionUID = 1L; 13 | 14 | public ListMap() { 15 | } 16 | 17 | public ListMap(int initialCapacity, float loadFactor) { 18 | super(initialCapacity, loadFactor); 19 | } 20 | 21 | public ListMap(int initialCapacity) { 22 | super(initialCapacity); 23 | } 24 | 25 | public ListMap(Map> m) { 26 | super(m); 27 | } 28 | 29 | public List addTo(K key, V value) { 30 | List l; 31 | if(super.containsKey(key)) { 32 | l = super.get(key); 33 | } else l = new ArrayList<>(); 34 | l.add(value); 35 | return super.put(key, l); 36 | } 37 | 38 | @SuppressWarnings("unchecked") 39 | @Override 40 | public List get(Object key){ 41 | if(!super.containsKey(key)) 42 | super.put((K) key, new ArrayList<>()); 43 | return super.get(key); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/clonerefactor/datatype/SetMap.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.clonerefactor.datatype; 2 | 3 | import java.util.HashMap; 4 | import java.util.HashSet; 5 | import java.util.Map; 6 | import java.util.Set; 7 | 8 | public class SetMap extends HashMap> { 9 | /** 10 | * 11 | */ 12 | private static final long serialVersionUID = 1L; 13 | 14 | public SetMap() { 15 | } 16 | 17 | public SetMap(int initialCapacity, float loadFactor) { 18 | super(initialCapacity, loadFactor); 19 | } 20 | 21 | public SetMap(int initialCapacity) { 22 | super(initialCapacity); 23 | } 24 | 25 | public SetMap(Map> m) { 26 | super(m); 27 | } 28 | 29 | public Set addTo(K key, V value) { 30 | Set l; 31 | if(super.containsKey(key)) { 32 | l = super.get(key); 33 | } else l = new HashSet<>(); 34 | l.add(value); 35 | return super.put(key, l); 36 | } 37 | 38 | @SuppressWarnings("unchecked") 39 | @Override 40 | public Set get(Object key){ 41 | if(!super.containsKey(key)) 42 | super.put((K) key, new HashSet<>()); 43 | return super.get(key); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/clonerefactor/detection/interfaces/CalculatesPercentages.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.clonerefactor.detection.interfaces; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.stream.IntStream; 6 | 7 | import com.simonbaars.clonerefactor.detection.type2.WeightedPercentage; 8 | 9 | public interface CalculatesPercentages { 10 | public default double calcPercentage(int part, int whole) { 11 | return whole == 0 ? 0D : (double)part/(double)whole*100D; 12 | } 13 | 14 | public default double diffPerc(int[] arr1, int[] arr2) { 15 | int same = 0, diff = 0; 16 | for(int i = 0; i percentages) { 41 | percentages = new ArrayList<>(percentages); 42 | while(percentages.size()>1) { 43 | percentages.set(0, percentages.get(0).mergeWith(percentages.get(1))); 44 | percentages.remove(1); 45 | } 46 | return percentages.get(0).getPercentage(); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/clonerefactor/detection/interfaces/ChecksThresholds.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.clonerefactor.detection.interfaces; 2 | 3 | import com.simonbaars.clonerefactor.model.Sequence; 4 | import com.simonbaars.clonerefactor.settings.Settings; 5 | 6 | public interface ChecksThresholds { 7 | public default boolean checkThresholds(Sequence s) { 8 | return compareNodesThreshold(s) && compareLinesThreshold(s) && compareTokensThreshold(s); 9 | } 10 | 11 | public default boolean compareNodesThreshold(Sequence s) { 12 | return s.getAny().getAmountOfNodes() >= Settings.get().getMinAmountOfNodes(); 13 | } 14 | 15 | public default boolean compareLinesThreshold(Sequence s) { 16 | return s.getAny().getEffectiveLines() >= Settings.get().getMinAmountOfLines(); 17 | } 18 | 19 | public default boolean compareTokensThreshold(Sequence s) { 20 | return s.getAny().getAmountOfTokens() >= Settings.get().getMinAmountOfTokens(); 21 | } 22 | 23 | public default boolean compareThresholds(int i, int j) { 24 | return i<=j; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/clonerefactor/detection/interfaces/RemovesDuplicates.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.clonerefactor.detection.interfaces; 2 | 3 | import java.util.List; 4 | 5 | import com.simonbaars.clonerefactor.model.Sequence; 6 | 7 | public interface RemovesDuplicates { 8 | public default boolean removeDuplicatesOf(List clones, Sequence l) { 9 | l.getSequence().removeIf(e -> l.getSequence().stream().anyMatch(f -> f!=e && f.getFile() == e.getFile() && f.getRange().contains(e.getRange()))); 10 | clones.removeIf(e -> isSubset(e, l)); 11 | return !clones.stream().anyMatch(e -> isSubset(l, e)); 12 | } 13 | 14 | public default boolean isSubset(Sequence existentClone, Sequence newClone) { 15 | return existentClone.getSequence().stream().allMatch(oldLoc -> newClone.getSequence().stream().anyMatch(newLoc -> oldLoc.getFile() == newLoc.getFile() && newLoc.getRange().contains(oldLoc.getRange()))); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/clonerefactor/detection/type2/Graph.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.clonerefactor.detection.type2; 2 | 3 | import java.util.ArrayList; 4 | // Java program to print connected components in 5 | // an undirected graph 6 | import java.util.LinkedList; 7 | import java.util.List; 8 | 9 | public class Graph { 10 | // A user define class to represent a graph. 11 | // A graph is an array of adjacency lists. 12 | // Size of array will be V (number of vertices 13 | // in graph) 14 | int V; 15 | LinkedList[] adjListArray; 16 | 17 | // constructor 18 | @SuppressWarnings("unchecked") 19 | public Graph(int V) { 20 | this.V = V; 21 | // define the size of array as 22 | // number of vertices 23 | adjListArray = new LinkedList[V]; 24 | 25 | // Create a new list for each vertex 26 | // such that adjacent nodes can be stored 27 | 28 | for(int i = 0; i < V ; i++){ 29 | adjListArray[i] = new LinkedList(); 30 | } 31 | } 32 | 33 | // Adds an edge to an undirected graph 34 | public void addEdge(int src, int dest) { 35 | // Add an edge from src to dest. 36 | adjListArray[src].add(dest); 37 | 38 | // Since graph is undirected, add an edge from dest 39 | // to src also 40 | adjListArray[dest].add(src); 41 | } 42 | 43 | private List DFSUtil(int v, boolean[] visited) { 44 | List connected = new ArrayList<>(); 45 | // Mark the current node as visited and print it 46 | visited[v] = true; 47 | connected.add(v); 48 | // Recur for all the vertices 49 | // adjacent to this vertex 50 | for (int x : adjListArray[v]) { 51 | if(!visited[x]) connected.addAll(DFSUtil(x,visited)); 52 | } 53 | return connected; 54 | } 55 | 56 | public List> connectedComponents() { 57 | List> connected = new ArrayList<>(); 58 | // Mark all the vertices as not visited 59 | boolean[] visited = new boolean[V]; 60 | for(int v = 0; v < V; ++v) { 61 | if(!visited[v]) { 62 | // print all reachable vertices 63 | // from v 64 | connected.add(DFSUtil(v,visited)); 65 | } 66 | } 67 | return connected; 68 | } 69 | } -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/clonerefactor/detection/type2/WeightedPercentage.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.clonerefactor.detection.type2; 2 | 3 | import com.simonbaars.clonerefactor.detection.interfaces.CalculatesPercentages; 4 | 5 | public class WeightedPercentage implements CalculatesPercentages { 6 | private final double percentage; 7 | private final int weight; 8 | 9 | public WeightedPercentage(double percentage, int weight) { 10 | super(); 11 | this.percentage = percentage; 12 | this.weight = weight; 13 | } 14 | 15 | public double getPercentage() { 16 | return percentage; 17 | } 18 | 19 | public int getWeight() { 20 | return weight; 21 | } 22 | 23 | public WeightedPercentage mergeWith(WeightedPercentage weighedPercentage) { 24 | int total = weight+weighedPercentage.getWeight(); 25 | double combinedPercentage = unweighted(total) + weighedPercentage.unweighted(total); 26 | return new WeightedPercentage(combinedPercentage, total); 27 | } 28 | 29 | private double unweighted(int total) { 30 | return total == 0 ? 0D : percentage/total*weight; 31 | } 32 | 33 | @Override 34 | public String toString() { 35 | return "WeightedPercentage [percentage=" + percentage + ", weight=" + weight + "]"; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/clonerefactor/detection/type3/FileLocations.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.clonerefactor.detection.type3; 2 | 3 | import java.util.Collections; 4 | import java.util.List; 5 | import java.util.stream.IntStream; 6 | 7 | import com.simonbaars.clonerefactor.model.Sequence; 8 | import com.simonbaars.clonerefactor.model.location.Location; 9 | 10 | public class FileLocations { 11 | private final Sequence seq; 12 | 13 | public FileLocations (Sequence seq) { 14 | Collections.sort(seq.getSequence()); 15 | this.seq = seq; 16 | } 17 | 18 | @Override 19 | public int hashCode() { 20 | final int prime = 31; 21 | int result = 1; 22 | for (Location e : seq.getSequence()) 23 | result = prime*result + (e==null ? 0 : e.getFile().hashCode()); 24 | return result; 25 | } 26 | 27 | @Override 28 | public boolean equals(Object obj) { 29 | if (this == obj) 30 | return true; 31 | if (obj == null) 32 | return false; 33 | if (getClass() != obj.getClass()) 34 | return false; 35 | FileLocations other = (FileLocations) obj; 36 | return seq.getSequence().size() == seq.getSequence().size() && IntStream.range(0, seq.getSequence().size()).allMatch(i -> seq.getSequence().get(i).getFile().equals(other.seq.getSequence().get(i).getFile())); 37 | } 38 | 39 | public List getLocs() { 40 | return seq.getSequence(); 41 | } 42 | 43 | public Sequence getSeq() { 44 | return seq; 45 | } 46 | 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/clonerefactor/detection/type3/Type3Calculation.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.clonerefactor.detection.type3; 2 | 3 | import com.simonbaars.clonerefactor.model.location.Location; 4 | import com.simonbaars.clonerefactor.model.location.LocationContents; 5 | 6 | public interface Type3Calculation { 7 | public default LocationContents calculateDiffContents(Location before, Location after) { 8 | LocationContents contents = new LocationContents(); 9 | Location line = before; 10 | while((line = line.getNextLine()) != null) { 11 | if(line.getRange().isBefore(after.getRange().begin)) { 12 | if(line.getRange().isAfter(before.getRange().end)){ 13 | populateContents(contents, line.getContents()); 14 | } 15 | } else break; 16 | } 17 | return contents; 18 | } 19 | 20 | public default void populateContents(LocationContents contents, LocationContents otherContents) { 21 | contents.getNodes().addAll(otherContents.getNodes()); 22 | contents.getTokens().addAll(otherContents.getTokens()); 23 | contents.getCompare().addAll(otherContents.getCompare()); 24 | } 25 | 26 | public default int calculateDiff(Location before, Location after) { 27 | return calculateDiffContents(before, after).getNodes().size(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/clonerefactor/detection/type3/Type3Location.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.clonerefactor.detection.type3; 2 | 3 | import java.nio.file.Path; 4 | 5 | import com.github.javaparser.Range; 6 | import com.simonbaars.clonerefactor.model.location.Location; 7 | import com.simonbaars.clonerefactor.model.location.LocationContents; 8 | 9 | public class Type3Location extends Location implements Type3Calculation{ 10 | private final LocationContents diffContents = new LocationContents(); 11 | 12 | public Type3Location(Location clonedLocation, Range r) { 13 | super(clonedLocation, r); 14 | } 15 | 16 | public Type3Location(Location clonedLocation) { 17 | super(clonedLocation); 18 | } 19 | 20 | 21 | public Type3Location(Path file, Range range) { 22 | super(file, range); 23 | } 24 | 25 | public Type3Location(Location location, Location location2) { 26 | super(location.getFile(), null); 27 | if(location.getRange().isBefore(location2.getRange().begin)) 28 | mergeLocations(location, location2); 29 | else mergeLocations(location2, location); 30 | if(location instanceof Type3Location) 31 | diffContents.merge(((Type3Location)location).getDiffContents()); 32 | } 33 | 34 | private void mergeLocations(Location before, Location after) { 35 | Range r = before.getRange().withEnd(after.getRange().end); 36 | populateContents(getContents(), before.getContents()); 37 | populateContents(getContents(), after.getContents()); 38 | setRange(r); 39 | calculateDiffContents(before, after); 40 | } 41 | 42 | public LocationContents getDiffContents() { 43 | return diffContents; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/clonerefactor/detection/type3/Type3Opportunities.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.clonerefactor.detection.type3; 2 | 3 | import java.util.List; 4 | import java.util.stream.IntStream; 5 | 6 | import com.simonbaars.clonerefactor.datatype.ListMap; 7 | import com.simonbaars.clonerefactor.detection.interfaces.CalculatesPercentages; 8 | import com.simonbaars.clonerefactor.model.Sequence; 9 | import com.simonbaars.clonerefactor.model.location.Location; 10 | import com.simonbaars.clonerefactor.settings.Settings; 11 | 12 | public class Type3Opportunities implements Type3Calculation, CalculatesPercentages { 13 | private ListMap opportunities = new ListMap<>(); 14 | 15 | public void determineType3Opportunities(List clones) { 16 | for(int i = 0; i otherFls = opportunities.get(fl.hashCode()); 20 | for(FileLocations loc : otherFls) { 21 | if(isType3(fl, loc)) { 22 | clones.remove(fl.getSeq()); 23 | clones.remove(loc.getSeq()); 24 | clones.add(merge(fl.getLocs(), loc.getLocs())); 25 | i--; 26 | } 27 | } 28 | } 29 | opportunities.addTo(fl.hashCode(), fl); 30 | } 31 | } 32 | 33 | private Sequence merge(List fl1, List fl2) { 34 | Sequence seq = new Sequence(); 35 | for(int i = 0; i { 43 | Location l1 = fl1.getLocs().get(i); 44 | Location l2 = fl2.getLocs().get(i); 45 | if(!l1.getContents().getNodes().get(l1.getContents().getNodes().size()-1).getParentNode().equals(l2.getContents().getNodes().get(0).getParentNode())) 46 | return false; 47 | if(l1.getRange().isBefore(l2.getRange().begin)) { 48 | return checkType3Threshold(l1, l2); 49 | } else return checkType3Threshold(l2, l1); 50 | }); 51 | } 52 | 53 | private boolean checkType3Threshold(Location l1, Location l2) { 54 | int combinedSize = l1.getAmountOfNodes() + l2.getAmountOfNodes(); 55 | int diff = calculateDiff(l1, l2); 56 | if(diff == 0) 57 | return false; 58 | return calcPercentage(diff, combinedSize) <= Settings.get().getType3GapSize(); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/clonerefactor/metrics/Metrics.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.clonerefactor.metrics; 2 | 3 | import com.simonbaars.clonerefactor.datatype.CountMap; 4 | import com.simonbaars.clonerefactor.metrics.enums.CloneContents.ContentsType; 5 | import com.simonbaars.clonerefactor.metrics.enums.CloneLocation.LocationType; 6 | import com.simonbaars.clonerefactor.metrics.enums.CloneRefactorability.Refactorability; 7 | import com.simonbaars.clonerefactor.metrics.enums.CloneRelation.RelationType; 8 | 9 | public class Metrics { 10 | public int totalAmountOfLines = 0; 11 | public int totalAmountOfEffectiveLines = 0; 12 | public int totalAmountOfNodes = 0; 13 | public int totalAmountOfTokens = 0; 14 | 15 | public int amountOfLinesCloned = 0; 16 | public int amountOfEffectiveLinesCloned = 0; 17 | public int amountOfNodesCloned = 0; 18 | public int amountOfTokensCloned = 0; 19 | 20 | public int overlappingNodes = 0; 21 | public int overlappingEffectiveLines = 0; 22 | public int overlappingTokens = 0; 23 | public int overlappingLines = 0; 24 | 25 | public final CountMap amountPerRelation = new CountMap<>(); 26 | public final CountMap amountPerLocation = new CountMap<>(); 27 | public final CountMap amountPerContents = new CountMap<>(); 28 | public final CountMap amountPerExtract = new CountMap<>(); 29 | 30 | public final CountMap amountPerCloneClassSize = new CountMap<>(); 31 | public final CountMap amountPerNodes = new CountMap<>(); 32 | public final CountMap amountPerTotalNodeVolume = new CountMap<>(); 33 | 34 | public final CountMap amountPerEffectiveLines = new CountMap<>(); 35 | public final CountMap amountPerTotalEffectiveLineVolume = new CountMap<>(); 36 | 37 | 38 | 39 | @Override 40 | public String toString() { 41 | return "Metrics [totalAmountOfLines=" + totalAmountOfLines + ", totalAmountOfEffectiveLines=" 42 | + totalAmountOfEffectiveLines + ", totalAmountOfNodes=" + totalAmountOfNodes + ", totalAmountOfTokens=" 43 | + totalAmountOfTokens + ", amountOfLinesCloned=" + amountOfLinesCloned 44 | + ", amountOfEffectiveLinesCloned=" + amountOfEffectiveLinesCloned + ", amountOfNodesCloned=" 45 | + amountOfNodesCloned + ", amountOfTokensCloned=" + amountOfTokensCloned + ", overlappingNodes=" 46 | + overlappingNodes + ", overlappingEffectiveLines=" + overlappingEffectiveLines + ", overlappingTokens=" 47 | + overlappingTokens + ", overlappingLines=" + overlappingLines + ", amountPerRelation=" 48 | + amountPerRelation + ", amountPerLocation=" + amountPerLocation + ", amountPerContents=" 49 | + amountPerContents + ", amountPerExtract=" + amountPerExtract + ", amountPerCloneClassSize=" 50 | + amountPerCloneClassSize + ", amountPerNodes=" + amountPerNodes + ", amountPerTotalNodeVolume=" 51 | + amountPerTotalNodeVolume + ", amountPerEffectiveLines=" + amountPerEffectiveLines 52 | + ", amountPerTotalEffectiveLineVolume=" + amountPerTotalEffectiveLineVolume + "]"; 53 | } 54 | 55 | 56 | 57 | public void add(Metrics metrics) { 58 | totalAmountOfLines+=metrics.totalAmountOfLines; 59 | totalAmountOfNodes+=metrics.totalAmountOfNodes; 60 | totalAmountOfTokens+=metrics.totalAmountOfTokens; 61 | totalAmountOfEffectiveLines+=metrics.totalAmountOfEffectiveLines; 62 | 63 | amountOfLinesCloned+=metrics.amountOfLinesCloned; 64 | amountOfNodesCloned+=metrics.amountOfNodesCloned; 65 | amountOfTokensCloned+=metrics.amountOfTokensCloned; 66 | amountOfEffectiveLinesCloned+=metrics.amountOfEffectiveLinesCloned; 67 | 68 | overlappingNodes += metrics.overlappingNodes; 69 | overlappingEffectiveLines = metrics.overlappingEffectiveLines; 70 | overlappingTokens = metrics.overlappingTokens; 71 | overlappingLines = metrics.overlappingLines; 72 | 73 | amountPerRelation.addAll(metrics.amountPerRelation); 74 | amountPerLocation.addAll(metrics.amountPerLocation); 75 | amountPerContents.addAll(metrics.amountPerContents); 76 | amountPerExtract.addAll(metrics.amountPerExtract); 77 | 78 | amountPerCloneClassSize.addAll(metrics.amountPerCloneClassSize); 79 | amountPerNodes.addAll(metrics.amountPerNodes); 80 | amountPerTotalNodeVolume.addAll(metrics.amountPerTotalNodeVolume); 81 | 82 | amountPerEffectiveLines.addAll(metrics.amountPerEffectiveLines); 83 | amountPerTotalEffectiveLineVolume.addAll(metrics.amountPerTotalEffectiveLineVolume); 84 | } 85 | 86 | 87 | 88 | 89 | } 90 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/clonerefactor/metrics/ProblemType.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.clonerefactor.metrics; 2 | 3 | public enum ProblemType { 4 | DUPLICATION("Duplication"), 5 | UNITINTERFACESIZE("Unit Interface Size"), 6 | UNITCOMPLEXITY("Unit Complexity"), 7 | UNITVOLUME("Unit Volume"); 8 | 9 | private final String name; 10 | 11 | private ProblemType(String name) { 12 | this.name= name; 13 | } 14 | 15 | public String getName() { 16 | return name; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/clonerefactor/metrics/collectors/Calculator.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.clonerefactor.metrics.collectors; 2 | 3 | public interface Calculator { 4 | public int calculate(T t); 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/clonerefactor/metrics/collectors/CyclomaticComplexityCalculator.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.clonerefactor.metrics.collectors; 2 | import static com.github.javaparser.ast.expr.BinaryExpr.Operator.AND; 3 | import static com.github.javaparser.ast.expr.BinaryExpr.Operator.OR; 4 | 5 | import java.util.List; 6 | import java.util.stream.Collectors; 7 | 8 | import com.github.javaparser.ast.body.MethodDeclaration; 9 | import com.github.javaparser.ast.expr.BinaryExpr; 10 | import com.github.javaparser.ast.expr.ConditionalExpr; 11 | import com.github.javaparser.ast.stmt.DoStmt; 12 | import com.github.javaparser.ast.stmt.ForStmt; 13 | import com.github.javaparser.ast.stmt.IfStmt; 14 | import com.github.javaparser.ast.stmt.SwitchEntry; 15 | import com.github.javaparser.ast.stmt.WhileStmt; 16 | 17 | public class CyclomaticComplexityCalculator implements Calculator { 18 | @Override 19 | public int calculate(MethodDeclaration method) { 20 | List ifStmts = method.findAll(IfStmt.class); 21 | List forStmts = method.findAll(ForStmt.class); 22 | List whileStmts = method.findAll(WhileStmt.class); 23 | List doStmts = method.findAll(DoStmt.class); 24 | List catchStmts = method.findAll(SwitchEntry.class).stream(). 25 | filter(s -> !s.getLabels().isEmpty()) //Don't include "default" statements, only labeled case statements 26 | .collect(Collectors.toList()); 27 | List ternaryExprs = method.findAll(ConditionalExpr.class); 28 | List andExprs = method.findAll(BinaryExpr.class).stream(). 29 | filter(f -> f.getOperator() == AND).collect(Collectors.toList()); 30 | List orExprs = method.findAll(BinaryExpr.class).stream(). 31 | filter(f -> f.getOperator() == OR).collect(Collectors.toList()); 32 | 33 | return ifStmts.size() + 34 | forStmts.size() + 35 | whileStmts.size() + 36 | doStmts.size() + 37 | catchStmts.size() + 38 | ternaryExprs.size() + 39 | andExprs.size() + 40 | orExprs.size() + 41 | 1; 42 | } 43 | } -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/clonerefactor/metrics/collectors/NumberOfParametersCalculator.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.clonerefactor.metrics.collectors; 2 | 3 | import com.github.javaparser.ast.body.MethodDeclaration; 4 | 5 | /** 6 | * Simply counts the number of parameters on a method 7 | */ 8 | public class NumberOfParametersCalculator implements Calculator { 9 | @Override 10 | public int calculate(MethodDeclaration method) { 11 | return method.getParameters().size(); 12 | } 13 | } -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/clonerefactor/metrics/collectors/UnitSizeCalculator.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.clonerefactor.metrics.collectors; 2 | import java.util.HashSet; 3 | import java.util.List; 4 | import java.util.Set; 5 | import java.util.stream.StreamSupport; 6 | 7 | import com.github.javaparser.ast.Node; 8 | import com.github.javaparser.ast.body.MethodDeclaration; 9 | import com.simonbaars.clonerefactor.model.FiltersTokens; 10 | 11 | public class UnitSizeCalculator implements Calculator, FiltersTokens { 12 | @Override 13 | public int calculate(MethodDeclaration method) { 14 | Set lines = new HashSet<>(); 15 | findAll(lines, method.getChildNodes()); 16 | return lines.size(); 17 | } 18 | 19 | private void findAll(Set lines, List childNodes) { 20 | for(Node child : childNodes) { 21 | if(child.getTokenRange().isPresent()) 22 | StreamSupport.stream(child.getTokenRange().get().spliterator(), false).filter(e -> isComparableToken(e) && e.getRange().isPresent()).forEach(e -> lines.add(e.getRange().get().begin.line)); 23 | findAll(lines, child.getChildNodes()); 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/clonerefactor/metrics/enums/CloneLocation.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.clonerefactor.metrics.enums; 2 | 3 | import static com.simonbaars.clonerefactor.metrics.enums.CloneLocation.LocationType.CLASSLEVEL; 4 | import static com.simonbaars.clonerefactor.metrics.enums.CloneLocation.LocationType.CONSTRUCTORLEVEL; 5 | import static com.simonbaars.clonerefactor.metrics.enums.CloneLocation.LocationType.ENUMLEVEL; 6 | import static com.simonbaars.clonerefactor.metrics.enums.CloneLocation.LocationType.INTERFACELEVEL; 7 | import static com.simonbaars.clonerefactor.metrics.enums.CloneLocation.LocationType.METHODLEVEL; 8 | import static com.simonbaars.clonerefactor.metrics.enums.CloneLocation.LocationType.OUTSIDE; 9 | 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | 13 | import com.github.javaparser.ast.Node; 14 | import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; 15 | import com.github.javaparser.ast.body.ConstructorDeclaration; 16 | import com.github.javaparser.ast.body.MethodDeclaration; 17 | import com.simonbaars.clonerefactor.metrics.enums.CloneLocation.LocationType; 18 | import com.simonbaars.clonerefactor.model.Sequence; 19 | import com.simonbaars.clonerefactor.model.location.Location; 20 | 21 | public class CloneLocation implements MetricEnum { 22 | public enum LocationType{ 23 | METHODLEVEL, 24 | CONSTRUCTORLEVEL, 25 | CLASSLEVEL, 26 | INTERFACELEVEL, 27 | ENUMLEVEL, 28 | OUTSIDE; 29 | } 30 | 31 | @Override 32 | public LocationType get(Sequence sequence) { 33 | return get(sequence.getSequence().get(0)); 34 | } 35 | 36 | public LocationType get(Location l) { 37 | List locations = new ArrayList<>(); 38 | for(int i = 0; i second).get(); 42 | } 43 | 44 | private LocationType getLocation(Node node, int i) { 45 | if(getMethod(node)!=null && (!(node instanceof MethodDeclaration) || i == 0)) 46 | return METHODLEVEL; 47 | if(getConstructor(node)!=null && (!(node instanceof ConstructorDeclaration) || i == 0)) 48 | return CONSTRUCTORLEVEL; 49 | ClassOrInterfaceDeclaration class1 = getClass(node); 50 | if(class1 != null) { 51 | if(class1.isInterface()) 52 | return INTERFACELEVEL; 53 | else return CLASSLEVEL; 54 | } 55 | if(getEnum(node)!=null) 56 | return ENUMLEVEL; 57 | return OUTSIDE; 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/clonerefactor/metrics/enums/CloneRefactorability.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.clonerefactor.metrics.enums; 2 | 3 | import java.util.List; 4 | 5 | import com.github.javaparser.ast.Node; 6 | import com.github.javaparser.ast.stmt.BreakStmt; 7 | import com.github.javaparser.ast.stmt.ContinueStmt; 8 | import com.github.javaparser.ast.stmt.ReturnStmt; 9 | import com.simonbaars.clonerefactor.ast.interfaces.RequiresNodeOperations; 10 | import com.simonbaars.clonerefactor.metrics.enums.CloneRefactorability.Refactorability; 11 | import com.simonbaars.clonerefactor.model.Sequence; 12 | import com.simonbaars.clonerefactor.model.location.Location; 13 | 14 | public class CloneRefactorability implements MetricEnum, RequiresNodeOperations { 15 | public enum Refactorability{ 16 | CANBEEXTRACTED, 17 | NOEXTRACTIONBYCONTENTTYPE, 18 | PARTIALBLOCK, 19 | COMPLEXCONTROLFLOW, 20 | } 21 | 22 | @Override 23 | public Refactorability get(Sequence sequence) { 24 | if(new CloneContents().get(sequence)!=CloneContents.ContentsType.PARTIALMETHOD) 25 | return Refactorability.NOEXTRACTIONBYCONTENTTYPE; 26 | if(sequence.getSequence().stream().anyMatch(e -> e.getContents().getNodes().stream().anyMatch(f -> complexControlFlow(f)))) 27 | return Refactorability.COMPLEXCONTROLFLOW; 28 | for(Location location : sequence.getSequence()) { 29 | for(Node n : location.getContents().getNodes()) { 30 | List children = childrenToParse(n); 31 | if(children.stream().anyMatch(e -> !isExcluded(e) && !location.getContents().getNodes().contains(e))) { 32 | return Refactorability.PARTIALBLOCK; 33 | } 34 | } 35 | } 36 | return Refactorability.CANBEEXTRACTED; 37 | } 38 | 39 | private boolean complexControlFlow(Node n) { 40 | return n instanceof BreakStmt || n instanceof ReturnStmt || n instanceof ContinueStmt; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/clonerefactor/metrics/enums/MetricEnum.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.clonerefactor.metrics.enums; 2 | 3 | import com.simonbaars.clonerefactor.model.Sequence; 4 | 5 | @SuppressWarnings("rawtypes") 6 | public interface MetricEnum extends RequiresNodeContext { 7 | public MyEnum get(Sequence sequence); 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/clonerefactor/metrics/enums/RequiresNodeContext.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.clonerefactor.metrics.enums; 2 | 3 | import com.github.javaparser.ast.CompilationUnit; 4 | import com.github.javaparser.ast.Node; 5 | import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; 6 | import com.github.javaparser.ast.body.ConstructorDeclaration; 7 | import com.github.javaparser.ast.body.EnumDeclaration; 8 | import com.github.javaparser.ast.body.MethodDeclaration; 9 | 10 | public interface RequiresNodeContext { 11 | public default MethodDeclaration getMethod(Node n1) { 12 | while (!(n1 instanceof MethodDeclaration)) { 13 | if(n1.getParentNode().isPresent()) { 14 | n1 = n1.getParentNode().get(); 15 | } else return null; 16 | } 17 | return (MethodDeclaration)n1; 18 | } 19 | 20 | public default ConstructorDeclaration getConstructor(Node n1) { 21 | while (!(n1 instanceof ConstructorDeclaration)) { 22 | if(n1.getParentNode().isPresent()) { 23 | n1 = n1.getParentNode().get(); 24 | } else return null; 25 | } 26 | return (ConstructorDeclaration)n1; 27 | } 28 | 29 | public default ClassOrInterfaceDeclaration getClass(Node n1) { 30 | while (!(n1 instanceof ClassOrInterfaceDeclaration)) { 31 | if(n1.getParentNode().isPresent()) { 32 | n1 = n1.getParentNode().get(); 33 | } else return null; 34 | } 35 | return (ClassOrInterfaceDeclaration)n1; 36 | } 37 | 38 | public default CompilationUnit getCompilationUnit(Node n1) { 39 | while (!(n1 instanceof CompilationUnit)) { 40 | if(n1.getParentNode().isPresent()) { 41 | n1 = n1.getParentNode().get(); 42 | } else return null; 43 | } 44 | return (CompilationUnit)n1; 45 | } 46 | 47 | public default EnumDeclaration getEnum(Node n1) { 48 | while (!(n1 instanceof EnumDeclaration)) { 49 | if(n1.getParentNode().isPresent()) { 50 | n1 = n1.getParentNode().get(); 51 | } else return null; 52 | } 53 | return (EnumDeclaration)n1; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/clonerefactor/model/DetectionResults.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.clonerefactor.model; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.Collections; 6 | import java.util.List; 7 | 8 | import com.simonbaars.clonerefactor.metrics.Metrics; 9 | 10 | public class DetectionResults { 11 | private Metrics metrics; 12 | private List clones; 13 | 14 | public DetectionResults(Metrics metrics, List clones) { 15 | super(); 16 | this.metrics = metrics; 17 | this.clones = clones; 18 | } 19 | 20 | public DetectionResults() { 21 | super(); 22 | this.metrics = new Metrics(); 23 | this.clones = new ArrayList<>(); 24 | } 25 | 26 | public Metrics getMetrics() { 27 | return metrics; 28 | } 29 | 30 | public void setMetrics(Metrics metrics) { 31 | this.metrics = metrics; 32 | } 33 | 34 | public List getClones() { 35 | return clones; 36 | } 37 | 38 | public void setClones(List clones) { 39 | this.clones = clones; 40 | } 41 | 42 | @Override 43 | public String toString() { 44 | return "DetectionResults [metrics=" + metrics + "\n" 45 | + "clones=" + Arrays.toString(clones.toArray()).replace("Location [", "\nLocation [").replace("Sequence [sequence=[", "\nSequence [sequence=[") + "]"; 46 | } 47 | 48 | public DetectionResults sorted() { 49 | Collections.sort(getClones()); 50 | return this; 51 | } 52 | 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/clonerefactor/model/FiltersTokens.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.clonerefactor.model; 2 | 3 | import java.util.Arrays; 4 | import java.util.List; 5 | import java.util.stream.Collectors; 6 | import java.util.stream.Stream; 7 | import java.util.stream.StreamSupport; 8 | 9 | import com.github.javaparser.JavaToken; 10 | import com.github.javaparser.JavaToken.Category; 11 | import com.github.javaparser.TokenRange; 12 | import com.simonbaars.clonerefactor.settings.Settings; 13 | 14 | public interface FiltersTokens { 15 | public static final Category[] NO_TOKEN = {Category.COMMENT, Category.EOL, Category.WHITESPACE_NO_EOL}; 16 | public static final Category[] LITERATURE_TYPE2_NO_TOKEN = {Category.COMMENT, Category.EOL, Category.WHITESPACE_NO_EOL, Category.IDENTIFIER, Category.LITERAL}; 17 | 18 | public default Stream getEffectiveTokens(TokenRange tokens) { 19 | return StreamSupport.stream(tokens.spliterator(), false).filter(this::isComparableToken); 20 | } 21 | 22 | public default List getEffectiveTokenList(TokenRange tokens){ 23 | return getEffectiveTokens(tokens).collect(Collectors.toList()); 24 | } 25 | 26 | public default boolean isComparableToken(JavaToken t) { 27 | return Arrays.stream(Settings.get().getCloneType().isNotTypeOne() && Settings.get().useLiteratureTypeDefinitions() ? LITERATURE_TYPE2_NO_TOKEN : NO_TOKEN).noneMatch(c -> c.equals(t.getCategory())); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/clonerefactor/model/Sequence.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.clonerefactor.model; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.Collection; 6 | import java.util.List; 7 | 8 | import com.simonbaars.clonerefactor.metrics.enums.CloneRefactorability; 9 | import com.simonbaars.clonerefactor.metrics.enums.CloneRefactorability.Refactorability; 10 | import com.simonbaars.clonerefactor.metrics.enums.CloneRelation; 11 | import com.simonbaars.clonerefactor.metrics.enums.CloneRelation.RelationType; 12 | import com.simonbaars.clonerefactor.model.location.Location; 13 | 14 | public class Sequence implements Comparable { 15 | final List sequence; 16 | 17 | private RelationType relationType; 18 | private Refactorability refactorability; 19 | 20 | public Sequence(List collection) { 21 | super(); 22 | this.sequence = collection; 23 | } 24 | 25 | public Sequence() { 26 | super(); 27 | this.sequence = new ArrayList<>(); 28 | } 29 | 30 | public Sequence(Collection values) { 31 | this(new ArrayList<>(values)); 32 | } 33 | 34 | public Sequence(Sequence copy, int begin, int end) { 35 | this.sequence = copy.sequence.subList(begin, end); 36 | } 37 | 38 | public List getSequence() { 39 | return sequence; 40 | } 41 | 42 | public Sequence add(Location l) { 43 | sequence.add(l); 44 | return this; //For method chaining 45 | } 46 | 47 | public int size() { 48 | return sequence.size(); 49 | } 50 | 51 | @Override 52 | public String toString() { 53 | return "Sequence [sequence=" + Arrays.toString(sequence.toArray()) + "]"; 54 | } 55 | 56 | @Override 57 | public int hashCode() { 58 | final int prime = 31; 59 | int result = 1; 60 | result = prime * result + ((sequence == null) ? 0 : sequence.hashCode()); 61 | return result; 62 | } 63 | 64 | @Override 65 | public boolean equals(Object obj) { 66 | if (this == obj) 67 | return true; 68 | if (obj == null) 69 | return false; 70 | if (getClass() != obj.getClass()) 71 | return false; 72 | Sequence other = (Sequence) obj; 73 | if (sequence == null) { 74 | if (other.sequence != null) 75 | return false; 76 | } else if (!sequence.equals(other.sequence)) 77 | return false; 78 | return true; 79 | } 80 | 81 | public int getNodeSize() { 82 | return sequence.isEmpty() ? 0 : sequence.get(0).getAmountOfNodes(); 83 | } 84 | 85 | public int getEffectiveLineSize() { 86 | return sequence.isEmpty() ? 0 : sequence.get(0).getEffectiveLines(); 87 | } 88 | 89 | public int getTotalNodeVolume() { 90 | return sequence.stream().mapToInt(e -> e.getAmountOfNodes()).sum(); 91 | } 92 | 93 | public int getTotalTokenVolume() { 94 | return sequence.stream().mapToInt(e -> e.getAmountOfTokens()).sum(); 95 | } 96 | 97 | public int getTotalEffectiveLineVolume() { 98 | return sequence.stream().mapToInt(e -> e.getEffectiveLines()).sum(); 99 | } 100 | 101 | public Location getAny() { 102 | return sequence.get(0); 103 | } 104 | 105 | @Override 106 | public int compareTo(Sequence o) { 107 | if(getTotalNodeVolume() == o.getTotalNodeVolume()) 108 | return Integer.compare(o.getTotalTokenVolume(), getTotalTokenVolume()); 109 | return Integer.compare(o.getTotalNodeVolume(), getTotalNodeVolume()); 110 | } 111 | 112 | public void setMetrics(CloneRelation relation, CloneRefactorability r) { 113 | relationType = relation.get(this); 114 | refactorability = r.get(this); 115 | } 116 | 117 | public RelationType getRelationType() { 118 | return relationType; 119 | } 120 | 121 | public Refactorability getRefactorability() { 122 | return refactorability; 123 | } 124 | 125 | public void isValid() { 126 | if(sequence.stream().map(e -> e.getContents().getNodes().size()).distinct().count()>1) 127 | throw new IllegalStateException("Invalid Sequence "+this); 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/clonerefactor/model/location/LocationHolder.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.clonerefactor.model.location; 2 | 3 | public class LocationHolder { 4 | private Location location; 5 | 6 | public Location getLocation() { 7 | return location; 8 | } 9 | 10 | public void setLocation(Location location) { 11 | this.location = location; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/clonerefactor/model/simple/AbstractCloneInstance.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.clonerefactor.model.simple; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.List; 6 | 7 | import com.simonbaars.clonerefactor.model.location.Location; 8 | 9 | public class AbstractCloneInstance { 10 | final List acs = new ArrayList<>(); 11 | 12 | public AbstractCloneInstance(Location l) { 13 | l.getContents().getNodes().forEach(n -> acs.add(new AbstractClonedStatement(n))); 14 | } 15 | 16 | @Override 17 | public int hashCode() { 18 | final int prime = 31; 19 | int result = 1; 20 | result = prime * result + ((acs == null) ? 0 : acs.hashCode()); 21 | return result; 22 | } 23 | 24 | @Override 25 | public boolean equals(Object obj) { 26 | if (this == obj) 27 | return true; 28 | if (obj == null) 29 | return false; 30 | if (getClass() != obj.getClass()) 31 | return false; 32 | AbstractCloneInstance other = (AbstractCloneInstance) obj; 33 | if (acs == null) { 34 | if (other.acs != null) 35 | return false; 36 | } else if (!acs.equals(other.acs)) 37 | return false; 38 | return true; 39 | } 40 | 41 | @Override 42 | public String toString() { 43 | return "AbstractCloneInstance [acs=" + Arrays.toString(acs.toArray()) + "]"; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/clonerefactor/model/simple/AbstractClonedStatement.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.clonerefactor.model.simple; 2 | 3 | import java.util.List; 4 | import java.util.stream.Collectors; 5 | 6 | import com.github.javaparser.ast.Node; 7 | import com.simonbaars.clonerefactor.ast.interfaces.RequiresNodeOperations; 8 | 9 | public class AbstractClonedStatement implements RequiresNodeOperations { 10 | private final Class statementClass; 11 | private final Class parentClass; 12 | private final List> childClasses; 13 | 14 | public AbstractClonedStatement(Node n) { 15 | statementClass = n.getClass(); 16 | parentClass = n.getParentNode().isPresent() ? n.getParentNode().get().getClass() : null; 17 | childClasses = childrenToParse(n).stream().filter(e -> !isExcluded(e)).map(e -> e.getClass()).collect(Collectors.toList()); 18 | } 19 | 20 | @Override 21 | public int hashCode() { 22 | final int prime = 31; 23 | int result = 1; 24 | result = prime * result + ((childClasses == null) ? 0 : childClasses.hashCode()); 25 | result = prime * result + ((parentClass == null) ? 0 : parentClass.hashCode()); 26 | result = prime * result + ((statementClass == null) ? 0 : statementClass.hashCode()); 27 | return result; 28 | } 29 | 30 | @Override 31 | public boolean equals(Object obj) { 32 | if (this == obj) 33 | return true; 34 | if (obj == null) 35 | return false; 36 | if (getClass() != obj.getClass()) 37 | return false; 38 | AbstractClonedStatement other = (AbstractClonedStatement) obj; 39 | if (childClasses == null) { 40 | if (other.childClasses != null) 41 | return false; 42 | } else if (!childClasses.equals(other.childClasses)) 43 | return false; 44 | if (parentClass == null) { 45 | if (other.parentClass != null) 46 | return false; 47 | } else if (!parentClass.equals(other.parentClass)) 48 | return false; 49 | if (statementClass == null) { 50 | if (other.statementClass != null) 51 | return false; 52 | } else if (!statementClass.equals(other.statementClass)) 53 | return false; 54 | return true; 55 | } 56 | 57 | @Override 58 | public String toString() { 59 | return "AbstractClonedStatement [statementClass=" + statementClass.getName() + ", parentClass=" + parentClass.getName() 60 | + ", childClasses=" + childClasses.stream().map(e -> e.getName()).collect(Collectors.joining(", ", "{", "}")) + "]"; 61 | } 62 | 63 | 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/clonerefactor/scripts/RunAllConfigurations.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.clonerefactor.scripts; 2 | 3 | import java.util.Arrays; 4 | 5 | import com.simonbaars.clonerefactor.settings.CloneType; 6 | import com.simonbaars.clonerefactor.settings.Scope; 7 | import com.simonbaars.clonerefactor.settings.Settings; 8 | 9 | public class RunAllConfigurations { 10 | 11 | public static void main(String[] args) { 12 | CloneType[] cloneTypes = CloneType.values(); 13 | Scope[] scopes = Scope.values(); 14 | Settings.get().setCloneType(cloneTypes[0]); 15 | Settings.get().setScope(scopes[0]); 16 | Settings.get().setUseLiteratureTypeDefinitions(false); 17 | 18 | for(int i = 1; i<40; i++) { 19 | Settings.get().setMinAmountOfTokens(i); 20 | RunOnCorpus.main(args); 21 | rotate(cloneTypes, scopes); 22 | } 23 | } 24 | 25 | private static void rotate(CloneType[] cloneTypes, Scope[] scopes) { 26 | int curCloneType = Arrays.binarySearch(cloneTypes, Settings.get().getCloneType()); 27 | int curScope = Arrays.binarySearch(scopes, Settings.get().getScope()); 28 | if(Settings.get().isUseLiteratureTypeDefinitions()) { 29 | if(curCloneType>curScope) { 30 | curScope ++; 31 | } else curCloneType ++; 32 | } 33 | Settings.get().setUseLiteratureTypeDefinitions(!Settings.get().isUseLiteratureTypeDefinitions()); 34 | Settings.get().setCloneType(cloneTypes[curCloneType]); 35 | Settings.get().setScope(scopes[curScope]); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/clonerefactor/scripts/RunOnCorpus.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.clonerefactor.scripts; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | 6 | import com.simonbaars.clonerefactor.settings.Settings; 7 | import com.simonbaars.clonerefactor.thread.ThreadPool; 8 | import com.simonbaars.clonerefactor.thread.WritesErrors; 9 | import com.simonbaars.clonerefactor.util.FileUtils; 10 | import com.simonbaars.clonerefactor.util.SavePaths; 11 | 12 | public class RunOnCorpus implements WritesErrors { 13 | 14 | public static void main(String[] args) { 15 | new RunOnCorpus().startCorpusCloneDetection(); 16 | } 17 | 18 | private void startCorpusCloneDetection() { 19 | try { 20 | System.out.println(Settings.get().getMinAmountOfTokens()); 21 | SavePaths.genTimestamp(); 22 | ThreadPool threadPool = new ThreadPool(); 23 | File[] corpusFiles = new File(SavePaths.getApplicationDataFolder()+"git").listFiles(); 24 | writeSettings(); 25 | analyzeAllProjects(threadPool, corpusFiles); 26 | threadPool.finishFinalThreads(); 27 | System.out.println("== Done =="); 28 | } catch (Exception e) { 29 | writeError(SavePaths.getMyOutputFolder()+"terminate", e); 30 | } 31 | } 32 | 33 | private void writeSettings() { 34 | try { 35 | FileUtils.writeStringToFile(new File(SavePaths.getMyOutputFolder()+"settings.txt"), Settings.get().toString()); 36 | } catch (IOException e) { 37 | e.printStackTrace(); 38 | } 39 | } 40 | 41 | private void analyzeAllProjects(ThreadPool threadPool, File[] corpusFiles) { 42 | for(int i = 0; i isQualified(getSourceFolder(f), 5, 1000))[2888]); 19 | } 20 | 21 | public static File[] getFilteredCorpusFiles(int min, int max) { 22 | return JAVA_PROJECTS_CORPUS_FOLDER.listFiles(f -> isQualified(getSourceFolder(f), min, max)); 23 | } 24 | 25 | public static File getSourceFolder(File f) { 26 | return new File(f.getAbsolutePath()+"/src/main/java"); 27 | } 28 | 29 | public static boolean isQualified(File project, int min, int max) { 30 | return project.exists() && between(min, max, countJavaFiles(project)); 31 | } 32 | 33 | private static boolean between(int min, int max, long javaFilesInProject) { 34 | return javaFilesInProject >=min && javaFilesInProject <= max; 35 | } 36 | 37 | private static long countJavaFiles(File project) { 38 | return getJavaFileStream(project).count(); 39 | } 40 | 41 | private static Stream getJavaFileStream(File project) { 42 | try { 43 | return Files.walk(project.toPath()) 44 | .parallel() 45 | .filter(p -> !p.toFile().isDirectory() && p.toString().endsWith(".java")); 46 | } catch (IOException e) { 47 | throw new RuntimeException(e); 48 | } 49 | } 50 | 51 | public static List getJavaFiles(File project){ 52 | return getJavaFileStream(project).map(e -> e.toFile()).collect(Collectors.toList()); 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/clonerefactor/scripts/prepare/ValidateCorpus.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.clonerefactor.scripts.prepare; 2 | 3 | import java.io.File; 4 | import java.io.FileOutputStream; 5 | import java.io.IOException; 6 | import java.net.HttpURLConnection; 7 | import java.net.URL; 8 | 9 | import com.simonbaars.clonerefactor.util.FileUtils; 10 | import com.simonbaars.clonerefactor.util.SavePaths; 11 | 12 | public class ValidateCorpus { 13 | 14 | public static void main(String[] args) throws IOException { 15 | String file = FileUtils.getFileAsString(SavePaths.getApplicationDataFolder()+"projects.txt"); 16 | FileOutputStream fos = new FileOutputStream(new File(SavePaths.getApplicationDataFolder()+"filtered_projects.txt")); 17 | for(String s : file.split("\n")) { 18 | int pom = doRequest("https://raw.githubusercontent.com"+s+"/master/pom.xml"), sourceFolder = doRequest("https://github.com"+s+"/tree/master/src/main/java"); 19 | if(pom != 404 && sourceFolder != 404) { 20 | fos.write(s.getBytes()); 21 | fos.write(System.lineSeparator().getBytes()); 22 | } 23 | } 24 | fos.close(); 25 | } 26 | 27 | public static int doRequest(String u) throws IOException { 28 | URL url = new URL(u); 29 | HttpURLConnection connection = (HttpURLConnection)url.openConnection(); 30 | connection.setRequestMethod("GET"); 31 | connection.connect(); 32 | int res = connection.getResponseCode(); 33 | connection.disconnect(); 34 | return res; 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/clonerefactor/settings/CloneType.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.clonerefactor.settings; 2 | 3 | public enum CloneType { 4 | TYPE1,TYPE2,TYPE3; 5 | 6 | public boolean isNotTypeOne() { 7 | return this!=TYPE1; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/clonerefactor/settings/Scope.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.clonerefactor.settings; 2 | 3 | public enum Scope { 4 | ALL, METHODSONLY, METHODBODYONLY 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/clonerefactor/thread/CorpusThread.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.clonerefactor.thread; 2 | 3 | import java.io.File; 4 | import java.nio.file.Paths; 5 | import java.util.concurrent.TimeoutException; 6 | 7 | import com.simonbaars.clonerefactor.Main; 8 | import com.simonbaars.clonerefactor.model.DetectionResults; 9 | 10 | public class CorpusThread extends Thread { 11 | private final File file; 12 | public DetectionResults res; 13 | public final long creationTime; 14 | public Exception error; 15 | 16 | public CorpusThread(File file) { 17 | this.file=file; 18 | this.creationTime = System.currentTimeMillis(); 19 | start(); 20 | } 21 | 22 | public void run() { 23 | try { 24 | res = Main.cloneDetection(file.toPath(), Paths.get(file.getAbsolutePath()+"/src/main/java")); 25 | res.sorted(); 26 | } catch(Exception e) { 27 | error = e; 28 | } 29 | } 30 | 31 | @SuppressWarnings("deprecation") 32 | public void timeout() { 33 | stop(); 34 | error = new TimeoutException("Thread has exceeded its timeout!"); 35 | } 36 | 37 | public File getFile() { 38 | return file; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/clonerefactor/thread/ThreadPool.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.clonerefactor.thread; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.util.Arrays; 6 | import java.util.stream.Collectors; 7 | import java.util.stream.IntStream; 8 | 9 | import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade; 10 | import com.simonbaars.clonerefactor.metrics.Metrics; 11 | import com.simonbaars.clonerefactor.model.DetectionResults; 12 | import com.simonbaars.clonerefactor.util.FileUtils; 13 | import com.simonbaars.clonerefactor.util.SavePaths; 14 | 15 | public class ThreadPool implements WritesErrors { 16 | private final File OUTPUT_FOLDER = new File(SavePaths.getFullOutputFolder()); 17 | private final File FULL_METRICS = new File(OUTPUT_FOLDER.getParent()+"/metrics.txt"); 18 | private final int NUMBER_OF_THREADS = 4; 19 | private final int THREAD_TIMEOUT = 600000; 20 | private final Metrics fullMetrics = new Metrics(); 21 | 22 | private final CorpusThread[] threads; 23 | 24 | public ThreadPool () { 25 | threads = new CorpusThread[NUMBER_OF_THREADS]; 26 | OUTPUT_FOLDER.mkdirs(); 27 | } 28 | 29 | public void waitForThreadToFinish() { 30 | if(allNull()) 31 | return; 32 | while(Arrays.stream(threads).filter(e -> e!=null).noneMatch(e -> !e.isAlive())) { 33 | try { 34 | Thread.sleep(100); 35 | nullifyThreadIfStarved(); 36 | } catch (InterruptedException e1) { 37 | Thread.currentThread().interrupt(); 38 | } 39 | } 40 | } 41 | 42 | private void nullifyThreadIfStarved() { 43 | IntStream.range(0,size()).filter(i -> threads[i]!=null && threads[i].creationTime+THREAD_TIMEOUT { 44 | threads[i].timeout(); 45 | }); 46 | } 47 | 48 | private int size() { 49 | return NUMBER_OF_THREADS; 50 | } 51 | 52 | public void addToAvailableThread(File file) { 53 | for(int i = 0; i e!=null)) { 64 | waitForThreadToFinish(); 65 | for(int i = 0; i e!=null).map(e -> e.getFile().getName()).collect(Collectors.joining(", ")); 104 | } 105 | 106 | public boolean anyNull() { 107 | return Arrays.stream(threads).anyMatch(e -> e==null); 108 | } 109 | 110 | public boolean allNull() { 111 | return Arrays.stream(threads).allMatch(e -> e==null); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/clonerefactor/thread/WritesErrors.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.clonerefactor.thread; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | 6 | import org.apache.commons.lang3.exception.ExceptionUtils; 7 | 8 | import com.simonbaars.clonerefactor.util.FileUtils; 9 | 10 | public interface WritesErrors { 11 | public default void writeError(String path, Exception exception) { 12 | try { 13 | FileUtils.writeStringToFile(new File(path+".txt"), ExceptionUtils.getStackTrace(exception)); 14 | } catch (IOException | NullPointerException e) { 15 | e.printStackTrace(); // Well, this is awkward... 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/clonerefactor/util/NoJavaFilesFoundException.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.clonerefactor.util; 2 | 3 | public class NoJavaFilesFoundException extends RuntimeException { 4 | 5 | /** 6 | * 7 | */ 8 | private static final long serialVersionUID = -2972109211543532640L; 9 | 10 | public NoJavaFilesFoundException() { 11 | super("No Java files were found in this folder!"); 12 | } 13 | 14 | public NoJavaFilesFoundException(String message, Throwable cause, boolean enableSuppression, 15 | boolean writableStackTrace) { 16 | super(message, cause, enableSuppression, writableStackTrace); 17 | } 18 | 19 | public NoJavaFilesFoundException(String message, Throwable cause) { 20 | super(message, cause); 21 | } 22 | 23 | public NoJavaFilesFoundException(String message) { 24 | super(message); 25 | } 26 | 27 | public NoJavaFilesFoundException(Throwable cause) { 28 | super(cause); 29 | } 30 | 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/clonerefactor/util/OperatingSystem.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.clonerefactor.util; 2 | 3 | public enum OperatingSystem { 4 | WINDOWS, LINUX, MACOS; 5 | 6 | public boolean isUnix() { 7 | return this != WINDOWS; 8 | } 9 | 10 | public static OperatingSystem get() { 11 | String os = System.getProperty("os.name").toLowerCase(); 12 | if (os.contains("win")) return WINDOWS; 13 | else if (os.contains("mac")) return MACOS; 14 | else return LINUX; 15 | } 16 | } -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/clonerefactor/util/SavePaths.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.clonerefactor.util; 2 | 3 | import java.io.File; 4 | import java.text.SimpleDateFormat; 5 | import java.util.Date; 6 | 7 | public class SavePaths { 8 | 9 | private static String dataFolder = "clone"; 10 | private static String timestamp = null; 11 | 12 | private SavePaths() {} 13 | 14 | public static void genTimestamp() { 15 | timestamp = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()); 16 | } 17 | 18 | public static void setAlternativeDataFolder(String folder) { 19 | dataFolder = folder; 20 | } 21 | 22 | public static String createDirectoryIfNotExists(String path){ 23 | new File(path).mkdirs(); 24 | return path; 25 | } 26 | 27 | public static String getApplicationDataFolder() { 28 | return getPathForOS() + File.separator + dataFolder + File.separator; 29 | } 30 | 31 | public static String getOutputFolder() { 32 | return getApplicationDataFolder() + "output" + File.separator; 33 | } 34 | 35 | private static String getPathForOS() { 36 | switch(OperatingSystem.get()) { 37 | case WINDOWS: return System.getenv("APPDATA"); 38 | default: return System.getProperty("user.home"); 39 | } 40 | } 41 | 42 | public static String getFullOutputFolder() { 43 | return getMyOutputFolder()+"full"+File.separator; 44 | } 45 | 46 | public static String getMyOutputFolder() { 47 | if(timestamp == null) 48 | genTimestamp(); 49 | return SavePaths.createDirectoryIfNotExists(SavePaths.getOutputFolder())+timestamp+File.separator; 50 | } 51 | 52 | public static String getJavaProjectFolder() { 53 | return getApplicationDataFolder()+"java_projects"+File.separator; 54 | } 55 | 56 | public static String getGitFolder() { 57 | return getApplicationDataFolder()+"git"+File.separator; 58 | } 59 | 60 | public static String getGitSourcesFolder() { 61 | return getApplicationDataFolder()+"gitsrc"+File.separator; 62 | } 63 | 64 | public static String getErrorFolder() { 65 | return getMyOutputFolder()+"errors"+File.separator; 66 | } 67 | } -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/clonerefactor/util/Wait.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.clonerefactor.util; 2 | 3 | import java.util.function.BooleanSupplier; 4 | 5 | public class Wait { 6 | private final int timeout; 7 | private final int interval; 8 | 9 | public Wait(int timeout) { 10 | this.timeout=timeout; 11 | this.interval=400; 12 | } 13 | 14 | public Wait(int timeout, int interval) { 15 | this.timeout=timeout; 16 | this.interval=interval; 17 | } 18 | 19 | public boolean until(BooleanSupplier t) { 20 | long endTime = System.currentTimeMillis()+(timeout*1000); 21 | while(System.currentTimeMillis() <(optional) clone type> <(optional) similarity>"; 34 | } 35 | 36 | @Override 37 | public List getAliases() { 38 | List aliases = Lists.newArrayList(); 39 | aliases.add("/codeclones"); 40 | return aliases; 41 | } 42 | 43 | @Override 44 | public void execute(MinecraftServer server, ICommandSender sender, String[] args) throws CommandException { 45 | if(args.length==0) { 46 | sender.sendMessage(FormatsText.format(net.minecraft.util.text.TextFormatting.BLUE, "Please enter the number of the project you'd like to search for code clones:")); 47 | String[] projects = new File(SavePaths.getProjectFolder()).list(); 48 | IntStream.range(0, projects.length).forEach(i -> sender.sendMessage(FormatsText.format(net.minecraft.util.text.TextFormatting.WHITE, "["+(i+1)+"] "+projects[i]))); 49 | CloneDetection.dialoge = 1; 50 | return; 51 | } 52 | ProblemDetectionThread.startWorker(server, args[0]); 53 | } 54 | 55 | @Override 56 | public boolean checkPermission(MinecraftServer server, ICommandSender sender) { 57 | return true; 58 | } 59 | 60 | @Override 61 | public List getTabCompletions(MinecraftServer server, ICommandSender sender, String[] args, 62 | BlockPos targetPos) { 63 | return Arrays.asList(new File(SavePaths.getProjectFolder()).list()); 64 | } 65 | 66 | @Override 67 | public boolean isUsernameIndex(String[] args, int index) { 68 | return false; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/codearena/EndCommand.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.codearena; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import com.google.common.collect.Lists; 7 | import com.simonbaars.codearena.common.FormatsText; 8 | 9 | import net.minecraft.command.CommandException; 10 | import net.minecraft.command.ICommand; 11 | import net.minecraft.command.ICommandSender; 12 | import net.minecraft.server.MinecraftServer; 13 | import net.minecraft.util.math.BlockPos; 14 | 15 | public class EndCommand implements ICommand, FormatsText { 16 | 17 | @Override 18 | public int compareTo(ICommand arg0) { 19 | return Integer.compare(hashCode(), arg0.hashCode()); 20 | } 21 | 22 | @Override 23 | public String getName() { 24 | return "end"; 25 | } 26 | 27 | @Override 28 | public String getUsage(ICommandSender sender) { 29 | return "/end (ends the current code clone arena)"; 30 | } 31 | 32 | @Override 33 | public List getAliases() { 34 | List aliases = Lists.newArrayList(); 35 | aliases.add("/end"); 36 | return aliases; 37 | } 38 | 39 | @Override 40 | public void execute(MinecraftServer server, ICommandSender sender, String[] args) throws CommandException { 41 | CloneDetection c = CloneDetection.get(); 42 | if(c.getArena() == null) 43 | sender.sendMessage(FormatsText.format(net.minecraft.util.text.TextFormatting.RED, "There is no Code Arena running")); 44 | else c.getArena().endChallengeForAllPlayers(); 45 | 46 | } 47 | 48 | @Override 49 | public boolean checkPermission(MinecraftServer server, ICommandSender sender) { 50 | return true; 51 | } 52 | 53 | @Override 54 | public List getTabCompletions(MinecraftServer server, ICommandSender sender, String[] args, 55 | BlockPos targetPos) { 56 | return new ArrayList<>(); 57 | } 58 | 59 | @Override 60 | public boolean isUsernameIndex(String[] args, int index) { 61 | return false; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/codearena/common/FormatsText.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.codearena.common; 2 | 3 | import net.minecraft.util.text.TextComponentTranslation; 4 | import net.minecraft.util.text.TextFormatting; 5 | 6 | public interface FormatsText { 7 | public static TextComponentTranslation format(TextFormatting color, String str, Object... args) 8 | { 9 | TextComponentTranslation ret = new TextComponentTranslation(str, args); 10 | ret.getStyle().setColor(color); 11 | return ret; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/codearena/common/OperatingSystem.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.codearena.common; 2 | 3 | public enum OperatingSystem { 4 | WINDOWS, LINUX, MACOS; 5 | 6 | public boolean isUnix() { 7 | return this != WINDOWS; 8 | } 9 | } -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/codearena/common/ResourceCommons.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.codearena.common; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.net.URI; 6 | import java.net.URL; 7 | import java.net.URLDecoder; 8 | import java.nio.file.FileSystem; 9 | import java.nio.file.FileSystems; 10 | import java.nio.file.FileVisitResult; 11 | import java.nio.file.Files; 12 | import java.nio.file.Path; 13 | import java.nio.file.Paths; 14 | import java.nio.file.SimpleFileVisitor; 15 | import java.nio.file.attribute.BasicFileAttributes; 16 | import java.util.HashMap; 17 | import java.util.Map; 18 | 19 | public class ResourceCommons { 20 | 21 | private ResourceCommons() {} 22 | 23 | public static File getResource(String path) { 24 | if(path.length()>0 && path.charAt(0) == File.separatorChar) 25 | path = path.substring(1); 26 | return new File(SavePaths.getResourceFolder()+path); 27 | } 28 | 29 | public static void extractResources() { 30 | extractResources(""); 31 | } 32 | 33 | public static void extractResources(String path) { 34 | try { 35 | File resource = getResource(""); 36 | if(!resource.exists()) 37 | extractResources(ResourceCommons.class, path); 38 | } catch (Exception e) { 39 | throw new RuntimeException("Resources could not be extracted!", e); 40 | } 41 | } 42 | 43 | public static void extractResources(@SuppressWarnings("rawtypes") Class protectionDomainProvider, String path) throws IOException { 44 | final File jarFile = new File(protectionDomainProvider.getProtectionDomain().getCodeSource().getLocation().getPath()); 45 | if(jarFile.isFile() && jarFile.getName().endsWith(".jar")) 46 | extractJar(jarFile, path); 47 | else { 48 | URL resourceUrl = null; 49 | resourceUrl = protectionDomainProvider.getResource(File.separator+path); 50 | if(resourceUrl == null) 51 | resourceUrl = protectionDomainProvider.getClassLoader().getResource(File.separator+path); 52 | copyPathToResourcesFolder(Paths.get(URLDecoder.decode(new File(resourceUrl.getFile()).getAbsolutePath(), "UTF-8")), path); 53 | } 54 | } 55 | 56 | private static void extractJar(File p, String path) throws IOException { 57 | Map env = new HashMap<>(); 58 | URI uri = URI.create("jar:" + p.toPath().toUri()); 59 | try (FileSystem fs = FileSystems.newFileSystem(uri, env)) 60 | { 61 | Path jarRoot = fs.getPath(File.separator + path); 62 | copyPathToResourcesFolder(jarRoot, path); 63 | } 64 | } 65 | 66 | private static void copyPathToResourcesFolder(Path jarRoot, String path) throws IOException { 67 | Files.walkFileTree(jarRoot, new SimpleFileVisitor() { 68 | @Override 69 | public FileVisitResult visitFile(Path filePath, BasicFileAttributes attrs) throws IOException { 70 | // Make sure that we conserve the hierachy of files and folders inside the zip 71 | Path relativePathInZip = jarRoot.relativize(filePath); 72 | String replace = relativePathInZip.toString().replace(".."+File.separator, ""); 73 | if(replace.indexOf(path) != -1) 74 | replace = replace.substring(replace.indexOf(path)+path.length()); 75 | File file = new File(SavePaths.getResourceFolder()+replace); 76 | Path targetPath = file.toPath(); 77 | Files.createDirectories(targetPath.getParent()); 78 | // And extract the file 79 | Files.copy(filePath, targetPath); 80 | 81 | return FileVisitResult.CONTINUE; 82 | } 83 | }); 84 | } 85 | } -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/codearena/common/SavePaths.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.codearena.common; 2 | 3 | import java.io.File; 4 | import java.util.Arrays; 5 | 6 | public class SavePaths { 7 | 8 | private static String dataFolder = ".clone"; 9 | public static final String[] NO_METRICS = {"loader.rsc", "metricscommons.rsc"}; 10 | 11 | private SavePaths() {} 12 | 13 | public static void setAlternativeDataFolder(String folder) { 14 | dataFolder = folder; 15 | } 16 | 17 | public static String createDirectoryIfNotExists(String path){ 18 | new File(path).mkdirs(); 19 | return path; 20 | } 21 | 22 | public static String getApplicationDataFolder() { 23 | return getPathForOS(System.getProperty("os.name")) + File.separator + dataFolder + File.separator; 24 | } 25 | 26 | public static String getResourceFolder() { 27 | return getApplicationDataFolder() + "resources" + File.separator; 28 | } 29 | 30 | public static String getRascalFolder() { 31 | return getResourceFolder() + "rascal" + File.separator; 32 | } 33 | 34 | public static String getProjectFolder() { 35 | return getApplicationDataFolder() + "projects" + File.separator; 36 | } 37 | 38 | public static String getSaveFolder() { 39 | return getApplicationDataFolder() + "saves" + File.separator; 40 | } 41 | 42 | public static boolean resourceFolderExists() { 43 | return new File(getResourceFolder()).exists(); 44 | } 45 | 46 | private static String getPathForOS(String os) { 47 | os = os.toLowerCase(); 48 | if (os.contains("win")) return System.getenv("APPDATA"); 49 | else if (os.contains("mac")) return System.getProperty("user.home") + File.separator + "Library" + File.separator + "Application Support"; 50 | else return System.getProperty("user.home"); 51 | } 52 | 53 | public static String[] getMetrics() { 54 | return new File(SavePaths.getRascalFolder()).list((dir, name) -> Arrays.stream(NO_METRICS).noneMatch(e -> e.equals(name))); 55 | } 56 | } -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/codearena/editor/CodeEditorMaker.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.codearena.editor; 2 | 3 | import java.io.File; 4 | 5 | import javax.swing.SwingUtilities; 6 | import javax.swing.UIManager; 7 | 8 | import com.simonbaars.clonerefactor.model.location.Location; 9 | import com.simonbaars.codearena.CloneDetection; 10 | import com.simonbaars.codearena.model.MetricProblem; 11 | import com.simonbaars.codearena.thread.ProblemDetectionThread; 12 | 13 | import net.minecraft.client.Minecraft; 14 | 15 | public class CodeEditorMaker { 16 | 17 | private CodeEditorMaker() {} 18 | 19 | public static void create(MetricProblem cloneClass) { 20 | ProblemDetectionThread.startWorker(Minecraft.getMinecraft().player, cloneClass, true); 21 | for(int i = 0; i { 24 | try { 25 | UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 26 | } catch (Exception e) { 27 | e.printStackTrace(); 28 | } 29 | Location location = cloneClass.get(j); 30 | CodeEditor e = new CodeEditor(cloneClass, location.getFile().toFile(), location.getRange().begin.line, location.getRange().end.line, j, cloneClass.size()); 31 | CloneDetection.get().openEditors.add(e); 32 | e.setVisible(true); 33 | }); 34 | } 35 | CodeEditor.locked = false; 36 | } 37 | 38 | public static void create(File file, String metric) { 39 | SwingUtilities.invokeLater(() -> { 40 | try { 41 | UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 42 | } catch (Exception e) { 43 | e.printStackTrace(); 44 | } 45 | CodeEditor e = new CodeEditor(file, false, metric); 46 | CloneDetection.get().openEditors.add(e); 47 | e.setVisible(true); 48 | }); 49 | CodeEditor.locked = false; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/codearena/editor/SaveFile.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.codearena.editor; 2 | 3 | import java.awt.event.ActionEvent; 4 | import java.io.File; 5 | import java.io.IOException; 6 | 7 | import javax.swing.AbstractAction; 8 | import javax.swing.JLabel; 9 | import javax.swing.JTextArea; 10 | 11 | import com.simonbaars.clonerefactor.util.FileUtils; 12 | 13 | public class SaveFile extends AbstractAction { 14 | /** 15 | * 16 | */ 17 | private static final long serialVersionUID = -4940861690942712089L; 18 | private File file; 19 | private JTextArea textArea; 20 | private JLabel statusBar; 21 | 22 | public SaveFile(File file, JTextArea textArea, JLabel statusBar) { 23 | super(); 24 | this.file = file; 25 | this.textArea = textArea; 26 | this.statusBar = statusBar; 27 | } 28 | 29 | @Override 30 | public void actionPerformed(ActionEvent e) { 31 | try { 32 | FileUtils.writeStringToFile(file, textArea.getText()); 33 | statusBar.setText("File successfully saved!"); 34 | } catch (IOException e1) { 35 | e1.printStackTrace(); 36 | } 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/codearena/editor/TipViewer.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.codearena.editor; 2 | 3 | import java.awt.BorderLayout; 4 | import java.awt.Desktop; 5 | import java.awt.Dimension; 6 | import java.io.IOException; 7 | import java.net.URISyntaxException; 8 | 9 | import javax.swing.JEditorPane; 10 | import javax.swing.JFrame; 11 | import javax.swing.JScrollPane; 12 | import javax.swing.event.HyperlinkEvent; 13 | import javax.swing.event.HyperlinkListener; 14 | import javax.swing.text.Document; 15 | import javax.swing.text.html.HTMLEditorKit; 16 | 17 | import com.simonbaars.clonerefactor.metrics.ProblemType; 18 | import com.simonbaars.clonerefactor.model.Sequence; 19 | import com.simonbaars.codearena.model.MetricProblem; 20 | 21 | public class TipViewer implements GetTip { 22 | public static void main(String[] args) { 23 | new TipViewer().createHTMLView(new MetricProblem(ProblemType.DUPLICATION, 10, new Sequence())); 24 | } 25 | 26 | public void createHTMLView(MetricProblem p) { 27 | // create jeditorpane 28 | JEditorPane jEditorPane = new JEditorPane(); 29 | 30 | // make it read-only 31 | jEditorPane.setEditable(false); 32 | 33 | // create a scrollpane; modify its attributes as desired 34 | JScrollPane scrollPane = new JScrollPane(jEditorPane); 35 | 36 | // add an html editor kit 37 | HTMLEditorKit kit = new HTMLEditorKit(); 38 | jEditorPane.setEditorKit(kit); 39 | jEditorPane.addHyperlinkListener(new HyperlinkListener() { 40 | 41 | @Override 42 | public void hyperlinkUpdate(HyperlinkEvent e) { 43 | if(e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { 44 | if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) { 45 | try { 46 | Desktop.getDesktop().browse(e.getURL().toURI()); 47 | } catch (IOException | URISyntaxException e1) { 48 | e1.printStackTrace(); 49 | } 50 | }else{ 51 | Runtime runtime = Runtime.getRuntime(); 52 | try { 53 | runtime.exec("xdg-open " + e.getURL().toString()); 54 | } catch (IOException e2) { 55 | e2.printStackTrace(); 56 | } 57 | } 58 | } 59 | } 60 | }); 61 | 62 | // create some simple html as a string 63 | String htmlString = getTip(p); 64 | 65 | // create a document, set it on the jeditorpane, then add the html 66 | Document doc = kit.createDefaultDocument(); 67 | jEditorPane.setDocument(doc); 68 | jEditorPane.setText(htmlString); 69 | 70 | // now add it all to a frame 71 | JFrame j = new JFrame("How to solve this problem"); 72 | j.getContentPane().add(scrollPane, BorderLayout.CENTER); 73 | 74 | // display the frame 75 | j.setSize(new Dimension(1280,720)); 76 | 77 | // pack it, if you prefer 78 | //j.pack(); 79 | 80 | // center the jframe, then make it visible 81 | j.setLocationRelativeTo(null); 82 | j.setVisible(true); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/codearena/minecraft/CreatorBlocks.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.codearena.minecraft; 2 | 3 | import net.minecraft.world.World; 4 | 5 | public class CreatorBlocks { 6 | protected World world; 7 | public int x; 8 | public int y; 9 | public int z; 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/codearena/minecraft/ForgeEventHandler.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.codearena.minecraft; 2 | 3 | import java.io.File; 4 | 5 | import com.simonbaars.codearena.CloneDetection; 6 | import com.simonbaars.codearena.common.SavePaths; 7 | import com.simonbaars.codearena.thread.ProblemDetectionThread; 8 | 9 | import net.minecraftforge.event.ServerChatEvent; 10 | import net.minecraftforge.event.world.WorldEvent; 11 | import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; 12 | 13 | public class ForgeEventHandler { 14 | public static int searchingPage = 1; 15 | boolean searchByTitle; 16 | 17 | @SubscribeEvent 18 | public void livingSpawnEvent(WorldEvent.Load event){ 19 | CloneDetection.dialoge=0; 20 | } 21 | 22 | @SubscribeEvent 23 | public void playerChat(ServerChatEvent event){ 24 | if(CloneDetection.dialoge!=0){ 25 | if(CloneDetection.dialoge==1){ 26 | try{ 27 | int inputNumber = Integer.parseInt(event.getMessage()); 28 | String[] projects = new File(SavePaths.getProjectFolder()).list(); 29 | if(inputNumber < 1 || inputNumber > projects.length){ 30 | CloneDetection.get().eventHandler.delayedPrints.add("This is not a valid number of a project. Please enter a number between 1-"+projects.length+"."); 31 | } else { 32 | //CloneDetection.eventHandler.delayedPrints.add("Thank you. We'll generate a beatiful city out of the clones of this project."); 33 | CloneDetection.dialoge=0; 34 | ProblemDetectionThread.startWorker(event.getPlayer(), projects[inputNumber-1]); 35 | } 36 | } catch (Exception e){ 37 | CloneDetection.get().eventHandler.delayedPrints.add("Please only use numbers"); 38 | } 39 | } 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/codearena/minecraft/ICreatorBlock.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.codearena.minecraft; 2 | 3 | public interface ICreatorBlock { 4 | abstract boolean run(); 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/codearena/minecraft/ModEntities.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.codearena.minecraft; 2 | 3 | import com.simonbaars.codearena.CloneDetection; 4 | import com.simonbaars.codearena.monster.codecreeper.CodeCreeperFactory; 5 | import com.simonbaars.codearena.monster.codecreeper.EntityCodeCreeper; 6 | import com.simonbaars.codearena.monster.codeskeleton.CodeSkeletonFactory; 7 | import com.simonbaars.codearena.monster.codeskeleton.EntityCodeSkeleton; 8 | import com.simonbaars.codearena.monster.codespider.CodeSpiderFactory; 9 | import com.simonbaars.codearena.monster.codespider.EntityCodeSpider; 10 | import com.simonbaars.codearena.monster.codezombie.CodeZombieFactory; 11 | import com.simonbaars.codearena.monster.codezombie.EntityCodeZombie; 12 | 13 | import net.minecraft.util.ResourceLocation; 14 | import net.minecraftforge.fml.client.registry.RenderingRegistry; 15 | import net.minecraftforge.fml.common.registry.EntityRegistry; 16 | import net.minecraftforge.fml.relauncher.Side; 17 | import net.minecraftforge.fml.relauncher.SideOnly; 18 | 19 | public class ModEntities { 20 | 21 | public static void init() { 22 | // Every entity in our mod has an ID (local to this mod) 23 | int id = 1; 24 | EntityRegistry.registerModEntity(new ResourceLocation(CloneDetection.MODID, "codespider"), EntityCodeSpider.class, "CodeSpider", id++, CloneDetection.get(), 64, 3, true, 0x996600, 0x00ff00); 25 | EntityRegistry.registerModEntity(new ResourceLocation(CloneDetection.MODID, "codecreeper"), EntityCodeCreeper.class, "CodeCreeper", id++, CloneDetection.get(), 64, 3, true, 0x996600, 0x00ff00); 26 | EntityRegistry.registerModEntity(new ResourceLocation(CloneDetection.MODID, "codeskeleton"), EntityCodeSkeleton.class, "CodeSkeleton", id++, CloneDetection.get(), 64, 3, true, 0x996600, 0x00ff00); 27 | EntityRegistry.registerModEntity(new ResourceLocation(CloneDetection.MODID, "codezombie"), EntityCodeZombie.class, "CodeZombie", id++, CloneDetection.get(), 64, 3, true, 0x996600, 0x00ff00); 28 | 29 | // We want our mob to spawn in Plains and ice plains biomes. If you don't add this then it will not spawn automatically 30 | // but you can of course still make it spawn manually 31 | //EntityRegistry.addSpawn(EntityWeirdZombie.class, 100, 3, 5, EnumCreatureType.MONSTER, Biomes.PLAINS, Biomes.ICE_PLAINS); 32 | 33 | // This is the loot table for our mob 34 | //LootTableList.register(EntityWeirdZombie.LOOT); 35 | } 36 | 37 | @SideOnly(Side.CLIENT) 38 | public static void initModels() { 39 | RenderingRegistry.registerEntityRenderingHandler(EntityCodeSpider.class, new CodeSpiderFactory()); 40 | RenderingRegistry.registerEntityRenderingHandler(EntityCodeSkeleton.class, new CodeSkeletonFactory()); 41 | RenderingRegistry.registerEntityRenderingHandler(EntityCodeCreeper.class, new CodeCreeperFactory()); 42 | RenderingRegistry.registerEntityRenderingHandler(EntityCodeZombie.class, new CodeZombieFactory()); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/codearena/minecraft/gui/CloneMenuKey.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.codearena.minecraft.gui; 2 | 3 | import org.lwjgl.input.Keyboard; 4 | 5 | import net.minecraft.client.Minecraft; 6 | import net.minecraft.client.gui.GuiChat; 7 | import net.minecraft.client.settings.KeyBinding; 8 | import net.minecraft.entity.player.EntityPlayer; 9 | import net.minecraft.server.MinecraftServer; 10 | import net.minecraft.world.World; 11 | import net.minecraftforge.common.MinecraftForge; 12 | import net.minecraftforge.fml.client.FMLClientHandler; 13 | import net.minecraftforge.fml.client.registry.ClientRegistry; 14 | import net.minecraftforge.fml.common.FMLCommonHandler; 15 | import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; 16 | import net.minecraftforge.fml.common.gameevent.InputEvent; 17 | import net.minecraftforge.fml.relauncher.Side; 18 | import net.minecraftforge.fml.relauncher.SideOnly; 19 | 20 | public class CloneMenuKey { 21 | 22 | @SideOnly(Side.CLIENT) 23 | public void registerRenderers() { 24 | MinecraftForge.EVENT_BUS.register(new KeyHandler()); 25 | } 26 | 27 | public static class KeyHandler { 28 | 29 | private final KeyBinding keys; 30 | 31 | public KeyHandler() { 32 | keys = new KeyBinding("key.mcreator.clonemenu", Keyboard.KEY_C, "key.categories.misc"); 33 | ClientRegistry.registerKeyBinding(keys); 34 | } 35 | 36 | @SubscribeEvent 37 | public void onKeyInput(InputEvent.KeyInputEvent event) { 38 | if (!FMLClientHandler.instance().isGUIOpen(GuiChat.class)) { 39 | if (org.lwjgl.input.Keyboard.isKeyDown(keys.getKeyCode())) { 40 | EntityPlayer entitySP = Minecraft.getMinecraft().player; 41 | int x = (int) entitySP.posX; 42 | int y = (int) entitySP.posY; 43 | int z = (int) entitySP.posZ; 44 | MinecraftServer server = FMLCommonHandler.instance().getMinecraftServerInstance(); 45 | World world = server.getWorld(entitySP.dimension); 46 | EntityPlayer entity = entitySP; 47 | for (EntityPlayer entityMP : world.playerEntities) 48 | if (entityMP.getName().equals(entitySP.getName())) 49 | entity = entityMP; 50 | OpenCloneGUI.executeProcedure(world, entity, x, y, z); 51 | } 52 | } 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/codearena/minecraft/gui/OpenCloneGUI.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.codearena.minecraft.gui; 2 | 3 | import com.simonbaars.codearena.CloneDetection; 4 | 5 | import net.minecraft.entity.Entity; 6 | import net.minecraft.entity.player.EntityPlayer; 7 | import net.minecraft.world.World; 8 | 9 | public class OpenCloneGUI { 10 | 11 | public static void executeProcedure(World world, Entity entity, int x, int y, int z) { 12 | if (entity instanceof EntityPlayer) { 13 | if(CloneDetection.get().getArena() == null) 14 | ((EntityPlayer) entity).openGui(CloneDetection.get(), GUISetupCloneFinding.GUIID, world, x, y, z); 15 | else ((EntityPlayer) entity).openGui(CloneDetection.get(), EndChallengeGUI.GUIID, world, x, y, z); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/codearena/minecraft/proxy/ClientProxy.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.codearena.minecraft.proxy; 2 | 3 | import com.simonbaars.codearena.CloneDetection; 4 | import com.simonbaars.codearena.minecraft.ModEntities; 5 | 6 | import net.minecraftforge.client.event.ModelRegistryEvent; 7 | import net.minecraftforge.client.model.obj.OBJLoader; 8 | import net.minecraftforge.fml.common.Mod; 9 | import net.minecraftforge.fml.common.event.FMLInitializationEvent; 10 | import net.minecraftforge.fml.common.event.FMLPostInitializationEvent; 11 | import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; 12 | import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; 13 | import net.minecraftforge.fml.relauncher.Side; 14 | 15 | @Mod.EventBusSubscriber(Side.CLIENT) 16 | public class ClientProxy extends CommonProxy { 17 | @Override 18 | public void preInit(FMLPreInitializationEvent e) { 19 | super.preInit(e); 20 | 21 | OBJLoader.INSTANCE.addDomain(CloneDetection.MODID); 22 | 23 | // Typically initialization of models and such goes here: 24 | ModEntities.initModels(); 25 | } 26 | 27 | @Override 28 | public void init(FMLInitializationEvent e) { 29 | super.init(e); 30 | 31 | } 32 | 33 | @Override 34 | public void postInit(FMLPostInitializationEvent e) { 35 | super.postInit(e); 36 | } 37 | 38 | @SubscribeEvent 39 | public static void registerModels(ModelRegistryEvent event) { 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/codearena/minecraft/proxy/CommonProxy.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.codearena.minecraft.proxy; 2 | 3 | import java.io.File; 4 | 5 | import com.simonbaars.codearena.CloneDetection; 6 | import com.simonbaars.codearena.minecraft.ModEntities; 7 | 8 | import net.minecraft.block.Block; 9 | import net.minecraft.item.Item; 10 | import net.minecraftforge.common.config.Configuration; 11 | import net.minecraftforge.event.RegistryEvent; 12 | import net.minecraftforge.fml.common.Mod; 13 | import net.minecraftforge.fml.common.event.FMLInitializationEvent; 14 | import net.minecraftforge.fml.common.event.FMLPostInitializationEvent; 15 | import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; 16 | import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; 17 | import net.minecraftforge.fml.common.network.NetworkRegistry; 18 | 19 | @Mod.EventBusSubscriber 20 | public class CommonProxy { 21 | 22 | // Config instance 23 | public static Configuration config; 24 | 25 | public void preInit(FMLPreInitializationEvent e) { 26 | File directory = e.getModConfigurationDirectory(); 27 | config = new Configuration(new File(directory.getPath(), "modtut.cfg")); 28 | 29 | // Initialization of blocks and items typically goes here: 30 | ModEntities.init(); 31 | 32 | } 33 | 34 | public void init(FMLInitializationEvent e) { 35 | NetworkRegistry.INSTANCE.registerGuiHandler(CloneDetection.get(), new GuiProxy()); 36 | } 37 | 38 | public void postInit(FMLPostInitializationEvent e) { 39 | if (config.hasChanged()) { 40 | config.save(); 41 | } 42 | } 43 | 44 | @SubscribeEvent 45 | public static void registerBlocks(RegistryEvent.Register event) { 46 | } 47 | 48 | @SubscribeEvent 49 | public static void registerItems(RegistryEvent.Register event) { 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/codearena/minecraft/proxy/GuiProxy.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.codearena.minecraft.proxy; 2 | 3 | import net.minecraft.entity.player.EntityPlayer; 4 | import net.minecraft.world.World; 5 | import net.minecraftforge.fml.common.network.IGuiHandler; 6 | 7 | public class GuiProxy implements IGuiHandler { 8 | 9 | @Override 10 | public Object getServerGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z) { 11 | return null; 12 | } 13 | 14 | @Override 15 | public Object getClientGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z) { 16 | return null; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/codearena/minecraft/proxy/ServerProxy.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.codearena.minecraft.proxy; 2 | 3 | public class ServerProxy extends CommonProxy { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/codearena/minecraft/structureloader/BlockPlaceHandler.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.codearena.minecraft.structureloader; 2 | 3 | import com.simonbaars.codearena.CloneDetection; 4 | 5 | import net.minecraft.block.Block; 6 | import net.minecraft.block.state.IBlockState; 7 | import net.minecraft.client.Minecraft; 8 | import net.minecraft.util.math.BlockPos; 9 | import net.minecraft.world.World; 10 | import net.minecraft.world.chunk.Chunk; 11 | import net.minecraft.world.chunk.storage.ExtendedBlockStorage; 12 | 13 | public class BlockPlaceHandler { 14 | public static void placeBlocks(World worldIn, World serverWorld, Block block, int posx, int posy, int posz, int sizex, int sizey, int sizez){ 15 | BlockPos pos; 16 | BlockPlacer blockPlacer = new BlockPlacer(serverWorld,false); 17 | BlockPlacer blockPlacer2 = new BlockPlacer(worldIn,false); 18 | for(int x = 0; x> 4]; 61 | if (storageArray == null) storageArray = chunk.getBlockStorageArray()[pos.getY() >> 4] = new ExtendedBlockStorage(pos.getY() >> 4 << 4, !world.provider.isNether()); 62 | 63 | if (storageArray.get(pos.getX() & 15, pos.getY() & 15, pos.getZ() & 15).getBlock() != state.getBlock()) 64 | { 65 | //IBlockState oldState = world.getBlockState(pos); 66 | storageArray.set(pos.getX() & 15, pos.getY() & 15, pos.getZ() & 15, state); 67 | if(world.isRemote){ 68 | CloneDetection.get().eventHandler.lightUpdate.addClientProcess(pos); 69 | } else { 70 | CloneDetection.get().eventHandler.lightUpdate.addServerProcess(pos); 71 | } 72 | //world.checkLightFor(EnumSkyBlock.SKY, pos); 73 | //world.markBlockForUpdate(pos); 74 | /*if(world.isRemote){ 75 | IMSM.eventHandler.lightUpdate.processes.add(pos); 76 | }*/ 77 | } 78 | } catch (Exception e){ 79 | //e.printStackTrace(); 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/codearena/minecraft/structureloader/LightUpdateCheck.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.codearena.minecraft.structureloader; 2 | 3 | import java.util.ArrayList; 4 | 5 | import net.minecraft.util.math.BlockPos; 6 | import net.minecraft.world.EnumSkyBlock; 7 | import net.minecraft.world.World; 8 | 9 | public class LightUpdateCheck { 10 | private World worldIn; 11 | private World serverWorld; 12 | private ArrayList serverProcesses = new ArrayList(); 13 | public ArrayList clientProcesses = new ArrayList(); 14 | 15 | 16 | public LightUpdateCheck(World worldIn, World serverWorld){ 17 | this.worldIn=worldIn; 18 | this.serverWorld=serverWorld; 19 | } 20 | 21 | public void addClientProcess(BlockPos pos){ 22 | clientProcesses.add(pos); 23 | } 24 | 25 | public void addServerProcess(BlockPos pos){ 26 | serverProcesses.add(pos); 27 | } 28 | 29 | public void runClient() { 30 | for(int i = clientProcesses.size()-1; i>=0; i--){ 31 | if(clientProcesses.get(i)!=null){ 32 | worldIn.checkLightFor(EnumSkyBlock.SKY, clientProcesses.get(i)); 33 | } 34 | clientProcesses.remove(i); 35 | } 36 | } 37 | public void runServer() { 38 | for(int i = serverProcesses.size()-1; i>=0; i--){ 39 | if(serverProcesses.get(i)!=null){ 40 | serverWorld.checkLightFor(EnumSkyBlock.SKY, serverProcesses.get(i)); 41 | } 42 | serverProcesses.remove(i); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/codearena/minecraft/structureloader/OutlineCreator.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.codearena.minecraft.structureloader; 2 | 3 | import com.simonbaars.codearena.minecraft.ICreatorBlock; 4 | 5 | import net.minecraft.util.math.BlockPos; 6 | 7 | public class OutlineCreator implements ICreatorBlock { 8 | SchematicStructure struct; 9 | BlockPos pos; 10 | int modifierx,modifiery,modifierz; 11 | public OutlineCreator(String name, BlockPos pos, int modifierx, int modifiery, int modifierz) { 12 | this.struct = new SchematicStructure(name+".structure"); 13 | struct.readFromFile(); 14 | this.pos=pos; 15 | } 16 | 17 | @Override 18 | public boolean run() { 19 | struct.showOutline(pos.getX(),modifierx, pos.getY(),modifiery, pos.getZ(),modifierz, this); 20 | return true; 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/codearena/minecraft/structureloader/Structure.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.codearena.minecraft.structureloader; 2 | 3 | import java.io.File; 4 | import java.io.FileInputStream; 5 | import java.io.FileNotFoundException; 6 | import java.io.InputStream; 7 | 8 | import net.minecraft.util.math.Vec3d; 9 | import net.minecraft.world.World; 10 | 11 | public class Structure 12 | { 13 | public static final int STRUCTURE_BLOCK_LIMIT = 100000; 14 | 15 | public int length; 16 | public int height; 17 | public int width; 18 | 19 | protected String fileName; 20 | public InputStream fileStream; 21 | protected String blockMode; 22 | protected boolean blockUpdate; 23 | 24 | public Float centerX; 25 | public Float centerY; 26 | public Float centerZ; 27 | protected Vec3d centerPos; 28 | 29 | public Structure(String fileName) 30 | { 31 | this.blockMode = "replace"; 32 | this.blockUpdate = true; 33 | this.fileName = "/structures/"+fileName+".structure"; 34 | //System.out.println("Registered as "+this.fileName); 35 | this.fileStream = Structure.class.getResourceAsStream(this.fileName); 36 | } 37 | 38 | 39 | public Structure(String fileName, boolean useless) 40 | { 41 | this.blockMode = "replace"; 42 | this.blockUpdate = true; 43 | this.fileName = "structures/"+fileName+".structure"; 44 | //System.out.println("Registered as "+this.fileName); 45 | try { 46 | this.fileStream = new FileInputStream(new File(this.fileName)+".structure"); 47 | } catch (FileNotFoundException e) { 48 | // TODO Auto-generated catch block 49 | e.printStackTrace(); 50 | } 51 | } 52 | public void readFromFile() 53 | { 54 | 55 | } 56 | 57 | public void doNotReplaceAir(){ 58 | blockMode="overlay"; 59 | } 60 | 61 | public void process(World serverWorld, World world, int posX, int posY, int posZ) 62 | { 63 | 64 | } 65 | 66 | public Vec3d getCenterPos() 67 | { 68 | return this.centerPos; 69 | } 70 | 71 | protected void initCenterPos() 72 | { 73 | int defaultCenterX = (int) (this.length / 2.0F); 74 | int defaultCenterZ = (int) (this.width / 2.0F); 75 | if (this.centerX == null) this.centerX = defaultCenterX + 0.5F; 76 | if (this.centerY == null) this.centerY = 0.0F; 77 | if (this.centerZ == null) this.centerZ = defaultCenterZ + 0.5F; 78 | this.centerPos = new Vec3d(this.centerX, this.centerY, this.centerZ); 79 | //System.out.println("SIZE STRUCTURE: "+width+", "+height+", "+length); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/codearena/minecraft/structureloader/StructureUtils.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.codearena.minecraft.structureloader; 2 | 3 | import net.minecraft.block.state.IBlockState; 4 | import net.minecraft.entity.Entity; 5 | import net.minecraft.nbt.NBTTagCompound; 6 | import net.minecraft.tileentity.TileEntity; 7 | import net.minecraft.util.math.BlockPos; 8 | import net.minecraft.util.math.Vec3d; 9 | import net.minecraft.world.World; 10 | import net.minecraft.world.chunk.Chunk; 11 | 12 | public class StructureUtils 13 | { 14 | public static BlockPos getWorldPos(BlockPos structPos, BlockPos structCenter, BlockPos harvestPos) 15 | { 16 | return harvestPos.add(structPos).subtract(structCenter); 17 | } 18 | 19 | public static BlockPos getWorldPos(BlockPos structPos, Vec3d structCenter, Vec3d harvestPos) 20 | { 21 | return new BlockPos(getWorldPos(new Vec3d(structPos.getX() + 0.5, structPos.getY(), structPos.getZ() + 0.5), structCenter, harvestPos)); 22 | } 23 | 24 | public static Vec3d getWorldPos(Vec3d structPos, Vec3d structCenter, Vec3d harvestPos) 25 | { 26 | return harvestPos.add(structPos).subtract(structCenter); 27 | } 28 | 29 | public static boolean setBlock(BlockPlacer blockPlacer, IBlockState blockState, BlockPos structPos, Vec3d structCenter, Vec3d harvestPos) 30 | { 31 | return blockPlacer.add(blockState, StructureUtils.getWorldPos(structPos, structCenter, harvestPos)); 32 | } 33 | 34 | public static void setTileEntity(World world, NBTTagCompound tileEntity, BlockPos structPos, Vec3d structCenter, Vec3d harvestPos) 35 | { 36 | BlockPos pos = getWorldPos(structPos, structCenter, harvestPos); 37 | IBlockState blockState = world.getBlockState(pos); 38 | 39 | world.removeTileEntity(pos); 40 | BlockPos chunkPos = new BlockPos(pos.getX() & 15, pos.getY(), pos.getZ() & 15); 41 | TileEntity blockTileEntity = world.getChunkFromBlockCoords(pos).getTileEntity(chunkPos, Chunk.EnumCreateEntityType.CHECK); 42 | 43 | blockTileEntity = blockState.getBlock().createTileEntity(world, blockState); 44 | blockTileEntity.readFromNBT(tileEntity); 45 | blockTileEntity.setPos(pos); 46 | blockTileEntity.setWorld(world); 47 | 48 | world.setTileEntity(pos, blockTileEntity); 49 | blockTileEntity.updateContainingBlockInfo(); 50 | } 51 | 52 | public static void setTileEntity(World world, TileEntity tileEntity, Vec3d structCenter, Vec3d harvestPos) 53 | { 54 | try{ 55 | BlockPos pos = getWorldPos(tileEntity.getPos(), structCenter, harvestPos); 56 | world.removeTileEntity(pos); 57 | tileEntity.setPos(pos); 58 | tileEntity.setWorld(world); 59 | world.setTileEntity(pos, tileEntity); 60 | } catch (ArrayIndexOutOfBoundsException e){ 61 | } 62 | } 63 | 64 | public static void setEntity(World world, Entity entity, Vec3d structCenter, Vec3d harvestPos) 65 | { 66 | Vec3d pos = getWorldPos(entity.getPositionVector(), structCenter, harvestPos); 67 | entity.setPosition(pos.x, pos.y, pos.x); 68 | world.spawnEntity(entity); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/codearena/model/MetricProblem.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.codearena.model; 2 | 3 | import java.util.List; 4 | import java.util.Optional; 5 | 6 | import com.github.javaparser.ast.CompilationUnit; 7 | import com.github.javaparser.ast.PackageDeclaration; 8 | import com.simonbaars.clonerefactor.metrics.ProblemType; 9 | import com.simonbaars.clonerefactor.metrics.enums.RequiresNodeContext; 10 | import com.simonbaars.clonerefactor.model.Sequence; 11 | import com.simonbaars.clonerefactor.model.location.Location; 12 | import com.simonbaars.codearena.editor.CodeEditorMaker; 13 | 14 | import net.minecraft.client.Minecraft; 15 | import net.minecraft.init.Items; 16 | import net.minecraft.item.ItemStack; 17 | 18 | public class MetricProblem implements Comparable, RequiresNodeContext { 19 | 20 | private int problemSize; 21 | private ProblemType type; 22 | private Sequence seq; 23 | private final String packageName; 24 | 25 | public MetricProblem(ProblemType problem, int problemSize, Sequence seq) { 26 | super(); 27 | this.type = problem; 28 | this.problemSize = problemSize; 29 | this.seq = seq; 30 | this.packageName = calcPackage(); 31 | Items.DIAMOND.setMaxStackSize(Integer.MAX_VALUE); 32 | ItemStack itemStackIn = new ItemStack(Items.DIAMOND, 1); 33 | itemStackIn.setStackDisplayName(this.packageName); 34 | Minecraft.getMinecraft().player.inventory.addItemStackToInventory(itemStackIn); 35 | Minecraft.getMinecraft().player.inventoryContainer.detectAndSendChanges(); 36 | } 37 | 38 | public int getProblemSize() { 39 | return problemSize; 40 | } 41 | 42 | public void setProblemSize(int lines) { 43 | this.problemSize = lines; 44 | } 45 | 46 | public List getLocations() { 47 | return seq.getSequence(); 48 | } 49 | 50 | @Override 51 | public int compareTo(MetricProblem o) { 52 | return Integer.compare(volume(), o.volume()); 53 | } 54 | 55 | public void add(Location construct) { 56 | seq.add(construct); 57 | } 58 | 59 | public int size() { 60 | return seq.size(); 61 | } 62 | 63 | public Location get(int j) { 64 | return seq.getSequence().get(j); 65 | } 66 | 67 | public int volume() { 68 | return problemSize; 69 | } 70 | 71 | public void open() { 72 | CodeEditorMaker.create(this); 73 | } 74 | 75 | public String getName() { 76 | if(size() == 0) 77 | return "error"; 78 | return get(0).getName(); 79 | } 80 | 81 | public String calcPackage() { 82 | if(size() == 0) 83 | return "error"; 84 | CompilationUnit compilationUnit = getCompilationUnit(get(0).getContents().getNodes().get(0)); 85 | if(compilationUnit != null){ 86 | Optional p = compilationUnit.getPackageDeclaration(); 87 | if(p.isPresent()) 88 | return p.get().getNameAsString(); 89 | } 90 | return "No package"; 91 | } 92 | 93 | public String getMetric() { 94 | return type.getName(); 95 | } 96 | 97 | public ProblemType getType() { 98 | return type; 99 | } 100 | 101 | public void setType(ProblemType type) { 102 | this.type = type; 103 | } 104 | 105 | public Sequence getSeq() { 106 | return seq; 107 | } 108 | 109 | public void setSeq(Sequence seq) { 110 | this.seq = seq; 111 | } 112 | 113 | public String getPackage() { 114 | return packageName; 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/codearena/model/ProblemScore.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.codearena.model; 2 | 3 | import com.simonbaars.clonerefactor.metrics.ProblemType; 4 | 5 | import net.minecraft.scoreboard.Score; 6 | import net.minecraft.scoreboard.ScoreObjective; 7 | 8 | public class ProblemScore { 9 | private Score score; 10 | private int scorePoints = 0; 11 | private final ProblemType type; 12 | 13 | public ProblemScore (ProblemType type) { 14 | this.score = null; 15 | this.type = type; 16 | } 17 | 18 | public ProblemScore (ProblemType type, Score score) { 19 | this.score = score; 20 | this.type = type; 21 | } 22 | 23 | public synchronized void increaseScore(int s) { 24 | scorePoints+=s; 25 | if(score != null) score.increaseScore(s); 26 | } 27 | 28 | public synchronized void incrementScore() { 29 | scorePoints++; 30 | if(score != null) score.incrementScore(); 31 | } 32 | 33 | public int getScorePoints() { 34 | return scorePoints; 35 | } 36 | 37 | public synchronized void setScorePoints(int scorePoints) { 38 | this.scorePoints = scorePoints; 39 | if(score != null) score.setScorePoints(scorePoints); 40 | } 41 | 42 | public Score getScore() { 43 | return score; 44 | } 45 | 46 | public void setScore(Score score) { 47 | this.score = score; 48 | this.score.setScorePoints(0); 49 | } 50 | 51 | public String getName() { 52 | return type.getName(); 53 | } 54 | 55 | @Override 56 | public String toString() { 57 | return "CloneScore [score=" + scorePoints + "]"; 58 | } 59 | 60 | public void setScore(ScoreObjective scoreBoard) { 61 | setScore(scoreBoard.getScoreboard().getOrCreateScore(getName(), scoreBoard)); 62 | } 63 | 64 | public ProblemType getType() { 65 | return type; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/codearena/monster/CodeEntity.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.codearena.monster; 2 | 3 | import com.simonbaars.codearena.model.MetricProblem; 4 | 5 | import net.minecraft.entity.monster.EntityMob; 6 | import net.minecraft.entity.player.EntityPlayer; 7 | import net.minecraft.util.DamageSource; 8 | import net.minecraft.world.World; 9 | 10 | public abstract class CodeEntity extends EntityMob { 11 | 12 | MetricProblem represents; 13 | private boolean isServer = false; 14 | 15 | public CodeEntity(World world, MetricProblem cloneClass) { 16 | super(world); 17 | this.represents = cloneClass; 18 | //float f = 0.03F*cloneClass.volume(); 19 | //double boundingX = getEntityBoundingBox().maxX-getEntityBoundingBox().minX*3; 20 | //double boundingY = getEntityBoundingBox().maxY-getEntityBoundingBox().minY/2; 21 | //double boundingZ = getEntityBoundingBox().maxZ-getEntityBoundingBox().minZ*3; 22 | //Vec3d center = getEntityBoundingBox().getCenter(); 23 | 24 | //this.setEntityBoundingBox(new AxisAlignedBB(center.x-((boundingX/2)*f), center.y-((boundingY/2)*f), center.z-((boundingZ/2)*f), center.x+((boundingX/2)*f), center.y+((boundingY/2)*f), center.z+((boundingZ/2)*f))); 25 | //this.setSize(1.5F*f, 0.5F*f); 26 | this.isServer = true; 27 | this.setHealth(Float.MAX_VALUE); 28 | this.setAlwaysRenderNameTag(true); 29 | this.setCustomNameTag(cloneClass.getName()); 30 | this.ignoreFrustumCheck = true; 31 | } 32 | 33 | public CodeEntity(World worldIn) { 34 | super(worldIn); 35 | } 36 | 37 | public void setSizePublic(float w, float h) { 38 | this.setSize(w, h); 39 | } 40 | 41 | @Override 42 | public boolean attackEntityFrom(DamageSource source, float amount){ 43 | if(isServer && represents != null && source.getTrueSource() instanceof EntityPlayer) //{ 44 | represents.open(); 45 | //setDead(); 46 | //} 47 | return super.attackEntityFrom(source, amount); 48 | } 49 | 50 | public MetricProblem getRepresents() { 51 | return represents; 52 | } 53 | 54 | public void setRepresents(MetricProblem represents) { 55 | this.represents = represents; 56 | } 57 | 58 | /*@Override 59 | public void setPosition(double par1, double par2, double par3) { 60 | AxisAlignedBB b = this.getEntityBoundingBox(); 61 | double boxSX = b.maxX - b.minX; 62 | double boxSY = b.maxY - b.minY; 63 | double boxSZ = b.maxZ - b.minZ; 64 | this.setEntityBoundingBox(new AxisAlignedBB(posX - boxSX/2D, posY, posZ - boxSZ/2D, posX + boxSX/2D, posY + boxSY, posZ + boxSZ/2D)); 65 | }*/ 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/codearena/monster/UsesCustomScaleFactors.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.codearena.monster; 2 | 3 | import com.simonbaars.codearena.model.MetricProblem; 4 | import com.simonbaars.codearena.monster.codecreeper.EntityCodeCreeper; 5 | import com.simonbaars.codearena.monster.codeskeleton.AbstractCodeSkeleton; 6 | import com.simonbaars.codearena.monster.codespider.EntityCodeSpider; 7 | import com.simonbaars.codearena.monster.codezombie.EntityCodeZombie; 8 | 9 | public interface UsesCustomScaleFactors { 10 | 11 | public default float getScaleFactor(CodeEntity codeEntity, MetricProblem p) { 12 | if(codeEntity instanceof EntityCodeSpider) { //Code clones 13 | return checkF(p.volume()*0.03F); 14 | } else if(codeEntity instanceof AbstractCodeSkeleton) { // Unit interface size 15 | return checkF(((p.volume()*2)+4)*0.03F); 16 | } else if(codeEntity instanceof EntityCodeCreeper) { // Unit volume 17 | return checkF(((p.volume()/1.5F)-5)*0.03F); 18 | } else if(codeEntity instanceof EntityCodeZombie) { // Unit complexity 19 | return checkF((p.volume()-5)*0.03F); 20 | } 21 | return 1F; 22 | } 23 | 24 | public default float getScaleFactor(CodeEntity codeEntity) { 25 | return getScaleFactor(codeEntity, codeEntity.getRepresents()); 26 | } 27 | 28 | public default float checkF(float f) { 29 | if(f>4.0F) 30 | f = 4.0F; 31 | return 0.4F+f; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/codearena/monster/codecreeper/CodeCreeperFactory.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.codearena.monster.codecreeper; 2 | 3 | import net.minecraft.client.renderer.entity.Render; 4 | import net.minecraft.client.renderer.entity.RenderManager; 5 | import net.minecraftforge.fml.client.registry.IRenderFactory; 6 | 7 | public class CodeCreeperFactory implements IRenderFactory { 8 | 9 | @Override 10 | public Render createRenderFor(RenderManager manager) { 11 | return new RenderCodeCreeper(manager); 12 | } 13 | 14 | } 15 | 16 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/codearena/monster/codecreeper/RenderCodeCreeper.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.codearena.monster.codecreeper; 2 | 3 | import com.simonbaars.codearena.CloneDetection; 4 | import com.simonbaars.codearena.challenge.CodeArena; 5 | import com.simonbaars.codearena.model.MetricProblem; 6 | import com.simonbaars.codearena.monster.UsesCustomScaleFactors; 7 | 8 | import net.minecraft.client.model.ModelCreeper; 9 | import net.minecraft.client.renderer.GlStateManager; 10 | import net.minecraft.client.renderer.entity.RenderLiving; 11 | import net.minecraft.client.renderer.entity.RenderManager; 12 | import net.minecraft.client.renderer.entity.layers.LayerCreeperCharge; 13 | import net.minecraft.entity.monster.EntityCreeper; 14 | import net.minecraft.util.ResourceLocation; 15 | import net.minecraft.util.math.MathHelper; 16 | import net.minecraftforge.fml.relauncher.Side; 17 | import net.minecraftforge.fml.relauncher.SideOnly; 18 | 19 | @SideOnly(Side.CLIENT) 20 | public class RenderCodeCreeper extends RenderLiving implements UsesCustomScaleFactors 21 | { 22 | private static final ResourceLocation CREEPER_TEXTURES = new ResourceLocation("textures/entity/creeper/creeper.png"); 23 | 24 | public RenderCodeCreeper(RenderManager renderManagerIn) 25 | { 26 | super(renderManagerIn, new ModelCreeper(), 0.5F); 27 | //this.addLayer(new LayerCreeperCharge(this)); 28 | } 29 | 30 | /** 31 | * Allows the render to do state modifications necessary before the model is rendered. 32 | 33 | protected void preRenderCallback(EntityCodeCreeper entitylivingbaseIn, float partialTickTime) 34 | { 35 | float f = entitylivingbaseIn.getCreeperFlashIntensity(partialTickTime); 36 | float f1 = 1.0F + MathHelper.sin(f * 100.0F) * f * 0.01F; 37 | f = MathHelper.clamp(f, 0.0F, 1.0F); 38 | f = f * f; 39 | f = f * f; 40 | float f2 = (1.0F + f * 0.4F) * f1; 41 | float f3 = (1.0F + f * 0.1F) / f1; 42 | GlStateManager.scale(f2, f3, f2); 43 | }*/ 44 | 45 | /** 46 | * Gets an RGBA int color multiplier to apply. 47 | */ 48 | protected int getColorMultiplier(EntityCodeCreeper entitylivingbaseIn, float lightBrightness, float partialTickTime) 49 | { 50 | float f = entitylivingbaseIn.getCreeperFlashIntensity(partialTickTime); 51 | 52 | if ((int)(f * 10.0F) % 2 == 0) 53 | { 54 | return 0; 55 | } 56 | else 57 | { 58 | int i = (int)(f * 0.2F * 255.0F); 59 | i = MathHelper.clamp(i, 0, 255); 60 | return i << 24 | 822083583; 61 | } 62 | } 63 | 64 | /** 65 | * Returns the location of an entity's texture. Doesn't seem to be called unless you call Render.bindEntityTexture. 66 | */ 67 | protected ResourceLocation getEntityTexture(EntityCodeCreeper entity) 68 | { 69 | return CREEPER_TEXTURES; 70 | } 71 | 72 | @Override 73 | protected void preRenderCallback(EntityCodeCreeper entitylivingbaseIn, float partialTickTime) 74 | { 75 | MetricProblem c = entitylivingbaseIn.getRepresents(); 76 | if(c == null) { 77 | CodeArena arena = CloneDetection.get().getArena(); 78 | if(arena == null) 79 | return; 80 | 81 | c = arena.findEntity(entitylivingbaseIn); 82 | 83 | if(c == null) 84 | return; 85 | } 86 | float scale = getScaleFactor(entitylivingbaseIn, c); 87 | 88 | GlStateManager.scale(scale, scale, scale); 89 | //System.out.println("Scaled by "+entitylivingbaseIn.getScaleFactor()+" because of "+entitylivingbaseIn.getCustomNameTag()+", "+entitylivingbaseIn.getHealth()+", "+entitylivingbaseIn.getAbsorptionAmount()); 90 | } 91 | } -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/codearena/monster/codeskeleton/CodeSkeletonFactory.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.codearena.monster.codeskeleton; 2 | 3 | import net.minecraft.client.renderer.entity.Render; 4 | import net.minecraft.client.renderer.entity.RenderManager; 5 | import net.minecraftforge.fml.client.registry.IRenderFactory; 6 | 7 | public class CodeSkeletonFactory implements IRenderFactory { 8 | 9 | @Override 10 | public Render createRenderFor(RenderManager manager) { 11 | return new RenderCodeSkeleton(manager); 12 | } 13 | 14 | } 15 | 16 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/codearena/monster/codeskeleton/EntityCodeSkeleton.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.codearena.monster.codeskeleton; 2 | 3 | import javax.annotation.Nullable; 4 | 5 | import com.simonbaars.codearena.model.MetricProblem; 6 | 7 | import net.minecraft.entity.EntityLiving; 8 | import net.minecraft.entity.projectile.EntityArrow; 9 | import net.minecraft.entity.projectile.EntitySpectralArrow; 10 | import net.minecraft.entity.projectile.EntityTippedArrow; 11 | import net.minecraft.init.Items; 12 | import net.minecraft.init.SoundEvents; 13 | import net.minecraft.inventory.EntityEquipmentSlot; 14 | import net.minecraft.item.ItemStack; 15 | import net.minecraft.util.DamageSource; 16 | import net.minecraft.util.ResourceLocation; 17 | import net.minecraft.util.SoundEvent; 18 | import net.minecraft.util.datafix.DataFixer; 19 | import net.minecraft.world.World; 20 | import net.minecraft.world.storage.loot.LootTableList; 21 | 22 | public class EntityCodeSkeleton extends AbstractCodeSkeleton 23 | { 24 | public EntityCodeSkeleton(World worldIn) 25 | { 26 | super(worldIn); 27 | } 28 | 29 | public EntityCodeSkeleton(World world, MetricProblem cloneClass) { 30 | super(world, cloneClass); 31 | } 32 | 33 | public static void registerFixesSkeleton(DataFixer fixer) 34 | { 35 | EntityLiving.registerFixesMob(fixer, EntityCodeSkeleton.class); 36 | } 37 | 38 | @Nullable 39 | protected ResourceLocation getLootTable() 40 | { 41 | return LootTableList.ENTITIES_SKELETON; 42 | } 43 | 44 | protected SoundEvent getAmbientSound() 45 | { 46 | return SoundEvents.ENTITY_SKELETON_AMBIENT; 47 | } 48 | 49 | protected SoundEvent getHurtSound(DamageSource damageSourceIn) 50 | { 51 | return SoundEvents.ENTITY_SKELETON_HURT; 52 | } 53 | 54 | protected SoundEvent getDeathSound() 55 | { 56 | return SoundEvents.ENTITY_SKELETON_DEATH; 57 | } 58 | 59 | protected SoundEvent getStepSound() 60 | { 61 | return SoundEvents.ENTITY_SKELETON_STEP; 62 | } 63 | 64 | /** 65 | * Called when the mob's health reaches 0. 66 | */ 67 | public void onDeath(DamageSource cause) 68 | { 69 | super.onDeath(cause); 70 | } 71 | 72 | protected EntityArrow getArrow(float p_190726_1_) 73 | { 74 | ItemStack itemstack = this.getItemStackFromSlot(EntityEquipmentSlot.OFFHAND); 75 | 76 | if (itemstack.getItem() == Items.SPECTRAL_ARROW) 77 | { 78 | EntitySpectralArrow entityspectralarrow = new EntitySpectralArrow(this.world, this); 79 | entityspectralarrow.setEnchantmentEffectsFromEntity(this, p_190726_1_); 80 | return entityspectralarrow; 81 | } 82 | else 83 | { 84 | EntityArrow entityarrow = super.getArrow(p_190726_1_); 85 | 86 | if (itemstack.getItem() == Items.TIPPED_ARROW && entityarrow instanceof EntityTippedArrow) 87 | { 88 | ((EntityTippedArrow)entityarrow).setPotionEffect(itemstack); 89 | } 90 | 91 | return entityarrow; 92 | } 93 | } 94 | } -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/codearena/monster/codeskeleton/RenderCodeSkeleton.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.codearena.monster.codeskeleton; 2 | 3 | import com.simonbaars.codearena.CloneDetection; 4 | import com.simonbaars.codearena.challenge.CodeArena; 5 | import com.simonbaars.codearena.model.MetricProblem; 6 | import com.simonbaars.codearena.monster.UsesCustomScaleFactors; 7 | 8 | import net.minecraft.client.renderer.GlStateManager; 9 | import net.minecraft.client.renderer.entity.RenderBiped; 10 | import net.minecraft.client.renderer.entity.RenderManager; 11 | import net.minecraft.client.renderer.entity.layers.LayerBipedArmor; 12 | import net.minecraft.client.renderer.entity.layers.LayerHeldItem; 13 | import net.minecraft.util.ResourceLocation; 14 | import net.minecraftforge.fml.relauncher.Side; 15 | import net.minecraftforge.fml.relauncher.SideOnly; 16 | 17 | @SideOnly(Side.CLIENT) 18 | public class RenderCodeSkeleton extends RenderBiped implements UsesCustomScaleFactors 19 | { 20 | private static final ResourceLocation SKELETON_TEXTURES = new ResourceLocation("textures/entity/skeleton/skeleton.png"); 21 | 22 | public RenderCodeSkeleton(RenderManager renderManagerIn) 23 | { 24 | super(renderManagerIn, new ModelCodeSkeleton(), 0.5F); 25 | this.addLayer(new LayerHeldItem(this)); 26 | this.addLayer(new LayerBipedArmor(this) 27 | { 28 | protected void initArmor() 29 | { 30 | this.modelLeggings = new ModelCodeSkeleton(0.5F, true); 31 | this.modelArmor = new ModelCodeSkeleton(1.0F, true); 32 | } 33 | }); 34 | } 35 | 36 | public void transformHeldFull3DItemLayer() 37 | { 38 | GlStateManager.translate(0.09375F, 0.1875F, 0.0F); 39 | } 40 | 41 | /** 42 | * Returns the location of an entity's texture. Doesn't seem to be called unless you call Render.bindEntityTexture. 43 | */ 44 | protected ResourceLocation getEntityTexture(AbstractCodeSkeleton entity) 45 | { 46 | return SKELETON_TEXTURES; 47 | } 48 | 49 | @Override 50 | protected void preRenderCallback(AbstractCodeSkeleton entitylivingbaseIn, float partialTickTime) 51 | { 52 | MetricProblem c = entitylivingbaseIn.getRepresents(); 53 | if(c == null) { 54 | CodeArena arena = CloneDetection.get().getArena(); 55 | if(arena == null) 56 | return; 57 | 58 | c = arena.findEntity(entitylivingbaseIn); 59 | 60 | if(c == null) 61 | return; 62 | } 63 | float scale = getScaleFactor(entitylivingbaseIn, c); 64 | 65 | GlStateManager.scale(scale, scale, scale); 66 | //System.out.println("Scaled by "+entitylivingbaseIn.getScaleFactor()+" because of "+entitylivingbaseIn.getCustomNameTag()+", "+entitylivingbaseIn.getHealth()+", "+entitylivingbaseIn.getAbsorptionAmount()); 67 | } 68 | } -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/codearena/monster/codespider/CodeSpiderFactory.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.codearena.monster.codespider; 2 | 3 | import net.minecraft.client.renderer.entity.Render; 4 | import net.minecraft.client.renderer.entity.RenderManager; 5 | import net.minecraftforge.fml.client.registry.IRenderFactory; 6 | 7 | public class CodeSpiderFactory implements IRenderFactory { 8 | 9 | @Override 10 | public Render createRenderFor(RenderManager manager) { 11 | return new RenderCodeSpider<>(manager); 12 | } 13 | 14 | } 15 | 16 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/codearena/monster/codespider/LayerCodeSpiderEyes.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.codearena.monster.codespider; 2 | 3 | import net.minecraft.client.Minecraft; 4 | import net.minecraft.client.renderer.GlStateManager; 5 | import net.minecraft.client.renderer.OpenGlHelper; 6 | import net.minecraft.client.renderer.entity.layers.LayerRenderer; 7 | import net.minecraft.util.ResourceLocation; 8 | import net.minecraftforge.fml.relauncher.Side; 9 | import net.minecraftforge.fml.relauncher.SideOnly; 10 | 11 | @SideOnly(Side.CLIENT) 12 | public class LayerCodeSpiderEyes implements LayerRenderer 13 | { 14 | private static final ResourceLocation SPIDER_EYES = new ResourceLocation("textures/entity/spider_eyes.png"); 15 | private final RenderCodeSpider spiderRenderer; 16 | 17 | public LayerCodeSpiderEyes(RenderCodeSpider spiderRendererIn) 18 | { 19 | this.spiderRenderer = spiderRendererIn; 20 | } 21 | 22 | public void doRenderLayer(T entitylivingbaseIn, float limbSwing, float limbSwingAmount, float partialTicks, float ageInTicks, float netHeadYaw, float headPitch, float scale) 23 | { 24 | this.spiderRenderer.bindTexture(SPIDER_EYES); 25 | GlStateManager.enableBlend(); 26 | GlStateManager.disableAlpha(); 27 | /*GlStateManager.blendFunc(GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ONE); 28 | 29 | if (entitylivingbaseIn.isInvisible()) 30 | { 31 | GlStateManager.depthMask(false); 32 | } 33 | else 34 | { 35 | GlStateManager.depthMask(true); 36 | } 37 | 38 | int i = 61680; 39 | int j = i % 65536; 40 | int k = i / 65536; 41 | OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, (float)j, (float)k); 42 | GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); 43 | Minecraft.getMinecraft().entityRenderer.setupFogColor(true); 44 | this.spiderRenderer.getMainModel().render(entitylivingbaseIn, limbSwing, limbSwingAmount, ageInTicks, netHeadYaw, headPitch, scale); 45 | Minecraft.getMinecraft().entityRenderer.setupFogColor(false); 46 | i = entitylivingbaseIn.getBrightnessForRender(); 47 | j = i % 65536; 48 | k = i / 65536; 49 | OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, (float)j, (float)k); 50 | this.spiderRenderer.setLightmap(entitylivingbaseIn);*/ 51 | GlStateManager.disableBlend(); 52 | GlStateManager.enableAlpha(); 53 | } 54 | 55 | public boolean shouldCombineTextures() 56 | { 57 | return false; 58 | } 59 | } -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/codearena/monster/codespider/RenderCodeSpider.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.codearena.monster.codespider; 2 | 3 | import com.simonbaars.codearena.CloneDetection; 4 | import com.simonbaars.codearena.challenge.CodeArena; 5 | import com.simonbaars.codearena.model.MetricProblem; 6 | import com.simonbaars.codearena.monster.UsesCustomScaleFactors; 7 | 8 | import net.minecraft.client.model.ModelSpider; 9 | import net.minecraft.client.renderer.GlStateManager; 10 | import net.minecraft.client.renderer.entity.RenderLiving; 11 | import net.minecraft.client.renderer.entity.RenderManager; 12 | import net.minecraft.util.ResourceLocation; 13 | import net.minecraftforge.fml.relauncher.Side; 14 | import net.minecraftforge.fml.relauncher.SideOnly; 15 | 16 | @SideOnly(Side.CLIENT) 17 | public class RenderCodeSpider extends RenderLiving implements UsesCustomScaleFactors 18 | { 19 | private static final ResourceLocation SPIDER_TEXTURES = new ResourceLocation("textures/entity/spider/spider.png"); 20 | 21 | public RenderCodeSpider(RenderManager renderManagerIn) 22 | { 23 | super(renderManagerIn, new ModelSpider(), 1.0F); 24 | this.addLayer(new LayerCodeSpiderEyes(this)); 25 | } 26 | 27 | protected float getDeathMaxRotation(T entityLivingBaseIn) 28 | { 29 | return 180.0F; 30 | } 31 | 32 | @Override 33 | protected void preRenderCallback(T entitylivingbaseIn, float partialTickTime) 34 | { 35 | MetricProblem c = entitylivingbaseIn.getRepresents(); 36 | if(c == null) { 37 | CodeArena arena = CloneDetection.get().getArena(); 38 | if(arena == null) 39 | return; 40 | 41 | c = arena.findEntity(entitylivingbaseIn); 42 | 43 | if(c == null) 44 | return; 45 | } 46 | float scale = getScaleFactor(entitylivingbaseIn, c); 47 | 48 | GlStateManager.scale(scale, scale, scale); 49 | //System.out.println("Scaled by "+entitylivingbaseIn.getScaleFactor()+" because of "+entitylivingbaseIn.getCustomNameTag()+", "+entitylivingbaseIn.getHealth()+", "+entitylivingbaseIn.getAbsorptionAmount()); 50 | } 51 | 52 | 53 | @Override 54 | public void doRender(T entity, double x, double y, double z, float entityYaw, float partialTicks){ 55 | /*GlStateManager.pushMatrix(); 56 | GlStateManager.disableCull(); 57 | GlStateManager.enableRescaleNormal(); 58 | GlStateManager.scale(entity.getScaleFactor(), entity.getScaleFactor(), entity.getScaleFactor()); 59 | GlStateManager.disableRescaleNormal(); 60 | GlStateManager.enableCull(); 61 | GlStateManager.popMatrix();*/ 62 | super.doRender(entity, x, y, z, entityYaw, partialTicks); 63 | } 64 | 65 | /** 66 | * Returns the location of an entity's texture. Doesn't seem to be called unless you call Render.bindEntityTexture. 67 | */ 68 | protected ResourceLocation getEntityTexture(T entity) 69 | { 70 | return SPIDER_TEXTURES; 71 | } 72 | } -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/codearena/monster/codezombie/CodeZombieFactory.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.codearena.monster.codezombie; 2 | 3 | import net.minecraft.client.renderer.entity.Render; 4 | import net.minecraft.client.renderer.entity.RenderManager; 5 | import net.minecraftforge.fml.client.registry.IRenderFactory; 6 | 7 | public class CodeZombieFactory implements IRenderFactory { 8 | 9 | @Override 10 | public Render createRenderFor(RenderManager manager) { 11 | return new RenderCodeZombie(manager); 12 | } 13 | 14 | } 15 | 16 | -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/codearena/monster/codezombie/RenderCodeZombie.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.codearena.monster.codezombie; 2 | 3 | import com.simonbaars.codearena.CloneDetection; 4 | import com.simonbaars.codearena.challenge.CodeArena; 5 | import com.simonbaars.codearena.model.MetricProblem; 6 | import com.simonbaars.codearena.monster.UsesCustomScaleFactors; 7 | 8 | import net.minecraft.client.model.ModelZombie; 9 | import net.minecraft.client.renderer.GlStateManager; 10 | import net.minecraft.client.renderer.entity.RenderBiped; 11 | import net.minecraft.client.renderer.entity.RenderManager; 12 | import net.minecraft.client.renderer.entity.layers.LayerBipedArmor; 13 | import net.minecraft.entity.monster.EntityZombie; 14 | import net.minecraft.util.ResourceLocation; 15 | import net.minecraftforge.fml.relauncher.Side; 16 | import net.minecraftforge.fml.relauncher.SideOnly; 17 | 18 | @SideOnly(Side.CLIENT) 19 | public class RenderCodeZombie extends RenderBiped implements UsesCustomScaleFactors 20 | { 21 | private static final ResourceLocation ZOMBIE_TEXTURES = new ResourceLocation("textures/entity/zombie/zombie.png"); 22 | 23 | public RenderCodeZombie(RenderManager renderManagerIn) 24 | { 25 | super(renderManagerIn, new ModelZombie(), 0.5F); 26 | LayerBipedArmor layerbipedarmor = new LayerBipedArmor(this) 27 | { 28 | protected void initArmor() 29 | { 30 | this.modelLeggings = new ModelZombie(0.5F, true); 31 | this.modelArmor = new ModelZombie(1.0F, true); 32 | } 33 | }; 34 | this.addLayer(layerbipedarmor); 35 | } 36 | 37 | /** 38 | * Returns the location of an entity's texture. Doesn't seem to be called unless you call Render.bindEntityTexture. 39 | */ 40 | protected ResourceLocation getEntityTexture(EntityCodeZombie entity) 41 | { 42 | return ZOMBIE_TEXTURES; 43 | } 44 | 45 | @Override 46 | protected void preRenderCallback(EntityCodeZombie entitylivingbaseIn, float partialTickTime) 47 | { 48 | MetricProblem c = entitylivingbaseIn.getRepresents(); 49 | if(c == null) { 50 | CodeArena arena = CloneDetection.get().getArena(); 51 | if(arena == null) 52 | return; 53 | 54 | c = arena.findEntity(entitylivingbaseIn); 55 | 56 | if(c == null) 57 | return; 58 | } 59 | float scale = getScaleFactor(entitylivingbaseIn, c); 60 | 61 | GlStateManager.scale(scale, scale, scale); 62 | //System.out.println("Scaled by "+entitylivingbaseIn.getScaleFactor()+" because of "+entitylivingbaseIn.getCustomNameTag()+", "+entitylivingbaseIn.getHealth()+", "+entitylivingbaseIn.getAbsorptionAmount()); 63 | } 64 | } -------------------------------------------------------------------------------- /src/main/java/com/simonbaars/codearena/thread/ProblemDetectionGoal.java: -------------------------------------------------------------------------------- 1 | package com.simonbaars.codearena.thread; 2 | 3 | public enum ProblemDetectionGoal { 4 | DETECTION, SCANBEFORE, SCANAFTER 5 | } 6 | -------------------------------------------------------------------------------- /src/main/resources/assets/clonedetection/lang/en_us.lang: -------------------------------------------------------------------------------- 1 | item.crossmark.name=Not Checked 2 | advancements.loadproject.title=Fixed Clone 3 | key.mcreator.clonemenu=CloneGUIOpen 4 | advancements.loadproject.descr=First time you fixed a clone! 5 | item.checkmark.name=Checked 6 | -------------------------------------------------------------------------------- /src/main/resources/assets/clonedetection/models/item/checkmark.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "items/checkbox" 5 | } 6 | } -------------------------------------------------------------------------------- /src/main/resources/assets/clonedetection/models/item/crossmark.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "items/cross" 5 | } 6 | } -------------------------------------------------------------------------------- /src/main/resources/assets/clonedetection/sounds.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /src/main/resources/assets/minecraft/endchallenge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimonBaars/CodeArena/bc0c6bf90fd19ccc0f0f11c6b37f8c3163b16c4b/src/main/resources/assets/minecraft/endchallenge.png -------------------------------------------------------------------------------- /src/main/resources/assets/minecraft/setupclonefinding.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimonBaars/CodeArena/bc0c6bf90fd19ccc0f0f11c6b37f8c3163b16c4b/src/main/resources/assets/minecraft/setupclonefinding.png -------------------------------------------------------------------------------- /src/main/resources/assets/minecraft/setupclonefinding.png~: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimonBaars/CodeArena/bc0c6bf90fd19ccc0f0f11c6b37f8c3163b16c4b/src/main/resources/assets/minecraft/setupclonefinding.png~ -------------------------------------------------------------------------------- /src/main/resources/assets/minecraft/textures/items/checkbox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimonBaars/CodeArena/bc0c6bf90fd19ccc0f0f11c6b37f8c3163b16c4b/src/main/resources/assets/minecraft/textures/items/checkbox.png -------------------------------------------------------------------------------- /src/main/resources/assets/minecraft/textures/items/cross.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimonBaars/CodeArena/bc0c6bf90fd19ccc0f0f11c6b37f8c3163b16c4b/src/main/resources/assets/minecraft/textures/items/cross.png -------------------------------------------------------------------------------- /src/main/resources/clonerefactor.properties: -------------------------------------------------------------------------------- 1 | clone_type=TYPE1 2 | scope=ALL 3 | 4 | min_statements=5 5 | min_tokens=1 6 | min_lines=1 7 | 8 | use_literature_type_definitions=true 9 | 10 | max_type2_variability_percentage=10.0% 11 | max_type3_gap_size=10.0% 12 | 13 | max_cc=6 14 | max_methodlines=15 15 | max_interface_parameters=4 -------------------------------------------------------------------------------- /src/main/resources/mcmod.info: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "modid": "clonedetection", 4 | "name": "Clone Detection", 5 | "description": "Clone Detection Minecraft mod.", 6 | "version": "${version}", 7 | "mcversion": "${mcversion}", 8 | "url": "", 9 | "updateUrl": "", 10 | "authorList": ["Sander", "Simon"], 11 | "credits": "University of Amsterdam", 12 | "logoFile": "", 13 | "screenshots": [], 14 | "dependencies": [] 15 | } 16 | ] 17 | -------------------------------------------------------------------------------- /src/main/resources/mobs/spider.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimonBaars/CodeArena/bc0c6bf90fd19ccc0f0f11c6b37f8c3163b16c4b/src/main/resources/mobs/spider.png -------------------------------------------------------------------------------- /src/main/resources/mobs/spider_eyes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimonBaars/CodeArena/bc0c6bf90fd19ccc0f0f11c6b37f8c3163b16c4b/src/main/resources/mobs/spider_eyes.png -------------------------------------------------------------------------------- /src/main/resources/pack.mcmeta: -------------------------------------------------------------------------------- 1 | { 2 | "pack": { 3 | "description": "clonedetection resources", 4 | "pack_format": 3, 5 | "_comment": "A pack_format of 3 should be used starting with Minecraft 1.11. All resources, including language files, should be lowercase (eg: en_us.lang). A pack_format of 2 will load your mod resources with LegacyV2Adapter, which requires language files to have uppercase letters (eg: en_US.lang)." 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/main/resources/structures/arena.structure: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimonBaars/CodeArena/bc0c6bf90fd19ccc0f0f11c6b37f8c3163b16c4b/src/main/resources/structures/arena.structure -------------------------------------------------------------------------------- /src/main/resources/structures/arenacheck.structure: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimonBaars/CodeArena/bc0c6bf90fd19ccc0f0f11c6b37f8c3163b16c4b/src/main/resources/structures/arenacheck.structure -------------------------------------------------------------------------------- /src/main/resources/structures/coliseum.structure: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimonBaars/CodeArena/bc0c6bf90fd19ccc0f0f11c6b37f8c3163b16c4b/src/main/resources/structures/coliseum.structure -------------------------------------------------------------------------------- /src/main/resources/structures/colloseum.structure: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimonBaars/CodeArena/bc0c6bf90fd19ccc0f0f11c6b37f8c3163b16c4b/src/main/resources/structures/colloseum.structure -------------------------------------------------------------------------------- /src/main/resources/structures/watchtower.structure: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimonBaars/CodeArena/bc0c6bf90fd19ccc0f0f11c6b37f8c3163b16c4b/src/main/resources/structures/watchtower.structure -------------------------------------------------------------------------------- /src/main/resources/tips/duplication.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |

Duplicate Code

4 | 5 | 6 | 7 |

Signs and Symptoms

8 |

Two code fragments look almost identical.

9 | 10 |

Reasons for the Problem

11 |

Duplication usually occurs when multiple programmers are working on different parts of the same program at the same time. Since they’re working on different tasks, they may be unaware their colleague has already written similar code that could be repurposed for their own needs.

12 |

There’s also more subtle duplication, when specific parts of code look different but actually perform the same job. This kind of duplication can be hard to find and fix.

13 |

Sometimes duplication is purposeful. When rushing to meet deadlines and the existing code is “almost right” for the job, novice programmers may not be able to resist the temptation of copying and pasting the relevant code. And in some cases, the programmer is simply too lazy to de-clutter.

14 |

Treatment

15 |
    16 |
  • 17 |

    If the same code is found in two or more methods in the same class: use Extract Method and place calls for the new method in both places.

    18 |
  • 19 |
  • 20 |

    If the same code is found in two subclasses of the same level:

    21 |
      22 |
    • 23 |

      Use Extract Method for both classes, followed by Pull Up Field for the fields used in the method that you’re pulling up.

      24 |
    • 25 |
    • 26 |

      If the duplicate code is inside a constructor, use Pull Up Constructor Body.

      27 |
    • 28 |
    • 29 |

      If the duplicate code is similar but not completely identical, use Form Template Method.

      30 |
    • 31 |
    • 32 |

      If two methods do the same thing but use different algorithms, select the best algorithm and apply Substitute Algorithm.

      33 |
    • 34 |
    35 |
  • 36 |
  • 37 |

    If duplicate code is found in two different classes:

    38 |
      39 |
    • 40 |

      If the classes aren’t part of a hierarchy, use Extract Superclass in order to create a single superclass for these classes that maintains all the previous functionality.

      41 |
    • 42 |
    • 43 |

      If it’s difficult or impossible to create a superclass, use Extract Class in one class and use the new component in the other.

      44 |
    • 45 |
    46 |
  • 47 |
  • 48 |

    If a large number of conditional expressions are present and perform the same code (differing only in their conditions), merge these operators into a single condition using Consolidate Conditional Expression and use Extract Method to place the condition in a separate method with an easy-to-understand name.

    49 |
  • 50 |
  • 51 |

    If the same code is performed in all branches of a conditional expression: place the identical code outside of the condition tree by using Consolidate Duplicate Conditional Fragments.

    52 |
  • 53 |
54 |

Payoff

55 |
    56 |
  • 57 |

    Merging duplicate code simplifies the structure of your code and makes it shorter.

    58 |
  • 59 |
  • 60 |

    Simplification + shortness = code that’s easier to simplify and cheaper to support.

    61 |
  • 62 |
63 | 64 |

When to Ignore

65 |
    66 |
  • In very rare cases, merging two identical fragments of code can make the code less intuitive and obvious.
  • 67 |
68 | 69 |

Read more at: https://refactoring.guru/smells/duplicate-code

70 | 71 | 72 |
-------------------------------------------------------------------------------- /src/main/resources/tips/longmethod.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |

Long Method

4 | 5 | 6 |

Signs and Symptoms

7 |

A method contains too many lines of code. Generally, any method longer than ten lines should make you start asking questions.

8 | 9 |

Reasons for the Problem

10 |

Like the Hotel California, something is always being added to a method but nothing is ever taken out. Since it’s easier to write code than to read it, this “smell” remains unnoticed until the method turns into an ugly, oversized beast.

11 |

Mentally, it’s often harder to create a new method than to add to an existing one: “But it’s just two lines, there’s no use in creating a whole method just for that...” Which means that another line is added and then yet another, giving birth to a tangle of spaghetti code.

12 |

Treatment

13 |

As a rule of thumb, if you feel the need to comment on something inside a method, you should take this code and put it in a new method. Even a single line can and should be split off into a separate method, if it requires explanations. And if the method has a descriptive name, nobody will need to look at the code to see what it does.

14 | 15 | 29 |

Payoff

30 |
    31 |
  • 32 |

    Among all types of object-oriented code, classes with short methods live longest. The longer a method or function is, the harder it becomes to understand and maintain it.

    33 |
  • 34 |
  • 35 |

    In addition, long methods offer the perfect hiding place for unwanted duplicate code.

    36 |
  • 37 |
38 | 39 |

Performance

40 |

Does an increase in the number of methods hurt performance, as many people claim? In almost all cases the impact is so negligible that it’s not even worth worrying about.

41 |

Plus, now that you have clear and understandable code, you’re more likely to find truly effective methods for restructuring code and getting real performance gains if the need ever arises.

42 | 43 |

Read more at: https://refactoring.guru/smells/long-method

44 | 45 | 46 |
-------------------------------------------------------------------------------- /src/main/resources/tips/unitinterface.html: -------------------------------------------------------------------------------- 1 |
2 |

Long Parameter List

3 | 4 |

Signs and Symptoms

5 |

More than three or four parameters for a method.

6 | 7 |

Reasons for the Problem

8 |

A long list of parameters might happen after several types of algorithms are merged in a single method. A long list may have been created to control which algorithm will be run and how.

9 |

Long parameter lists may also be the byproduct of efforts to make classes more independent of each other. For example, the code for creating specific objects needed in a method was moved from the method to the code for calling the method, but the created objects are passed to the method as parameters. Thus the original class no longer knows about the relationships between objects, and dependency has decreased. But if several of these objects are created, each of them will require its own parameter, which means a longer parameter list.

10 |

It’s hard to understand such lists, which become contradictory and hard to use as they grow longer. Instead of a long list of parameters, a method can use the data of its own object. If the current object doesn’t contain all necessary data, another object (which will get the necessary data) can be passed as a method parameter.

11 |

Treatment

12 |
    13 |
  • 14 |

    Check what values are passed to parameters. If some of the arguments are just results of method calls of another object, use Replace Parameter with Method Call. This object can be placed in the field of its own class or passed as a method parameter.

    15 |
  • 16 |
  • 17 |

    Instead of passing a group of data received from another object as parameters, pass the object itself to the method, by using Preserve Whole Object.

    18 |
  • 19 |
  • 20 |

    If there are several unrelated data elements, sometimes you can merge them into a single parameter object via Introduce Parameter Object.

    21 |
  • 22 |
23 | 24 |

Payoff

25 |
    26 |
  • 27 |

    More readable, shorter code.

    28 |
  • 29 |
  • 30 |

    Refactoring may reveal previously unnoticed duplicate code.

    31 |
  • 32 |
33 |

When to Ignore

34 |
    35 |
  • Don’t get rid of parameters if doing so would cause unwanted dependency between classes.
  • 36 |
37 | 38 |

Read more at: https://refactoring.guru/smells/long-parameter-list

39 | 40 |
-------------------------------------------------------------------------------- /src/main/test/EditorTest.java: -------------------------------------------------------------------------------- 1 | import java.io.File; 2 | 3 | import javax.swing.SwingUtilities; 4 | import javax.swing.UIManager; 5 | 6 | import org.junit.Test; 7 | 8 | import com.simonbaars.codearena.editor.CodeEditor; 9 | 10 | public class EditorTest { 11 | 12 | @Test 13 | public void test() throws InterruptedException { 14 | SwingUtilities.invokeLater(() -> { 15 | try { 16 | UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 17 | // UIManager.setLookAndFeel("org.pushingpixels.substance.api.skin.SubstanceGraphiteAquaLookAndFeel"); 18 | } catch (Exception e) { 19 | e.printStackTrace(); 20 | } 21 | new CodeEditor(new File("/home/simon/.clone/projects/ProjectWithDuplicateBetweenFiles/src/nl/sandersimon/dup3/Main.java"), 15, 20).setVisible(true); 22 | }); 23 | 24 | Thread.sleep(100000); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/test/EditorTest2.java: -------------------------------------------------------------------------------- 1 | import org.junit.Test; 2 | 3 | import com.simonbaars.codearena.CloneCommand; 4 | import com.simonbaars.codearena.CloneDetection; 5 | import com.simonbaars.codearena.editor.CodeEditorMaker; 6 | import com.simonbaars.codearena.thread.ProblemDetectionThread; 7 | 8 | import net.minecraft.command.CommandException; 9 | import net.minecraft.command.CommandSenderWrapper; 10 | 11 | public class EditorTest2 { 12 | 13 | @Test 14 | public void test() throws InterruptedException { 15 | CloneDetection d = new CloneDetection(); 16 | d.preInit(null); 17 | d.init(null); 18 | CloneCommand c = new CloneCommand(); 19 | try { 20 | c.execute(null, new CommandSenderWrapper(null, null, null, null, null, false), new String[] {"ProjectWithDuplicateBetweenFiles"}); 21 | } catch (CommandException e) { 22 | e.printStackTrace(); 23 | } 24 | while(ProblemDetectionThread.getWorker().isAlive()) 25 | try { 26 | Thread.sleep(100); 27 | } catch (InterruptedException e) { 28 | Thread.currentThread().interrupt(); 29 | } 30 | //CodeEditorMaker.create(d.getClones().get(0)); 31 | 32 | //Thread.sleep(100000); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/test/PackageTest.java: -------------------------------------------------------------------------------- 1 | import org.junit.Test; 2 | 3 | import com.simonbaars.codearena.model.Location; 4 | import com.simonbaars.codearena.model.MetricProblem; 5 | 6 | public class PackageTest { 7 | @Test 8 | public void testPackage() { 9 | MetricProblem c = new MetricProblem(); 10 | c.getLocations().add(new Location("/home/simon/.clone/projects/ProjectWithDuplicateBetweenFiles/src/nl/sandersimon/dup3/Main2.java")); 11 | System.out.println(c.getPackage()); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/test/ProjectParseTest.java: -------------------------------------------------------------------------------- 1 | import static org.junit.Assert.*; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.nio.file.FileVisitResult; 6 | import java.nio.file.Files; 7 | import java.nio.file.Path; 8 | import java.nio.file.Paths; 9 | import java.nio.file.SimpleFileVisitor; 10 | import java.nio.file.attribute.BasicFileAttributes; 11 | 12 | import org.junit.Test; 13 | 14 | import com.simonbaars.codearena.common.SavePaths; 15 | import com.simonbaars.codearena.model.Location; 16 | import com.simonbaars.codearena.model.MetricProblem; 17 | 18 | public class ProjectParseTest { 19 | 20 | @Test 21 | public void test() { 22 | MetricProblem foundLocs = new MetricProblem(); 23 | try { 24 | Files.walkFileTree(Paths.get(SavePaths.getProjectFolder()+"smallsql0.21_src"+"/src/"), new SimpleFileVisitor() { 25 | @Override 26 | public FileVisitResult visitFile(Path filePath, BasicFileAttributes attrs) throws IOException { 27 | File file = filePath.toFile(); 28 | if(file.getName().endsWith(".java")) 29 | foundLocs.getLocations().add(new Location(file.getAbsolutePath())); 30 | return FileVisitResult.CONTINUE; 31 | } 32 | }); 33 | } catch (IOException e) { 34 | e.printStackTrace(); 35 | } 36 | System.out.println(foundLocs.rascalLocList()); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/test/TestConsole.java: -------------------------------------------------------------------------------- 1 | import org.junit.Test; 2 | 3 | import com.simonbaars.codearena.CloneCommand; 4 | import com.simonbaars.codearena.CloneDetection; 5 | import com.simonbaars.codearena.thread.ProblemDetectionThread; 6 | 7 | import net.minecraft.command.CommandException; 8 | import net.minecraft.command.CommandSenderWrapper; 9 | 10 | public class TestConsole { 11 | 12 | @Test 13 | public void test() { 14 | CloneDetection d = new CloneDetection(); 15 | d.preInit(null); 16 | d.init(null); 17 | CloneCommand c = new CloneCommand(); 18 | try { 19 | c.execute(null, new CommandSenderWrapper(null, null, null, null, null, false), new String[] {"ProjectWithDuplicateBetweenFiles"}); 20 | } catch (CommandException e) { 21 | e.printStackTrace(); 22 | } 23 | while(ProblemDetectionThread.getWorker().isAlive()) 24 | try { 25 | Thread.sleep(1000); 26 | } catch (InterruptedException e) { 27 | Thread.currentThread().interrupt(); 28 | } 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/test/TestLocConverter.java: -------------------------------------------------------------------------------- 1 | import org.junit.Test; 2 | 3 | import com.simonbaars.codearena.thread.ProblemDetectionThread; 4 | 5 | import scala.actors.threadpool.Arrays; 6 | 7 | public class TestLocConverter { 8 | 9 | @Test 10 | public void test() { 11 | String input = "[<8,[|java+compilationUnit:///home/simon/.clone/projects/ProjectWithDuplicateBetweenFiles/src/nl/sandersimon/dup3/Main2.java|(0,436,<12,0>,<19,1>),|java+compilationUnit:///home/simon/.clone/projects/ProjectWithDuplicateBetweenFiles/src/nl/sandersimon/dup3/Main.java|(0,0,<14,0>,<21,0>)]>]"; 12 | //new CloneDetectionThread("", false).populateResult(); 13 | //System.out.println(Arrays.toString(.toArray())); 14 | } 15 | 16 | } --------------------------------------------------------------------------------