Repository navigation
feat: combine the binding and attribute source generators - #524
Open
glennawatson wants to merge 214 commits into
Open
glennawatson wants to merge 214 commits into
glennawatson wants to merge 214 commits into
Conversation
Clean up the shared scenarios files
…#4) * Fix .NET Framework build errors and MAUI Visibility ambiguity - Add RequiresUnreferencedCodeAttribute polyfill for net462/net472/net481 targets where the attribute is inaccessible (only public in .NET 5+) - Add ModuleInitializerAttribute polyfill for benchmark net462 target - Fix CS0104 Visibility ambiguity in MAUI project on Windows targets by using type aliases instead of namespace imports * Fix remaining .NET Framework polyfill and visibility issues - Add InternalsVisibleTo from ReactiveUI.Binding to Wpf, WinForms, and Maui projects so they can access internal polyfill attributes (RequiresUnreferencedCodeAttribute, NotNullWhenAttribute, etc.) - Add missing using for POCOObservableForProperty in MAUI's DependencyObjectObservableForProperty.cs - Emit ModuleInitializerAttribute polyfill from source generator for consumer projects targeting .NET Framework (same pattern as existing CallerArgumentExpressionAttribute polyfill) * Remove all polyfill emission from source generator The generator should never emit polyfills into consumer projects. Instead it detects platform capabilities and generates appropriate code: - Remove CallerArgumentExpressionAttribute polyfill emission; the supportsCallerArgExpr flag now checks both C# 10+ language version AND that the attribute exists in the compilation, falling back to file/line dispatch when unavailable - Remove [ModuleInitializer] from generated registration code entirely - Replace [ModuleInitializer] in ReactiveUI benchmarks with explicit static constructor calls using an atomic bool guard pattern - Update snapshot tests
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
* chore: increase the amount of unit testing * Fix stack overflow in tests * remove tests from code coverage by exclusion * Update claude file * Further adding tests * Further testing * Fix complete names of tests Improve coverage tests
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
* feat: add AOT-safe ViewLocator with source-generated view dispatch ## New Features - Add IViewLocator, DefaultViewLocator, ViewLocator, and ViewMappingBuilder runtime types supporting three-tier view resolution: generated dispatch → explicit mappings → service locator fallback. - Add source generator that scans IViewFor<T> implementations at compile time and generates a type-switch dispatch function for AOT-safe view resolution. - Add ViewRegistrationExtractor and ViewRegistrationInfo model for extracting view/view-model pairs from the compilation. - Integrate ConfigureViewLocator into the builder pattern via IReactiveUIBindingBuilder, ReactiveUIBindingBuilder, and BuilderMixins. ## Tests - Add 7 snapshot tests for ViewLocatorDispatchGenerator covering single/multiple views, abstract exclusion, private/missing constructors, deduplication, and non-IViewFor classes. - Add 31 runtime tests for DefaultViewLocator, ViewLocator, ViewMappingBuilder, ViewLocatorNotFoundException, and builder integration. - Add TestExecutor infrastructure following ReactiveUI's executor pattern for clean test isolation. * fix: minor corrections to ViewLocator implementation - Update BindingGenerator XML doc to mention all three pipelines (A, B, C) - Make DefaultViewLocator _lock instance-scoped instead of static since it only guards the per-instance _mappings dictionary
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
) ## View Registration Attributes - Add ExcludeFromViewRegistration, SingleInstanceView, and ViewContract attributes to ReactiveUI.Binding - Source generator reads attributes to skip excluded views, emit singleton caching, and generate contract-aware dispatch - Add CreateMappingBuilder() factory method on DefaultViewLocator ## Generator Improvements - Rewrite ViewLocatorDispatchGenerator to use raw string literals ($$""" pattern) - Deduplicate by (ViewModel FQN, Contract) pair instead of ViewModel FQN alone - Remove redundant IEquatable<Self> from all sealed record model types ## Test Coverage - 100% line and branch coverage maintained * fix: ViewLocatorDispatch contract ordering, thread safety, and defensive improvements - Group dispatch branches by ViewModel type so contract-specific checks are emitted before the default branch (prevents shadowing) - Escape contract strings with SymbolDisplay.FormatLiteral for safe codegen - Use Interlocked.CompareExchange for thread-safe singleton view caching - Fix strategyDoc for SingleInstanceView without parameterless constructor - Move [ExcludeFromViewRegistration] check inside IViewFor<T> guard to prevent EnsureNotNull crash in compilations without ReactiveUI.Binding - Add tests for grouped dispatch and contract-only dispatch (100% coverage)
#18) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
#27) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
- TUnit 1.76 makes dotnet test report no devices for the Uno and MAUI projects on Windows. - Skip the Windows PRI step in the MAUI sample off Windows. - Ignore the single CI-stamped version for the binding packages.
- Version 18.11 makes dotnet test report no devices on Windows and macOS; the tests run on Microsoft Testing Platform without it.
- dotnet test on rc.3 asks for a device to run the MAUI and WinUI test projects on and fails before running tests.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #524 +/- ##
==========================================
+ Coverage 96.75% 98.94% +2.18%
==========================================
Files 76 470 +394
Lines 3824 18808 +14984
Branches 544 2777 +2233
==========================================
+ Hits 3700 18609 +14909
- Misses 124 199 +75 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
…tor benchmark - Add WhenAny, WhenAnyObservable, InvokeCommand and BindInteraction call sites to the generation benchmark. - Update the adapter benchmark to the helpers the generator now references.
- Emitters and the view and property generators take arrays; Collect() results are read with RoslynArray.Unwrap. - Stages that cache collected members hold EquatableArray. - ImmutableArray stays only for the arrays Roslyn's symbol APIs return.
- Remove the SONAR_ENABLED gate and keep the existing ReactiveUI.Binding.SourceGenerators project key.
…benchmarks - Benchmark harness: async trace copy, no forced collection, BenchmarkDotNet logger instead of Console. - Samples: report through Trace, and make the members CA1822 flagged static. - Drop the NoWarn entries and editorconfig relaxations for them.
- restore RXUIBIND002, RXUIBIND005 and RXUIBIND020 with their tests and benchmarks - restore RXUISG0016 (analyzer and code fix) and RXUISG0022 with their tests - benchmark the two restored attribute analyzers - write the MAUI sample's output through Trace.TraceInformation - update CLAUDE.md: shipped diagnostics are never removed without a request
- move the repeated Dispose into a helper so the example keeps its output
- the generator finds the public field by name, so WhenAnyValue on it observes the dependency property
- test the delivery gate under contention by holding it through a blocking comparison - test the all-options constructor and a callback that throws with nothing queued - drop the unreachable queue branch when the initial value is published - test the ToProperty initial-value analyzer's candidate matching directly - show shared disposal through a second owner instead of a repeated Dispose call
- drop the binding-v tag stream that no release step created - one v* stream and a 10.0 floor give both families the same computed version - the release workflow's override reaches every project again
- restore the binding-v tag stream with its own release workflow and solution filters - give the attribute packages their own filter and release workflow - each release computes its version from its own tags, so nothing is tagged by hand
|
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


Summary
Combines ReactiveUI.Binding.SourceGenerators into this repository, so the attribute generators and the binding generators build, test and ship together. The binding family's single-file generator structure is the model for both.
SourceWriterand one array-backedEquatableArray<T>. Internal code uses arrays, lists and sets.ImmutableArray<T>stays only where Roslyn requires it.[IViewFor],[IViewFor<T>]and[IViewFor("TypeName")]are back, with the view registration the binding family reads.ReactiveObjectowner now generatesToProperty;classis no longer repeated beside a class type constraint (CS0450); MAUI and Avalonia XAML in the 2009 namespace is read; an[ObservableAsProperty]value is readable from the notifications its helper raises as it starts.docs, and each example has a README.Why
The two families are coupled: the attribute generators write members the binding generators observe, and both replace the same ReactiveUI runtime work. Keeping them apart meant two sets of infrastructure and two sets of fixes.
Refs reactiveui/ReactiveUI.Binding.SourceGenerators#182, #184 and #185. Refs reactiveui/ReactiveUI#4538 and #4541.
Breaking changes
ReactiveUI.Binding.SourceGeneratorssolution and project files are renamed into this repository's layout. Package IDs are unchanged.ReactiveUI.Binding*packages keep separate version lines (vandbinding-vtags), so tagging one family never moves the other.ObservableAsPropertyHelper<T>gainsCreateoverloads that take anObservablePropertyTarget, andPendingValue. Existing overloads are unchanged.How this was verified
Generator, analyzer and runtime tests for both families, including new tests for each fix above. The packed attribute package was inspected for its bands and README. The MAUI Android and wasm projects could not be built here because those workloads are not installed; CI builds them.
Notes for the reviewer
src/ReactiveUI.SourceGenerators.SharedandCLAUDE.md, which describe the layout and the rules both families follow.Checklist