Skip to content

Parser improvements: empty record, dot-shorthand patterns, abstract/external fields, null-aware map keys, etc.#97

Merged
TimWhiting merged 17 commits into
UserNobody14:masterfrom
AlexLaroche:alexandre/parser-improvements
May 5, 2026
Merged

Parser improvements: empty record, dot-shorthand patterns, abstract/external fields, null-aware map keys, etc.#97
TimWhiting merged 17 commits into
UserNobody14:masterfrom
AlexLaroche:alexandre/parser-improvements

Conversation

@AlexLaroche

@AlexLaroche AlexLaroche commented May 4, 2026

Copy link
Copy Markdown
Contributor

A set of small, targeted grammar fixes uncovered while running real-world Dart packages through tree-sitter-dart. Each commit is self-contained, cites the relevant Dart spec section, and ships with a corpus test (where the fix introduces new AST shapes). All commits keep the existing 175-test corpus and the syntax-highlighting test suite passing.

Validation

I scanned the pub.dev catalog (latest version of each package) using the parser produced by this branch, then re-scanned every previously-failing package against the freshly-built parser to discount stale results. Final counts:

metric result
total package-versions scanned 5,285
fully clean parses 5,147 (97.4%)
PartialParsing errors 56 (1.1%)
only non-parse errors (e.g. analysis-time issues) 82 (1.6%)

For reference, an earlier snapshot of the same corpus had 102 packages with PartialParsing. The seventeen commits in this PR clear roughly half of those (~45% drop on that snapshot), with 0 regressions on the previously-clean control sample at every iteration. The remaining 56 are dominated by patterns that need deeper grammar restructuring than incremental edits can address — primarily @override followed by a record return type with named fields (e.g. @override (String name, int age) foo();), where tree-sitter commits to the annotation's argument-list path before discovering the failure.

Commits

  1. Allow empty record literal ()_record_literal_no_const now accepts the unit/empty record. The empty form gets a negative dynamic precedence so f<T>() still parses as type-args + empty-args; new GLR conflicts vs record_type and _strict_formal_parameter_list.
  2. Allow dot-shorthand in case patterns and const invocationscase .red:, case .new():, case .fromRGB(1, 2, 3): now parse. const_object_expression gains const_builtin + dot_shorthand + arguments for const Color c = const .new();.
  3. Allow get/set as identifier in initialized_identifierint set = 0; and String get = 'foo'; parse as fields. Mirrors the existing aliasing in _declared_identifier.
  4. Allow get/set/Function as identifier in assignable expressionsset = 5; and Function.apply(...) parse correctly. Aliases _get, _set, and _function_builtin_identifier to identifier in _primary and assignable_expression.
  5. Support abstract instance fields and top-level external variables — Adds abstract <type>? <ids>; / abstract final ... / abstract covariant ... to declaration, and external <type>? <ids>; (with optional final/late) to _top_level_definition.
  6. Allow get/set/Function as label and operator as identifierf(get: x, set: y) and String operator; parse. Adds the aliases to the label rule and to initialized_identifier/_declared_identifier.
  7. Add empty/null statement ;if (cond) ; and stray ; now parse via a new empty_statement rule.
  8. Support external instance fields with final/covariant — Adds external final <type>? <ids> and external covariant <var-or-type> <ids> to declaration for dart:js_interop extension types.
  9. Allow trailing comma in for-loop update expressionsfor (var i = 0; i < n; i += 15,) { ... } parses (commaSepcommaSepTrailingComma).
  10. Allow full expression on field initializer right-hand sideA(int? x) : x = x ??= 5; now parses (_real_expression_expression).
  11. Allow null-aware key in map literal entry{?maybeKey: value, key: ?maybeValue} parses (Dart 3 null-aware elements).
  12. Allow null-assertion ! and argument parts within cascade subsectionsobj.._parent!.onChildrenChanged(this) parses (common in flame, flutter widget code). After the leading cascade selector and after each subsection's assignable selector, accept argument parts and ! interleaved — mirrors the general selector form used in non-cascade chains.
  13. Allow built-in identifiers as static external field namesexternal SomeType get; (used by dart:ffi Struct conventions, e.g. colibri_stateless) parses. Aliases get/set/operator to identifier in the _external_and_static + _type + identifier arm.
  14. Allow unnamed library directive (library;) — Dart 2.19+ permits an unnamed library; to attach a doc comment / annotation to a library file without a name. Makes the dotted_identifier_list in library_name optional.
  15. Extend symbol literals to accept dotted ids and operators — Dart symbols accept a dotted identifier list (#foo.bar.baz) or a single operator token (#+, #==, #[], #[]=, #~, #|, #&, #^, plus the relational, shift, additive, multiplicative ops). The previous grammar only accepted #identifier.
  16. Allow single-named-field record literal with trailing comma(name: value,) parses as a record. Dart 3 requires the trailing comma here to disambiguate from a labeled parenthesized expression.
  17. Scope operator keyword highlight to operator_signature — Once operator is aliased as an identifier (commit 6), the global "operator" @keyword query in highlights.scm would tag occurrences like var operator = 1; as a keyword. Drop it from the global list and add a scoped query under operator_signature, mirroring the pattern already used for get and set.

Spec references

Each commit message cites the relevant section of the Dart Language Specification (Records, Patterns, Built-in Identifiers, Statements, Constructor field initializers, Null-aware elements, External members, Abstract instance variables, Symbols, Libraries).

Generated files

src/grammar.json, src/node-types.json, and src/parser.c are regenerated from grammar.js via tree-sitter generate and committed as part of each grammar.js change, matching the convention already used in this repo.

Alexandre Laroche and others added 17 commits May 4, 2026 10:56
Per the Dart specification, a record literal may have zero positional
and zero named fields, written as `()` (the unit/empty record). The
existing `_record_literal_no_const` rule required at least one field,
so `()` failed to parse as an expression in real-world code.

Reference: Dart Language Specification, Records (recordLiteral) — an
empty `()` is a record with zero positional fields and zero named
fields.

The empty form is given a negative dynamic precedence so that, in
contexts like `f<T>()` where the parser must choose between
type_arguments + empty arguments and a relational expression with an
empty record on the right, it prefers the existing call/type-argument
path.

Conflicts added between `_record_literal_no_const` and `record_type` /
`_strict_formal_parameter_list` to keep the GLR parser exploring all
three interpretations of `(...)` in their respective contexts.
Per Dart 3.10 dot-shorthand and the patterns specification, a
dot-shorthand expression may appear as a constant pattern, e.g.

    switch (c) {
      case .red:        // static member dot-shorthand
      case .new():      // default constructor dot-shorthand
      case .fromRGB(1): // named constructor dot-shorthand with args
    }

and `const` may prefix a dot-shorthand constructor invocation, with the
receiver type inferred from context:

    const Color c = const .new();
    const Color d = const .fromRGB(1, 2, 3);

Adds:
  - `$.dot_shorthand` (optionally followed by type arguments and an
    arguments list) as a `constant_pattern` choice.
  - `seq($.const_builtin, $.dot_shorthand, $.arguments)` as a second
    alternative in `const_object_expression`.

Reference: Dart Language Specification — Dot Shorthands and Patterns.
Per the Dart specification, `get` and `set` are built-in identifiers
(not reserved words) and may be used as ordinary identifiers — for
example as the name of a local variable or a class field with an
explicit type. The `_declared_identifier` rule already aliases
`_get`/`_set` to `identifier`; mirror that on `initialized_identifier`
so declarations like

    class C {
      int set = 0;
      String get = 'foo';
    }

parse correctly. Without this change, the grammar fell back to the
getter/setter declaration rules (which require an initializer-less
signature) and failed in real-world packages such as `sqlparser` and
`s_packages` that use `set`/`get` as field names.

Adds GLR conflicts so the parser keeps the variable-declaration and
getter/setter signature paths open while reading `Type get` /
`Type set`.

Reference: Dart Language Specification — Built-in Identifiers
(`get`, `set`) and Variable Declaration / initializedIdentifier.
Per the Dart specification, `get`, `set`, and `Function` are built-in
identifiers and may appear as ordinary identifiers — including on the
left-hand side of an assignment, or as the receiver of a method call.

Real-world packages such as `sqlparser` (`set = ...`) and
`auro_stream_live` (`Function.apply(...)`) failed to parse because:

- `assignable_expression` only accepted `$.identifier` for the
  bare-identifier case, so `set = expr` and `get = expr` parsed as
  the start of a setter/getter signature instead of an assignment.
- `_primary` did not include `Function` as an identifier, so
  `Function.apply(args)` could not be parsed as a method call (the
  `Function` class is referenced by name).

Adds aliased `_get`, `_set`, and `_function_builtin_identifier`
choices to both `_primary` and `assignable_expression`, plus the
required GLR conflicts (`_primary` vs. `_type_not_void_not_function`
/ `_function_type_tail`) so the parser can still recognize `Function`
as part of a function type (`Function(int)`, `Function?`).

Reference: Dart Language Specification — Built-in Identifiers
(`get`, `set`, `Function`).
Two related Dart 3 declaration forms were missing:

1. Abstract instance fields. Per the Dart spec, an instance field
   inside an abstract class may be declared without an initializer
   using the `abstract` modifier; the field has no implementation and
   subclasses must provide a concrete getter/setter. Forms supported:
       abstract <type>? <ids>;
       abstract final <type>? <ids>;
       abstract covariant <type>? <ids>;
   Affects packages such as `embrace`, `crypto_wallet_util`, and
   `catalyst_builder`.

2. Top-level external variable declarations. Used by `dart:js_interop`
   patterns such as `@JS() external _DdLogs? DD_LOGS;`. The existing
   `_top_level_definition` choice supported `external function/getter/
   setter` signatures but not external variables. Forms supported:
       external <type>? <ids>;
       external final <type>? <ids>;
       external late <type>? <ids>;
   Affects packages such as `datadog_flutter_plugin`, `dwds`, and
   `ditto_live`.

Reference: Dart Language Specification — Abstract Instance Variables
and (Static) External Variables.
Two more built-in identifier sites the grammar did not yet treat as
ordinary identifiers:

- `label` only accepted `\$.identifier`, so named arguments like
  `f(get: x, set: y)` failed to parse. Real-world example:
  `datahub_aperture` constructs `ResourceEndpoint(get: ..., post: ...)`.
- `initialized_identifier` and `_declared_identifier` did not accept
  `operator` as an identifier, so `String operator;` did not parse.
  Real-world example: `ffastdb` declares a `String operator;` field.

Adds aliased `_get`, `_set`, `_function_builtin_identifier` choices
to `label`, and aliased `_operator` to both `initialized_identifier`
and `_declared_identifier`. Also adds a GLR conflict between
`operator_signature` and `_var_or_type` so the parser keeps both
the operator-method-signature path (`Type operator +(...)`) and the
variable-declaration path (`Type operator;`) open.

Reference: Dart Language Specification — Built-in Identifiers
(`get`, `set`, `operator`, `Function`).
Per the Dart specification, a single `;` is the empty (null) statement.
It can appear anywhere a statement is expected, e.g. as the body of an
`if (cond) ;` form, after a `return;` continuation, or as a stray `;`
in a function body. The grammar previously had no rule for this, so
real-world code using it failed to parse.

Adds an `empty_statement` rule and includes it in `_statement`. Affects
packages such as `crypto_wallet_util` (`if (!isUint(n, 53)) ;`) and
`littlefish_feature_user_pins` (`return; ;`).

Reference: Dart Language Specification — Statements (emptyStatement).
Per the Dart specification (Static Interop / External Members), a
class instance field may be declared with the `external` modifier in
combination with `final` or `covariant`. The grammar previously
covered only the bare `external <type> <id>` form (via the
`_external_and_static + _type + identifier` rule), so

    extension type _Foo._(JSObject _) implements JSObject {
      external final JSString field;
    }

failed to parse. Affects `dart:js_interop` extension types in
packages such as `ditto_live`.

Adds two new declaration alternatives:
  external final <type>? <id-list>
  external covariant <var-or-type> <id-list>
Per the Dart spec, expression lists generally allow trailing commas.
The C-style for-loop's update list (`for (init; cond; u1, u2,)`) was
parsed with `commaSep` (no trailing comma); switch to
`commaSepTrailingComma` so code such as

    for (var i = 0; i < n; i += 15,) { ... }

parses. Affects packages such as `pdf_plus`.
Per Dart spec the right-hand side of a constructor field initializer
is a full `expression`, including compound assignments such as `??=`.
The grammar restricted it to `_real_expression`, which excluded
assignment expressions, so code such as

    A(int? x) : x = x ??= 5;

failed to parse. Real-world examples in `matrix` (constructor body
chained `??=` assignments) and `syncfusion_flutter_gauges`.

Reference: Dart Language Specification — Constructor field
initializers (`fieldInitializer`).
Per Dart 3 (null-aware elements), a map entry may use `?` before the
key as well as before the value to mark the corresponding sub-
expression as null-aware:

    {
      ?maybeKey: 1,         // omit entry if maybeKey is null
      key: ?maybeValue,     // omit entry if maybeValue is null
      ?maybeKey: ?maybeValue,
    }

The grammar previously allowed `?` only before the value. Adds
`optional('?')` before the key in the `pair` rule. Affects packages
such as `analyzer` and `drift_dev`.

Reference: Dart Language Specification — Null-aware elements.
Cascades like `obj.._parent!.onChildrenChanged(this)` fail to parse
because the cascade subsection rule only allowed an assignable selector
followed by argument parts, with no way to apply the postfix `!` null
assertion between selectors. The non-cascade `selector` rule already
handles this via the general selector form.

Mirror that here: after the leading cascade selector and after each
subsection's assignable selector, accept argument parts and `!`
interleaved. This matches the shape Dart programs actually use when
chaining null-asserted member access in cascades (common in flame,
flutter widget code, etc.).
`dart:ffi` Struct definitions sometimes declare external fields whose
name is a built-in identifier (`get`, `set`, `operator`). For example
in the `colibri_stateless` package:

    @ffi.Packed(1)
    final class colibri_StatusCondition extends ffi.Struct {
        external colibri_StatusCondition_DataType get;
    }

These names are reserved keywords only in restricted contexts; in field
declarations they are valid identifiers. Accept them as aliases of
`identifier` in the static external field arm so packages using ffi
struct conventions parse cleanly.
Dart 2.19+ allows the library directive to be written without a name
(`library;`) so the file can carry a doc comment or annotation that
documents the library as a whole, without forcing the author to invent
a globally-unique library identifier. The reference is the language
versioning in the Dart language spec section 'Libraries' (the library
declaration's name part is optional since the library declaration
syntax was clarified for the unnamed-library form).

Without this, the parser inserts a synthetic MISSING identifier and
emits a partial parse for any file that uses the form, e.g.
`just_storage`'s `example/di_setup_example.dart` and many other
documentation-only library files.
Per the Dart language spec section 'Symbols', a symbol literal accepts:
- a single identifier or dotted identifier list (e.g. `#a.b.c`)
- a single operator token (e.g. `#+`, `#==`, `#[]`, `#[]=`, `#~`)

The previous grammar only accepted `#identifier`, so common forms used
in serialization/codegen libraries (e.g. `firebase_dart`'s
`#UploadTask.pause` and `build_runner` symbol-as-key patterns) failed
to parse.
A record literal with exactly one named field requires a trailing
comma (`(name: value,)`) to be unambiguously a record rather than a
labeled parenthesized expression. The grammar previously accepted
`(label: expr)` (no comma) and `(label: expr, more,)` (2+ fields)
but rejected the unambiguous single-named-field form.

This pattern shows up in real code returning records with one named
component, e.g. `return (prefix: syntheticImport.prefix,);`. See
Dart 3 record literal grammar in the language spec.
When this branch added `alias($._operator, $.identifier)` to
`initialized_identifier` and `_declared_identifier` (so that
`String operator;` parses), the parser started accepting the
`'operator'` keyword token in identifier position. Tree-sitter still
emits the underlying anonymous keyword node, so the global
`"operator" @keyword` query in highlights.scm fired in places where
`operator` is being used as a variable name (e.g. `var operator = 1;`),
breaking the `keywords.dart` highlight test.

Fix: drop `"operator"` from the global keyword list and add a scoped
query that highlights it as a keyword only inside `operator_signature`.
Mirrors the existing pattern used for `get`/`set` (which already work
this way and pass the same test).
@TimWhiting TimWhiting merged commit 6922ad2 into UserNobody14:master May 5, 2026
3 checks passed
AlexLaroche added a commit to AlexLaroche/ocaml-tree-sitter-semgrep that referenced this pull request May 5, 2026
Brings in the merged upstream PR UserNobody14/tree-sitter-dart#97
with 16 grammar improvements + 1 highlight fix:

  - Empty record literal `()`
  - Dart 3.10 dot-shorthand in case patterns and `const` invocations
  - `get`/`set`/`operator`/`Function` as ordinary identifiers in
    initialized_identifier, _declared_identifier, assignable_expression,
    label, and static external field name positions
  - Abstract instance fields (`abstract <type>? <ids>;`)
  - Top-level external variables and external instance fields with
    `final`/`covariant` (dart:js_interop extension types)
  - Empty/null statement (`;`)
  - Trailing comma in for-loop update expressions
  - Full expression on field initializer right-hand side
  - Null-aware key in map literal entry (Dart 3 null-aware elements)
  - Null-assertion `!` and argument parts within cascade subsections
  - Unnamed library directive (`library;`)
  - Symbol literals with dotted ids and operators (`#a.b.c`, `#+`, `#==`)
  - Single-named-field record literal with trailing comma (`(name: v,)`)
  - Scoped `operator` keyword highlight to operator_signature

Validation against the pub.dev catalog: 5,285 packages scanned, 5,147
clean parses (97.4%), 56 PartialParsing (down from ~102 before this
branch), 0 control regressions across iterations.
yosefAlsuhaibani pushed a commit to semgrep/semgrep that referenced this pull request May 15, 2026
…ilities (semgrep/semgrep-proprietary#6332)

> **Draft — gated on
semgrep/ocaml-tree-sitter-semgrep#590 landing
and an r2c admin running `./release dart` to publish a real release
commit to `semgrep/semgrep-dart`. See "Before marking ready" below.**

## Summary

- Bumps the `languages/dart/tree-sitter/semgrep-dart` submodule to a
regenerated artifact built from upstream
`UserNobody14/tree-sitter-dart@02e9bb19` (13 commits ahead of the
May-2023 pin), and adapts `Parse_dart_tree_sitter.ml` to the new CST
shape.
- Resolves the headline Dart 3 parsing gap: empty-paren `object_pattern`
(e.g. `_MyClass()` arms in `switch`), now common in Flutter (upstream PR
[#93](UserNobody14/tree-sitter-dart#93)).
- Resolves the `@annotation` + record-return-type method gap (e.g.
`@override (R, T) method() {…}`, the Elm-style architecture pattern in
Flutter) — this was the dominant remaining `PartialParsing` cause on the
pub.dev catalog (upstream PR
[#98](UserNobody14/tree-sitter-dart#98)).
- Also picks up: 16 grammar fixes from the upstream parser-improvements
PR ([#97](UserNobody14/tree-sitter-dart#97)) —
empty record literal `()`, dot-shorthand patterns, abstract/external
fields, null-aware map keys, dotted/operator symbol literals,
single-named-field record literals, unnamed library directive, and more.
- Drops the stale "tree-sitter-dart is currently buggy" segfault gate in
`Parse_target.ml` and the `Lang.Dart` exclusion in `Rule_fetching.ml` —
the original repro (`': string (* filename *)'`) now exits cleanly.
- Fixes three parser-side bugs in `Parse_dart_tree_sitter.ml` discovered
during pattern-validation work that reproduce on `develop` too:
1. **Uninitialized local variable declarations were silently dropped.**
`String z;` / `late String w;` inside a function body never made it into
the AST, so patterns like `String $X;` could not match local
declarations. Fixed by emitting `(id, None)` instead of `[]` when the
optional `= expr` is absent.
2. **Patterns starting with a Dart statement keyword silently
misparsed.** `if (kDebugMode) { ... }` parsed as a function definition
(with `if` as the return type), `await foo();` parsed as a bare
`Call(foo, [])` with `await` stripped. Detect statement-keyword starts
up-front and route through the `__SEMGREP_EXPRESSION` path, bypassing
the misleading file-parse.
3. **Function-definition patterns silently degraded to calls.** `void
test() { ... }` reinterpreted as `Call(test, [])` (losing return type,
body, and function context), so `pattern-inside: void test() { ... }`
could never match a function definition. Tightened the forward-decl
ambiguity heuristic so only truly-ambiguous shapes (no return type, no
params, empty body, no attrs) collapse to a Call.
- Adds three Dart-side metavariable capabilities that other major
languages already had:
1. **Typed metavariable `$X as T`** — in pattern mode, the existing Dart
`as` cast is reinterpreted as `TypedMetavar` when the LHS is a
metavariable (TS/Java/Swift use the same trick).
2. **`metavariable-type: T` filter** — Dart registered in
`Parse_metavariable_type` (`x as %s` wrap, `Cast` unwrap).
3. **Metavariables inside string interpolations** — `print("hello $X")`
now binds `$X` to the interpolation expression on Dart targets, matching
Semgrep's convention everywhere else. Real Dart `$name` interpolations
(lowercase) keep the literal-text behavior so existing patterns still
match.

## Validation

Generated the artifact via the standard flow (`make && make install &&
cd lang && ./test-lang dart && ./release dart --dry-run`) on
`ocaml-tree-sitter-semgrep` with the bumped submodule, then tested the
regenerated `parse-dart`:

| Corpus | Old grammar (`80e23c07`) | New grammar (`02e9bb19`) |
|---|---|---|
| 199 random `.dart` files from
[`flutter/flutter@master`](https://github.com/flutter/flutter) (1-30 KB)
| 196 ok / 3 fail | **199 ok / 0 fail** |
| 5,285 latest-version packages on pub.dev | ~102 `PartialParsing` |
**56 `PartialParsing` (1.1%)** |

The 3 Flutter files that previously failed all live inside developer
tooling and exercise Dart 3 patterns:

-
[`dev/bots/check_tests_cross_imports.dart`](https://github.com/flutter/flutter/blob/master/dev/bots/check_tests_cross_imports.dart)
— `switch (this) { _MaterialLibrary() => ..., _CupertinoLibrary() =>
..., _OtherLibrary() => ... }`
-
[`dev/bots/custom_rules/no_stop_watches.dart`](https://github.com/flutter/flutter/blob/master/dev/bots/custom_rules/no_stop_watches.dart)
— `Element() || null`, nested `InterfaceType(element: ...)`
-
[`dev/bots/custom_rules/render_box_intrinsics.dart`](https://github.com/flutter/flutter/blob/master/dev/bots/custom_rules/render_box_intrinsics.dart)
— `switch (node.parent) { ... }`

## New tests (8)

Added regression tests covering every distinct fix and capability in
this branch:

| Test | Covers |
|---|---|
| `tests/parsing/dart/switch_object_pattern.dart` | Empty-paren /
field-bearing / generic / guarded `object_pattern` arms in switch (Dart
3 `#93`) |
| `tests/parsing/dart/dart3_grammar_features.dart` | Empty record `()`,
single-named record `(name: v,)`, dot-shorthand `.foo`/`.new`,
null-aware map element `?key: value`, null-assertion `!` in cascade,
unnamed library directive, dotted/operator symbol literals (`#a.b.c`,
`#==`), `get`/`set` as identifiers |
| `tests/patterns/dart/uninit_local_var.{dart,sgrep}` | `String $X;`
matches uninitialized locals (parser fix #1) |
| `tests/patterns/dart/function_def_void.{dart,sgrep}` | `void test() {
... }` matches function definitions (parser fix #3) |
| `tests/rules/if_pattern_dart.{yaml,dart}` | `if (kDebugMode) { ... }`
matches real If statements (parser fix #2 — `if` keyword routing) |
| `tests/rules/await_pattern_dart.{yaml,dart}` | `await fetch($URL)`
matches only awaited calls (parser fix #2 — `await` keyword routing) |
| `tests/rules/typed_metavar_dart.{yaml,dart}` | `print($X as String)`
binds against String args/decls only (typed metavariable) |
| `tests/rules/metavar_type_dart.{yaml,dart}` | `metavariable-type:
String` filter (typed metavariable) |
| `tests/rules/string_interp_metavar_dart.{yaml,dart}` | `print("hello
$X")` binds the interpolation expression |

## Commit groups

This branch is 21 commits — grouped by intent:

1. **Submodule bump (commit 1)** — `chore(dart): bump tree-sitter-dart
and adapt OCaml mapper for Dart 3` style commit at the base.
2. **CST-shape adaptations (commits 2–10)** — one commit per upstream
grammar change, each adjusting `Parse_dart_tree_sitter.ml` to consume
the new CST shape: abstract/external var, label/operator identifiers,
empty-statement, external instance fields, for-loop/field-initializer
changes, null-aware map key, null-assertion in cascades, ffi external
get/set fields, full symbol literals, single-named record, record-return
method.
3. **Parser bug fixes (commits 11–14)** — independent of the bump,
surfaced during pattern validation: uninitialized-local-decl drop,
statement-keyword pattern routing, `await`/`rethrow` keyword routing,
function-definition pattern degradation.
4. **Pattern-mode capabilities (commits 17–19)** — typed metavariable
`$X as T` + `metavariable-type` registration, metavariables inside
string interpolations, function-def pattern matching.
5. **Cleanup (commit 15)** — drop the stale segfault gate in
`Parse_target.ml` and the `Lang.Dart` exclusion in `Rule_fetching.ml`.
6. **Validation pointer (commit 16)** — _temporary_ redirect of
`.gitmodules` so this branch resolves the validation artifact from
`AlexLaroche/semgrep-dart`. **Drop before merge.**
7. **Style (commit 20)** — `style(dart): apply ocamlformat 0.29.0` to
satisfy CI's `lint-ocaml` hook (CI uses 0.29.0; recent edits were made
with a local 0.27.0 whose `break-cases` differs).
8. **Tests (commits 21–22)** — 8 new tests covering every fix and
capability above (table in the previous section).

## Before marking ready for review

- [x] semgrep/ocaml-tree-sitter-semgrep#590
lands (bumps the upstream tree-sitter-dart submodule there to
`02e9bb19`).
- [x] An r2c admin runs `./release dart` on `ocaml-tree-sitter-semgrep`
to publish a real release commit on `semgrep/semgrep-dart`.
- [x] Drop the `chore(dart): point semgrep-dart submodule URL at fork
for validation` commit.
- [x] Re-point the submodule pointer from `c5a5e6c1` (on
`AlexLaroche/semgrep-dart`) to whatever real release SHA appears on
`semgrep/semgrep-dart`.
- [ ] CI green on this repo.

## Test plan

- [x] `make core` clean against the bumped submodule.
- [x] Dart lang-parsing tests pass; Dart sgrep-pattern tests pass.
- [x] Standalone `parse-dart`: 199/199 files in `flutter/flutter@master`
parse cleanly (was 196/199).
- [x] pub.dev: 5,229/5,285 fully clean (was ~5,183), 56 `PartialParsing`
(was ~102).
- [x] Original "segfault" repro (`: string (* filename *)`) — exits
cleanly, no signal, on both `parse-dart` and `semgrep-core
-dump_pattern`.
- [x] Pre-commit `lint-ocaml` hook passes locally with ocamlformat
0.29.0.
- [ ] CI on this repo (semgrep/semgrep).

Synced from OSS PR #11678
Author: @AlexLaroche
Imported by: @yosefAlsuhaibani

Closes #11678
OSS-sync-author: Alexandre Laroche <larochealexandre@hotmail.com>

Test plan:

synced from Pro df36084f8b8ee40724eab0322e710c3369efe6f5
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants