Skip to content

[c-sharp] fix Semgrep pattern parsing for top-level expressions, declarations, and ellipsis positions - #584

Draft
brandonspark wants to merge 1 commit into
mainfrom
fix/c-sharp-pattern-augmentation
Draft

[c-sharp] fix Semgrep pattern parsing for top-level expressions, declarations, and ellipsis positions#584
brandonspark wants to merge 1 commit into
mainfrom
fix/c-sharp-pattern-augmentation

Conversation

@brandonspark

Copy link
Copy Markdown
Contributor

Summary

Augments lang/semgrep-grammars/src/semgrep-c-sharp/grammar.js so several
modern C# pattern shapes that previously errored at parse time are now
admitted by the grammar.

Changes

  • Top-level bare _expression alternative on compilation_unit so
    patterns without a trailing ; parse: $X is null,
    $X with { ... }, $X is { $P: $V },
    from $X in $Y where $C select $E.
  • Top-level bare property_declaration alternative so
    public $T $P { get; init; } parses (instead of being mis-tokenized
    as local_declaration_statement + stray block).
  • expression_statement extended to accept C# 7/8/9+ expression
    shapes that the upstream _expression_statement_expression rejects:
    is_pattern_expression, interpolated_string_expression,
    lambda_expression, conditional_access_expression,
    type_of_expression, element_access_expression, and
    range_expression.
  • switch_expression_arm accepts $.ellipsis so
    $X switch { $P => $E, ... } parses.
  • type_parameter accepts $.ellipsis so class $C<...> { } parses.

The new top-level alternatives are gated with strongly negative
prec.dynamic so ordinary C# code still resolves through the existing
previous path. Targeted conflicts entries disambiguate the small
number of unavoidable overlaps.

Tickets

  • Closes LANG-478 (top-level expression patterns).
  • Closes LANG-484 (top-level LINQ + property declarations).
  • Partially addresses LANG-494 (augmentation parts only):
    switch-arm ... and <...> type-parameter ellipsis are fixed here.
    The I$I metavariable+identifier concatenation case from LANG-494
    is deferred — it is labeled fix:scanner-or-entrypoint upstream and
    requires scanner-level work (token.immediate for zero-width
    adjacency, or pattern-preprocessing in semgrep-core).

Test plan

  • make build && make test passes (188 corpus tests, 15 new).
  • tree-sitter parse spot-checked on every pattern listed in the
    three Linear tickets.
  • Wait for CI on this PR.
  • Land the companion semgrep-c-sharp SHA bump in
    semgrep/semgrep-c-sharp.

…arations, and ellipsis positions

Extend `lang/semgrep-grammars/src/semgrep-c-sharp/grammar.js` so several
modern C# pattern shapes that previously errored at parse time are now
admitted by the grammar:

- Top-level bare expression alternative on `compilation_unit`: covers
  patterns without a trailing `;` like `$X is null`, `$X with { ... }`,
  `$X is { $P: $V }`, `from $X in $Y where $C select $E`.
- Top-level bare `property_declaration` alternative: covers patterns
  like `public $T $P { get; init; }` that were mis-parsed as a
  `local_declaration_statement` followed by a stray block.
- `expression_statement` extended with the C# 7/8/9+ expression shapes
  that upstream's `_expression_statement_expression` rejects, so
  `$X is $T $Y;`, `$"hello {$X}";`, `($X) => $E;`, `$X?.$Y;`,
  `typeof($T);`, `$X[..$Y];`, `$X..$Y;`, and `init $X => $Y;` all parse.
- `switch_expression_arm` accepts `$.ellipsis` so
  `$X switch { $P => $E, ... }` parses.
- `type_parameter` accepts `$.ellipsis` so `class $C<...> { }` parses.

The new top-level alternatives are gated with strongly negative
`prec.dynamic` so that ordinary C# code still resolves through the
existing `previous` (i.e. `global_statement` /
`_namespace_member_declaration`) path. Targeted `conflicts` entries
disambiguate where the new alternatives unavoidably overlap with the
upstream rules.

Closes LANG-478, LANG-484. Partially addresses LANG-494 (the augmentation
parts: switch-arm `...` and `<...>` type-parameter ellipsis). The
`I$I` metavariable+identifier concatenation case from LANG-494 is
deferred — it requires scanner-level work (token immediacy /
`token.immediate`) and is labeled `fix:scanner-or-entrypoint` upstream.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.

1 participant