Skip to content

Commit 410c5e3

Browse files
author
Barnabás Domozi
committed
Implement relational cohesion metric.
1 parent bfe84de commit 410c5e3

5 files changed

Lines changed: 80 additions & 3 deletions

File tree

plugins/cpp_metrics/model/include/model/cppcohesionmetrics.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,16 @@ struct CohesionCppRecordView
2525
CppAstNodeId astNodeId;
2626
};
2727

28+
#pragma db view \
29+
object(CppRecord) \
30+
object(CppAstNode : CppRecord::astNodeId == CppAstNode::id) \
31+
object(File : CppAstNode::location.file)
32+
struct CohesionCppRecord_Count
33+
{
34+
#pragma db column("count(" + CppEntity::id + ")")
35+
std::size_t count;
36+
};
37+
2838
#pragma db view \
2939
object(CppMemberType) \
3040
object(CppAstNode : CppMemberType::memberAstNode) \

plugins/cpp_metrics/model/include/model/cppfilemetrics.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ struct CppFileMetrics
1313
{
1414
enum Type
1515
{
16-
EFFERENT_MODULE
16+
EFFERENT_MODULE,
17+
RELATIONAL_COHESION_MODULE
1718
};
1819

1920
#pragma db id auto
@@ -26,7 +27,7 @@ struct CppFileMetrics
2627
Type type;
2728

2829
#pragma db not_null
29-
unsigned value;
30+
double value;
3031
};
3132

3233
#pragma db view \
@@ -44,7 +45,7 @@ struct CppModuleMetricsForPathView
4445
CppFileMetrics::Type type;
4546

4647
#pragma db column(CppFileMetrics::value)
47-
unsigned value;
48+
double value;
4849
};
4950

5051
#pragma db view \

plugins/cpp_metrics/model/include/model/cpptypedependencymetrics.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,20 @@ struct CppTypeDependencyMetricsPathView
4949
std::string dependencyPath;
5050
};
5151

52+
#pragma db view \
53+
object(CppTypeDependencyMetrics) \
54+
object(CppAstNode = EntityAstNode : CppTypeDependencyMetrics::entityHash == EntityAstNode::entityHash \
55+
&& EntityAstNode::astType == cc::model::CppAstNode::AstType::Definition) \
56+
object(File = EntityFile : EntityAstNode::location.file == EntityFile::id) \
57+
object(CppAstNode = DependencyAstNode : CppTypeDependencyMetrics::dependencyHash == DependencyAstNode::entityHash \
58+
&& DependencyAstNode::astType == cc::model::CppAstNode::AstType::Definition) \
59+
object(File = DependencyFile : DependencyAstNode::location.file == DependencyFile::id)
60+
struct CppTypeDependencyMetrics_Count
61+
{
62+
#pragma db column("count(" + CppTypeDependencyMetrics::id + ")")
63+
std::size_t count;
64+
};
65+
5266
#pragma db view \
5367
object(CppTypeDependencyMetrics) \
5468
object(CppAstNode = EntityAstNode : CppTypeDependencyMetrics::entityHash == EntityAstNode::entityHash \

plugins/cpp_metrics/parser/include/cppmetricsparser/cppmetricsparser.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ class CppMetricsParser : public AbstractParser
8282
void afferentTypeLevel();
8383
// Calculate the efferent coupling at module level.
8484
void efferentModuleLevel();
85+
// Calculate relational cohesion at module level.
86+
void relationalCohesionModuleLevel();
8587
// Returns module path query based on parser configuration.
8688
odb::query<model::File> getModulePathsQuery();
8789

@@ -207,6 +209,7 @@ class CppMetricsParser : public AbstractParser
207209
static const int efferentCouplingTypesPartitionMultiplier = 5;
208210
static const int afferentCouplingTypesPartitionMultiplier = 5;
209211
static const int efferentCouplingModulesPartitionMultiplier = 5;
212+
static const int relationalCohesionPartitionMultiplier = 5;
210213
};
211214

212215
} // parser

plugins/cpp_metrics/parser/src/cppmetricsparser.cpp

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -576,6 +576,53 @@ void CppMetricsParser::efferentModuleLevel()
576576
});
577577
}
578578

579+
void CppMetricsParser::relationalCohesionModuleLevel()
580+
{
581+
// Compute relational cohesion defined by CppDepend:
582+
// https://www.cppdepend.com/documentation/code-metrics#RelationalCohesion
583+
584+
parallelCalcMetric<model::File>(
585+
"Relational cohesion at module level",
586+
_threadCount * relationalCohesionPartitionMultiplier,// number of jobs; adjust for granularity
587+
getModulePathsQuery(),
588+
[&, this](const MetricsTasks<model::File>& tasks)
589+
{
590+
util::OdbTransaction{_ctx.db}([&, this]
591+
{
592+
typedef odb::query<model::CppTypeDependencyMetrics_Count> TypeDependencyQuery;
593+
typedef model::CppTypeDependencyMetrics_Count TypeDependencyResult;
594+
typedef odb::query<model::CohesionCppRecord_Count> RecordQuery;
595+
typedef model::CohesionCppRecord_Count RecordResult;
596+
597+
for (const model::File& file : tasks)
598+
{
599+
TypeDependencyResult dependencies = _ctx.db->query_value<model::CppTypeDependencyMetrics_Count>(
600+
TypeDependencyQuery::EntityFile::path.like(file.path + '%') &&
601+
TypeDependencyQuery::DependencyFile::path.like(file.path + '%'));
602+
603+
// Let R be the number of type relationships that are internal to a module
604+
// (i.e that do not connect to types outside the module)
605+
const std::size_t r = dependencies.count;
606+
607+
RecordResult types = _ctx.db->query_value<model::CohesionCppRecord_Count>(
608+
RecordQuery::File::path.like(file.path + '%'));
609+
610+
// Let N be the number of types within the module.
611+
const std::size_t n = types.count;
612+
613+
// Relational cohesion
614+
const double h = (n != 0) ? (double)(r + 1) / n : 0;
615+
616+
model::CppFileMetrics metric;
617+
metric.file = file.id;
618+
metric.type = model::CppFileMetrics::Type::RELATIONAL_COHESION_MODULE;
619+
metric.value = h;
620+
_ctx.db->persist(metric);
621+
}
622+
});
623+
});
624+
}
625+
579626
bool CppMetricsParser::parse()
580627
{
581628
LOG(info) << "[cppmetricsparser] Computing function parameter count metric.";
@@ -594,6 +641,8 @@ bool CppMetricsParser::parse()
594641
afferentTypeLevel();
595642
LOG(info) << "[cppmetricsparser] Computing efferent coupling metric at module level.";
596643
efferentModuleLevel(); // This metric needs to be calculated after efferentTypeLevel
644+
LOG(info) << "[cppmetricsparser] Computing relational cohesion metric at module level.";
645+
relationalCohesionModuleLevel(); // This metric needs to be calculated after efferentTypeLevel
597646
return true;
598647
}
599648

0 commit comments

Comments
 (0)