Skip to content

Commit 8d231d9

Browse files
author
Barnabás Domozi
committed
Added afferent coupling for types.
1 parent c709db4 commit 8d231d9

File tree

6 files changed

+108
-3
lines changed

6 files changed

+108
-3
lines changed

plugins/cpp/model/include/model/cpprecord.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,15 @@ struct CppRecordCount
9090
std::size_t count;
9191
};
9292

93+
#pragma db view \
94+
object(CppMemberType) \
95+
object(CppAstNode : CppMemberType::memberAstNode == CppAstNode::id)
96+
struct CppMemberTypeAstView
97+
{
98+
#pragma db column(CppMemberType::typeHash)
99+
std::uint64_t typeHash;
100+
};
101+
93102
}
94103
}
95104

plugins/cpp_metrics/model/include/model/cppastnodemetrics.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ struct CppAstNodeMetrics
2222
BUMPY_ROAD = 4,
2323
LACK_OF_COHESION = 5,
2424
LACK_OF_COHESION_HS = 6,
25-
EFFERENT_TYPE = 7
25+
EFFERENT_TYPE = 7,
26+
AFFERENT_TYPE = 8
2627
};
2728

2829
#pragma db id auto

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ class CppMetricsParser : public AbstractParser
7878
void lackOfCohesion();
7979
// Calculate the efferent coupling of types.
8080
void efferentTypeLevel();
81+
// Calculate the afferent coupling of types.
82+
void afferentTypeLevel();
8183

8284

8385
/// @brief Constructs an ODB query that you can use to filter only
@@ -200,6 +202,7 @@ class CppMetricsParser : public AbstractParser
200202
static const int functionBumpyRoadPartitionMultiplier = 5;
201203
static const int lackOfCohesionPartitionMultiplier = 25;
202204
static const int efferentCouplingTypesPartitionMultiplier = 5;
205+
static const int afferentCouplingTypesPartitionMultiplier = 5;
203206
};
204207

205208
} // parser

plugins/cpp_metrics/parser/src/cppmetricsparser.cpp

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
#include <model/cppfilemetrics-odb.hxx>
99
#include <model/cppinheritance.h>
1010
#include <model/cppinheritance-odb.hxx>
11+
#include <model/cpprecord.h>
12+
#include <model/cpprecord-odb.hxx>
1113

1214
#include <model/cppastnode.h>
1315
#include <model/cppastnode-odb.hxx>
@@ -428,6 +430,89 @@ void CppMetricsParser::efferentTypeLevel()
428430
});
429431
}
430432

433+
void CppMetricsParser::afferentTypeLevel()
434+
{
435+
parallelCalcMetric<model::CohesionCppRecordView>(
436+
"Afferent coupling of types",
437+
_threadCount * afferentCouplingTypesPartitionMultiplier,// number of jobs; adjust for granularity
438+
getFilterPathsQuery<model::CohesionCppRecordView>(),
439+
[&, this](const MetricsTasks<model::CohesionCppRecordView>& tasks)
440+
{
441+
util::OdbTransaction{_ctx.db}([&, this]
442+
{
443+
typedef odb::query<cc::model::CppAstNode> AstQuery;
444+
typedef odb::query<cc::model::CppInheritance> InheritanceQuery;
445+
typedef odb::query<cc::model::CppMemberType> MemTypeQuery;
446+
typedef odb::result<cc::model::CppAstNode> AstResult;
447+
typedef odb::result<cc::model::CppMemberTypeAstView> MemTypeAstResult;
448+
449+
std::set<std::uint64_t> dependentTypes;
450+
for (const model::CohesionCppRecordView& type : tasks)
451+
{
452+
dependentTypes.clear();
453+
454+
// Find derived types
455+
for (const model::CppInheritance& inheritance : _ctx.db->query<model::CppInheritance>(
456+
InheritanceQuery::base == type.entityHash))
457+
{
458+
dependentTypes.insert(inheritance.derived);
459+
}
460+
461+
// Find usages of the type
462+
for (const model::CppAstNode& usage : _ctx.db->query<model::CppAstNode>(
463+
AstQuery::entityHash == type.entityHash &&
464+
AstQuery::location.range.end.line != model::Position::npos))
465+
{
466+
// Check if usage is in class member function or attribute
467+
MemTypeAstResult memberNode = _ctx.db->query<model::CppMemberTypeAstView>(
468+
AstQuery::symbolType.in(model::CppAstNode::SymbolType::Function, model::CppAstNode::SymbolType::Variable) &&
469+
AstQuery::astType.in(model::CppAstNode::AstType::Definition, model::CppAstNode::AstType::Declaration) &&
470+
AstQuery::location.file == usage.location.file.object_id() &&
471+
AstQuery::location.range.start.line <= usage.location.range.start.line &&
472+
AstQuery::location.range.end.line >= usage.location.range.end.line &&
473+
MemTypeQuery::typeHash != usage.entityHash);
474+
475+
if (!memberNode.empty())
476+
{
477+
dependentTypes.insert(memberNode.begin()->typeHash);
478+
} else {
479+
// The usage can be in a member function defined outside of the class definition
480+
// E.g. void ClassName::foo() { A a; }
481+
// ^ usage here
482+
483+
// Find parent function
484+
AstResult parentFunction = _ctx.db->query<model::CppAstNode>(
485+
AstQuery::symbolType == model::CppAstNode::SymbolType::Function &&
486+
AstQuery::astType == model::CppAstNode::AstType::Definition &&
487+
AstQuery::location.file == usage.location.file.object_id() &&
488+
AstQuery::location.range.start.line <= usage.location.range.start.line &&
489+
AstQuery::location.range.end.line >= usage.location.range.end.line);
490+
491+
if (!parentFunction.empty())
492+
{
493+
// Find if the function is a member function of a class
494+
MemTypeAstResult memberFunction = _ctx.db->query<model::CppMemberTypeAstView>(
495+
AstQuery::entityHash == parentFunction.begin()->entityHash &&
496+
MemTypeQuery::typeHash != usage.entityHash);
497+
498+
if (!memberFunction.empty())
499+
{
500+
dependentTypes.insert(memberFunction.begin()->typeHash);
501+
}
502+
}
503+
}
504+
}
505+
506+
model::CppAstNodeMetrics metric;
507+
metric.astNodeId = type.astNodeId;
508+
metric.type = model::CppAstNodeMetrics::Type::AFFERENT_TYPE;
509+
metric.value = dependentTypes.size();
510+
_ctx.db->persist(metric);
511+
}
512+
});
513+
});
514+
}
515+
431516
bool CppMetricsParser::parse()
432517
{
433518
LOG(info) << "[cppmetricsparser] Computing function parameter count metric.";
@@ -442,6 +527,8 @@ bool CppMetricsParser::parse()
442527
lackOfCohesion();
443528
LOG(info) << "[cppmetricsparser] Computing efferent coupling metric for types.";
444529
efferentTypeLevel();
530+
LOG(info) << "[cppmetricsparser] Computing afferent coupling metric for types.";
531+
afferentTypeLevel();
445532
return true;
446533
}
447534

plugins/cpp_metrics/service/cxxmetrics.thrift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ enum CppAstNodeMetricsType
1212
BumpyRoad = 4,
1313
LackOfCohesion = 5,
1414
LackOfCohesionHS = 6,
15-
EfferentType = 7
15+
EfferentType = 7,
16+
AfferentType = 8
1617
}
1718

1819
enum CppModuleMetricsType
@@ -124,4 +125,4 @@ service CppMetricsService
124125
* This function returns the names of module-level C++ metrics.
125126
*/
126127
list<CppModuleMetricsTypeName> getCppModuleMetricsTypeNames()
127-
}
128+
}

plugins/cpp_metrics/service/src/cppmetricsservice.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@ void CppMetricsServiceHandler::getCppAstNodeMetricsTypeNames(
5757
typeName.type = CppAstNodeMetricsType::EfferentType;
5858
typeName.name = "Efferent coupling of type";
5959
_return.push_back(typeName);
60+
61+
typeName.type = CppAstNodeMetricsType::AfferentType;
62+
typeName.name = "Afferent coupling of type";
63+
_return.push_back(typeName);
6064
}
6165

6266
void CppMetricsServiceHandler::getCppModuleMetricsTypeNames(

0 commit comments

Comments
 (0)