Source generator: compiled companion NodeSet support and base-qualified NodeState emission - #4063
Conversation
Enhancements to the model source generator so that a *compiled* companion NodeSet2 (e.g. an OPC companion spec such as Robotics/IA, or the OpenUSD binding model) can be source-generated: - Add OpcUaStateTypeIndex and wire it through ModelCompilation / ModelSourceGenerator so standard (ns=0) node-state/method-state class names are resolved from the referenced Core(.Types) metadata. - Add StandardMethodStateFallback: when a compiled NodeSet instantiates a standard type that carries methods (e.g. a FileDirectoryType 'Delete' instance), the default naming can compute an 'Opc.Ua.*MethodState' name that Core never emits under that name. Degrade an unresolved standard 'global::Opc.Ua.*MethodState' reference to the base 'global::Opc.Ua. MethodState' only when that typed class is neither declared by the current pass nor present in the compilation, keyed on the exact Opc.Ua namespace and never entered by the Stack pass that builds Core.Types. This is the scoped interim workaround tracked by #4060 (the proper upstream fix is a name-resolution step, which this makes unnecessary once landed). - NodeStateGenerator / ModelDesignExtensions / FluentBuilderGenerator: supporting changes for the above. - Opc.Ua.Types: expose internals to Opc.Ua.Core.Encoders.Tests. Validated: generator builds (netstandard2.0), Opc.Ua.Core.Types generates and builds, and the full Opc.Ua.SourceGeneration.Core test suite passes (3715 passed / 8 skipped / 0 failed).
… generator The model source generator now emits base-qualified writes (((global::Opc.Ua.NodeState)state).X = ...) for the base NodeState members NodeId, SymbolicName, BrowseName, AccessRestrictions, ReleaseStatus, Categories, Specification and Description in the generated NodeState/NodeManager factories. When a generated subclass shadows one of these members with a strongly-typed 'new' property, an unqualified write would target the shadow rather than the base setter; base-qualifying guarantees it reaches NodeState. For non-shadowing types it is a redundant-but-safe upcast, so all existing generated consumers continue to compile unchanged. Also global::-qualifies the namespace prefix in the emitted NodeId/ExpandedNodeId static declarations (NodeIdTemplates) to avoid namespace-collision ambiguities. Updates the affected source-generator golden-string tests to expect the base-qualified emission.
|
|
There was a problem hiding this comment.
Pull request overview
Note
Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.
This PR updates the OPC UA model source generator to emit base-qualified writes to NodeState members (avoiding issues when generated subclasses shadow those members), and to global::-qualify emitted NodeId/ExpandedNodeId declarations to prevent namespace collisions.
Changes:
- Base-qualify generated assignments to
NodeStateproperties in NodeState/NodeManager factories. global::-qualify namespace prefixes in emittedNodeId/ExpandedNodeIddeclarations.- Update golden-string tests to assert the new emitted code forms.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| tools/Opc.Ua.SourceGeneration.Core/Generators/NodeStateTemplates.cs | Emits base-qualified writes in templates (factory output). |
| tools/Opc.Ua.SourceGeneration.Core/Generators/NodeStateGenerator.cs | Base-qualifies additional emitted property assignments (ReleaseStatus/Categories/etc.). |
| tools/Opc.Ua.SourceGeneration.Core/Generators/NodeIdTemplates.cs | global::-qualifies namespace prefix usage in emitted declarations. |
| tests/Opc.Ua.SourceGeneration.Core.Tests/Generators/NodeStateGeneratorTests.cs | Updates assertions for base-qualified NodeId/BrowseName writes. |
| tests/Opc.Ua.SourceGeneration.Core.Tests/Generators/NodeManagerGeneratorTests.cs | Updates assertions for base-qualified AccessRestrictions writes. |
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## master #4063 +/- ##
==========================================
- Coverage 73.86% 73.59% -0.28%
==========================================
Files 1345 1347 +2
Lines 180038 180218 +180
Branches 31678 31704 +26
==========================================
- Hits 132993 132632 -361
- Misses 36290 36863 +573
+ Partials 10755 10723 -32
🚀 New features to boost your workflow:
|
Resolved conflicts: - Source generator (StandardMethodStateFallback/NodeStateGenerator/ModelSourceGenerator/ FluentBuilderGenerator/ModelDesignExtensions/ModelCompilation/OpcUaStateTypeIndex): took master's #4063 (canonical merged 'compiled companion models' implementation), which correctly generates the OpenUSD/Robotics companion models. - PumpDeviceIntegrationServer: kept the OpenUSD demo wiring (UpdateAlarmActive/representation), dropped the device-health feature that master removed; captured the PumpState returned by master's MaterialisePumpInstanceAsync instead of the removed m_pump1 field. - Opc.Ua.Di.Tests.csproj: unioned net472 Compile-Remove entries. Validated: Di.Tests + both samples + OpenUsd/Robotics libs build clean on net10.0; unit tests green.
…ntal-dataencodings Resolves conflicts in the two model source-generator files (NodeStateGenerator.cs, NodeStateTemplates.cs) in favour of origin/master. Master's version is the reviewed evolution of this branch's own generator work (branch commits 842c876 + 0f94bc1, extracted as PR #4063 and squash-merged as 66be673): it replaces the inline ((global::Opc.Ua.NodeState)state).X = ... cast with a NodeState-typed 'nodeState' local and adds compiled-companion-model support (OpcUaStateTypeIndex / StandardMethodStateFallback). The branch has no independent changes to these two files, so taking master's version adopts the reviewed approach without losing branch-specific work.
Improves the OPC UA model source generator so it can source-generate compiled companion NodeSet2 models (for example an OPC companion spec such as Robotics/IA, or the OpenUSD binding model), and hardens the emitted NodeState/NodeManager code. The change is confined to the generator (
tools/Opc.Ua.SourceGeneration*) and adds no runtime API surface.Resolving standard types from referenced metadata. A new
OpcUaStateTypeIndexcollects the simple names of the standardOpc.Ua.*Stateclasses (node-state and method-state) available in the compilation, including referenced assemblies such asOpc.Ua.Core. Wired throughModelCompilationandModelSourceGenerator, it lets a companion model resolve standard (ns=0) class names from the referenced Core(.Types) metadata instead of inferring them.Standard method-state fallback (interim, #4060). When a compiled NodeSet instantiates a standard type that carries methods (e.g. a
FileDirectoryTypeDeleteinstance), the default naming can compute anOpc.Ua.*MethodStatename that Core never emits.StandardMethodStateFallbackis an ambient, execution-context-scoped policy that degrades such an unresolvedglobal::Opc.Ua.*MethodStatereference to the baseglobal::Opc.Ua.MethodState- only when the typed class is neither declared by the current pass nor present in the compilation, keyed on the exactOpc.Uanamespace, and never applied in the Stack pass that builds Core.Types. This is the scoped interim workaround tracked by #4060; the proper upstream fix is a name-resolution step that makes it unnecessary.Base-qualified attribute writes. The generator now emits base-qualified writes -
((global::Opc.Ua.NodeState)state).X = ...- for the baseNodeStatemembersNodeId,SymbolicName,BrowseName,AccessRestrictions,ReleaseStatus,Categories,SpecificationandDescription. When a generated subclass shadows one of these with a strongly-typednewproperty, an unqualified write would target the shadow rather than the base setter; base-qualifying guarantees it reachesNodeState. For non-shadowing types it is a redundant-but-safe upcast, so existing generated consumers compile unchanged.Supporting changes. The emitted
NodeId/ExpandedNodeIdstatic declarations are nowglobal::-qualified on their namespace prefix to avoid namespace-collision ambiguities, with related adjustments inNodeStateGenerator,ModelDesignExtensionsandFluentBuilderGenerator.Opc.Ua.Typesadditionally exposes internals toOpc.Ua.Core.Encoders.Tests.Tests and validation. New
StandardMethodStateFallbackTestscover the fallback policy, and the NodeState/NodeManager golden-string tests are updated to expect the base-qualified emission. The change set is exercised by theOpc.Ua.SourceGeneration.Coregenerator test suite on net10.0 and net48, and by regenerating and buildingOpc.Ua.Core.Typesacross the full target-framework set (net472 through net10.0); PR CI runs the complete build/test matrix.