From 0299025f9dd5672f5d60ffe21b0de040f060b46e Mon Sep 17 00:00:00 2001 From: Klein Kristof Date: Wed, 8 May 2024 09:59:50 +0200 Subject: [PATCH 1/3] Added calculation for relational cohesion --- plugins/cpp_metrics/model/CMakeLists.txt | 5 +- .../include/model/cpprelationalcohesion.h | 111 ++++++++++ .../cppmetricsparser/cppmetricsparser.h | 2 + .../parser/src/cppmetricsparser.cpp | 205 ++++++++++++++++++ 4 files changed, 321 insertions(+), 2 deletions(-) create mode 100644 plugins/cpp_metrics/model/include/model/cpprelationalcohesion.h diff --git a/plugins/cpp_metrics/model/CMakeLists.txt b/plugins/cpp_metrics/model/CMakeLists.txt index 38d8ca343..580be0d66 100644 --- a/plugins/cpp_metrics/model/CMakeLists.txt +++ b/plugins/cpp_metrics/model/CMakeLists.txt @@ -5,11 +5,12 @@ include_directories( set(ODB_SOURCES include/model/cppastnodemetrics.h include/model/cppcohesionmetrics.h - include/model/cppfilemetrics.h) + include/model/cppfilemetrics.h + include/model/cpprelationalcohesion.h) generate_odb_files("${ODB_SOURCES}" "cpp") add_odb_library(cppmetricsmodel ${ODB_CXX_SOURCES}) target_link_libraries(cppmetricsmodel cppmodel) -install_sql() \ No newline at end of file +install_sql() diff --git a/plugins/cpp_metrics/model/include/model/cpprelationalcohesion.h b/plugins/cpp_metrics/model/include/model/cpprelationalcohesion.h new file mode 100644 index 000000000..654cd3f7f --- /dev/null +++ b/plugins/cpp_metrics/model/include/model/cpprelationalcohesion.h @@ -0,0 +1,111 @@ +#ifndef CC_MODEL_CPPRELATIONALCOHESION_H +#define CC_MODEL_CPPRELATIONALCOHESION_H + +#include +#include +#include +#include +#include + +namespace cc +{ + namespace model + { + + #pragma db view \ + object(File) + struct RelationalCohesionFileView + { + #pragma db column(File::path) + std::string filePath; + + #pragma db column(File::type) + std::string fileType; + + }; + + #pragma db view \ + object(CppRecord) \ + object(CppAstNode : CppRecord::astNodeId == CppAstNode::id) \ + object(File : CppAstNode::location.file) \ + object(CppMemberType : CppMemberType::memberAstNode) + struct RelationalCohesionRecordView + { + #pragma db column(CppEntity::entityHash) + std::size_t entityHash; + + #pragma db column(CppMemberType::typeHash) + std::size_t typeHash; + + #pragma db column(CppEntity::qualifiedName) + std::string qualifiedName; + + #pragma db column(CppEntity::astNodeId) + CppAstNodeId astNodeId; + + #pragma db column(File::path) + std::string filePath; + }; + + #pragma db view \ + object(CppFunction) \ + object(CppAstNode : CppFunction::astNodeId == CppAstNode::id) \ + object(File : CppAstNode::location.file) + struct RelationalCohesionFunctionView + { + #pragma db column(CppEntity::entityHash) + std::size_t entityHash; + + #pragma db column(CppTypedEntity::typeHash) + std::size_t returnType; + + #pragma db column(File::path) + std::string filePath; + }; + + #pragma db view \ + object(CppEntity) \ + object(CppVariable = Parameters : CppFunction::parameters) \ + object(CppAstNode : CppAstNode.id == CppEntity.astNodeId) \ + object(File : CppAstNode::location.file) + struct RelationalCohessionFunctionParameterView + { + #pragma db column(Parameters::typeHash) + std::size_t typeHash; + + #pragma db column(File::path) + std::string filePath; + }; + + + #pragma db view \ + object(CppVariable = Locals : CppFunction::locals) \ + object(CppAstNode : CppAstNode.id == CppEntity.astNodeId) \ + object(File : CppAstNode::location.file) + struct RelationalCohessionFunctionLocalView + { + #pragma db column(Locals::typeHash) + std::size_t typeHash; + + #pragma db column(File::path) + std::string filePath; + }; + + #pragma db view \ + object(CppVariable) \ + object(CppAstNode : CppAstNode.id == CppEntity.astNodeId) \ + object(File : CppAstNode::location.file) + struct RelationalCohesionVariableView + { + #pragma db column(CppVariable::typeHash) + std::size_t typeHash; + + #pragma db column(File::path) + std::string filePath; + + }; + + } +} + +#endif \ No newline at end of file diff --git a/plugins/cpp_metrics/parser/include/cppmetricsparser/cppmetricsparser.h b/plugins/cpp_metrics/parser/include/cppmetricsparser/cppmetricsparser.h index 6dcfb0bc2..e376f467c 100644 --- a/plugins/cpp_metrics/parser/include/cppmetricsparser/cppmetricsparser.h +++ b/plugins/cpp_metrics/parser/include/cppmetricsparser/cppmetricsparser.h @@ -38,6 +38,8 @@ class CppMetricsParser : public AbstractParser // Calculate the lack of cohesion between member variables // and member functions for every type. void lackOfCohesion(); + // Calculate the cohesion within modules + void relationalCohesion(); std::vector _inputPaths; std::unordered_set _fileIdCache; diff --git a/plugins/cpp_metrics/parser/src/cppmetricsparser.cpp b/plugins/cpp_metrics/parser/src/cppmetricsparser.cpp index 7e8269a4d..3a71529c6 100644 --- a/plugins/cpp_metrics/parser/src/cppmetricsparser.cpp +++ b/plugins/cpp_metrics/parser/src/cppmetricsparser.cpp @@ -4,6 +4,8 @@ #include #include #include +#include +#include #include #include @@ -18,6 +20,7 @@ #include #include +#include namespace cc { @@ -141,6 +144,208 @@ void CppMetricsParser::functionMcCabe() }); } +void CppMetricsParser::relationalCohesion() +{ + util::OdbTransaction {_ctx.db} ([&, this] + { + + std::unordered_set filepaths; + std::vector filepathVector; + filepathVector.insert(filepathVector.end(), filepaths.begin(), filepaths.end()); + std::unordered_map> pathsInModule; + std::unordered_map> typesUnderPath; + std::unordered_map> functionsUnderPath; + std::unordered_map typeDefinitionPaths; + + //get the project filepaths + //change this later to only get the required modules + for (const model::RelationalCohesionFileView& file + : _ctx.db->query()) + { + if (cc::util::isRootedUnderAnyOf( _inputPaths, file.filePath) && + file.fileType == "DIR") + { + filepaths.insert(file.filePath); + } + } + + //get what filepaths are contained within a module + for (auto &¤tPath : filepaths) + { + std::vector pathVector; + pathVector.push_back(currentPath); + std::unordered_set pathsFound; + for (auto &&path : filepaths) + { + if (cc::util::isRootedUnderAnyOf(pathVector,path)) + { + pathsFound.insert(path); + } + } + pathsInModule.insert(std::make_pair(currentPath,pathsFound)); + } + + //find types defined under every filepath in the project + for (auto &¤tPath : filepaths) + { + std::unordered_set typesFound; + std::vector pathVector; + pathVector.push_back(currentPath); + for (const model::RelationalCohesionRecordView& record + : _ctx.db->query()) + { + if (cc::util::isRootedUnderAnyOf(pathVector,record.filePath)) + { + typesFound.insert(record.typeHash); + } + } + typesUnderPath.insert(std::make_pair(currentPath,typesFound)); + } + + //save where each type is defined so self relations can be excluded + for (const model::RelationalCohesionRecordView& record + : _ctx.db->query()) + { + typeDefinitionPaths.insert(std::make_pair(record.typeHash,record.filePath)); + } + + //find relations + for (auto &&path : filepaths) + { + std::vector currentModulePaths( + pathsInModule[path].begin(), pathsInModule[path].end() + ); + + uint relationsInModule = 0; //R + std::unordered_set relationsInCurrentFile; + std::unordered_set filesAlreadyChecked; + //select the next module + for (auto &&modulePath : currentModulePaths) + { + std::vector pathVector; + pathVector.push_back(modulePath); + //find the files defined under the current module member + for (const model::RelationalCohesionFileView& file + : _ctx.db->query()) + { + if (file.fileType != "CPP" && + !cc::util::isRootedUnderAnyOf(pathVector,file.filePath) && + filesAlreadyChecked.find(file.filePath) != filesAlreadyChecked.end() + ) + { + continue; + } + filesAlreadyChecked.insert(file.filePath); + relationsInCurrentFile.clear(); + //check function return types + for (const model::RelationalCohesionFunctionView& function + : _ctx.db->query()) + { + if ( + function.filePath == file.filePath && + //check if function is in the current file + typeDefinitionPaths[function.returnType] != function.filePath && + //check for self relation + cc::util::isRootedUnderAnyOf(currentModulePaths,typeDefinitionPaths[function.returnType]) && + //check if return type is defined within the current module + relationsInCurrentFile.find(function.returnType) == relationsInCurrentFile.end() + //check if relation is already found + ) + { + ++relationsInModule; + relationsInCurrentFile.insert(function.returnType); + } + + } + + //check function parameters + for (const model::RelationalCohessionFunctionParameterView& parameter + : _ctx.db->query()) + { + if ( + parameter.filePath == file.filePath && + //check if the parameter is in the current file + typeDefinitionPaths[parameter.typeHash] != parameter.filePath && + //check for self relation + cc::util::isRootedUnderAnyOf(currentModulePaths,typeDefinitionPaths[parameter.typeHash]) && + //check if the type is defined within the current module + relationsInCurrentFile.find(parameter.typeHash) == relationsInCurrentFile.end() + //check if relation is already found + ) + { + ++relationsInModule; + relationsInCurrentFile.insert(parameter.typeHash); + } + + } + + //check function locals + for (const model::RelationalCohessionFunctionLocalView& local + : _ctx.db->query()) + { + if ( + local.filePath == file.filePath && + //check if the local variable is in the current file + typeDefinitionPaths[local.typeHash] != local.filePath && + //check for self relation + cc::util::isRootedUnderAnyOf(currentModulePaths,typeDefinitionPaths[local.typeHash]) && + //check if the type is defined within the current module + relationsInCurrentFile.find(local.typeHash) == relationsInCurrentFile.end() + //check if relation is already found + ) + { + ++relationsInModule; + relationsInCurrentFile.insert(local.typeHash); + } + + } + + //check variables + for (const model::RelationalCohesionVariableView& variable + : _ctx.db->query()) + { + if ( + variable.filePath == file.filePath && + //check if the variable is in the current file + typeDefinitionPaths[variable.typeHash] != variable.filePath && + //check for self relation + cc::util::isRootedUnderAnyOf(currentModulePaths,typeDefinitionPaths[variable.typeHash]) && + //check if the type is defined within the current module + relationsInCurrentFile.find(variable.typeHash) == relationsInCurrentFile.end() + //check if relation is already found + ) + { + ++relationsInModule; + relationsInCurrentFile.insert(variable.typeHash); + } + + } + + } + + } + //calculate relational cohesion for module + //formula: H = (R + 1)/ N + //where H is the relational cohesion value, + //R is the number of relationships internal to the module, + //N is the number of types in the module + + uint numberOfTypesInModule = typesUnderPath[path].size(); //N + + double relationalCohesion = + (static_cast(relationsInModule) + 1.0) / static_cast(numberOfTypesInModule); + + //TODO: persistance + + } + + + + + + }); +} + void CppMetricsParser::lackOfCohesion() { util::OdbTransaction {_ctx.db} ([&, this] From 313d540673b0a8b77b1ccf927b565cbb3e29f276 Mon Sep 17 00:00:00 2001 From: Klein Kristof Date: Wed, 8 May 2024 11:26:49 +0200 Subject: [PATCH 2/3] Fixed an include error --- .../model/include/model/cpprelationalcohesion.h | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/plugins/cpp_metrics/model/include/model/cpprelationalcohesion.h b/plugins/cpp_metrics/model/include/model/cpprelationalcohesion.h index 654cd3f7f..12da4424d 100644 --- a/plugins/cpp_metrics/model/include/model/cpprelationalcohesion.h +++ b/plugins/cpp_metrics/model/include/model/cpprelationalcohesion.h @@ -63,10 +63,12 @@ namespace cc std::string filePath; }; + // object(CppEntity) \ + #pragma db view \ - object(CppEntity) \ + object(CppFunction) \ object(CppVariable = Parameters : CppFunction::parameters) \ - object(CppAstNode : CppAstNode.id == CppEntity.astNodeId) \ + object(CppAstNode : CppAstNode::id == CppFunction::astNodeId) \ object(File : CppAstNode::location.file) struct RelationalCohessionFunctionParameterView { @@ -79,8 +81,9 @@ namespace cc #pragma db view \ + object(CppFunction) \ object(CppVariable = Locals : CppFunction::locals) \ - object(CppAstNode : CppAstNode.id == CppEntity.astNodeId) \ + object(CppAstNode : CppAstNode::id == CppFunction::astNodeId) \ object(File : CppAstNode::location.file) struct RelationalCohessionFunctionLocalView { @@ -93,7 +96,7 @@ namespace cc #pragma db view \ object(CppVariable) \ - object(CppAstNode : CppAstNode.id == CppEntity.astNodeId) \ + object(CppAstNode : CppAstNode::id == CppEntity::astNodeId) \ object(File : CppAstNode::location.file) struct RelationalCohesionVariableView { From 61a1f5fe2912f2abe1c177573b0e7c828b5577af Mon Sep 17 00:00:00 2001 From: Klein Kristof Date: Wed, 15 May 2024 11:06:49 +0200 Subject: [PATCH 3/3] Refactored relational cohesion calculation --- .../model/include/model/cppfilemetrics.h | 4 +- .../include/model/cpprelationalcohesion.h | 3 + .../parser/src/cppmetricsparser.cpp | 290 +++++++++--------- 3 files changed, 145 insertions(+), 152 deletions(-) diff --git a/plugins/cpp_metrics/model/include/model/cppfilemetrics.h b/plugins/cpp_metrics/model/include/model/cppfilemetrics.h index 357eb5cb5..ab462deba 100644 --- a/plugins/cpp_metrics/model/include/model/cppfilemetrics.h +++ b/plugins/cpp_metrics/model/include/model/cppfilemetrics.h @@ -13,7 +13,7 @@ struct CppFileMetrics { enum Type { - PLACEHOLDER + RELATIONAL_COHESION = 1 }; #pragma db id auto @@ -26,7 +26,7 @@ struct CppFileMetrics Type type; #pragma db not_null - unsigned value; + double value; }; } //model diff --git a/plugins/cpp_metrics/model/include/model/cpprelationalcohesion.h b/plugins/cpp_metrics/model/include/model/cpprelationalcohesion.h index 12da4424d..2e236badd 100644 --- a/plugins/cpp_metrics/model/include/model/cpprelationalcohesion.h +++ b/plugins/cpp_metrics/model/include/model/cpprelationalcohesion.h @@ -22,6 +22,9 @@ namespace cc #pragma db column(File::type) std::string fileType; + #pragma db column(File::id) + std::size_t fileId; + }; #pragma db view \ diff --git a/plugins/cpp_metrics/parser/src/cppmetricsparser.cpp b/plugins/cpp_metrics/parser/src/cppmetricsparser.cpp index 3a71529c6..06a3bae0c 100644 --- a/plugins/cpp_metrics/parser/src/cppmetricsparser.cpp +++ b/plugins/cpp_metrics/parser/src/cppmetricsparser.cpp @@ -149,199 +149,188 @@ void CppMetricsParser::relationalCohesion() util::OdbTransaction {_ctx.db} ([&, this] { - std::unordered_set filepaths; - std::vector filepathVector; - filepathVector.insert(filepathVector.end(), filepaths.begin(), filepaths.end()); - std::unordered_map> pathsInModule; - std::unordered_map> typesUnderPath; - std::unordered_map> functionsUnderPath; + std::unordered_set filepaths(_inputPaths.begin(),_inputPaths.end()); std::unordered_map typeDefinitionPaths; + std::unordered_set typesFound; - //get the project filepaths - //change this later to only get the required modules - for (const model::RelationalCohesionFileView& file - : _ctx.db->query()) - { - if (cc::util::isRootedUnderAnyOf( _inputPaths, file.filePath) && - file.fileType == "DIR") - { - filepaths.insert(file.filePath); - } - } - //get what filepaths are contained within a module - for (auto &¤tPath : filepaths) + + //TODO: implement module handling logic + + std::unordered_map moduleIds; + + for (auto &&path : filepaths) { - std::vector pathVector; - pathVector.push_back(currentPath); - std::unordered_set pathsFound; - for (auto &&path : filepaths) + for(const model::RelationalCohesionFileView& file + : _ctx.db->query( + odb::query::query_columns::path.equal(path) + )) { - if (cc::util::isRootedUnderAnyOf(pathVector,path)) - { - pathsFound.insert(path); - } + moduleIds[path] = file.fileId; } - pathsInModule.insert(std::make_pair(currentPath,pathsFound)); } + - //find types defined under every filepath in the project - for (auto &¤tPath : filepaths) + for (auto &&path : filepaths) { - std::unordered_set typesFound; - std::vector pathVector; - pathVector.push_back(currentPath); + + typesFound.clear(); + typeDefinitionPaths.clear(); + //find the types defined in the module for (const model::RelationalCohesionRecordView& record - : _ctx.db->query()) + : _ctx.db->query( + odb::query::query_columns::File::path.like(path + "%") + )) + { + typesFound.insert(record.typeHash); //save types defined inside the module + typeDefinitionPaths.insert(std::make_pair(record.typeHash,record.filePath)); //save where the type is defined to avoid self relation + } + + std::unordered_map> relationsFoundInFile; //store the type relations already found for each file + int relationsInModule = 0; + + //check function return types + for (const model::RelationalCohesionFunctionView& function + : _ctx.db->query( + odb::query::query_columns::File::path.like(path + "%") + )) { - if (cc::util::isRootedUnderAnyOf(pathVector,record.filePath)) + if ( + typesFound.find(function.returnType) != typesFound.end() && + //check if return type is defined within the current module + typeDefinitionPaths[function.returnType] != function.filePath && + //check for self relation + (relationsFoundInFile.find(function.filePath) == relationsFoundInFile.end() || + //check if any reletaions were found in the current file + relationsFoundInFile[function.filePath].find(function.returnType) == relationsFoundInFile[function.filePath].end()) + //check if this relation is already found + ) { - typesFound.insert(record.typeHash); + ++relationsInModule; + auto it = relationsFoundInFile.find(function.filePath); + if (it != relationsFoundInFile.end()) + { + it->second.insert(function.returnType); + } + else + { + relationsFoundInFile.insert(std::make_pair(function.filePath,std::unordered_set{function.returnType})); + } } + } - typesUnderPath.insert(std::make_pair(currentPath,typesFound)); - } - //save where each type is defined so self relations can be excluded - for (const model::RelationalCohesionRecordView& record - : _ctx.db->query()) - { - typeDefinitionPaths.insert(std::make_pair(record.typeHash,record.filePath)); - } - - //find relations - for (auto &&path : filepaths) - { - std::vector currentModulePaths( - pathsInModule[path].begin(), pathsInModule[path].end() - ); - - uint relationsInModule = 0; //R - std::unordered_set relationsInCurrentFile; - std::unordered_set filesAlreadyChecked; - //select the next module - for (auto &&modulePath : currentModulePaths) + //check function parameters + for (const model::RelationalCohessionFunctionParameterView& parameter + : _ctx.db->query( + odb::query::query_columns::File::path.like(path + "%") + )) { - std::vector pathVector; - pathVector.push_back(modulePath); - //find the files defined under the current module member - for (const model::RelationalCohesionFileView& file - : _ctx.db->query()) + if ( + typesFound.find(parameter.typeHash) != typesFound.end() && + //check if return type is defined within the current module + typeDefinitionPaths[parameter.typeHash] != parameter.filePath && + //check for self relation + (relationsFoundInFile.find(parameter.filePath) == relationsFoundInFile.end() || + //check if any reletaions were found in the current file + relationsFoundInFile[parameter.filePath].find(parameter.typeHash) == relationsFoundInFile[parameter.filePath].end()) + //check if this relation is already found + ) { - if (file.fileType != "CPP" && - !cc::util::isRootedUnderAnyOf(pathVector,file.filePath) && - filesAlreadyChecked.find(file.filePath) != filesAlreadyChecked.end() - ) + ++relationsInModule; + auto it = relationsFoundInFile.find(parameter.filePath); + if (it != relationsFoundInFile.end()) { - continue; + it->second.insert(parameter.typeHash); } - filesAlreadyChecked.insert(file.filePath); - relationsInCurrentFile.clear(); - //check function return types - for (const model::RelationalCohesionFunctionView& function - : _ctx.db->query()) + else { - if ( - function.filePath == file.filePath && - //check if function is in the current file - typeDefinitionPaths[function.returnType] != function.filePath && - //check for self relation - cc::util::isRootedUnderAnyOf(currentModulePaths,typeDefinitionPaths[function.returnType]) && - //check if return type is defined within the current module - relationsInCurrentFile.find(function.returnType) == relationsInCurrentFile.end() - //check if relation is already found - ) - { - ++relationsInModule; - relationsInCurrentFile.insert(function.returnType); - } - + relationsFoundInFile.insert(std::make_pair(parameter.filePath,std::unordered_set{parameter.typeHash})); } + } + + } - //check function parameters - for (const model::RelationalCohessionFunctionParameterView& parameter - : _ctx.db->query()) + //check function locals + for (const model::RelationalCohessionFunctionLocalView& local + : _ctx.db->query( + odb::query::query_columns::File::path.like(path + "%") + )) + { + if ( + typesFound.find(local.typeHash) != typesFound.end() && + //check if return type is defined within the current module + typeDefinitionPaths[local.typeHash] != local.filePath && + //check for self relation + (relationsFoundInFile.find(local.filePath) == relationsFoundInFile.end() || + //check if any reletaions were found in the current file + relationsFoundInFile[local.filePath].find(local.typeHash) == relationsFoundInFile[local.filePath].end()) + //check if this relation is already found + ) + { + ++relationsInModule; + auto it = relationsFoundInFile.find(local.filePath); + if (it != relationsFoundInFile.end()) { - if ( - parameter.filePath == file.filePath && - //check if the parameter is in the current file - typeDefinitionPaths[parameter.typeHash] != parameter.filePath && - //check for self relation - cc::util::isRootedUnderAnyOf(currentModulePaths,typeDefinitionPaths[parameter.typeHash]) && - //check if the type is defined within the current module - relationsInCurrentFile.find(parameter.typeHash) == relationsInCurrentFile.end() - //check if relation is already found - ) - { - ++relationsInModule; - relationsInCurrentFile.insert(parameter.typeHash); - } - + it->second.insert(local.typeHash); } - - //check function locals - for (const model::RelationalCohessionFunctionLocalView& local - : _ctx.db->query()) + else { - if ( - local.filePath == file.filePath && - //check if the local variable is in the current file - typeDefinitionPaths[local.typeHash] != local.filePath && - //check for self relation - cc::util::isRootedUnderAnyOf(currentModulePaths,typeDefinitionPaths[local.typeHash]) && - //check if the type is defined within the current module - relationsInCurrentFile.find(local.typeHash) == relationsInCurrentFile.end() - //check if relation is already found - ) - { - ++relationsInModule; - relationsInCurrentFile.insert(local.typeHash); - } - + relationsFoundInFile.insert(std::make_pair(local.filePath,std::unordered_set{local.typeHash})); } + } + + } - //check variables - for (const model::RelationalCohesionVariableView& variable - : _ctx.db->query()) + //check variables + for (const model::RelationalCohesionVariableView& variable + : _ctx.db->query( + odb::query::query_columns::File::path.like(path + "%") + )) + { + if ( + typesFound.find(variable.typeHash) != typesFound.end() && + //check if return type is defined within the current module + typeDefinitionPaths[variable.typeHash] != variable.filePath && + //check for self relation + (relationsFoundInFile.find(variable.filePath) == relationsFoundInFile.end() || + //check if any reletaions were found in the current file + relationsFoundInFile[variable.filePath].find(variable.typeHash) == relationsFoundInFile[variable.filePath].end()) + //check if this relation is already found + ) + { + ++relationsInModule; + auto it = relationsFoundInFile.find(variable.filePath); + if (it != relationsFoundInFile.end()) { - if ( - variable.filePath == file.filePath && - //check if the variable is in the current file - typeDefinitionPaths[variable.typeHash] != variable.filePath && - //check for self relation - cc::util::isRootedUnderAnyOf(currentModulePaths,typeDefinitionPaths[variable.typeHash]) && - //check if the type is defined within the current module - relationsInCurrentFile.find(variable.typeHash) == relationsInCurrentFile.end() - //check if relation is already found - ) - { - ++relationsInModule; - relationsInCurrentFile.insert(variable.typeHash); - } - + it->second.insert(variable.typeHash); + } + else + { + relationsFoundInFile.insert(std::make_pair(variable.filePath,std::unordered_set{variable.typeHash})); } - } } + //calculate relational cohesion for module //formula: H = (R + 1)/ N //where H is the relational cohesion value, //R is the number of relationships internal to the module, //N is the number of types in the module - uint numberOfTypesInModule = typesUnderPath[path].size(); //N + uint numberOfTypesInModule = typesFound.size(); //N double relationalCohesion = (static_cast(relationsInModule) + 1.0) / static_cast(numberOfTypesInModule); - - //TODO: persistance - } - + model::CppFileMetrics relationalCohesionMetrics; + relationalCohesionMetrics.file = moduleIds[path]; + relationalCohesionMetrics.value = relationalCohesion; + relationalCohesionMetrics.type = model::CppFileMetrics::Type::RELATIONAL_COHESION; + _ctx.db->persist(relationalCohesionMetrics); - - + } }); } @@ -456,6 +445,7 @@ bool CppMetricsParser::parse() functionParameters(); functionMcCabe(); lackOfCohesion(); + relationalCohesion(); return true; }