├── .classpath ├── .github └── workflows │ └── actions.yml ├── .gitignore ├── .project ├── .settings ├── org.eclipse.jdt.core.prefs └── org.eclipse.m2e.core.prefs ├── LICENSE ├── NOTICE ├── README.md ├── manifest.mf ├── pom.xml ├── src └── Designite │ ├── ArgumentParser │ ├── ArgumentParser.java │ ├── CLIArgumentParser.java │ ├── InputArgs.java │ └── RegularArgumentParser.java │ ├── Designite.java │ ├── SourceModel │ ├── AccessStates.java │ ├── CSVSmellsExportable.java │ ├── FieldVisitor.java │ ├── ImportVisitor.java │ ├── LocalVarVisitor.java │ ├── MethodInvVisitor.java │ ├── MethodVisitor.java │ ├── Parsable.java │ ├── Resolver.java │ ├── SM_EntitiesWithType.java │ ├── SM_Field.java │ ├── SM_LocalVar.java │ ├── SM_Method.java │ ├── SM_Package.java │ ├── SM_Parameter.java │ ├── SM_Project.java │ ├── SM_SourceItem.java │ ├── SM_Type.java │ ├── SourceItemInfo.java │ ├── TypeInfo.java │ ├── TypeVisitor.java │ └── VariableVisitor.java │ ├── metrics │ ├── MethodMetrics.java │ ├── MethodMetricsExtractor.java │ ├── MetricExtractor.java │ ├── Metrics.java │ ├── TypeMetrics.java │ └── TypeMetricsExtractor.java │ ├── smells │ ├── ThresholdsDTO.java │ ├── ThresholdsParser.java │ ├── designSmells │ │ ├── AbstractionSmellDetector.java │ │ ├── CodeSmellDetector.java │ │ ├── DesignSmellDetector.java │ │ ├── DesignSmellFacade.java │ │ ├── EncapsulationSmellDetector.java │ │ ├── HierarchySmellDetector.java │ │ └── ModularizationSmellDetector.java │ ├── implementationSmells │ │ └── ImplementationSmellDetector.java │ └── models │ │ ├── CodeSmell.java │ │ ├── DesignCodeSmell.java │ │ └── ImplementationCodeSmell.java │ ├── utils │ ├── CSVUtils.java │ ├── Constants.java │ ├── DJLogger.java │ ├── FileManager.java │ └── models │ │ ├── Edge.java │ │ ├── Graph.java │ │ └── Vertex.java │ └── visitors │ ├── DirectAceessFieldVisitor.java │ ├── InstanceOfVisitor.java │ ├── MethodControlFlowVisitor.java │ ├── NumberLiteralVisitor.java │ ├── StaticFieldAccessVisitor.java │ └── ThrowVisitor.java └── tests ├── DesigniteTests └── DesigniteTests │ ├── DesigniteTests.java │ ├── InputArgsTest.java │ ├── SM_FieldTest.java │ ├── SM_LocalVarTests.java │ ├── SM_MethodTest.java │ ├── SM_Method_CalledMethodsTests.java │ ├── SM_PackageTest.java │ ├── SM_ParameterTest.java │ ├── SM_ProjectTest.java │ ├── SM_TypeTest.java │ ├── metrics │ ├── MethodMetricsTest.java │ └── TypeMetricsTest.java │ ├── smells │ ├── ThresholdsParserTest.java │ ├── designSmells │ │ ├── AbstractionSmellDetectorTest.java │ │ ├── EncapsulationSmellDetectorTest.java │ │ ├── HierarchySmellDetectorTest.java │ │ └── ModularizationSmellDetectorTest.java │ └── implementationSmells │ │ └── ImplementationSmellDetectorTest.java │ └── utils │ └── models │ └── GraphTest.java └── TestFiles ├── codeSmells ├── notExistingThreshold.txt ├── thresholdsDefault.txt ├── thresholdsNonDefault.txt ├── wrongRowFormatNoEquals.txt └── wrongRowFormatNoNumberAsKey.txt ├── metrics └── metricsPackage │ ├── AnotherClass.java │ ├── Child1.java │ ├── Child2.java │ ├── ForeignClass1.java │ ├── ForeignClass2.java │ ├── ForeignClass3.java │ ├── ForeignClass4.java │ ├── ForeignClass5.java │ ├── InterfaceChild1.java │ ├── InterfaceChild2.java │ ├── InterfaceGrandChild.java │ ├── InterfaceParent.java │ ├── TestMetricsClass.java │ └── YetAnotherClass.java ├── test_inputs └── TestMethods.java ├── test_inputs2 ├── TestMethods.java └── TestMethods2.java └── test_package ├── AbstractClass.java ├── DefaultClass.java ├── EmptyClass.java ├── Interface.java ├── NestedClass.java ├── TestClass.java └── TestMethods.java /.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /.github/workflows/actions.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: setup 14 | uses: actions/checkout@v4 15 | - name: Set up JDK 11 16 | uses: actions/setup-java@v4 17 | with: 18 | distribution: 'corretto' 19 | java-version: 21 20 | - name: Build with Maven 21 | run: mvn clean install 22 | # - name: Download DesigniteJava 23 | # run: wget "https://www.designite-tools.com/static/download/DJE/DesigniteJava.jar" 24 | # - name: Create 'analysis' folder 25 | # run: mkdir analysis 26 | # - name: Analyze project with DesigniteJava 27 | # run: | 28 | # java -jar DesigniteJava.jar -i . -o analysis/ -f XML 29 | # ls 30 | # curl -X PUT -H "Authorization: Token ${{ secrets.QSCORED_API_KEY }}" -H "repository-link:https://github.com/tushartushar/DesigniteJava" -H "username: ts.iitm@gmail.com" -H "Content-Type: mulitpart/form-data" --url "https://qscored.com/api/upload/file.xml?is_open_access=on&version=$GITHUB_RUN_NUMBER&project_name=DesigniteJava" -F "file=@analysis/DesigniteAnalysis.xml" 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | */*.class 3 | */*/*.class 4 | 5 | *.csv 6 | */*.csv 7 | */*/*.csv 8 | csv/ 9 | 10 | # Ignore Mac DS_Store files 11 | .DS_Store 12 | **/.DS_Store 13 | 14 | /output 15 | /.idea/ 16 | 17 | tempDesigniteDebugLog*.txt 18 | tempDesigniteLog*.txt 19 | designCodeSmells.txt 20 | 21 | # Mobile Tools for Java (J2ME) 22 | .mtj.tmp/ 23 | 24 | # Package Files # 25 | *.war 26 | *.ear 27 | 28 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 29 | hs_err_pid* 30 | /bin/ 31 | /target/ 32 | target/ 33 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | DesigniteJava 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | org.eclipse.m2e.core.maven2Builder 15 | 16 | 17 | 18 | 19 | 20 | org.eclipse.m2e.core.maven2Nature 21 | org.eclipse.jdt.core.javanature 22 | 23 | 24 | -------------------------------------------------------------------------------- /.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled 3 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 4 | org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve 5 | org.eclipse.jdt.core.compiler.compliance=1.8 6 | org.eclipse.jdt.core.compiler.debug.lineNumber=generate 7 | org.eclipse.jdt.core.compiler.debug.localVariable=generate 8 | org.eclipse.jdt.core.compiler.debug.sourceFile=generate 9 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error 10 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error 11 | org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning 12 | org.eclipse.jdt.core.compiler.source=1.8 13 | -------------------------------------------------------------------------------- /.settings/org.eclipse.m2e.core.prefs: -------------------------------------------------------------------------------- 1 | activeProfiles= 2 | eclipse.preferences.version=1 3 | resolveWorkspaceProjects=true 4 | version=1 5 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | DesigniteJava 2 | Copyright 2014-2018 Designite 3 | 4 | This product includes software developed at 5 | Designite (http://www.designite-tools.com/). 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DesigniteJava 2 | DesigniteJava is a code quality assessment tool for code written in Java. It detects numerous design and implementation smells. It also computes many commonly used object-oriented metrics. 3 | 4 | ## Features 5 | * Detects 17 design smells 6 | - Imperative Abstraction 7 | - Multifaceted Abstraction 8 | - Unnecessary Abstraction 9 | - Unutilized Abstraction 10 | - Deficient Encapsulation 11 | - Unexploited Encapsulation 12 | - Broken Modularization 13 | - Cyclic-Dependent Modularization 14 | - Insufficient Modularization 15 | - Hub-like Modularization 16 | - Broken Hierarchy 17 | - Cyclic Hierarchy 18 | - Deep Hierarchy 19 | - Missing Hierarchy 20 | - Multipath Hierarchy 21 | - Rebellious Hierarchy 22 | - Wide Hierarchy 23 | * Detects 10 implementation smells 24 | - Abstract Function Call From Constructor 25 | - Complex Conditional 26 | - Complex Method 27 | - Empty catch clause 28 | - Long Identifier 29 | - Long Method 30 | - Long Parameter List 31 | - Long Statement 32 | - Magic Number 33 | - Missing default 34 | * Computes following object-oriented metrics 35 | - LOC (Lines Of Code - at method and class granularity) 36 | - CC (Cyclomatic Complexity - Method) 37 | - PC (Parameter Count - Method) 38 | - NOF (Number of Fields - Class) 39 | - NOPF (Number of Public Fields - Class) 40 | - NOM (Number of Methods - Class) 41 | - NOPM (Number of Public Methods - Class) 42 | - WMC (Weighted Methods per Class - Class) 43 | - NC (Number of Children - Class) 44 | - DIT (Depth of Inheritance Tree - Class) 45 | - LCOM (Lack of Cohesion in Methods - Class) 46 | - FANIN (Fan-in - Class) 47 | - FANOUT (Fan-out - Class) 48 | 49 | ## Where can I get the latest release? 50 | You may download the executable jar from the [Designite](https://www.designite-tools.com/products-dj) website. 51 | 52 | ## Compilation 53 | We use maven to develop and build this application with the help of Eclipse IDE and libraries. 54 | To create a runnable jar, run the following command in the directory where the repository is cloned: 55 | ```text 56 | mvn clean install 57 | ``` 58 | If you use Eclipse: 59 | * open the project using Eclipse 60 | * then right-click on the project name and select 'run as > maven install' 61 | 62 | ## Execute the tool 63 | After the previous step is done: 64 | * Open terminal/command line console and run the jar 65 | ```text 66 | java -jar Designite.jar -i -o 67 | ``` 68 | **Note:** Make sure that the output folder is empty. Tool deletes all the existing files in the output folder. 69 | 70 | ## Notes 71 | The implemented LCOM is a custom implementation to avoid the problems of existing LCOM alternatives. Traditional, LCOM value may range only between 0 and 1. However, there are many cases, when computing LCOM is not feasible and traditional implementations give value 0 giving us a false sense of satisfaction. So, when you find -1 as LCOM value for a class, this means we do not have enough information or LCOM is not applicable (for instance, for an interface). More details can be found here (though, it is an old post): https://www.tusharma.in/revisiting-lcom.html 72 | 73 | ## Contribute 74 | Feel free to clone/fork/contribute to the DesigniteJava open-source project. 75 | 76 | ## Report Bugs 77 | Open an issue if you encounter a bug in the tool. 78 | 79 | ## Credits 80 | Apart from [me](http://www.tusharma.in), following people generously contributed efforts to this project. 81 | - Antonis Gkortzis 82 | - Theodore Stassinopoulos 83 | - Alexandra Chaniotakis 84 | 85 | ## Star History 86 | 87 | [![Star History Chart](https://api.star-history.com/svg?repos=tushartushar/DesigniteJava&type=Date)](https://star-history.com/#tushartushar/DesigniteJava&Date) 88 | -------------------------------------------------------------------------------- /manifest.mf: -------------------------------------------------------------------------------- 1 | Manifest-version: 1.0 2 | Main-Class: Designite 3 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | DesigniteJava 5 | DesigniteJava 6 | 1.1.2 7 | jar 8 | 9 | 10 | 11 | junit 12 | junit 13 | 4.13.2 14 | test 15 | 16 | 17 | org.mockito 18 | mockito-core 19 | 4.2.0 20 | 21 | 22 | org.eclipse.jdt 23 | org.eclipse.jdt.core 24 | 3.31.0 25 | 26 | 27 | org.eclipse.text 28 | org.eclipse.text 29 | 3.5.101 30 | 31 | 32 | commons-cli 33 | commons-cli 34 | 1.5.0 35 | 36 | 37 | 38 | 39 | src 40 | tests/DesigniteTests 41 | 42 | 43 | tests/TestFiles 44 | 45 | **/*.java 46 | 47 | 48 | 49 | 50 | 51 | maven-assembly-plugin 52 | 53 | false 54 | ${project.artifactId} 55 | 56 | 57 | Designite.Designite 58 | 59 | 60 | 61 | jar-with-dependencies 62 | 63 | 64 | 65 | 66 | make-assembly 67 | package 68 | 69 | single 70 | 71 | 72 | 73 | 74 | 75 | org.apache.maven.plugins 76 | maven-jar-plugin 77 | 2.4 78 | 79 | 80 | 81 | true 82 | lib/ 83 | Designite.Designite 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 11 92 | 11 93 | UTF-8 94 | 95 | DesigniteJava 96 | http://www.designite-tools.com 97 | DesigniteJava is a software design quality assessment tool. It computes matrices and detect code smells in Java source code. 98 | 99 | http://www.designite-tools.com 100 | Designite 101 | 102 | -------------------------------------------------------------------------------- /src/Designite/ArgumentParser/ArgumentParser.java: -------------------------------------------------------------------------------- 1 | package Designite.ArgumentParser; 2 | 3 | import org.apache.commons.cli.Option; 4 | 5 | 6 | public abstract class ArgumentParser { 7 | /** 8 | * {@code createRequiredOption}. A method to initialise required {@link Option}. 9 | * @param shortOpt 10 | * @param longOpt 11 | * @param description 12 | * @return 13 | */ 14 | Option createRequiredOption(String shortOpt, String longOpt, String description) { 15 | Option option = new Option(shortOpt, longOpt, true, description); 16 | option.setRequired(true); 17 | return option; 18 | } 19 | 20 | /** 21 | * {@code parseArguments} converts the appropriate {@code args} parameter from the system. 22 | * It extracts the data from system arguments. 23 | * @param args 24 | * @return 25 | */ 26 | public abstract InputArgs parseArguments(String[] args); 27 | 28 | 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/Designite/ArgumentParser/CLIArgumentParser.java: -------------------------------------------------------------------------------- 1 | package Designite.ArgumentParser; 2 | 3 | import Designite.utils.DJLogger; 4 | import org.apache.commons.cli.*; 5 | 6 | /** 7 | * {@code CLIArgumentParser} is a subclass of {@code ArgumentParser} that requires arguments from 8 | * the console application in order to process the given arguments. 9 | */ 10 | public class CLIArgumentParser extends ArgumentParser { 11 | 12 | @Override 13 | public InputArgs parseArguments(String[] args) { 14 | Options argOptions = new Options(); 15 | argOptions.addOption(this.createRequiredOption("i", "Input", "Input source folder path")); 16 | argOptions.addOption(this.createRequiredOption("o", "Output", "Path to the output folder")); 17 | CommandLineParser parser = new DefaultParser(); 18 | HelpFormatter formatter = new HelpFormatter(); 19 | CommandLine cmd = null; 20 | try { 21 | cmd = parser.parse(argOptions, args); 22 | } catch (ParseException e) { 23 | System.out.println(e.getMessage()); 24 | formatter.printHelp("Designite", argOptions); 25 | DJLogger.log("Quitting.."); 26 | System.exit(1); 27 | } 28 | String inputFolderPath = cmd.getOptionValue("Input"); 29 | String outputFolderPath = cmd.getOptionValue("Output"); 30 | try { 31 | return new InputArgs(inputFolderPath, outputFolderPath); 32 | } catch (IllegalArgumentException ex) { 33 | DJLogger.log(ex.getMessage()); 34 | DJLogger.log("Quitting.."); 35 | System.err.printf("The specified input path does not exist: %s%n", inputFolderPath); 36 | System.exit(3); 37 | } 38 | return null; 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/Designite/ArgumentParser/InputArgs.java: -------------------------------------------------------------------------------- 1 | package Designite.ArgumentParser; 2 | 3 | import java.io.File; 4 | 5 | public class InputArgs { 6 | private String sourceFolder; 7 | private String outputFolder; 8 | 9 | public InputArgs() { 10 | //It is invoked only in case of error 11 | } 12 | 13 | public InputArgs(String inputFolderPath, String outputFolderPath) { 14 | sourceFolder = inputFolderPath; 15 | outputFolder = outputFolderPath; 16 | checkEssentialInputs(); 17 | } 18 | 19 | public String getSourceFolder() { 20 | return sourceFolder; 21 | } 22 | 23 | public String getOutputFolder() { 24 | return outputFolder; 25 | } 26 | 27 | //At least, the source folder must be specified 28 | private void checkEssentialInputs() { 29 | if (sourceFolder==null) 30 | { 31 | //System.out.println("Input source folder is not specified."); 32 | throw new IllegalArgumentException("Input source folder is not specified."); 33 | } 34 | File folder = new File(sourceFolder); 35 | if (!(folder.exists() && folder.isDirectory())) 36 | { 37 | //System.out.println("Input source folder path is not valid."); 38 | throw new IllegalArgumentException("Input source folder path is not valid."); 39 | } 40 | File outFolder = new File(outputFolder); 41 | if (outFolder.exists() && outFolder.isFile()) 42 | { 43 | //System.out.println("The specified output folder path is not valid."); 44 | throw new IllegalArgumentException("The specified output folder path is not valid."); 45 | } 46 | } 47 | 48 | /*** 49 | * Analyzes the provided sourceFolder variable and 50 | * extracts the name of the project. 51 | * @return A String with the name of the project. 52 | * When the given sourceFolder has a value of src 53 | * or source then the method returns 54 | * the name of the direct parent directory 55 | */ 56 | public String getProjectName() { 57 | File temp = new File(sourceFolder); 58 | if (temp.getName().equals("src") || temp.getName().equals("source")) { 59 | return new File(temp.getParent()).getName(); 60 | } else { 61 | return new File(sourceFolder).getName(); 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/Designite/ArgumentParser/RegularArgumentParser.java: -------------------------------------------------------------------------------- 1 | package Designite.ArgumentParser; 2 | 3 | import Designite.utils.DJLogger; 4 | 5 | import java.io.File; 6 | 7 | 8 | /** 9 | * {@code RegularArgumentParser} is a subclass of {@code ArgumentParser} that does not require any 10 | * arguments. By default, it will use the current working directory (cwd) of the Java project 11 | * to identify or analyze the smells in the current working project itself. 12 | */ 13 | public class RegularArgumentParser extends ArgumentParser { 14 | 15 | @Override 16 | public InputArgs parseArguments(String[] args) { 17 | String cwd = System.getProperty("user.dir"); 18 | String inputFolderPath = String.join(File.separator, cwd, "src","Designite"); 19 | String outputFolderPath = String.join(File.separator, cwd, "output"); 20 | try { 21 | return new InputArgs(inputFolderPath, outputFolderPath); 22 | } catch (IllegalArgumentException ex) { 23 | DJLogger.log(ex.getMessage()); 24 | DJLogger.log("Quitting.."); 25 | System.exit(3); 26 | } 27 | return null; 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/Designite/Designite.java: -------------------------------------------------------------------------------- 1 | package Designite; 2 | 3 | import Designite.ArgumentParser.ArgumentParser; 4 | import Designite.ArgumentParser.CLIArgumentParser; 5 | import Designite.ArgumentParser.InputArgs; 6 | import Designite.ArgumentParser.RegularArgumentParser; 7 | import Designite.SourceModel.SM_Project; 8 | import Designite.utils.Constants; 9 | import Designite.utils.DJLogger; 10 | 11 | import java.io.FileNotFoundException; 12 | import java.io.PrintWriter; 13 | import java.text.SimpleDateFormat; 14 | import java.util.Calendar; 15 | 16 | /** 17 | * This is the start of the project 18 | */ 19 | public class Designite { 20 | public static void main(String[] args) throws FileNotFoundException { 21 | ArgumentParser argumentParser = (Constants.DEBUG) ? new RegularArgumentParser() : new CLIArgumentParser(); 22 | InputArgs argsObj = argumentParser.parseArguments(args); 23 | DJLogger.getInstance().setOutputDirectory(argsObj.getOutputFolder()); 24 | SM_Project project = new SM_Project(argsObj); 25 | project.parse(); 26 | project.resolve(); 27 | project.computeMetrics(); 28 | project.detectCodeSmells(); 29 | writeDebugLog(argsObj, project); 30 | DJLogger.log("Done."); 31 | } 32 | 33 | private static void writeDebugLog(InputArgs argsObj, SM_Project project) { 34 | if (Constants.DEBUG) { 35 | PrintWriter writer = getDebugLogStream(argsObj); 36 | project.printDebugLog(writer); 37 | if (writer != null) writer.close(); 38 | } 39 | } 40 | 41 | private static PrintWriter getDebugLogStream(InputArgs argsObj) { 42 | PrintWriter writer = null; 43 | if (!argsObj.getOutputFolder().equals("")) { 44 | String timeStamp = new SimpleDateFormat("ddMMyyyy_HHmm").format(Calendar.getInstance().getTime()); 45 | String filename = argsObj.getOutputFolder() + "DesigniteDebugLog" + timeStamp + ".txt"; 46 | try { 47 | writer = new PrintWriter(filename); 48 | } catch (FileNotFoundException ex) { 49 | DJLogger.log(ex.getMessage()); 50 | } 51 | } 52 | return writer; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/Designite/SourceModel/AccessStates.java: -------------------------------------------------------------------------------- 1 | package Designite.SourceModel; 2 | 3 | public enum AccessStates { 4 | 5 | PUBLIC, PROTECTED, DEFAULT, PRIVATE 6 | 7 | } 8 | -------------------------------------------------------------------------------- /src/Designite/SourceModel/CSVSmellsExportable.java: -------------------------------------------------------------------------------- 1 | package Designite.SourceModel; 2 | 3 | public interface CSVSmellsExportable { 4 | 5 | void exportSmellsToCSV(); 6 | 7 | } 8 | -------------------------------------------------------------------------------- /src/Designite/SourceModel/FieldVisitor.java: -------------------------------------------------------------------------------- 1 | package Designite.SourceModel; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import org.eclipse.jdt.core.dom.ASTVisitor; 7 | import org.eclipse.jdt.core.dom.FieldDeclaration; 8 | import org.eclipse.jdt.core.dom.VariableDeclarationFragment; 9 | 10 | public class FieldVisitor extends ASTVisitor { 11 | List fields = new ArrayList(); 12 | private SM_Type parentType; 13 | 14 | public FieldVisitor(SM_Type parentType) { 15 | super(); 16 | this.parentType = parentType; 17 | } 18 | 19 | @Override 20 | public boolean visit(FieldDeclaration fieldDeclaration) { 21 | List fieldList = fieldDeclaration.fragments(); 22 | for (VariableDeclarationFragment field : fieldList) { 23 | SM_Field newField = new SM_Field(fieldDeclaration, field, parentType); 24 | fields.add(newField); 25 | } 26 | 27 | return super.visit(fieldDeclaration); 28 | } 29 | 30 | public List getFields() { 31 | return fields; 32 | } 33 | 34 | /* 35 | * public int countFields() { return fields.size(); } 36 | */ 37 | } 38 | -------------------------------------------------------------------------------- /src/Designite/SourceModel/ImportVisitor.java: -------------------------------------------------------------------------------- 1 | package Designite.SourceModel; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import org.eclipse.jdt.core.dom.ASTVisitor; 7 | import org.eclipse.jdt.core.dom.ImportDeclaration; 8 | 9 | public class ImportVisitor extends ASTVisitor { 10 | List imports = new ArrayList<>(); 11 | 12 | @Override 13 | public boolean visit(ImportDeclaration newImport) { 14 | imports.add(newImport); 15 | 16 | return super.visit(newImport); 17 | } 18 | 19 | public List getImports(){ 20 | return imports; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Designite/SourceModel/LocalVarVisitor.java: -------------------------------------------------------------------------------- 1 | package Designite.SourceModel; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Iterator; 5 | import java.util.List; 6 | 7 | import org.eclipse.jdt.core.dom.ASTVisitor; 8 | import org.eclipse.jdt.core.dom.VariableDeclarationFragment; 9 | import org.eclipse.jdt.core.dom.VariableDeclarationStatement; 10 | 11 | public class LocalVarVisitor extends ASTVisitor { 12 | List localVariables = new ArrayList(); 13 | private SM_Method parentMethod; 14 | 15 | public LocalVarVisitor(SM_Method methodObj) { 16 | this.parentMethod = methodObj; 17 | } 18 | 19 | public boolean visit(VariableDeclarationStatement variable){ 20 | for (Iterator iter = variable.fragments().iterator(); iter.hasNext();) { 21 | VariableDeclarationFragment fragment = (VariableDeclarationFragment) iter.next(); 22 | // IVariableBinding binding = fragment.resolveBinding(); 23 | 24 | SM_LocalVar newLocalVar = new SM_LocalVar(variable, fragment, parentMethod); 25 | //newLocalVar.setType(variable.getType()); 26 | localVariables.add(newLocalVar); 27 | } 28 | return super.visit(variable); 29 | } 30 | 31 | public List getLocalVarList() { 32 | return localVariables; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/Designite/SourceModel/MethodInvVisitor.java: -------------------------------------------------------------------------------- 1 | package Designite.SourceModel; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import org.eclipse.jdt.core.dom.ASTVisitor; 7 | import org.eclipse.jdt.core.dom.MethodDeclaration; 8 | import org.eclipse.jdt.core.dom.MethodInvocation; 9 | import org.eclipse.jdt.core.dom.SuperMethodInvocation; 10 | 11 | public class MethodInvVisitor extends ASTVisitor { 12 | List calledMethods = new ArrayList(); 13 | //private MethodDeclaration methodDeclaration; 14 | 15 | public MethodInvVisitor(MethodDeclaration methodDeclaration) { 16 | //this.methodDeclaration = methodDeclaration; 17 | } 18 | 19 | public MethodInvVisitor() { 20 | 21 | } 22 | 23 | @Override 24 | public boolean visit(MethodInvocation method) { 25 | calledMethods.add(method); 26 | method.resolveMethodBinding(); 27 | return super.visit(method); 28 | } 29 | 30 | public boolean visit(SuperMethodInvocation method) { 31 | return super.visit(method); 32 | } 33 | 34 | public List getCalledMethods() { 35 | return calledMethods; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Designite/SourceModel/MethodVisitor.java: -------------------------------------------------------------------------------- 1 | package Designite.SourceModel; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import org.eclipse.jdt.core.dom.ASTVisitor; 7 | import org.eclipse.jdt.core.dom.MethodDeclaration; 8 | import org.eclipse.jdt.core.dom.TypeDeclaration; 9 | 10 | public class MethodVisitor extends ASTVisitor { 11 | List methods = new ArrayList(); 12 | //private TypeDeclaration typeDeclaration; 13 | private SM_Type parentType; 14 | 15 | public MethodVisitor(TypeDeclaration typeDeclaration, SM_Type typeObj) { 16 | super(); 17 | //this.typeDeclaration = typeDeclaration; 18 | this.parentType = typeObj; 19 | } 20 | 21 | @Override 22 | public boolean visit(MethodDeclaration method) { 23 | SM_Method newMethod = new SM_Method(method, parentType); 24 | methods.add(newMethod); 25 | 26 | return super.visit(method); 27 | } 28 | 29 | public List getMethods(){ 30 | return methods; 31 | } 32 | 33 | public int countMethods() { 34 | return methods.size(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Designite/SourceModel/Parsable.java: -------------------------------------------------------------------------------- 1 | package Designite.SourceModel; 2 | 3 | public interface Parsable { 4 | void parse(); 5 | } 6 | -------------------------------------------------------------------------------- /src/Designite/SourceModel/SM_EntitiesWithType.java: -------------------------------------------------------------------------------- 1 | package Designite.SourceModel; 2 | 3 | import java.util.List; 4 | 5 | public abstract class SM_EntitiesWithType extends SM_SourceItem { 6 | 7 | protected TypeInfo typeInfo; 8 | 9 | public boolean isPrimitiveType() { 10 | return typeInfo.isPrimitiveType(); 11 | } 12 | 13 | public SM_Type getParentType() { 14 | // Always returns null. 15 | // Should be overridden by subclasses 16 | return null; 17 | } 18 | 19 | // public boolean isTypeVariable() { 20 | // return typeInfo.isTypeVariable(); 21 | // } 22 | 23 | public SM_Type getType() { 24 | return typeInfo.getTypeObj(); 25 | } 26 | 27 | public String getPrimitiveType() { 28 | return typeInfo.getObjPrimitiveType(); 29 | } 30 | 31 | public boolean isParametrizedType() { 32 | return typeInfo.isParametrizedType(); 33 | } 34 | 35 | public List getNonPrimitiveTypeParameters() { 36 | return typeInfo.getNonPrimitiveTypeParameters(); 37 | } 38 | 39 | public String getTypeOverallToString() { 40 | if (isPrimitiveType()) { 41 | return getPrimitiveType(); 42 | } else { 43 | return getType() != null 44 | ? getType().getName() 45 | : "UnresolvedType"; // in case of unresolved types 46 | } 47 | // if (typeInfo != null) { 48 | // if (isPrimitiveType()) { 49 | // return getPrimitiveType(); 50 | // } else { 51 | // return getType().getName(); 52 | // } 53 | // } else 54 | // return "generic"; 55 | } 56 | 57 | // @Override 58 | // public void parse() { 59 | // 60 | // } 61 | } 62 | -------------------------------------------------------------------------------- /src/Designite/SourceModel/SM_Field.java: -------------------------------------------------------------------------------- 1 | package Designite.SourceModel; 2 | 3 | import java.io.PrintWriter; 4 | import java.lang.reflect.Modifier; 5 | import java.util.regex.Matcher; 6 | import java.util.regex.Pattern; 7 | 8 | import org.eclipse.jdt.core.dom.FieldDeclaration; 9 | import org.eclipse.jdt.core.dom.TypeDeclaration; 10 | import org.eclipse.jdt.core.dom.VariableDeclarationFragment; 11 | 12 | import Designite.utils.models.Vertex; 13 | 14 | public class SM_Field extends SM_EntitiesWithType implements Vertex { 15 | private TypeDeclaration typeDeclaration; 16 | private FieldDeclaration fieldDeclaration; 17 | private SM_Type parentType; 18 | private SM_Type nestedParentType = null; 19 | private boolean finalField = false; 20 | private boolean staticField = false; 21 | //private VariableDeclarationFragment variableDeclaration; 22 | 23 | public SM_Field(FieldDeclaration fieldDeclaration, VariableDeclarationFragment varDecl, SM_Type parentType) { 24 | this.fieldDeclaration = fieldDeclaration; 25 | //this.variableDeclaration = varDecl; 26 | this.parentType = parentType; 27 | setAccessModifier(fieldDeclaration.getModifiers()); 28 | setFieldInfo(fieldDeclaration); 29 | name = varDecl.getName().toString(); 30 | assignToNestedTypeIfNecessary(); 31 | } 32 | 33 | void setFieldInfo(FieldDeclaration field){ 34 | int modifiers = field.getModifiers(); 35 | if (Modifier.isFinal(modifiers)) 36 | finalField = true; 37 | if (Modifier.isStatic(modifiers)) 38 | staticField = true; 39 | } 40 | 41 | private void assignToNestedTypeIfNecessary() { 42 | if (parentType.getNestedTypes().size() < 1) { 43 | return; 44 | } else { 45 | String typeName = getNestedParentName(); 46 | if(typeName != null) { 47 | typeName = typeName.trim(); 48 | this.nestedParentType = parentType.getNestedTypeFromName(typeName); 49 | if(this.nestedParentType != null) { 50 | } 51 | } 52 | } 53 | } 54 | 55 | private String getNestedParentName() { 56 | final String regex = "public|private[ ]{1,}class[ ]{1,}([^\\{]*)[\\{]{1}"; 57 | final String inputString = this.fieldDeclaration.getParent().toString(); 58 | final Pattern pattern = Pattern.compile(regex); 59 | final Matcher matcher = pattern.matcher(inputString); 60 | 61 | String typeName = ""; 62 | while (matcher.find()) { 63 | typeName = matcher.group(1); 64 | return typeName; 65 | } 66 | return ""; 67 | } 68 | 69 | public SM_Type getNestedParent() { 70 | return this.nestedParentType; 71 | } 72 | 73 | public TypeDeclaration getTypeDeclaration() { 74 | return typeDeclaration; 75 | } 76 | 77 | public boolean isFinal() { 78 | return finalField; 79 | } 80 | 81 | public boolean isStatic() { 82 | return staticField; 83 | } 84 | 85 | @Override 86 | public SM_Type getParentType() { 87 | return parentType; 88 | } 89 | 90 | 91 | @Override 92 | public void printDebugLog(PrintWriter writer) { 93 | print(writer, "\t\tField name: " + getName()); 94 | print(writer, "\t\tParent class: " + this.parentType.getName()); 95 | print(writer, "\t\tAccess: " + getAccessModifier()); 96 | print(writer, "\t\tFinal: " + isFinal()); 97 | print(writer, "\t\tStatic: " + isStatic()); 98 | if (!isPrimitiveType()) { 99 | if (getType() != null) { 100 | print(writer, "\t\tField type: " + getType().getName()); 101 | } else { 102 | print(writer, "\t\tField type: " + typeInfo.getObjPrimitiveType()); 103 | } 104 | } 105 | else 106 | if (isPrimitiveType()) 107 | print(writer, "\t\tPrimitive field type: " + getPrimitiveType()); 108 | if (isParametrizedType()) { 109 | print(writer, "\t\tList of parameters: " + typeInfo.getStringOfNonPrimitiveParameters()); 110 | } 111 | print(writer, "\t\t----"); 112 | } 113 | 114 | @Override 115 | public void resolve() { 116 | Resolver resolver = new Resolver(); 117 | typeInfo = resolver.resolveVariableType(fieldDeclaration.getType(), getParentType().getParentPkg().getParentProject(), getParentType()); 118 | } 119 | 120 | } 121 | -------------------------------------------------------------------------------- /src/Designite/SourceModel/SM_LocalVar.java: -------------------------------------------------------------------------------- 1 | package Designite.SourceModel; 2 | 3 | import java.io.PrintWriter; 4 | 5 | import org.eclipse.jdt.core.dom.VariableDeclarationFragment; 6 | import org.eclipse.jdt.core.dom.VariableDeclarationStatement; 7 | 8 | public class SM_LocalVar extends SM_EntitiesWithType { 9 | private VariableDeclarationFragment localVarFragment; 10 | private SM_Method parentMethod; 11 | private VariableDeclarationStatement localVarDecl; 12 | 13 | public SM_LocalVar(VariableDeclarationStatement varDecl, VariableDeclarationFragment localVar, SM_Method method) { 14 | this.localVarFragment = localVar; 15 | parentMethod = method; 16 | name = localVarFragment.getName().toString(); 17 | localVarDecl = varDecl; 18 | } 19 | 20 | public SM_Method getParentMethod() { 21 | return parentMethod; 22 | } 23 | 24 | @Override 25 | public SM_Type getParentType() { 26 | return this.parentMethod.getParentType(); 27 | } 28 | 29 | @Override 30 | public void printDebugLog(PrintWriter writer) { 31 | print(writer, "\t\t\tLocalVar: " + getName()); 32 | print(writer, "\t\t\tParent method: " + this.parentMethod.getName()); 33 | 34 | if (!isPrimitiveType()) { 35 | // if (!isPrimitiveType() && !isTypeVariable()) { 36 | if (typeInfo.isParametrizedType()) { 37 | print(writer, "\t\t\tParameter types: " + typeInfo.getStringOfNonPrimitiveParameters()); 38 | } 39 | else { 40 | // print(writer, "\t\t\tVariable type: " + getType().getName()); 41 | print(writer, "\t\t\tVariable type: " + getType()); 42 | } 43 | } /*else if (isTypeVariable()) { 44 | print(writer, "\t\t\tType Variable :: " + getName()); 45 | }*/ 46 | else 47 | print(writer, "\t\t\tPrimitive variable type: " + getPrimitiveType()); 48 | print(writer, "\t\t\t----"); 49 | } 50 | 51 | @Override 52 | public void resolve() { 53 | Resolver resolver = new Resolver(); 54 | typeInfo = resolver.resolveVariableType(localVarDecl.getType(), parentMethod.getParentType().getParentPkg().getParentProject(), getParentType()); 55 | } 56 | 57 | @Override 58 | public String toString() { 59 | return "Local variable name=" + name 60 | + ", type=" + localVarDecl.getType() 61 | + ", isParameterizedType=" + localVarDecl.getType().isParameterizedType(); 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /src/Designite/SourceModel/SM_Method.java: -------------------------------------------------------------------------------- 1 | package Designite.SourceModel; 2 | 3 | import java.io.PrintWriter; 4 | import java.lang.reflect.Modifier; 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | import org.eclipse.jdt.core.dom.FieldAccess; 9 | import org.eclipse.jdt.core.dom.MethodDeclaration; 10 | import org.eclipse.jdt.core.dom.MethodInvocation; 11 | import org.eclipse.jdt.core.dom.SimpleName; 12 | import org.eclipse.jdt.core.dom.SingleVariableDeclaration; 13 | import org.eclipse.jdt.core.dom.Type; 14 | 15 | import Designite.utils.models.Vertex; 16 | import Designite.visitors.DirectAceessFieldVisitor; 17 | import Designite.visitors.InstanceOfVisitor; 18 | import Designite.visitors.ThrowVisitor; 19 | 20 | public class SM_Method extends SM_SourceItem implements Vertex, Parsable { 21 | 22 | private boolean abstractMethod; 23 | private boolean finalMethod; 24 | private boolean staticMethod; 25 | private boolean isConstructor; 26 | private boolean throwsException; 27 | private SM_Type parentType; 28 | 29 | private MethodDeclaration methodDeclaration; 30 | 31 | private List calledMethodsList = new ArrayList(); 32 | private List parameterList = new ArrayList(); 33 | private List localVarList = new ArrayList(); 34 | private List calledMethods = new ArrayList(); 35 | private List referencedTypeList = new ArrayList(); 36 | private List namesInMethod = new ArrayList<>(); 37 | private List thisAccessesInMethod = new ArrayList<>(); 38 | private List directFieldAccesses = new ArrayList<>(); 39 | private List typesInInstanceOf = new ArrayList<>(); 40 | private List smTypesInInstanceOf = new ArrayList<>(); 41 | 42 | public SM_Method(MethodDeclaration methodDeclaration, SM_Type typeObj) { 43 | name = methodDeclaration.getName().toString(); 44 | this.parentType = typeObj; 45 | this.methodDeclaration = methodDeclaration; 46 | setMethodInfo(methodDeclaration); 47 | setAccessModifier(methodDeclaration.getModifiers()); 48 | } 49 | 50 | public void setMethodInfo(MethodDeclaration method) { 51 | int modifiers = method.getModifiers(); 52 | if (Modifier.isAbstract(modifiers)) 53 | abstractMethod = true; 54 | if (Modifier.isFinal(modifiers)) 55 | finalMethod = true; 56 | if (Modifier.isStatic(modifiers)) 57 | staticMethod = true; 58 | if (method.isConstructor()) 59 | isConstructor = true; 60 | } 61 | 62 | public boolean isAbstract() { 63 | return this.abstractMethod; 64 | } 65 | 66 | public boolean isStatic() { 67 | return this.staticMethod; 68 | } 69 | 70 | public boolean isFinal() { 71 | return this.finalMethod; 72 | } 73 | 74 | public boolean isConstructor() { 75 | return this.isConstructor; 76 | } 77 | 78 | public SM_Type getParentType() { 79 | return parentType; 80 | } 81 | 82 | public boolean throwsException() { 83 | return throwsException; 84 | } 85 | 86 | public boolean hasBody() { 87 | return this.methodDeclaration.getBody() != null; 88 | } 89 | 90 | public List getParameterList() { 91 | return parameterList; 92 | } 93 | 94 | public List getLocalVarList() { 95 | return localVarList; 96 | } 97 | 98 | public List getCalledMethods() { 99 | return calledMethodsList; 100 | } 101 | 102 | public MethodDeclaration getMethodDeclaration() { 103 | return methodDeclaration; 104 | } 105 | 106 | private void prepareCalledMethodsList() { 107 | MethodInvVisitor invVisitor = new MethodInvVisitor(methodDeclaration); 108 | methodDeclaration.accept(invVisitor); 109 | List invList = invVisitor.getCalledMethods(); 110 | if (invList.size() > 0) { 111 | calledMethods.addAll(invList); 112 | } 113 | } 114 | 115 | private void prepareInstanceOfVisitorList() { 116 | InstanceOfVisitor instanceOfVisitor = new InstanceOfVisitor(); 117 | methodDeclaration.accept(instanceOfVisitor); 118 | List instanceOfTypes = instanceOfVisitor.getTypesInInstanceOf(); 119 | if (instanceOfTypes.size() > 0) { 120 | typesInInstanceOf.addAll(instanceOfTypes); 121 | } 122 | } 123 | 124 | private void prepareParametersList(SingleVariableDeclaration var) { 125 | VariableVisitor parameterVisitor = new VariableVisitor(this); 126 | // methodDeclaration.accept(parameterVisitor); 127 | var.accept(parameterVisitor); 128 | List pList = parameterVisitor.getParameterList(); 129 | if (pList.size() > 0) { 130 | parameterList.addAll(pList); 131 | } 132 | } 133 | 134 | //SM_Parameter uses an empty parse method. So commenting this. 135 | // private void parseParameters() { 136 | // for (SM_Parameter param : parameterList) { 137 | // param.parse(); 138 | // } 139 | // } 140 | 141 | private void prepareLocalVarList() { 142 | LocalVarVisitor localVarVisitor = new LocalVarVisitor(this); 143 | methodDeclaration.accept(localVarVisitor); 144 | List lList = localVarVisitor.getLocalVarList(); 145 | if (lList.size() > 0) { 146 | localVarList.addAll(lList); 147 | } 148 | } 149 | 150 | //SM_LocalVar inherits SM_EntitiesWithType which inter uses an empty parse method. So, commenting this. 151 | // private void parseLocalVar() { 152 | // for (SM_LocalVar var : localVarList) { 153 | // var.parse(); 154 | // } 155 | // } 156 | 157 | public String getMethodBody() { 158 | if (this.hasBody()) 159 | return this.getMethodDeclaration().getBody().toString(); 160 | else 161 | return ""; 162 | } 163 | 164 | @Override 165 | public void printDebugLog(PrintWriter writer) { 166 | print(writer, "\t\tMethod: " + name); 167 | print(writer, "\t\tParent type: " + this.getParentType().getName()); 168 | print(writer, "\t\tConstructor: " + isConstructor); 169 | print(writer, "\t\tReturns: " + methodDeclaration.getReturnType2()); 170 | print(writer, "\t\tAccess: " + accessModifier); 171 | print(writer, "\t\tAbstract: " + abstractMethod); 172 | print(writer, "\t\tFinal: " + finalMethod); 173 | print(writer, "\t\tStatic: " + staticMethod); 174 | print(writer, "\t\tCalled methods: "); 175 | for(SM_Method method:getCalledMethods()) 176 | print(writer, "\t\t\t" + method.getName()); 177 | for (SM_Parameter param : parameterList) 178 | param.printDebugLog(writer); 179 | for (SM_LocalVar var : localVarList) 180 | var.printDebugLog(writer); 181 | print(writer, "\t\t----"); 182 | } 183 | 184 | //TODO: Modularize parser with private functions 185 | @Override 186 | public void parse() { 187 | prepareCalledMethodsList(); 188 | 189 | List variableList = methodDeclaration.parameters(); 190 | for (SingleVariableDeclaration var : variableList) { 191 | prepareParametersList(var); 192 | // parseParameters(); 193 | } 194 | 195 | prepareLocalVarList(); 196 | // parseLocalVar(); 197 | 198 | DirectAceessFieldVisitor directAceessFieldVisitor = new DirectAceessFieldVisitor(); 199 | methodDeclaration.accept(directAceessFieldVisitor); 200 | List names = directAceessFieldVisitor.getNames(); 201 | List thisAccesses = directAceessFieldVisitor.getThisAccesses(); 202 | if (names.size() > 0) { 203 | namesInMethod.addAll(names); 204 | } 205 | if (thisAccesses.size() > 0) { 206 | thisAccessesInMethod.addAll(thisAccesses); 207 | } 208 | prepareInstanceOfVisitorList(); 209 | 210 | ThrowVisitor throwVisithor = new ThrowVisitor(); 211 | methodDeclaration.accept(throwVisithor); 212 | throwsException = throwVisithor.throwsException(); 213 | } 214 | 215 | @Override 216 | public void resolve() { 217 | for (SM_Parameter param : parameterList) { 218 | param.resolve(); 219 | } 220 | for (SM_LocalVar localVar : localVarList) { 221 | localVar.resolve(); 222 | } 223 | calledMethodsList = (new Resolver()).inferCalledMethods(calledMethods, parentType); 224 | setReferencedTypes(); 225 | setDirectFieldAccesses(); 226 | setSMTypesInInstanceOf(); 227 | } 228 | 229 | private void setReferencedTypes() { 230 | for (SM_Parameter param : parameterList) { 231 | if (!param.isPrimitiveType()) { 232 | addunique(param.getType()); 233 | } 234 | } 235 | for (SM_LocalVar localVar : localVarList) { 236 | if (!localVar.isPrimitiveType()) { 237 | addunique(localVar.getType()); 238 | } 239 | } 240 | for (SM_Method methodCall : calledMethodsList) { 241 | if (methodCall.isStatic()) { 242 | addunique(methodCall.getParentType()); 243 | } 244 | } 245 | } 246 | 247 | private void setDirectFieldAccesses() { 248 | for (FieldAccess thisAccess : thisAccessesInMethod) { 249 | SM_Field sameField = getFieldWithSameName(thisAccess.getName().toString()); 250 | if (sameField != null && !directFieldAccesses.contains(sameField)) { 251 | directFieldAccesses.add(sameField); 252 | } 253 | } 254 | for (SimpleName name : namesInMethod) { 255 | if (!existsAsNameInLocalVars(name.toString())) { 256 | SM_Field sameField = getFieldWithSameName(name.toString()); 257 | if (sameField != null && !directFieldAccesses.contains(sameField)) { 258 | directFieldAccesses.add(sameField); 259 | } 260 | } 261 | } 262 | } 263 | 264 | private boolean existsAsNameInLocalVars(String name) { 265 | for (SM_LocalVar localVar : localVarList) { 266 | if (name.equals(localVar.getName())) { 267 | return true; 268 | } 269 | } 270 | return false; 271 | } 272 | 273 | private SM_Field getFieldWithSameName(String name) { 274 | for (SM_Field field : parentType.getFieldList()) { 275 | if (name.equals(field.getName())) { 276 | return field; 277 | } 278 | } 279 | return null; 280 | } 281 | 282 | private void setSMTypesInInstanceOf() { 283 | Resolver resolver = new Resolver(); 284 | for (Type type : typesInInstanceOf) { 285 | SM_Type smType = resolver.resolveType(type, parentType.getParentPkg().getParentProject()); 286 | if (smType != null && !smTypesInInstanceOf.contains(smType)) { 287 | smTypesInInstanceOf.add(smType); 288 | } 289 | } 290 | } 291 | 292 | private void addunique(SM_Type variableType) { 293 | if (!referencedTypeList.contains(variableType)) 294 | referencedTypeList.add(variableType); 295 | } 296 | 297 | public List getReferencedTypeList() { 298 | return referencedTypeList; 299 | } 300 | 301 | public List getDirectFieldAccesses() { 302 | return directFieldAccesses; 303 | } 304 | 305 | public List getSMTypesInInstanceOf() { 306 | return smTypesInInstanceOf; 307 | } 308 | 309 | } 310 | -------------------------------------------------------------------------------- /src/Designite/SourceModel/SM_Package.java: -------------------------------------------------------------------------------- 1 | package Designite.SourceModel; 2 | 3 | import java.io.File; 4 | import java.io.PrintWriter; 5 | import java.util.ArrayList; 6 | import java.util.HashMap; 7 | import java.util.List; 8 | import java.util.Map; 9 | 10 | import Designite.metrics.TypeMetricsExtractor; 11 | import org.eclipse.jdt.core.dom.CompilationUnit; 12 | 13 | import Designite.ArgumentParser.InputArgs; 14 | import Designite.metrics.TypeMetrics; 15 | import Designite.smells.designSmells.DesignSmellFacade; 16 | import Designite.smells.models.DesignCodeSmell; 17 | import Designite.utils.CSVUtils; 18 | import Designite.utils.Constants; 19 | import Designite.utils.models.Edge; 20 | 21 | public class SM_Package extends SM_SourceItem implements Parsable{ 22 | private List compilationUnitList; 23 | private List typeList = new ArrayList<>(); 24 | private SM_Project parentProject; 25 | private Map metricsMapping = new HashMap<>(); 26 | private Map> smellMapping = new HashMap<>(); 27 | private InputArgs inputArgs; 28 | 29 | public SM_Package(String packageName, SM_Project parentObj, InputArgs inputArgs) { 30 | name = packageName; 31 | compilationUnitList = new ArrayList(); 32 | parentProject = parentObj; 33 | this.inputArgs = inputArgs; 34 | } 35 | 36 | public SM_Project getParentProject() { 37 | return parentProject; 38 | } 39 | 40 | 41 | public List getCompilationUnitList() { 42 | return compilationUnitList; 43 | } 44 | 45 | 46 | public List getTypeList() { 47 | return typeList; 48 | } 49 | 50 | void addCompilationUnit(CompilationUnit unit) { 51 | compilationUnitList.add(unit); 52 | } 53 | 54 | private void addNestedClass(List list) { 55 | if (list.size() > 1) { 56 | for (int i = 1; i < list.size(); i++) { 57 | //SM_Type nested = list.get(i); 58 | //SM_Type outer = list.get(0); 59 | typeList.add(list.get(i)); 60 | list.get(0).addNestedClass(list.get(i)); 61 | list.get(i).setNestedClass(list.get(0).getTypeDeclaration()); 62 | } 63 | } 64 | } 65 | 66 | private void parseTypes(SM_Package parentPkg) { 67 | for (SM_Type type : typeList) { 68 | type.parse(); 69 | // System.out.println("Type : " + type.name + ", nested:: " + type.getNestedTypes()); 70 | } 71 | } 72 | 73 | @Override 74 | public void printDebugLog(PrintWriter writer) { 75 | print(writer, "Package: " + name); 76 | for (SM_Type type : typeList) { 77 | type.printDebugLog(writer); 78 | } 79 | print(writer, "----"); 80 | } 81 | 82 | @Override 83 | public void parse() { 84 | 85 | for (CompilationUnit unit : compilationUnitList) { 86 | /* 87 | * ImportVisitor importVisitor = new ImportVisitor(); 88 | * unit.accept(importVisitor); List importList = 89 | * importVisitor.getImports(); if (importList.size() > 0) 90 | * imports.addAll(importList); 91 | */ 92 | 93 | TypeVisitor visitor = new TypeVisitor(unit, this, inputArgs); 94 | unit.accept(visitor); 95 | List list = visitor.getTypeList(); 96 | if (list.size() > 0) { 97 | if (list.size() == 1) { 98 | typeList.addAll(list); // if the compilation unit contains 99 | // only one class; simpler case, 100 | // there is no nested classes 101 | } else { 102 | typeList.add(list.get(0)); 103 | // System.out.println("TypeList :: " + list); 104 | addNestedClass(list); 105 | } 106 | } 107 | } 108 | parseTypes(this); 109 | } 110 | 111 | @Override 112 | public void resolve() { 113 | for (SM_Type type : typeList) { 114 | type.resolve(); 115 | } 116 | } 117 | 118 | public void extractTypeMetrics() { 119 | for (SM_Type type : typeList) { 120 | type.extractMethodMetrics(); 121 | TypeMetrics metrics = new TypeMetricsExtractor(type).extractMetrics(); 122 | metricsMapping.put(type, metrics); 123 | exportMetricsToCSV(metrics, type.getName()); 124 | updateDependencyGraph(type); 125 | } 126 | } 127 | 128 | private void updateDependencyGraph(SM_Type type) { 129 | if (type.getReferencedTypeList().size() > 0) { 130 | for (SM_Type dependency : type.getReferencedTypeList()) { 131 | getParentProject().getHierarchyGraph().addEdge(new Edge(type, dependency)); 132 | } 133 | } 134 | getParentProject().getHierarchyGraph().addVertex(type); 135 | } 136 | 137 | public TypeMetrics getMetricsFromType(SM_Type type) { 138 | return metricsMapping.get(type); 139 | } 140 | 141 | private void exportMetricsToCSV(TypeMetrics metrics, String typeName) { 142 | String path = inputArgs.getOutputFolder() 143 | + File.separator + Constants.TYPE_METRICS_PATH_SUFFIX; 144 | CSVUtils.addToCSVFile(path, getMetricsAsARow(metrics, typeName)); 145 | } 146 | 147 | private String getMetricsAsARow(TypeMetrics metrics, String typeName) { 148 | return getParentProject().getName() 149 | + "," + getName() 150 | + "," + typeName 151 | + "," + metrics.getNumOfFields() 152 | + "," + metrics.getNumOfPublicFields() 153 | + "," + metrics.getNumOfMethods() 154 | + "," + metrics.getNumOfPublicMethods() 155 | + "," + metrics.getNumOfLines() 156 | + "," + metrics.getWeightedMethodsPerClass() 157 | + "," + metrics.getNumOfChildren() 158 | + "," + metrics.getInheritanceDepth() 159 | + "," + metrics.getLcom() 160 | + "," + metrics.getNumOfFanInTypes() 161 | + "," + metrics.getNumOfFanOutTypes() 162 | + "\n"; 163 | } 164 | 165 | public void extractCodeSmells() { 166 | for (SM_Type type : typeList) { 167 | DesignSmellFacade detector = new DesignSmellFacade(metricsMapping.get(type) 168 | , new SourceItemInfo(getParentProject().getName() 169 | , getName() 170 | , type.getName()) 171 | ); 172 | type.extractCodeSmells(); 173 | smellMapping.put(type, detector.detectCodeSmells()); 174 | exportDesignSmellsToCSV(type); 175 | } 176 | } 177 | 178 | private void exportDesignSmellsToCSV(SM_Type type) { 179 | CSVUtils.addAllToCSVFile(inputArgs.getOutputFolder() 180 | + File.separator + Constants.DESIGN_CODE_SMELLS_PATH_SUFFIX 181 | , smellMapping.get(type)); 182 | } 183 | 184 | } 185 | -------------------------------------------------------------------------------- /src/Designite/SourceModel/SM_Parameter.java: -------------------------------------------------------------------------------- 1 | package Designite.SourceModel; 2 | 3 | import java.io.PrintWriter; 4 | 5 | import org.eclipse.jdt.core.dom.SingleVariableDeclaration; 6 | import org.eclipse.jdt.core.dom.Type; 7 | 8 | public class SM_Parameter extends SM_EntitiesWithType { 9 | private SM_Method parentMethod; 10 | private SingleVariableDeclaration variableDecl; 11 | 12 | public SM_Parameter(SingleVariableDeclaration variable, SM_Method methodObj) { 13 | name = variable.getName().toString(); 14 | this.parentMethod = methodObj; 15 | variableDecl = variable; 16 | 17 | } 18 | 19 | void setParent(SM_Method parentMethod) { 20 | this.parentMethod = parentMethod; 21 | } 22 | 23 | public SM_Method getParent() { 24 | return parentMethod; 25 | } 26 | 27 | @Override 28 | public SM_Type getParentType() { 29 | return this.parentMethod.getParentType(); 30 | } 31 | 32 | @Override 33 | public void printDebugLog(PrintWriter writer) { 34 | print(writer, "\t\t\tParameter: " + name); 35 | print(writer, "\t\t\tParent Method: " + getParent().getName()); 36 | if (!isPrimitiveType() && getType() != null) 37 | print(writer, "\t\t\tParameter type: " + getType().getName()); 38 | else { 39 | print(writer, "\t\t\tPrimitive parameter type: " + getPrimitiveType()); 40 | } 41 | print(writer, "\t\t\t----"); 42 | } 43 | 44 | @Override 45 | public void resolve() { 46 | Resolver resolver = new Resolver(); 47 | typeInfo = resolver.resolveVariableType(variableDecl.getType(), parentMethod.getParentType().getParentPkg().getParentProject(), getParentType()); 48 | } 49 | 50 | public Type getTypeBinding() { 51 | return variableDecl.getType(); 52 | } 53 | 54 | @Override 55 | public String toString() { 56 | return "Parameter=" + name 57 | + ", type=" + getTypeBinding() 58 | + ", is=" + getTypeBinding().getNodeType(); 59 | } 60 | 61 | // @Override 62 | // public void parse() { 63 | // 64 | // } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/Designite/SourceModel/SM_Project.java: -------------------------------------------------------------------------------- 1 | package Designite.SourceModel; 2 | 3 | import java.io.File; 4 | import java.io.PrintWriter; 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | import java.util.Map; 8 | 9 | import Designite.utils.DJLogger; 10 | import Designite.utils.FileManager; 11 | import org.eclipse.jdt.core.JavaCore; 12 | import org.eclipse.jdt.core.dom.AST; 13 | import org.eclipse.jdt.core.dom.ASTParser; 14 | import org.eclipse.jdt.core.dom.CompilationUnit; 15 | import org.eclipse.jface.text.Document; 16 | 17 | import Designite.ArgumentParser.InputArgs; 18 | import Designite.utils.CSVUtils; 19 | import Designite.utils.models.Graph; 20 | 21 | public class SM_Project extends SM_SourceItem implements Parsable { 22 | 23 | private InputArgs inputArgs; 24 | private List sourceFileList; 25 | private List compilationUnitList; 26 | private List packageList; 27 | private Graph hierarchyGraph; 28 | private Graph dependencyGraph; 29 | private String unitName; 30 | 31 | public SM_Project(InputArgs argsObj) { 32 | this.inputArgs = argsObj; 33 | sourceFileList = new ArrayList(); 34 | compilationUnitList = new ArrayList(); 35 | packageList = new ArrayList(); 36 | hierarchyGraph = new Graph(); 37 | dependencyGraph = new Graph(); 38 | setName(this.inputArgs.getProjectName()); 39 | } 40 | 41 | public SM_Project() { 42 | sourceFileList = new ArrayList(); 43 | compilationUnitList = new ArrayList(); 44 | packageList = new ArrayList(); 45 | hierarchyGraph = new Graph(); 46 | dependencyGraph = new Graph(); 47 | setName(this.inputArgs.getProjectName()); 48 | } 49 | 50 | 51 | 52 | 53 | public void setName(String name) { 54 | this.name = name; 55 | } 56 | 57 | public List getSourceFileList() { 58 | return sourceFileList; 59 | } 60 | 61 | public void setCompilationUnitList(List list) { 62 | if (list == null) 63 | throw new NullPointerException(); 64 | compilationUnitList = list; 65 | } 66 | 67 | public List getCompilationUnitList() { 68 | return compilationUnitList; 69 | } 70 | 71 | public List getPackageList() { 72 | return packageList; 73 | } 74 | 75 | public int getPackageCount() { 76 | return packageList.size(); 77 | } 78 | 79 | // method used in tests 80 | public CompilationUnit createCU(String filePath) { 81 | String fileToString = FileManager.getInstance().readFileToString(filePath); 82 | int startingIndex = filePath.lastIndexOf(File.separatorChar); 83 | unitName = filePath.substring(startingIndex + 1); 84 | 85 | return createAST(fileToString, unitName); 86 | } 87 | 88 | private void parseAllPackages() { 89 | for (SM_Package pkg : packageList) { 90 | pkg.parse(); 91 | } 92 | } 93 | 94 | public Graph getHierarchyGraph() { 95 | return hierarchyGraph; 96 | } 97 | 98 | public Graph getDependencyGraph() { 99 | return dependencyGraph; 100 | } 101 | 102 | private void createPackageObjects() { 103 | checkNotNull(compilationUnitList); 104 | String packageName; 105 | for (CompilationUnit unit : compilationUnitList) { 106 | if (unit.getPackage() != null) { 107 | packageName = unit.getPackage().getName().toString(); 108 | } else { 109 | packageName = "(default package)"; 110 | } 111 | SM_Package pkgObj = searchPackage(packageName); 112 | // If pkgObj is null, package has not yet created 113 | if (pkgObj == null) { 114 | pkgObj = new SM_Package(packageName, this, inputArgs); 115 | packageList.add(pkgObj); 116 | } 117 | pkgObj.addCompilationUnit(unit); 118 | } 119 | } 120 | 121 | private void checkNotNull(List list) { 122 | if (list == null) { 123 | DJLogger.log("Application couldn't find any source code files in the specified path."); 124 | System.exit(1); 125 | DJLogger.log("Quitting.."); 126 | } 127 | } 128 | 129 | private SM_Package searchPackage(String packageName) { 130 | for (SM_Package pkg : packageList) { 131 | if (pkg.getName().equals(packageName)) 132 | return pkg; 133 | } 134 | return null; 135 | } 136 | 137 | private void createCompilationUnits() { 138 | try { 139 | sourceFileList = FileManager.getInstance().listFiles(inputArgs.getSourceFolder()); 140 | for (String file : sourceFileList) { 141 | String fileToString = FileManager.getInstance().readFileToString(file); 142 | int startingIndex = file.lastIndexOf(File.separatorChar); 143 | unitName = file.substring(startingIndex + 1); 144 | CompilationUnit unit = createAST(fileToString, unitName); 145 | if (unit != null) 146 | compilationUnitList.add(unit); 147 | } 148 | } catch (NullPointerException e) { 149 | e.printStackTrace(); 150 | } 151 | } 152 | 153 | private CompilationUnit createAST(final String content, String unitName) { 154 | Document doc = new Document(content); 155 | final ASTParser parser = ASTParser.newParser(AST.JLS8); 156 | parser.setResolveBindings(true); 157 | parser.setKind(ASTParser.K_COMPILATION_UNIT); 158 | parser.setBindingsRecovery(true); 159 | parser.setStatementsRecovery(true); 160 | parser.setUnitName(unitName); 161 | Map options = JavaCore.getOptions(); 162 | JavaCore.setComplianceOptions(JavaCore.VERSION_1_8, options); 163 | parser.setCompilerOptions(options); 164 | String[] sources = { inputArgs.getSourceFolder() }; 165 | parser.setEnvironment(null, sources, null, true); 166 | parser.setSource(doc.get().toCharArray()); 167 | 168 | CompilationUnit cu = null; 169 | try { 170 | cu = (CompilationUnit) parser.createAST(null); 171 | } catch (NullPointerException ex) { 172 | // Consume it. 173 | // In some rare situations, the above statement in try block results in a 174 | // NullPointer exception. 175 | // I tried to figure out but it seems it is coming from the parser library. 176 | // Hence, leaving it silently. 177 | } 178 | if (cu != null) 179 | if (!cu.getAST().hasBindingsRecovery()) { 180 | System.out.println("Binding not activated."); 181 | } 182 | 183 | return cu; 184 | } 185 | 186 | // TODO : Duplicate code found in FileManager. 187 | // VIOLATION: Single Responsibility 188 | // private void getFileList(String path) { 189 | // File root = new File(path); 190 | // File[] list = root.listFiles(); 191 | // 192 | // if (list == null) 193 | // return; 194 | // for (File f : list) { 195 | // if (f.isDirectory()) { 196 | // getFileList(f.getAbsolutePath()); 197 | // } else { 198 | // 199 | // if (f.getName().endsWith(".java")) 200 | // sourceFileList.add(f.getAbsolutePath()); 201 | // } 202 | // } 203 | // return; 204 | // } 205 | 206 | // VIOLATION: Single Responsibility 207 | // private String readFileToString(String sourcePath) { 208 | // try { 209 | // return new String(Files.readAllBytes(Paths.get(sourcePath))); 210 | // } catch (IOException e) { 211 | // e.printStackTrace(); 212 | // return new String(); 213 | // } 214 | // } 215 | 216 | @Override 217 | public void printDebugLog(PrintWriter writer) { 218 | print(writer, "Project: " + name); 219 | print(writer, "-------------------"); 220 | for (SM_Package pkg : packageList) { 221 | pkg.printDebugLog(writer); 222 | } 223 | } 224 | 225 | @Override 226 | public void parse() { 227 | DJLogger.log("Parsing the source code ..."); 228 | createCompilationUnits(); 229 | createPackageObjects(); 230 | parseAllPackages(); 231 | } 232 | 233 | public void resolve() { 234 | DJLogger.log("Resolving symbols..."); 235 | for (SM_Package pkg : packageList) { 236 | pkg.resolve(); 237 | } 238 | hierarchyGraph.computeConnectedComponents(); 239 | dependencyGraph.computeStronglyConnectedComponents(); 240 | } 241 | 242 | public void computeMetrics() { 243 | DJLogger.log("Extracting metrics..."); 244 | CSVUtils.initializeCSVDirectory(name, inputArgs.getOutputFolder()); 245 | for (SM_Package pkg : packageList) { 246 | pkg.extractTypeMetrics(); 247 | } 248 | } 249 | 250 | public void detectCodeSmells() { 251 | DJLogger.log("Extracting code smells..."); 252 | for (SM_Package pkg : packageList) { 253 | pkg.extractCodeSmells(); 254 | } 255 | } 256 | 257 | } 258 | -------------------------------------------------------------------------------- /src/Designite/SourceModel/SM_SourceItem.java: -------------------------------------------------------------------------------- 1 | package Designite.SourceModel; 2 | 3 | import java.lang.reflect.Modifier; 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | import java.io.PrintWriter; 7 | 8 | public abstract class SM_SourceItem { 9 | protected String name; 10 | protected AccessStates accessModifier; 11 | // protected SM_SourceItem getParentInfo(); 12 | 13 | /** 14 | * This method prints the whole source code model For debugging purposes 15 | * only 16 | */ 17 | public abstract void printDebugLog(PrintWriter writer); 18 | 19 | /** 20 | * This is the first pass of parsing a source code entity. 21 | */ 22 | // public abstract void parse(); 23 | 24 | /** 25 | * This method establishes relationships among source-code entities. Such 26 | * relationships include variable types, super/sub types, etc. 27 | */ 28 | public abstract void resolve(); 29 | 30 | public String getName() { 31 | return name; 32 | } 33 | 34 | public AccessStates getAccessModifier() { 35 | return accessModifier; 36 | } 37 | 38 | // TODO check default case 39 | void setAccessModifier(int modifier) { 40 | if (Modifier.isPublic(modifier)) 41 | accessModifier = AccessStates.PUBLIC; 42 | else if (Modifier.isProtected(modifier)) 43 | accessModifier = AccessStates.PROTECTED; 44 | else if (Modifier.isPrivate(modifier)) 45 | accessModifier = AccessStates.PRIVATE; 46 | else 47 | accessModifier = AccessStates.DEFAULT; 48 | } 49 | 50 | protected SM_Type findType(SM_Project parentProject, String typeName, String pkgName) { 51 | for (SM_Package pkg:parentProject.getPackageList()) 52 | if (pkg.getName().equals(pkgName)) 53 | { 54 | for(SM_Type type:pkg.getTypeList()) 55 | if(type.getName().equals(typeName)) 56 | return type; 57 | } 58 | return null; 59 | } 60 | List getTypesOfProject(SM_Project project) { 61 | List pkgList = new ArrayList<>(); 62 | List typeList = new ArrayList<>(); 63 | 64 | pkgList.addAll(project.getPackageList()); 65 | for (SM_Package pkg : pkgList) 66 | typeList.addAll(pkg.getTypeList()); 67 | 68 | return typeList; 69 | } 70 | 71 | List getMethodsOfProject(SM_Project project) { 72 | List typeList = new ArrayList<>(); 73 | List methodList = new ArrayList<>(); 74 | 75 | typeList.addAll(getTypesOfProject(project)); 76 | for (SM_Type type : typeList) 77 | methodList.addAll(type.getMethodList()); 78 | 79 | return methodList; 80 | } 81 | 82 | List getMethodsOfPkg(SM_Package pkg) { 83 | List typeList = new ArrayList<>(); 84 | List methodList = new ArrayList<>(); 85 | 86 | typeList.addAll(pkg.getTypeList()); 87 | for (SM_Type type : typeList) 88 | methodList.addAll(type.getMethodList()); 89 | 90 | return methodList; 91 | } 92 | 93 | void print(PrintWriter writer, String str) { 94 | if (writer != null) 95 | { 96 | writer.println(str); 97 | writer.flush(); 98 | } 99 | else 100 | System.out.println(str); 101 | } 102 | 103 | protected String convertListToString(List typeList) { 104 | String result = ""; 105 | for (SM_Type type : typeList) 106 | if(result.equals("")) 107 | result = type.getName(); 108 | else 109 | result += ", " + type.getName(); 110 | return null; 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /src/Designite/SourceModel/SourceItemInfo.java: -------------------------------------------------------------------------------- 1 | package Designite.SourceModel; 2 | 3 | public class SourceItemInfo { 4 | 5 | private String projectName; 6 | private String packageName; 7 | private String typeName; 8 | private String methodName; 9 | 10 | public SourceItemInfo(String projectName 11 | , String packageName) { 12 | this.projectName = projectName; 13 | this.packageName = packageName; 14 | } 15 | 16 | public SourceItemInfo(String projectName 17 | , String packageName 18 | , String typeName) { 19 | this(projectName, packageName); 20 | this.typeName = typeName; 21 | } 22 | 23 | public SourceItemInfo(String projectName 24 | , String packageName 25 | , String typeName 26 | , String methodName) { 27 | this(projectName, packageName, typeName); 28 | this.methodName = methodName; 29 | } 30 | 31 | public String getProjectName() { 32 | return projectName; 33 | } 34 | 35 | public String getPackageName() { 36 | return packageName; 37 | } 38 | 39 | public String getTypeName() { 40 | return typeName; 41 | } 42 | 43 | public String getMethodName() { 44 | return methodName; 45 | } 46 | 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/Designite/SourceModel/TypeInfo.java: -------------------------------------------------------------------------------- 1 | package Designite.SourceModel; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | public class TypeInfo { 7 | 8 | private SM_Type typeObj; 9 | private boolean primitiveType; 10 | private String objPrimitiveType; 11 | private boolean parametrizedType; 12 | private List nonPrimitiveTypeParameters = new ArrayList<>(); 13 | 14 | private static final int COMMA_LENGTH = 2; 15 | 16 | public SM_Type getTypeObj() { 17 | return typeObj; 18 | } 19 | 20 | public void setTypeObj(SM_Type typeObj) { 21 | this.typeObj = typeObj; 22 | } 23 | 24 | public boolean isPrimitiveType() { 25 | return primitiveType; 26 | } 27 | 28 | public void setPrimitiveType(boolean primitiveType) { 29 | this.primitiveType = primitiveType; 30 | } 31 | 32 | public String getObjPrimitiveType() { 33 | return objPrimitiveType; 34 | } 35 | 36 | public void setObjPrimitiveType(String objType) { 37 | this.objPrimitiveType = objType; 38 | } 39 | 40 | public boolean isParametrizedType() { 41 | return parametrizedType; 42 | } 43 | 44 | public void setParametrizedType(boolean parametrizedType) { 45 | this.parametrizedType = parametrizedType; 46 | } 47 | 48 | public List getNonPrimitiveTypeParameters() { 49 | return nonPrimitiveTypeParameters; 50 | } 51 | 52 | public String getStringOfNonPrimitiveParameters() { 53 | String output = "["; 54 | for (SM_Type type : nonPrimitiveTypeParameters) { 55 | output += type.getName() + ", "; 56 | } 57 | return removeLastComma(output) + "]"; 58 | } 59 | 60 | private String removeLastComma(String str) { 61 | return (str.length() > COMMA_LENGTH) ? str.substring(0, str.length() - COMMA_LENGTH) : str; 62 | } 63 | 64 | public int getNumOfNonPrimitiveParameters() { 65 | return getNonPrimitiveTypeParameters().size(); 66 | } 67 | 68 | public void addNonPrimitiveTypeParameter(SM_Type element) { 69 | nonPrimitiveTypeParameters.add(element); 70 | } 71 | 72 | @Override 73 | public String toString() { 74 | return "TypeInfo [typeObj=" + typeObj + ", primitiveType=" + primitiveType + ", objPrimitiveType=" + objPrimitiveType 75 | + ", parametrizedType=" + parametrizedType + ", nonPrimitiveTypeParameters=" 76 | + getStringOfNonPrimitiveParameters() + "]"; 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /src/Designite/SourceModel/TypeVisitor.java: -------------------------------------------------------------------------------- 1 | package Designite.SourceModel; 2 | 3 | import org.eclipse.jdt.core.dom.ASTVisitor; 4 | import org.eclipse.jdt.core.dom.CompilationUnit; 5 | import org.eclipse.jdt.core.dom.TypeDeclaration; 6 | 7 | import Designite.ArgumentParser.InputArgs; 8 | 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | 12 | public class TypeVisitor extends ASTVisitor{ 13 | private List types = new ArrayList(); 14 | private List typeDeclarationList = new ArrayList(); 15 | private CompilationUnit compilationUnit; 16 | private SM_Type newType; 17 | private SM_Package pkgObj; 18 | private InputArgs inputArgs; 19 | 20 | public TypeVisitor(CompilationUnit cu, SM_Package pkgObj, InputArgs inputArgs) { 21 | super(); 22 | this.compilationUnit = cu; 23 | this.pkgObj = pkgObj; 24 | this.inputArgs = inputArgs; 25 | } 26 | 27 | @Override 28 | public boolean visit(TypeDeclaration typeDeclaration){ 29 | typeDeclarationList.add(typeDeclaration); 30 | newType = new SM_Type(typeDeclaration, compilationUnit, pkgObj, inputArgs); 31 | types.add(newType); 32 | 33 | return super.visit(typeDeclaration); 34 | } 35 | 36 | public SM_Type getType() { 37 | return newType; 38 | } 39 | 40 | public List getTypeList() { 41 | return types; 42 | } 43 | 44 | public List getTypeDeclarationList() { 45 | return typeDeclarationList; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Designite/SourceModel/VariableVisitor.java: -------------------------------------------------------------------------------- 1 | package Designite.SourceModel; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import org.eclipse.jdt.core.dom.ASTVisitor; 7 | import org.eclipse.jdt.core.dom.SingleVariableDeclaration; 8 | 9 | public class VariableVisitor extends ASTVisitor { 10 | List parameters = new ArrayList(); 11 | private SM_Method parentMethod; 12 | 13 | public VariableVisitor(SM_Method methodObj) { 14 | super(); 15 | this.parentMethod = methodObj; 16 | } 17 | 18 | @Override 19 | public boolean visit(SingleVariableDeclaration variable) { 20 | SM_Parameter newParameter = new SM_Parameter(variable, parentMethod); 21 | parameters.add(newParameter); 22 | 23 | return super.visit(variable); 24 | } 25 | 26 | public List getParameterList() { 27 | return parameters; 28 | } 29 | 30 | /*public int countParameters() { 31 | return parameters.size(); 32 | }*/ 33 | } 34 | -------------------------------------------------------------------------------- /src/Designite/metrics/MethodMetrics.java: -------------------------------------------------------------------------------- 1 | package Designite.metrics; 2 | 3 | import java.util.List; 4 | 5 | import Designite.SourceModel.SM_Field; 6 | import Designite.SourceModel.SM_Method; 7 | import Designite.SourceModel.SM_Type; 8 | 9 | public class MethodMetrics extends Metrics { 10 | 11 | private int numOfParameters; 12 | private int cyclomaticComplexity; 13 | private int numOfLines; 14 | private SM_Method method; 15 | 16 | public int getNumOfParameters() { 17 | return numOfParameters; 18 | } 19 | 20 | public int getCyclomaticComplexity() { 21 | return cyclomaticComplexity; 22 | } 23 | 24 | public int getNumOfLines() { 25 | return numOfLines; 26 | } 27 | 28 | public void setNumOfParameters(int numOfParameters) { 29 | this.numOfParameters = numOfParameters; 30 | } 31 | 32 | public void setCyclomaticComplexity(int cyclomaticComplexity) { 33 | this.cyclomaticComplexity = cyclomaticComplexity; 34 | } 35 | 36 | public void setNumOfLines(int numOfLines) { 37 | this.numOfLines = numOfLines; 38 | } 39 | 40 | public void setMethod(SM_Method method){ 41 | this.method = method; 42 | } 43 | 44 | public SM_Method getMethod() { 45 | return method; 46 | } 47 | 48 | public List getDirectFieldAccesses() { 49 | return method.getDirectFieldAccesses(); 50 | } 51 | 52 | public List getSMTypesInInstanceOf() { 53 | return method.getSMTypesInInstanceOf(); 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/Designite/metrics/MethodMetricsExtractor.java: -------------------------------------------------------------------------------- 1 | package Designite.metrics; 2 | 3 | import Designite.SourceModel.SM_Method; 4 | import Designite.SourceModel.SM_Type; 5 | import Designite.visitors.MethodControlFlowVisitor; 6 | 7 | import java.util.List; 8 | 9 | public class MethodMetricsExtractor implements MetricExtractor{ 10 | 11 | private SM_Method method; 12 | private MethodMetrics methodMetrics; 13 | 14 | public MethodMetricsExtractor(SM_Method method) { 15 | this.method = method; 16 | } 17 | 18 | @Override 19 | public MethodMetrics extractMetrics() { 20 | methodMetrics = new MethodMetrics(); 21 | extractNumOfParametersMetrics(); 22 | extractCyclomaticComplexity(); 23 | extractNumberOfLines(); 24 | methodMetrics.setMethod(method); 25 | return methodMetrics; 26 | } 27 | 28 | 29 | private void extractNumOfParametersMetrics() { 30 | methodMetrics.setNumOfParameters(method.getParameterList().size()); 31 | } 32 | 33 | private void extractCyclomaticComplexity() { 34 | methodMetrics.setCyclomaticComplexity(calculateCyclomaticComplexity()); 35 | } 36 | 37 | private int calculateCyclomaticComplexity() { 38 | MethodControlFlowVisitor visitor = new MethodControlFlowVisitor(); 39 | method.getMethodDeclaration().accept(visitor); 40 | return visitor.getNumOfIfStatements() 41 | + visitor.getNumOfSwitchCaseStatementsWitoutDefault() 42 | + visitor.getNumOfForStatements() 43 | + visitor.getNumOfWhileStatements() 44 | + visitor.getNumOfDoStatements() 45 | + visitor.getNumOfForeachStatements() 46 | + 1; 47 | } 48 | 49 | private void extractNumberOfLines() { 50 | if (methodHasBody()) { 51 | String body = method.getMethodDeclaration().getBody().toString(); 52 | int length = body.length(); 53 | // long newlines = body.lines().count(); 54 | methodMetrics.setNumOfLines(length - body.replace("\n", "").length()); 55 | } 56 | } 57 | 58 | private boolean methodHasBody() { 59 | return method.getMethodDeclaration().getBody() != null; 60 | } 61 | 62 | 63 | 64 | 65 | } 66 | -------------------------------------------------------------------------------- /src/Designite/metrics/MetricExtractor.java: -------------------------------------------------------------------------------- 1 | package Designite.metrics; 2 | 3 | public interface MetricExtractor { 4 | 5 | Metrics extractMetrics(); 6 | } 7 | -------------------------------------------------------------------------------- /src/Designite/metrics/Metrics.java: -------------------------------------------------------------------------------- 1 | package Designite.metrics; 2 | 3 | public class Metrics { 4 | } 5 | -------------------------------------------------------------------------------- /src/Designite/metrics/TypeMetrics.java: -------------------------------------------------------------------------------- 1 | package Designite.metrics; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import Designite.SourceModel.AccessStates; 7 | import Designite.SourceModel.SM_Field; 8 | import Designite.SourceModel.SM_Method; 9 | import Designite.SourceModel.SM_Type; 10 | 11 | import Designite.utils.models.Edge; 12 | import Designite.utils.models.Graph; 13 | import Designite.utils.models.Vertex; 14 | 15 | public class TypeMetrics extends Metrics{ 16 | 17 | private int numOfFields; 18 | private int numOfPublicFields; 19 | private int numOfMethods; 20 | private int numOfPublicMethods; 21 | private int depthOfInheritance; 22 | private int numOfLines; 23 | private int numOfChildren; 24 | private int weightedMethodsPerClass; 25 | private int numOfFanOutTypes; 26 | private int numOfFanInTypes; 27 | private double lcom; 28 | private SM_Type type; 29 | 30 | public void setNumOfFields(int numOfFields) { 31 | this.numOfFields = numOfFields; 32 | } 33 | 34 | public void setNumOfPublicFields(int numOfPublicFields) { 35 | this.numOfPublicFields = numOfPublicFields; 36 | } 37 | 38 | public void setNumOfMethods(int numOfMethods) { 39 | this.numOfMethods = numOfMethods; 40 | } 41 | 42 | public void setNumOfPublicMethods(int numOfPublicMethods) { 43 | this.numOfPublicMethods = numOfPublicMethods; 44 | } 45 | 46 | public void setDepthOfInheritance(int depthOfInheritance) { 47 | this.depthOfInheritance = depthOfInheritance; 48 | } 49 | 50 | public void setNumOfLines(int numOfLines) { 51 | this.numOfLines = numOfLines; 52 | } 53 | 54 | public void setNumOfChildren(int numOfChildren) { 55 | this.numOfChildren = numOfChildren; 56 | } 57 | 58 | public void setWeightedMethodsPerClass(int weightedMethodsPerClass) { 59 | this.weightedMethodsPerClass = weightedMethodsPerClass; 60 | } 61 | 62 | public void setNumOfFanOutTypes(int numOfFanOutTypes) { 63 | this.numOfFanOutTypes = numOfFanOutTypes; 64 | } 65 | 66 | public void setNumOfFanInTypes(int numOfFanInTypes) { 67 | this.numOfFanInTypes = numOfFanInTypes; 68 | } 69 | 70 | public void setLcom(double lcom) { 71 | this.lcom = lcom; 72 | } 73 | 74 | public int getNumOfFields() { 75 | return numOfFields; 76 | } 77 | 78 | public int getNumOfPublicFields() { 79 | return numOfPublicFields; 80 | } 81 | 82 | public int getNumOfMethods() { 83 | return numOfMethods; 84 | } 85 | 86 | public int getNumOfPublicMethods() { 87 | return numOfPublicMethods; 88 | } 89 | 90 | public int getInheritanceDepth() { 91 | return depthOfInheritance; 92 | } 93 | 94 | public int getNumOfLines() { 95 | return numOfLines; 96 | } 97 | 98 | public int getNumOfChildren() { 99 | return numOfChildren; 100 | } 101 | 102 | public int getWeightedMethodsPerClass() { 103 | return weightedMethodsPerClass; 104 | } 105 | 106 | public int getNumOfFanOutTypes() { 107 | return numOfFanOutTypes; 108 | } 109 | 110 | public int getNumOfFanInTypes() { 111 | return numOfFanInTypes; 112 | } 113 | 114 | public double getLcom() { 115 | return lcom; 116 | } 117 | public SM_Type getType() { 118 | return type; 119 | } 120 | public void setType(SM_Type type){ 121 | this.type = type; 122 | } 123 | 124 | } 125 | -------------------------------------------------------------------------------- /src/Designite/metrics/TypeMetricsExtractor.java: -------------------------------------------------------------------------------- 1 | package Designite.metrics; 2 | 3 | import Designite.SourceModel.AccessStates; 4 | import Designite.SourceModel.SM_Field; 5 | import Designite.SourceModel.SM_Method; 6 | import Designite.SourceModel.SM_Type; 7 | import Designite.utils.models.Edge; 8 | import Designite.utils.models.Graph; 9 | import Designite.utils.models.Vertex; 10 | 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | 14 | public class TypeMetricsExtractor implements MetricExtractor{ 15 | 16 | private SM_Type type; 17 | 18 | private Graph graph; 19 | 20 | private TypeMetrics typeMetrics; 21 | 22 | public TypeMetricsExtractor(SM_Type type){ 23 | this.type = type; 24 | } 25 | 26 | @Override 27 | public TypeMetrics extractMetrics() { 28 | typeMetrics = new TypeMetrics(); 29 | extractNumOfFieldMetrics(); 30 | extractNumOfMethodsMetrics(); 31 | extractDepthOfInheritance(); 32 | extractNumberOfLines(); 33 | extractNumberOfChildren(); 34 | extractWeightedMethodsPerClass(); 35 | extractNumOfFanOutTypes(); 36 | extractNumOfFanInTypes(); 37 | extractLCOM(); 38 | typeMetrics.setType(this.type); 39 | return typeMetrics; 40 | } 41 | 42 | private void extractNumOfFieldMetrics() { 43 | for (SM_Field field : type.getFieldList()) { 44 | typeMetrics.setNumOfFields(typeMetrics.getNumOfFields()+1); 45 | if (field.getAccessModifier() == AccessStates.PUBLIC) { 46 | // do not calculate fields that belong to a nested class with a stricter access modifier 47 | SM_Type nestedParent = field.getNestedParent(); 48 | if(nestedParent != null && nestedParent.getAccessModifier() != AccessStates.PUBLIC) { 49 | continue; 50 | } 51 | typeMetrics.setNumOfPublicFields(typeMetrics.getNumOfPublicFields()+1); 52 | } 53 | } 54 | } 55 | 56 | private void extractNumOfMethodsMetrics() { 57 | for (SM_Method method : type.getMethodList()) { 58 | typeMetrics.setNumOfMethods(typeMetrics.getNumOfMethods()+1); 59 | if (method.getAccessModifier() == AccessStates.PUBLIC) { 60 | typeMetrics.setNumOfPublicMethods(typeMetrics.getNumOfPublicMethods()+1); 61 | } 62 | } 63 | } 64 | 65 | private void extractDepthOfInheritance() { 66 | int depthOfInheritance = typeMetrics.getInheritanceDepth(); 67 | depthOfInheritance += findInheritanceDepth(type.getSuperTypes()); 68 | typeMetrics.setDepthOfInheritance(depthOfInheritance); 69 | } 70 | 71 | private void extractNumberOfLines() { 72 | String body = type.getTypeDeclaration().toString(); 73 | typeMetrics.setNumOfLines(body.length() - body.replace("\n", "").length()); 74 | } 75 | 76 | private void extractNumberOfChildren() { 77 | typeMetrics.setNumOfChildren(type.getSubTypes().size()); 78 | } 79 | 80 | private int findInheritanceDepth(List superTypes) { 81 | if (superTypes.size() == 0) { 82 | return 0; 83 | } 84 | List deeperSuperTypes = new ArrayList<>(); 85 | for (SM_Type superType : superTypes) { 86 | deeperSuperTypes.addAll(superType.getSuperTypes()); 87 | } 88 | // FIXME : switch to iterative process to avoid stack overflows 89 | try { 90 | return findInheritanceDepth(deeperSuperTypes) + 1; 91 | } catch (StackOverflowError ex) { 92 | System.err.println("Inheritance depth analysis step skipped due to memory overflow."); 93 | return 0; 94 | } 95 | } 96 | 97 | private void extractWeightedMethodsPerClass() { 98 | int weightedMethodsPerClass = typeMetrics.getWeightedMethodsPerClass(); 99 | for (SM_Method method : type.getMethodList()) { 100 | weightedMethodsPerClass += type.getMetricsFromMethod(method).getCyclomaticComplexity(); 101 | } 102 | typeMetrics.setWeightedMethodsPerClass(weightedMethodsPerClass); 103 | } 104 | 105 | private void extractNumOfFanOutTypes() { 106 | int numOfFanOutTypes = typeMetrics.getNumOfFanOutTypes(); 107 | numOfFanOutTypes += type.getReferencedTypeList().size(); 108 | typeMetrics.setNumOfFanOutTypes(numOfFanOutTypes); 109 | } 110 | 111 | private void extractNumOfFanInTypes() { 112 | int numOfFanInTypes = typeMetrics.getNumOfFanInTypes(); 113 | numOfFanInTypes += type.getTypesThatReferenceThis().size(); 114 | typeMetrics.setNumOfFanInTypes(numOfFanInTypes); 115 | } 116 | 117 | private void extractLCOM() { 118 | if (isNotLcomComputable()) { 119 | typeMetrics.setLcom(-1.0); 120 | return; 121 | } 122 | initializeGraph(); 123 | typeMetrics.setLcom(computeLCOM()); 124 | 125 | } 126 | 127 | private boolean isNotLcomComputable() { 128 | return type.isInterface() 129 | || type.getFieldList().size() == 0 130 | || type.getMethodList().size() == 0; 131 | } 132 | 133 | private void initializeGraph() { 134 | initializeVertices(); 135 | initializeEdges(); 136 | } 137 | 138 | private void initializeVertices() { 139 | //List vertices = new ArrayList<>(); 140 | graph = new Graph(); 141 | for (SM_Method method : type.getMethodList()) { 142 | graph.addVertex(method); 143 | } 144 | for (SM_Field field : type.getFieldList()) { 145 | graph.addVertex(field); 146 | } 147 | } 148 | 149 | private void initializeEdges() { 150 | for (SM_Method method : type.getMethodList()) { 151 | addAdjacentFields(method); 152 | addAdjacentMethods(method); 153 | } 154 | } 155 | 156 | private void addAdjacentFields(SM_Method method) { 157 | for (SM_Field fieldVertex : method.getDirectFieldAccesses()) { 158 | graph.addEdge(new Edge(method, fieldVertex)); 159 | } 160 | } 161 | 162 | private void addAdjacentMethods(SM_Method method) { 163 | for (SM_Method methodVertex : type.getMethodList()) { 164 | if (!method.equals(methodVertex) && method.getCalledMethods().contains(methodVertex)) { 165 | graph.addEdge(new Edge(method, methodVertex)); 166 | } 167 | } 168 | } 169 | 170 | private double computeLCOM() { 171 | graph.computeConnectedComponents(); 172 | List> nonSingleElementFieldComponents = getNonSingleElementFieldComponents(); 173 | if (nonSingleElementFieldComponents.size() > 1) { 174 | return ((double) getNonSingleElementFieldComponents().size()) / type.getMethodList().size(); 175 | } 176 | return 0.0; 177 | } 178 | 179 | private List> getNonSingleElementFieldComponents() { 180 | List> cleanComponents = new ArrayList<>();; 181 | for (List component : graph.getConnectedComponnents()) { 182 | if (component.size() != 1 || !(component.get(0) instanceof SM_Field)) { 183 | cleanComponents.add(component); 184 | } 185 | } 186 | return cleanComponents; 187 | } 188 | 189 | } 190 | -------------------------------------------------------------------------------- /src/Designite/smells/ThresholdsDTO.java: -------------------------------------------------------------------------------- 1 | package Designite.smells; 2 | 3 | public class ThresholdsDTO { 4 | 5 | private int complexCondition = 3; 6 | private int complexMethod = 8; 7 | private int longIdentifier = 30; 8 | private int longMethod = 100; 9 | private int longParameterList = 5; 10 | private int longStatement = 120; 11 | 12 | private int imperativeAbstractionLargeNumOfLines = 50; 13 | private double multifacetedAbstractionLargeLCOM = 0.8; 14 | private int multifacetedAbstractionManyFields = 7; 15 | private int multifacetedAbstractionManyMethods = 7; 16 | private int unnecessaryAbstractionFewFields = 5; 17 | 18 | private int deepHierarchy = 6; 19 | private int wideHierarchy = 10; 20 | 21 | private int brokenModularizationLargeFieldSet = 5; 22 | private int hubLikeModularizationLargeFanIn = 20; 23 | private int hubLikeModularizationLargeFanOut = 20; 24 | private int insufficientModularizationLargePublicInterface = 20; 25 | private int insufficientModularizationLargeNumOfMethods = 30; 26 | private int insufficientModularizationHighComplexity = 100; 27 | 28 | public int getComplexCondition() { 29 | return complexCondition; 30 | } 31 | 32 | public void setComplexCondition(int complexCondition) { 33 | this.complexCondition = complexCondition; 34 | } 35 | 36 | public int getComplexMethod() { 37 | return complexMethod; 38 | } 39 | 40 | public void setComplexMethod(int complexMethod) { 41 | this.complexMethod = complexMethod; 42 | } 43 | 44 | public int getLongIdentifier() { 45 | return longIdentifier; 46 | } 47 | 48 | public void setLongIdentifier(int longIdentifier) { 49 | this.longIdentifier = longIdentifier; 50 | } 51 | 52 | public int getLongMethod() { 53 | return longMethod; 54 | } 55 | 56 | public void setLongMethod(int longMethod) { 57 | this.longMethod = longMethod; 58 | } 59 | 60 | public int getLongParameterList() { 61 | return longParameterList; 62 | } 63 | 64 | public void setLongParameterList(int longParameterList) { 65 | this.longParameterList = longParameterList; 66 | } 67 | 68 | public void setLongStatement(int longStatement) { 69 | this.longStatement = longStatement; 70 | } 71 | 72 | public int getLongStatement() { 73 | return this.longStatement; 74 | } 75 | 76 | public int getImperativeAbstractionLargeNumOfLines() { 77 | return imperativeAbstractionLargeNumOfLines; 78 | } 79 | 80 | public void setImperativeAbstractionLargeNumOfLines(int imperativeAbstractionLargeNumOfLines) { 81 | this.imperativeAbstractionLargeNumOfLines = imperativeAbstractionLargeNumOfLines; 82 | } 83 | 84 | public double getMultifacetedAbstractionLargeLCOM() { 85 | return multifacetedAbstractionLargeLCOM; 86 | } 87 | 88 | public void setMultifacetedAbstractionLargeLCOM(double multifacetedAbstractionLargeLCOM) { 89 | this.multifacetedAbstractionLargeLCOM = multifacetedAbstractionLargeLCOM; 90 | } 91 | 92 | public int getMultifacetedAbstractionManyFields() { 93 | return multifacetedAbstractionManyFields; 94 | } 95 | 96 | public void setMultifacetedAbstractionManyFields(int multifacetedAbstractionManyFields) { 97 | this.multifacetedAbstractionManyFields = multifacetedAbstractionManyFields; 98 | } 99 | 100 | public int getMultifacetedAbstractionManyMethods() { 101 | return multifacetedAbstractionManyMethods; 102 | } 103 | 104 | public void setMultifacetedAbstractionManyMethods(int multifacetedAbstractionManyMethods) { 105 | this.multifacetedAbstractionManyMethods = multifacetedAbstractionManyMethods; 106 | } 107 | 108 | public int getUnnecessaryAbstractionFewFields() { 109 | return unnecessaryAbstractionFewFields; 110 | } 111 | 112 | public void setUnnecessaryAbstractionFewFields(int unnecessaryAbstractionFewFields) { 113 | this.unnecessaryAbstractionFewFields = unnecessaryAbstractionFewFields; 114 | } 115 | 116 | public int getDeepHierarchy() { 117 | return deepHierarchy; 118 | } 119 | 120 | public void setDeepHierarchy(int deepHierarchy) { 121 | this.deepHierarchy = deepHierarchy; 122 | } 123 | 124 | public int getWideHierarchy() { 125 | return wideHierarchy; 126 | } 127 | 128 | public void setWideHierarchy(int wideHierarchy) { 129 | this.wideHierarchy = wideHierarchy; 130 | } 131 | 132 | public int getBrokenModularizationLargeFieldSet() { 133 | return brokenModularizationLargeFieldSet; 134 | } 135 | 136 | public void setBrokenModularizationLargeFieldSet(int brokenModularizationLargeFieldSet) { 137 | this.brokenModularizationLargeFieldSet = brokenModularizationLargeFieldSet; 138 | } 139 | 140 | public int getHubLikeModularizationLargeFanIn() { 141 | return hubLikeModularizationLargeFanIn; 142 | } 143 | 144 | public void setHubLikeModularizationLargeFanIn(int hubLikeModularizationLargeFanIn) { 145 | this.hubLikeModularizationLargeFanIn = hubLikeModularizationLargeFanIn; 146 | } 147 | 148 | public int getHubLikeModularizationLargeFanOut() { 149 | return hubLikeModularizationLargeFanOut; 150 | } 151 | 152 | public void setHubLikeModularizationLargeFanOut(int hubLikeModularizationLargeFanOut) { 153 | this.hubLikeModularizationLargeFanOut = hubLikeModularizationLargeFanOut; 154 | } 155 | 156 | public int getInsufficientModularizationLargePublicInterface() { 157 | return insufficientModularizationLargePublicInterface; 158 | } 159 | 160 | public void setInsufficientModularizationLargePublicInterface(int insufficientModularizationLargePublicInterface) { 161 | this.insufficientModularizationLargePublicInterface = insufficientModularizationLargePublicInterface; 162 | } 163 | 164 | public int getInsufficientModularizationLargeNumOfMethods() { 165 | return insufficientModularizationLargeNumOfMethods; 166 | } 167 | 168 | public void setInsufficientModularizationLargeNumOfMethods(int insufficientModularizationLargeNumOfMethods) { 169 | this.insufficientModularizationLargeNumOfMethods = insufficientModularizationLargeNumOfMethods; 170 | } 171 | 172 | public int getInsufficientModularizationHighComplexity() { 173 | return insufficientModularizationHighComplexity; 174 | } 175 | 176 | public void setInsufficientModularizationHighComplexity(int insufficientModularizationHighComplexity) { 177 | this.insufficientModularizationHighComplexity = insufficientModularizationHighComplexity; 178 | } 179 | 180 | } 181 | -------------------------------------------------------------------------------- /src/Designite/smells/ThresholdsParser.java: -------------------------------------------------------------------------------- 1 | package Designite.smells; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.File; 5 | import java.io.FileNotFoundException; 6 | import java.io.FileReader; 7 | import java.io.IOException; 8 | import java.util.regex.Pattern; 9 | 10 | import Designite.utils.DJLogger; 11 | 12 | public class ThresholdsParser { 13 | 14 | private static final String emptySpaceRegex = "^\\s+$"; 15 | private static final String legalFormatRegex = "^\\w+[\\ \\t]*=[\\ \\t]*\\d+(.d+)?[\\ \\t]*\\n?$"; 16 | 17 | private final Pattern emptySpacePattern = Pattern.compile(emptySpaceRegex); 18 | private final Pattern legalFormatPattern = Pattern.compile(legalFormatRegex); 19 | 20 | private ThresholdsDTO thresholds = new ThresholdsDTO(); 21 | private File file; 22 | 23 | public ThresholdsParser(String thresholdPath) { 24 | file = new File(thresholdPath); 25 | } 26 | 27 | public void parseThresholds() throws FileNotFoundException, IOException, IllegalArgumentException { 28 | checkFileExists(); 29 | parseLineByLine(); 30 | } 31 | 32 | private void checkFileExists() throws FileNotFoundException { 33 | if (!file.exists()) { 34 | String message = "constants.txt file not found in project folder."; 35 | DJLogger.log(message); 36 | throw new FileNotFoundException(message); 37 | } 38 | } 39 | 40 | private void parseLineByLine() throws IOException, IllegalArgumentException { 41 | FileReader fileReader = new FileReader(file); 42 | BufferedReader bufferedReader = new BufferedReader(fileReader); 43 | String line; 44 | while ((line = bufferedReader.readLine()) != null) { 45 | if (isNotEmpty(line)) { 46 | if (!isWellFormatted(line)) { 47 | String message = "Line: " + line + "\nis not of the form 'someDescription' = 'someNumber'"; 48 | DJLogger.log(message); 49 | bufferedReader.close(); 50 | throw new IllegalArgumentException(message); 51 | } 52 | String[] decomposedLine = line.replaceAll("\\s", "").split("="); 53 | setThresholdsStrategy(decomposedLine[0], Double.parseDouble(decomposedLine[1])); 54 | } 55 | } 56 | bufferedReader.close(); 57 | } 58 | 59 | private boolean isNotEmpty(String line) { 60 | return !emptySpacePattern.matcher(line).matches(); 61 | } 62 | 63 | private boolean isWellFormatted(String line) { 64 | return legalFormatPattern.matcher(line).matches(); 65 | } 66 | 67 | private void setThresholdsStrategy(String key, Double value) throws IllegalArgumentException { 68 | switch (key) { 69 | case "deepHierarchy": 70 | thresholds.setDeepHierarchy(value.intValue()); 71 | break; 72 | case "insufficientModularizationLargePublicInterface": 73 | thresholds.setInsufficientModularizationLargePublicInterface(value.intValue()); 74 | break; 75 | case "insufficientModularizationLargeNumOfMethods": 76 | thresholds.setInsufficientModularizationLargeNumOfMethods(value.intValue()); 77 | break; 78 | case "insufficientModularizationHighComplexity": 79 | thresholds.setInsufficientModularizationHighComplexity(value.intValue()); 80 | break; 81 | case "wideHierarchy": 82 | thresholds.setWideHierarchy(value.intValue()); 83 | break; 84 | default: 85 | String message = "No such threshold: " + key; 86 | DJLogger.log(message); 87 | throw new IllegalArgumentException(message); 88 | } 89 | } 90 | 91 | public ThresholdsDTO getThresholds() { 92 | return thresholds; 93 | } 94 | 95 | } 96 | -------------------------------------------------------------------------------- /src/Designite/smells/designSmells/AbstractionSmellDetector.java: -------------------------------------------------------------------------------- 1 | package Designite.smells.designSmells; 2 | 3 | import java.util.List; 4 | 5 | import Designite.SourceModel.AccessStates; 6 | import Designite.SourceModel.SM_Method; 7 | import Designite.SourceModel.SM_Type; 8 | import Designite.SourceModel.SourceItemInfo; 9 | import Designite.metrics.MethodMetrics; 10 | import Designite.metrics.TypeMetrics; 11 | import Designite.smells.models.DesignCodeSmell; 12 | 13 | public class AbstractionSmellDetector extends DesignSmellDetector { 14 | 15 | private static final String IMPERATIVE_ABSTRACTION = "Imperative Abstraction"; 16 | private static final String MULTIFACETED_ABSTRACTION = "Multifaceted Abstraction"; 17 | private static final String UNNECESSARY_ABSTRACTION = "Unnecessary Abstraction"; 18 | private static final String UNUTILIZED_ABSTRACTION = "Unutilized Abstraction"; 19 | 20 | public AbstractionSmellDetector(TypeMetrics typeMetrics 21 | , SourceItemInfo info) { 22 | super(typeMetrics, info); 23 | } 24 | 25 | @Override 26 | public List detectCodeSmells() { 27 | detectImperativeAbstraction(); 28 | detectMultifacetedAbstraction(); 29 | detectUnnecessaryAbstraction(); 30 | detectUnutilizedAbstraction(); 31 | return getSmells(); 32 | } 33 | 34 | public List detectImperativeAbstraction() { 35 | if (hasImperativeAbstraction()) { 36 | addToSmells(initializeCodeSmell(IMPERATIVE_ABSTRACTION)); 37 | } 38 | return getSmells(); 39 | } 40 | 41 | public boolean hasImperativeAbstraction() { 42 | SM_Type currentType = getTypeMetrics().getType(); 43 | if(getTypeMetrics().getNumOfPublicMethods() != 1 ) { 44 | return false; 45 | } else { 46 | List methods = currentType.getMethodList(); 47 | for(SM_Method method : methods) { 48 | if (method.getAccessModifier() == AccessStates.PUBLIC) { 49 | MethodMetrics metrics = currentType.getMetricsFromMethod(method); 50 | if(metrics.getNumOfLines() > getThresholdsDTO().getImperativeAbstractionLargeNumOfLines()){ 51 | return true; 52 | } 53 | } 54 | } 55 | return false; 56 | } 57 | } 58 | 59 | public List detectMultifacetedAbstraction() { 60 | if (hasMultifacetedAbstraction()) { 61 | addToSmells(initializeCodeSmell(MULTIFACETED_ABSTRACTION)); 62 | } 63 | return getSmells(); 64 | } 65 | 66 | private boolean hasMultifacetedAbstraction() { 67 | return getTypeMetrics().getLcom() >= getThresholdsDTO().getMultifacetedAbstractionLargeLCOM() 68 | && getTypeMetrics().getNumOfFields() >= getThresholdsDTO().getMultifacetedAbstractionManyFields() 69 | && getTypeMetrics().getNumOfMethods() >= getThresholdsDTO().getMultifacetedAbstractionManyMethods(); 70 | } 71 | 72 | public List detectUnnecessaryAbstraction() { 73 | if (hasUnnecessaryAbstraction()) { 74 | addToSmells(initializeCodeSmell(UNNECESSARY_ABSTRACTION)); 75 | } 76 | return getSmells(); 77 | } 78 | 79 | private boolean hasUnnecessaryAbstraction() { 80 | return getTypeMetrics().getNumOfMethods() == 0 81 | && getTypeMetrics().getNumOfFields() 82 | <= getThresholdsDTO().getUnnecessaryAbstractionFewFields(); 83 | } 84 | 85 | public List detectUnutilizedAbstraction() { 86 | if (hasUnutilizedAbstraction()) { 87 | addToSmells(initializeCodeSmell(UNUTILIZED_ABSTRACTION)); 88 | } 89 | return getSmells(); 90 | } 91 | 92 | private boolean hasUnutilizedAbstraction() { 93 | if (hasSuperTypes()) { 94 | return !hasSuperTypeWithFanIn() || !hasFanIn(getTypeMetrics()); 95 | } 96 | return !hasFanIn(getTypeMetrics()); 97 | } 98 | 99 | private boolean hasSuperTypes() { 100 | return getTypeMetrics().getType().getSuperTypes().size() > 0; 101 | } 102 | 103 | private boolean hasSuperTypeWithFanIn() { 104 | for (SM_Type superType : getTypeMetrics().getType().getSuperTypes()) { 105 | if (hasFanIn(superType.getParentPkg().getMetricsFromType(superType))) { 106 | return true; 107 | } 108 | } 109 | return false; 110 | } 111 | 112 | private boolean hasFanIn(TypeMetrics metrics) { 113 | return metrics.getNumOfFanInTypes() > 0; 114 | } 115 | 116 | } 117 | -------------------------------------------------------------------------------- /src/Designite/smells/designSmells/CodeSmellDetector.java: -------------------------------------------------------------------------------- 1 | package Designite.smells.designSmells; 2 | 3 | import Designite.smells.models.CodeSmell; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | public abstract class CodeSmellDetector { 9 | 10 | protected List smells = new ArrayList<>(); 11 | 12 | protected void addToSmells(T smell) { 13 | smells.add(smell); 14 | } 15 | 16 | public abstract T initializeCodeSmell(String smellName); 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/Designite/smells/designSmells/DesignSmellDetector.java: -------------------------------------------------------------------------------- 1 | package Designite.smells.designSmells; 2 | 3 | import Designite.SourceModel.SourceItemInfo; 4 | import Designite.metrics.TypeMetrics; 5 | import Designite.smells.ThresholdsDTO; 6 | import Designite.smells.models.DesignCodeSmell; 7 | 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | 11 | public abstract class DesignSmellDetector extends CodeSmellDetector { 12 | 13 | 14 | private final TypeMetrics typeMetrics; 15 | private final SourceItemInfo info; 16 | private final ThresholdsDTO thresholdsDTO; 17 | 18 | public DesignSmellDetector(TypeMetrics typeMetrics, SourceItemInfo info) { 19 | this.typeMetrics = typeMetrics; 20 | this.info = info; 21 | 22 | thresholdsDTO = new ThresholdsDTO(); 23 | smells = new ArrayList<>(); 24 | } 25 | 26 | abstract public List detectCodeSmells(); 27 | 28 | public List getSmells() { 29 | return smells; 30 | } 31 | 32 | public DesignCodeSmell initializeCodeSmell(String smellName) { 33 | return new DesignCodeSmell(getSourceItemInfo().getProjectName(), getSourceItemInfo().getPackageName(), getSourceItemInfo().getTypeName(), smellName); 34 | } 35 | 36 | protected TypeMetrics getTypeMetrics() { 37 | return typeMetrics; 38 | } 39 | 40 | protected SourceItemInfo getSourceItemInfo() { 41 | return info; 42 | } 43 | 44 | protected ThresholdsDTO getThresholdsDTO() { 45 | return thresholdsDTO; 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/Designite/smells/designSmells/DesignSmellFacade.java: -------------------------------------------------------------------------------- 1 | package Designite.smells.designSmells; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import Designite.SourceModel.SourceItemInfo; 7 | import Designite.metrics.TypeMetrics; 8 | import Designite.smells.models.DesignCodeSmell; 9 | 10 | public class DesignSmellFacade { 11 | 12 | private AbstractionSmellDetector abstractionSmellDetector; 13 | private EncapsulationSmellDetector encapsulationSmellDetector; 14 | private HierarchySmellDetector hierarchySmellDetector; 15 | private ModularizationSmellDetector modularizationSmellDetector; 16 | 17 | private List smells; 18 | 19 | public DesignSmellFacade(TypeMetrics typeMetrics, SourceItemInfo info) { 20 | 21 | abstractionSmellDetector = new AbstractionSmellDetector(typeMetrics, info); 22 | encapsulationSmellDetector = new EncapsulationSmellDetector(typeMetrics, info); 23 | hierarchySmellDetector = new HierarchySmellDetector(typeMetrics, info); 24 | modularizationSmellDetector = new ModularizationSmellDetector(typeMetrics, info); 25 | 26 | smells = new ArrayList<>(); 27 | } 28 | 29 | public List detectCodeSmells() { 30 | smells.addAll(abstractionSmellDetector.detectCodeSmells()); 31 | smells.addAll(encapsulationSmellDetector.detectCodeSmells()); 32 | smells.addAll(hierarchySmellDetector.detectCodeSmells()); 33 | smells.addAll(modularizationSmellDetector.detectCodeSmells()); 34 | 35 | return smells; 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/Designite/smells/designSmells/EncapsulationSmellDetector.java: -------------------------------------------------------------------------------- 1 | package Designite.smells.designSmells; 2 | 3 | import java.util.List; 4 | 5 | import Designite.SourceModel.SM_Method; 6 | import Designite.SourceModel.SM_Project; 7 | import Designite.SourceModel.SM_Type; 8 | import Designite.SourceModel.SourceItemInfo; 9 | import Designite.metrics.TypeMetrics; 10 | import Designite.smells.models.DesignCodeSmell; 11 | import Designite.utils.models.Graph; 12 | 13 | public class EncapsulationSmellDetector extends DesignSmellDetector { 14 | 15 | private static final String DEFICIENT_ENCAPSULATION = "Deficient Encapsulation"; 16 | private static final String UNEXPLOITED_ENCAPSULATION = "Unexploited Encapsulation"; 17 | 18 | public EncapsulationSmellDetector(TypeMetrics typeMetrics 19 | , SourceItemInfo info) { 20 | super(typeMetrics, info); 21 | } 22 | 23 | @Override 24 | public List detectCodeSmells() { 25 | detectDeficientEncapsulation(); 26 | detectUnexploitedEncapsulation(); 27 | return getSmells(); 28 | } 29 | 30 | public List detectDeficientEncapsulation() { 31 | if (hasDeficientEncapsulation()) { 32 | addToSmells(initializeCodeSmell(DEFICIENT_ENCAPSULATION)); 33 | } 34 | return getSmells(); 35 | } 36 | 37 | private boolean hasDeficientEncapsulation() { 38 | return getTypeMetrics().getNumOfPublicFields() > 0; 39 | } 40 | 41 | public List detectUnexploitedEncapsulation() { 42 | if (hasUnexploitedEncapsulation()) { 43 | addToSmells(initializeCodeSmell(UNEXPLOITED_ENCAPSULATION)); 44 | } 45 | return getSmells(); 46 | } 47 | 48 | private boolean hasUnexploitedEncapsulation() { 49 | for (SM_Method method : getTypeMetrics().getType().getMethodList()) { 50 | for (SM_Type type : method.getSMTypesInInstanceOf()) { 51 | for (SM_Type crossType : method.getSMTypesInInstanceOf()) { 52 | if (!type.equals(crossType) && inSameHierarchy(type, crossType)) { 53 | return true; 54 | } 55 | } 56 | } 57 | } 58 | return false; 59 | } 60 | 61 | private boolean inSameHierarchy(SM_Type type, SM_Type crossType) { 62 | Graph hierarchyGraph = getProject(type).getHierarchyGraph(); 63 | return hierarchyGraph.inSameConnectedComponent(type, crossType); 64 | } 65 | 66 | private SM_Project getProject(SM_Type type) { 67 | return type.getParentPkg().getParentProject(); 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /src/Designite/smells/designSmells/HierarchySmellDetector.java: -------------------------------------------------------------------------------- 1 | package Designite.smells.designSmells; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import Designite.SourceModel.AccessStates; 7 | import Designite.SourceModel.SM_Method; 8 | import Designite.SourceModel.SM_Type; 9 | import Designite.SourceModel.SourceItemInfo; 10 | import Designite.metrics.MethodMetrics; 11 | import Designite.metrics.TypeMetrics; 12 | import Designite.smells.models.DesignCodeSmell; 13 | 14 | public class HierarchySmellDetector extends DesignSmellDetector { 15 | 16 | private static final String BROKEN_HIERARCHY = "Broken Hierarchy"; 17 | private static final String CYCLIC_HIERARCHY = "Cyclic Hierarchy"; 18 | private static final String DEEP_HIERARCHY = "Deep Hierarchy"; 19 | private static final String MISSING_HIERARCHY = "Missing Hierarchy"; 20 | private static final String MULTIPATH_HIERARCHY = "Multipath Hierarchy"; 21 | private static final String REBELIOUS_HIERARCHY = "Rebellious Hierarchy"; 22 | private static final String WIDE_HIERARCHY = "Wide Hierarchy"; 23 | 24 | private static final int EMPTY_BODY = 0; 25 | private static final int ONLY_ONE_STATEMENT = 1; 26 | private static final int INSTANCE_OF_TYPES_NOT_IN_HIERARCHY_THRESHOLD = 2; 27 | 28 | public HierarchySmellDetector(TypeMetrics typeMetrics, SourceItemInfo info) { 29 | super(typeMetrics, info); 30 | } 31 | 32 | @Override 33 | public List detectCodeSmells() { 34 | detectBrokenHierarchy(); 35 | detectCyclicHierarchy(); 36 | detectDeepHierarchy(); 37 | detectMissingHierarchy(); 38 | detectMultipathHierarchy(); 39 | detectRebeliousHierarchy(); 40 | detectWideHierarchy(); 41 | return getSmells(); 42 | } 43 | 44 | public List detectBrokenHierarchy() { 45 | if (hasBrokenHierarchy()) { 46 | addToSmells(initializeCodeSmell(BROKEN_HIERARCHY)); 47 | } 48 | return getSmells(); 49 | } 50 | 51 | private boolean hasBrokenHierarchy() { 52 | SM_Type type = getTypeMetrics().getType(); 53 | if (hasSuperTypes(type) && hasPublicMethods()) { 54 | for (SM_Type superType : type.getSuperTypes()) { 55 | if (!methodIsOverriden(type, superType)) { 56 | return true; 57 | } 58 | } 59 | } 60 | return false; 61 | } 62 | 63 | private boolean hasSuperTypes(SM_Type type) { 64 | return !type.getSuperTypes().isEmpty(); 65 | } 66 | 67 | private boolean hasPublicMethods() { 68 | return getTypeMetrics().getNumOfPublicMethods() > 0; 69 | } 70 | 71 | private boolean methodIsOverriden(SM_Type type, SM_Type superType) { 72 | boolean overrides = false; 73 | for (SM_Method superMethod : superType.getMethodList()) { 74 | if (superMethod.getAccessModifier() == AccessStates.PUBLIC || superMethod.isAbstract() || superType.isInterface()) { 75 | for (SM_Method method : type.getMethodList()) { 76 | if (method.getAccessModifier() == AccessStates.PUBLIC && shareTheSameName(method, superMethod)) { 77 | overrides = true; 78 | } 79 | } 80 | } 81 | } 82 | return overrides; 83 | } 84 | 85 | private boolean shareTheSameName(SM_Method method, SM_Method superMethod) { 86 | return method.getName().equals(superMethod.getName()); 87 | } 88 | 89 | public List detectCyclicHierarchy() { 90 | if (hasCyclicDependency()) { 91 | addToSmells(initializeCodeSmell(CYCLIC_HIERARCHY)); 92 | } 93 | return getSmells(); 94 | } 95 | 96 | private boolean hasCyclicDependency() { 97 | for (SM_Type superType : getTypeMetrics().getType().getSuperTypes()) { 98 | if (hasCyclicDependency(superType)) { 99 | return true; 100 | } 101 | } 102 | return false; 103 | } 104 | 105 | private boolean hasCyclicDependency(SM_Type superType) { 106 | // FIXME : switch to iterative process to avoid stack overflows 107 | try { 108 | if (superType.getName().equals(getSourceItemInfo().getTypeName())) { 109 | return true; 110 | } 111 | for (SM_Type superSuperType : superType.getSuperTypes()) { 112 | if (hasCyclicDependency(superSuperType)) { 113 | return true; 114 | } 115 | } 116 | return false; 117 | } catch (StackOverflowError er) { 118 | System.err.println("Cyclic dependency analysis skipped due to memory overflow."); 119 | return false; 120 | } 121 | } 122 | 123 | public List detectDeepHierarchy() { 124 | if (hasDeepHierarchy()) { 125 | addToSmells(initializeCodeSmell(DEEP_HIERARCHY)); 126 | } 127 | return getSmells(); 128 | } 129 | 130 | private boolean hasDeepHierarchy() { 131 | return getTypeMetrics().getInheritanceDepth() 132 | > getThresholdsDTO().getDeepHierarchy(); 133 | } 134 | 135 | public List detectMissingHierarchy() { 136 | if (hasMissingHierarchy()) { 137 | addToSmells(initializeCodeSmell(MISSING_HIERARCHY)); 138 | } 139 | return getSmells(); 140 | } 141 | 142 | private boolean hasMissingHierarchy() { 143 | SM_Type type = getTypeMetrics().getType(); 144 | for (SM_Method method : type.getMethodList()) { 145 | List listOfInstanceOfTypes = method.getSMTypesInInstanceOf(); 146 | List allAncestors = getAllAncestors(type, new ArrayList<>()); 147 | if (setDifference(listOfInstanceOfTypes, allAncestors).size() 148 | >= INSTANCE_OF_TYPES_NOT_IN_HIERARCHY_THRESHOLD) { 149 | return true; 150 | } 151 | } 152 | return false; 153 | } 154 | 155 | private List getAllAncestors(SM_Type type, List ancestors) { 156 | //FIXME : replace recursion with iterative loop to avoid stack overflows. 157 | try { 158 | for (SM_Type superType : type.getSuperTypes()) { 159 | if (!ancestors.contains(superType)) { 160 | ancestors.add(superType); 161 | } 162 | getAllAncestors(superType, ancestors); 163 | } 164 | return ancestors; 165 | } catch (StackOverflowError er) { 166 | System.err.println("Ancestors analysis skipped due to memory overflow."); 167 | return ancestors; 168 | } 169 | } 170 | 171 | private List setDifference(List oneList, List otherList) { 172 | List outcome = new ArrayList<>(); 173 | for (SM_Type type : oneList) { 174 | if (!otherList.contains(type)) { 175 | outcome.add(type); 176 | } 177 | } 178 | return outcome; 179 | } 180 | 181 | public List detectMultipathHierarchy() { 182 | if (hasMultipathHierarchy()) { 183 | addToSmells(initializeCodeSmell(MULTIPATH_HIERARCHY)); 184 | } 185 | return getSmells(); 186 | } 187 | 188 | private boolean hasMultipathHierarchy() { 189 | for (SM_Type superType : getTypeMetrics().getType().getSuperTypes()) { 190 | for (SM_Type otherSuperType : getTypeMetrics().getType().getSuperTypes()) { 191 | if (!superType.equals(otherSuperType)) { 192 | for (SM_Type ancestorType : otherSuperType.getSuperTypes()) { 193 | if (sameAsSomeAncestor(superType, ancestorType)) { 194 | return true; 195 | } 196 | } 197 | } 198 | } 199 | } 200 | return false; 201 | } 202 | 203 | private boolean sameAsSomeAncestor(SM_Type targetType, SM_Type ancestorType) { 204 | if (targetType.equals(ancestorType)) { 205 | return true; 206 | } 207 | for (SM_Type deeperAncestor : ancestorType.getSuperTypes()) { 208 | //This looks crazy but in some cases 'getSuperTypes()' call returns itself as supertype 209 | //The following check is to avoid StackOverFlow Exception. 210 | if (ancestorType == deeperAncestor) 211 | return false; 212 | if (sameAsSomeAncestor(targetType, deeperAncestor)) { 213 | return true; 214 | } 215 | } 216 | return false; 217 | } 218 | 219 | public List detectRebeliousHierarchy() { 220 | if (hasRebeliousHierarchy()) { 221 | addToSmells(initializeCodeSmell(REBELIOUS_HIERARCHY)); 222 | } 223 | return getSmells(); 224 | } 225 | 226 | private boolean hasRebeliousHierarchy() { 227 | for (SM_Method method : getTypeMetrics().getType().getMethodList()) { 228 | MethodMetrics methodMetrics = getTypeMetrics().getType().getMetricsFromMethod(method); 229 | if (hasSuperType()) { 230 | if (hasEmptyBody(methodMetrics) || hasOnlyAThrowStatement(methodMetrics, method)) { 231 | for (SM_Type superType : getTypeMetrics().getType().getSuperTypes()) { 232 | if (methodIsOverriden(method, superType)) { 233 | return true; 234 | } 235 | } 236 | } 237 | } 238 | } 239 | return false; 240 | } 241 | 242 | private boolean hasSuperType() { 243 | return getTypeMetrics().getType().getSuperTypes().size() > 0; 244 | } 245 | 246 | private boolean hasEmptyBody(MethodMetrics methodMetrics) { 247 | return methodMetrics.getNumOfLines() == EMPTY_BODY; 248 | } 249 | 250 | private boolean hasOnlyAThrowStatement(MethodMetrics methodMetrics, SM_Method method) { 251 | return methodMetrics.getNumOfLines() == ONLY_ONE_STATEMENT 252 | && method.throwsException(); 253 | } 254 | 255 | private boolean methodIsOverriden(SM_Method method, SM_Type type) { 256 | if (existMethodWithSameSignature(method, type)) { 257 | return true; 258 | } 259 | boolean flag = false; 260 | // FIXME : switch to iterative process to avoid stack overflows 261 | for (SM_Type superType : type.getSuperTypes()) { 262 | try { 263 | flag = methodIsOverriden(method, superType); 264 | } catch (StackOverflowError er) { 265 | System.err.println("Method is overriden analysis skipped due to memory overflow"); 266 | } 267 | } 268 | return flag; 269 | } 270 | 271 | private boolean existMethodWithSameSignature(SM_Method method, SM_Type type) { 272 | for (SM_Method otherMethod : type.getMethodList()) { 273 | if (haveSameSignature(method, otherMethod)) { 274 | return true; 275 | } 276 | } 277 | return false; 278 | } 279 | 280 | private boolean haveSameSignature(SM_Method method, SM_Method otherMethod) { 281 | return method.getName().equals(otherMethod.getName()) 282 | && haveSameArguments(method, otherMethod); 283 | } 284 | 285 | private boolean haveSameArguments(SM_Method method, SM_Method otherMethod) { 286 | if (method.getParameterList().size() != otherMethod.getParameterList().size()) { 287 | return false; 288 | } 289 | for (int i = 0; i < method.getParameterList().size(); i++) { 290 | if (!getParameterTypeFromIndex(method, i).equals(getParameterTypeFromIndex(otherMethod, i))) { 291 | return false; 292 | } 293 | } 294 | return true; 295 | } 296 | 297 | private String getParameterTypeFromIndex(SM_Method method, int index) { 298 | return method.getParameterList().get(index).getTypeOverallToString(); 299 | } 300 | 301 | public List detectWideHierarchy() { 302 | if (hasWideHierarchy()) { 303 | addToSmells(initializeCodeSmell(WIDE_HIERARCHY)); 304 | } 305 | return getSmells(); 306 | } 307 | 308 | private boolean hasWideHierarchy() { 309 | return getTypeMetrics().getNumOfChildren() 310 | > getThresholdsDTO().getWideHierarchy(); 311 | } 312 | 313 | } 314 | -------------------------------------------------------------------------------- /src/Designite/smells/designSmells/ModularizationSmellDetector.java: -------------------------------------------------------------------------------- 1 | package Designite.smells.designSmells; 2 | 3 | import java.util.List; 4 | 5 | import Designite.SourceModel.SourceItemInfo; 6 | import Designite.metrics.TypeMetrics; 7 | import Designite.smells.models.DesignCodeSmell; 8 | import Designite.utils.models.Graph; 9 | 10 | public class ModularizationSmellDetector extends DesignSmellDetector { 11 | 12 | private static final String BROKEN_MODULARIZATION = "Broken Modularization"; 13 | private static final String CYCLIC_DEPENDENT_MODULARIZATION = "Cyclic-Dependent Modularization"; 14 | private static final String INSUFFICIENT_MODULARIZATION = "Insufficient Modularization"; 15 | private static final String HUB_LIKE_MODULARIZATION = "Hub-like Modularization"; 16 | 17 | public ModularizationSmellDetector(TypeMetrics typeMetrics, SourceItemInfo info) { 18 | super(typeMetrics, info); 19 | } 20 | 21 | @Override 22 | public List detectCodeSmells() { 23 | detectBrokenModularization(); 24 | detectCyclicDependentModularization(); 25 | detectInsufficientModularization(); 26 | detectHubLikeModularization(); 27 | return getSmells(); 28 | } 29 | 30 | public List detectBrokenModularization() { 31 | if (hasBrokenModularization()) { 32 | addToSmells(initializeCodeSmell(BROKEN_MODULARIZATION)); 33 | } 34 | return getSmells(); 35 | } 36 | 37 | private boolean hasBrokenModularization() { 38 | return getTypeMetrics().getNumOfMethods() == 0 39 | && getTypeMetrics().getNumOfFields() >= getThresholdsDTO().getBrokenModularizationLargeFieldSet(); 40 | } 41 | 42 | public List detectCyclicDependentModularization() { 43 | if (hasCyclicDependentModularization()) { 44 | addToSmells(initializeCodeSmell(CYCLIC_DEPENDENT_MODULARIZATION)); 45 | } 46 | return getSmells(); 47 | } 48 | 49 | private boolean hasCyclicDependentModularization() { 50 | Graph dependencyGraph = getTypeMetrics().getType().getParentPkg().getParentProject().getDependencyGraph(); 51 | if (dependencyGraph.getStrongComponentOfVertex(getTypeMetrics().getType()).size() > 1) { 52 | return true; 53 | } 54 | return false; 55 | } 56 | 57 | public List detectInsufficientModularization() { 58 | if (hasInsufficientModularization()) { 59 | addToSmells(initializeCodeSmell(INSUFFICIENT_MODULARIZATION)); 60 | } 61 | return getSmells(); 62 | } 63 | 64 | private boolean hasInsufficientModularization() { 65 | return hasLargePublicInterface() 66 | || hasLargeNumberOfMethods() 67 | || hasHighComplexity(); 68 | } 69 | 70 | private boolean hasLargePublicInterface() { 71 | return getTypeMetrics().getNumOfPublicMethods() 72 | >= getThresholdsDTO().getInsufficientModularizationLargePublicInterface(); 73 | } 74 | 75 | private boolean hasLargeNumberOfMethods() { 76 | return getTypeMetrics().getNumOfMethods() 77 | >= getThresholdsDTO().getInsufficientModularizationLargeNumOfMethods(); 78 | } 79 | 80 | private boolean hasHighComplexity() { 81 | return getTypeMetrics().getWeightedMethodsPerClass() 82 | >= getThresholdsDTO().getInsufficientModularizationHighComplexity(); 83 | } 84 | 85 | public List detectHubLikeModularization() { 86 | if (hasHubLikeModularization()) { 87 | addToSmells(initializeCodeSmell(HUB_LIKE_MODULARIZATION)); 88 | } 89 | return getSmells(); 90 | } 91 | 92 | private boolean hasHubLikeModularization() { 93 | return getTypeMetrics().getNumOfFanInTypes() 94 | >= getThresholdsDTO().getHubLikeModularizationLargeFanIn() 95 | && getTypeMetrics().getNumOfFanOutTypes() 96 | >= getThresholdsDTO().getHubLikeModularizationLargeFanOut(); 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /src/Designite/smells/models/CodeSmell.java: -------------------------------------------------------------------------------- 1 | package Designite.smells.models; 2 | 3 | public class CodeSmell { 4 | 5 | private String projectName; 6 | private String packageName; 7 | 8 | public CodeSmell(String projectName, String packageName) { 9 | this.projectName = projectName; 10 | this.packageName = packageName; 11 | } 12 | 13 | public String getProjectName() { 14 | return projectName; 15 | } 16 | 17 | public String getPackageName() { 18 | return packageName; 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/Designite/smells/models/DesignCodeSmell.java: -------------------------------------------------------------------------------- 1 | package Designite.smells.models; 2 | 3 | public class DesignCodeSmell extends CodeSmell { 4 | 5 | private String typeName; 6 | private String smellName; 7 | 8 | public DesignCodeSmell(String projectName 9 | , String packageName 10 | , String typeName 11 | , String smellName) { 12 | super(projectName, packageName); 13 | this.typeName = typeName; 14 | this.smellName = smellName; 15 | } 16 | 17 | public String getTypeName() { 18 | return typeName; 19 | } 20 | 21 | public String getSmellName() { 22 | return smellName; 23 | } 24 | 25 | @Override 26 | public String toString() { 27 | return getProjectName() 28 | + "," + getPackageName() 29 | + "," + typeName 30 | + "," + smellName 31 | + "\n"; 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/Designite/smells/models/ImplementationCodeSmell.java: -------------------------------------------------------------------------------- 1 | package Designite.smells.models; 2 | 3 | public class ImplementationCodeSmell extends CodeSmell { 4 | 5 | private String typeName; 6 | private String methodName; 7 | private String smellName; 8 | 9 | public ImplementationCodeSmell(String projectName 10 | , String packageName 11 | , String typeName 12 | , String methodName 13 | , String smellName) { 14 | super(projectName, packageName); 15 | this.typeName = typeName; 16 | this.methodName = methodName; 17 | this.smellName = smellName; 18 | } 19 | 20 | public String getTypeName() { 21 | return typeName; 22 | } 23 | 24 | public String getMethodName() { 25 | return methodName; 26 | } 27 | 28 | public String getSmellName() { 29 | return smellName; 30 | } 31 | 32 | @Override 33 | public String toString() { 34 | return getProjectName() 35 | + "," + getPackageName() 36 | + "," + typeName 37 | + "," + methodName 38 | + "," + smellName 39 | + "\n"; 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/Designite/utils/CSVUtils.java: -------------------------------------------------------------------------------- 1 | package Designite.utils; 2 | 3 | import java.io.BufferedWriter; 4 | import java.io.File; 5 | import java.io.FileWriter; 6 | import java.io.IOException; 7 | import java.util.List; 8 | 9 | public class CSVUtils { 10 | //TODO create an integration test for checking the exporting feature 11 | public static void initializeCSVDirectory(String projectName, String dirPath) { 12 | File dir = new File(dirPath); 13 | createDirIfNotExists(dir); 14 | cleanup(dir); 15 | initializeNeededFiles(dir); 16 | } 17 | 18 | private static void createDirIfNotExists(File dir) { 19 | if (!dir.exists()) { 20 | try { 21 | //The program is failing here. It couldn't create the directory. 22 | //I see we are providing relative path; that could be the reason 23 | //We may prepare the absolute path (by combining it with the output path) 24 | //and try again. 25 | if(dir.mkdirs()==false) 26 | System.out.print("oops, couldn't create the directory " + dir); 27 | } catch (Exception e) { 28 | e.printStackTrace(); 29 | DJLogger.log(e.getMessage()); 30 | } 31 | } 32 | } 33 | 34 | private static void cleanup(File dir) { 35 | if (dir.listFiles() != null) { 36 | for (File file : dir.listFiles()) { 37 | file.delete(); 38 | } 39 | } 40 | } 41 | 42 | private static void initializeNeededFiles(File dir) { 43 | createCSVFile(dir.getPath() + File.separator + Constants.TYPE_METRICS_PATH_SUFFIX, Constants.TYPE_METRICS_HEADER); 44 | createCSVFile(dir.getPath() + File.separator + Constants.METHOD_METRICS_PATH_SUFFIX, Constants.METHOD_METRICS_HEADER); 45 | createCSVFile(dir.getPath() + File.separator + Constants.DESIGN_CODE_SMELLS_PATH_SUFFIX, Constants.DESIGN_CODE_SMELLS_HEADER); 46 | createCSVFile(dir.getPath() + File.separator + Constants.IMPLEMENTATION_CODE_SMELLS_PATH_SUFFIX, Constants.IMPLEMENTATION_CODE_SMELLS_HEADER); 47 | } 48 | 49 | private static void createCSVFile(String path, String header) { 50 | try { 51 | File file = new File(path); 52 | file.createNewFile(); 53 | FileWriter fileWriter = new FileWriter(file, true); 54 | BufferedWriter bufferedWriter = new BufferedWriter(fileWriter); 55 | bufferedWriter.append(header); 56 | bufferedWriter.close(); 57 | } catch(IOException e) { 58 | e.printStackTrace(); 59 | DJLogger.log(e.getMessage()); 60 | } 61 | } 62 | 63 | public static void addToCSVFile(String path, String row) { 64 | try { 65 | File file = new File(path); 66 | FileWriter fileWriter = new FileWriter(file, true); 67 | BufferedWriter bufferedWriter = new BufferedWriter(fileWriter); 68 | bufferedWriter.append(row); 69 | bufferedWriter.close(); 70 | } catch(IOException e) { 71 | e.printStackTrace(); 72 | DJLogger.log(e.getMessage()); 73 | } 74 | } 75 | 76 | public static void addAllToCSVFile(String path, List collection) { 77 | try { 78 | File file = new File(path); 79 | FileWriter fileWriter = new FileWriter(file, true); 80 | BufferedWriter bufferedWriter = new BufferedWriter(fileWriter); 81 | for (Object obj : collection) { 82 | String row = (obj instanceof String) ? (String) obj : obj.toString(); 83 | bufferedWriter.append(row); 84 | } 85 | bufferedWriter.close(); 86 | } catch(IOException e) { 87 | e.printStackTrace(); 88 | DJLogger.log(e.getMessage()); 89 | } 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /src/Designite/utils/Constants.java: -------------------------------------------------------------------------------- 1 | package Designite.utils; 2 | 3 | import java.io.File; 4 | 5 | public class Constants { 6 | 7 | /*public static final String PATH_OF_THRESHOLDS = System.getProperty("user.dir") 8 | + File.separator 9 | + "thresholds.txt";*/ 10 | 11 | //public static String CSV_DIRECTORY_PATH = System.getProperty("user.dir") 12 | // + File.separator 13 | // + "default_csv"; 14 | 15 | public static final String TYPE_METRICS_PATH_SUFFIX = "typeMetrics.csv"; 16 | public static final String METHOD_METRICS_PATH_SUFFIX = "methodMetrics.csv"; 17 | public static final String DESIGN_CODE_SMELLS_PATH_SUFFIX = "designCodeSmells.csv"; 18 | public static final String IMPLEMENTATION_CODE_SMELLS_PATH_SUFFIX = "implementationCodeSmells.csv"; 19 | 20 | public static final String TYPE_METRICS_HEADER = "Project Name" 21 | + ",Package Name" 22 | + ",Type Name" 23 | + ",NOF" 24 | + ",NOPF" 25 | + ",NOM" 26 | + ",NOPM" 27 | + ",LOC" 28 | + ",WMC" 29 | + ",NC" 30 | + ",DIT" 31 | + ",LCOM" 32 | + ",FANIN" 33 | + ",FANOUT" 34 | + "\n"; 35 | 36 | public static final String METHOD_METRICS_HEADER = "Project Name" 37 | + ",Package Name" 38 | + ",Type Name" 39 | + ",MethodName" 40 | + ",LOC" 41 | + ",CC" 42 | + ",PC" 43 | + "\n"; 44 | 45 | public static final String DESIGN_CODE_SMELLS_HEADER = "Project Name" 46 | + ",Package Name" 47 | + ",Type Name" 48 | + ",Code Smell" 49 | + "\n"; 50 | 51 | public static final String IMPLEMENTATION_CODE_SMELLS_HEADER = "Project Name" 52 | + ",Package Name" 53 | + ",Type Name" 54 | + ",Method Name" 55 | + ",Code Smell" 56 | + "\n"; 57 | public static final boolean DEBUG = true; 58 | } 59 | -------------------------------------------------------------------------------- /src/Designite/utils/DJLogger.java: -------------------------------------------------------------------------------- 1 | package Designite.utils; 2 | 3 | import java.io.*; 4 | import java.nio.charset.StandardCharsets; 5 | import java.text.SimpleDateFormat; 6 | import java.util.Calendar; 7 | 8 | 9 | public class DJLogger { 10 | 11 | // This variable must be private, making it public may expose sensitive information 12 | private String logFile; 13 | 14 | private final static DJLogger DJ_LOGGER = getInstance(); 15 | 16 | public static DJLogger getInstance() { 17 | if (DJ_LOGGER == null) { 18 | return new DJLogger(); 19 | } 20 | return DJ_LOGGER; 21 | } 22 | 23 | /** 24 | * Ensure to set {@code outputDirectory} before program execution, 25 | * as it creates log files in the specified 26 | * directory. Failing to provide a valid directory may result in errors. 27 | * @param outputDirectory 28 | * @throws FileNotFoundException 29 | */ 30 | public void setOutputDirectory(String outputDirectory) throws FileNotFoundException { 31 | String timeStamp = new SimpleDateFormat("ddMMyyyy_HHmm").format(Calendar.getInstance().getTime()); 32 | String logAbsolutePath = outputDirectory + File.separator + "DesigniteLog" + timeStamp + ".txt"; 33 | FileManager.getInstance().createFileIfNotExists(logAbsolutePath); 34 | this.logFile = logAbsolutePath; 35 | } 36 | 37 | private DJLogger() { 38 | } 39 | 40 | /** 41 | * Logs the {@code logMessage} into the file. 42 | * @param logMessage 43 | */ 44 | public static void log(String logMessage) { 45 | System.out.println(logMessage); 46 | if (DJ_LOGGER.logFile == null) { 47 | //Commented the following line just to make the execution non-verbose 48 | //System.out.println("Log file path has been not set. Logging not support."); 49 | return; 50 | } 51 | try (Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(DJ_LOGGER.logFile, true), StandardCharsets.UTF_8))) { 52 | writer.write(logMessage + "\n"); 53 | // Redundant close -> try-catch closes the file after execution. 54 | // writer.close(); 55 | } catch (IOException ex) { 56 | System.out.println("Exception during logging. " + ex.getMessage()); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/Designite/utils/FileManager.java: -------------------------------------------------------------------------------- 1 | package Designite.utils; 2 | 3 | import java.io.File; 4 | import java.io.FileNotFoundException; 5 | import java.io.IOException; 6 | import java.io.PrintWriter; 7 | import java.nio.file.Files; 8 | import java.nio.file.Paths; 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | 12 | public class FileManager { 13 | 14 | private static FileManager fileManager; 15 | 16 | /** 17 | * The Singleton Design principle has been applied to manage one object only throughout the program execution. 18 | * @return {@code Instance of} {@link FileManager} 19 | */ 20 | public static FileManager getInstance() { 21 | if (fileManager == null) { 22 | fileManager = new FileManager(); 23 | } 24 | return fileManager; 25 | } 26 | 27 | private FileManager() { 28 | } 29 | 30 | public FileManager(String sourcePath) { 31 | listFiles(sourcePath); 32 | } 33 | 34 | /** 35 | * Returns list of all files from a nested folder, recursively traversing from 36 | * the deepest level of folder tree. 37 | * @param sourcePath 38 | * @return 39 | */ 40 | public List listFiles(String sourcePath) { 41 | List sourceFileList = new ArrayList(); 42 | this.listFiles(sourcePath, sourceFileList); 43 | return sourceFileList; 44 | } 45 | 46 | /** 47 | * Returns list of all files from a nested folder, recursively traversing tree from 48 | * the deepest level of folder tree. 49 | * @param sourcePath 50 | * @param sourceFileList 51 | * @return List 52 | */ 53 | private List listFiles(String sourcePath, List sourceFileList) { 54 | File file; 55 | try { 56 | file = new File(sourcePath); 57 | if (file.isFile() && file.getName().endsWith(".java")) { 58 | sourceFileList.add(file.getAbsolutePath()); 59 | } else if (file.isDirectory()) { 60 | sourceFileList.addAll(listFilesFromFolder(file.getAbsolutePath())); 61 | } else { 62 | // help menu 63 | // This block is a dead code. Moreover, It does not provide a resolution if the files are not found. 64 | System.out.println("No file found to be analyzed."); 65 | System.out.println("Usage instructions: "); 66 | } 67 | } catch (Exception e) { 68 | e.printStackTrace(); 69 | } 70 | return sourceFileList; 71 | } 72 | 73 | /** 74 | * Returns List of files in the specified {@code folderPath} 75 | * @param folderPath 76 | * @return List 77 | */ 78 | public List listFilesFromFolder(String folderPath) { 79 | File file = new File(folderPath); 80 | File[] paths; 81 | List fileList = new ArrayList(); 82 | paths = file.listFiles(); 83 | for (File path : paths) { 84 | if (path.isFile() && path.getAbsolutePath().endsWith(".java")) { 85 | fileList.add(path.getAbsolutePath()); 86 | } else if (path.isDirectory()) { 87 | fileList.addAll(listFilesFromFolder(path.getAbsolutePath())); 88 | } 89 | } 90 | return fileList; 91 | } 92 | 93 | 94 | /** 95 | * Reads all lines from the file specified in {@code sourcePath}. 96 | * @param sourcePath 97 | * @return 98 | */ 99 | public String readFileToString(String sourcePath) { 100 | try { 101 | return new String(Files.readAllBytes(Paths.get(sourcePath))); 102 | } catch (IOException e) { 103 | e.printStackTrace(); 104 | return ""; 105 | } 106 | } 107 | 108 | 109 | /** 110 | * Creates a new file at the specified path if it doesn't exist. 111 | * @param filePath 112 | * @return 113 | * @throws FileNotFoundException 114 | */ 115 | public PrintWriter createFileIfNotExists(String filePath) throws FileNotFoundException { 116 | File file = new File(filePath); 117 | File parent = file.getParentFile(); 118 | if (parent.isDirectory() && !parent.exists()) { 119 | parent.mkdirs(); 120 | } 121 | return new PrintWriter(file); 122 | } 123 | 124 | 125 | } 126 | -------------------------------------------------------------------------------- /src/Designite/utils/models/Edge.java: -------------------------------------------------------------------------------- 1 | package Designite.utils.models; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | public class Edge { 7 | 8 | private Vertex firstVertex; 9 | private Vertex secondVertex; 10 | private List edge; 11 | 12 | public Edge(Vertex firstVertex, Vertex secondVertex) { 13 | this.firstVertex = firstVertex; 14 | this.secondVertex = secondVertex; 15 | 16 | edge = new ArrayList<>(); 17 | edge.add(firstVertex); 18 | edge.add(secondVertex); 19 | } 20 | 21 | public Vertex getFirstVertex() { 22 | return firstVertex; 23 | } 24 | 25 | public Vertex getSecondVertex() { 26 | return secondVertex; 27 | } 28 | 29 | public List getVertices() { 30 | return edge; 31 | } 32 | 33 | public boolean containsVertex(Vertex vertex) { 34 | return edge.contains(vertex); 35 | } 36 | 37 | public Vertex getOtherVertex(Vertex vertex) { 38 | if (edge.get(0).equals(vertex)) { 39 | return edge.get(1); 40 | } else if (edge.get(1).equals(vertex)) { 41 | return edge.get(0); 42 | } else { 43 | return null; 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/Designite/utils/models/Graph.java: -------------------------------------------------------------------------------- 1 | package Designite.utils.models; 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 Graph { 9 | 10 | private List vertices = new ArrayList<>(); 11 | private Map> adjacencyList = new HashMap<>(); 12 | private Map> directedAdjacencyList = new HashMap<>(); 13 | private Map> reversedDirectedAdjacencyList = new HashMap<>(); 14 | private Map visitedVertices = new HashMap<>(); 15 | private List> connectedComponents = new ArrayList<>(); 16 | private Map> connectedComponnentsMapping = new HashMap<>(); 17 | private List> stronglyConnectedComponents = new ArrayList<>(); 18 | private Map> stronglyConnectedComponnentsMapping = new HashMap<>(); 19 | private List helperVertexList = new ArrayList<>(); 20 | 21 | public void computeConnectedComponents() { 22 | initializeVisitedVerices(); 23 | for (Vertex vertex : vertices) { 24 | if (!visitedVertices.get(vertex)) { 25 | List connectedComponent = new ArrayList<>(); 26 | depthFirstSearch(connectedComponent, vertex, GraphAlingment.UNDIRECTED); 27 | connectedComponents.add(connectedComponent); 28 | updateMapping(connectedComponnentsMapping, connectedComponent); 29 | } 30 | } 31 | } 32 | 33 | public void computeStronglyConnectedComponents() { 34 | reversePassDFS(); 35 | straightPassDFS(); 36 | } 37 | 38 | public void reversePassDFS() { 39 | initializeVisitedVerices(); 40 | for (int i = vertices.size()-1; i >= 0 ; i--) { 41 | if (!visitedVertices.get(vertices.get(i))) { 42 | depthFirstSearch(new ArrayList<>(), vertices.get(i), GraphAlingment.REVERSE_DIRECTED); 43 | } 44 | } 45 | } 46 | 47 | public void straightPassDFS() { 48 | initializeVisitedVerices(); 49 | for (int i = vertices.size()-1; i >= 0 ; i--) { 50 | if (!visitedVertices.get(helperVertexList.get(i))) { 51 | List stronglyConnectedComponent = new ArrayList<>(); 52 | depthFirstSearch(stronglyConnectedComponent, helperVertexList.get(i), GraphAlingment.DIRECTED); 53 | stronglyConnectedComponents.add(stronglyConnectedComponent); 54 | updateMapping(stronglyConnectedComponnentsMapping, stronglyConnectedComponent); 55 | } 56 | } 57 | } 58 | 59 | private void initializeVisitedVerices() { 60 | for (Vertex vertex : vertices) { 61 | visitedVertices.put(vertex, false); 62 | } 63 | } 64 | 65 | private void updateMapping(Map> mapping, List component) { 66 | for (Vertex vertex : component) { 67 | mapping.put(vertex, component); 68 | } 69 | } 70 | 71 | private void depthFirstSearch(List connectedComponent, Vertex vertex, GraphAlingment align) { 72 | visitedVertices.put(vertex, true); 73 | if (align != GraphAlingment.REVERSE_DIRECTED) { 74 | connectedComponent.add(vertex); 75 | } 76 | for (Vertex adjacentVertex : getAdjacentVertices(vertex, align)) { 77 | if (!visitedVertices.get(adjacentVertex)) { 78 | depthFirstSearch(connectedComponent, adjacentVertex, align); 79 | } 80 | } 81 | if (align == GraphAlingment.REVERSE_DIRECTED) { 82 | helperVertexList.add(vertex); 83 | } 84 | } 85 | 86 | public void addVertex(Vertex vertex) { 87 | if (!vertices.contains(vertex)) { 88 | initializeVertex(vertex); 89 | } 90 | } 91 | 92 | public void addEdge(Edge edge) { 93 | initializeEdge(edge); 94 | addDirectedEdge(edge); 95 | addUndirectedEdge(edge); 96 | } 97 | 98 | private void initializeEdge(Edge edge) { 99 | if (!adjacencyList.containsKey(edge.getFirstVertex())) { 100 | initializeVertex(edge.getFirstVertex()); 101 | } 102 | if (!adjacencyList.containsKey(edge.getSecondVertex())) { 103 | initializeVertex(edge.getSecondVertex()); 104 | } 105 | } 106 | 107 | private void initializeVertex(Vertex vertex) { 108 | adjacencyList.put(vertex, new ArrayList<>()); 109 | directedAdjacencyList.put(vertex, new ArrayList<>()); 110 | reversedDirectedAdjacencyList.put(vertex, new ArrayList<>()); 111 | vertices.add(vertex); 112 | } 113 | 114 | private void addDirectedEdge(Edge edge) { 115 | List adjacentVertices = directedAdjacencyList.get(edge.getFirstVertex()); 116 | if (!adjacentVertices.contains(edge.getSecondVertex())) { 117 | adjacentVertices.add(edge.getSecondVertex()); 118 | directedAdjacencyList.put(edge.getFirstVertex(), adjacentVertices); 119 | addReverseDirectedEdge(edge); 120 | } 121 | } 122 | 123 | private void addReverseDirectedEdge(Edge edge) { 124 | List adjacentVertices = reversedDirectedAdjacencyList.get(edge.getSecondVertex()); 125 | adjacentVertices.add(edge.getFirstVertex()); 126 | reversedDirectedAdjacencyList.put(edge.getSecondVertex(), adjacentVertices); 127 | } 128 | 129 | private void addUndirectedEdge(Edge edge) { 130 | for (Vertex vertex : edge.getVertices()) { 131 | List adjacentVertices = adjacencyList.get(vertex); 132 | if (!adjacentVertices.contains(edge.getOtherVertex(vertex))) { 133 | adjacentVertices.add(edge.getOtherVertex(vertex)); 134 | adjacencyList.put(vertex, adjacentVertices); 135 | } 136 | } 137 | } 138 | 139 | private List getAdjacentVertices(Vertex vertex, GraphAlingment align) { 140 | if (align == GraphAlingment.UNDIRECTED) { 141 | return adjacencyList.get(vertex); 142 | } else if (align == GraphAlingment.DIRECTED) { 143 | return directedAdjacencyList.get(vertex); 144 | } else if (align == GraphAlingment.REVERSE_DIRECTED) { 145 | return reversedDirectedAdjacencyList.get(vertex); 146 | } 147 | return null; 148 | } 149 | 150 | public List> getConnectedComponnents() { 151 | return connectedComponents; 152 | } 153 | 154 | public List> getStronglyConnectedComponents() { 155 | return stronglyConnectedComponents; 156 | } 157 | 158 | public List getComponentOfVertex(Vertex vertex) { 159 | return connectedComponnentsMapping.get(vertex); 160 | } 161 | 162 | public List getStrongComponentOfVertex(Vertex vertex) { 163 | return stronglyConnectedComponnentsMapping.get(vertex); 164 | } 165 | 166 | public boolean inSameConnectedComponent(Vertex vertex1, Vertex vertex2) { 167 | return getComponentOfVertex(vertex1).equals(getComponentOfVertex(vertex2)); 168 | } 169 | 170 | private enum GraphAlingment { 171 | UNDIRECTED, DIRECTED, REVERSE_DIRECTED 172 | } 173 | 174 | } 175 | -------------------------------------------------------------------------------- /src/Designite/utils/models/Vertex.java: -------------------------------------------------------------------------------- 1 | package Designite.utils.models; 2 | 3 | public interface Vertex { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /src/Designite/visitors/DirectAceessFieldVisitor.java: -------------------------------------------------------------------------------- 1 | package Designite.visitors; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import org.eclipse.jdt.core.dom.ASTVisitor; 7 | import org.eclipse.jdt.core.dom.FieldAccess; 8 | import org.eclipse.jdt.core.dom.SimpleName; 9 | import org.eclipse.jdt.core.dom.ThisExpression; 10 | 11 | public class DirectAceessFieldVisitor extends ASTVisitor { 12 | 13 | private List names = new ArrayList<>(); 14 | private List thisAccesses = new ArrayList<>(); 15 | 16 | public boolean visit(SimpleName node) { 17 | if (!names.contains(node)) { 18 | names.add(node); 19 | } 20 | return true; 21 | } 22 | 23 | public boolean visit(FieldAccess node) { 24 | if (node.getExpression() instanceof ThisExpression) { 25 | if (!this.thisAccesses.contains(node)) { 26 | thisAccesses.add(node); 27 | } 28 | } 29 | return true; 30 | } 31 | 32 | public List getNames() { 33 | return names; 34 | } 35 | 36 | public List getThisAccesses() { 37 | return thisAccesses; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Designite/visitors/InstanceOfVisitor.java: -------------------------------------------------------------------------------- 1 | package Designite.visitors; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import org.eclipse.jdt.core.dom.ASTVisitor; 7 | import org.eclipse.jdt.core.dom.InstanceofExpression; 8 | import org.eclipse.jdt.core.dom.Type; 9 | 10 | public class InstanceOfVisitor extends ASTVisitor { 11 | 12 | private List typesInInstanceOf = new ArrayList<>();; 13 | 14 | public boolean visit(InstanceofExpression node) { 15 | typesInInstanceOf.add(node.getRightOperand()); 16 | return true; 17 | } 18 | 19 | public List getTypesInInstanceOf() { 20 | return typesInInstanceOf; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Designite/visitors/MethodControlFlowVisitor.java: -------------------------------------------------------------------------------- 1 | package Designite.visitors; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import org.eclipse.jdt.core.dom.ASTVisitor; 7 | import org.eclipse.jdt.core.dom.DoStatement; 8 | import org.eclipse.jdt.core.dom.EnhancedForStatement; 9 | import org.eclipse.jdt.core.dom.ForStatement; 10 | import org.eclipse.jdt.core.dom.IfStatement; 11 | import org.eclipse.jdt.core.dom.SwitchCase; 12 | import org.eclipse.jdt.core.dom.TryStatement; 13 | import org.eclipse.jdt.core.dom.SwitchStatement; 14 | import org.eclipse.jdt.core.dom.WhileStatement; 15 | 16 | public class MethodControlFlowVisitor extends ASTVisitor { 17 | 18 | private List ifStatements = new ArrayList<>(); 19 | private List switchStatements = new ArrayList<>(); 20 | private List switchCases = new ArrayList<>(); 21 | private List switchCasesWitoutDefaults = new ArrayList<>(); 22 | private List forStatements = new ArrayList<>(); 23 | private List whileStatements = new ArrayList<>(); 24 | private List doStatements = new ArrayList<>(); 25 | private List foreachStatements = new ArrayList<>(); 26 | private List tryStatements = new ArrayList<>(); 27 | 28 | public boolean visit(IfStatement node) { 29 | ifStatements.add(node); 30 | return true; 31 | } 32 | 33 | public boolean visit(SwitchCase node) { 34 | switchCases.add(node); 35 | if (!node.isDefault()) { 36 | switchCasesWitoutDefaults.add(node); 37 | } 38 | return true; 39 | } 40 | 41 | public boolean visit(SwitchStatement node) { 42 | switchStatements.add(node); 43 | return true; 44 | } 45 | 46 | public boolean visit(ForStatement node) { 47 | forStatements.add(node); 48 | return true; 49 | } 50 | 51 | public boolean visit(WhileStatement node) { 52 | whileStatements.add(node); 53 | return true; 54 | } 55 | 56 | public boolean visit(DoStatement node) { 57 | doStatements.add(node); 58 | return true; 59 | } 60 | 61 | public boolean visit(EnhancedForStatement node) { 62 | foreachStatements.add(node); 63 | return true; 64 | } 65 | 66 | public boolean visit(TryStatement node) { 67 | tryStatements.add(node); 68 | return true; 69 | } 70 | 71 | public List getIfStatements() { 72 | return ifStatements; 73 | } 74 | 75 | public List getForStatements() { 76 | return forStatements; 77 | } 78 | 79 | public List getWhileStatements() { 80 | return whileStatements; 81 | } 82 | 83 | public List getDoStatements() { 84 | return doStatements; 85 | } 86 | 87 | public List getTryStatements() { 88 | return tryStatements; 89 | } 90 | 91 | public int getNumOfIfStatements() { 92 | return ifStatements.size(); 93 | } 94 | 95 | public List getSwitchStatements() { 96 | return switchStatements; 97 | } 98 | 99 | public int getNumOfSwitchCaseStatementsWitoutDefault() { 100 | return switchCasesWitoutDefaults.size(); 101 | } 102 | 103 | public int getNumOfForStatements() { 104 | return forStatements.size(); 105 | } 106 | 107 | public int getNumOfWhileStatements() { 108 | return whileStatements.size(); 109 | } 110 | 111 | public int getNumOfDoStatements() { 112 | return doStatements.size(); 113 | } 114 | 115 | public int getNumOfForeachStatements() { 116 | return foreachStatements.size(); 117 | } 118 | 119 | } 120 | -------------------------------------------------------------------------------- /src/Designite/visitors/NumberLiteralVisitor.java: -------------------------------------------------------------------------------- 1 | package Designite.visitors; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import org.eclipse.jdt.core.dom.ASTVisitor; 7 | import org.eclipse.jdt.core.dom.NumberLiteral; 8 | 9 | public class NumberLiteralVisitor extends ASTVisitor { 10 | private List numberLiteralsExpressions = new ArrayList<>(); 11 | 12 | public boolean visit(NumberLiteral node) 13 | { 14 | numberLiteralsExpressions.add(node); 15 | return true; 16 | } 17 | 18 | public List getNumberLiteralsExpressions() { 19 | return numberLiteralsExpressions; 20 | } 21 | 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/Designite/visitors/StaticFieldAccessVisitor.java: -------------------------------------------------------------------------------- 1 | package Designite.visitors; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import org.eclipse.jdt.core.dom.ASTVisitor; 7 | import org.eclipse.jdt.core.dom.Name; 8 | import org.eclipse.jdt.core.dom.QualifiedName; 9 | 10 | public class StaticFieldAccessVisitor extends ASTVisitor { 11 | 12 | private List staticFieldAccesses = new ArrayList<>(); 13 | 14 | public boolean visit(QualifiedName node) { 15 | staticFieldAccesses.add(node.getQualifier()); 16 | return true; 17 | } 18 | 19 | public List getStaticFieldAccesses() { 20 | return staticFieldAccesses; 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/Designite/visitors/ThrowVisitor.java: -------------------------------------------------------------------------------- 1 | package Designite.visitors; 2 | 3 | import org.eclipse.jdt.core.dom.ASTVisitor; 4 | import org.eclipse.jdt.core.dom.ThrowStatement; 5 | 6 | public class ThrowVisitor extends ASTVisitor { 7 | 8 | private boolean throwsException; 9 | 10 | public boolean visit(ThrowStatement node) { 11 | throwsException = true; 12 | return true; 13 | } 14 | 15 | public boolean throwsException() { 16 | return throwsException; 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /tests/DesigniteTests/DesigniteTests/DesigniteTests.java: -------------------------------------------------------------------------------- 1 | package DesigniteTests; 2 | 3 | import java.io.BufferedWriter; 4 | import java.io.File; 5 | import java.io.FileWriter; 6 | import java.io.IOException; 7 | 8 | public abstract class DesigniteTests { 9 | 10 | protected static final String PARAMETER_TEST_INPUT_FILE_PATH = getTestingPath() + File.separator + "parameterTestInput.txt"; 11 | protected static final String CALLED_METHOD_TEST_INPUT_FILE_PATH = getTestingPath() + File.separator + "calledMethodTestInput.txt"; 12 | protected static final String TEST_BATCH_FILE_PATH = getTestingPath() + File.separator + "testBatchFile.txt"; 13 | protected static final String IN_BATCH_FILE_PATH = getTestingPath() + File.separator + "inBatchFile.txt"; 14 | protected static final String METRICS_FILE_PATH = getTestingPath() + File.separator + "metricsFile.txt"; 15 | protected static final String CODE_SMELLS_FILE_PATH = getTestingPath() + File.separator + "codeSmellsFile.txt"; 16 | 17 | protected static final String PARAMETER_TEST_INPUT_FILE_CONTENT = "[Source folder]\n" + getTestingPath() + File.separator + "test_inputs"; 18 | protected static final String CALLED_METHOD_TEST_INPUT_FILE_CONTENT = "[Source folder]\n" + getTestingPath() + File.separator + "test_inputs2"; 19 | protected static final String TEST_BATCH_FILE_CONTENT = "[Source folder]\n" + getTestingPath() + File.separator + "test_package"; 20 | protected static final String IN_BATCH_FILE_CONTENT = "[Source folder]\n" + System.getProperty("user.dir") + "\n\n" + "[Output folder]\n" + System.getProperty("user.dir") + File.separator + "temp"; 21 | protected static final String IN_BATCH_FILE_CONTENT_SRC = "[Source folder]\n" + System.getProperty("user.dir") + File.separator + "src" + "\n\n" + "[Output folder]\n" + System.getProperty("user.dir") + File.separator + "temp"; 22 | protected static final String IN_BATCH_FILE_CONTENT_SOURCE = "[Source folder]\n" + System.getProperty("user.dir") + File.separator + "source" + "\n\n" + "[Output folder]\n" + System.getProperty("user.dir") + File.separator + "temp"; 23 | protected static final String METRICS_FILE_CONTENT = "[Source folder]\n" + getTestingPath() + File.separator + "metrics" + "\n\n" + "[Output folder]\n" + System.getProperty("user.dir") + File.separator + "temp"; 24 | protected static final String CODE_SMELLS_FILE_CONTENT = "[Source folder]\n" + getTestingPath() + File.separator + "codeSmells"; 25 | 26 | protected static String getTestingPath() { 27 | String path = System.getProperty("user.dir") + File.separator + "tests" + File.separator + "TestFiles"; 28 | 29 | return path; 30 | } 31 | 32 | protected void createFileForArguments(String path, String content) { 33 | try { 34 | File file = new File(path); 35 | if (!file.exists()) { 36 | file.createNewFile(); 37 | } 38 | FileWriter fileWriter = new FileWriter(path, false); 39 | BufferedWriter bufferedWriter = new BufferedWriter(fileWriter); 40 | bufferedWriter.write(content); 41 | bufferedWriter.close(); 42 | } catch (IOException e) { 43 | e.printStackTrace(); 44 | } 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /tests/DesigniteTests/DesigniteTests/InputArgsTest.java: -------------------------------------------------------------------------------- 1 | package DesigniteTests; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | 5 | import java.io.File; 6 | 7 | import org.junit.Test; 8 | 9 | import Designite.ArgumentParser.InputArgs; 10 | 11 | public class InputArgsTest extends DesigniteTests { 12 | 13 | // Negative case- folder path specified rather than input batch file 14 | @Test(expected = IllegalArgumentException.class) 15 | public void testInputArgs_negative_folder() { 16 | new InputArgs(null, getTestingPath()); 17 | } 18 | 19 | @Test(expected = IllegalArgumentException.class) 20 | public void testInputArgs_passingInvalidFilePath_ReturnsException() { 21 | new InputArgs(getTestingPath() + File.separator + "invalidFile.txt", getTestingPath()); 22 | } 23 | 24 | @Test(expected = IllegalArgumentException.class) 25 | public void testInputArgs_passingFilePath_ReturnsException() { 26 | new InputArgs(getTestingPath() + File.separator + "TestFiles" + File.separator + "singleJavaFile.txt", getTestingPath()); 27 | } 28 | 29 | @Test 30 | public void testInputArgs_getProjectName() { 31 | InputArgs args = new InputArgs(System.getProperty("user.dir"), getTestingPath()); 32 | String currentProjectDir = new File(System.getProperty("user.dir")).getName(); 33 | assertEquals(currentProjectDir, args.getProjectName()); 34 | } 35 | 36 | @Test 37 | public void testInputArgs_getProjectName_src() { 38 | InputArgs args = new InputArgs(System.getProperty("user.dir") + File.separator + "src", getTestingPath()); 39 | String currentProjectDir = new File(System.getProperty("user.dir")).getName(); 40 | assertEquals(currentProjectDir, args.getProjectName()); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /tests/DesigniteTests/DesigniteTests/SM_FieldTest.java: -------------------------------------------------------------------------------- 1 | package DesigniteTests; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import java.io.File; 6 | import java.util.List; 7 | 8 | import org.eclipse.jdt.core.dom.VariableDeclarationFragment; 9 | import org.junit.Before; 10 | import org.junit.Test; 11 | 12 | import Designite.ArgumentParser.InputArgs; 13 | import Designite.SourceModel.AccessStates; 14 | import Designite.SourceModel.SM_Field; 15 | import Designite.SourceModel.SM_Package; 16 | import Designite.SourceModel.SM_Project; 17 | import Designite.SourceModel.SM_Type; 18 | 19 | public class SM_FieldTest extends DesigniteTests { 20 | 21 | private SM_Project project; 22 | private SM_Field newField; 23 | private List fields; 24 | List fieldList; 25 | 26 | @Before 27 | public void setUp() { 28 | project = new SM_Project(new InputArgs(getTestingPath() + File.separator + "test_inputs", getTestingPath())); 29 | project.parse(); 30 | project.resolve(); 31 | fields = project.getPackageList().get(0).getTypeList().get(0).getFieldList(); 32 | } 33 | 34 | @Test 35 | public void SM_Field_getName() { 36 | assertEquals(fields.get(4).getName(), "publicField"); 37 | } 38 | 39 | @Test 40 | public void SM_Field_checkAccess() { 41 | if (fields.get(4).getName().equals("publicField")) 42 | assertEquals(fields.get(4).getAccessModifier(), AccessStates.PUBLIC); 43 | else 44 | fail(); 45 | } 46 | 47 | @Test 48 | public void SM_Field_checkParentType() { 49 | if (fields.get(4).getName().equals("publicField")) 50 | assertEquals(fields.get(4).getParentType().getName(), "TestMethods"); 51 | else 52 | fail(); 53 | } 54 | 55 | @Test 56 | public void SM_Field_check_StaticField() { 57 | if (fields.get(0).getName().equals("counter")) 58 | assertTrue(fields.get(0).isStatic()); 59 | else 60 | fail(); 61 | } 62 | 63 | @Test 64 | public void SM_Field_check_FinalField() { 65 | if (fields.get(3).getName().equals("CONSTANT")) 66 | assertTrue(fields.get(3).isFinal()); 67 | else 68 | fail(); 69 | } 70 | 71 | @Test 72 | public void SM_Method_getParent() { 73 | project.parse(); 74 | 75 | for (SM_Package pkg : project.getPackageList()) { 76 | if (pkg.getName().equals("test_package")) { 77 | for (SM_Type type : pkg.getTypeList()) { 78 | if (type.getName().equals("TestMethods")) { 79 | for (SM_Field field : type.getFieldList()) { 80 | if (field.getName().equals("counter")) 81 | assertEquals(field.getParentType().getParentPkg().getParentProject().getName(), 82 | "Project"); 83 | } 84 | } 85 | } 86 | } 87 | } 88 | } 89 | 90 | @Test 91 | public void SM_Method_getType() { 92 | newField = fields.get(0); 93 | assertEquals(newField.isPrimitiveType(), true); 94 | assertEquals(newField.getPrimitiveType(), "int"); 95 | } 96 | 97 | @Test 98 | public void SM_Method_getType_from_source() { 99 | newField = fields.get(4); 100 | assertEquals(newField.isPrimitiveType(), false); 101 | assertEquals(newField.getType().getName(), "TestMethods"); 102 | } 103 | 104 | @Test // is a List considered as SingleVariableDeclaration? 105 | public void SM_Method_check_listParameter() { 106 | newField = fields.get(1); 107 | assertEquals(newField.getPrimitiveType(), "List"); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /tests/DesigniteTests/DesigniteTests/SM_LocalVarTests.java: -------------------------------------------------------------------------------- 1 | package DesigniteTests; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | 5 | import java.io.File; 6 | import java.util.List; 7 | 8 | import org.eclipse.jdt.core.dom.VariableDeclarationFragment; 9 | import org.junit.Before; 10 | import org.junit.Test; 11 | 12 | import Designite.ArgumentParser.InputArgs; 13 | import Designite.SourceModel.SM_LocalVar; 14 | import Designite.SourceModel.SM_Method; 15 | import Designite.SourceModel.SM_Project; 16 | 17 | public class SM_LocalVarTests extends DesigniteTests { 18 | 19 | private SM_Project project; 20 | private SM_LocalVar newLocalVar; 21 | private List methods; 22 | List fieldList; 23 | 24 | @Before 25 | public void setUp() { 26 | project = new SM_Project(new InputArgs(getTestingPath() + File.separator + "test_inputs", getTestingPath())); 27 | project.parse(); 28 | project.resolve(); 29 | methods = project.getPackageList().get(0).getTypeList().get(0).getMethodList(); 30 | } 31 | 32 | @Test 33 | public void SM_LocalVar_getType() { 34 | newLocalVar = methods.get(0).getLocalVarList().get(0); 35 | assertEquals(newLocalVar.isPrimitiveType(), true); 36 | assertEquals(newLocalVar.getPrimitiveType(), "int"); 37 | } 38 | 39 | @Test 40 | public void SM_LocalVar_getType_from_source() { 41 | newLocalVar = methods.get(1).getLocalVarList().get(0); 42 | assertEquals(newLocalVar.isPrimitiveType(), false); 43 | assertEquals(newLocalVar.getType().getName(), "TestMethods"); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /tests/DesigniteTests/DesigniteTests/SM_MethodTest.java: -------------------------------------------------------------------------------- 1 | package DesigniteTests; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import java.io.File; 6 | import java.util.List; 7 | 8 | import org.eclipse.jdt.core.dom.CompilationUnit; 9 | import org.eclipse.jdt.core.dom.TypeDeclaration; 10 | import org.junit.Before; 11 | import org.junit.Test; 12 | 13 | import Designite.ArgumentParser.InputArgs; 14 | import Designite.SourceModel.AccessStates; 15 | import Designite.SourceModel.SM_Method; 16 | import Designite.SourceModel.SM_Package; 17 | import Designite.SourceModel.SM_Project; 18 | import Designite.SourceModel.SM_Type; 19 | 20 | public class SM_MethodTest extends DesigniteTests { 21 | 22 | private SM_Project project; 23 | private SM_Type type; 24 | private List methods; 25 | 26 | @SuppressWarnings("unchecked") 27 | @Before 28 | public void setUp() { 29 | project = new SM_Project(new InputArgs(getTestingPath() + File.separator + "test_package", getTestingPath())); 30 | CompilationUnit unit = project.createCU(getTestingPath() + File.separator + "test_package" + File.separator + "TestMethods.java"); 31 | List typeList = unit.types(); 32 | 33 | for(TypeDeclaration typeDecl: typeList){ 34 | type = new SM_Type(typeDecl, unit, new SM_Package("Test", project, null), null); 35 | type.parse(); 36 | } 37 | 38 | methods = type.getMethodList(); 39 | } 40 | 41 | @Test 42 | public void SM_Method_checkMethodName() { 43 | assertEquals(methods.get(1).getName(), "publicMethod"); 44 | } 45 | 46 | @Test 47 | public void SM_Method_checkAccess() { 48 | assertEquals(methods.get(1).getAccessModifier(), AccessStates.PUBLIC); 49 | } 50 | 51 | @Test 52 | public void SM_Method_isConstructor() { 53 | assertTrue(methods.get(0).isConstructor()); 54 | } 55 | 56 | @Test 57 | public void SM_Method_isStatic() { 58 | if (methods.get(2).getName().equals("count")) 59 | assertTrue(methods.get(2).isStatic()); 60 | else 61 | fail(); 62 | } 63 | 64 | /*@Test 65 | public void SM_Method_getParent() { 66 | project.parse(); 67 | 68 | for (SM_Package pkg: project.getPackageList()) { 69 | if (pkg.getName().equals("test_package")) { 70 | for (SM_Type type:pkg.getTypeList()) { 71 | if (type.getName().equals("TestMethods")) { 72 | for (SM_Method method:type.getMethodList()) { 73 | if (method.getName().equals("count")) 74 | assertEquals(method.getParent().getName(), "TestMethods"); 75 | } 76 | } 77 | } 78 | } 79 | } 80 | }*/ 81 | } 82 | -------------------------------------------------------------------------------- /tests/DesigniteTests/DesigniteTests/SM_Method_CalledMethodsTests.java: -------------------------------------------------------------------------------- 1 | package DesigniteTests; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | import static org.junit.Assert.fail; 5 | 6 | import java.io.File; 7 | 8 | import org.junit.Before; 9 | import org.junit.Test; 10 | 11 | import Designite.ArgumentParser.InputArgs; 12 | import Designite.SourceModel.SM_Method; 13 | import Designite.SourceModel.SM_Package; 14 | import Designite.SourceModel.SM_Project; 15 | import Designite.SourceModel.SM_Type; 16 | 17 | public class SM_Method_CalledMethodsTests extends DesigniteTests { 18 | 19 | private SM_Project project; 20 | 21 | 22 | @Before 23 | public void setUp() { 24 | createFileForArguments(CALLED_METHOD_TEST_INPUT_FILE_PATH, CALLED_METHOD_TEST_INPUT_FILE_CONTENT); 25 | project = new SM_Project(new InputArgs(getTestingPath() + File.separator + "test_inputs2", getTestingPath())); 26 | project.parse(); 27 | project.resolve(); 28 | } 29 | 30 | @Test 31 | public void SM_Method_CalledMethods_withinClass() { 32 | SM_Type type = getDesiredType(); 33 | if (type==null) 34 | fail(); 35 | SM_Method method = getDesiredMethod(type, "publicMethod"); 36 | if (method == null) 37 | fail(); 38 | if (method.getCalledMethods().size()==1) 39 | { 40 | SM_Method calledMethod = method.getCalledMethods().get(0); 41 | assertEquals("TestMethods", calledMethod.getParentType().getName()); 42 | assertEquals("print", calledMethod.getName()); 43 | } 44 | } 45 | 46 | @Test 47 | public void SM_Method_CalledMethods_outsideClass() { 48 | SM_Type type = getDesiredType(); 49 | if (type==null) 50 | fail(); 51 | SM_Method method = getDesiredMethod(type, "print"); 52 | if (method == null) 53 | fail(); 54 | if (method.getCalledMethods().size()==1) 55 | { 56 | SM_Method calledMethod = method.getCalledMethods().get(0); 57 | assertEquals("TestMethods2", calledMethod.getParentType().getName()); 58 | assertEquals("print2", calledMethod.getName()); 59 | } 60 | } 61 | 62 | @Test 63 | public void SM_Method_CalledMethods_staticMethod() { 64 | SM_Type type = getDesiredType(); 65 | if (type==null) 66 | fail(); 67 | SM_Method method = getDesiredMethod(type, "count"); 68 | if (method == null) 69 | fail(); 70 | if (method.getCalledMethods().size()==1) 71 | { 72 | SM_Method calledMethod = method.getCalledMethods().get(0); 73 | assertEquals("Logger", calledMethod.getParentType().getName()); 74 | assertEquals("log", calledMethod.getName()); 75 | } 76 | } 77 | 78 | private SM_Method getDesiredMethod(SM_Type type, String name) { 79 | for(SM_Method method:type.getMethodList()) 80 | if(method.getName().equals(name)) 81 | return method; 82 | return null; 83 | } 84 | 85 | private SM_Type getDesiredType() { 86 | for(SM_Package pkg:project.getPackageList()) 87 | for (SM_Type aType:pkg.getTypeList()) 88 | if(aType.getName().equals("TestMethods")) 89 | return aType; 90 | return null; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /tests/DesigniteTests/DesigniteTests/SM_PackageTest.java: -------------------------------------------------------------------------------- 1 | package DesigniteTests; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import java.io.File; 6 | import java.util.List; 7 | 8 | import org.eclipse.jdt.core.dom.CompilationUnit; 9 | import org.junit.Before; 10 | import org.junit.Test; 11 | 12 | import Designite.ArgumentParser.InputArgs; 13 | import Designite.SourceModel.SM_Package; 14 | import Designite.SourceModel.SM_Project; 15 | 16 | public class SM_PackageTest extends DesigniteTests { 17 | 18 | @Before 19 | public void setup() { 20 | 21 | } 22 | 23 | @Test 24 | public void SM_Package_positive_case() { 25 | SM_Project project = new SM_Project(new InputArgs(System.getProperty("user.dir"), getTestingPath())); 26 | project.parse(); 27 | List pkgList = project.getPackageList(); 28 | 29 | for (SM_Package pkg : pkgList) { 30 | if (pkg.getName().equals("Designite")) 31 | assertEquals(pkg.getTypeList().size(), 1); 32 | if (pkg.getName().equals("Designite.SourceModel")) 33 | //Added additional class in the package. 34 | assertEquals(21, pkg.getTypeList().size()); 35 | } 36 | } 37 | 38 | @Test 39 | // assert that every CU in pkgCUList is included in projectCUList 40 | public void SM_Package_cuList() { 41 | SM_Project project = new SM_Project(new InputArgs(getTestingPath() + File.separator + "test_package", getTestingPath())); 42 | project.parse(); 43 | 44 | List projectCUList = project.getCompilationUnitList(); 45 | List pkgList = project.getPackageList(); 46 | 47 | for (SM_Package pkg : pkgList) { 48 | List pkgCUList = pkg.getCompilationUnitList(); 49 | for (CompilationUnit pkgUnit : pkgCUList) 50 | assertTrue(projectCUList.contains(pkgUnit)); 51 | } 52 | } 53 | 54 | @Test 55 | public void SM_Package_nullInput() { 56 | SM_Package pkg = new SM_Package(null, null, null); 57 | assertEquals(pkg.getName(), null); 58 | } 59 | 60 | @Test 61 | public void SM_Package_countTypes() { 62 | SM_Project project = new SM_Project(new InputArgs(getTestingPath() + File.separator + "test_package", getTestingPath())); 63 | project.parse(); 64 | List pkgList = project.getPackageList(); 65 | 66 | for (SM_Package pkg : pkgList) { 67 | if (pkg.getName().equals("(default package)")) { 68 | assertEquals(pkg.getTypeList().size(), 1); 69 | } 70 | // Empty class is not included while counting types 71 | if (pkg.getName().equals("test_package")) { 72 | assertEquals(6, pkg.getTypeList().size()); 73 | } 74 | } 75 | } 76 | 77 | @Test 78 | public void SM_Package_getParent() { 79 | SM_Project project = new SM_Project(new InputArgs(getTestingPath() + File.separator + "test_package", getTestingPath())); 80 | project.parse(); 81 | List pkgList = project.getPackageList(); 82 | 83 | for (SM_Package pkg : pkgList) { 84 | if (pkg.getName().equals("Designite")) 85 | assertEquals(pkg.getParentProject(), project); 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /tests/DesigniteTests/DesigniteTests/SM_ParameterTest.java: -------------------------------------------------------------------------------- 1 | package DesigniteTests; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | 5 | import java.io.File; 6 | import java.util.List; 7 | 8 | import org.junit.Before; 9 | import org.junit.Test; 10 | 11 | import Designite.ArgumentParser.InputArgs; 12 | import Designite.SourceModel.SM_Method; 13 | import Designite.SourceModel.SM_Parameter; 14 | import Designite.SourceModel.SM_Project; 15 | 16 | public class SM_ParameterTest extends DesigniteTests { 17 | 18 | private SM_Project project; 19 | private SM_Parameter newParameter; 20 | private List methods; 21 | private List parameters; 22 | 23 | @Before 24 | public void setUp() { 25 | project = new SM_Project(new InputArgs(getTestingPath() + File.separator + "test_inputs", getTestingPath())); 26 | project.parse(); 27 | project.resolve(); 28 | methods = project.getPackageList().get(0).getTypeList().get(0).getMethodList(); 29 | } 30 | 31 | @Test 32 | public void SM_Parameter_check_getName() { 33 | parameters = getSpecificMethod("TestMethods").getParameterList(); 34 | newParameter = parameters.get(0); 35 | assertEquals(newParameter.getName(), "name"); 36 | } 37 | 38 | @Test 39 | public void SM_Parameter_getType() { 40 | parameters = getSpecificMethod("TestMethods").getParameterList(); 41 | newParameter = parameters.get(0); 42 | assertEquals(newParameter.isPrimitiveType(), true); 43 | assertEquals(newParameter.getPrimitiveType(), "String"); 44 | } 45 | 46 | @Test 47 | public void SM_Parameter_getType_from_source() { 48 | parameters = getSpecificMethod("publicMethod").getParameterList(); 49 | newParameter = parameters.get(0); 50 | assertEquals(newParameter.isPrimitiveType(), false); 51 | assertEquals(newParameter.getType().getName(), "TestMethods"); 52 | } 53 | @Test // is a List considered as SingleVariableDeclaration? 54 | public void SM_Parameter_check_listParameter() { 55 | parameters = getSpecificMethod("getList").getParameterList(); 56 | newParameter = parameters.get(0); 57 | assertEquals(newParameter.getPrimitiveType(), "List"); 58 | } 59 | private SM_Method getSpecificMethod(String methodName) { 60 | for(SM_Method method:methods) 61 | if(method.getName().equals(methodName)) 62 | return method; 63 | return null; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /tests/DesigniteTests/DesigniteTests/SM_ProjectTest.java: -------------------------------------------------------------------------------- 1 | package DesigniteTests; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import java.io.File; 6 | 7 | import org.junit.Test; 8 | 9 | import Designite.ArgumentParser.InputArgs; 10 | import Designite.SourceModel.SM_Project; 11 | 12 | public class SM_ProjectTest extends DesigniteTests { 13 | 14 | @Test 15 | public void testSM_Project_positive_case() { 16 | SM_Project project = new SM_Project(new InputArgs( System.getProperty("user.dir"), getTestingPath())); 17 | project.parse(); 18 | 19 | /*for (SM_Package pkg : project.getPackageList()) 20 | System.out.println(pkg.getName());*/ 21 | assertEquals(22, project.getPackageCount()); 22 | 23 | } 24 | 25 | @Test(expected = NullPointerException.class) 26 | public void testSM_Project_nullCU() { 27 | SM_Project project = new SM_Project(new InputArgs(getTestingPath() + File.separator + "test_package", getTestingPath())); 28 | project.setCompilationUnitList(null); 29 | project.parse(); 30 | } 31 | 32 | @Test 33 | public void testSM_Project_sourceFilesCounter() { 34 | SM_Project project = new SM_Project(new InputArgs(getTestingPath() + File.separator + "test_package", getTestingPath())); 35 | project.parse(); 36 | assertEquals(7, project.getSourceFileList().size()); 37 | } 38 | 39 | @Test 40 | public void testSM_Project_cuCounter() { 41 | SM_Project project = new SM_Project(new InputArgs(getTestingPath() + File.separator + "test_package", getTestingPath())); 42 | project.parse(); 43 | assertEquals(7, project.getCompilationUnitList().size()); 44 | } 45 | 46 | @Test 47 | public void testSM_Project_packageCounter() { 48 | SM_Project project = new SM_Project(new InputArgs(getTestingPath() + File.separator + "test_package", getTestingPath())); 49 | project.parse(); 50 | assertEquals(2, project.getPackageCount()); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /tests/DesigniteTests/DesigniteTests/SM_TypeTest.java: -------------------------------------------------------------------------------- 1 | package DesigniteTests; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | import static org.junit.Assert.assertTrue; 5 | 6 | import java.io.File; 7 | import java.util.List; 8 | 9 | import org.eclipse.jdt.core.dom.CompilationUnit; 10 | import org.eclipse.jdt.core.dom.TypeDeclaration; 11 | import org.junit.Before; 12 | import org.junit.Test; 13 | 14 | import Designite.ArgumentParser.InputArgs; 15 | import Designite.SourceModel.AccessStates; 16 | import Designite.SourceModel.SM_Package; 17 | import Designite.SourceModel.SM_Project; 18 | import Designite.SourceModel.SM_Type; 19 | 20 | public class SM_TypeTest extends DesigniteTests { 21 | 22 | private SM_Project project; 23 | private SM_Type type; 24 | 25 | @Before 26 | public void setUp() { 27 | project = new SM_Project(new InputArgs(getTestingPath() + File.separator + "test_package", getTestingPath())); 28 | } 29 | 30 | @Test 31 | public void SM_Type_getName() { 32 | CompilationUnit unit = project.createCU(getTestingPath() + File.separator + "test_package" +File.separator + "TestClass.java"); 33 | List typeList = unit.types(); 34 | 35 | SM_Type type = null; 36 | for (TypeDeclaration typeDecl : typeList) 37 | type = new SM_Type(typeDecl, unit, new SM_Package("Test", project, null), null); 38 | 39 | assertEquals(type.getName(), "TestClass"); 40 | } 41 | 42 | @Test 43 | public void SM_Type_checkDefaultAccess() { 44 | CompilationUnit unit = project.createCU(getTestingPath() + File.separator + "test_package" +File.separator + "DefaultClass.java"); 45 | List typeList = unit.types(); 46 | 47 | SM_Type type = null; 48 | for (TypeDeclaration typeDecl : typeList) 49 | type = new SM_Type(typeDecl, unit, new SM_Package("Test", project, null), null); 50 | assertEquals(type.getAccessModifier(), AccessStates.DEFAULT); 51 | } 52 | 53 | @Test 54 | public void SM_Type_check_isAbstract() { 55 | CompilationUnit unit = project.createCU(getTestingPath() + File.separator +"test_package" + File.separator + "AbstractClass.java"); 56 | List typeList = unit.types(); 57 | 58 | SM_Type type = null; 59 | for (TypeDeclaration typeDecl : typeList) 60 | type = new SM_Type(typeDecl, unit, new SM_Package("Test", project, null), null); 61 | assertTrue(type.isAbstract()); 62 | } 63 | 64 | @Test 65 | public void SM_Type_check_isInterface() { 66 | CompilationUnit unit = project.createCU(getTestingPath() + File.separator +"test_package"+File.separator +"Interface.java"); 67 | List typeList = unit.types(); 68 | 69 | SM_Type type = null; 70 | for (TypeDeclaration typeDecl : typeList) 71 | type = new SM_Type(typeDecl, unit, new SM_Package("Test", project, null), null); 72 | assertTrue(type.isInterface()); 73 | } 74 | 75 | @Test //too complicated for the moment 76 | public void SM_Type_check_isNestedClass() { 77 | SM_Project project = new SM_Project(new InputArgs(getTestingPath() + File.separator +"test_package", getTestingPath())); 78 | project.parse(); 79 | List packageList = project.getPackageList(); 80 | 81 | for (SM_Package pkg: packageList) { 82 | if (pkg.getName().equals("test_package")) { 83 | List list = pkg.getTypeList(); 84 | for (SM_Type type:list) { 85 | if (type.getName().equals("InnerClass")) 86 | assertTrue(type.isNestedClass()); 87 | } 88 | } 89 | } 90 | } 91 | 92 | @Test(expected = NullPointerException.class) 93 | public void SM_Type_nullTypeDeclaration() { 94 | CompilationUnit unit = project.createCU(getTestingPath() + File.separator +"test_package"+File.separator +"TestClass.java"); 95 | type = new SM_Type(null, unit, null, null); 96 | } 97 | 98 | @Test(expected = NullPointerException.class) 99 | public void SM_Type_nullCompilationUnit() { 100 | CompilationUnit unit = project.createCU(getTestingPath() + File.separator +"test_package"+File.separator +"TestClass.java"); 101 | List listOfTypes = unit.types(); 102 | 103 | type = new SM_Type(listOfTypes.get(0), null, null, null); 104 | } 105 | 106 | @Test 107 | public void SM_Type_countFields() { 108 | project.parse(); 109 | List packageList = project.getPackageList(); 110 | 111 | for (SM_Package pkg: packageList) { 112 | if (pkg.getName().equals("test_package")) { 113 | List list = pkg.getTypeList(); 114 | for (SM_Type type:list) { 115 | if (type.getName().equals("TestMethods")) 116 | assertEquals(type.getFieldList().size(), 5); 117 | } 118 | } 119 | } 120 | } 121 | 122 | @Test 123 | public void SM_Type_countMethods() { 124 | SM_Project project = new SM_Project(new InputArgs(getTestingPath() + File.separator +"test_package", getTestingPath())); 125 | project.parse(); 126 | List packageList = project.getPackageList(); 127 | 128 | for (SM_Package pkg: packageList) { 129 | if (pkg.getName().equals("test_package")) { 130 | List list = pkg.getTypeList(); 131 | for (SM_Type type:list) { 132 | if (type.getName().equals("TestMethods")) 133 | assertEquals(type.getMethodList().size(), 5); 134 | } 135 | } 136 | } 137 | } 138 | 139 | @Test 140 | public void testHierarchyGraph() { 141 | project = new SM_Project(new InputArgs(getTestingPath() + File.separator + "metrics", getTestingPath())); 142 | project.parse(); 143 | project.resolve(); 144 | 145 | int expected = 6; 146 | int actual = project.getHierarchyGraph().getConnectedComponnents().size(); 147 | 148 | assertEquals(expected, actual); 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /tests/DesigniteTests/DesigniteTests/metrics/MethodMetricsTest.java: -------------------------------------------------------------------------------- 1 | package DesigniteTests.metrics; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | 5 | import java.io.File; 6 | 7 | import org.junit.Before; 8 | import org.junit.Test; 9 | 10 | import Designite.ArgumentParser.InputArgs; 11 | import Designite.SourceModel.SM_Method; 12 | import Designite.SourceModel.SM_Project; 13 | import Designite.SourceModel.SM_Type; 14 | import Designite.metrics.MethodMetrics; 15 | import DesigniteTests.DesigniteTests; 16 | 17 | public class MethodMetricsTest extends DesigniteTests { 18 | 19 | private SM_Project project; 20 | private MethodMetrics methodMetrics; 21 | 22 | @Before 23 | public void setUp() { 24 | project = new SM_Project(new InputArgs(getTestingPath() + File.separator + "metrics", getTestingPath())); 25 | project.parse(); 26 | project.resolve(); 27 | project.computeMetrics(); 28 | SM_Type type = getSpecificType("TestMetricsClass"); 29 | SM_Method method = getSpecificMethod(type, "publicMethod"); 30 | methodMetrics = type.getMetricsFromMethod(method); 31 | } 32 | 33 | @Test 34 | public void testNumOfParameters() { 35 | int expected = 5; 36 | int actual = methodMetrics.getNumOfParameters(); 37 | 38 | assertEquals(expected, actual); 39 | } 40 | 41 | @Test 42 | public void testCyclomaicComplexity() { 43 | int expected = 9; 44 | int actual = methodMetrics.getCyclomaticComplexity(); 45 | 46 | assertEquals(expected, actual); 47 | } 48 | 49 | 50 | @Test 51 | public void testNumberOfDirectFieldsUsed() { 52 | SM_Type type = getSpecificType("TestMetricsClass"); 53 | SM_Method method = getSpecificMethod(type, "publicMethod"); 54 | 55 | int expected = 2; 56 | int actual = type.getMetricsFromMethod(method).getDirectFieldAccesses().size(); 57 | 58 | assertEquals(expected, actual); 59 | } 60 | 61 | private SM_Method getSpecificMethod(SM_Type type, String methodName) { 62 | for(SM_Method method:type.getMethodList()) 63 | if(method.getName().equals(methodName)) 64 | return method; 65 | return null; 66 | } 67 | 68 | private SM_Type getSpecificType(String name) { 69 | for(SM_Type type:project.getPackageList().get(0).getTypeList()) 70 | if(type.getName().equals(name)) 71 | return type; 72 | return null; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /tests/DesigniteTests/DesigniteTests/metrics/TypeMetricsTest.java: -------------------------------------------------------------------------------- 1 | package DesigniteTests.metrics; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | 5 | import java.io.File; 6 | 7 | import org.junit.Before; 8 | import org.junit.Test; 9 | 10 | import Designite.ArgumentParser.InputArgs; 11 | import Designite.SourceModel.SM_Package; 12 | import Designite.SourceModel.SM_Project; 13 | import Designite.SourceModel.SM_Type; 14 | import Designite.metrics.TypeMetrics; 15 | import DesigniteTests.DesigniteTests; 16 | 17 | public class TypeMetricsTest extends DesigniteTests { 18 | 19 | private SM_Project project; 20 | private TypeMetrics typeMetrics; 21 | 22 | @Before 23 | public void setUp() { 24 | createFileForArguments(METRICS_FILE_PATH, METRICS_FILE_CONTENT); 25 | project = new SM_Project(new InputArgs(getTestingPath() + File.separator + "metrics", getTestingPath())); 26 | project.parse(); 27 | project.resolve(); 28 | project.computeMetrics(); 29 | SM_Package pkg = project.getPackageList().get(0); 30 | SM_Type type = getSpecificType("TestMetricsClass"); 31 | typeMetrics = pkg.getMetricsFromType(type); 32 | } 33 | 34 | private SM_Type getSpecificType(String name) { 35 | for(SM_Type type:project.getPackageList().get(0).getTypeList()) 36 | if(type.getName().equals(name)) 37 | return type; 38 | return null; 39 | } 40 | 41 | @Test 42 | public void testNumOfFieldsProperlyReturned() { 43 | int expected = 3; 44 | int actual = typeMetrics.getNumOfFields(); 45 | 46 | assertEquals(expected, actual); 47 | } 48 | 49 | @Test 50 | public void testNumOfPublicFieldsProperlyReturned() { 51 | int expected = 1; 52 | int actual = typeMetrics.getNumOfPublicFields(); 53 | 54 | assertEquals(expected, actual); 55 | } 56 | 57 | @Test 58 | public void testNumOfMethodsProperlyReturned() { 59 | int expected = 2; 60 | int actual = typeMetrics.getNumOfMethods(); 61 | 62 | assertEquals(expected, actual); 63 | } 64 | 65 | @Test 66 | public void testNumOfPublicMethodsProperlyReturned() { 67 | int expected = 1; 68 | int actual = typeMetrics.getNumOfPublicMethods(); 69 | 70 | assertEquals(expected, actual); 71 | } 72 | 73 | @Test 74 | public void testInheritanceDepth() { 75 | int expected = 3; 76 | int actual = typeMetrics.getInheritanceDepth(); 77 | 78 | assertEquals(expected, actual); 79 | } 80 | 81 | 82 | @Test 83 | public void testNumOfChildren() { 84 | int expected = 2; 85 | int actual = typeMetrics.getNumOfChildren(); 86 | 87 | assertEquals(expected, actual); 88 | 89 | } 90 | 91 | @Test 92 | public void testWeightedMethodsPerClass() { 93 | int expected = 10; 94 | int actual = typeMetrics.getWeightedMethodsPerClass(); 95 | 96 | assertEquals(expected, actual); 97 | } 98 | 99 | @Test 100 | public void testFanOutTypes() { 101 | int expected = 5; 102 | int actual = typeMetrics.getNumOfFanOutTypes(); 103 | 104 | //SM_Type type = getSpecificType("TestMetricsClass"); 105 | //System.out.println(type.getReferencedTypeList().toString()); 106 | 107 | assertEquals(expected, actual); 108 | } 109 | 110 | @Test 111 | public void testFanInTypes() { 112 | int expected = 2; 113 | int actual = typeMetrics.getNumOfFanInTypes(); 114 | 115 | assertEquals(expected, actual); 116 | } 117 | 118 | @Test 119 | public void testLCOMWhenInterface() { 120 | SM_Package pkg = project.getPackageList().get(0); 121 | // SM_Type someInterface = pkg.getTypeList().get(0); 122 | SM_Type someInterface = getSpecificType("InterfaceChild2"); 123 | double delta = 0.01; 124 | 125 | double expected = -1.0; 126 | double actual = pkg.getMetricsFromType(someInterface).getLcom(); 127 | 128 | assertEquals(expected, actual, delta); 129 | } 130 | 131 | @Test 132 | public void testLCOMWhenNoFields() { 133 | SM_Package pkg = project.getPackageList().get(0); 134 | SM_Type foreignClass4 = pkg.getTypeList().get(10); 135 | double delta = 0.01; 136 | 137 | double expected = -1.0; 138 | double actual = pkg.getMetricsFromType(foreignClass4).getLcom(); 139 | 140 | assertEquals(expected, actual, delta); 141 | } 142 | 143 | @Test 144 | public void testLCOMWhenNoMethods() { 145 | SM_Package pkg = project.getPackageList().get(0); 146 | //SM_Type foreignClass1 = pkg.getTypeList().get(9); 147 | SM_Type foreignClass1 = getSpecificType("ForeignClass1"); 148 | double delta = 0.01; 149 | 150 | double expected = -1.0; 151 | double actual = pkg.getMetricsFromType(foreignClass1).getLcom(); 152 | 153 | assertEquals(expected, actual, delta); 154 | } 155 | 156 | @Test 157 | public void testLCOMWhenHasTwoComponents() { 158 | double delta = 0.01; 159 | 160 | double expected = 1.0; 161 | double actual = typeMetrics.getLcom(); 162 | 163 | assertEquals(expected, actual, delta); 164 | } 165 | 166 | @Test 167 | public void testLCOMWhenHasOneComponent() { 168 | SM_Package pkg = project.getPackageList().get(0); 169 | SM_Type child2 = getSpecificType("Child2"); 170 | double delta = 0.01; 171 | 172 | double expected = 0.0; 173 | double actual = pkg.getMetricsFromType(child2).getLcom(); 174 | 175 | assertEquals(expected, actual, delta); 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /tests/DesigniteTests/DesigniteTests/smells/ThresholdsParserTest.java: -------------------------------------------------------------------------------- 1 | package DesigniteTests.smells; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import java.io.File; 6 | import java.io.FileNotFoundException; 7 | 8 | import org.junit.Test; 9 | 10 | import Designite.smells.ThresholdsDTO; 11 | import Designite.smells.ThresholdsParser; 12 | import DesigniteTests.DesigniteTests; 13 | 14 | public class ThresholdsParserTest extends DesigniteTests { 15 | 16 | @Test 17 | public void testNumberOfThresholds() { 18 | ThresholdsDTO dto = new ThresholdsDTO(); 19 | 20 | int expected = 19; 21 | int actual = dto.getClass().getDeclaredFields().length; 22 | 23 | assertEquals(expected, actual); 24 | } 25 | 26 | @Test 27 | public void testParseThresholdsHappyPath() { 28 | ThresholdsParser parser = new ThresholdsParser(getTestingPath() 29 | + File.separator + "codeSmells" 30 | + File.separator + "thresholdsDefault.txt"); 31 | try { 32 | parser.parseThresholds(); 33 | } catch(Exception e) { 34 | fail(); 35 | } 36 | } 37 | 38 | @Test 39 | public void testParseThresholdsThrowsErrorWhenFileIsMissing() { 40 | ThresholdsParser parser = new ThresholdsParser(getTestingPath() 41 | + File.separator + "codeSmells" 42 | + File.separator + "missingFile.txt"); 43 | try { 44 | parser.parseThresholds(); 45 | fail(); 46 | } catch(FileNotFoundException e) { 47 | 48 | } catch(Exception e) { 49 | fail(); 50 | } 51 | } 52 | 53 | @Test 54 | public void testParseThresholdThrowsErrorWhenNoNumberAsValue() { 55 | ThresholdsParser parser = new ThresholdsParser(getTestingPath() 56 | + File.separator + "codeSmells" 57 | + File.separator + "wrongRowFormatNoNumberAsKey.txt"); 58 | try { 59 | parser.parseThresholds(); 60 | } catch(IllegalArgumentException e) { 61 | String expected = "Line: insufficientModularizationLargePublicInterface = abc" 62 | + "\nis not of the form 'someDescription' = 'someNumber'"; 63 | String actual = e.getMessage(); 64 | //System.out.println(actual); 65 | assertEquals(expected, actual); 66 | } catch(Exception e) { 67 | fail(); 68 | } 69 | } 70 | 71 | @Test 72 | public void testParseThresholdThrowsErrorWhenMissingEquals() { 73 | ThresholdsParser parser = new ThresholdsParser(getTestingPath() 74 | + File.separator + "codeSmells" 75 | + File.separator + "wrongRowFormatNoEquals.txt"); 76 | try { 77 | parser.parseThresholds(); 78 | } catch(IllegalArgumentException e) { 79 | String expected = "Line: insufficientModularizationLargePublicInterface 20" 80 | + "\nis not of the form 'someDescription' = 'someNumber'"; 81 | String actual = e.getMessage(); 82 | //System.out.println(actual); 83 | assertEquals(expected, actual); 84 | } catch(Exception e) { 85 | fail(); 86 | } 87 | } 88 | 89 | @Test 90 | public void testParseThresholdThrowsErrorWhenWrongKey() { 91 | ThresholdsParser parser = new ThresholdsParser(getTestingPath() 92 | + File.separator + "codeSmells" 93 | + File.separator + "wrongRowFormatNoEquals.txt"); 94 | try { 95 | parser.parseThresholds(); 96 | } catch(IllegalArgumentException e) { 97 | String expected = "Line: insufficientModularizationLargePublicInterface 20" 98 | + "\nis not of the form 'someDescription' = 'someNumber'"; 99 | String actual = e.getMessage(); 100 | //System.out.println(actual); 101 | assertEquals(expected, actual); 102 | } catch(Exception e) { 103 | fail(); 104 | } 105 | } 106 | 107 | @Test 108 | public void testParseThresholdThrowsErrorWhenThresholdDoesNotExist() { 109 | ThresholdsParser parser = new ThresholdsParser(getTestingPath() 110 | + File.separator + "codeSmells" 111 | + File.separator + "notExistingThreshold.txt"); 112 | try { 113 | parser.parseThresholds(); 114 | fail(); 115 | } catch(IllegalArgumentException e) { 116 | String expected = "No such threshold: myTheshold"; 117 | String actual = e.getMessage(); 118 | //System.out.println(actual); 119 | assertEquals(expected, actual); 120 | } catch(Exception e) { 121 | fail(); 122 | } 123 | } 124 | 125 | @Test 126 | public void testParseThresholdReadsSuccessfullyFromConfigFile() { 127 | ThresholdsParser parser = new ThresholdsParser(getTestingPath() 128 | + File.separator + "codeSmells" 129 | + File.separator + "thresholdsNonDefault.txt"); 130 | try { 131 | parser.parseThresholds(); 132 | 133 | int expected = 14; 134 | int actual = parser 135 | .getThresholds() 136 | .getInsufficientModularizationLargePublicInterface(); 137 | 138 | assertEquals(expected, actual); 139 | } catch(Exception e) { 140 | fail(); 141 | } 142 | } 143 | 144 | } 145 | -------------------------------------------------------------------------------- /tests/DesigniteTests/DesigniteTests/smells/designSmells/EncapsulationSmellDetectorTest.java: -------------------------------------------------------------------------------- 1 | package DesigniteTests.smells.designSmells; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | import static org.mockito.Mockito.mock; 5 | import static org.mockito.Mockito.when; 6 | 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | import org.junit.Test; 11 | 12 | import Designite.SourceModel.SM_Method; 13 | import Designite.SourceModel.SM_Package; 14 | import Designite.SourceModel.SM_Project; 15 | import Designite.SourceModel.SM_Type; 16 | import Designite.SourceModel.SourceItemInfo; 17 | import Designite.metrics.TypeMetrics; 18 | //import Designite.smells.ThresholdsDTO; 19 | import Designite.smells.designSmells.EncapsulationSmellDetector; 20 | import Designite.utils.models.Graph; 21 | 22 | public class EncapsulationSmellDetectorTest { 23 | 24 | private SourceItemInfo info = new SourceItemInfo("testProject", "testPackage", "testType"); 25 | //private ThresholdsDTO thresholds = new ThresholdsDTO(); 26 | 27 | @Test 28 | public void testDeficientEncapsulationWhenHappyPath() { 29 | TypeMetrics metrics = mock(TypeMetrics.class); 30 | when(metrics.getNumOfPublicFields()).thenReturn(0); 31 | EncapsulationSmellDetector detector = new EncapsulationSmellDetector(metrics, info); 32 | 33 | int expected = 0; 34 | int actual = detector.detectDeficientEncapsulation().size(); 35 | 36 | assertEquals(expected, actual); 37 | } 38 | 39 | @Test 40 | public void testDeficientEncapsulationWhenSmellIsDetected() { 41 | TypeMetrics metrics = mock(TypeMetrics.class); 42 | when(metrics.getNumOfPublicFields()).thenReturn(1); 43 | EncapsulationSmellDetector detector = new EncapsulationSmellDetector(metrics, info); 44 | 45 | int expected = 1; 46 | int actual = detector.detectDeficientEncapsulation().size(); 47 | 48 | assertEquals(expected, actual); 49 | } 50 | 51 | @Test 52 | public void testUnexploitedEncapsulationWhenHappyPath() { 53 | TypeMetrics metrics = mock(TypeMetrics.class); 54 | SM_Type type = mock(SM_Type.class); 55 | SM_Method method = mock(SM_Method.class); 56 | SM_Type type1 = mock(SM_Type.class); 57 | SM_Type type2 = mock(SM_Type.class); 58 | SM_Package pkg = mock(SM_Package.class); 59 | SM_Project project = mock(SM_Project.class); 60 | Graph hierarchyGraph = mock(Graph.class); 61 | List methodList = new ArrayList<>(); 62 | methodList.add(method); 63 | List instanceOfTypes = new ArrayList<>(); 64 | instanceOfTypes.add(type1); 65 | instanceOfTypes.add(type2); 66 | when(metrics.getType()).thenReturn(type); 67 | when(type.getMethodList()).thenReturn(methodList); 68 | when(method.getSMTypesInInstanceOf()).thenReturn(instanceOfTypes); 69 | when(type1.getParentPkg()).thenReturn(pkg); 70 | when(type2.getParentPkg()).thenReturn(pkg); 71 | when(pkg.getParentProject()).thenReturn(project); 72 | when(project.getHierarchyGraph()).thenReturn(hierarchyGraph); 73 | when(hierarchyGraph.inSameConnectedComponent(type1, type2)).thenReturn(false); 74 | EncapsulationSmellDetector detector = new EncapsulationSmellDetector(metrics, info); 75 | 76 | int expected = 0; 77 | int actual = detector.detectUnexploitedEncapsulation().size(); 78 | 79 | assertEquals(expected, actual); 80 | } 81 | 82 | @Test 83 | public void testUnexploitedEncapsulationWhenSmellOccurs() { 84 | TypeMetrics metrics = mock(TypeMetrics.class); 85 | SM_Type type = mock(SM_Type.class); 86 | SM_Method method = mock(SM_Method.class); 87 | SM_Type type1 = mock(SM_Type.class); 88 | SM_Type type2 = mock(SM_Type.class); 89 | SM_Package pkg = mock(SM_Package.class); 90 | SM_Project project = mock(SM_Project.class); 91 | Graph hierarchyGraph = mock(Graph.class); 92 | List methodList = new ArrayList<>(); 93 | methodList.add(method); 94 | List instanceOfTypes = new ArrayList<>(); 95 | instanceOfTypes.add(type1); 96 | instanceOfTypes.add(type2); 97 | when(metrics.getType()).thenReturn(type); 98 | when(type.getMethodList()).thenReturn(methodList); 99 | when(method.getSMTypesInInstanceOf()).thenReturn(instanceOfTypes); 100 | when(type1.getParentPkg()).thenReturn(pkg); 101 | when(type2.getParentPkg()).thenReturn(pkg); 102 | when(pkg.getParentProject()).thenReturn(project); 103 | when(project.getHierarchyGraph()).thenReturn(hierarchyGraph); 104 | when(hierarchyGraph.inSameConnectedComponent(type1, type2)).thenReturn(true); 105 | EncapsulationSmellDetector detector = new EncapsulationSmellDetector(metrics, info); 106 | 107 | int expected = 1; 108 | int actual = detector.detectUnexploitedEncapsulation().size(); 109 | 110 | assertEquals(expected, actual); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /tests/DesigniteTests/DesigniteTests/smells/designSmells/ModularizationSmellDetectorTest.java: -------------------------------------------------------------------------------- 1 | package DesigniteTests.smells.designSmells; 2 | 3 | import static org.junit.Assert.*; 4 | import static org.mockito.Mockito.*; 5 | 6 | import java.util.List; 7 | import java.util.ArrayList; 8 | 9 | import org.junit.Test; 10 | 11 | import Designite.SourceModel.SM_Package; 12 | import Designite.SourceModel.SM_Project; 13 | import Designite.SourceModel.SM_Type; 14 | import Designite.SourceModel.SourceItemInfo; 15 | import Designite.metrics.TypeMetrics; 16 | import Designite.smells.ThresholdsDTO; 17 | import Designite.smells.designSmells.ModularizationSmellDetector; 18 | import Designite.utils.models.Graph; 19 | import Designite.utils.models.Vertex; 20 | 21 | public class ModularizationSmellDetectorTest { 22 | 23 | private SourceItemInfo info = new SourceItemInfo("testProject", "testPackage", "testType"); 24 | private ThresholdsDTO thresholds = new ThresholdsDTO(); 25 | 26 | @Test 27 | public void testBrokenModularizationWhenHappyPathWithAtLeastOneMethod() { 28 | TypeMetrics metrics = mock(TypeMetrics.class); 29 | when(metrics.getNumOfMethods()) 30 | .thenReturn(1); 31 | when(metrics.getNumOfFields()) 32 | .thenReturn(thresholds.getBrokenModularizationLargeFieldSet() + 1); 33 | ModularizationSmellDetector detector = new ModularizationSmellDetector(metrics, info); 34 | 35 | int expected = 0; 36 | int actual = detector.detectBrokenModularization().size(); 37 | 38 | assertEquals(expected, actual); 39 | } 40 | 41 | @Test 42 | public void testBrokenModularizationWhenHappyPathWithFewFields() { 43 | TypeMetrics metrics = mock(TypeMetrics.class); 44 | when(metrics.getNumOfMethods()) 45 | .thenReturn(0); 46 | when(metrics.getNumOfFields()) 47 | .thenReturn(thresholds.getBrokenModularizationLargeFieldSet() - 1); 48 | ModularizationSmellDetector detector = new ModularizationSmellDetector(metrics, info); 49 | 50 | int expected = 0; 51 | int actual = detector.detectBrokenModularization().size(); 52 | 53 | assertEquals(expected, actual); 54 | } 55 | 56 | @Test 57 | public void testBrokenModularizationWhenSmellIsDetected() { 58 | TypeMetrics metrics = mock(TypeMetrics.class); 59 | when(metrics.getNumOfMethods()) 60 | .thenReturn(0); 61 | when(metrics.getNumOfFields()) 62 | .thenReturn(thresholds.getBrokenModularizationLargeFieldSet() + 1); 63 | ModularizationSmellDetector detector = new ModularizationSmellDetector(metrics, info); 64 | 65 | int expected = 1; 66 | int actual = detector.detectBrokenModularization().size(); 67 | 68 | assertEquals(expected, actual); 69 | } 70 | 71 | @Test 72 | public void testCyclicDependentModularizationWhenHappyPath() { 73 | TypeMetrics metrics = mock(TypeMetrics.class); 74 | SM_Type type = mock(SM_Type.class); 75 | SM_Package pkg = mock(SM_Package.class); 76 | SM_Project project = mock(SM_Project.class); 77 | Graph dependencyGraph = mock(Graph.class); 78 | List component = new ArrayList<>(); 79 | component.add(type); 80 | when(metrics.getType()).thenReturn(type); 81 | when(type.getParentPkg()).thenReturn(pkg); 82 | when(pkg.getParentProject()).thenReturn(project); 83 | when(project.getDependencyGraph()).thenReturn(dependencyGraph); 84 | when(dependencyGraph.getStrongComponentOfVertex(type)).thenReturn(component); 85 | ModularizationSmellDetector detector = new ModularizationSmellDetector(metrics, info); 86 | 87 | int expected = 0; 88 | int actual = detector.detectCyclicDependentModularization().size(); 89 | 90 | assertEquals(expected, actual); 91 | } 92 | 93 | @Test 94 | public void testCyclicDependentModularizationWhenSmellOccurs() { 95 | TypeMetrics metrics = mock(TypeMetrics.class); 96 | SM_Type type = mock(SM_Type.class); 97 | SM_Type cyclicDependentType = mock(SM_Type.class); 98 | SM_Package pkg = mock(SM_Package.class); 99 | SM_Project project = mock(SM_Project.class); 100 | Graph dependencyGraph = mock(Graph.class); 101 | List component = new ArrayList<>(); 102 | component.add(type); 103 | component.add(cyclicDependentType); 104 | when(metrics.getType()).thenReturn(type); 105 | when(type.getParentPkg()).thenReturn(pkg); 106 | when(pkg.getParentProject()).thenReturn(project); 107 | when(project.getDependencyGraph()).thenReturn(dependencyGraph); 108 | when(dependencyGraph.getStrongComponentOfVertex(type)).thenReturn(component); 109 | ModularizationSmellDetector detector = new ModularizationSmellDetector(metrics, info); 110 | 111 | int expected = 1; 112 | int actual = detector.detectCyclicDependentModularization().size(); 113 | 114 | assertEquals(expected, actual); 115 | } 116 | 117 | @Test 118 | public void testInsufficientModularizationHappyPath() { 119 | TypeMetrics metrics = mock(TypeMetrics.class); 120 | when(metrics.getNumOfPublicMethods()) 121 | .thenReturn(thresholds.getInsufficientModularizationLargePublicInterface() - 1); 122 | when(metrics.getNumOfMethods()) 123 | .thenReturn(thresholds.getInsufficientModularizationLargeNumOfMethods() - 1); 124 | when(metrics.getWeightedMethodsPerClass()) 125 | .thenReturn(thresholds.getInsufficientModularizationHighComplexity() - 1); 126 | ModularizationSmellDetector detector = new ModularizationSmellDetector(metrics, info); 127 | 128 | int expected = 0; 129 | int actual = detector.detectInsufficientModularization().size(); 130 | 131 | assertEquals(expected, actual); 132 | } 133 | 134 | @Test 135 | public void testInsufficientModularizationWhenLargePublicInteface() { 136 | TypeMetrics metrics = mock(TypeMetrics.class); 137 | when(metrics.getNumOfPublicMethods()) 138 | .thenReturn(thresholds.getInsufficientModularizationLargePublicInterface() + 1); 139 | ModularizationSmellDetector detector = new ModularizationSmellDetector(metrics, info); 140 | 141 | int expected = 1; 142 | int actual = detector.detectInsufficientModularization().size(); 143 | 144 | assertEquals(expected, actual); 145 | } 146 | 147 | @Test 148 | public void testInsufficientModularizationWhenLargeNumOfMethods() { 149 | TypeMetrics metrics = mock(TypeMetrics.class); 150 | when(metrics.getNumOfMethods()) 151 | .thenReturn(thresholds.getInsufficientModularizationLargeNumOfMethods() + 1); 152 | ModularizationSmellDetector detector = new ModularizationSmellDetector(metrics, info); 153 | 154 | int expected = 1; 155 | int actual = detector.detectInsufficientModularization().size(); 156 | 157 | assertEquals(expected, actual); 158 | } 159 | 160 | @Test 161 | public void testInsufficientModularizationWhenHighComplexity() { 162 | TypeMetrics metrics = mock(TypeMetrics.class); 163 | when(metrics.getWeightedMethodsPerClass()) 164 | .thenReturn(thresholds.getInsufficientModularizationHighComplexity() + 1); 165 | ModularizationSmellDetector detector = new ModularizationSmellDetector(metrics, info); 166 | 167 | int expected = 1; 168 | int actual = detector.detectInsufficientModularization().size(); 169 | 170 | assertEquals(expected, actual); 171 | } 172 | 173 | @Test 174 | public void testHubLikeModularizationWhenHappyPathWithSmallFanIn() { 175 | TypeMetrics metrics = mock(TypeMetrics.class); 176 | when(metrics.getNumOfFanInTypes()) 177 | .thenReturn(thresholds.getHubLikeModularizationLargeFanIn() - 1); 178 | when(metrics.getNumOfFanInTypes()) 179 | .thenReturn(thresholds.getHubLikeModularizationLargeFanOut() + 1); 180 | ModularizationSmellDetector detector = new ModularizationSmellDetector(metrics, info); 181 | 182 | int expected = 0; 183 | int actual = detector.detectHubLikeModularization().size(); 184 | 185 | assertEquals(expected, actual); 186 | } 187 | 188 | @Test 189 | public void testHubLikeModularizationWhenHappyPathWithSmallFanOut() { 190 | TypeMetrics metrics = mock(TypeMetrics.class); 191 | when(metrics.getNumOfFanInTypes()) 192 | .thenReturn(thresholds.getHubLikeModularizationLargeFanIn() + 1); 193 | when(metrics.getNumOfFanInTypes()) 194 | .thenReturn(thresholds.getHubLikeModularizationLargeFanOut() - 1); 195 | ModularizationSmellDetector detector = new ModularizationSmellDetector(metrics, info); 196 | 197 | int expected = 0; 198 | int actual = detector.detectHubLikeModularization().size(); 199 | 200 | assertEquals(expected, actual); 201 | } 202 | 203 | @Test 204 | public void testHubLikeModularizationWhenSmellIsDetected() { 205 | TypeMetrics metrics = mock(TypeMetrics.class); 206 | when(metrics.getNumOfFanInTypes()) 207 | .thenReturn(thresholds.getHubLikeModularizationLargeFanIn() + 1); 208 | when(metrics.getNumOfFanOutTypes()) 209 | .thenReturn(thresholds.getHubLikeModularizationLargeFanOut() + 1); 210 | ModularizationSmellDetector detector = new ModularizationSmellDetector(metrics, info); 211 | 212 | int expected = 1; 213 | int actual = detector.detectHubLikeModularization().size(); 214 | 215 | assertEquals(expected, actual); 216 | } 217 | 218 | } 219 | -------------------------------------------------------------------------------- /tests/DesigniteTests/DesigniteTests/utils/models/GraphTest.java: -------------------------------------------------------------------------------- 1 | package DesigniteTests.utils.models; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | 5 | import org.junit.Before; 6 | import org.junit.Test; 7 | 8 | import Designite.utils.models.Edge; 9 | import Designite.utils.models.Graph; 10 | import Designite.utils.models.Vertex; 11 | 12 | public class GraphTest { 13 | 14 | private Graph graph; 15 | 16 | @Before 17 | public void setup() { 18 | Vertex vertex1 = new Vertex(){}; 19 | Vertex vertex2 = new Vertex(){}; 20 | Vertex vertex3 = new Vertex(){}; 21 | Vertex vertex4 = new Vertex(){}; 22 | Vertex vertex5 = new Vertex(){}; 23 | Vertex vertex6 = new Vertex(){}; 24 | Vertex vertex7 = new Vertex(){}; 25 | Vertex vertex8 = new Vertex(){}; 26 | Vertex vertex9 = new Vertex(){}; 27 | Vertex vertex10 = new Vertex(){}; 28 | 29 | Edge edge1 = new Edge(vertex1, vertex2); 30 | Edge edge2 = new Edge(vertex4, vertex1); 31 | Edge edge3 = new Edge(vertex2, vertex3); 32 | Edge edge4 = new Edge(vertex2, vertex4); 33 | Edge edge5 = new Edge(vertex3, vertex4); 34 | Edge edge6 = new Edge(vertex5, vertex6); 35 | Edge edge7 = new Edge(vertex6, vertex9); 36 | Edge edge8 = new Edge(vertex7, vertex8); 37 | Edge edge9 = new Edge(vertex9, vertex7); 38 | Edge edge10 = new Edge(vertex8, vertex9); 39 | 40 | graph = new Graph(); 41 | graph.addVertex(vertex1); 42 | graph.addVertex(vertex2); 43 | graph.addVertex(vertex3); 44 | graph.addVertex(vertex4); 45 | graph.addVertex(vertex5); 46 | graph.addVertex(vertex6); 47 | graph.addVertex(vertex7); 48 | graph.addVertex(vertex8); 49 | graph.addVertex(vertex9); 50 | graph.addVertex(vertex10); 51 | 52 | graph.addEdge(edge1); 53 | graph.addEdge(edge2); 54 | graph.addEdge(edge3); 55 | graph.addEdge(edge4); 56 | graph.addEdge(edge5); 57 | graph.addEdge(edge6); 58 | graph.addEdge(edge7); 59 | graph.addEdge(edge8); 60 | graph.addEdge(edge9); 61 | graph.addEdge(edge10); 62 | 63 | graph.computeConnectedComponents(); 64 | graph.computeStronglyConnectedComponents(); 65 | } 66 | 67 | @Test 68 | public void testNumberOfComponents() { 69 | int expected = 3; 70 | int actual = graph.getConnectedComponnents().size(); 71 | 72 | assertEquals(expected, actual); 73 | } 74 | 75 | @Test 76 | public void testDegreeOfFirstComponent() { 77 | int expected = 4; 78 | int actual = graph.getConnectedComponnents().get(0).size(); 79 | 80 | assertEquals(expected, actual); 81 | } 82 | 83 | @Test 84 | public void testDegreeOfSecondComponent() { 85 | int expected = 5; 86 | int actual = graph.getConnectedComponnents().get(1).size(); 87 | 88 | assertEquals(expected, actual); 89 | } 90 | 91 | @Test 92 | public void testDegreeOfThirdComponent() { 93 | int expected = 1; 94 | int actual = graph.getConnectedComponnents().get(2).size(); 95 | 96 | assertEquals(expected, actual); 97 | } 98 | 99 | @Test 100 | public void testNumberOfStrongComponents() { 101 | int expected = 5; 102 | int actual = graph.getStronglyConnectedComponents().size(); 103 | 104 | assertEquals(expected, actual); 105 | } 106 | 107 | @Test 108 | public void testDegreeOfFirstStrongComponte() { 109 | int expected = 4; 110 | int actual = graph.getStronglyConnectedComponents().get(0).size(); 111 | 112 | assertEquals(expected, actual); 113 | } 114 | 115 | @Test 116 | public void testDegreeOfSecondStrongComponte() { 117 | int expected = 3; 118 | int actual = graph.getStronglyConnectedComponents().get(1).size(); 119 | 120 | assertEquals(expected, actual); 121 | } 122 | 123 | @Test 124 | public void testDegreeOfThirdStrongComponte() { 125 | int expected = 1; 126 | int actual = graph.getStronglyConnectedComponents().get(2).size(); 127 | 128 | assertEquals(expected, actual); 129 | } 130 | 131 | @Test 132 | public void testDegreeOfFourthStrongComponte() { 133 | int expected = 1; 134 | int actual = graph.getStronglyConnectedComponents().get(3).size(); 135 | 136 | assertEquals(expected, actual); 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /tests/TestFiles/codeSmells/notExistingThreshold.txt: -------------------------------------------------------------------------------- 1 | myTheshold = 20 -------------------------------------------------------------------------------- /tests/TestFiles/codeSmells/thresholdsDefault.txt: -------------------------------------------------------------------------------- 1 | insufficientModularizationLargePublicInterface = 20 2 | insufficientModularizationLargeNumOfMethods = 30 3 | insufficientModularizationHighComplexity = 100 4 | -------------------------------------------------------------------------------- /tests/TestFiles/codeSmells/thresholdsNonDefault.txt: -------------------------------------------------------------------------------- 1 | insufficientModularizationLargePublicInterface =14 -------------------------------------------------------------------------------- /tests/TestFiles/codeSmells/wrongRowFormatNoEquals.txt: -------------------------------------------------------------------------------- 1 | insufficientModularizationLargePublicInterface 20 -------------------------------------------------------------------------------- /tests/TestFiles/codeSmells/wrongRowFormatNoNumberAsKey.txt: -------------------------------------------------------------------------------- 1 | insufficientModularizationLargePublicInterface = abc -------------------------------------------------------------------------------- /tests/TestFiles/metrics/metricsPackage/AnotherClass.java: -------------------------------------------------------------------------------- 1 | package metricsPackage; 2 | 3 | public class AnotherClass extends YetAnotherClass{ 4 | 5 | } 6 | -------------------------------------------------------------------------------- /tests/TestFiles/metrics/metricsPackage/Child1.java: -------------------------------------------------------------------------------- 1 | package metricsPackage; 2 | 3 | 4 | public class Child1 extends TestMetricsClass { 5 | 6 | private String field1 = "foo"; 7 | private String[] field2; 8 | private boolean bool = false; 9 | private int field3 = 0; 10 | 11 | public void foo() { 12 | int field3 = 5; 13 | field1 = "bar"; 14 | String random = "random"; 15 | for (String word : field2) { 16 | if (bool) { 17 | this.field3++; 18 | field1 = "rab"; 19 | ForeignClass4.func(); 20 | ForeignClass5.ERROR; 21 | } 22 | } 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /tests/TestFiles/metrics/metricsPackage/Child2.java: -------------------------------------------------------------------------------- 1 | package metricsPackage; 2 | 3 | public class Child2 extends TestMetricsClass { 4 | 5 | private int field1; 6 | private int field2; 7 | private int field3; 8 | private int field4; 9 | 10 | public void method1() { 11 | field1++; 12 | field2++; 13 | } 14 | 15 | public void method2() { 16 | field3++ 17 | } 18 | 19 | public void method3() { 20 | method1(); 21 | field3++; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /tests/TestFiles/metrics/metricsPackage/ForeignClass1.java: -------------------------------------------------------------------------------- 1 | package metricsPackage; 2 | 3 | public class ForeignClass1 { 4 | 5 | private TestMetricsClass cl = new TestMetricsClass(); 6 | } 7 | -------------------------------------------------------------------------------- /tests/TestFiles/metrics/metricsPackage/ForeignClass2.java: -------------------------------------------------------------------------------- 1 | package metricsPackage; 2 | 3 | public class ForeignClass2 { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /tests/TestFiles/metrics/metricsPackage/ForeignClass3.java: -------------------------------------------------------------------------------- 1 | package metricsPackage; 2 | 3 | public class ForeignClass3 { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /tests/TestFiles/metrics/metricsPackage/ForeignClass4.java: -------------------------------------------------------------------------------- 1 | package metricsPackage; 2 | 3 | public class ForeignClass4 { 4 | 5 | public static int func() { 6 | TestMetricsClass cl = new TestMetricsClass(); 7 | return 0; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /tests/TestFiles/metrics/metricsPackage/ForeignClass5.java: -------------------------------------------------------------------------------- 1 | package metricsPackage; 2 | 3 | public class ForeignClass5 { 4 | 5 | public static String ERROR = "error"; 6 | } 7 | -------------------------------------------------------------------------------- /tests/TestFiles/metrics/metricsPackage/InterfaceChild1.java: -------------------------------------------------------------------------------- 1 | package metricsPackage; 2 | 3 | public interface InterfaceChild1 extends InterfaceParent { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /tests/TestFiles/metrics/metricsPackage/InterfaceChild2.java: -------------------------------------------------------------------------------- 1 | package metricsPackage; 2 | 3 | public interface InterfaceChild2 extends InterfaceParent { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /tests/TestFiles/metrics/metricsPackage/InterfaceGrandChild.java: -------------------------------------------------------------------------------- 1 | package metricsPackage; 2 | 3 | public interface InterfaceGrandChild extends InterfaceChild1 { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /tests/TestFiles/metrics/metricsPackage/InterfaceParent.java: -------------------------------------------------------------------------------- 1 | package metricsPackage; 2 | 3 | public interface InterfaceParent { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /tests/TestFiles/metrics/metricsPackage/TestMetricsClass.java: -------------------------------------------------------------------------------- 1 | package metricsPackage; 2 | 3 | public class TestMetricsClass extends AnotherClass implements InterfaceGrandChild, InterfaceChild2 { 4 | 5 | private String foo = ForeignClass5.ERROR; 6 | public String[] bar; 7 | private ForeignClass1 fc1; 8 | 9 | public void publicMethod(String parameter1, int parameter2, ForeignClass2 parameter3, A e, List myList) { 10 | 11 | ForeignClass3 fc3 = new ForeignClass3(); 12 | int num = ForeignClass4.func(); 13 | String[] s = new String[1]; 14 | 15 | // To test cyclomatic complexity 16 | if (true) { 17 | for (int i = 0; i < 5; i++) { 18 | for (String b : bar) { 19 | 20 | } 21 | } 22 | } else if (true || false) { 23 | while (false) { 24 | do { 25 | 26 | } while (false); 27 | } 28 | } else { 29 | switch (foo) { 30 | case "foo": 31 | break; 32 | case "bar": 33 | break; 34 | default: 35 | } 36 | } 37 | } 38 | 39 | private void privateMethod() { 40 | 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /tests/TestFiles/metrics/metricsPackage/YetAnotherClass.java: -------------------------------------------------------------------------------- 1 | package metricsPackage; 2 | 3 | public class YetAnotherClass { 4 | } 5 | -------------------------------------------------------------------------------- /tests/TestFiles/test_inputs/TestMethods.java: -------------------------------------------------------------------------------- 1 | package test_inputs; 2 | 3 | import java.util.List; 4 | 5 | public class TestMethods { 6 | //public TestClass publicField; 7 | private static int counter = 0; 8 | private List name, id; 9 | final int CONSTANT = 7; 10 | public TestMethods publicField; 11 | 12 | TestMethods(String name) { 13 | int a = 0; 14 | counter++; 15 | } 16 | 17 | public int publicMethod(TestMethods t) { 18 | TestMethods temp = t; 19 | return counter; 20 | } 21 | 22 | public static void count(int a) { 23 | 24 | } 25 | 26 | public List getList(List list) { 27 | return list; 28 | 29 | } 30 | 31 | public void print() { 32 | System.out.println("Name: " + name); 33 | System.out.println("Id: " + id); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /tests/TestFiles/test_inputs2/TestMethods.java: -------------------------------------------------------------------------------- 1 | package test_inputs2; 2 | 3 | import java.util.List; 4 | 5 | public class TestMethods { 6 | //public TestClass publicField; 7 | private static int counter = 0; 8 | private List name, id; 9 | final int CONSTANT = 7; 10 | public TestMethods publicField; 11 | 12 | TestMethods(String name) { 13 | int a = 0; 14 | counter++; 15 | } 16 | 17 | public int publicMethod(TestMethods t) { 18 | TestMethods temp = t; 19 | print(); 20 | return counter; 21 | } 22 | 23 | public static void count(int a) { 24 | Logger.log("nothing"); 25 | } 26 | 27 | public List getList(List list) { 28 | return list; 29 | 30 | } 31 | 32 | public void print() { 33 | TestMethods2 obj = new TestMethods2(); 34 | obj.print2(); 35 | System.out.println("Name: " + name); 36 | System.out.println("Id: " + id); 37 | } 38 | 39 | public void magicNumberDemo() { 40 | int[] arr = {0,1}; 41 | int x = 1; 42 | int z = Integer.valueOf(2); 43 | int y = "aes".length(); 44 | int k = arr[1]; 45 | 46 | if ( x == 10 && x > 5); 47 | if ( x != 10 ); 48 | if ( x > 10 ); 49 | if ( x < 10 ); 50 | if ( x >= 10 ); 51 | if ( x <= 10 ); 52 | if ( z > arr[0] ); 53 | if ("test".charAt(Integer.valueOf(0))); 54 | 55 | List list = new ArrayList<>(new int[] {0,1}); 56 | int l = list.get(0); 57 | } 58 | } 59 | 60 | class Logger{ 61 | 62 | public static void log(String msg) 63 | { 64 | 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /tests/TestFiles/test_inputs2/TestMethods2.java: -------------------------------------------------------------------------------- 1 | package test_inputs2; 2 | 3 | public class TestMethods2 { 4 | 5 | public void print2() { 6 | // TODO Auto-generated method stub 7 | 8 | } 9 | 10 | } 11 | -------------------------------------------------------------------------------- /tests/TestFiles/test_package/AbstractClass.java: -------------------------------------------------------------------------------- 1 | package test_package; 2 | 3 | public abstract class AbstractClass { 4 | abstract void abstractMethod(); 5 | } 6 | -------------------------------------------------------------------------------- /tests/TestFiles/test_package/DefaultClass.java: -------------------------------------------------------------------------------- 1 | package test_package; 2 | 3 | class DefaultClass { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /tests/TestFiles/test_package/EmptyClass.java: -------------------------------------------------------------------------------- 1 | package test_package; 2 | 3 | 4 | -------------------------------------------------------------------------------- /tests/TestFiles/test_package/Interface.java: -------------------------------------------------------------------------------- 1 | package test_package; 2 | 3 | interface Interface { 4 | void initialiseVariable(int value); 5 | void start(); 6 | } 7 | -------------------------------------------------------------------------------- /tests/TestFiles/test_package/NestedClass.java: -------------------------------------------------------------------------------- 1 | package test_package; 2 | 3 | public class NestedClass { 4 | class InnerClass { 5 | 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /tests/TestFiles/test_package/TestClass.java: -------------------------------------------------------------------------------- 1 | package test_package; 2 | 3 | public class TestClass { 4 | public void method() { 5 | 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /tests/TestFiles/test_package/TestMethods.java: -------------------------------------------------------------------------------- 1 | package test_package2; 2 | 3 | import java.util.List; 4 | 5 | public class TestMethods { 6 | public TestClass publicField; 7 | private static int counter = 0; 8 | private String name, id; 9 | final int CONSTANT = 7; 10 | 11 | TestMethods(String name) { 12 | this.name = name; 13 | counter++; 14 | } 15 | 16 | public int publicMethod(TestMethods t) { 17 | return counter; 18 | } 19 | 20 | public static void count(int a) { 21 | 22 | } 23 | 24 | public List getList(List list) { 25 | return list; 26 | 27 | } 28 | 29 | public void print() { 30 | System.out.println("Name: " + name); 31 | System.out.println("Id: " + id); 32 | } 33 | } 34 | --------------------------------------------------------------------------------