org.sonar.plugins.cxx.cohesion.CxxCohesionSensor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of sonar-cxx-plugin Show documentation
Show all versions of sonar-cxx-plugin Show documentation
C++ Plugin for Sonar (Community Edition)
The newest version!
/*
* Sonar Cxx Plugin, open source software quality management tool.
* Copyright (C) 2010 - 2011, Neticoa SAS France - Tous droits reserves.
* Author(s) : Franck Bonin, Neticoa SAS France.
*
* Sonar Cxx Plugin is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* Sonar Cxx Plugin is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with Sonar Cxx Plugin; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
*/
package org.sonar.plugins.cxx.cohesion;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.sonar.api.batch.SensorContext;
import org.sonar.api.measures.CoreMetrics;
import org.sonar.api.measures.PersistenceMode;
import org.sonar.api.measures.RangeDistributionBuilder;
import org.sonar.api.resources.InputFile;
import org.sonar.api.resources.Project;
import org.sonar.plugins.cxx.ast.CxxCppParsedFile;
import org.sonar.plugins.cxx.ast.CxxCppParser;
import org.sonar.plugins.cxx.ast.CxxCppParserException;
import org.sonar.plugins.cxx.ast.cpp.CxxClass;
import org.sonar.plugins.cxx.ast.cpp.CxxClassMember;
import org.sonar.plugins.cxx.ast.cpp.CxxClassMethod;
import org.sonar.plugins.cxx.ast.cpp.HasFullName;
import org.sonar.plugins.cxx.cohesion.graph.Edge;
import org.sonar.plugins.cxx.cohesion.graph.Graph;
import org.sonar.plugins.cxx.cohesion.graph.Node;
import org.sonar.plugins.cxx.utils.CxxFileSensor;
import org.sonar.plugins.cxx.utils.CxxUtils;
public class CxxCohesionSensor extends CxxFileSensor {
private static final Number[] LCOM4_LIMITS = { 2, 3, 4, 5, 10 };
private CxxCppParser parser = new CxxCppParser();
private RangeDistributionBuilder builder = new RangeDistributionBuilder(CoreMetrics.LCOM4_DISTRIBUTION, LCOM4_LIMITS);
@Override
protected void parseFile(InputFile file, Project project, SensorContext context) {
try {
CxxCppParsedFile parsedFile = parser.parseFile(file);
double lcom4 = analyzeFileCohesion(parsedFile.getClasses());
CxxUtils.LOG.debug(parsedFile + " " + lcom4);
saveFileMeasure(file, lcom4, project, context);
} catch (CxxCppParserException e) {
CxxUtils.LOG.error(e.getMessage());
}
}
private void saveFileMeasure(InputFile inputFile, double fileCohesion, Project project, SensorContext context) {
org.sonar.api.resources.File resource = org.sonar.api.resources.File.fromIOFile(inputFile.getFile(), project);
if(context.getResource(resource) != null) {
context.saveMeasure(resource, CoreMetrics.LCOM4, fileCohesion);
context.saveMeasure(resource, builder.build().setPersistenceMode(PersistenceMode.MEMORY));
} else {
CxxUtils.LOG.error("Resource not indexed: " + inputFile.getFile().getAbsolutePath());
}
}
private double analyzeFileCohesion(Set classes) {
double fileCohesion = 0;
Iterator it = classes.iterator();
while(it.hasNext()) {
CxxClass clazz = it.next();
double classCohesion = analyzeClassCohesion(clazz);
builder.add(classCohesion);
fileCohesion += classCohesion;
}
return fileCohesion;
}
private double analyzeClassCohesion(CxxClass clazz) {
CxxUtils.LOG.debug("Analyzing " + clazz + " LCOM4...");
Set classMembers = clazz.getMembers();
Set classMethods = clazz.getMethods();
if(classMethods.isEmpty()) {
return 0.0;
}
Graph callGraph = constructCallGraph(classMembers, classMethods);
analyzeMemberAndMethodUsage(callGraph, classMembers, classMethods);
return getCohesiveComponentsCount(callGraph);
}
private double getCohesiveComponentsCount(Graph callGraph) {
double lcom4 = 0.0;
Set graphNodes = new HashSet(callGraph.getNodes());
Iterator nodeIt = callGraph.getNodes().iterator();
while(nodeIt.hasNext()) { //remove connected nodes
Set toRemove = callGraph.visitAllNodesFrom(nodeIt.next());
if(graphNodes.removeAll(toRemove)) {
lcom4 += 1.0;
}
}
while(!graphNodes.isEmpty()) { //remove rest
nodeIt = graphNodes.iterator();
while(nodeIt.hasNext()) {
nodeIt.remove();
lcom4 += 1.0;
}
}
return lcom4;
}
private void analyzeMemberAndMethodUsage(Graph callGraph, Set classMembers, Set classMethods) {
Iterator methodIt = classMethods.iterator();
while(methodIt.hasNext()) {
CxxClassMethod method = methodIt.next();
analyzeMemberUsage(callGraph, classMembers, method);
analyzeMethodUsage(callGraph, classMethods, method);
}
}
private void analyzeMethodUsage(Graph callGraph, Set classMethods, CxxClassMethod method) {
Iterator secondMethodIt = classMethods.iterator();
while(secondMethodIt.hasNext()) {
CxxClassMethod secondMethod = secondMethodIt.next();
if(!secondMethod.equals(method) && isNameUsedInMethod(secondMethod, method)) {
callGraph.addEdge( new Edge( new Node(secondMethod), new Node(method) ) );
CxxUtils.LOG.debug("Method connection " + secondMethod + " <--> " + method);
}
}
}
private void analyzeMemberUsage(Graph callGraph, Set classMembers, CxxClassMethod method) {
Iterator memberIt = classMembers.iterator();
while(memberIt.hasNext()) {
CxxClassMember member = memberIt.next();
if(isNameUsedInMethod(member, method)) {
callGraph.addEdge( new Edge( new Node(member), new Node(method) ) );
CxxUtils.LOG.debug("Member connection " + member + " <--> " + method);
}
}
}
private boolean isNameUsedInMethod(HasFullName fullNameObject, CxxClassMethod method) {
List usedNames = method.getBody().getDetectedNames();
if(usedNames.contains(fullNameObject.getName())) {
return true;
}
return false;
}
private Graph constructCallGraph(Set classMembers, Set classMethods) {
Graph callGraph = new Graph();
Iterator memberIt = classMembers.iterator();
while(memberIt.hasNext()) {
callGraph.addNode( new Node(memberIt.next()) );
}
Iterator methodIt = classMethods.iterator();
while(methodIt.hasNext()) {
callGraph.addNode( new Node(methodIt.next()));
}
return callGraph;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy