From 8a5610f721ead887086ae3b1e30decc8c7e90e5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=BCkki=20D=C3=A1niel?= Date: Thu, 4 Apr 2024 11:44:42 +0200 Subject: [PATCH] New metrics: statement count, max nestedness, lines of code, local variable count. --- plugins/cpp/model/include/model/cppfunction.h | 39 ++++++++++ plugins/cpp/parser/src/clangastvisitor.h | 8 ++ .../model/include/model/cppastnodemetrics.h | 4 + .../cppmetricsparser/cppmetricsparser.h | 4 + .../parser/src/cppmetricsparser.cpp | 75 +++++++++++++++++-- 5 files changed, 122 insertions(+), 8 deletions(-) diff --git a/plugins/cpp/model/include/model/cppfunction.h b/plugins/cpp/model/include/model/cppfunction.h index 638e3d1a7..49488b4a6 100644 --- a/plugins/cpp/model/include/model/cppfunction.h +++ b/plugins/cpp/model/include/model/cppfunction.h @@ -26,6 +26,7 @@ struct CppFunction : CppTypedEntity unsigned int bumpiness; unsigned int statementCount; + unsigned int nestedness; std::string toString() const { @@ -39,6 +40,23 @@ struct CppFunction : CppTypedEntity typedef std::shared_ptr CppFunctionPtr; +#pragma db view \ + object(CppFunction) \ + object(CppAstNode : CppFunction::astNodeId == CppAstNode::id) \ + object(File : CppAstNode::location.file) +struct CppFunctionLOC +{ + #pragma db column(CppEntity::astNodeId) + CppAstNodeId id; + + #pragma db column(CppAstNode::location.range.end.line \ + + "-" + CppAstNode::location.range.start.line) + Position::PosType lines; + + #pragma db column(File::path) + std::string filePath; +}; + #pragma db view \ object(CppFunction) object(CppVariable = Parameters : CppFunction::parameters) struct CppFunctionParamCount @@ -73,6 +91,24 @@ struct CppFunctionLocalCount std::size_t count; }; +#pragma db view \ + object(CppFunction) \ + object(CppVariable = Locals : CppFunction::locals) \ + object(CppAstNode : CppFunction::astNodeId == CppAstNode::id) \ + object(File : CppAstNode::location.file) \ + query((?) + "GROUP BY" + cc::model::CppEntity::astNodeId + "," + cc::model::File::path) +struct CppFunctionLocalCountWithId +{ + #pragma db column(CppEntity::astNodeId) + CppAstNodeId id; + + #pragma db column("count(" + Locals::id + ")") + std::size_t count; + + #pragma db column(File::path) + std::string filePath; +}; + #pragma db view \ object(CppFunction) \ object(CppAstNode : CppFunction::astNodeId == CppAstNode::id) \ @@ -108,6 +144,9 @@ struct CppFunctionBumpyRoad #pragma db column(CppFunction::statementCount) unsigned int statementCount; + #pragma db column(CppFunction::nestedness) + unsigned int nestedness; + #pragma db column(File::path) std::string filePath; }; diff --git a/plugins/cpp/parser/src/clangastvisitor.h b/plugins/cpp/parser/src/clangastvisitor.h index 5f3e7eb1e..6d94a69f1 100644 --- a/plugins/cpp/parser/src/clangastvisitor.h +++ b/plugins/cpp/parser/src/clangastvisitor.h @@ -240,6 +240,10 @@ class ClangASTVisitor : public clang::RecursiveASTVisitor prevFun->bumpiness += _curFun->bumpiness + _curFun->statementCount * scope->Depth(); prevFun->statementCount += _curFun->statementCount; + + unsigned int nestedness = scope->Depth() + _curFun->nestedness; + if (nestedness > prevFun->nestedness) + prevFun->nestedness = nestedness; } } }; @@ -315,6 +319,9 @@ class ClangASTVisitor : public clang::RecursiveASTVisitor model::CppFunctionPtr& fun = _functionStack.top(); fun->bumpiness += scope_.Depth(); ++fun->statementCount; + + if (scope_.Depth() > fun->nestedness) + fun->nestedness = scope_.Depth(); } } @@ -917,6 +924,7 @@ class ClangASTVisitor : public clang::RecursiveASTVisitor cppFunction->flowCount = 0; cppFunction->bumpiness = 0; cppFunction->statementCount = 0; + cppFunction->nestedness = 0; unsigned int count = fn_->getNumTemplateParameterLists(); for (unsigned int t = 0; t < count; ++t) diff --git a/plugins/cpp_metrics/model/include/model/cppastnodemetrics.h b/plugins/cpp_metrics/model/include/model/cppastnodemetrics.h index 8272bd3c8..0ee51719c 100644 --- a/plugins/cpp_metrics/model/include/model/cppastnodemetrics.h +++ b/plugins/cpp_metrics/model/include/model/cppastnodemetrics.h @@ -23,6 +23,10 @@ struct CppAstNodeMetrics BRANCH_COUNT = 6, LOOP_COUNT = 7, FLOW_COUNT = 8, + STATEMENT_COUNT = 9, + NESTEDNESS = 10, + LINES_OF_CODE = 11, + LOCAL_COUNT = 12, }; #pragma db id auto diff --git a/plugins/cpp_metrics/parser/include/cppmetricsparser/cppmetricsparser.h b/plugins/cpp_metrics/parser/include/cppmetricsparser/cppmetricsparser.h index ddc99aa07..45269db85 100644 --- a/plugins/cpp_metrics/parser/include/cppmetricsparser/cppmetricsparser.h +++ b/plugins/cpp_metrics/parser/include/cppmetricsparser/cppmetricsparser.h @@ -31,8 +31,12 @@ class CppMetricsParser : public AbstractParser virtual bool parse() override; private: + // Calculate lines of code for every function. + void linesOfCode(); // Calculate the count of parameters for every function. void functionParameters(); + // Calculate the count of local variables for every function. + void functionLocals(); // Calculate the McCabe complexity of functions. void functionMcCabe(); // Calculate the bumpy road metric for every function. diff --git a/plugins/cpp_metrics/parser/src/cppmetricsparser.cpp b/plugins/cpp_metrics/parser/src/cppmetricsparser.cpp index dd52156cf..705bbfc00 100644 --- a/plugins/cpp_metrics/parser/src/cppmetricsparser.cpp +++ b/plugins/cpp_metrics/parser/src/cppmetricsparser.cpp @@ -103,6 +103,27 @@ bool CppMetricsParser::cleanupDatabase() return true; } + +void CppMetricsParser::linesOfCode() +{ + util::OdbTransaction {_ctx.db} ([&, this] + { + for (const model::CppFunctionLOC& loc + : _ctx.db->query()) + { + // Skip functions that were included from external libraries. + if (!cc::util::isRootedUnderAnyOf(_inputPaths, loc.filePath)) + continue; + + model::CppAstNodeMetrics metric; + metric.astNodeId = loc.id; + metric.type = model::CppAstNodeMetrics::Type::LINES_OF_CODE; + metric.value = loc.lines; + _ctx.db->persist(metric); + } + }); +} + void CppMetricsParser::functionParameters() { util::OdbTransaction {_ctx.db} ([&, this] @@ -123,6 +144,26 @@ void CppMetricsParser::functionParameters() }); } +void CppMetricsParser::functionLocals() +{ + util::OdbTransaction {_ctx.db} ([&, this] + { + for (const model::CppFunctionLocalCountWithId& localCount + : _ctx.db->query()) + { + // Skip functions that were included from external libraries. + if (!cc::util::isRootedUnderAnyOf(_inputPaths, localCount.filePath)) + continue; + + model::CppAstNodeMetrics funcLocals; + funcLocals.astNodeId = localCount.id; + funcLocals.type = model::CppAstNodeMetrics::Type::LOCAL_COUNT; + funcLocals.value = localCount.count; + _ctx.db->persist(funcLocals); + } + }); +} + void CppMetricsParser::functionMcCabe() { util::OdbTransaction {_ctx.db} ([&, this] @@ -182,11 +223,23 @@ void CppMetricsParser::functionBumpyRoad() const double dC = function.statementCount; const bool empty = function.statementCount == 0; - model::CppAstNodeMetrics metrics; - metrics.astNodeId = function.astNodeId; - metrics.type = model::CppAstNodeMetrics::Type::BUMPY_ROAD; - metrics.value = empty ? 1.0 : (dB / dC); - _ctx.db->persist(metrics); + model::CppAstNodeMetrics br; + br.astNodeId = function.astNodeId; + br.type = model::CppAstNodeMetrics::Type::BUMPY_ROAD; + br.value = empty ? 1.0 : (dB / dC); + _ctx.db->persist(br); + + model::CppAstNodeMetrics sc; + sc.astNodeId = function.astNodeId; + sc.type = model::CppAstNodeMetrics::Type::STATEMENT_COUNT; + sc.value = function.statementCount; + _ctx.db->persist(sc); + + model::CppAstNodeMetrics nn; + nn.astNodeId = function.astNodeId; + nn.type = model::CppAstNodeMetrics::Type::NESTEDNESS; + nn.value = function.nestedness; + _ctx.db->persist(nn); } }); } @@ -437,7 +490,9 @@ class MetricsExtractor bool CppMetricsParser::parse() { + linesOfCode(); //functionParameters(); + functionLocals(); functionMcCabe(); functionBumpyRoad(); //lackOfCohesion(); @@ -466,11 +521,15 @@ bool CppMetricsParser::extract() std::cout << "Extracting to: " << me.RootDir().c_str() << std::endl; typedef model::CppAstNodeMetrics::Type Type; - me.Extract(Type::BRANCH_COUNT, "Branch"); - me.Extract(Type::LOOP_COUNT, "Loop"); - me.Extract(Type::FLOW_COUNT, "Flow"); + me.Extract(Type::BRANCH_COUNT, "BranchCount"); + me.Extract(Type::LOOP_COUNT, "LoopCount"); + me.Extract(Type::FLOW_COUNT, "FlowCount"); me.Extract(Type::MCCABE, "McCabe"); me.Extract(Type::BUMPY_ROAD, "BumpyRoad"); + me.Extract(Type::STATEMENT_COUNT, "StatementCount"); + me.Extract(Type::NESTEDNESS, "Nestedness"); + me.Extract(Type::LINES_OF_CODE, "LinesOfCode"); + me.Extract(Type::LOCAL_COUNT, "LocalCount"); return true; }