diff --git a/plugins/cpp/model/include/model/cppfunction.h b/plugins/cpp/model/include/model/cppfunction.h index 7eca88a29..b6e39395f 100644 --- a/plugins/cpp/model/include/model/cppfunction.h +++ b/plugins/cpp/model/include/model/cppfunction.h @@ -95,6 +95,29 @@ struct CppFunctionBumpyRoad unsigned int statementCount; }; +#pragma db view \ + object(CppFunction) \ + object(CppVariable = Parameters : CppFunction::parameters) +struct CppFunctionParamTypeView +{ + #pragma db column(CppFunction::astNodeId) + CppAstNodeId astNodeId; + + #pragma db column(Parameters::typeHash) + std::uint64_t paramTypeHash; +}; + +#pragma db view \ + object(CppFunction) \ + object(CppVariable = Locals : CppFunction::locals) +struct CppFunctionLocalTypeView +{ +#pragma db column(CppFunction::astNodeId) + CppAstNodeId astNodeId; + +#pragma db column(Locals::typeHash) + std::uint64_t paramTypeHash; +}; } } diff --git a/plugins/cpp_metrics/model/include/model/cppastnodemetrics.h b/plugins/cpp_metrics/model/include/model/cppastnodemetrics.h index 184b3b455..69e996451 100644 --- a/plugins/cpp_metrics/model/include/model/cppastnodemetrics.h +++ b/plugins/cpp_metrics/model/include/model/cppastnodemetrics.h @@ -22,6 +22,7 @@ struct CppAstNodeMetrics BUMPY_ROAD = 4, LACK_OF_COHESION = 5, LACK_OF_COHESION_HS = 6, + EFFERENT_TYPE = 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..69f1f2b40 100644 --- a/plugins/cpp_metrics/parser/include/cppmetricsparser/cppmetricsparser.h +++ b/plugins/cpp_metrics/parser/include/cppmetricsparser/cppmetricsparser.h @@ -76,6 +76,8 @@ class CppMetricsParser : public AbstractParser // Calculate the lack of cohesion between member variables // and member functions for every type. void lackOfCohesion(); + // Calculate the efferent coupling of types. + void efferentTypeLevel(); /// @brief Constructs an ODB query that you can use to filter only @@ -197,6 +199,7 @@ class CppMetricsParser : public AbstractParser static const int functionMcCabePartitionMultiplier = 5; static const int functionBumpyRoadPartitionMultiplier = 5; static const int lackOfCohesionPartitionMultiplier = 25; + static const int efferentCouplingTypesPartitionMultiplier = 5; }; } // parser diff --git a/plugins/cpp_metrics/parser/src/cppmetricsparser.cpp b/plugins/cpp_metrics/parser/src/cppmetricsparser.cpp index a95501512..8fe839c64 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 @@ -364,6 +366,68 @@ void CppMetricsParser::lackOfCohesion() }); } +void CppMetricsParser::efferentTypeLevel() +{ + parallelCalcMetric( + "Efferent coupling of types", + _threadCount * efferentCouplingTypesPartitionMultiplier,// number of jobs; adjust for granularity + getFilterPathsQuery(), + [&, this](const MetricsTasks& tasks) + { + util::OdbTransaction{_ctx.db}([&, this] + { + typedef odb::query MemTypeQuery; + typedef odb::query InheritanceQuery; + typedef odb::query ParamQuery; + typedef odb::query LocalQuery; + typedef odb::query FuncQuery; + + std::set dependentTypes; + for (const model::CohesionCppRecordView& type : tasks) + { + dependentTypes.clear(); + + // Count parent types + auto inheritanceView = _ctx.db->query( + InheritanceQuery::derived == type.entityHash); + + // Count unique attribute types + // and unique types in function parameters and local variables + for (const model::CppMemberType& mem: _ctx.db->query( + MemTypeQuery::typeHash == type.entityHash)) + { + auto funcAstNodeId = mem.memberAstNode.load()->id; + + if (mem.kind == cc::model::CppMemberType::Field) + { + dependentTypes.insert(mem.memberTypeHash); + } + else + { + for (const auto& param: _ctx.db->query( + FuncQuery::astNodeId == funcAstNodeId)) + { + dependentTypes.insert(param.paramTypeHash); + } + + for (const auto& local: _ctx.db->query( + FuncQuery::astNodeId == funcAstNodeId)) + { + dependentTypes.insert(local.paramTypeHash); + } + } + } + + model::CppAstNodeMetrics metric; + metric.astNodeId = type.astNodeId; + metric.type = model::CppAstNodeMetrics::Type::EFFERENT_TYPE; + metric.value = inheritanceView.begin()->count + dependentTypes.size(); + _ctx.db->persist(metric); + } + }); + }); +} + bool CppMetricsParser::parse() { LOG(info) << "[cppmetricsparser] Computing function parameter count metric."; @@ -376,6 +440,8 @@ bool CppMetricsParser::parse() typeMcCabe(); LOG(info) << "[cppmetricsparser] Computing Lack of Cohesion metric for types."; lackOfCohesion(); + LOG(info) << "[cppmetricsparser] Computing efferent coupling metric for types."; + efferentTypeLevel(); return true; } diff --git a/plugins/cpp_metrics/service/cxxmetrics.thrift b/plugins/cpp_metrics/service/cxxmetrics.thrift index 6ab81d974..152063a48 100644 --- a/plugins/cpp_metrics/service/cxxmetrics.thrift +++ b/plugins/cpp_metrics/service/cxxmetrics.thrift @@ -12,6 +12,7 @@ enum CppAstNodeMetricsType BumpyRoad = 4, LackOfCohesion = 5, LackOfCohesionHS = 6, + EfferentType = 7 } enum CppModuleMetricsType diff --git a/plugins/cpp_metrics/service/src/cppmetricsservice.cpp b/plugins/cpp_metrics/service/src/cppmetricsservice.cpp index 0dd92371e..9e3b999b5 100644 --- a/plugins/cpp_metrics/service/src/cppmetricsservice.cpp +++ b/plugins/cpp_metrics/service/src/cppmetricsservice.cpp @@ -53,6 +53,10 @@ void CppMetricsServiceHandler::getCppAstNodeMetricsTypeNames( typeName.type = CppAstNodeMetricsType::LackOfCohesionHS; typeName.name = "Lack of cohesion of type (Henderson-Sellers variant)"; _return.push_back(typeName); + + typeName.type = CppAstNodeMetricsType::EfferentType; + typeName.name = "Efferent coupling of type"; + _return.push_back(typeName); } void CppMetricsServiceHandler::getCppModuleMetricsTypeNames( @@ -194,9 +198,8 @@ void CppMetricsServiceHandler::getCppAstNodeMetricsDetailedForPath( metric.astValue = node.astValue; metric.symbolType = cc::model::symbolTypeToString(node.symbolType); metric.astType = cc::model::astTypeToString(node.astType); + metric.metrics.insert(pair); - std::map metricsList; - metricsList.insert(pair); _return.insert(std::make_pair(std::to_string(node.astNodeId), metric)); } }