Skip to content

chore: Keep ExecuteDynamicCode editor sources under 500 lines - #1781

Merged
hatayama merged 3 commits into
feature/god-class-split-integrationfrom
feat/split-execute-dynamic-code
Jul 14, 2026
Merged

hatayama merged 3 commits into
feature/god-class-split-integrationfrom
feat/split-execute-dynamic-code

Conversation

@hatayama

@hatayama hatayama commented Jul 14, 2026 •

Copy link
Copy Markdown
Owner

Summary

  • Split three ExecuteDynamicCode god classes so each implementation file stays under 500 lines without changing runtime behavior.
  • Added characterization tests first so Rewrite/Analyze/WrapIfNeeded outputs stay locked across the Extract Class refactor.

User Impact

  • No user-facing behavior change. Dynamic code execution, compilation worker host, and source shaping behave as before.
  • Maintainability improves for future ExecuteDynamicCode fixes by separating scanning, unescaping, token scanning, and worker process startup.

Changes

  • DynamicCodeLiteralHoister → hoisting orchestration + DynamicCodeLiteralSyntaxScanner + DynamicCodeRegularStringLiteralUnescaper
  • SourceShaper → structure analysis/wrap + SourceTokenScanner
  • SharedRoslynCompilerWorkerHost → orchestration + SharedRoslynCompilerWorkerHostProcess + SharedRoslynCompilerWorkerHostResults
  • Characterization tests for Hoister/SourceShaper committed before the split commits

Verification

  • dist/darwin-arm64/uloop compile → 0 errors, 0 warnings
  • wc -l on target + extracted files: all < 500
  • uloop run-tests EditMode filter DynamicCode/SourceShaper/SharedRoslynCompilerWorker… → 232 passed
  • dotnet test tests/UnityCliLoop.CodeComplexity.Tests → 12 passed

Made with Cursor

Review in cubic

hatayama and others added 2 commits July 14, 2026 17:18
…aper

Lock current Rewrite/Analyze/WrapIfNeeded outputs before splitting the god classes so behavior stays pinned across Extract Class refactors.

Co-authored-by: Cursor <cursoragent@cursor.com>
Extract Class on DynamicCodeLiteralHoister, SourceShaper, and SharedRoslynCompilerWorkerHost so each file has one clear responsibility while keeping Rewrite/Analyze/WrapIfNeeded and worker host APIs behaviorally unchanged.

Co-authored-by: Cursor <cursoragent@cursor.com>
@coderabbitai

coderabbitai Bot commented Jul 14, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@hatayama, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 1 minute

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 8b549a0c-3f5d-4899-9822-3e544bf364df

📥 Commits

Reviewing files that changed from the base of the PR and between 9eb5a64 and 1eb65fa.

📒 Files selected for processing (3)
  • Assets/Tests/Editor/DynamicCodeToolTests/DynamicCodeLiteralHoisterCharacterizationTests.cs
  • Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/DynamicCompilation/SourceShaper.cs
  • Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/DynamicCompilation/SourceTokenScanner.cs
📝 Walkthrough

Walkthrough

Changes

Dynamic code literal rewriting

Layer / File(s) Summary
Literal scanning and unescaping
Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/DynamicCompilation/DynamicCodeLiteralSyntaxScanner.cs, Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/DynamicCompilation/DynamicCodeRegularStringLiteralUnescaper.cs
Adds shared scanning for C# literals/comments and decoding for regular-string escape sequences.
Hoister delegation and coverage
Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/DynamicCompilation/DynamicCodeLiteralHoister.cs, Assets/Tests/Editor/DynamicCodeToolTests/DynamicCodeLiteralHoisterCharacterizationTests.cs
Delegates literal handling to the shared utilities and characterizes hoisting, ordering, escaping, and inline literal behavior.

Source shaping scanner extraction

Layer / File(s) Summary
Source token scanning
Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/DynamicCompilation/SourceTokenScanner.cs
Adds comment, literal, statement, block, attribute, and brace-aware source traversal helpers.
SourceShaper integration and characterization
Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/DynamicCompilation/SourceShaper.cs, Assets/Tests/Editor/DynamicCodeToolTests/SourceShaperCharacterizationTests.cs
Routes SourceShaper scanning through SourceTokenScanner and tests analysis and wrapper behavior.

Shared Roslyn worker lifecycle

Layer / File(s) Summary
Worker process controller and results
Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/DynamicCompilation/SharedRoslynCompilerWorkerHostProcess.cs, Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/DynamicCompilation/SharedRoslynCompilerWorkerHostResults.cs
Adds worker path, build, startup, lifecycle, and structured result handling.
Host delegation and shutdown wiring
Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/DynamicCompilation/SharedRoslynCompilerWorkerHost.cs
Moves readiness and path operations from the host into the extracted process controller.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 1.64% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately captures the main change: shrinking ExecuteDynamicCode editor source files under 500 lines.
Description check ✅ Passed The description is clearly related to the refactor and characterization tests in this changeset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/split-execute-dynamic-code

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Add characterization coverage for terminated and unterminated block comments around the rewritten TryCopy* path, and move SkipWhitespace into SourceTokenScanner so scanning no longer depends back on SourceShaper.

Co-authored-by: Cursor <cursoragent@cursor.com>

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 2

🧹 Nitpick comments (2)
Assets/Tests/Editor/DynamicCodeToolTests/DynamicCodeLiteralHoisterCharacterizationTests.cs (1)

10-194: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add characterization coverage for escape variants and comments.

Existing tests cover ints/strings/verbatim/char/interpolated/decimal/comments, but the newly extracted DynamicCodeRegularStringLiteralUnescaper and DynamicCodeLiteralSyntaxScanner also handle \x, \u, \U escapes, block comments, and nested-brace interpolation expressions — none of which are pinned here. Given this PR's stated goal is to lock existing behavior before splitting these classes, a few more cases (e.g. "\u0041", "\x41", /* block */, $"{new[]{1,2}}") would strengthen the safety net for exactly the logic that moved.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@Assets/Tests/Editor/DynamicCodeToolTests/DynamicCodeLiteralHoisterCharacterizationTests.cs`
around lines 10 - 194, Add characterization tests in
DynamicCodeLiteralHoisterCharacterizationTests covering regular string literals
with \x, \u, and \U escapes and asserting their unescaped binding values; add a
block-comment case confirming comments remain intact while literals are hoisted;
and add a nested-brace interpolated-string case confirming the complete
interpolation remains opaque with no bindings.
Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/DynamicCompilation/SourceTokenScanner.cs (1)

33-58: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicate comment-skipping logic between TryMatch* and TryAdvance*.

TryMatchLineComment/TryMatchBlockComment (Lines 33-58) reimplement the exact same scanning logic as the private TryAdvanceLineComment/TryAdvanceBlockComment (Lines 156-178), just with an out-param instead of a tuple return. Two independent implementations of the same rule invite silent divergence during future edits.

♻️ Suggested consolidation
 internal static bool TryMatchLineComment(string s, int pos, out int afterComment)
 {
-    afterComment = pos;
-    if (pos + 1 < s.Length && s[pos] == '/' && s[pos + 1] == '/')
-    {
-        int end = pos + 2;
-        while (end < s.Length && s[end] != '\n') end++;
-        if (end < s.Length) end++; // skip \n
-        afterComment = end;
-        return true;
-    }
-    return false;
+    (bool matched, int nextPosition) = TryAdvanceLineComment(s, pos);
+    afterComment = matched ? nextPosition : pos;
+    return matched;
 }

Apply the same pattern to TryMatchBlockComment / TryAdvanceBlockComment.

Also applies to: 134-178

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/DynamicCompilation/SourceTokenScanner.cs`
around lines 33 - 58, Consolidate the duplicate scanning logic by updating
TryMatchLineComment and TryMatchBlockComment to reuse the corresponding
TryAdvanceLineComment and TryAdvanceBlockComment implementations, adapting their
tuple results to the existing out-parameter contract. Remove the independent
comment-scanning loops while preserving the current success/failure behavior and
computed positions.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/DynamicCompilation/SourceTokenScanner.cs`:
- Around line 10-31: Move the pure whitespace-scanning implementation into
SourceTokenScanner and update SkipWhitespaceAndComments to call that local
primitive instead of SourceShaper.SkipWhitespace. Retain
SourceShaper.SkipWhitespace as a thin delegate to SourceTokenScanner so existing
callers remain unchanged while the dependency points only from SourceShaper to
the low-level scanner.
- Around line 134-268: Update AdvanceOneToken and the interpolated-string
scanning helpers to recognize combined prefixes $@"...", @$", and raw
interpolated forms with one or more $ characters before triple quotes. Route
verbatim forms through verbatim quote semantics and raw forms through the
appropriate raw interpolated scanner, ensuring each token stops at its actual
closing delimiter while preserving existing handling for regular interpolated
strings.

---

Nitpick comments:
In
`@Assets/Tests/Editor/DynamicCodeToolTests/DynamicCodeLiteralHoisterCharacterizationTests.cs`:
- Around line 10-194: Add characterization tests in
DynamicCodeLiteralHoisterCharacterizationTests covering regular string literals
with \x, \u, and \U escapes and asserting their unescaped binding values; add a
block-comment case confirming comments remain intact while literals are hoisted;
and add a nested-brace interpolated-string case confirming the complete
interpolation remains opaque with no bindings.

In
`@Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/DynamicCompilation/SourceTokenScanner.cs`:
- Around line 33-58: Consolidate the duplicate scanning logic by updating
TryMatchLineComment and TryMatchBlockComment to reuse the corresponding
TryAdvanceLineComment and TryAdvanceBlockComment implementations, adapting their
tuple results to the existing out-parameter contract. Remove the independent
comment-scanning loops while preserving the current success/failure behavior and
computed positions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ef322649-f4fe-4b54-beea-c07d8a89543f

📥 Commits

Reviewing files that changed from the base of the PR and between 0dffc75 and 9eb5a64.

⛔ Files ignored due to path filters (7)
  • Assets/Tests/Editor/DynamicCodeToolTests/DynamicCodeLiteralHoisterCharacterizationTests.cs.meta is excluded by none and included by none
  • Assets/Tests/Editor/DynamicCodeToolTests/SourceShaperCharacterizationTests.cs.meta is excluded by none and included by none
  • Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/DynamicCompilation/DynamicCodeLiteralSyntaxScanner.cs.meta is excluded by none and included by none
  • Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/DynamicCompilation/DynamicCodeRegularStringLiteralUnescaper.cs.meta is excluded by none and included by none
  • Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/DynamicCompilation/SharedRoslynCompilerWorkerHostProcess.cs.meta is excluded by none and included by none
  • Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/DynamicCompilation/SharedRoslynCompilerWorkerHostResults.cs.meta is excluded by none and included by none
  • Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/DynamicCompilation/SourceTokenScanner.cs.meta is excluded by none and included by none
📒 Files selected for processing (10)
  • Assets/Tests/Editor/DynamicCodeToolTests/DynamicCodeLiteralHoisterCharacterizationTests.cs
  • Assets/Tests/Editor/DynamicCodeToolTests/SourceShaperCharacterizationTests.cs
  • Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/DynamicCompilation/DynamicCodeLiteralHoister.cs
  • Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/DynamicCompilation/DynamicCodeLiteralSyntaxScanner.cs
  • Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/DynamicCompilation/DynamicCodeRegularStringLiteralUnescaper.cs
  • Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/DynamicCompilation/SharedRoslynCompilerWorkerHost.cs
  • Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/DynamicCompilation/SharedRoslynCompilerWorkerHostProcess.cs
  • Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/DynamicCompilation/SharedRoslynCompilerWorkerHostResults.cs
  • Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/DynamicCompilation/SourceShaper.cs
  • Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/DynamicCompilation/SourceTokenScanner.cs

@hatayama

Copy link
Copy Markdown
Owner Author

Review disposition (merge gate)

  • Fable final review: LGTM after required block-comment characterization tests + SkipWhitespace untangle (1eb65fa)
  • Autoreview: clean (0 actionable)
  • CodeRabbit status check: pass
  • CodeRabbit inline:
    1. Circular SkipWhitespace → already fixed in 1eb65fa
    2. Combined interpolated prefixes ($@/@$/raw) → pre-existing, move-only; deferred (not introduced by this PR)
    3. Nitpicks (more escape tests / comment-helper consolidation) → deferred as non-blocking

Merging to feature/god-class-split-integration.

@hatayama
hatayama merged commit 8027c30 into feature/god-class-split-integration Jul 14, 2026
2 checks passed
@hatayama
hatayama deleted the feat/split-execute-dynamic-code branch July 14, 2026 08:44
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