Skip to content

Commit d5c6671

Browse files
authored
Merge pull request Ericsson#803 from mcserep/lackofcohesion-sqlite
Don't construct queries with too many OR statements for SQLite
2 parents 613f50c + 483643c commit d5c6671

File tree

1 file changed

+55
-1
lines changed

1 file changed

+55
-1
lines changed

plugins/cpp_metrics/parser/src/cppmetricsparser.cpp

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)