diff --git a/plugins/cpp/model/CMakeLists.txt b/plugins/cpp/model/CMakeLists.txt index 3e3d76ab8..d4a145bed 100644 --- a/plugins/cpp/model/CMakeLists.txt +++ b/plugins/cpp/model/CMakeLists.txt @@ -15,7 +15,8 @@ set(ODB_SOURCES include/model/cppmacro.h include/model/cppmacroexpansion.h include/model/cppedge.h - include/model/cppdoccomment.h) + include/model/cppdoccomment.h + include/model/cpptypedependency.h) generate_odb_files("${ODB_SOURCES}") diff --git a/plugins/cpp/model/include/model/cppfunction.h b/plugins/cpp/model/include/model/cppfunction.h index 81eadfd52..c136278a9 100644 --- a/plugins/cpp/model/include/model/cppfunction.h +++ b/plugins/cpp/model/include/model/cppfunction.h @@ -1,6 +1,7 @@ #ifndef CC_MODEL_CPPFUNCTION_H #define CC_MODEL_CPPFUNCTION_H +#include #include #include "cppentity.h" @@ -23,6 +24,10 @@ struct CppFunction : CppTypedEntity unsigned int bumpiness; unsigned int statementCount; + // Hash of the record (e.g. class or struct) in which this function is declared + // recordHash = 0 means this is a global function + std::uint64_t recordHash = 0; + std::string toString() const { return std::string("CppFunction") diff --git a/plugins/cpp/model/include/model/cpptypedependency.h b/plugins/cpp/model/include/model/cpptypedependency.h new file mode 100644 index 000000000..d7ebe6ad2 --- /dev/null +++ b/plugins/cpp/model/include/model/cpptypedependency.h @@ -0,0 +1,126 @@ +#ifndef CC_MODEL_CPPTYPEDEPENDENCY_H +#define CC_MODEL_CPPTYPEDEPENDENCY_H + +#include +#include +#include +#include +#include +#include + +namespace cc +{ +namespace model +{ + +#pragma db object +struct CppTypeDependency +{ + #pragma db id auto + std::uint64_t id; + + #pragma db not_null + std::uint64_t entityHash; + + #pragma db not_null + std::uint64_t dependencyHash; + + std::string toString() const + { + return std::string("CppTypeDependency") + .append("\nid = ").append(std::to_string(id)) + .append("\nentityHash = ").append(std::to_string(entityHash)) + .append("\ndependencyHash = ").append(std::to_string(dependencyHash)); + } + +#pragma db index member(entityHash) +#pragma db index member(dependencyHash) +}; + +typedef std::shared_ptr CppTypeDependencyPtr; + +#pragma db view \ + object(CppTypeDependency) \ + object(CppAstNode = EntityAstNode : CppTypeDependency::entityHash == EntityAstNode::entityHash \ + && EntityAstNode::astType == cc::model::CppAstNode::AstType::Definition) \ + object(File = EntityFile : EntityAstNode::location.file == EntityFile::id) \ + object(CppAstNode = DependencyAstNode : CppTypeDependency::dependencyHash == DependencyAstNode::entityHash \ + && DependencyAstNode::astType == cc::model::CppAstNode::AstType::Definition) \ + object(File = DependencyFile : DependencyAstNode::location.file == DependencyFile::id) +struct CppTypeDependencyPathView +{ + #pragma db column(CppTypeDependency::entityHash) + std::size_t entityHash; + + #pragma db column(CppTypeDependency::dependencyHash) + std::size_t dependencyHash; + + #pragma db column(EntityFile::path) + std::string entityPath; + + #pragma db column(DependencyFile::path) + std::string dependencyPath; +}; + +#pragma db view \ + object(CppTypeDependency) \ + object(CppAstNode = EntityAstNode : CppTypeDependency::entityHash == EntityAstNode::entityHash \ + && EntityAstNode::astType == cc::model::CppAstNode::AstType::Definition) \ + object(File = EntityFile : EntityAstNode::location.file == EntityFile::id) \ + object(CppAstNode = DependencyAstNode : CppTypeDependency::dependencyHash == DependencyAstNode::entityHash \ + && DependencyAstNode::astType == cc::model::CppAstNode::AstType::Definition) \ + object(File = DependencyFile : DependencyAstNode::location.file == DependencyFile::id) +struct CppTypeDependency_Count +{ + #pragma db column("count(" + CppTypeDependency::id + ")") + std::size_t count; +}; + +#pragma db view \ + object(CppTypeDependency) \ + object(CppAstNode = EntityAstNode : CppTypeDependency::entityHash == EntityAstNode::entityHash \ + && EntityAstNode::astType == cc::model::CppAstNode::AstType::Definition) \ + object(File = EntityFile : EntityAstNode::location.file == EntityFile::id) \ + object(CppAstNode = DependencyAstNode : CppTypeDependency::dependencyHash == DependencyAstNode::entityHash \ + && DependencyAstNode::astType == cc::model::CppAstNode::AstType::Definition) \ + object(File = DependencyFile : DependencyAstNode::location.file == DependencyFile::id) +struct CppTypeDependency_Distinct_D_Count +{ + #pragma db column("count(distinct" + CppTypeDependency::dependencyHash + ")") + std::size_t count; +}; + +#pragma db view \ + object(CppTypeDependency) \ + object(CppAstNode = EntityAstNode : CppTypeDependency::entityHash == EntityAstNode::entityHash \ + && EntityAstNode::astType == cc::model::CppAstNode::AstType::Definition) \ + object(File = EntityFile : EntityAstNode::location.file == EntityFile::id) \ + object(CppAstNode = DependencyAstNode : CppTypeDependency::dependencyHash == DependencyAstNode::entityHash \ + && DependencyAstNode::astType == cc::model::CppAstNode::AstType::Definition) \ + object(File = DependencyFile : DependencyAstNode::location.file == DependencyFile::id) +struct CppTypeDependency_Distinct_E_Count +{ + #pragma db column("count(distinct" + CppTypeDependency::entityHash + ")") + std::size_t count; +}; + +#pragma db view \ + object(CppTypeDependency) +struct CppTypeDependency_Efferent_Count +{ + #pragma db column("count(distinct" + CppTypeDependency::dependencyHash + ")") + std::size_t count; +}; + +#pragma db view \ + object(CppTypeDependency) +struct CppTypeDependency_Afferent_Count +{ + #pragma db column("count(distinct" + CppTypeDependency::entityHash + ")") + std::size_t count; +}; + +} // model +} // cc + +#endif // CC_MODEL_CPPTYPEDEPENDENCY_H diff --git a/plugins/cpp/parser/src/clangastvisitor.h b/plugins/cpp/parser/src/clangastvisitor.h index 9849f785b..c0951f2d3 100644 --- a/plugins/cpp/parser/src/clangastvisitor.h +++ b/plugins/cpp/parser/src/clangastvisitor.h @@ -34,6 +34,8 @@ #include #include #include +#include +#include #include #include @@ -129,6 +131,7 @@ class ClangASTVisitor : public clang::RecursiveASTVisitor util::persistAll(_friends, _ctx.db); util::persistAll(_functions, _ctx.db); util::persistAll(_relations, _ctx.db); + util::persistAll(_typeDependencies, _ctx.db); }); } @@ -571,6 +574,27 @@ class ClangASTVisitor : public clang::RecursiveASTVisitor _locToTypeLoc[tl_.getBeginLoc().getRawEncoding()] = astNode; + //--- CppTypeDependency ---// + std::uint64_t typeHash = 0; + if (!_typeStack.empty()) + { + typeHash = _typeStack.top()->entityHash; + } + + if (typeHash == 0 && !_functionStack.empty()) + { + typeHash = _functionStack.top()->recordHash; + } + + if (typeHash != 0 && typeHash != astNode->entityHash) + { + model::CppTypeDependencyPtr td = std::make_shared(); + _typeDependencies.push_back(td); + + td->entityHash = typeHash; + td->dependencyHash = astNode->entityHash; + } + return true; } @@ -913,6 +937,11 @@ class ClangASTVisitor : public clang::RecursiveASTVisitor clang::CXXMethodDecl* md = llvm::dyn_cast(fn_); if (md) { + if (const clang::CXXRecordDecl* parent = md->getParent()) + { + cppFunction->recordHash = util::fnvHash(getUSR(parent)); + } + if (md->isVirtual()) cppFunction->tags.insert(model::Tag::Virtual); @@ -1837,6 +1866,7 @@ class ClangASTVisitor : public clang::RecursiveASTVisitor std::vector _inheritances; std::vector _friends; std::vector _relations; + std::vector _typeDependencies; // TODO: Maybe we don't even need a stack, if functions can't be nested. // Check lambda. diff --git a/plugins/cpp_metrics/model/CMakeLists.txt b/plugins/cpp_metrics/model/CMakeLists.txt index 21a812fc2..ca30f7c5a 100644 --- a/plugins/cpp_metrics/model/CMakeLists.txt +++ b/plugins/cpp_metrics/model/CMakeLists.txt @@ -5,8 +5,7 @@ include_directories( set(ODB_SOURCES include/model/cppastnodemetrics.h include/model/cppcohesionmetrics.h - include/model/cppfilemetrics.h - include/model/cpptypedependencymetrics.h) + include/model/cppfilemetrics.h) generate_odb_files("${ODB_SOURCES}" "cpp") diff --git a/plugins/cpp_metrics/model/include/model/cpptypedependencymetrics.h b/plugins/cpp_metrics/model/include/model/cpptypedependencymetrics.h deleted file mode 100644 index 926eb4bba..000000000 --- a/plugins/cpp_metrics/model/include/model/cpptypedependencymetrics.h +++ /dev/null @@ -1,100 +0,0 @@ -#ifndef CC_MODEL_CPPTYPEDEPENDENCYMETRICS_H -#define CC_MODEL_CPPTYPEDEPENDENCYMETRICS_H - -#include -#include -#include -#include -#include -#include - -namespace cc -{ -namespace model -{ - -#pragma db object -struct CppTypeDependencyMetrics -{ - #pragma db id auto - std::uint64_t id; - - #pragma db not_null - std::uint64_t entityHash; - - #pragma db not_null - std::uint64_t dependencyHash; - -#pragma db index member(entityHash) -#pragma db index member(dependencyHash) -}; - -#pragma db view \ - object(CppTypeDependencyMetrics) \ - object(CppAstNode = EntityAstNode : CppTypeDependencyMetrics::entityHash == EntityAstNode::entityHash \ - && EntityAstNode::astType == cc::model::CppAstNode::AstType::Definition) \ - object(File = EntityFile : EntityAstNode::location.file == EntityFile::id) \ - object(CppAstNode = DependencyAstNode : CppTypeDependencyMetrics::dependencyHash == DependencyAstNode::entityHash \ - && DependencyAstNode::astType == cc::model::CppAstNode::AstType::Definition) \ - object(File = DependencyFile : DependencyAstNode::location.file == DependencyFile::id) -struct CppTypeDependencyMetricsPathView -{ - #pragma db column(CppTypeDependencyMetrics::entityHash) - std::size_t entityHash; - - #pragma db column(CppTypeDependencyMetrics::dependencyHash) - std::size_t dependencyHash; - - #pragma db column(EntityFile::path) - std::string entityPath; - - #pragma db column(DependencyFile::path) - std::string dependencyPath; -}; - -#pragma db view \ - object(CppTypeDependencyMetrics) \ - object(CppAstNode = EntityAstNode : CppTypeDependencyMetrics::entityHash == EntityAstNode::entityHash \ - && EntityAstNode::astType == cc::model::CppAstNode::AstType::Definition) \ - object(File = EntityFile : EntityAstNode::location.file == EntityFile::id) \ - object(CppAstNode = DependencyAstNode : CppTypeDependencyMetrics::dependencyHash == DependencyAstNode::entityHash \ - && DependencyAstNode::astType == cc::model::CppAstNode::AstType::Definition) \ - object(File = DependencyFile : DependencyAstNode::location.file == DependencyFile::id) -struct CppTypeDependencyMetrics_Count -{ - #pragma db column("count(" + CppTypeDependencyMetrics::id + ")") - std::size_t count; -}; - -#pragma db view \ - object(CppTypeDependencyMetrics) \ - object(CppAstNode = EntityAstNode : CppTypeDependencyMetrics::entityHash == EntityAstNode::entityHash \ - && EntityAstNode::astType == cc::model::CppAstNode::AstType::Definition) \ - object(File = EntityFile : EntityAstNode::location.file == EntityFile::id) \ - object(CppAstNode = DependencyAstNode : CppTypeDependencyMetrics::dependencyHash == DependencyAstNode::entityHash \ - && DependencyAstNode::astType == cc::model::CppAstNode::AstType::Definition) \ - object(File = DependencyFile : DependencyAstNode::location.file == DependencyFile::id) -struct CppTypeDependencyMetrics_Distinct_D_Count -{ - #pragma db column("count(distinct" + CppTypeDependencyMetrics::dependencyHash + ")") - std::size_t count; -}; - -#pragma db view \ - object(CppTypeDependencyMetrics) \ - object(CppAstNode = EntityAstNode : CppTypeDependencyMetrics::entityHash == EntityAstNode::entityHash \ - && EntityAstNode::astType == cc::model::CppAstNode::AstType::Definition) \ - object(File = EntityFile : EntityAstNode::location.file == EntityFile::id) \ - object(CppAstNode = DependencyAstNode : CppTypeDependencyMetrics::dependencyHash == DependencyAstNode::entityHash \ - && DependencyAstNode::astType == cc::model::CppAstNode::AstType::Definition) \ - object(File = DependencyFile : DependencyAstNode::location.file == DependencyFile::id) -struct CppTypeDependencyMetrics_Distinct_E_Count -{ - #pragma db column("count(distinct" + CppTypeDependencyMetrics::entityHash + ")") - std::size_t count; -}; - -} // model -} // cc - -#endif // CC_MODEL_CPPTYPEDEPENDENCYMETRICS_H diff --git a/plugins/cpp_metrics/parser/src/cppmetricsparser.cpp b/plugins/cpp_metrics/parser/src/cppmetricsparser.cpp index 7f0d7bac0..188762cda 100644 --- a/plugins/cpp_metrics/parser/src/cppmetricsparser.cpp +++ b/plugins/cpp_metrics/parser/src/cppmetricsparser.cpp @@ -10,8 +10,8 @@ #include #include #include -#include -#include +#include +#include #include #include #include @@ -422,71 +422,19 @@ void CppMetricsParser::efferentTypeLevel() { util::OdbTransaction{_ctx.db}([&, this] { - typedef odb::query MemTypeQuery; - typedef odb::query InheritanceQuery; - typedef odb::query FuncQuery; + typedef odb::query TypeDependencyQuery; + typedef model::CppTypeDependency_Efferent_Count TypeDependencyResult; - std::set dependentTypes; for (const model::CohesionCppRecordView& type : tasks) { - dependentTypes.clear(); - - // Count parent types - auto inheritanceView = _ctx.db->query( - InheritanceQuery::derived == type.entityHash); - auto inheritanceCount = _ctx.db->query_value( - 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); - } - } - } + const TypeDependencyResult result = _ctx.db->query_value( + TypeDependencyQuery::entityHash == type.entityHash); model::CppAstNodeMetrics metric; metric.astNodeId = type.astNodeId; metric.type = model::CppAstNodeMetrics::Type::EFFERENT_TYPE; - metric.value = inheritanceCount.count + dependentTypes.size(); + metric.value = result.count; _ctx.db->persist(metric); - - auto typeRelationInserter = [this](const std::uint64_t& entityHash, const std::uint64_t& dependencyHash) - { - model::CppTypeDependencyMetrics relation; - relation.entityHash = entityHash; - relation.dependencyHash = dependencyHash; - _ctx.db->persist(relation); - }; - - // Insert type dependency relations - for (const std::uint64_t& d : dependentTypes) { - typeRelationInserter(type.entityHash, d); - } - - // Insert inheritance relations - for (const model::CppInheritance& d : inheritanceView) { - typeRelationInserter(type.entityHash, d.base); - } } }); }); @@ -502,73 +450,18 @@ void CppMetricsParser::afferentTypeLevel() { util::OdbTransaction{_ctx.db}([&, this] { - typedef odb::query AstQuery; - typedef odb::query InheritanceQuery; - typedef odb::query MemTypeQuery; - typedef odb::result AstResult; - typedef odb::result MemTypeAstResult; + typedef odb::query TypeDependencyQuery; + typedef model::CppTypeDependency_Afferent_Count TypeDependencyResult; - std::set dependentTypes; for (const model::CohesionCppRecordView& type : tasks) { - dependentTypes.clear(); - - // Find derived types - for (const model::CppInheritance& inheritance : _ctx.db->query( - InheritanceQuery::base == type.entityHash)) - { - dependentTypes.insert(inheritance.derived); - } - - // Find usages of the type - for (const model::CppAstNode& usage : _ctx.db->query( - AstQuery::entityHash == type.entityHash && - AstQuery::location.range.end.line != model::Position::npos)) - { - // Check if usage is in class member function or attribute - MemTypeAstResult memberNode = _ctx.db->query( - AstQuery::symbolType.in(model::CppAstNode::SymbolType::Function, model::CppAstNode::SymbolType::Variable) && - AstQuery::astType.in(model::CppAstNode::AstType::Definition, model::CppAstNode::AstType::Declaration) && - AstQuery::location.file == usage.location.file.object_id() && - AstQuery::location.range.start.line <= usage.location.range.start.line && - AstQuery::location.range.end.line >= usage.location.range.end.line && - MemTypeQuery::typeHash != usage.entityHash); - - if (!memberNode.empty()) - { - dependentTypes.insert(memberNode.begin()->typeHash); - } else { - // The usage can be in a member function defined outside of the class definition - // E.g. void ClassName::foo() { A a; } - // ^ usage here - - // Find parent function - AstResult parentFunction = _ctx.db->query( - AstQuery::symbolType == model::CppAstNode::SymbolType::Function && - AstQuery::astType == model::CppAstNode::AstType::Definition && - AstQuery::location.file == usage.location.file.object_id() && - AstQuery::location.range.start.line <= usage.location.range.start.line && - AstQuery::location.range.end.line >= usage.location.range.end.line); - - if (!parentFunction.empty()) - { - // Find if the function is a member function of a class - MemTypeAstResult memberFunction = _ctx.db->query( - AstQuery::entityHash == parentFunction.begin()->entityHash && - MemTypeQuery::typeHash != usage.entityHash); - - if (!memberFunction.empty()) - { - dependentTypes.insert(memberFunction.begin()->typeHash); - } - } - } - } + const TypeDependencyResult result = _ctx.db->query_value( + TypeDependencyQuery::dependencyHash == type.entityHash); model::CppAstNodeMetrics metric; metric.astNodeId = type.astNodeId; metric.type = model::CppAstNodeMetrics::Type::AFFERENT_TYPE; - metric.value = dependentTypes.size(); + metric.value = result.count; _ctx.db->persist(metric); } }); @@ -596,12 +489,12 @@ void CppMetricsParser::efferentModuleLevel() { util::OdbTransaction{_ctx.db}([&, this] { - typedef odb::query TypeDependencyQuery; - typedef model::CppTypeDependencyMetrics_Distinct_D_Count TypeDependencyResult; + typedef odb::query TypeDependencyQuery; + typedef model::CppTypeDependency_Distinct_D_Count TypeDependencyResult; for (const model::File& file : tasks) { - TypeDependencyResult types = _ctx.db->query_value( + TypeDependencyResult types = _ctx.db->query_value( TypeDependencyQuery::EntityFile::path.like(file.path + '%') && !TypeDependencyQuery::DependencyFile::path.like(file.path + '%')); @@ -625,12 +518,12 @@ void CppMetricsParser::afferentModuleLevel() { util::OdbTransaction{_ctx.db}([&, this] { - typedef odb::query TypeDependencyQuery; - typedef model::CppTypeDependencyMetrics_Distinct_E_Count TypeDependencyResult; + typedef odb::query TypeDependencyQuery; + typedef model::CppTypeDependency_Distinct_E_Count TypeDependencyResult; for (const model::File& file : tasks) { - TypeDependencyResult types = _ctx.db->query_value( + TypeDependencyResult types = _ctx.db->query_value( !TypeDependencyQuery::EntityFile::path.like(file.path + '%') && TypeDependencyQuery::DependencyFile::path.like(file.path + '%')); @@ -657,14 +550,14 @@ void CppMetricsParser::relationalCohesionModuleLevel() { util::OdbTransaction{_ctx.db}([&, this] { - typedef odb::query TypeDependencyQuery; - typedef model::CppTypeDependencyMetrics_Count TypeDependencyResult; + typedef odb::query TypeDependencyQuery; + typedef model::CppTypeDependency_Count TypeDependencyResult; typedef odb::query RecordQuery; typedef model::CohesionCppRecord_Count RecordResult; for (const model::File& file : tasks) { - TypeDependencyResult dependencies = _ctx.db->query_value( + TypeDependencyResult dependencies = _ctx.db->query_value( TypeDependencyQuery::EntityFile::path.like(file.path + '%') && TypeDependencyQuery::DependencyFile::path.like(file.path + '%')); diff --git a/plugins/cpp_metrics/test/sources/parser/CMakeLists.txt b/plugins/cpp_metrics/test/sources/parser/CMakeLists.txt index 88ccb5fe4..af6559570 100644 --- a/plugins/cpp_metrics/test/sources/parser/CMakeLists.txt +++ b/plugins/cpp_metrics/test/sources/parser/CMakeLists.txt @@ -6,5 +6,6 @@ add_library(CppMetricsTestProject STATIC typemccabe.cpp lackofcohesion.cpp bumpyroad.cpp + efferentcoupling.cpp afferentcoupling.cpp modulemetrics.cpp) diff --git a/plugins/cpp_metrics/test/sources/parser/afferentcoupling.cpp b/plugins/cpp_metrics/test/sources/parser/afferentcoupling.cpp index 61601122e..9ec43178d 100644 --- a/plugins/cpp_metrics/test/sources/parser/afferentcoupling.cpp +++ b/plugins/cpp_metrics/test/sources/parser/afferentcoupling.cpp @@ -1,6 +1,8 @@ #include #include +namespace CC_CPP_AFFERENT_COUPLING_METRICS_TEST +{ // Member types class A {}; class A_D { @@ -174,3 +176,4 @@ class H2_D2 { } }; // ========== +} diff --git a/plugins/cpp_metrics/test/sources/parser/efferentcoupling.cpp b/plugins/cpp_metrics/test/sources/parser/efferentcoupling.cpp new file mode 100644 index 000000000..2562b45fc --- /dev/null +++ b/plugins/cpp_metrics/test/sources/parser/efferentcoupling.cpp @@ -0,0 +1,195 @@ +#include +#include +#include + +namespace CC_CPP_EFFERENT_COUPLING_METRICS_TEST +{ +// Member types +class A {}; + +class A1 { + int a; + bool b; + + void foo(char* c); +}; + +class A2 { + A a; +}; + +class A3 { + A* a; +}; + +class A4 { + A& a; +}; + +class A5 { + std::vector a; +}; + +class A6 { + std::unique_ptr a; +}; + +class A7 { + int i; + A a; +}; + +// ========== + +// Function parameters +class B { + void foo(A a); +}; + +class B2 { + void foo(A* a); +}; + +class B3 { + void foo(A& a); +}; + +class B4 { + void foo(std::vector& a); +}; + +class B5 { + void foo(std::unique_ptr& a); +}; + +class B6 { + void foo(int, bool, A* a); +}; + +class B7 { + void foo(int, bool); + void foo(int, bool, A* a); +}; + +// ========== + +// Function local variables +class C { + void foo() { A a; } +}; + +class C2 { + void foo() { A* a; } +}; + +class C3 { + void foo() { std::vector a; } +}; + +class C4 { + void foo() { auto a = A(); } +}; + +class C5 { + void foo(); +}; + +void C5::foo() { A a; } + +class C6 { + void foo(); +}; + +void C6::foo() { std::unique_ptr a; } +// ========== + +// Function return types +class D { + A foo() { return A(); }; +}; + +class D2 { + A* foo() { return nullptr; }; +}; + +class D3 { + std::vector foo(); +}; + +// Inheritance +class E : public A {}; +// ========== + +// Multiple usage of the same type +class F : public A { + A* a; + + void foo() + { + A a; + } + + void bar(std::vector a_vec); +}; + +class F2 { + std::unique_ptr a; + + A foo(); +}; + +A F2::foo() { return A(); } + +// ========== + +// Depends on multiple types +class G { + A a; + B b; +}; + +class G2 : public A, public B {}; + +class G3 { + A foo() { return A(); }; + + std::vector b; +}; + +class G4 : public A { + A a; + + void foo(A& a); + + void bar() + { + B b; + } +}; + +class G5 { + void foo(); +}; + +void G5::foo() +{ + auto a = A(); + B b; +} + +class G6 { + A a; + + void foo(std::vector&, B b); +}; + +class G7 { + A foo() { return A(); } + B bar() { return B(); } +}; + +class G8 { + std::unordered_map map; +}; +// ========== +} diff --git a/plugins/cpp_metrics/test/src/cppmetricsparsertest.cpp b/plugins/cpp_metrics/test/src/cppmetricsparsertest.cpp index fb9a18a51..d8ba5776d 100644 --- a/plugins/cpp_metrics/test/src/cppmetricsparsertest.cpp +++ b/plugins/cpp_metrics/test/src/cppmetricsparsertest.cpp @@ -272,6 +272,71 @@ INSTANTIATE_TEST_SUITE_P( ::testing::ValuesIn(paramLackOfCohesion) ); +// Efferent coupling + +class ParameterizedEfferentCouplingTest + : public CppMetricsParserTest, + public ::testing::WithParamInterface +{}; + +std::vector paramEfferent = { + {"CC_CPP_EFFERENT_COUPLING_METRICS_TEST::A", 0}, + {"CC_CPP_EFFERENT_COUPLING_METRICS_TEST::A1", 0}, + {"CC_CPP_EFFERENT_COUPLING_METRICS_TEST::A2", 1}, + {"CC_CPP_EFFERENT_COUPLING_METRICS_TEST::A3", 1}, + {"CC_CPP_EFFERENT_COUPLING_METRICS_TEST::A4", 1}, + {"CC_CPP_EFFERENT_COUPLING_METRICS_TEST::A5", 1}, + {"CC_CPP_EFFERENT_COUPLING_METRICS_TEST::A6", 1}, + {"CC_CPP_EFFERENT_COUPLING_METRICS_TEST::A7", 1}, + {"CC_CPP_EFFERENT_COUPLING_METRICS_TEST::B", 1}, + {"CC_CPP_EFFERENT_COUPLING_METRICS_TEST::B2", 1}, + {"CC_CPP_EFFERENT_COUPLING_METRICS_TEST::B3", 1}, + {"CC_CPP_EFFERENT_COUPLING_METRICS_TEST::B4", 1}, + {"CC_CPP_EFFERENT_COUPLING_METRICS_TEST::B5", 1}, + {"CC_CPP_EFFERENT_COUPLING_METRICS_TEST::B6", 1}, + {"CC_CPP_EFFERENT_COUPLING_METRICS_TEST::B7", 1}, + {"CC_CPP_EFFERENT_COUPLING_METRICS_TEST::C", 1}, + {"CC_CPP_EFFERENT_COUPLING_METRICS_TEST::C2", 1}, + {"CC_CPP_EFFERENT_COUPLING_METRICS_TEST::C3", 1}, + {"CC_CPP_EFFERENT_COUPLING_METRICS_TEST::C4", 1}, + {"CC_CPP_EFFERENT_COUPLING_METRICS_TEST::C5", 1}, + {"CC_CPP_EFFERENT_COUPLING_METRICS_TEST::C6", 1}, + {"CC_CPP_EFFERENT_COUPLING_METRICS_TEST::D", 1}, + {"CC_CPP_EFFERENT_COUPLING_METRICS_TEST::D2", 1}, + {"CC_CPP_EFFERENT_COUPLING_METRICS_TEST::D3", 1}, + {"CC_CPP_EFFERENT_COUPLING_METRICS_TEST::E", 1}, + {"CC_CPP_EFFERENT_COUPLING_METRICS_TEST::F", 1}, + {"CC_CPP_EFFERENT_COUPLING_METRICS_TEST::F2", 1}, + {"CC_CPP_EFFERENT_COUPLING_METRICS_TEST::G", 2}, + {"CC_CPP_EFFERENT_COUPLING_METRICS_TEST::G2", 2}, + {"CC_CPP_EFFERENT_COUPLING_METRICS_TEST::G3", 2}, + {"CC_CPP_EFFERENT_COUPLING_METRICS_TEST::G4", 2}, + {"CC_CPP_EFFERENT_COUPLING_METRICS_TEST::G5", 2}, + {"CC_CPP_EFFERENT_COUPLING_METRICS_TEST::G6", 2}, + {"CC_CPP_EFFERENT_COUPLING_METRICS_TEST::G7", 2}, + {"CC_CPP_EFFERENT_COUPLING_METRICS_TEST::G8", 2}, +}; + +TEST_P(ParameterizedEfferentCouplingTest, TypeEfferentTest) { + _transaction([&, this]() { + + const auto record = _db->query_value( + odb::query::qualifiedName == GetParam().first); + + const auto metric = _db->query_value( + odb::query::astNodeId == record.astNodeId && + odb::query::type == model::CppAstNodeMetrics::EFFERENT_TYPE); + + EXPECT_EQ(GetParam().second, metric.value); + }); +} + +INSTANTIATE_TEST_SUITE_P( + ParameterizedEfferentCouplingTestSuite, + ParameterizedEfferentCouplingTest, + ::testing::ValuesIn(paramEfferent) +); + // Afferent coupling class ParameterizedAfferentCouplingTest @@ -280,27 +345,27 @@ class ParameterizedAfferentCouplingTest {}; std::vector paramAfferent = { - {"A", 1}, - {"A2", 1}, - {"A3", 1}, - {"A4", 1}, - {"A5", 1}, - {"B", 1}, - {"B2", 1}, - {"B3", 1}, - {"B4", 1}, - {"B5", 1}, - {"B6", 1}, - {"B7", 1}, - {"B8", 1}, - {"C", 1}, - {"C2", 1}, - {"C3", 1}, - {"E", 1}, - {"F", 1}, - {"G", 1}, - {"H", 2}, - {"H2", 2}, + {"CC_CPP_AFFERENT_COUPLING_METRICS_TEST::A", 1}, + {"CC_CPP_AFFERENT_COUPLING_METRICS_TEST::A2", 1}, + {"CC_CPP_AFFERENT_COUPLING_METRICS_TEST::A3", 1}, + {"CC_CPP_AFFERENT_COUPLING_METRICS_TEST::A4", 1}, + {"CC_CPP_AFFERENT_COUPLING_METRICS_TEST::A5", 1}, + {"CC_CPP_AFFERENT_COUPLING_METRICS_TEST::B", 1}, + {"CC_CPP_AFFERENT_COUPLING_METRICS_TEST::B2", 1}, + {"CC_CPP_AFFERENT_COUPLING_METRICS_TEST::B3", 1}, + {"CC_CPP_AFFERENT_COUPLING_METRICS_TEST::B4", 1}, + {"CC_CPP_AFFERENT_COUPLING_METRICS_TEST::B5", 1}, + {"CC_CPP_AFFERENT_COUPLING_METRICS_TEST::B6", 1}, + {"CC_CPP_AFFERENT_COUPLING_METRICS_TEST::B7", 1}, + {"CC_CPP_AFFERENT_COUPLING_METRICS_TEST::B8", 1}, + {"CC_CPP_AFFERENT_COUPLING_METRICS_TEST::C", 1}, + {"CC_CPP_AFFERENT_COUPLING_METRICS_TEST::C2", 1}, + {"CC_CPP_AFFERENT_COUPLING_METRICS_TEST::C3", 1}, + {"CC_CPP_AFFERENT_COUPLING_METRICS_TEST::E", 1}, + {"CC_CPP_AFFERENT_COUPLING_METRICS_TEST::F", 1}, + {"CC_CPP_AFFERENT_COUPLING_METRICS_TEST::G", 1}, + {"CC_CPP_AFFERENT_COUPLING_METRICS_TEST::H", 2}, + {"CC_CPP_AFFERENT_COUPLING_METRICS_TEST::H2", 2}, }; TEST_P(ParameterizedAfferentCouplingTest, TypeAfferentTest) { @@ -425,4 +490,4 @@ INSTANTIATE_TEST_SUITE_P( ParameterizedRelationalCohesionTestSuite, ParameterizedRelationalCohesionTest, ::testing::ValuesIn(paramRelationalCohesion) -); \ No newline at end of file +);