feat(extract): add QML support and Qt C++/QML bridge (#1716)#1748
Open
Hamza-Masuadi wants to merge 4 commits into
Open
feat(extract): add QML support and Qt C++/QML bridge (#1716)#1748Hamza-Masuadi wants to merge 4 commits into
Hamza-Masuadi wants to merge 4 commits into
Conversation
QML files declare a tree of typed objects (Item { id: root; Text { ... } }).
The new extractor walks that tree with tree-sitter-qmljs, distinguishing real
child objects from grouped-property-binding blocks (e.g. `anchors { ... }`)
by QML's own uppercase/lowercase type-name convention, and models:
- the file's root object as its own reusable component (named after the
file stem, since that's how QML engines expose it to other files)
- id: bindings as their own nodes for reference resolution
- properties, functions, signals, inline components, and enum decls
- Behavior on <prop> { ... } as a real anonymous child object
- ui_object_array children (e.g. `states: [ State { ... } ]`)
- id/property-alias/event-handler references and same-file JS calls
- cross-file component instantiation via sourceless stub nodes, resolved
onto the real definition by graphify's existing corpus-wide rewire pass
- import statements (module and relative-path) as imports_from edges
Member-call resolution (`x.method()`) checks that `method` is actually
defined on the node `x` resolves to via a func_owner map, not just that some
same-named function exists anywhere in the file -- func_table is a flat,
whole-file dict, so without this check two same-named methods on different
objects/components would let one shadow the other and produce a wrong
`calls` edge. A bare function reference with no call parens (a valid QML
idiom, e.g. `onClicked: doSomething`) now also resolves to a `references`
edge instead of being silently dropped. Anonymous same-typed siblings that
start on the same source line (e.g. a compact `states: [State{}, State{}]`
one-liner) are disambiguated by column, not just line, so they no longer
collapse into a single node.
tree-sitter-qmljs's PyPI release has a broken Python binding build (missing
src/scanner.c, so the extension fails to import) -- fixed upstream at
yuja/tree-sitter-qmljs#29, pending merge. The dev dependency group pins a
patched fork in the meantime; the `qml` extra tracks the eventual PyPI fix.
Verified against all 452 .qml files in a real ~450k-line Qt/QML app with
zero extraction errors (23k nodes, 35k edges).
Co-authored-by: Cursor <[email protected]>
tree-sitter-qmljs is not published on PyPI under any name, so pip install graphifyy[qml] can never resolve this extra on its own (and PyPI disallows direct git-URL deps in published metadata, so this can't be fixed from our end). Left out of the `all` extra for the same reason -- users who want QML support install tree-sitter-qmljs from git themselves. For our own tests/CI, pin the dev group directly to yuja/tree-sitter-qmljs@565872b, which has the external-scanner-missing fix (yuja/tree-sitter-qmljs#29) merged and generated parser sources refreshed on top of it. Co-authored-by: Cursor <[email protected]>
39c3d9d to
f90063a
Compare
Author
|
Update on the
|
Close out the remaining Graphify-Labs#1716 scope on top of the QML extractor: tag signals:/slots:, model Q_PROPERTY READ/WRITE/NOTIFY, and resolve QML_NAMED_ELEMENT / qmlRegisterType aliases onto real C++ class nodes. Co-authored-by: Cursor <[email protected]>
Skip bridge tests that need QML when tree-sitter-qmljs is missing, pick the correct alias string for qmlRegisterUncreatableType, and only remappable QML type stubs (origin_file) in the alias resolver. Co-authored-by: Cursor <[email protected]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds Qt/QML support to graphify's deterministic AST extraction layer, covering the full scope of #1716:
tree-sitter-qmljsextractor for.qmlfilesQML_NAMED_ELEMENT/qmlRegisterTypealiases resolve onto real C++ class nodessignals:,slots:,Q_PROPERTY, and bareQ_OBJECT/Q_GADGETparsing fixesQML extractor (
graphify/extractors/qml.py)Walks the QML object tree and models:
id:bindings, properties, functions, signals, inline components, enumsBehavior on <prop> { ... }andui_object_arraychildrenfunc_owner)imports_fromedgesWired into
_DISPATCH,LANGUAGE_EXTRACTORS,CODE_EXTENSIONS, and_LANG_FAMILY.C++ / Qt bridge (
extractors/engine.py+extract.py)signals:/slots:bodyless prototypes become taggedsignal/slotnodesQ_PROPERTY(type name READ … WRITE … NOTIFY …)emits apropertynode plus accessor edgesQML_NAMED_ELEMENT("Alias")andqmlRegisterType<T>(…, "Alias")feed_resolve_cpp_qml_aliasesQ_OBJECT/Q_GADGETget a semicolon preprocess so followingsignals:/slots:sections parse cleanlyQ_OBJECT,QML_NAMED_ELEMENT, …) is suppressed as field nodestree-sitter-qmljsdependencytree-sitter-qmljsis not on PyPI, sopip install graphifyy[qml]cannot resolve the extra on its own (and PyPI rejects git-URL deps in published metadata). Left out of theallextra for the same reason.pip install git+https://github.com/yuja/tree-sitter-qmljsfirstyuja/tree-sitter-qmljs@565872b(scanner.c fix from UnicodeDecodeError on Windows (GBK locale) during graphify install #29 + regenerated sources)Test plan
tests/test_qml.py(components, bindings, Behavior, ids, stubs, builtins, member-call disambiguation, bare refs, arrays, imports, inline components, missing grammar)tests/test_cpp_qml_bridge.py(named-element alias, bare QML_ELEMENT, ambiguous alias guard, qmlRegisterType, signals, slots, Q_PROPERTY accessors, macro-noise suppression, build survival).qmlfiles): zero extraction crashes; signal nodes and alias bridging verified