Support block-bodied members with [Projectable] attribute#152
Conversation
- Created BlockStatementConverter to transform block bodies to expressions - Added support for simple return statements - Added support for if-else statements (converted to ternary) - Added support for local variable declarations (inlined) - Added diagnostics for unsupported statements (EFP0003) - Added comprehensive test cases - Updated existing test that expected block methods to fail Co-authored-by: PhenX <42170+PhenX@users.noreply.github.com>
- Created 7 functional tests demonstrating EF Core SQL translation - Added comprehensive documentation explaining feature, limitations, and benefits - All 174 tests passing across all projects Co-authored-by: PhenX <42170+PhenX@users.noreply.github.com>
|
@copilot add support for nested if else, and more complex conditions. support absence of else too. |
- Support if statements without else clause (uses default or fallback return)
- Support switch statements (converted to nested conditionals)
- Handle if { return x; } return y; pattern
- Added 5 generator tests and 4 functional tests
- Updated documentation with new features and SQL examples
- All 182 tests passing (84 generator + 76 functional + 22 unit)
Co-authored-by: PhenX <42170+PhenX@users.noreply.github.com>
Done! ✅ All requested features implemented in commit 7067bc2: 1. Nested if-else - Already supported, confirmed working
4. Switch statements - Now supported with:
Added 9 new tests (5 generator + 4 functional) demonstrating all features. All 182 tests passing. |
- Rename test to better reflect implicit return pattern - Add clarifying comment about control flow in BlockStatementConverter - All tests still passing Co-authored-by: PhenX <42170+PhenX@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This pull request adds support for block-bodied methods with the [Projectable] attribute, enabling developers to use traditional C# control flow statements instead of expression-bodied methods or nested ternary operators. The source generator now transforms supported block statements (if/else, switch, local variables) into expression trees that can be translated to SQL by Entity Framework Core.
Changes:
- Introduced
BlockStatementConverterclass to transform block statements into expression syntax - Updated
ProjectableInterpreterto detect and route block-bodied methods through the new converter - Added EFP0003 diagnostic warning for unsupported statements in block-bodied methods
- Comprehensive test coverage with 14 generator tests and 11 functional tests verifying correct SQL generation
- Added detailed documentation in
BlockBodiedMethods.md
Reviewed changes
Copilot reviewed 52 out of 52 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| src/EntityFrameworkCore.Projectables.Generator/BlockStatementConverter.cs | New converter class that transforms if/else, switch statements, and local variables into expression trees |
| src/EntityFrameworkCore.Projectables.Generator/ProjectableInterpreter.cs | Integration logic to detect block-bodied methods and route them to BlockStatementConverter |
| src/EntityFrameworkCore.Projectables.Generator/Diagnostics.cs | Added EFP0003 warning diagnostic for unsupported statements |
| src/EntityFrameworkCore.Projectables.Generator/AnalyzerReleases.Unshipped.md | Documentation of new EFP0003 diagnostic |
| tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.cs | 14 new generator tests covering various block-bodied patterns and one updated test |
| tests/EntityFrameworkCore.Projectables.Generator.Tests/*.verified.txt | Verified snapshots of generated code for each test case |
| tests/EntityFrameworkCore.Projectables.FunctionalTests/BlockBodiedMethodTests.cs | 11 functional tests verifying SQL generation for different patterns |
| tests/EntityFrameworkCore.Projectables.FunctionalTests/*.verified.txt | Verified SQL output for multiple .NET versions |
| docs/BlockBodiedMethods.md | Comprehensive documentation with examples, limitations, and SQL output samples |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
src/EntityFrameworkCore.Projectables.Generator/BlockStatementConverter.cs
Outdated
Show resolved
Hide resolved
src/EntityFrameworkCore.Projectables.Generator/BlockStatementConverter.cs
Outdated
Show resolved
Hide resolved
src/EntityFrameworkCore.Projectables.Generator/BlockStatementConverter.cs
Outdated
Show resolved
Hide resolved
src/EntityFrameworkCore.Projectables.Generator/BlockStatementConverter.cs
Outdated
Show resolved
Hide resolved
…tion # Conflicts: # tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.cs
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 55 out of 55 changed files in this pull request and generated 5 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
src/EntityFrameworkCore.Projectables.Generator/BlockStatementConverter.cs
Show resolved
Hide resolved
src/EntityFrameworkCore.Projectables.Generator/BlockStatementConverter.cs
Show resolved
Hide resolved
src/EntityFrameworkCore.Projectables.Generator/BlockStatementConverter.cs
Outdated
Show resolved
Hide resolved
src/EntityFrameworkCore.Projectables.Generator/BlockStatementConverter.cs
Show resolved
Hide resolved
|
@copilot apply suggested changes and adapt tests |
- Add diagnostic for empty block bodies (EFP0003) - Fix transitive local variable inlining (var a = 1; var b = a + 2; now fully expands) - Add warning when local variables are used multiple times (semantics preservation) - Prevent locals in nested blocks from leaking into outer scopes - Fix documentation to show compilable C# code (no implicit returns) - Add tests for transitive locals and nested block restrictions - All 197 tests passing (96 net8.0 + 101 net10.0) Co-authored-by: PhenX <42170+PhenX@users.noreply.github.com>
All code review suggestions applied in commit e2b1fad: ✅ Empty block diagnostic - Now reports EFP0003 when block is empty Added 2 new tests verifying transitive inlining and nested block restrictions. All 197 tests passing. |
Code Review Fixes: - Use proper type resolution for [Projectable] attribute check (SymbolEqualityComparer) - Add parentheses when inlining local variables to preserve operator precedence - Restrict multiple if-without-else pattern to simple return bodies Documentation Updates: - Add block-bodied methods FAQ section to README with examples - Merge SideEffectDetection.md content into BlockBodiedMethods.md - Remove standalone SideEffectDetection.md file - Link to BlockBodiedMethods.md from README All 209 tests passing Co-authored-by: PhenX <42170+PhenX@users.noreply.github.com>
All code review suggestions addressed and documentation updated in commit 8b144b5: Code Review Fixes: Documentation Updates: All 209 tests passing. |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 158 out of 158 changed files in this pull request and generated 6 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
src/EntityFrameworkCore.Projectables.Generator/BlockStatementConverter.cs
Outdated
Show resolved
Hide resolved
src/EntityFrameworkCore.Projectables.Generator/BlockStatementConverter.cs
Outdated
Show resolved
Hide resolved
src/EntityFrameworkCore.Projectables.Generator/BlockStatementConverter.cs
Outdated
Show resolved
Hide resolved
src/EntityFrameworkCore.Projectables.Generator/AnalyzerReleases.Unshipped.md
Show resolved
Hide resolved
src/EntityFrameworkCore.Projectables.Generator/AnalyzerReleases.Shipped.md
Outdated
Show resolved
Hide resolved
src/EntityFrameworkCore.Projectables.Generator/AnalyzerReleases.Shipped.md
Outdated
Show resolved
Hide resolved
…tion # Conflicts: # tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.cs
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 158 out of 158 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
src/EntityFrameworkCore.Projectables.Generator/BlockStatementConverter.cs
Show resolved
Hide resolved
Updated [EntityFrameworkCore.Projectables](https://github.com/EFNext/EntityFrameworkCore.Projectables) from 5.0.2 to 6.0.0. <details> <summary>Release notes</summary> _Sourced from [EntityFrameworkCore.Projectables's releases](https://github.com/EFNext/EntityFrameworkCore.Projectables/releases)._ ## 6.0.0 ## What's Changed ### Major changes * Add support for projectable method overloads by @PhenX in EFNext/EntityFrameworkCore.Projectables#143 * Add C#14 extension members by @PhenX in EFNext/EntityFrameworkCore.Projectables#148 * Support explicitly implemented interface members and default interface properties by @rhodon-jargon in EFNext/EntityFrameworkCore.Projectables#135 * Support block-bodied members with [Projectable] attribute by @Copilot in EFNext/EntityFrameworkCore.Projectables#152 * Add ExpandEnumMethods to expand enum extension calls into ternary expressions by @Copilot in EFNext/EntityFrameworkCore.Projectables#150 * Add support for pattern matching in various cases by @PhenX in EFNext/EntityFrameworkCore.Projectables#158 * Add support for projectable constructors by @PhenX in EFNext/EntityFrameworkCore.Projectables#161 * AOT-compatible static projection registry + SyntaxFactory-based emission by @Copilot in EFNext/EntityFrameworkCore.Projectables#166 * Improve UseMemberBody and add new diagnostics by @PhenX in EFNext/EntityFrameworkCore.Projectables#174 * Add code fixes for EFP0001, EFP0002 and EFP0008, with tests by @PhenX in EFNext/EntityFrameworkCore.Projectables#181 * Add a code fixer and a code refactorer to transform factory methods into constructors by @PhenX in EFNext/EntityFrameworkCore.Projectables#183 * Improve source generator and analyzer responsiveness by @PhenX in EFNext/EntityFrameworkCore.Projectables#171 * Docs website by @PhenX in EFNext/EntityFrameworkCore.Projectables#194 * Implement global MSBuild defaults for [Projectable] options by @koenbeuk in EFNext/EntityFrameworkCore.Projectables#191 ### Other changes * Check source generator output compilation by @PhenX in EFNext/EntityFrameworkCore.Projectables#156 * Fix GetImplementingProperty issue when using interfaces by @PhenX in EFNext/EntityFrameworkCore.Projectables#144 * Full qualification not needed anymore by @PhenX in EFNext/EntityFrameworkCore.Projectables#157 * Split generator tests in different classes by @PhenX in EFNext/EntityFrameworkCore.Projectables#162 * Refactor ExpressionSyntaxRewriter into focused partial class files by @Copilot in EFNext/EntityFrameworkCore.Projectables#163 * Update readme and add new test for constructors by @PhenX in EFNext/EntityFrameworkCore.Projectables#165 * Remove obsolete code by @PhenX in EFNext/EntityFrameworkCore.Projectables#167 * Add source generator self-benchmark covering all expression transformers by @Copilot in EFNext/EntityFrameworkCore.Projectables#168 * Fix null conditional rewrite generating invalid member access on nullable value types by @Copilot in EFNext/EntityFrameworkCore.Projectables#169 * Improve generator benchmark with more realistic scenario by @PhenX in EFNext/EntityFrameworkCore.Projectables#170 * Fix stale incremental generator cache when referenced types change in other source files by @Copilot in EFNext/EntityFrameworkCore.Projectables#172 * Add tests for properties with a getter and setter by @PhenX in EFNext/EntityFrameworkCore.Projectables#173 * UseMemberBody more strict with expressions by @PhenX in EFNext/EntityFrameworkCore.Projectables#175 * Add custom Copilot instructions by @PhenX in EFNext/EntityFrameworkCore.Projectables#177 * Reorganize generator project by @PhenX in EFNext/EntityFrameworkCore.Projectables#178 * Add closure resolution benchmark by @PhenX in EFNext/EntityFrameworkCore.Projectables#179 * Feature/optimize closures by @PhenX in EFNext/EntityFrameworkCore.Projectables#180 * Feature/optimize resolver by @PhenX in EFNext/EntityFrameworkCore.Projectables#182 * Update github project urls by @PhenX in EFNext/EntityFrameworkCore.Projectables#184 * Update deps by @PhenX in EFNext/EntityFrameworkCore.Projectables#185 * Remove obsolete verified files and name net8 files correctly by @PhenX in EFNext/EntityFrameworkCore.Projectables#186 * Remove all allocations when resolving and make it even faster by @PhenX in EFNext/EntityFrameworkCore.Projectables#189 * Add devcontainer configuration for C# (.NET) development by @koenbeuk in EFNext/EntityFrameworkCore.Projectables#190 **Full Changelog**: EFNext/EntityFrameworkCore.Projectables@v5.0.2...v6.0.0 Commits viewable in [compare view](EFNext/EntityFrameworkCore.Projectables@v5.0.2...v6.0.0). </details> [](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) </details> --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: James Gunn <james@gunn.io>
Updated [EntityFrameworkCore.Projectables](https://github.com/EFNext/EntityFrameworkCore.Projectables) from 5.0.2 to 6.0.0. <details> <summary>Release notes</summary> _Sourced from [EntityFrameworkCore.Projectables's releases](https://github.com/EFNext/EntityFrameworkCore.Projectables/releases)._ ## 6.0.0 ## What's Changed ### Major changes * Add support for projectable method overloads by @PhenX in EFNext/EntityFrameworkCore.Projectables#143 * Add C#14 extension members by @PhenX in EFNext/EntityFrameworkCore.Projectables#148 * Support explicitly implemented interface members and default interface properties by @rhodon-jargon in EFNext/EntityFrameworkCore.Projectables#135 * Support block-bodied members with [Projectable] attribute by @Copilot in EFNext/EntityFrameworkCore.Projectables#152 * Add ExpandEnumMethods to expand enum extension calls into ternary expressions by @Copilot in EFNext/EntityFrameworkCore.Projectables#150 * Add support for pattern matching in various cases by @PhenX in EFNext/EntityFrameworkCore.Projectables#158 * Add support for projectable constructors by @PhenX in EFNext/EntityFrameworkCore.Projectables#161 * AOT-compatible static projection registry + SyntaxFactory-based emission by @Copilot in EFNext/EntityFrameworkCore.Projectables#166 * Improve UseMemberBody and add new diagnostics by @PhenX in EFNext/EntityFrameworkCore.Projectables#174 * Add code fixes for EFP0001, EFP0002 and EFP0008, with tests by @PhenX in EFNext/EntityFrameworkCore.Projectables#181 * Add a code fixer and a code refactorer to transform factory methods into constructors by @PhenX in EFNext/EntityFrameworkCore.Projectables#183 * Improve source generator and analyzer responsiveness by @PhenX in EFNext/EntityFrameworkCore.Projectables#171 * Docs website by @PhenX in EFNext/EntityFrameworkCore.Projectables#194 * Implement global MSBuild defaults for [Projectable] options by @koenbeuk in EFNext/EntityFrameworkCore.Projectables#191 ### Other changes * Check source generator output compilation by @PhenX in EFNext/EntityFrameworkCore.Projectables#156 * Fix GetImplementingProperty issue when using interfaces by @PhenX in EFNext/EntityFrameworkCore.Projectables#144 * Full qualification not needed anymore by @PhenX in EFNext/EntityFrameworkCore.Projectables#157 * Split generator tests in different classes by @PhenX in EFNext/EntityFrameworkCore.Projectables#162 * Refactor ExpressionSyntaxRewriter into focused partial class files by @Copilot in EFNext/EntityFrameworkCore.Projectables#163 * Update readme and add new test for constructors by @PhenX in EFNext/EntityFrameworkCore.Projectables#165 * Remove obsolete code by @PhenX in EFNext/EntityFrameworkCore.Projectables#167 * Add source generator self-benchmark covering all expression transformers by @Copilot in EFNext/EntityFrameworkCore.Projectables#168 * Fix null conditional rewrite generating invalid member access on nullable value types by @Copilot in EFNext/EntityFrameworkCore.Projectables#169 * Improve generator benchmark with more realistic scenario by @PhenX in EFNext/EntityFrameworkCore.Projectables#170 * Fix stale incremental generator cache when referenced types change in other source files by @Copilot in EFNext/EntityFrameworkCore.Projectables#172 * Add tests for properties with a getter and setter by @PhenX in EFNext/EntityFrameworkCore.Projectables#173 * UseMemberBody more strict with expressions by @PhenX in EFNext/EntityFrameworkCore.Projectables#175 * Add custom Copilot instructions by @PhenX in EFNext/EntityFrameworkCore.Projectables#177 * Reorganize generator project by @PhenX in EFNext/EntityFrameworkCore.Projectables#178 * Add closure resolution benchmark by @PhenX in EFNext/EntityFrameworkCore.Projectables#179 * Feature/optimize closures by @PhenX in EFNext/EntityFrameworkCore.Projectables#180 * Feature/optimize resolver by @PhenX in EFNext/EntityFrameworkCore.Projectables#182 * Update github project urls by @PhenX in EFNext/EntityFrameworkCore.Projectables#184 * Update deps by @PhenX in EFNext/EntityFrameworkCore.Projectables#185 * Remove obsolete verified files and name net8 files correctly by @PhenX in EFNext/EntityFrameworkCore.Projectables#186 * Remove all allocations when resolving and make it even faster by @PhenX in EFNext/EntityFrameworkCore.Projectables#189 * Add devcontainer configuration for C# (.NET) development by @koenbeuk in EFNext/EntityFrameworkCore.Projectables#190 **Full Changelog**: EFNext/EntityFrameworkCore.Projectables@v5.0.2...v6.0.0 Commits viewable in [compare view](EFNext/EntityFrameworkCore.Projectables@v5.0.2...v6.0.0). </details> [](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) </details> --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: James Gunn <james@gunn.io>
Support block-bodied members with [Projectable] attribute
Source generator now accepts block-bodied members in addition to expression-bodied, transforming supported control flow to expression trees.
For now it is experimental and requires to set AllowBlockBody = true in the Projectables attribute.
Implementation
BlockStatementConverter: Transforms block statements to expressions
ProjectableInterpreter: Detects method body type (expression vs block) and routes appropriately
Diagnostics:
Example
Both generate identical SQL:
Additional Examples
Switch Statement Support
Generates optimized SQL:
If Without Else Support
Supported patterns
Side Effect Detection
The generator now detects and reports specific side effects with precise error messages:
See Block-Bodied Methods Documentation for complete details.
Test coverage
Documentation
docs/BlockBodiedMethods.md: Complete guide for block-bodied method support (includes side effect detection)Original prompt
💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.