├── .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 | [](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 extends A> 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 |
--------------------------------------------------------------------------------