Skip to content

Commit f7b0b0a

Browse files
author
Barnabás Domozi
committed
Implement efferent coupling at module level.
1 parent bd60791 commit f7b0b0a

File tree

7 files changed

+156
-10
lines changed

7 files changed

+156
-10
lines changed

plugins/cpp_metrics/model/CMakeLists.txt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,12 @@ include_directories(
55
set(ODB_SOURCES
66
include/model/cppastnodemetrics.h
77
include/model/cppcohesionmetrics.h
8-
include/model/cppfilemetrics.h)
8+
include/model/cppfilemetrics.h
9+
include/model/cpptypedependencymetrics.h)
910

1011
generate_odb_files("${ODB_SOURCES}" "cpp")
1112

1213
add_odb_library(cppmetricsmodel ${ODB_CXX_SOURCES})
1314
target_link_libraries(cppmetricsmodel cppmodel)
1415

15-
install_sql()
16+
install_sql()

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ struct CppFileMetrics
1313
{
1414
enum Type
1515
{
16-
PLACEHOLDER
16+
EFFERENT_MODULE
1717
};
1818

1919
#pragma db id auto
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
#ifndef CC_MODEL_CPPTYPEDEPENDENCYMETRICS_H
2+
#define CC_MODEL_CPPTYPEDEPENDENCYMETRICS_H
3+
4+
#include <cstdint>
5+
#include <string>
6+
#include <model/cppentity.h>
7+
#include <model/cpprecord.h>
8+
#include <model/cppastnode.h>
9+
#include <model/file.h>
10+
11+
namespace cc
12+
{
13+
namespace model
14+
{
15+
16+
#pragma db object
17+
struct CppTypeDependencyMetrics
18+
{
19+
#pragma db id auto
20+
std::uint64_t id;
21+
22+
#pragma db not_null
23+
std::uint64_t entityHash;
24+
25+
#pragma db not_null
26+
std::uint64_t dependencyHash;
27+
};
28+
29+
#pragma db view \
30+
object(CppTypeDependencyMetrics) \
31+
object(CppAstNode = EntityAstNode : CppTypeDependencyMetrics::entityHash == EntityAstNode::entityHash \
32+
&& EntityAstNode::astType == cc::model::CppAstNode::AstType::Definition) \
33+
object(File = EntityFile : EntityAstNode::location.file == EntityFile::id) \
34+
object(CppAstNode = DependencyAstNode : CppTypeDependencyMetrics::dependencyHash == DependencyAstNode::entityHash \
35+
&& DependencyAstNode::astType == cc::model::CppAstNode::AstType::Definition) \
36+
object(File = DependencyFile : DependencyAstNode::location.file == DependencyFile::id)
37+
struct CppTypeDependencyMetricsPathView
38+
{
39+
#pragma db column(CppTypeDependencyMetrics::entityHash)
40+
std::size_t entityHash;
41+
42+
#pragma db column(CppTypeDependencyMetrics::dependencyHash)
43+
std::size_t dependencyHash;
44+
45+
#pragma db column(EntityFile::path)
46+
std::string entityPath;
47+
48+
#pragma db column(DependencyFile::path)
49+
std::string dependencyPath;
50+
};
51+
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+
query((?), distinct)
61+
struct CppDistinctTypeDependencyMetricsPathView
62+
{
63+
#pragma db column(CppTypeDependencyMetrics::dependencyHash)
64+
std::size_t dependencyHash;
65+
};
66+
67+
} // model
68+
} // cc
69+
70+
#endif // CC_MODEL_CPPTYPEDEPENDENCYMETRICS_H

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,10 @@ class CppMetricsParser : public AbstractParser
8080
void efferentTypeLevel();
8181
// Calculate the afferent coupling of types.
8282
void afferentTypeLevel();
83-
83+
// Calculate the efferent coupling at module level.
84+
void efferentModuleLevel();
85+
// Returns module path query based on parser configuration.
86+
odb::query<model::File> getModulePathsQuery();
8487

8588
/// @brief Constructs an ODB query that you can use to filter only
8689
/// the database records of the given parameter type whose path
@@ -203,6 +206,7 @@ class CppMetricsParser : public AbstractParser
203206
static const int lackOfCohesionPartitionMultiplier = 25;
204207
static const int efferentCouplingTypesPartitionMultiplier = 5;
205208
static const int afferentCouplingTypesPartitionMultiplier = 5;
209+
static const int efferentCouplingModulesPartitionMultiplier = 5;
206210
};
207211

208212
} // parser

plugins/cpp_metrics/parser/src/cppmetricsparser.cpp

Lines changed: 66 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,12 @@
1010
#include <model/cppinheritance-odb.hxx>
1111
#include <model/cpprecord.h>
1212
#include <model/cpprecord-odb.hxx>
13-
13+
#include <model/cpptypedependencymetrics.h>
14+
#include <model/cpptypedependencymetrics-odb.hxx>
1415
#include <model/cppastnode.h>
1516
#include <model/cppastnode-odb.hxx>
17+
#include <model/file.h>
18+
#include <model/file-odb.hxx>
1619

1720
#include <boost/filesystem.hpp>
1821

@@ -390,7 +393,7 @@ void CppMetricsParser::efferentTypeLevel()
390393
dependentTypes.clear();
391394

392395
// Count parent types
393-
auto inheritanceView = _ctx.db->query<model::CppInheritanceCount>(
396+
auto inheritanceView = _ctx.db->query<model::CppInheritance>(
394397
InheritanceQuery::derived == type.entityHash);
395398

396399
// Count unique attribute types
@@ -423,8 +426,26 @@ void CppMetricsParser::efferentTypeLevel()
423426
model::CppAstNodeMetrics metric;
424427
metric.astNodeId = type.astNodeId;
425428
metric.type = model::CppAstNodeMetrics::Type::EFFERENT_TYPE;
426-
metric.value = inheritanceView.begin()->count + dependentTypes.size();
429+
metric.value = inheritanceView.size() + dependentTypes.size();
427430
_ctx.db->persist(metric);
431+
432+
auto typeRelationInserter = [this](const std::uint64_t& entityHash, const std::uint64_t& dependencyHash)
433+
{
434+
model::CppTypeDependencyMetrics relation;
435+
relation.entityHash = entityHash;
436+
relation.dependencyHash = dependencyHash;
437+
_ctx.db->persist(relation);
438+
};
439+
440+
// Insert type dependency relations
441+
for (const std::uint64_t& d : dependentTypes) {
442+
typeRelationInserter(type.entityHash, d);
443+
}
444+
445+
// Insert inheritance relations
446+
for (const model::CppInheritance& d : inheritanceView) {
447+
typeRelationInserter(type.entityHash, d.base);
448+
}
428449
}
429450
});
430451
});
@@ -513,6 +534,46 @@ void CppMetricsParser::afferentTypeLevel()
513534
});
514535
}
515536

537+
odb::query<model::File> CppMetricsParser::getModulePathsQuery()
538+
{
539+
if (_ctx.moduleDirectories.empty()) {
540+
// No module directories specified, compute for all directories
541+
return odb::query<model::File>::type == cc::model::File::DIRECTORY_TYPE && getFilterPathsQuery<model::File>();
542+
} else {
543+
// Compute for module directories
544+
return odb::query<model::File>::path.in_range(_ctx.moduleDirectories.begin(), _ctx.moduleDirectories.end());
545+
}
546+
}
547+
548+
void CppMetricsParser::efferentModuleLevel()
549+
{
550+
parallelCalcMetric<model::File>(
551+
"Efferent coupling at module level",
552+
_threadCount * efferentCouplingModulesPartitionMultiplier,// number of jobs; adjust for granularity
553+
getModulePathsQuery(),
554+
[&, this](const MetricsTasks<model::File>& tasks)
555+
{
556+
util::OdbTransaction{_ctx.db}([&, this]
557+
{
558+
typedef odb::query<cc::model::CppDistinctTypeDependencyMetricsPathView> TypeDependencyQuery;
559+
typedef odb::result<cc::model::CppDistinctTypeDependencyMetricsPathView> TypeDependencyResult;
560+
561+
for (const model::File& file : tasks)
562+
{
563+
TypeDependencyResult types = _ctx.db->query<model::CppDistinctTypeDependencyMetricsPathView>(
564+
TypeDependencyQuery::EntityFile::path.like(file.path + '%') &&
565+
!TypeDependencyQuery::DependencyFile::path.like(file.path + '%'));
566+
567+
model::CppFileMetrics metric;
568+
metric.file = file.id;
569+
metric.type = model::CppFileMetrics::Type::EFFERENT_MODULE;
570+
metric.value = types.size();
571+
_ctx.db->persist(metric);
572+
}
573+
});
574+
});
575+
}
576+
516577
bool CppMetricsParser::parse()
517578
{
518579
LOG(info) << "[cppmetricsparser] Computing function parameter count metric.";
@@ -529,6 +590,8 @@ bool CppMetricsParser::parse()
529590
efferentTypeLevel();
530591
LOG(info) << "[cppmetricsparser] Computing afferent coupling metric for types.";
531592
afferentTypeLevel();
593+
LOG(info) << "[cppmetricsparser] Computing efferent coupling metric at module level.";
594+
efferentModuleLevel(); // This metric needs to be calculated after efferentTypeLevel
532595
return true;
533596
}
534597

util/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ add_library(util SHARED
1818
src/util.cpp)
1919

2020
target_link_libraries(util
21+
model
2122
gvc
2223
${Boost_LIBRARIES})
2324

util/include/util/dbutil.h

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
#include <memory>
55
#include <string>
6+
#include <model/file.h>
7+
#include <model/file-odb.hxx>
68

79
#include <odb/database.hxx>
810

@@ -147,10 +149,15 @@ odb::query<TQueryParam> getFilterPathsQuery(
147149
TIter begin_,
148150
const TSentinel& end_)
149151
{
150-
typedef typename odb::query<TQueryParam>::query_columns QParam;
151-
const auto& QParamPath = QParam::File::path;
152-
constexpr char ODBWildcard = '%';
152+
const auto& QParamPath = [](){
153+
if constexpr (std::is_same<TQueryParam, cc::model::File>::value) {
154+
return odb::query<TQueryParam>::path;
155+
} else {
156+
return odb::query<TQueryParam>::query_columns::File::path;
157+
}
158+
}();
153159

160+
constexpr char ODBWildcard = '%';
154161
assert(begin_ != end_ && "At least one filter path must be provided.");
155162
odb::query<TQueryParam> query = QParamPath.like(*begin_ + ODBWildcard);
156163
while (++begin_ != end_)

0 commit comments

Comments
 (0)