@@ -134,7 +134,7 @@ void CppMetricsParser::functionMcCabe()
134134 {
135135 model::CppAstNodeMetrics funcMcCabe;
136136 funcMcCabe.astNodeId = param.astNodeId ;
137- funcMcCabe.type = model::CppAstNodeMetrics::Type::MCCABE ;
137+ funcMcCabe.type = model::CppAstNodeMetrics::Type::MCCABE_FUNCTION ;
138138 funcMcCabe.value = param.mccabe ;
139139 _ctx.db ->persist (funcMcCabe);
140140 }
@@ -169,6 +169,94 @@ void CppMetricsParser::functionBumpyRoad()
169169 });
170170}
171171
172+ void CppMetricsParser::typeMcCabe ()
173+ {
174+ util::OdbTransaction {_ctx.db } ([&, this ]
175+ {
176+ using MemberT = model::CppMemberType;
177+ using AstNode = model::CppAstNode;
178+ using Entity = model::CppEntity;
179+ using AstNodeMet = model::CppAstNodeMetrics;
180+
181+ std::map<model::CppAstNodeId, unsigned int > mcValues;
182+
183+ // Process all class definitions
184+ for (const auto & type : _ctx.db ->query <AstNode>(
185+ odb::query<AstNode>::symbolType == AstNode::SymbolType::Type &&
186+ odb::query<AstNode>::astType == AstNode::AstType::Definition))
187+ {
188+ // Skip if class is included from external library
189+ type.location .file .load ();
190+ const auto typeFile = _ctx.db ->query_one <model::File>(
191+ odb::query<model::File>::id == type.location .file ->id );
192+ if (!typeFile || !cc::util::isRootedUnderAnyOf (_inputPaths, typeFile->path ))
193+ continue ;
194+
195+ // Skip if its a template instantiation
196+ const auto typeEntity = _ctx.db ->query_one <Entity>(
197+ odb::query<Entity>::astNodeId == type.id );
198+ if (typeEntity && typeEntity->tags .find (model::Tag::TemplateInstantiation)
199+ != typeEntity->tags .cend ())
200+ continue ;
201+
202+ mcValues[type.id ] = 0 ;
203+
204+ // Process its methods
205+ for (const auto & method : _ctx.db ->query <MemberT>(
206+ odb::query<MemberT>::typeHash == type.entityHash &&
207+ odb::query<MemberT>::kind == MemberT::Kind::Method))
208+ {
209+ // Lookup AST node of method
210+ method.memberAstNode .load ();
211+ const auto methodAstNode = _ctx.db ->query_one <AstNode>(
212+ odb::query<AstNode>::id == method.memberAstNode ->id );
213+ if (!methodAstNode)
214+ continue ;
215+
216+ // Lookup its definition (different AST node if not defined in class body)
217+ auto methodDefs = _ctx.db ->query <AstNode>(
218+ odb::query<AstNode>::entityHash == methodAstNode->entityHash &&
219+ odb::query<AstNode>::symbolType == AstNode::SymbolType::Function &&
220+ odb::query<AstNode>::astType == AstNode::AstType::Definition);
221+ if (methodDefs.empty ())
222+ continue ;
223+ const auto methodDef = *methodDefs.begin ();
224+ // Note: we cannot use query_one, because a project might have multiple
225+ // functions with the same entityHash compiled to different binaries
226+ // So we take the first result, which introduces a small level of
227+ // potential inaccuracy
228+ // This could be optimized in the future if linkage information about
229+ // translation units got added to the database
230+
231+ // Skip implicitly defined methods (constructors, operator=, etc.)
232+ const auto entity = _ctx.db ->query_one <Entity>(
233+ odb::query<Entity>::astNodeId == methodDef.id );
234+ if (entity && entity->tags .find (model::Tag::Implicit) != entity->tags .cend ())
235+ continue ;
236+
237+ // Lookup metrics of this definition
238+ const auto funcMetrics = _ctx.db ->query_one <AstNodeMet>(
239+ odb::query<AstNodeMet>::astNodeId == methodDef.id &&
240+ odb::query<AstNodeMet>::type == model::CppAstNodeMetrics::Type::MCCABE_FUNCTION);
241+ if (funcMetrics)
242+ {
243+ // Increase class mccabe by the method's
244+ mcValues[type.id ] += funcMetrics->value ;
245+ }
246+ }
247+ }
248+
249+ for (const auto & mcValue : mcValues)
250+ {
251+ model::CppAstNodeMetrics typeMcMetric;
252+ typeMcMetric.astNodeId = mcValue.first ;
253+ typeMcMetric.type = model::CppAstNodeMetrics::Type::MCCABE_TYPE;
254+ typeMcMetric.value = mcValue.second ;
255+ _ctx.db ->persist (typeMcMetric);
256+ }
257+ });
258+ }
259+
172260void CppMetricsParser::lackOfCohesion ()
173261{
174262 // Calculate the cohesion metric for all types on parallel threads.
@@ -284,6 +372,8 @@ bool CppMetricsParser::parse()
284372 functionMcCabe ();
285373 LOG (info) << " [cppmetricsparser] Computing Bumpy Road metric for functions." ;
286374 functionBumpyRoad ();
375+ LOG (info) << " [cppmetricsparser] Computing McCabe metric for types." ;
376+ typeMcCabe ();
287377 LOG (info) << " [cppmetricsparser] Computing Lack of Cohesion metric for types." ;
288378 lackOfCohesion ();
289379 return true ;
0 commit comments