Skip to content

feat(extractor): accept .csproj/.sln input (roslyn-tools CLI-first project resolution)#139

Merged
PhysShell merged 4 commits into
mainfrom
claude/roslyn-tools-own-net-l36cwp
Jun 27, 2026
Merged

feat(extractor): accept .csproj/.sln input (roslyn-tools CLI-first project resolution)#139
PhysShell merged 4 commits into
mainfrom
claude/roslyn-tools-own-net-l36cwp

Conversation

@PhysShell

@PhysShell PhysShell commented Jun 27, 2026

Copy link
Copy Markdown
Owner

Что и зачем

Prompted by "could dotnet/roslyn-tools give us a ready-made C# frontend?" — the verdict (in docs/notes/roslyn-tools-and-cli.md) is no: it's engineering scaffolding, not an analysis source. This PR ships the first borrowable plyushka from its tooling shape: CLI-first project/solution input.

The OwnSharp Roslyn extractor previously accepted only .cs files/dirs, while the README/note already advertised --project App.csproj. This makes that real, keeping the seam intact: the C# side stays a fact extractor (emits OwnIR facts); the verdict still comes from the Python core (python -m ownlang ownir). A .csproj only changes which files are read, not who decides ownership.

Changes

  • OwnSharp.Extractor/Program.cs:
    • ProjectCsFiles — resolves a .csproj to its source set dependency-free (directory scan of *.cs, SDK default-compile-items), honouring <EnableDefaultCompileItems>false> and <Compile Remove="..."> via a small glob translator (SpecMatcher), plus concrete linked <Compile Include> outside the tree. No MSBuild evaluation.
    • SolutionProjects — quote-aware parse of a classic .sln, fanning out over member projects.
    • Wired into Expand; --project / --solution flag aliases beside the positional form.
  • frontend/roslyn/project-input-sample/ — an SDK .csproj + an injected-bus event leak (outside samples/ so it doesn't perturb directory-scan CI jobs).
  • CI wpf-extractor: a step asserting OWN001 surfaces via the .csproj, with positional == --project parity at the OwnIR fact boundary (jq -S).
  • README + the roslyn-tools note: document the input forms; mark this plyushka landed; re-aim the next PR at extract/check/explain subcommands.

The full project/package/reference graph (real MSBuild evaluation) is deliberately deferred — that's the ProjectDependencies-category work for DI/solution scans, not the v0 leak extractor.

Тип изменения

  • Новая возможность (feature) — .csproj/.sln input
  • Исправление бага
  • Рефакторинг / тех-долг
  • Документация
  • CI / инфраструктура

Проверка

  • No dotnet in the dev sandbox, so the C# extractor compiles/runs only in CI — the new wpf-extractor step exercises the .csproj path there. New code is file/XML/text only (no Roslyn-analysis changes) to bound that blind spot.
  • The Python bridge (locally runnable) was verified against a facts file mirroring the new sample: renders CustomerSubscription.cs:12: warning: [OWN001] …, matching the CI assertions.
  • The SpecMatcher glob translation was validated against the common forms (*.cs, **/*.cs, Folder/**, concrete paths) before commit.
  • ci.yml (YAML) and the new .csproj (XML) parse cleanly.

Связанный issue

Нет связанного issue — продолжение P-001 / docs/notes/roslyn-tools-and-cli.md (the "Next PR" named there).

Чеклист

  • Код собирается / тесты проходят (Python core + bridge locally; C# extractor via CI)
  • Документация обновлена (README, roslyn-tools note)
  • Добавлен CI-голден на новую возможность (project-file input + fact-level parity)
  • Учтены замечания ботов (Codex P2 + CodeRabbit ×3)
  • Принцип "один чекер" сохранён — C# extractor только эмитит факты

Review follow-ups addressed

  • Codex P2 — a missing/typo'd .csproj no longer directory-scans the parent (84e4d6e).
  • CodeRabbit (Major)ProjectCsFiles honours explicit compile-set exclusions (3ec8bc7).
  • CodeRabbit (Major).sln parsing is quote-aware, not comma-split (3ec8bc7).
  • CodeRabbit (Minor) — CI parity asserted at the fact boundary via jq -S (3ec8bc7).

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • The Roslyn extractor now accepts .csproj and .sln inputs via both positional paths and --project / --solution flags.
  • Bug Fixes
    • Improved .csproj/.sln expansion: handles default compile items, explicit <Compile> links, skip rules, parse failures (falls back), and missing/unreadable inputs (skips with warnings).
  • Documentation
    • Updated CLI docs and README with the dependency-free resolution approach and supported input types.
  • Tests
    • CI validates .csproj input mode correctness and ensures flag vs positional invocations produce identical extracted outputs.

…oject resolution)

The first borrowed plyushka from the roslyn-tools tooling shape: the OwnSharp
Roslyn extractor now takes a .csproj or .sln as input (positional, or via
--project / --solution), not just a .cs file list. ProjectCsFiles resolves a
project to its source set the dependency-free way — scan the project directory
for *.cs (SDK default-compile-items) plus concrete linked <Compile> files, no
MSBuild evaluation; SolutionProjects fans a .sln out over its member projects.
This deliberately stops short of the full project/package/reference graph (the
ProjectDependencies-category work parked for DI/solution scans).

- Program.cs: ProjectCsFiles + SolutionProjects helpers, wired into Expand;
  --project/--solution flag aliases; usage text updated.
- New project-input-sample/ (outside samples/ so it doesn't perturb the
  directory-scan jobs): an SDK csproj + an injected-bus event leak.
- CI wpf-extractor: a step pinning the .csproj path to a golden, asserting the
  leak surfaces as OWN001 and that positional == --project.
- README + roslyn-tools-and-cli note: document the input forms; mark this
  plyushka landed and re-aim the next PR at extract/check/explain subcommands.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KzA6KGQVRzP52tBEKwJ3SW
@coderabbitai

coderabbitai Bot commented Jun 27, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 826186bc-690e-4575-9d21-47730025ebe9

📥 Commits

Reviewing files that changed from the base of the PR and between 3ec8bc7 and 38cc90f.

📒 Files selected for processing (1)
  • frontend/roslyn/OwnSharp.Extractor/Program.cs
🚧 Files skipped from review as they are similar to previous changes (1)
  • frontend/roslyn/OwnSharp.Extractor/Program.cs

📝 Walkthrough

Walkthrough

The extractor now accepts .csproj and .sln inputs via positional arguments or --project/--solution, resolves them to .cs files without MSBuild evaluation, and adds a sample project plus CI and docs updates that exercise and describe the new input forms.

Changes

Roslyn project input support

Layer / File(s) Summary
CLI parsing and resolution
frontend/roslyn/OwnSharp.Extractor/Program.cs
Adds .csproj/.sln input forms, resolves them into .cs files, and wires the new branches into Expand(...).
Sample project fixture
frontend/roslyn/project-input-sample/ProjectInputSample.csproj, frontend/roslyn/project-input-sample/CustomerSubscription.cs
Adds the sample SDK-style project and event-bus subscription types used as project-file input content.
CI and docs
.github/workflows/ci.yml, docs/notes/roslyn-tools-and-cli.md, frontend/roslyn/README.md
Adds CI checks for project-file input and updates the Roslyn CLI/input documentation.

Sequence Diagram(s)

sequenceDiagram
  participant ownsharp-extract
  participant Expand
  participant ProjectCsFiles
  participant SolutionProjects

  ownsharp-extract->>Expand: raw input list
  Expand->>ProjectCsFiles: resolve .csproj input
  ProjectCsFiles-->>Expand: .cs files from scan and linked <Compile>
  Expand->>SolutionProjects: resolve .sln input
  SolutionProjects-->>Expand: member .csproj paths
  Expand-->>ownsharp-extract: expanded .cs file set
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

(_/)
( •_•) I hopped through projects, one by one,
/ >🍃 .csproj and .sln were fun.
extract and check went off to play,
and OWN001 blinked bright today.

Possibly related PRs

  • PhysShell/Own.NET#25: Updates the Roslyn CLI/documentation contract around project input handling in the same area of the codebase.
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes adding .csproj/.sln input support to the Roslyn extractor.
Description check ✅ Passed The description covers the required sections, including purpose, type, verification, issue, and checklist.
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 docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/roslyn-tools-own-net-l36cwp

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

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a2c7d6270e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

var full = Path.GetFullPath(csproj);
var dir = Path.GetDirectoryName(full) ?? ".";
var result = new List<string>();
foreach (var f in Directory.EnumerateFiles(dir, "*.cs", opts))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Do not scan a directory when the project file is missing

When a direct .csproj input is misspelled or otherwise absent, ProjectCsFiles derives the parent directory and enumerates every *.cs under it before XDocument.Load(full) reports the missing project. For example, ownsharp-extract --project src/Missing.csproj will analyze src/**/*.cs (or throw if src also does not exist) instead of skipping/failing the bad input, so a typo can produce diagnostics for an unintended source set.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Good catch — fixed in 84e4d6e. ProjectCsFiles now guards on File.Exists(full) before deriving the directory: a missing project warns (project not found: …) and returns empty, so a typo'd --project src/Missing.csproj no longer analyses src/**/*.cs. The directory-scan fallback is now reserved for a present-but-malformed project (one whose <Compile> links we couldn't read), never an absent one.


Generated by Claude Code

…odex P2)

ProjectCsFiles built the parent-directory *.cs scan before loading the project
XML, so a typo'd `--project src/Missing.csproj` would analyse all of src/**/*.cs
(or throw if src is also absent) instead of skipping the bad input. Guard on
File.Exists up front: a missing project warns and returns empty. The
directory-scan fallback now applies only to a present-but-malformed project
(whose <Compile> links could not be read), never an absent one.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KzA6KGQVRzP52tBEKwJ3SW

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 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 @.github/workflows/ci.yml:
- Around line 964-970: The current CI check in the workflow only compares the
rendered `ownlang ownir` diagnostics, which can hide differences between the
positional input and the `--project` path. Update the parity assertion around
the `dotnet run` invocation for OwnSharp.Extractor to compare the canonicalized
`proj-facts.json` and `proj-facts-flag.json` outputs directly, using the
existing `proj-facts*` artifacts, so the test verifies extractor equivalence at
the fact boundary rather than after Python normalization.

In `@frontend/roslyn/OwnSharp.Extractor/Program.cs`:
- Around line 125-167: The ProjectCsFiles source-set resolution is
over-inclusive because it scans every in-tree *.cs before considering the
project’s explicit compile set. Update ProjectCsFiles to derive files from the
.csproj’s actual Compile items and respect exclusions like
EnableDefaultCompileItems=false and <Compile Remove=...>, while still handling
explicit linked <Compile Include=...> entries; keep the existing unique paths
logic in ProjectCsFiles, IsSkipped, and the XML parsing flow, but change the
default scan to not treat all in-tree files as compiled input.
- Around line 193-196: The solution-entry parsing in
Program.ParseSolutionEntries is splitting on raw commas, which breaks quoted
`Project(...)= "Name", "relpath", "{guid}"` lines when names or paths contain
commas. Update the parsing logic to be quote-aware in this section so it
extracts the project path from the second quoted field without using a naive
Split(','); keep the change localized around the existing `t.Substring(eq + 1)`
/ `parts` handling.
🪄 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 Plus

Run ID: 74c45e07-fccb-4348-9fc2-f4ccaf722f3c

📥 Commits

Reviewing files that changed from the base of the PR and between 3867c4b and a2c7d62.

📒 Files selected for processing (6)
  • .github/workflows/ci.yml
  • docs/notes/roslyn-tools-and-cli.md
  • frontend/roslyn/OwnSharp.Extractor/Program.cs
  • frontend/roslyn/README.md
  • frontend/roslyn/project-input-sample/CustomerSubscription.cs
  • frontend/roslyn/project-input-sample/ProjectInputSample.csproj

Comment thread .github/workflows/ci.yml Outdated
Comment thread frontend/roslyn/OwnSharp.Extractor/Program.cs
Comment thread frontend/roslyn/OwnSharp.Extractor/Program.cs Outdated
… fact-level CI parity (CodeRabbit)

Addresses three CodeRabbit review findings on the .csproj/.sln input PR:

- ProjectCsFiles (Major): no longer treats every in-tree *.cs as compiled. It now
  honours <EnableDefaultCompileItems>false> (switch to include-driven) and
  <Compile Remove="..."> (subtract excluded files), matched via a small glob
  translator (SpecMatcher: concrete paths, *.cs, **/*.cs, Folder/**) — so .csproj
  input doesn't emit findings from files the project doesn't compile. Still no
  MSBuild evaluation.
- SolutionProjects (Major): replace the naive Split(',') with quote-aware field
  extraction (QuotedFields), so a comma inside a quoted project name/path no longer
  misreads the line.
- CI (Minor): assert positional == --project parity at the OwnIR fact boundary
  (jq -S canonicalized facts diff) instead of after Python normalization.

README updated to describe the honoured exclusions.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KzA6KGQVRzP52tBEKwJ3SW

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 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 `@frontend/roslyn/OwnSharp.Extractor/Program.cs`:
- Around line 132-155: Add a matchTimeout when constructing the Regex inside
SpecMatcher so glob-derived patterns cannot hang on pathological inputs. Update
the regex creation in Program.SpecMatcher to use a bounded timeout while keeping
the existing IgnoreCase behavior and path-relative matching logic unchanged.
🪄 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 Plus

Run ID: a613495a-891e-469b-b691-7421ca0ddc7f

📥 Commits

Reviewing files that changed from the base of the PR and between 84e4d6e and 3ec8bc7.

📒 Files selected for processing (3)
  • .github/workflows/ci.yml
  • frontend/roslyn/OwnSharp.Extractor/Program.cs
  • frontend/roslyn/README.md
✅ Files skipped from review due to trivial changes (1)
  • frontend/roslyn/README.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • .github/workflows/ci.yml

Comment thread frontend/roslyn/OwnSharp.Extractor/Program.cs
…deRabbit ReDoS)

.csproj <Compile Include>/<Compile Remove> globs are untrusted in CI; adjacent
wildcards (**/**, **/*) translate to ambiguous adjacent quantifiers the
backtracking .NET regex engine can blow up on. Construct the Regex with a 1s
matchTimeout, and catch RegexMatchTimeoutException in the predicate so a
pathological glob degrades to "no match" with a warning instead of crashing the
extractor.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KzA6KGQVRzP52tBEKwJ3SW
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