Skip to content

Commit 20a9bd2

Browse files
authored
Merge pull request #790 from wbqpk3/efferent_coupling_modules
Implement efferent coupling at module level
2 parents 93cc594 + 1ceb98e commit 20a9bd2

File tree

17 files changed

+290
-25
lines changed

17 files changed

+290
-25
lines changed

plugins/cpp/model/include/model/cppfunction.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ struct CppFunction : CppTypedEntity
3636
typedef std::shared_ptr<CppFunction> CppFunctionPtr;
3737

3838
#pragma db view \
39-
object(CppFunction) object(CppVariable = Parameters : CppFunction::parameters)
39+
object(CppFunction) object(CppVariable = Parameters inner : CppFunction::parameters)
4040
struct CppFunctionParamCount
4141
{
4242
#pragma db column("count(" + Parameters::id + ")")
@@ -45,7 +45,7 @@ struct CppFunctionParamCount
4545

4646
#pragma db view \
4747
object(CppFunction) \
48-
object(CppVariable = Parameters : CppFunction::parameters) \
48+
object(CppVariable = Parameters inner : CppFunction::parameters) \
4949
object(CppAstNode : CppFunction::astNodeId == CppAstNode::id) \
5050
object(File : CppAstNode::location.file) \
5151
query((?) + "GROUP BY" + cc::model::CppEntity::astNodeId + "," + cc::model::File::path)
@@ -59,7 +59,7 @@ struct CppFunctionParamCountWithId
5959
};
6060

6161
#pragma db view \
62-
object(CppFunction) object(CppVariable = Locals : CppFunction::locals)
62+
object(CppFunction) object(CppVariable = Locals inner : CppFunction::locals)
6363
struct CppFunctionLocalCount
6464
{
6565
#pragma db column("count(" + Locals::id + ")")
@@ -97,7 +97,7 @@ struct CppFunctionBumpyRoad
9797

9898
#pragma db view \
9999
object(CppFunction) \
100-
object(CppVariable = Parameters : CppFunction::parameters)
100+
object(CppVariable = Parameters inner : CppFunction::parameters)
101101
struct CppFunctionParamTypeView
102102
{
103103
#pragma db column(CppFunction::astNodeId)
@@ -109,7 +109,7 @@ struct CppFunctionParamTypeView
109109

110110
#pragma db view \
111111
object(CppFunction) \
112-
object(CppVariable = Locals : CppFunction::locals)
112+
object(CppVariable = Locals inner : CppFunction::locals)
113113
struct CppFunctionLocalTypeView
114114
{
115115
#pragma db column(CppFunction::astNodeId)

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: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
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+
struct CppTypeDependencyMetricsPathViewDistinctCount
61+
{
62+
#pragma db column("count(distinct" + CppTypeDependencyMetrics::dependencyHash + ")")
63+
std::size_t count;
64+
};
65+
66+
} // model
67+
} // cc
68+
69+
#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: 68 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,9 @@ 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>(
397+
InheritanceQuery::derived == type.entityHash);
398+
auto inheritanceCount = _ctx.db->query_value<model::CppInheritanceCount>(
394399
InheritanceQuery::derived == type.entityHash);
395400

396401
// Count unique attribute types
@@ -423,8 +428,26 @@ void CppMetricsParser::efferentTypeLevel()
423428
model::CppAstNodeMetrics metric;
424429
metric.astNodeId = type.astNodeId;
425430
metric.type = model::CppAstNodeMetrics::Type::EFFERENT_TYPE;
426-
metric.value = inheritanceView.begin()->count + dependentTypes.size();
431+
metric.value = inheritanceCount.count + dependentTypes.size();
427432
_ctx.db->persist(metric);
433+
434+
auto typeRelationInserter = [this](const std::uint64_t& entityHash, const std::uint64_t& dependencyHash)
435+
{
436+
model::CppTypeDependencyMetrics relation;
437+
relation.entityHash = entityHash;
438+
relation.dependencyHash = dependencyHash;
439+
_ctx.db->persist(relation);
440+
};
441+
442+
// Insert type dependency relations
443+
for (const std::uint64_t& d : dependentTypes) {
444+
typeRelationInserter(type.entityHash, d);
445+
}
446+
447+
// Insert inheritance relations
448+
for (const model::CppInheritance& d : inheritanceView) {
449+
typeRelationInserter(type.entityHash, d.base);
450+
}
428451
}
429452
});
430453
});
@@ -513,6 +536,46 @@ void CppMetricsParser::afferentTypeLevel()
513536
});
514537
}
515538

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

plugins/cpp_metrics/test/sources/parser/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@ add_library(CppMetricsTestProject STATIC
66
typemccabe.cpp
77
lackofcohesion.cpp
88
bumpyroad.cpp
9-
afferentcoupling.cpp)
9+
afferentcoupling.cpp
10+
modulemetrics.cpp)
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#ifndef CC_CPP_MODULE_METRICS_TEST_A1
2+
#define CC_CPP_MODULE_METRICS_TEST_A1
3+
4+
#include "./a2.h"
5+
6+
namespace CC_CPP_MODULE_METRICS_TEST
7+
{
8+
class A1 {
9+
A2 a2;
10+
};
11+
}
12+
13+
#endif
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#ifndef CC_CPP_MODULE_METRICS_TEST_A2
2+
#define CC_CPP_MODULE_METRICS_TEST_A2
3+
4+
#include "../module_b/b1.h"
5+
6+
namespace CC_CPP_MODULE_METRICS_TEST
7+
{
8+
class A2 {
9+
B1 b1;
10+
};
11+
}
12+
13+
#endif
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#ifndef CC_CPP_MODULE_METRICS_TEST_B1
2+
#define CC_CPP_MODULE_METRICS_TEST_B1
3+
4+
#include "./b2.h"
5+
6+
namespace CC_CPP_MODULE_METRICS_TEST
7+
{
8+
class B1 {
9+
B2 b2;
10+
};
11+
}
12+
13+
#endif

0 commit comments

Comments
 (0)