Skip to content

perf: replace O(n) indexOf+children with O(1) nextSibling traversal in C# analyzer - #499

Merged
askpt merged 2 commits into
mainfrom
repo-assist/perf-sibling-traversal-O1-csharp-20260803-612a2d3fca09cbed
Aug 3, 2026
Merged

perf: replace O(n) indexOf+children with O(1) nextSibling traversal in C# analyzer#499
askpt merged 2 commits into
mainfrom
repo-assist/perf-sibling-traversal-O1-csharp-20260803-612a2d3fca09cbed

Conversation

@github-actions

@github-actions github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

🤖 This pull request was created by Repo Assist, an automated AI assistant.

Summary

Eliminates two O(n) linear scans over parent.children in CSharpMetricsAnalyzer by replacing them with direct nextSibling pointer walks (O(1) per step in tree-sitter's underlying C structure).

Changes

src/metricsAnalyzer/languages/csharpAnalyzer.ts

1. getMethodBody — preprocessor sibling search

Previously:

const methodIndex = parent.children.indexOf(node);  // O(n) scan
for (let i = methodIndex + 1; i < parent.children.length; i++) {
  const sibling = parent.children[i];
  ...
}

Now:

let sibling = node.nextSibling;  // O(1) pointer walk
while (sibling) {
  ...
  sibling = sibling.nextSibling;
}

2. hasMatchingColonInSiblings — ternary colon detection

Previously:

const errorIndex = parent.children.indexOf(errorNode);  // O(n) scan
for (let i = errorIndex + 1; i < Math.min(errorIndex + 3, ...); i++) {
  const sibling = parent.children[i];
  ...
}

Now:

let sibling = errorNode.nextSibling;  // O(1) pointer walk
for (let steps = 0; sibling && steps < 2; steps++, sibling = sibling.nextSibling) {
  ...
}

Also simplifies the parent-null guard in hasMatchingColonInSiblings (no longer needs parent at all since nextSibling handles missing siblings gracefully).

Rationale

Array.prototype.indexOf walks the entire children array to find the node. In large C# classes with many members, this linear scan runs every time a preprocessor-split method or ternary in an ERROR node is encountered. The SyntaxNode.nextSibling property in tree-sitter is a constant-time pointer dereference, making both paths run in O(k) where k is bounded by either the class size found (early exit on preproc_if or another method) or 2 (the fixed step limit for colon detection).

Test Status

npm run compile  ✅  (0 errors)
npm run lint     ✅  (0 warnings)
npm run test:unit  ✅  201 passing, 0 failing

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • releaseassets.githubusercontent.com

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "releaseassets.githubusercontent.com"

See Network Configuration for more information.

Generated by 🌈 Repo Assist, see workflow run. Learn more.
Comment /repo-assist to run again

Add this agentic workflow to your repo

To install this agentic workflow, run

gh aw add githubnext/agentics/workflows/repo-assist.md@42c2ab5b4e4c9273534c39259b2e0df7f20f07e9

…n C# analyzer

In CSharpMetricsAnalyzer two methods used parent.children.indexOf(node) which
is an O(n) linear scan over the children array:

1. getMethodBody: when searching for a preproc_if sibling after a split method,
   previously called parent.children.indexOf(node) then iterated by index.
   Now uses node.nextSibling directly, eliminating both the O(n) indexOf scan
   and the intermediate children array allocation.

2. hasMatchingColonInSiblings: previously called parent.children.indexOf(errorNode)
   then iterated over the next 2 children by index.  Now walks errorNode.nextSibling
   directly for up to 2 steps.

tree-sitter SyntaxNode.nextSibling is O(1) (it is a pointer walk in the underlying
C structure), so both hot paths now run in O(k) where k ≤ 2 or k = number of
preprocessor siblings found — independent of class size.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@askpt askpt changed the title [repo-assist] perf: replace O(n) indexOf+children with O(1) nextSibling traversal in C# analyzer perf: replace O(n) indexOf+children with O(1) nextSibling traversal in C# analyzer Aug 3, 2026
@codecov

codecov Bot commented Aug 3, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 75.00000% with 5 lines in your changes missing coverage. Please review.
✅ Project coverage is 81.46%. Comparing base (fd7d1f7) to head (badb8e2).

Files with missing lines Patch % Lines
src/metricsAnalyzer/languages/csharpAnalyzer.ts 75.00% 5 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #499      +/-   ##
==========================================
+ Coverage   81.37%   81.46%   +0.08%     
==========================================
  Files          13       13              
  Lines        4366     4354      -12     
  Branches      442      441       -1     
==========================================
- Hits         3553     3547       -6     
+ Misses        812      806       -6     
  Partials        1        1              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@askpt
askpt marked this pull request as ready for review August 3, 2026 08:40
@askpt
askpt self-requested a review as a code owner August 3, 2026 08:40
Copilot AI review requested due to automatic review settings August 3, 2026 08:40

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Not ready to approve

The new sibling-walk stop condition still only breaks on class/interface declarations and should also stop on other type declarations (struct/record/enum) to avoid mis-associating a later preproc_if as the method body.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.

Pull request overview

Optimizes the C# cognitive complexity analyzer’s tree-sitter AST traversal by replacing parent.children.indexOf(...) + indexed loops with nextSibling pointer walks, reducing repeated linear scans when handling preprocessor-split method bodies and fragmented ternary operators.

Changes:

  • Updated getFunctionBody to search for preproc_if using node.nextSibling traversal instead of scanning parent.children.
  • Updated hasMatchingColonInSiblings to check up to two nextSiblings instead of scanning via indexOf + bounds math.
File summaries
File Description
src/metricsAnalyzer/languages/csharpAnalyzer.ts Replaces sibling lookup loops that depend on parent.children.indexOf with nextSibling traversal for better performance in C# AST analysis.
Review details
  • Files reviewed: 1/1 changed files
  • Comments generated: 1
  • Review effort level: Lite

We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.

Comment thread src/metricsAnalyzer/languages/csharpAnalyzer.ts Outdated
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@askpt
askpt merged commit ed4f8b0 into main Aug 3, 2026
9 checks passed
@askpt
askpt deleted the repo-assist/perf-sibling-traversal-O1-csharp-20260803-612a2d3fca09cbed branch August 3, 2026 08:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants