@@ -178,89 +178,90 @@ void CppMetricsParser::functionBumpyRoad()
178178
179179void CppMetricsParser::typeMcCabe ()
180180{
181- util::OdbTransaction {_ctx.db } ([&, this ]
181+ using MemberT = model::CppMemberType;
182+ using AstNode = model::CppAstNode;
183+ using Entity = model::CppEntity;
184+ using AstNodeMet = model::CppAstNodeMetrics;
185+
186+ // Calculate type level McCabe metric for all types on parallel threads.
187+ parallelCalcMetric<AstNode>(
188+ " Type-level McCabe" ,
189+ _threadCount * typeMcCabePartitionMultiplier,// number of jobs; adjust for granularity
190+ odb::query<AstNode>::symbolType == AstNode::SymbolType::Type &&
191+ odb::query<AstNode>::astType == AstNode::AstType::Definition,
192+ [&, this ](const MetricsTasks<AstNode>& tasks)
182193 {
183- using MemberT = model::CppMemberType;
184- using AstNode = model::CppAstNode;
185- using Entity = model::CppEntity;
186- using AstNodeMet = model::CppAstNodeMetrics;
187-
188- std::map<model::CppAstNodeId, unsigned int > mcValues;
189-
190- // Process all class definitions
191- for (const auto & type : _ctx.db ->query <AstNode>(
192- odb::query<AstNode>::symbolType == AstNode::SymbolType::Type &&
193- odb::query<AstNode>::astType == AstNode::AstType::Definition))
194+ util::OdbTransaction {_ctx.db } ([&, this ]
194195 {
195- // Skip if class is included from external library
196- type.location .file .load ();
197- const auto typeFile = _ctx.db ->query_one <model::File>(
198- odb::query<model::File>::id == type.location .file ->id );
199- if (!typeFile || !cc::util::isRootedUnderAnyOf (_inputPaths, typeFile->path ))
200- continue ;
201-
202- // Skip if its a template instantiation
203- const auto typeEntity = _ctx.db ->query_one <Entity>(
204- odb::query<Entity>::astNodeId == type.id );
205- if (typeEntity && typeEntity->tags .find (model::Tag::TemplateInstantiation)
206- != typeEntity->tags .cend ())
207- continue ;
208-
209- mcValues[type.id ] = 0 ;
210-
211- // Process its methods
212- for (const auto & method : _ctx.db ->query <MemberT>(
213- odb::query<MemberT>::typeHash == type.entityHash &&
214- odb::query<MemberT>::kind == MemberT::Kind::Method))
196+ for (const AstNode& type : tasks)
215197 {
216- // Lookup AST node of method
217- method. memberAstNode .load ();
218- const auto methodAstNode = _ctx.db ->query_one <AstNode >(
219- odb::query<AstNode >::id == method. memberAstNode ->id );
220- if (!methodAstNode )
198+ // Skip if class is included from external library
199+ type. location . file .load ();
200+ const auto typeFile = _ctx.db ->query_one <model::File >(
201+ odb::query<model::File >::id == type. location . file ->id );
202+ if (!typeFile || ! cc::util::isRootedUnderAnyOf (_inputPaths, typeFile-> path ) )
221203 continue ;
222204
223- // Lookup its definition (different AST node if not defined in class body)
224- auto methodDefs = _ctx.db ->query <AstNode>(
225- odb::query<AstNode>::entityHash == methodAstNode->entityHash &&
226- odb::query<AstNode>::symbolType == AstNode::SymbolType::Function &&
227- odb::query<AstNode>::astType == AstNode::AstType::Definition);
228- if (methodDefs.empty ())
229- continue ;
230- const auto methodDef = *methodDefs.begin ();
231- // Note: we cannot use query_one, because a project might have multiple
232- // functions with the same entityHash compiled to different binaries
233- // So we take the first result, which introduces a small level of
234- // potential inaccuracy
235- // This could be optimized in the future if linkage information about
236- // translation units got added to the database
237-
238- // Skip implicitly defined methods (constructors, operator=, etc.)
239- const auto entity = _ctx.db ->query_one <Entity>(
240- odb::query<Entity>::astNodeId == methodDef.id );
241- if (entity && entity->tags .find (model::Tag::Implicit) != entity->tags .cend ())
205+ // Skip if its a template instantiation
206+ const auto typeEntity = _ctx.db ->query_one <Entity>(
207+ odb::query<Entity>::astNodeId == type.id );
208+ if (typeEntity && typeEntity->tags .find (model::Tag::TemplateInstantiation)
209+ != typeEntity->tags .cend ())
242210 continue ;
243211
244- // Lookup metrics of this definition
245- const auto funcMetrics = _ctx.db ->query_one <AstNodeMet>(
246- odb::query<AstNodeMet>::astNodeId == methodDef.id &&
247- odb::query<AstNodeMet>::type == model::CppAstNodeMetrics::Type::MCCABE_FUNCTION);
248- if (funcMetrics)
212+ unsigned int value = 0 ;
213+
214+ // Process its methods
215+ for (const auto & method : _ctx.db ->query <MemberT>(
216+ odb::query<MemberT>::typeHash == type.entityHash &&
217+ odb::query<MemberT>::kind == MemberT::Kind::Method))
249218 {
250- // Increase class mccabe by the method's
251- mcValues[type.id ] += funcMetrics->value ;
219+ // Lookup AST node of method
220+ method.memberAstNode .load ();
221+ const auto methodAstNode = _ctx.db ->query_one <AstNode>(
222+ odb::query<AstNode>::id == method.memberAstNode ->id );
223+ if (!methodAstNode)
224+ continue ;
225+
226+ // Lookup its definition (different AST node if not defined in class body)
227+ auto methodDefs = _ctx.db ->query <AstNode>(
228+ odb::query<AstNode>::entityHash == methodAstNode->entityHash &&
229+ odb::query<AstNode>::symbolType == AstNode::SymbolType::Function &&
230+ odb::query<AstNode>::astType == AstNode::AstType::Definition);
231+ if (methodDefs.empty ())
232+ continue ;
233+ const auto methodDef = *methodDefs.begin ();
234+ // Note: we cannot use query_one, because a project might have multiple
235+ // functions with the same entityHash compiled to different binaries
236+ // So we take the first result, which introduces a small level of
237+ // potential inaccuracy
238+ // This could be optimized in the future if linkage information about
239+ // translation units got added to the database
240+
241+ // Skip implicitly defined methods (constructors, operator=, etc.)
242+ const auto entity = _ctx.db ->query_one <Entity>(
243+ odb::query<Entity>::astNodeId == methodDef.id );
244+ if (entity && entity->tags .find (model::Tag::Implicit) != entity->tags .cend ())
245+ continue ;
246+
247+ // Lookup metrics of this definition
248+ const auto funcMetrics = _ctx.db ->query_one <AstNodeMet>(
249+ odb::query<AstNodeMet>::astNodeId == methodDef.id &&
250+ odb::query<AstNodeMet>::type == model::CppAstNodeMetrics::Type::MCCABE_FUNCTION);
251+ if (funcMetrics)
252+ {
253+ // Increase class mccabe by the method's
254+ value += funcMetrics->value ;
255+ }
252256 }
253- }
254- }
255257
256- for (const auto & mcValue : mcValues)
257- {
258- model::CppAstNodeMetrics typeMcMetric;
259- typeMcMetric.astNodeId = mcValue.first ;
260- typeMcMetric.type = model::CppAstNodeMetrics::Type::MCCABE_TYPE;
261- typeMcMetric.value = mcValue.second ;
262- _ctx.db ->persist (typeMcMetric);
263- }
258+ model::CppAstNodeMetrics typeMcMetric;
259+ typeMcMetric.astNodeId = type.id ;
260+ typeMcMetric.type = model::CppAstNodeMetrics::Type::MCCABE_TYPE;
261+ typeMcMetric.value = value;
262+ _ctx.db ->persist (typeMcMetric);
263+ }
264+ });
264265 });
265266}
266267
0 commit comments