diff --git a/src/Designite/SourceModel/Parsable.java b/src/Designite/SourceModel/Parsable.java new file mode 100644 index 0000000..92fff81 --- /dev/null +++ b/src/Designite/SourceModel/Parsable.java @@ -0,0 +1,5 @@ +package Designite.SourceModel; + +public interface Parsable { + void parse(); +} diff --git a/src/Designite/SourceModel/SM_EntitiesWithType.java b/src/Designite/SourceModel/SM_EntitiesWithType.java index 55e890b..ab6348b 100644 --- a/src/Designite/SourceModel/SM_EntitiesWithType.java +++ b/src/Designite/SourceModel/SM_EntitiesWithType.java @@ -54,8 +54,8 @@ public String getTypeOverallToString() { // return "generic"; } - @Override - public void parse() { - - } +// @Override +// public void parse() { +// +// } } diff --git a/src/Designite/SourceModel/SM_Method.java b/src/Designite/SourceModel/SM_Method.java index a456df0..ba47982 100644 --- a/src/Designite/SourceModel/SM_Method.java +++ b/src/Designite/SourceModel/SM_Method.java @@ -17,7 +17,7 @@ import Designite.visitors.InstanceOfVisitor; import Designite.visitors.ThrowVisitor; -public class SM_Method extends SM_SourceItem implements Vertex { +public class SM_Method extends SM_SourceItem implements Vertex, Parsable { private boolean abstractMethod; private boolean finalMethod; @@ -103,17 +103,56 @@ public MethodDeclaration getMethodDeclaration() { return methodDeclaration; } - private void parseParameters() { - for (SM_Parameter param : parameterList) { - param.parse(); + private void prepareCalledMethodsList() { + MethodInvVisitor invVisitor = new MethodInvVisitor(methodDeclaration); + methodDeclaration.accept(invVisitor); + List invList = invVisitor.getCalledMethods(); + if (invList.size() > 0) { + calledMethods.addAll(invList); } } - private void parseLocalVar() { - for (SM_LocalVar var : localVarList) { - var.parse(); + private void prepareInstanceOfVisitorList() { + InstanceOfVisitor instanceOfVisitor = new InstanceOfVisitor(); + methodDeclaration.accept(instanceOfVisitor); + List instanceOfTypes = instanceOfVisitor.getTypesInInstanceOf(); + if (instanceOfTypes.size() > 0) { + typesInInstanceOf.addAll(instanceOfTypes); + } + } + + private void prepareParametersList(SingleVariableDeclaration var) { + VariableVisitor parameterVisitor = new VariableVisitor(this); + // methodDeclaration.accept(parameterVisitor); + var.accept(parameterVisitor); + List pList = parameterVisitor.getParameterList(); + if (pList.size() > 0) { + parameterList.addAll(pList); + } + } + + //SM_Parameter uses an empty parse method. So commenting this. +// private void parseParameters() { +// for (SM_Parameter param : parameterList) { +// param.parse(); +// } +// } + + private void prepareLocalVarList() { + LocalVarVisitor localVarVisitor = new LocalVarVisitor(this); + methodDeclaration.accept(localVarVisitor); + List lList = localVarVisitor.getLocalVarList(); + if (lList.size() > 0) { + localVarList.addAll(lList); } } + +//SM_LocalVar inherits SM_EntitiesWithType which inter uses an empty parse method. So, commenting this. +// private void parseLocalVar() { +// for (SM_LocalVar var : localVarList) { +// var.parse(); +// } +// } public String getMethodBody() { if (this.hasBody()) @@ -145,32 +184,16 @@ public void printDebugLog(PrintWriter writer) { //TODO: Modularize parser with private functions @Override public void parse() { - MethodInvVisitor invVisitor = new MethodInvVisitor(methodDeclaration); - methodDeclaration.accept(invVisitor); - List invList = invVisitor.getCalledMethods(); - if (invList.size() > 0) { - calledMethods.addAll(invList); - } + prepareCalledMethodsList(); List variableList = methodDeclaration.parameters(); for (SingleVariableDeclaration var : variableList) { - VariableVisitor parameterVisitor = new VariableVisitor(this); - // methodDeclaration.accept(parameterVisitor); - var.accept(parameterVisitor); - List pList = parameterVisitor.getParameterList(); - if (pList.size() > 0) { - parameterList.addAll(pList); - } - parseParameters(); + prepareParametersList(var); +// parseParameters(); } - LocalVarVisitor localVarVisitor = new LocalVarVisitor(this); - methodDeclaration.accept(localVarVisitor); - List lList = localVarVisitor.getLocalVarList(); - if (lList.size() > 0) { - localVarList.addAll(lList); - } - parseLocalVar(); + prepareLocalVarList(); +// parseLocalVar(); DirectAceessFieldVisitor directAceessFieldVisitor = new DirectAceessFieldVisitor(); methodDeclaration.accept(directAceessFieldVisitor); @@ -182,14 +205,8 @@ public void parse() { if (thisAccesses.size() > 0) { thisAccessesInMethod.addAll(thisAccesses); } - - InstanceOfVisitor instanceOfVisitor = new InstanceOfVisitor(); - methodDeclaration.accept(instanceOfVisitor); - List instanceOfTypes = instanceOfVisitor.getTypesInInstanceOf(); - if (instanceOfTypes.size() > 0) { - typesInInstanceOf.addAll(instanceOfTypes); - } - + prepareInstanceOfVisitorList(); + ThrowVisitor throwVisithor = new ThrowVisitor(); methodDeclaration.accept(throwVisithor); throwsException = throwVisithor.throwsException(); diff --git a/src/Designite/SourceModel/SM_Package.java b/src/Designite/SourceModel/SM_Package.java index 717056c..eacfaa9 100644 --- a/src/Designite/SourceModel/SM_Package.java +++ b/src/Designite/SourceModel/SM_Package.java @@ -7,6 +7,7 @@ import java.util.List; import java.util.Map; +import Designite.metrics.TypeMetricsExtractor; import org.eclipse.jdt.core.dom.CompilationUnit; import Designite.InputArgs; @@ -17,7 +18,7 @@ import Designite.utils.Constants; import Designite.utils.models.Edge; -public class SM_Package extends SM_SourceItem { +public class SM_Package extends SM_SourceItem implements Parsable{ private List compilationUnitList; private List typeList = new ArrayList<>(); private SM_Project parentProject; @@ -117,8 +118,7 @@ public void resolve() { public void extractTypeMetrics() { for (SM_Type type : typeList) { type.extractMethodMetrics(); - TypeMetrics metrics = new TypeMetrics(type); - metrics.extractMetrics(); + TypeMetrics metrics = new TypeMetricsExtractor(type).extractMetrics(); metricsMapping.put(type, metrics); exportMetricsToCSV(metrics, type.getName()); updateDependencyGraph(type); diff --git a/src/Designite/SourceModel/SM_Parameter.java b/src/Designite/SourceModel/SM_Parameter.java index 4276aaf..dc84ce3 100644 --- a/src/Designite/SourceModel/SM_Parameter.java +++ b/src/Designite/SourceModel/SM_Parameter.java @@ -58,9 +58,9 @@ public String toString() { + ", is=" + getTypeBinding().getNodeType(); } - @Override - public void parse() { - - } +// @Override +// public void parse() { +// +// } } diff --git a/src/Designite/SourceModel/SM_Project.java b/src/Designite/SourceModel/SM_Project.java index 9d0f45f..4739a03 100644 --- a/src/Designite/SourceModel/SM_Project.java +++ b/src/Designite/SourceModel/SM_Project.java @@ -20,7 +20,7 @@ import Designite.utils.Logger; import Designite.utils.models.Graph; -public class SM_Project extends SM_SourceItem { +public class SM_Project extends SM_SourceItem implements Parsable { private InputArgs inputArgs; private List sourceFileList; diff --git a/src/Designite/SourceModel/SM_SourceItem.java b/src/Designite/SourceModel/SM_SourceItem.java index 56be1af..299492b 100644 --- a/src/Designite/SourceModel/SM_SourceItem.java +++ b/src/Designite/SourceModel/SM_SourceItem.java @@ -19,7 +19,7 @@ public abstract class SM_SourceItem { /** * This is the first pass of parsing a source code entity. */ - public abstract void parse(); +// public abstract void parse(); /** * This method establishes relationships among source-code entities. Such diff --git a/src/Designite/SourceModel/SM_Type.java b/src/Designite/SourceModel/SM_Type.java index 1c32c18..e9a4ba6 100644 --- a/src/Designite/SourceModel/SM_Type.java +++ b/src/Designite/SourceModel/SM_Type.java @@ -7,6 +7,7 @@ import java.util.List; import java.util.Map; +import Designite.metrics.MethodMetricsExtractor; import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jdt.core.dom.ImportDeclaration; import org.eclipse.jdt.core.dom.Modifier; @@ -25,7 +26,7 @@ import Designite.visitors.StaticFieldAccessVisitor; //TODO check EnumDeclaration, AnnotationTypeDeclaration and nested classes -public class SM_Type extends SM_SourceItem implements Vertex { +public class SM_Type extends SM_SourceItem implements Vertex, Parsable { private boolean isAbstract = false; @@ -221,11 +222,12 @@ private void parseMethods() { } } - private void parseFields() { - for (SM_Field field : fieldList) { - field.parse(); - } - } + //SM_Field inherits SM_EntitiesWithType which inter uses an empty parse method. So, commenting this. +// private void parseFields() { +// for (SM_Field field : fieldList) { +// field.parse(); +// } +// } @Override public void printDebugLog(PrintWriter writer) { @@ -263,7 +265,7 @@ public void parse() { List fList = fieldVisitor.getFields(); if (fList.size() > 0) fieldList.addAll(fList); - parseFields(); +// parseFields(); StaticFieldAccessVisitor fieldAccessVisitor = new StaticFieldAccessVisitor(); typeDeclaration.accept(fieldAccessVisitor); @@ -349,8 +351,7 @@ private void addUniqueReference(SM_Type type, SM_Type typeToAdd, boolean invardR public void extractMethodMetrics() { for (SM_Method method : methodList) { - MethodMetrics metrics = new MethodMetrics(method); - metrics.extractMetrics(); + MethodMetrics metrics = new MethodMetricsExtractor(method).extractMetrics(); metricsMapping.put(method, metrics); exportMethodMetricsToCSV(metrics, method.getName()); } diff --git a/src/Designite/SourceModel/TypeInfo.java b/src/Designite/SourceModel/TypeInfo.java index e3c9444..c69f53c 100644 --- a/src/Designite/SourceModel/TypeInfo.java +++ b/src/Designite/SourceModel/TypeInfo.java @@ -11,6 +11,8 @@ public class TypeInfo { private boolean parametrizedType; private List nonPrimitiveTypeParameters = new ArrayList<>(); + private static final int COMMA_LENGTH = 2; + public SM_Type getTypeObj() { return typeObj; } @@ -56,7 +58,7 @@ public String getStringOfNonPrimitiveParameters() { } private String removeLastComma(String str) { - return (str.length() > 2) ? str.substring(0, str.length() - 2) : str; + return (str.length() > COMMA_LENGTH) ? str.substring(0, str.length() - COMMA_LENGTH) : str; } public int getNumOfNonPrimitiveParameters() { diff --git a/src/Designite/metrics/MethodMetrics.java b/src/Designite/metrics/MethodMetrics.java index 5214623..939bc14 100644 --- a/src/Designite/metrics/MethodMetrics.java +++ b/src/Designite/metrics/MethodMetrics.java @@ -5,60 +5,14 @@ import Designite.SourceModel.SM_Field; import Designite.SourceModel.SM_Method; import Designite.SourceModel.SM_Type; -import Designite.visitors.MethodControlFlowVisitor; -public class MethodMetrics implements MetricExtractor { +public class MethodMetrics extends Metrics { private int numOfParameters; private int cyclomaticComplexity; private int numOfLines; - private SM_Method method; - - public MethodMetrics(SM_Method method) { - this.method = method; - } - - @Override - public void extractMetrics() { - extractNumOfParametersMetrics(); - extractCyclomaticComplexity(); - extractNumberOfLines(); - } - - private void extractNumOfParametersMetrics() { - numOfParameters = method.getParameterList().size(); - } - - private void extractCyclomaticComplexity() { - cyclomaticComplexity = calculateCyclomaticComplexity(); - } - - private int calculateCyclomaticComplexity() { - MethodControlFlowVisitor visitor = new MethodControlFlowVisitor(); - method.getMethodDeclaration().accept(visitor); - return visitor.getNumOfIfStatements() - + visitor.getNumOfSwitchCaseStatementsWitoutDefault() - + visitor.getNumOfForStatements() - + visitor.getNumOfWhileStatements() - + visitor.getNumOfDoStatements() - + visitor.getNumOfForeachStatements() - + 1; - } - - private void extractNumberOfLines() { - if (methodHasBody()) { - String body = method.getMethodDeclaration().getBody().toString(); - int length = body.length(); -// long newlines = body.lines().count(); - numOfLines = length - body.replace("\n", "").length(); - } - } - - private boolean methodHasBody() { - return method.getMethodDeclaration().getBody() != null; - } - + public int getNumOfParameters() { return numOfParameters; } @@ -71,16 +25,32 @@ public int getNumOfLines() { return numOfLines; } + public void setNumOfParameters(int numOfParameters) { + this.numOfParameters = numOfParameters; + } + + public void setCyclomaticComplexity(int cyclomaticComplexity) { + this.cyclomaticComplexity = cyclomaticComplexity; + } + + public void setNumOfLines(int numOfLines) { + this.numOfLines = numOfLines; + } + + public void setMethod(SM_Method method){ + this.method = method; + } + + public SM_Method getMethod() { + return method; + } + public List getDirectFieldAccesses() { return method.getDirectFieldAccesses(); } - + public List getSMTypesInInstanceOf() { return method.getSMTypesInInstanceOf(); } - - public SM_Method getMethod() { - return method; - } } diff --git a/src/Designite/metrics/MethodMetricsExtractor.java b/src/Designite/metrics/MethodMetricsExtractor.java new file mode 100644 index 0000000..74e63fb --- /dev/null +++ b/src/Designite/metrics/MethodMetricsExtractor.java @@ -0,0 +1,65 @@ +package Designite.metrics; + +import Designite.SourceModel.SM_Method; +import Designite.SourceModel.SM_Type; +import Designite.visitors.MethodControlFlowVisitor; + +import java.util.List; + +public class MethodMetricsExtractor implements MetricExtractor{ + + private SM_Method method; + private MethodMetrics methodMetrics; + + public MethodMetricsExtractor(SM_Method method) { + this.method = method; + } + + @Override + public MethodMetrics extractMetrics() { + methodMetrics = new MethodMetrics(); + extractNumOfParametersMetrics(); + extractCyclomaticComplexity(); + extractNumberOfLines(); + methodMetrics.setMethod(method); + return methodMetrics; + } + + + private void extractNumOfParametersMetrics() { + methodMetrics.setNumOfParameters(method.getParameterList().size()); + } + + private void extractCyclomaticComplexity() { + methodMetrics.setCyclomaticComplexity(calculateCyclomaticComplexity()); + } + + private int calculateCyclomaticComplexity() { + MethodControlFlowVisitor visitor = new MethodControlFlowVisitor(); + method.getMethodDeclaration().accept(visitor); + return visitor.getNumOfIfStatements() + + visitor.getNumOfSwitchCaseStatementsWitoutDefault() + + visitor.getNumOfForStatements() + + visitor.getNumOfWhileStatements() + + visitor.getNumOfDoStatements() + + visitor.getNumOfForeachStatements() + + 1; + } + + private void extractNumberOfLines() { + if (methodHasBody()) { + String body = method.getMethodDeclaration().getBody().toString(); + int length = body.length(); +// long newlines = body.lines().count(); + methodMetrics.setNumOfLines(length - body.replace("\n", "").length()); + } + } + + private boolean methodHasBody() { + return method.getMethodDeclaration().getBody() != null; + } + + + + +} diff --git a/src/Designite/metrics/MetricExtractor.java b/src/Designite/metrics/MetricExtractor.java index c3ec55e..78cac7c 100644 --- a/src/Designite/metrics/MetricExtractor.java +++ b/src/Designite/metrics/MetricExtractor.java @@ -2,5 +2,5 @@ public interface MetricExtractor { - void extractMetrics(); + Metrics extractMetrics(); } diff --git a/src/Designite/metrics/Metrics.java b/src/Designite/metrics/Metrics.java new file mode 100644 index 0000000..77899f6 --- /dev/null +++ b/src/Designite/metrics/Metrics.java @@ -0,0 +1,4 @@ +package Designite.metrics; + +public class Metrics { +} diff --git a/src/Designite/metrics/TypeMetrics.java b/src/Designite/metrics/TypeMetrics.java index 3df3d43..773f050 100644 --- a/src/Designite/metrics/TypeMetrics.java +++ b/src/Designite/metrics/TypeMetrics.java @@ -7,11 +7,12 @@ import Designite.SourceModel.SM_Field; import Designite.SourceModel.SM_Method; import Designite.SourceModel.SM_Type; + import Designite.utils.models.Edge; import Designite.utils.models.Graph; import Designite.utils.models.Vertex; -public class TypeMetrics implements MetricExtractor { +public class TypeMetrics extends Metrics{ private int numOfFields; private int numOfPublicFields; @@ -24,166 +25,50 @@ public class TypeMetrics implements MetricExtractor { private int numOfFanOutTypes; private int numOfFanInTypes; private double lcom; - private SM_Type type; - - private Graph graph; - - public TypeMetrics(SM_Type type) { - - this.type = type; - } - - @Override - public void extractMetrics() { - extractNumOfFieldMetrics(); - extractNumOfMethodsMetrics(); - extractDepthOfInheritance(); - extractNumberOfLines(); - extractNumberOfChildren(); - extractWeightedMethodsPerClass(); - extractNumOfFanOutTypes(); - extractNumOfFanInTypes(); - extractLCOM(); - } - - private void extractNumOfFieldMetrics() { - for (SM_Field field : type.getFieldList()) { - numOfFields++; - if (field.getAccessModifier() == AccessStates.PUBLIC) { - // do not calculate fields that belong to a nested class with a stricter access modifier - SM_Type nestedParent = field.getNestedParent(); - if(nestedParent != null && nestedParent.getAccessModifier() != AccessStates.PUBLIC) { - continue; - } - numOfPublicFields++; - } - } - } - - private void extractNumOfMethodsMetrics() { - for (SM_Method method : type.getMethodList()) { - numOfMethods++; - if (method.getAccessModifier() == AccessStates.PUBLIC) { - numOfPublicMethods++; - } - } - } - - private void extractDepthOfInheritance() { - depthOfInheritance += findInheritanceDepth(type.getSuperTypes()); - } - - private void extractNumberOfLines() { - String body = type.getTypeDeclaration().toString(); - numOfLines = body.length() - body.replace("\n", "").length(); - } - - private void extractNumberOfChildren() { - numOfChildren = type.getSubTypes().size(); - } - - private int findInheritanceDepth(List superTypes) { - if (superTypes.size() == 0) { - return 0; - } - List deeperSuperTypes = new ArrayList<>(); - for (SM_Type superType : superTypes) { - deeperSuperTypes.addAll(superType.getSuperTypes()); - } - // FIXME : switch to iterative process to avoid stack overflows - try { - return findInheritanceDepth(deeperSuperTypes) + 1; - } catch (StackOverflowError ex) { - System.err.println("Inheritance depth analysis step skipped due to memory overflow."); - return 0; - } - } - - private void extractWeightedMethodsPerClass() { - for (SM_Method method : type.getMethodList()) { - weightedMethodsPerClass += type.getMetricsFromMethod(method).getCyclomaticComplexity(); - } - } - - private void extractNumOfFanOutTypes() { - numOfFanOutTypes += type.getReferencedTypeList().size(); + + public void setNumOfFields(int numOfFields) { + this.numOfFields = numOfFields; } - - private void extractNumOfFanInTypes() { - numOfFanInTypes += type.getTypesThatReferenceThis().size(); + + public void setNumOfPublicFields(int numOfPublicFields) { + this.numOfPublicFields = numOfPublicFields; } - - private void extractLCOM() { - if (isNotLcomComputable()) { - lcom = -1.0; - return; - } - initializeGraph(); - lcom = computeLCOM(); + public void setNumOfMethods(int numOfMethods) { + this.numOfMethods = numOfMethods; } - - private boolean isNotLcomComputable() { - return type.isInterface() - || type.getFieldList().size() == 0 - || type.getMethodList().size() == 0; + + public void setNumOfPublicMethods(int numOfPublicMethods) { + this.numOfPublicMethods = numOfPublicMethods; } - - private void initializeGraph() { - initializeVertices(); - initializeEdges(); + + public void setDepthOfInheritance(int depthOfInheritance) { + this.depthOfInheritance = depthOfInheritance; } - - private void initializeVertices() { - //List vertices = new ArrayList<>(); - graph = new Graph(); - for (SM_Method method : type.getMethodList()) { - graph.addVertex(method); - } - for (SM_Field field : type.getFieldList()) { - graph.addVertex(field); - } + + public void setNumOfLines(int numOfLines) { + this.numOfLines = numOfLines; } - - private void initializeEdges() { - for (SM_Method method : type.getMethodList()) { - addAdjacentFields(method); - addAdjacentMethods(method); - } + + public void setNumOfChildren(int numOfChildren) { + this.numOfChildren = numOfChildren; } - - private void addAdjacentFields(SM_Method method) { - for (SM_Field fieldVertex : method.getDirectFieldAccesses()) { - graph.addEdge(new Edge(method, fieldVertex)); - } + + public void setWeightedMethodsPerClass(int weightedMethodsPerClass) { + this.weightedMethodsPerClass = weightedMethodsPerClass; } - - private void addAdjacentMethods(SM_Method method) { - for (SM_Method methodVertex : type.getMethodList()) { - if (!method.equals(methodVertex) && method.getCalledMethods().contains(methodVertex)) { - graph.addEdge(new Edge(method, methodVertex)); - } - } + + public void setNumOfFanOutTypes(int numOfFanOutTypes) { + this.numOfFanOutTypes = numOfFanOutTypes; } - - private double computeLCOM() { - graph.computeConnectedComponents(); - List> nonSingleElementFieldComponents = getNonSingleElementFieldComponents(); - if (nonSingleElementFieldComponents.size() > 1) { - return ((double) getNonSingleElementFieldComponents().size()) / type.getMethodList().size(); - } - return 0.0; + + public void setNumOfFanInTypes(int numOfFanInTypes) { + this.numOfFanInTypes = numOfFanInTypes; } - - private List> getNonSingleElementFieldComponents() { - List> cleanComponents = new ArrayList<>();; - for (List component : graph.getConnectedComponnents()) { - if (component.size() != 1 || !(component.get(0) instanceof SM_Field)) { - cleanComponents.add(component); - } - } - return cleanComponents; + + public void setLcom(double lcom) { + this.lcom = lcom; } public int getNumOfFields() { @@ -229,9 +114,11 @@ public int getNumOfFanInTypes() { public double getLcom() { return lcom; } - public SM_Type getType() { return type; } + public void setType(SM_Type type){ + this.type = type; + } } diff --git a/src/Designite/metrics/TypeMetricsExtractor.java b/src/Designite/metrics/TypeMetricsExtractor.java new file mode 100644 index 0000000..8aea65b --- /dev/null +++ b/src/Designite/metrics/TypeMetricsExtractor.java @@ -0,0 +1,189 @@ +package Designite.metrics; + +import Designite.SourceModel.AccessStates; +import Designite.SourceModel.SM_Field; +import Designite.SourceModel.SM_Method; +import Designite.SourceModel.SM_Type; +import Designite.utils.models.Edge; +import Designite.utils.models.Graph; +import Designite.utils.models.Vertex; + +import java.util.ArrayList; +import java.util.List; + +public class TypeMetricsExtractor implements MetricExtractor{ + + private SM_Type type; + + private Graph graph; + + private TypeMetrics typeMetrics; + + public TypeMetricsExtractor(SM_Type type){ + this.type = type; + } + + @Override + public TypeMetrics extractMetrics() { + typeMetrics = new TypeMetrics(); + extractNumOfFieldMetrics(); + extractNumOfMethodsMetrics(); + extractDepthOfInheritance(); + extractNumberOfLines(); + extractNumberOfChildren(); + extractWeightedMethodsPerClass(); + extractNumOfFanOutTypes(); + extractNumOfFanInTypes(); + extractLCOM(); + typeMetrics.setType(this.type); + return typeMetrics; + } + + private void extractNumOfFieldMetrics() { + for (SM_Field field : type.getFieldList()) { + typeMetrics.setNumOfFields(typeMetrics.getNumOfFields()+1); + if (field.getAccessModifier() == AccessStates.PUBLIC) { + // do not calculate fields that belong to a nested class with a stricter access modifier + SM_Type nestedParent = field.getNestedParent(); + if(nestedParent != null && nestedParent.getAccessModifier() != AccessStates.PUBLIC) { + continue; + } + typeMetrics.setNumOfPublicFields(typeMetrics.getNumOfPublicFields()+1); + } + } + } + + private void extractNumOfMethodsMetrics() { + for (SM_Method method : type.getMethodList()) { + typeMetrics.setNumOfMethods(typeMetrics.getNumOfMethods()+1); + if (method.getAccessModifier() == AccessStates.PUBLIC) { + typeMetrics.setNumOfPublicMethods(typeMetrics.getNumOfPublicMethods()+1); + } + } + } + + private void extractDepthOfInheritance() { + int depthOfInheritance = typeMetrics.getInheritanceDepth(); + depthOfInheritance += findInheritanceDepth(type.getSuperTypes()); + typeMetrics.setDepthOfInheritance(depthOfInheritance); + } + + private void extractNumberOfLines() { + String body = type.getTypeDeclaration().toString(); + typeMetrics.setNumOfLines(body.length() - body.replace("\n", "").length()); + } + + private void extractNumberOfChildren() { + typeMetrics.setNumOfChildren(type.getSubTypes().size()); + } + + private int findInheritanceDepth(List superTypes) { + if (superTypes.size() == 0) { + return 0; + } + List deeperSuperTypes = new ArrayList<>(); + for (SM_Type superType : superTypes) { + deeperSuperTypes.addAll(superType.getSuperTypes()); + } + // FIXME : switch to iterative process to avoid stack overflows + try { + return findInheritanceDepth(deeperSuperTypes) + 1; + } catch (StackOverflowError ex) { + System.err.println("Inheritance depth analysis step skipped due to memory overflow."); + return 0; + } + } + + private void extractWeightedMethodsPerClass() { + int weightedMethodsPerClass = typeMetrics.getWeightedMethodsPerClass(); + for (SM_Method method : type.getMethodList()) { + weightedMethodsPerClass += type.getMetricsFromMethod(method).getCyclomaticComplexity(); + } + typeMetrics.setWeightedMethodsPerClass(weightedMethodsPerClass); + } + + private void extractNumOfFanOutTypes() { + int numOfFanOutTypes = typeMetrics.getNumOfFanOutTypes(); + numOfFanOutTypes += type.getReferencedTypeList().size(); + typeMetrics.setNumOfFanOutTypes(numOfFanOutTypes); + } + + private void extractNumOfFanInTypes() { + int numOfFanInTypes = typeMetrics.getNumOfFanInTypes(); + numOfFanInTypes += type.getTypesThatReferenceThis().size(); + typeMetrics.setNumOfFanInTypes(numOfFanInTypes); + } + + private void extractLCOM() { + if (isNotLcomComputable()) { + typeMetrics.setLcom(-1.0); + return; + } + initializeGraph(); + typeMetrics.setLcom(computeLCOM()); + + } + + private boolean isNotLcomComputable() { + return type.isInterface() + || type.getFieldList().size() == 0 + || type.getMethodList().size() == 0; + } + + private void initializeGraph() { + initializeVertices(); + initializeEdges(); + } + + private void initializeVertices() { + //List vertices = new ArrayList<>(); + graph = new Graph(); + for (SM_Method method : type.getMethodList()) { + graph.addVertex(method); + } + for (SM_Field field : type.getFieldList()) { + graph.addVertex(field); + } + } + + private void initializeEdges() { + for (SM_Method method : type.getMethodList()) { + addAdjacentFields(method); + addAdjacentMethods(method); + } + } + + private void addAdjacentFields(SM_Method method) { + for (SM_Field fieldVertex : method.getDirectFieldAccesses()) { + graph.addEdge(new Edge(method, fieldVertex)); + } + } + + private void addAdjacentMethods(SM_Method method) { + for (SM_Method methodVertex : type.getMethodList()) { + if (!method.equals(methodVertex) && method.getCalledMethods().contains(methodVertex)) { + graph.addEdge(new Edge(method, methodVertex)); + } + } + } + + private double computeLCOM() { + graph.computeConnectedComponents(); + List> nonSingleElementFieldComponents = getNonSingleElementFieldComponents(); + if (nonSingleElementFieldComponents.size() > 1) { + return ((double) getNonSingleElementFieldComponents().size()) / type.getMethodList().size(); + } + return 0.0; + } + + private List> getNonSingleElementFieldComponents() { + List> cleanComponents = new ArrayList<>();; + for (List component : graph.getConnectedComponnents()) { + if (component.size() != 1 || !(component.get(0) instanceof SM_Field)) { + cleanComponents.add(component); + } + } + return cleanComponents; + } + +} diff --git a/src/Designite/smells/implementationSmells/ImplementationSmellDetector.java b/src/Designite/smells/implementationSmells/ImplementationSmellDetector.java index dc919c3..b70b7ba 100644 --- a/src/Designite/smells/implementationSmells/ImplementationSmellDetector.java +++ b/src/Designite/smells/implementationSmells/ImplementationSmellDetector.java @@ -33,7 +33,7 @@ public class ImplementationSmellDetector { private SourceItemInfo info; private ThresholdsDTO thresholdsDTO; - private static final String ABSTRACT_FUMCTION_CALL_FROM_CONSTRUCTOR = "Abstract Function Call From Constructor"; + private static final String ABST_FUNC_CALL_FRM_CTOR = "Abstract Function Call From Constructor"; private static final String COMPLEX_CONDITIONAL = "Complex Conditional"; private static final String COMPLEX_METHOD = "Complex Method"; private static final String EMPTY_CATCH_CLAUSE = "Empty catch clause"; @@ -72,7 +72,7 @@ public List detectCodeSmells() { public List detectAbstractFunctionCallFromConstructor() { if (hasAbstractFunctionCallFromConstructor()) { - addToSmells(initializeCodeSmell(ABSTRACT_FUMCTION_CALL_FROM_CONSTRUCTOR)); + addToSmells(initializeCodeSmell(ABST_FUNC_CALL_FRM_CTOR)); } return smells; } diff --git a/tests/DesigniteTests/DesigniteTests/SM_PackageTest.java b/tests/DesigniteTests/DesigniteTests/SM_PackageTest.java index a307295..3bcdec7 100644 --- a/tests/DesigniteTests/DesigniteTests/SM_PackageTest.java +++ b/tests/DesigniteTests/DesigniteTests/SM_PackageTest.java @@ -30,7 +30,8 @@ public void SM_Package_positive_case() { if (pkg.getName().equals("Designite")) assertEquals(pkg.getTypeList().size(), 2); if (pkg.getName().equals("Designite.SourceModel")) - assertEquals(20, pkg.getTypeList().size()); + //Added additional class in the package. + assertEquals(21, pkg.getTypeList().size()); } }