@@ -315,6 +315,60 @@ void CppMetricsParser::lackOfCohesion()
315315 // Record these fields for later use.
316316 fieldHashes.insert (field.entityHash );
317317 }
318+ std::size_t fieldCount = fieldHashes.size ();
319+
320+ #ifdef DATABASE_SQLITE
321+ /* SQLite has a fixed-size recursive descent parser, and each logical operator (like OR) adds a
322+ * level to the parser's stack. Constructing queries with many ORs can lead to a stack overflow.
323+ */
324+
325+ // Counter variables.
326+ std::size_t methodCount = 0 ;
327+ std::size_t totalCohesion = 0 ;
328+
329+ for (const model::CohesionCppMethodView& method
330+ : _ctx.db ->query <model::CohesionCppMethodView>(QMethodTypeHash == type.entityHash ))
331+ {
332+ // Do not consider methods with no explicit bodies.
333+ const model::Position start (method.startLine , method.startColumn );
334+ const model::Position end (method.endLine , method.endColumn );
335+
336+ if (!(start < end))
337+ {
338+ continue ;
339+ }
340+
341+ std::unordered_set<HashType> usedFields;
342+
343+ // Query AST nodes that use a variable for reading or writing...
344+ for (const model::CohesionCppAstNodeView& node
345+ : _ctx.db ->query <model::CohesionCppAstNodeView>(
346+ // ... in the same file as the current method
347+ (QNodeFilePath == method.filePath &&
348+ // ... within the textual scope of the current method's body.
349+ (QNodeRange.start .line > start.line
350+ || (QNodeRange.start .line == start.line
351+ && QNodeRange.start .column >= start.column )) &&
352+ (QNodeRange.end .line < end.line
353+ || (QNodeRange.end .line == end.line
354+ && QNodeRange.end .column <= end.column )))
355+ ))
356+ {
357+ // If this AST node is a reference to a field of the type...
358+ if (fieldHashes.find (node.entityHash ) != fieldHashes.end ())
359+ {
360+ // ... then mark it as used by this method.
361+ usedFields.insert (node.entityHash );
362+ }
363+ }
364+
365+ ++methodCount;
366+ totalCohesion += usedFields.size ();
367+ }
368+ #else
369+ /* With more advanced database engines like PostgreSQL or MySQL we can choose an optimized query strategy.
370+ * These engines use much more robust parsing engine and can handle deeply nested expressions.
371+ */
318372
319373 // Query all methods of the current type.
320374 std::vector<model::CohesionCppMethodView> methods;
@@ -354,7 +408,6 @@ void CppMetricsParser::lackOfCohesion()
354408 }
355409
356410 // Counter variables.
357- std::size_t fieldCount = fieldHashes.size ();
358411 std::size_t methodCount = methods.size ();
359412 std::size_t totalCohesion = 0 ;
360413
@@ -384,6 +437,7 @@ void CppMetricsParser::lackOfCohesion()
384437
385438 totalCohesion += usedFields.size ();
386439 }
440+ #endif
387441
388442 // Calculate and record metrics.
389443 const double dF = fieldCount;
0 commit comments