From d80357056486ac0772938e443fd252bdf3367605 Mon Sep 17 00:00:00 2001 From: Klein Kristof Date: Mon, 1 Jul 2024 10:06:24 +0200 Subject: [PATCH 1/4] Added calculation for afferent coupling of types --- plugins/cpp_metrics/model/CMakeLists.txt | 3 +- .../model/include/model/cppafferentmetrics.h | 38 ++++++++++++++ .../model/include/model/cppastnodemetrics.h | 1 + .../cppmetricsparser/cppmetricsparser.h | 3 +- .../parser/src/cppmetricsparser.cpp | 50 +++++++++++++++++++ 5 files changed, 93 insertions(+), 2 deletions(-) create mode 100644 plugins/cpp_metrics/model/include/model/cppafferentmetrics.h diff --git a/plugins/cpp_metrics/model/CMakeLists.txt b/plugins/cpp_metrics/model/CMakeLists.txt index 38d8ca343..807776e24 100644 --- a/plugins/cpp_metrics/model/CMakeLists.txt +++ b/plugins/cpp_metrics/model/CMakeLists.txt @@ -5,7 +5,8 @@ include_directories( set(ODB_SOURCES include/model/cppastnodemetrics.h include/model/cppcohesionmetrics.h - include/model/cppfilemetrics.h) + include/model/cppfilemetrics.h + include/model/cppafferentmetrics.h) generate_odb_files("${ODB_SOURCES}" "cpp") diff --git a/plugins/cpp_metrics/model/include/model/cppafferentmetrics.h b/plugins/cpp_metrics/model/include/model/cppafferentmetrics.h new file mode 100644 index 000000000..25691d62b --- /dev/null +++ b/plugins/cpp_metrics/model/include/model/cppafferentmetrics.h @@ -0,0 +1,38 @@ +#ifndef CC_MODEL_AFFERENTMETRICS_H +#define CC_MODEL_AFFERENTMETRICS_H + +#include +#include +#include + +namespace cc +{ +namespace model +{ + #pragma db view \ + object(CppRecord) \ + object(CppAstNode : CppRecord::astNodeId == CppAstNode::id) \ + object(File : CppAstNode::location.file) \ + object(CppMemberType : CppMemberType::memberAstNode) + struct AfferentRecordView + { + #pragma db column(CppEntity::entityHash) + std::size_t entityHash; + + #pragma db column(CppMemberType::typeHash) + std::size_t typeHash; + + #pragma db column(CppEntity::qualifiedName) + std::string qualifiedName; + + #pragma db column(CppEntity::astNodeId) + CppAstNodeId astNodeId; + + #pragma db column(File::path) + std::string filePath; + }; + +} //model +} //cc + +#endif //CC_MODEL_AFFERENTMETRICS_H diff --git a/plugins/cpp_metrics/model/include/model/cppastnodemetrics.h b/plugins/cpp_metrics/model/include/model/cppastnodemetrics.h index e4c039e8c..68cac1a89 100644 --- a/plugins/cpp_metrics/model/include/model/cppastnodemetrics.h +++ b/plugins/cpp_metrics/model/include/model/cppastnodemetrics.h @@ -21,6 +21,7 @@ struct CppAstNodeMetrics BUMPY_ROAD = 4, LACK_OF_COHESION = 5, LACK_OF_COHESION_HS = 6, + AFFERENT_COUPLING = 7 }; #pragma db id auto diff --git a/plugins/cpp_metrics/parser/include/cppmetricsparser/cppmetricsparser.h b/plugins/cpp_metrics/parser/include/cppmetricsparser/cppmetricsparser.h index 0991b96ad..1168f6391 100644 --- a/plugins/cpp_metrics/parser/include/cppmetricsparser/cppmetricsparser.h +++ b/plugins/cpp_metrics/parser/include/cppmetricsparser/cppmetricsparser.h @@ -76,7 +76,8 @@ class CppMetricsParser : public AbstractParser // Calculate the lack of cohesion between member variables // and member functions for every type. void lackOfCohesion(); - + // Calculate afferent coupling metric bewteen types + void afferentCouplingTypeLevel(); /// @brief Constructs an ODB query that you can use to filter only /// the database records of the given parameter type whose path diff --git a/plugins/cpp_metrics/parser/src/cppmetricsparser.cpp b/plugins/cpp_metrics/parser/src/cppmetricsparser.cpp index a95501512..7845a81df 100644 --- a/plugins/cpp_metrics/parser/src/cppmetricsparser.cpp +++ b/plugins/cpp_metrics/parser/src/cppmetricsparser.cpp @@ -6,6 +6,8 @@ #include #include #include +#include +#include #include #include @@ -98,6 +100,52 @@ bool CppMetricsParser::cleanupDatabase() return true; } + +void CppMetricsParser::afferentCouplingTypeLevel() +{ + util::OdbTransaction{_ctx.db}([&,this] + { + std::set typesFound; + std::unordered_map typeFoundCnt; + std::unordered_map astNodeIdOfType; + + for (const model::AfferentRecordView& type + : _ctx.db->query()) + { + if (!cc::util::isRootedUnderAnyOf(_inputPaths, type.filePath)) + { + continue; + } + + typesFound.clear(); + for (const model::CppMemberType& member : _ctx.db->query( + odb::query::typeHash == type.entityHash && + odb::query::kind == model::CppMemberType::Kind::Field)) + { + typesFound.insert(member.memberTypeHash); + } + + astNodeIdOfType[type.typeHash] = type.astNodeId; + + for (const auto& t : typesFound) + { + typeFoundCnt[t]++; + } + } + + for (const auto& pair : typeFoundCnt) + { + model::CppAstNodeMetrics metric; + metric.astNodeId = astNodeIdOfType[pair.first]; + metric.type = model::CppAstNodeMetrics::Type::AFFERENT_COUPLING; + metric.value = pair.second; + _ctx.db->persist(metric); + } + + + }); +} + void CppMetricsParser::functionParameters() { parallelCalcMetric( @@ -376,6 +424,8 @@ bool CppMetricsParser::parse() typeMcCabe(); LOG(info) << "[cppmetricsparser] Computing Lack of Cohesion metric for types."; lackOfCohesion(); + LOG(info) << "[cppmetricsparser] Computing Afferent Coupling metric for types."; + afferentCouplingTypeLevel(); return true; } From bc01a1034b124021fa210f86bb52fe74ecd205d2 Mon Sep 17 00:00:00 2001 From: Klein Kristof Date: Sun, 7 Jul 2024 22:29:26 +0200 Subject: [PATCH 2/4] Made the metric calculation parallel --- .../cppmetricsparser/cppmetricsparser.h | 1 + .../parser/src/cppmetricsparser.cpp | 71 +++++++++++-------- 2 files changed, 41 insertions(+), 31 deletions(-) diff --git a/plugins/cpp_metrics/parser/include/cppmetricsparser/cppmetricsparser.h b/plugins/cpp_metrics/parser/include/cppmetricsparser/cppmetricsparser.h index 1168f6391..0e6ae31d4 100644 --- a/plugins/cpp_metrics/parser/include/cppmetricsparser/cppmetricsparser.h +++ b/plugins/cpp_metrics/parser/include/cppmetricsparser/cppmetricsparser.h @@ -198,6 +198,7 @@ class CppMetricsParser : public AbstractParser static const int functionMcCabePartitionMultiplier = 5; static const int functionBumpyRoadPartitionMultiplier = 5; static const int lackOfCohesionPartitionMultiplier = 25; + static const int afferentCouplingPartitionMultiplier = 25; }; } // parser diff --git a/plugins/cpp_metrics/parser/src/cppmetricsparser.cpp b/plugins/cpp_metrics/parser/src/cppmetricsparser.cpp index 7845a81df..054090bf6 100644 --- a/plugins/cpp_metrics/parser/src/cppmetricsparser.cpp +++ b/plugins/cpp_metrics/parser/src/cppmetricsparser.cpp @@ -103,46 +103,55 @@ bool CppMetricsParser::cleanupDatabase() void CppMetricsParser::afferentCouplingTypeLevel() { - util::OdbTransaction{_ctx.db}([&,this] - { - std::set typesFound; - std::unordered_map typeFoundCnt; - std::unordered_map astNodeIdOfType; - for (const model::AfferentRecordView& type - : _ctx.db->query()) + // Calculate the cohesion metric for all types on parallel threads. + parallelCalcMetric( + "Afferent coupling", + _threadCount * lackOfCohesionPartitionMultiplier, // number of jobs; adjust for granularity + getFilterPathsQuery(), + [&, this](const MetricsTasks& tasks) + { + util::OdbTransaction{_ctx.db}([&,this] { - if (!cc::util::isRootedUnderAnyOf(_inputPaths, type.filePath)) - { - continue; - } + std::set typesFound; + std::unordered_map typeFoundCnt; + std::unordered_map astNodeIdOfType; - typesFound.clear(); - for (const model::CppMemberType& member : _ctx.db->query( - odb::query::typeHash == type.entityHash && - odb::query::kind == model::CppMemberType::Kind::Field)) + for (const model::AfferentRecordView& type + : _ctx.db->query()) { - typesFound.insert(member.memberTypeHash); + if (!cc::util::isRootedUnderAnyOf(_inputPaths, type.filePath)) + { + continue; + } + + typesFound.clear(); + for (const model::CppMemberType& member : _ctx.db->query( + odb::query::typeHash == type.entityHash && + odb::query::kind == model::CppMemberType::Kind::Field)) + { + typesFound.insert(member.memberTypeHash); + } + + astNodeIdOfType[type.typeHash] = type.astNodeId; + + for (const auto& t : typesFound) + { + typeFoundCnt[t]++; + } } - astNodeIdOfType[type.typeHash] = type.astNodeId; - - for (const auto& t : typesFound) + for (const auto& pair : typeFoundCnt) { - typeFoundCnt[t]++; + model::CppAstNodeMetrics metric; + metric.astNodeId = astNodeIdOfType[pair.first]; + metric.type = model::CppAstNodeMetrics::Type::AFFERENT_COUPLING; + metric.value = pair.second; + _ctx.db->persist(metric); } - } - - for (const auto& pair : typeFoundCnt) - { - model::CppAstNodeMetrics metric; - metric.astNodeId = astNodeIdOfType[pair.first]; - metric.type = model::CppAstNodeMetrics::Type::AFFERENT_COUPLING; - metric.value = pair.second; - _ctx.db->persist(metric); - } - + + }); }); } From 73f8e721e9d671d55efd9c697a432654b94b6b88 Mon Sep 17 00:00:00 2001 From: Klein Kristof Date: Sun, 7 Jul 2024 22:33:05 +0200 Subject: [PATCH 3/4] Revert "Made the metric calculation parallel" This reverts commit bc01a1034b124021fa210f86bb52fe74ecd205d2. --- .../cppmetricsparser/cppmetricsparser.h | 1 - .../parser/src/cppmetricsparser.cpp | 71 ++++++++----------- 2 files changed, 31 insertions(+), 41 deletions(-) diff --git a/plugins/cpp_metrics/parser/include/cppmetricsparser/cppmetricsparser.h b/plugins/cpp_metrics/parser/include/cppmetricsparser/cppmetricsparser.h index 0e6ae31d4..1168f6391 100644 --- a/plugins/cpp_metrics/parser/include/cppmetricsparser/cppmetricsparser.h +++ b/plugins/cpp_metrics/parser/include/cppmetricsparser/cppmetricsparser.h @@ -198,7 +198,6 @@ class CppMetricsParser : public AbstractParser static const int functionMcCabePartitionMultiplier = 5; static const int functionBumpyRoadPartitionMultiplier = 5; static const int lackOfCohesionPartitionMultiplier = 25; - static const int afferentCouplingPartitionMultiplier = 25; }; } // parser diff --git a/plugins/cpp_metrics/parser/src/cppmetricsparser.cpp b/plugins/cpp_metrics/parser/src/cppmetricsparser.cpp index 054090bf6..7845a81df 100644 --- a/plugins/cpp_metrics/parser/src/cppmetricsparser.cpp +++ b/plugins/cpp_metrics/parser/src/cppmetricsparser.cpp @@ -103,55 +103,46 @@ bool CppMetricsParser::cleanupDatabase() void CppMetricsParser::afferentCouplingTypeLevel() { - - // Calculate the cohesion metric for all types on parallel threads. - parallelCalcMetric( - "Afferent coupling", - _threadCount * lackOfCohesionPartitionMultiplier, // number of jobs; adjust for granularity - getFilterPathsQuery(), - [&, this](const MetricsTasks& tasks) + util::OdbTransaction{_ctx.db}([&,this] { - util::OdbTransaction{_ctx.db}([&,this] - { - std::set typesFound; - std::unordered_map typeFoundCnt; - std::unordered_map astNodeIdOfType; + std::set typesFound; + std::unordered_map typeFoundCnt; + std::unordered_map astNodeIdOfType; - for (const model::AfferentRecordView& type - : _ctx.db->query()) + for (const model::AfferentRecordView& type + : _ctx.db->query()) + { + if (!cc::util::isRootedUnderAnyOf(_inputPaths, type.filePath)) { - if (!cc::util::isRootedUnderAnyOf(_inputPaths, type.filePath)) - { - continue; - } - - typesFound.clear(); - for (const model::CppMemberType& member : _ctx.db->query( - odb::query::typeHash == type.entityHash && - odb::query::kind == model::CppMemberType::Kind::Field)) - { - typesFound.insert(member.memberTypeHash); - } - - astNodeIdOfType[type.typeHash] = type.astNodeId; + continue; + } - for (const auto& t : typesFound) - { - typeFoundCnt[t]++; - } + typesFound.clear(); + for (const model::CppMemberType& member : _ctx.db->query( + odb::query::typeHash == type.entityHash && + odb::query::kind == model::CppMemberType::Kind::Field)) + { + typesFound.insert(member.memberTypeHash); } - for (const auto& pair : typeFoundCnt) + astNodeIdOfType[type.typeHash] = type.astNodeId; + + for (const auto& t : typesFound) { - model::CppAstNodeMetrics metric; - metric.astNodeId = astNodeIdOfType[pair.first]; - metric.type = model::CppAstNodeMetrics::Type::AFFERENT_COUPLING; - metric.value = pair.second; - _ctx.db->persist(metric); + typeFoundCnt[t]++; } - + } + + for (const auto& pair : typeFoundCnt) + { + model::CppAstNodeMetrics metric; + metric.astNodeId = astNodeIdOfType[pair.first]; + metric.type = model::CppAstNodeMetrics::Type::AFFERENT_COUPLING; + metric.value = pair.second; + _ctx.db->persist(metric); + } + - }); }); } From d3bec52cdd46a82a0da2e762872d140696c391bb Mon Sep 17 00:00:00 2001 From: Klein Kristof Date: Sun, 7 Jul 2024 22:34:23 +0200 Subject: [PATCH 4/4] Made the metric calculation parallel --- .../cppmetricsparser/cppmetricsparser.h | 1 + .../parser/src/cppmetricsparser.cpp | 71 +++++++++++-------- 2 files changed, 41 insertions(+), 31 deletions(-) diff --git a/plugins/cpp_metrics/parser/include/cppmetricsparser/cppmetricsparser.h b/plugins/cpp_metrics/parser/include/cppmetricsparser/cppmetricsparser.h index 1168f6391..0e6ae31d4 100644 --- a/plugins/cpp_metrics/parser/include/cppmetricsparser/cppmetricsparser.h +++ b/plugins/cpp_metrics/parser/include/cppmetricsparser/cppmetricsparser.h @@ -198,6 +198,7 @@ class CppMetricsParser : public AbstractParser static const int functionMcCabePartitionMultiplier = 5; static const int functionBumpyRoadPartitionMultiplier = 5; static const int lackOfCohesionPartitionMultiplier = 25; + static const int afferentCouplingPartitionMultiplier = 25; }; } // parser diff --git a/plugins/cpp_metrics/parser/src/cppmetricsparser.cpp b/plugins/cpp_metrics/parser/src/cppmetricsparser.cpp index 7845a81df..985bbfe66 100644 --- a/plugins/cpp_metrics/parser/src/cppmetricsparser.cpp +++ b/plugins/cpp_metrics/parser/src/cppmetricsparser.cpp @@ -103,46 +103,55 @@ bool CppMetricsParser::cleanupDatabase() void CppMetricsParser::afferentCouplingTypeLevel() { - util::OdbTransaction{_ctx.db}([&,this] - { - std::set typesFound; - std::unordered_map typeFoundCnt; - std::unordered_map astNodeIdOfType; - for (const model::AfferentRecordView& type - : _ctx.db->query()) + // Calculate the cohesion metric for all types on parallel threads. + parallelCalcMetric( + "Afferent coupling", + _threadCount * afferentCouplingPartitionMultiplier, // number of jobs; adjust for granularity + getFilterPathsQuery(), + [&, this](const MetricsTasks& tasks) + { + util::OdbTransaction{_ctx.db}([&,this] { - if (!cc::util::isRootedUnderAnyOf(_inputPaths, type.filePath)) - { - continue; - } + std::set typesFound; + std::unordered_map typeFoundCnt; + std::unordered_map astNodeIdOfType; - typesFound.clear(); - for (const model::CppMemberType& member : _ctx.db->query( - odb::query::typeHash == type.entityHash && - odb::query::kind == model::CppMemberType::Kind::Field)) + for (const model::AfferentRecordView& type + : _ctx.db->query()) { - typesFound.insert(member.memberTypeHash); + if (!cc::util::isRootedUnderAnyOf(_inputPaths, type.filePath)) + { + continue; + } + + typesFound.clear(); + for (const model::CppMemberType& member : _ctx.db->query( + odb::query::typeHash == type.entityHash && + odb::query::kind == model::CppMemberType::Kind::Field)) + { + typesFound.insert(member.memberTypeHash); + } + + astNodeIdOfType[type.typeHash] = type.astNodeId; + + for (const auto& t : typesFound) + { + typeFoundCnt[t]++; + } } - astNodeIdOfType[type.typeHash] = type.astNodeId; - - for (const auto& t : typesFound) + for (const auto& pair : typeFoundCnt) { - typeFoundCnt[t]++; + model::CppAstNodeMetrics metric; + metric.astNodeId = astNodeIdOfType[pair.first]; + metric.type = model::CppAstNodeMetrics::Type::AFFERENT_COUPLING; + metric.value = pair.second; + _ctx.db->persist(metric); } - } - - for (const auto& pair : typeFoundCnt) - { - model::CppAstNodeMetrics metric; - metric.astNodeId = astNodeIdOfType[pair.first]; - metric.type = model::CppAstNodeMetrics::Type::AFFERENT_COUPLING; - metric.value = pair.second; - _ctx.db->persist(metric); - } - + + }); }); }