Summary
After a full rebuild with v2.3.2 (which includes the PR #371 scoped-method-name fix), Function nodes
are still not created for C++ class method definitions. This affects both plain C++ and Qt-based projects.
Additionally, Qt macros (Q_OBJECT, QT_BEGIN_NAMESPACE) are misidentified as Function nodes.
Two distinct bugs are confirmed by running CodeParser().parse_file() directly.
Environment
- code-review-graph version: 2.3.2
- OS: Windows 11 (26200)
- Python: 3.12.10
Reproduction
Files used
MyWidgetPlain.h — pure C++, no Qt macros:
#pragma once
class MyWidgetPlain {
public:
MyWidgetPlain();
~MyWidgetPlain();
void doSomething();
int calculateValue(int a, int b);
protected:
void onButtonClicked();
void onDataReceived(int value);
void onReset();
};
MyWidgetPlain.cpp:
#include "MyWidgetPlain.h"
MyWidgetPlain::MyWidgetPlain() {}
MyWidgetPlain::~MyWidgetPlain() {}
void MyWidgetPlain::doSomething() { onReset(); }
int MyWidgetPlain::calculateValue(int a, int b) { return a + b; }
void MyWidgetPlain::onButtonClicked() { int result = calculateValue(1, 2); }
void MyWidgetPlain::onDataReceived(int value) { if (value < 0) return; doSomething(); }
void MyWidgetPlain::onReset() {}
MyWidget.h — Qt-based:
#pragma once
#include <QMainWindow>
QT_BEGIN_NAMESPACE namespace Ui { class MyWidgetClass; };
QT_END_NAMESPACE
class MyWidget : public QMainWindow {
Q_OBJECT
public:
MyWidget(QWidget* parent = nullptr);
~MyWidget();
void doSomething();
int calculateValue(int a, int b);
protected Q_SLOTS:
void onButtonClicked();
void onDataReceived(int value);
public Q_SLOTS:
void onReset();
Q_SIGNALS:
void dataReady(int result);
void errorOccurred(const QString& msg);
};
MyWidget.cpp:
#include "MyWidget.h"
MyWidget::MyWidget(QWidget* parent) : QMainWindow(parent) {}
MyWidget::~MyWidget() {}
void MyWidget::doSomething() { onReset(); }
int MyWidget::calculateValue(int a, int b) { return a + b; }
void MyWidget::onButtonClicked() { Q_EMIT dataReady(calculateValue(1, 2)); }
void MyWidget::onDataReceived(int value) { if (value < 0) { Q_EMIT errorOccurred("err"); return; } doSomething(); }
void MyWidget::onReset() { Q_EMIT dataReady(0); }
Test script
import sys
sys.path.insert(0, r'<path-to-crg-site-packages>')
from pathlib import Path
from code_review_graph.parser import CodeParser
for fname in ['MyWidgetPlain.cpp', 'MyWidgetPlain.h', 'MyWidget.cpp', 'MyWidget.h']:
nodes, edges = CodeParser().parse_file(Path(fname))
print(f'\n=== {fname} -> {len(nodes)} nodes, {len(edges)} edges ===')
for n in nodes:
print(f' [{n.kind:10}] {n.name}')
Actual output
=== MyWidgetPlain.cpp -> 1 nodes, 1 edges ===
[File ] MyWidgetPlain.cpp
=== MyWidgetPlain.h -> 2 nodes, 3 edges ===
[File ] MyWidgetPlain.h
[Function ] class
=== MyWidget.cpp -> 1 nodes, 1 edges ===
[File ] MyWidget.cpp
=== MyWidget.h -> 2 nodes, 2 edges ===
[File ] MyWidget.h
[Function ] QT_BEGIN_NAMESPACE
Expected output
=== MyWidgetPlain.cpp -> 8 nodes ===
[File ] MyWidgetPlain.cpp
[Function ] MyWidgetPlain (constructor)
[Function ] ~MyWidgetPlain (destructor)
[Function ] doSomething
[Function ] calculateValue
[Function ] onButtonClicked
[Function ] onDataReceived
[Function ] onReset
=== MyWidgetPlain.h -> 9 nodes ===
[File ] MyWidgetPlain.h
[Class ] MyWidgetPlain
[Function ] MyWidgetPlain
... (all declared methods)
=== MyWidget.cpp -> 8 nodes ===
[File ] MyWidget.cpp
[Function ] MyWidget
[Function ] ~MyWidget
[Function ] doSomething
... (all defined methods)
=== MyWidget.h -> 10 nodes ===
[File ] MyWidget.h
[Class ] MyWidget
[Function ] MyWidget
... (all declared methods and signals)
Bug breakdown
Bug 1 — .cpp scoped method definitions produce no Function nodes
MyWidgetPlain.cpp has zero Qt dependencies, but none of its 7 method definitions
(MyWidgetPlain::MyWidgetPlain, void MyWidgetPlain::doSomething, etc.) are emitted as nodes.
This means the fix in PR #371 (qualified_identifier / destructor_name / operator_name handling)
is either not applied in this version or does not cover this case.
Note: PR #371 was merged 2026-05-07 and v2.3.2 was released after that date.
The scoped method definitions in .cpp files are still not parsed.
Bug 2 — Wrong node emitted for .h class definition
MyWidgetPlain.h emits a Function node named "class" instead of a Class node named
"MyWidgetPlain". The parser appears to be picking up the class keyword token as the node name.
Bug 3 — Qt macro QT_BEGIN_NAMESPACE emitted as a Function node
MyWidget.h emits a Function node named "QT_BEGIN_NAMESPACE".
The following pattern confuses the parser:
QT_BEGIN_NAMESPACE namespace Ui { class MyWidgetClass; };
QT_END_NAMESPACE
Tree-sitter cannot expand macros, so it treats QT_BEGIN_NAMESPACE as a function-like token.
Bug 4 — Qt class body macros prevent all member parsing
Q_OBJECT, Q_SIGNALS:, and protected Q_SLOTS: inside the class body cause the Tree-sitter
AST for the class body to be malformed. As a result, zero member Function nodes are emitted for
MyWidget.cpp — same outcome as MyWidgetPlain.cpp, suggesting Bug 1 is the primary cause and
Bug 4 adds further breakage for Qt projects specifically.
Impact
- Any C++ project using out-of-line method definitions (
Class::method() in .cpp) gets zero
Function nodes — which is the standard pattern for all non-trivial C++ codebases.
- Qt projects (QObject-derived classes) are additionally affected by macro misidentification.
detect-changes always returns changed_functions: [] and risk_score: 0.0 for C++ projects,
making it effectively unusable for C++.
Related
Summary
After a full rebuild with v2.3.2 (which includes the PR #371 scoped-method-name fix), Function nodes
are still not created for C++ class method definitions. This affects both plain C++ and Qt-based projects.
Additionally, Qt macros (
Q_OBJECT,QT_BEGIN_NAMESPACE) are misidentified as Function nodes.Two distinct bugs are confirmed by running
CodeParser().parse_file()directly.Environment
Reproduction
Files used
MyWidgetPlain.h — pure C++, no Qt macros:
MyWidgetPlain.cpp:
MyWidget.h — Qt-based:
MyWidget.cpp:
Test script
Actual output
Expected output
Bug breakdown
Bug 1 —
.cppscoped method definitions produce no Function nodesMyWidgetPlain.cpphas zero Qt dependencies, but none of its 7 method definitions(
MyWidgetPlain::MyWidgetPlain,void MyWidgetPlain::doSomething, etc.) are emitted as nodes.This means the fix in PR #371 (
qualified_identifier/destructor_name/operator_namehandling)is either not applied in this version or does not cover this case.
Note: PR #371 was merged 2026-05-07 and v2.3.2 was released after that date.
The scoped method definitions in
.cppfiles are still not parsed.Bug 2 — Wrong node emitted for
.hclass definitionMyWidgetPlain.hemits aFunctionnode named"class"instead of aClassnode named"MyWidgetPlain". The parser appears to be picking up theclasskeyword token as the node name.Bug 3 — Qt macro
QT_BEGIN_NAMESPACEemitted as aFunctionnodeMyWidget.hemits aFunctionnode named"QT_BEGIN_NAMESPACE".The following pattern confuses the parser:
Tree-sitter cannot expand macros, so it treats
QT_BEGIN_NAMESPACEas a function-like token.Bug 4 — Qt class body macros prevent all member parsing
Q_OBJECT,Q_SIGNALS:, andprotected Q_SLOTS:inside the class body cause the Tree-sitterAST for the class body to be malformed. As a result, zero member Function nodes are emitted for
MyWidget.cpp— same outcome asMyWidgetPlain.cpp, suggesting Bug 1 is the primary cause andBug 4 adds further breakage for Qt projects specifically.
Impact
Class::method()in.cpp) gets zeroFunction nodes — which is the standard pattern for all non-trivial C++ codebases.
detect-changesalways returnschanged_functions: []andrisk_score: 0.0for C++ projects,making it effectively unusable for C++.
Related
This PR targeted the same area but the fix does not appear to be effective for standard
out-of-line method definitions.