mirror of
https://github.com/OPCFoundation/UA-.NETStandard.git
synced 2026-10-28 22:55:49 +08:00
release/2.0.0
8
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
e639932b95 |
Fix source generator defects from the Client/Types/SourceGeneration audit (#4473)
# Description
Fixes the SourceGeneration findings of a read-only bug audit of
`a05a36055` — sections 15 (host generators, Roslyn side), 16
(SourceGeneration.Core schema / ModelDesign loader) and 17
(SourceGeneration.Core generators). 36 of the 39 findings are fixed;
each has a regression test.
### Generated-code correctness
- **State machine NodeId constants** were emitted as `const uint` even
when the aliased `Objects` constant is a `string`, so every model using
string NodeIds with a `FiniteStateMachineType` subtype failed with
CS0029. The constant type now follows the aliased node, looked up from
the same source `NodeIdGenerator` emits from — top-level nodes **plus
each node's instance hierarchy**, since a state or transition only ever
exists as a hierarchy entry.
- `NodeIdGenerator` emitted string identifiers into C# string literals
without escaping them.
- Structure field names are authored data, so they can be C# keywords or
collide with the members every generated data type carries. Properties
and `{Type}Fields` members now go through a sanitizing,
collision-breaking mapping (including two siblings that sanitize to the
same identifier). **Wire names are untouched** — OPC 10000-3 §8.51
requires the StructureField name to match the BrowseName, and the
`DataMember`/encode/decode names still come from `Parameter.Name`.
- `NodeStateGenerator`'s copy-on-write cast now uses the fully qualified
data type name, which a cross-model structure needs.
- `GetScalarValueAsCode` emitted `(double)NaN` and the infinities, which
do not compile.
- `TemplateWriter` formatted with the current culture, so a machine with
a comma decimal separator emitted invalid generated source.
### Served schema documents
- The binary schema described a **different wire layout than the
generated `Encode`/`Decode`**: unions carried no
`SwitchField`/`SwitchValue`, and structures with optional fields carried
no encoding-mask presence bits. Both are now emitted per **OPC 10000-6
§5.2.7**, matching the layout the runtime `BsdSchemaGenerator` produces.
A structure with more than 32 optional fields now fails generation
instead of silently wrapping `1 << 32` back onto the first field's bit.
- Documentation text and attribute values are XML-escaped.
### ModelDesign loading and validation
- Identifiers pinned in a CSV were dropped whenever any other loaded
namespace declared the same symbolic name. Removal is now scoped to the
file's target namespace, and explicit `NumericId`s are keyed by
`(namespace, id)` so the same number in two namespaces is legal.
- Declaration order inside a design file no longer matters — base types
are imported and validated ahead of their subtypes.
- OptionSet `OptionSetValues` were truncated at bit 31 (signed shift)
and bits 32–63 of a 64-bit option set were never emitted.
- An authored `ValueRank` is no longer overwritten by the shape of the
default value (OPC 10000-3 §6.2.8: a ValueRank may only be further
restricted), and a VariableType data type may be narrowed any number of
levels deep rather than exactly one.
- NodeSet import: `AccessRestrictions="0"` means "no restrictions", not
`EncryptionRequired` (OPC 10000-3 §8.56) — an unrecognised mask stays
**fail-closed**; a NodeSet without `<Models>` reports what is wrong; an
optional `<References>` no longer throws; the parent/child reference
scan looks at the parent's references; and `IsTypeOf` terminates on the
self-referential root reference types NodeSets routinely declare.
- Version comparison is numeric per component (ordinally `"1.05.9"`
sorts above `"1.05.10"`) and now lives on `SemVer`, so the NodeSet
collection and the dependency tie-break cannot pick different winners; a
publication-date version no longer outranks a real one.
### Host generator
- `[DataType]` on an `enum` is matched again (an enum is not a
`TypeDeclarationSyntax`), MODELGEN003 renders its arguments instead of
the raw template, and the Types hint name keeps the namespace's dots so
`A.BC` and `AB.C` cannot claim the same one.
- Compilation-derived pipeline stages carry value comparers, so editing
a file no longer re-runs the entire model generation on every keystroke.
- A NodeSet that fails to load skips that file rather than every
remaining one; a file listed twice as an `AdditionalFile` is deduped;
superseded NodeSet versions are still recognised as NodeSet inputs and
not generated a second time by the ModelDesign pass.
- `LogLevel.Critical` maps to a diagnostic instead of being silently
dropped.
### Client
- `EventRecordFieldReaders` gained the readers the event record
generator needs (including `Variant`, enumerations and the array forms).
Fields whose type had no reader were declared on the record but never
populated, so they read as `null`/`default` for every event.
## Not fixed (deliberately)
- **Forward same-namespace hierarchical references in
`NodeSetToModelDesign.ImportReferences`** — the audit flags the
inverse-only handling as asymmetric. Making it symmetric compiles and
passes every generator unit test, but regresses the address space: all
17 `RobotOpenUsdE2eTests` fail in `OneTimeSetUpAsync` because the hosted
server never finishes starting. Reverted, with a comment at the site
recording why.
- **§17.10 and §15.10** (both low + PLAUSIBLE) — each needs a wider
refactor than this PR: a consistent NodeId-constant rename across ~6
cross-reference sites, and replacing `Location` with a serializable
equivalent for incremental cache equality.
## Spec cross-check
The encoding/schema changes were checked against the specification: OPC
10000-6 §5.2.7 (32-bit EncodingMask, one bit per optional field in
order, padded), the union `SwitchField` encoding, OPC 10000-3 §8.56
(AccessRestrictionType bit mask), §6.2.8 and §5.6.2/§5.6.5 (ValueRank),
§8.51 (StructureField name == BrowseName).
`GenerateStackTests.OptionalFieldBitsAgreeBetweenBsdAndGeneratedEncoder`
pins the BSD presence-bit order against the generated encoder's
`LogRecordFields` so the two cannot drift apart again.
## Related Issues
_No tracking issue — this PR implements the SourceGeneration sections of
a bug audit. Happy to open one if maintainers prefer._
## Checklist
- [ ] I have signed the
[CLA](https://opcfoundation.org/license/cla/ContributorLicenseAgreementv1.0.pdf)
and read the
[CONTRIBUTING](https://github.com/OPCFoundation/UA-.NETStandard/blob/master/CONTRIBUTING.md)
doc.
- [x] I have added tests that prove my fix is effective or that my
feature works and increased code coverage.
- [x] I have added all necessary documentation.
- [x] I have verified that my changes do not introduce (new) build or
analyzer warnings.
- [ ] I ran **all** tests locally using the **UA.slnx** solution against
at least .net **framework** and .net **10**, and all passed.
- [ ] I fixed **all** failing and flaky tests in the CI pipelines and
**all** CodeQL warnings.
- [ ] I have addressed **all** PR feedback received.
> Note on the test checkbox: verified on **net10.0 only** — `UA.slnx`
builds clean (0 warnings, 0 errors) and
`Opc.Ua.SourceGeneration.Core.Tests` (3915),
`Opc.Ua.SourceGeneration.Tests` (184), `Opc.Ua.Di.Tests` (425, including
the `RobotOpenUsdE2eTests` end-to-end fixture that catches address-space
content changes) and the `EventRecordFieldReaders` tests (16) all pass.
.NET Framework has **not** been run locally; CI needs to confirm it.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: Marc Schier <marcschier@users.noreply.github.com>
|
||
|
|
02ea934a31 |
Complete fluent node manager extensibility (#4418)
# Description Complete the fluent node-manager extensibility surface needed by dynamic and externally backed address spaces. This change: - adds virtual node families with cheap NodeId ownership checks, async materialization, per-operation caching, custom browsing, and family-level callbacks; - adds monitored-item pre-creation decisions, complete lifecycle hooks, async batch hooks, stack-managed custom monitored items, and subscription-gated polling; - exposes the startup `ApplicationConfiguration` to generated manager partials through `FluentNodeManagerBase`; - fixes typed builder proxy support, concrete object wrapper types, and fully-qualified generated model composition; - reports unresolved `[NodeManager]` namespace expressions as `MODELGEN035` instead of silently dropping them; - documents the new APIs and compatibility behavior. ## Related Issues - Fixes #4397 - Fixes #4398 - Fixes #4399 - Fixes #4403 - Fixes #4404 - Fixes #4405 ## Validation - `Opc.Ua.Server.Tests` on `net10.0`: 4,886 passed, 5 skipped. - `Opc.Ua.SourceGeneration.Core.Tests` on `net10.0`: 3,807 passed, 8 skipped. - `Opc.Ua.SourceGeneration.Tests` on `net10.0`: 164 passed. - Runtime and generator regression selections passed on `net48`. - Review-feedback validation: 376 fluent tests passed on `net10.0`; 22 focused tests passed on `net48`. - The CI timing regression was repeated five times on `net48` and once on `net10.0`. - All 266 applicable GitHub Actions and Azure Pipelines checks, including CodeQL and coverage, pass on `83c571423`. - AppVeyor reports an immediate zero-duration no-run failure because `appveyor.yml` whitelists only the `appveyor` branch; it did not execute this PR. - `UA.slnx` builds successfully for `net10.0`; affected project builds are warning-free. - The repository-wide `dotnet test UA.slnx` invocation is currently blocked by the solution's mixed VSTest/Microsoft.Testing.Platform configuration under the .NET 10 SDK, so the affected test projects were run individually. ## Checklist - [ ] I have signed the [CLA](https://opcfoundation.org/license/cla/ContributorLicenseAgreementv1.0.pdf) and read the [CONTRIBUTING](https://github.com/OPCFoundation/UA-.NETStandard/blob/master/CONTRIBUTING.md) doc. - [x] I have added tests that prove my fix is effective or that my feature works and increased code coverage. - [x] I have added all necessary documentation. - [x] I have verified that my changes do not introduce (new) build or analyzer warnings. - [ ] I ran **all** tests locally using the **UA.slnx** solution against at least .net **framework** and .net **10**, and all passed. - [x] I fixed **all** failing and flaky tests in the CI pipelines and **all** CodeQL warnings. - [x] I have addressed **all** PR feedback received. --------- Copilot-Session: afaa67c9-fc97-4185-a785-edd54a937d95 |
||
|
|
e73e71184d |
[WotCon] Add OPC UA WoT Connectivity 1.1 with the Types, source generation, Server and xRegistry work it builds on (#4128)
## Summary Adds OPC UA WoT Connectivity 1.1 to the stack, together with the Types, source generation, Server and xRegistry work it is built on. This branch is the merge point for the fourteen-PR stack that replaced integration PR #4093; every constituent PR was reviewed and approved separately and is listed below. 414 files changed, +108,936 / -3,199. Roughly 46k added lines of product code, 57k of tests, plus samples, tools and documentation. ## Types - Complete `ExtensionObject` raw-body decoding for binary, XML and JSON bodies by resolving the concrete type through the message context's encodeable factory, and simplify the `Variant` structure helpers by delegating to it (#4128). - Add `IAtomicFileReplace` as an optional `IFileSystem` capability so existing external implementations keep working, with atomic publish for `LocalFileSystem` via `File.Replace`/`File.Move` and for `VirtualFileSystem` by re-keying the in-memory entry (#4128). - Add lossless conversion between WoT documents and NodeSet2 (`Opc.Ua.Wot.WotNodeSetConverter`). A byte-exact `uav:nodeSet` envelope is preserved when requested, the structured `uav:nodes` projection is used when the readable vocabulary is incomplete, and NodeSet2 is otherwise synthesized from readable WoT terms. Unmapped JSON members survive a round trip as pointer-addressed residue (#4131). ## Source generation - Improve the NodeSet to ModelDesign conversion and the generated node state (#4132). - Generate OPC UA models directly from WoT Thing Description files (#4134). ## Server - Add live NodeManager shadow and immediate reload. A reload materializes a new generation beside the active one and switches atomically; the superseded generation is retired gracefully so existing MonitoredItems keep being served until they drain, or immediately when the caller asks for it. Includes the request admission and drain machinery that lets an orderly shutdown wait for admitted requests instead of tearing down underneath them (#4147). - Make subscription transfer between sessions transactional, so a failed transfer leaves neither session holding a partially moved subscription (#4150). ## xRegistry - Allow clients to use explicit registry roots rather than assuming a well-known location (#4130). ## WoT Connectivity - Add the WoT Connectivity 1.1 information model: a registry-first revision layered on the abstract xRegistry base model, incorporating the complete published OPC 10100-1 v1.02 surface as deprecated nodes in the same namespace so existing 1.02 clients keep working (#4139). - Add the protocol binding abstractions and planners that compile WoT forms into executable plans (#4140). - Add the HTTP, Modbus, OPC UA and MQTT binding executors (#4144). - Add the registry and its stores, including document versioning, validation, dependency resolution and refresh (#4146). - Add the registry client (#4142). - Materialize WoT Thing Descriptions into the server address space, deriving types from Thing Models and instances from Thing Descriptions (#4154). - Restore the WoT asset registry bridge so the deprecated 1.02 asset surface is backed by the registry (#4171). - Add the WoT Connectivity samples and complete the documentation (#4156), and restore the remaining coverage and docs (#4172). ## New projects `src/Opc.Ua.WotCon.Bindings`, `src/Opc.Ua.WotCon.Bindings.Mqtt`, `tests/Opc.Ua.WotCon.Bindings.Tests`, `tests/Opc.Ua.WotCon.Samples.Tests`, and the `samples/WotCon` AggregationServer, AggregationClient and FlatTagServer samples. ## Constituent pull requests Merged into this branch top-down, each independently approved: | PR | Title | | --- | --- | | #4128 | [Types] Complete ExtensionObject decoding and add an atomic file replace capability | | #4131 | [Types] Add lossless conversion between WoT documents and NodeSet2 | | #4132 | [SourceGeneration] Improve NodeSet to ModelDesign conversion and generated node state | | #4134 | [SourceGeneration] Generate OPC UA models from WoT Thing Description files | | #4147 | [Server] Add live NodeManager shadow and immediate reload | | #4150 | [Server] Make subscription transfer between sessions transactional | | #4130 | [XRegistry] Allow clients to use explicit registry roots | | #4139 | [WotCon] Add the WoT Connectivity 1.1 information model | | #4140 | [WotCon] Add the WoT protocol binding abstractions and planners | | #4144 | [WotCon] Add the HTTP, Modbus, OPC UA and MQTT binding executors | | #4146 | [WotCon] Add the WoT Connectivity registry and its stores | | #4142 | [WotCon] Add the WoT Connectivity registry client | | #4154 | [WotCon] Materialize WoT Thing Descriptions into the server address space | | #4156 | [WotCon] Add the WoT Connectivity samples and complete the documentation | | #4171 | Restore WoT asset registry bridge | | #4172 | Restore WoT coverage and docs | Supersedes #4093. ## Follow-up The WoT Connectivity and WoT Binding drafts have moved to 1.1-draft2 since this work was authored. Aligning with that revision - the removed group vocabulary, the new projection/View construct, the remaining model vocabulary terms and the two new portable-identity validation rules - is tracked separately and will follow in its own pull request. ## Validation Built for every target framework with zero warnings and zero errors, and validated at the tip of the stack with `Opc.Ua.WotCon.Tests` at 999 passed / 0 failed and `Opc.Ua.Server.Tests` at 4024 passed / 0 failed. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 9e6a5abf-3299-4cd1-9855-010fedbf0ad8 |
||
|
|
0357380335 |
Source generator: typed NodeSet method signatures and referenced model accessors (#4124)
**Stack 2/5** — base #4123. Part of the #4096 split; see #4096 for the overall picture. > Review after #4123. The diff shown against `master` will include #4123 until that merges. ## What this is Source generator only; no runtime library changes. ## Contents - **Typed NodeSet method signatures.** A method imported from a NodeSet now gets a typed signature. Methods that share a declared signature are grouped onto one generated `MethodType`, named after its owner when the plain name would collide, so two unrelated `Execute` methods no longer share a class. - **An override that keeps the signature it inherits keeps the declaration it overrides.** Pointing `MethodDeclarationNode` at the override itself made `MethodDeclarationId` self-referential. OPC 10000-4 lets a caller invoke a method with the NodeId of its declaration in the ObjectType *or any supertype*, and `MethodState.MethodDeclarationId` is what the server matches on, so `Call` stopped resolving and returned `Bad_MethodInvalid` for every alarm subtype. An override that genuinely changes its signature still becomes its own declaration. - **`StateNumbers` / `TransitionNumbers` were emitted empty for every NodeSet-sourced model**, because such children arrive as `VariableDesign` rather than `PropertyDesign` and were filtered out. Any companion model built from a NodeSet was writing `StateNumber = 0` on the wire — a Part 16 defect well beyond the models in this stack. The ModelDesign path is unchanged. - **Referenced models can contribute fluent accessors**, carried by a model dependency payload so a downstream model can extend an upstream one. ## Notes for the reviewer - `tests/Opc.Ua.SourceGeneration.Tests` is left at its `master` content here. Its new vendor-subtype test uses the Robotics NodeSet as its fixture, so it can only land with the Robotics change at the top of the stack (5/5). - `PumpInstanceNodeIdRegressionTests` gains six `InputArguments`/`OutputArguments` entries for argument-less standard condition methods. Typed method signatures materialise those properties from the `ConditionType` declaration even where the method takes none. That is a real deviation, pinned rather than hidden so it stays visible; it is worth a follow-up. ## Validation `dotnet build UA.slnx` — 0 errors. | Suite | Result | | --- | --- | | Opc.Ua.SourceGeneration.Core.Tests | 3739 / 0 | | Opc.Ua.SourceGeneration.Tests | 81 / 0 | | Opc.Ua.Di.Tests | 304 / 0 | | Opc.Ua.History.Tests | 506 / 0 | | Opc.Ua.Gds.Tests | 1095 / 0 | History and GDS are listed because they are what the method-declaration fix above is load-bearing for: without it they fail with 10 and 370 errors respectively. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 8cbb8cd0-f0cb-4ab0-bea2-6202fbf69485 |
||
|
|
76d33cb139 |
Remove SourceGenerator.Foundations, ship analyzers under Roslyn-versioned folders for VS2022 and VS2026, and validate the packages (#4120)
# Description The two OPC UA source generators were built on `SourceGenerator.Foundations` (SGF), whose only job was getting the generator's dependency closure loaded inside the compiler. It does so with a **process-wide, first-generator-wins `AppDomain.AssemblyResolve` hook backed by a non-concurrent `Dictionary` mutated from `AssemblyLoad` callbacks**. Concurrent compilations in a shared `VBCSCompiler` race it, which is the root cause of the intermittent clean-build failure: ``` CSC : error CS8784: Generator 'StackSourceGeneratorHoist' failed to initialize. ... Exception was of type 'FileNotFoundException' with message 'Could not load file or assembly 'SourceGenerator.Foundations.Contracts, Version=2.0.14.0, ...' ``` The repository already solves that problem deterministically — #4041 made the NuGet packages ship the full closure under `analyzers/dotnet/.../cs`, and `Directory.Build.targets` registers the same closure as `Analyzer` items for in-repo `ProjectReference` consumers. SGF was therefore pure liability and is removed. ## What changed **1. SourceGenerator.Foundations removed.** `ModelSourceGenerator` and `StackSourceGenerator` are plain `[Generator(LanguageNames.CSharp)] IIncrementalGenerator` implementations again. SGF's implicit crash handling is replaced by an explicit `SourceGenerator.Guard` that reports `MODELGEN003` / `STACKGEN003` and rethrows cancellation. Its logger sink was already dead code and is dropped. `Opc.Ua.SourceGeneration.Stack.dll` shrank from **18 MB** (embedded closure) to **29 KB**. **2. Analyzers now ship under Roslyn-versioned folders.** `analyzers/dotnet/roslyn4.14/cs` and `analyzers/dotnet/roslyn5.0/cs` instead of `analyzers/dotnet/cs`, driven by `roslyn.props` at the repository root, with new `*.Pack` projects owning the package identity. The versioned folder matters: a host older than the band **skips** the analyzer instead of loading it and failing inside generator initialization. **3. Dependencies flow automatically.** Both delivery paths discover the payload by globbing the generator's output directory, so adding a package to a generator's dependency tree requires **no** `.csproj`, `.targets`, `.nuspec` or validation-script edit. Verified by temporarily adding a `PackageReference` and watching it appear in the payload with no other file touched. ## Two Roslyn bands: VS2022 and VS2026 Analyzers ship twice, once per band. The .NET SDK loads the highest band its compiler supports and **silently skips** anything above it, so a single-band package leaves every consumer below that band with no diagnostics and no generated code. | Band | Built against | Loaded by | | --- | --- | --- | | `roslyn4.14` | `Microsoft.CodeAnalysis.CSharp 4.14.0` | Visual Studio 2022 17.14+ / .NET 9 SDK | | `roslyn5.0` | `Microsoft.CodeAnalysis.CSharp 5.0.0` | Visual Studio 2026 18.0+ / .NET 10 SDK | Getting this wrong is invisible, which is most of why it took three attempts. The rule: > An analyzer must reference the **lowest** `System.Collections.Immutable` / `System.Reflection.Metadata` across all hosts it claims to support, and must never ship them. .NET binds a reference *upward* but never downward. Every failure mode is a compiler **warning**: | Diagnostic | Cause | | --- | --- | | `CS9057` | Built against a newer Roslyn than the host, so it is skipped entirely | | `CS8784` | Loaded, then `MissingMethodException` - a shipped S.C.I bound a second `ImmutableArray<T>` | | `CS8032` | Analyzer instance could not be created | This PR first shipped a `roslyn4.8` band that **never loaded** - confirmed against a real Roslyn 4.8 compiler: ``` warning CS8784: Generator 'ModelSourceGenerator' failed to initialize ... MissingMethodException: Method not found: 'IncrementalValueProvider`1<ImmutableArray`1<!!0>> IncrementalValueProviderExtensions.Collect(IncrementalValuesProvider`1<!!0>)' ``` That band was removed, and **this is not a regression**: master had the same defect, pinned to Roslyn 4.14 while referencing `System.Collections.Immutable 10.0.0.0`, so no 4.x host ever worked there either. The band that landed instead is `4.14`, and it is nearly free: `Microsoft.CodeAnalysis 4.14` depends on the **same S.C.I 9.0.0 as 5.0.0** and its `csc` runs on `net9.0`. Both bands therefore share `$(RoslynRuntimeVersion)`, so `Opc.Ua.Types` and `Opc.Ua.SourceGeneration.Core` are compiled **once** and serve both; only the five Roslyn-referencing assemblies get a second build, each from a 12-line project that glob-links the primary sources and overrides `RoslynApiVersion`. Going lower still - 4.8 wants S.C.I 7.x - would mean rebuilding that whole closure, `Opc.Ua.Types` included, and remains out of scope. (`System.Collections.Immutable 7.0.0` also does not resolve in this repository: `NU1603`, 8.0.0 substituted.) **Nothing else in the repository exercises the down-level payload**, and since every failure is a warning, a broken band would ship silently - exactly as the 4.8 one did. So `validate-source-generator-packages.ps1` now restores a real `Microsoft.Net.Compilers.Toolset 4.14.0`, runs its `csc.dll` over the packed `roslyn4.14` payload, and asserts **both** that none of `CS9057`/`CS8784`/`CS8032`/`CS8034` is emitted **and** that `/reportanalyzer` lists the generator as having executed - silence alone would also pass if the generator were never handed to the compiler. The migration analyzer, whose payload comes from a hand-written nuspec rather than `SourceGeneratorPack.targets`, gets the same check plus a band/assembly manifest assertion. To stop the trap recurring, `Microsoft.CodeAnalysis*`, `System.Collections.Immutable` and `System.Reflection.Metadata` are excluded from both the package payload and the in-repo analyzer closure, and asserted against in the validation script. `roslyn.props` and `docs/DeveloperGuide.md` document what adding a band requires. ## The shipped package set is unchanged Evaluating `PackageId`/`IsPackable` across every project in `preview-pack.slnx` gives the **same 47 package ids** on `master` and on this branch, and a full Release build plus `dotnet pack --no-build` produces exactly those 47. Only the owning project changed: | Package | master | this PR | | --- | --- | --- | | `…Opc.Ua.SourceGeneration` | `Opc.Ua.SourceGeneration.csproj` | `Opc.Ua.SourceGeneration.Pack.csproj` | | `…Opc.Ua.SourceGeneration.Stack` | `Opc.Ua.SourceGeneration.Stack.csproj` | `Opc.Ua.SourceGeneration.Stack.Pack.csproj` | `.azurepipelines/expected-packages.txt` pins the expected set and the validation script fails when the packed output drifts. ## Two new package checks **`build/<PackageId>.props` naming.** NuGet only auto-imports that exact name, and the file declares every `CompilerVisibleProperty` / `CompilerVisibleItemMetadata` the model generator relies on. It was previously packed as `build/OPCFoundation.Opc.Ua.SourceGeneration.props`, which does **not** match the package id — so **no NuGet consumer ever imported it**, and every `ModelSourceGenerator*` property and `AdditionalFiles` metadata was silently invisible. In-repo projects were unaffected because they import it by relative path. **An end-to-end consumer that actually drives the generator.** The pre-existing clean-consumer check only proved the analyzer *loads*. `Test-SourceGeneratingConsumer` builds a standalone project that feeds a real NodeSet2 in as an `AdditionalFile`, pins a `ModelSourceGeneratorPrefix` that cannot be derived from the model, and references the emitted types from hand-written code. It deliberately does **not** import the props by path, so the package's auto-import is what is under test. Both checks were verified to fail against a package rebuilt with the misnamed props. ## CI: parallelism re-enabled `buildandtest.yml` pinned three `dotnet build` invocations to `/p:UseSharedCompilation=false` and `-maxcpucount:1`. `dotnet build` defaults to all logical processors, so `-maxcpucount:1` actively disabled parallelism. Both flags were introduced silently in unrelated PRs (`f358078b1`, `208c601b0`) and suppress exactly the conditions the SGF race needed — now structurally gone. Compilation is ~72 % of what that workflow executes (233 of 323 job-minutes in run `29916768976`), so the queue-independent `Build` step durations are the baseline: | Measurement | Baseline | | --- | --- | | `Build` step, 26 `test-*` jobs | mean 5.53 min, sum 143.9 min | | `build-linux-all-tfm` | 56.3 min | | `build-windows-all-tfm` | 32.5 min | `codeql-analysis.yml` keeps the flag — the CodeQL tracer requires it. ## Incidental fixes - `Microsoft.CodeAnalysis.CSharp` declares an exact `[version]` range on `Microsoft.CodeAnalysis.Common`, so with `CentralPackageTransitivePinningEnabled` the central pins must move in lockstep or restore fails with `NU1109`. They now derive from `$(RoslynApiVersionVS2026)`. - `MigrationGeneratorTests` created its generator driver without parse options — silently fine under Roslyn 4.14, `Inconsistent language versions` under 5.0. - The migration analyzer props injected `<Analyzer>` items by hand from `analyzers/dotnet/cs`; NuGet registers analyzers itself and selects the matching folder, so the injection was obsolete and would now force the wrong assembly to load. - Exception diagnostics reported `ex.StackTrace` (null for an exception that never left its throw site, and carrying neither type nor inner chain) — now `ex.ToString()` at all three call sites. - The pack guard tested the flattened assembly list, so it only fired when *no* variant produced output; it now checks each declared variant contributed assemblies. - `GeneratePackageOnBuild` is disabled for the generators; packing happens in CI or on an explicit `dotnet pack`. ## Note for reviewers **Building this repository requires a Roslyn 5.x host** (the .NET 10 SDK or Visual Studio 2026). That is already the documented prerequisite and every CI leg installs `10.0.x` last, but it is now a hard requirement. ## Related Issues _No tracking issue: this is a follow-up to the CS8784 clean-build failure reported against #4041, which fixed the packaged delivery path but left the in-repo project-reference path relying on the SGF resolver._ - Follow-up to #4041 ## Checklist _Put an `x` in the boxes that apply. You can complete these step by step after opening the PR._ - [x] I have signed the [CLA](https://opcfoundation.org/license/cla/ContributorLicenseAgreementv1.0.pdf) and read the [CONTRIBUTING](https://github.com/OPCFoundation/UA-.NETStandard/blob/master/CONTRIBUTING.md) doc. - [x] I have added tests that prove my fix is effective or that my feature works and increased code coverage. - [x] I have added all necessary documentation. - [x] I have verified that my changes do not introduce (new) build or analyzer warnings. - [x] I ran **all** tests locally using the **UA.slnx** solution against at least .net **framework** and .net **10**, and all passed. - [ ] I fixed **all** failing and flaky tests in the CI pipelines and **all** CodeQL warnings. - [ ] I have addressed **all** PR feedback received. ### Verification detail | Check | Result | | --- | --- | | `dotnet build UA.slnx` (clean, and after merging master) | 0 errors; 18 warnings, all pre-existing `CA1873` in `Opc.Ua.Client` | | `Opc.Ua.SourceGeneration.Tests` | 81/81 on net10.0 and net48 | | `Opc.Ua.SourceGeneration.Stack.Tests` | 92/92 on net10.0, 89/89 on net48 | | `Opc.Ua.SourceGeneration.Core.Tests` | 3722 passed, 8 skipped | | `Opc.Ua.MigrationAnalyzer.Tests` | 121/121 on net10.0 and net48 | | Package id set, master vs branch | identical, 47 packages | | Release build + `dotnet pack --no-build` | 47 packages, matching the manifest; both `roslyn4.14` and `roslyn5.0` present; no host-provided assemblies shipped | | `validate-source-generator-packages.ps1` | passes, including manifest, props-naming, end-to-end generator consumer and down-level host checks | | Down-level band under real csc 4.14.0 | all three analyzer packages load **and run** | | Negative tests | misnamed props → both checks fail as designed; hidden variant output → pack guard fires; 5.0 build placed in `roslyn4.14` → real `CS9057`; non-running generator name → execution assertion fires; expecting a `roslyn4.8` band → manifest check fires | --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 9ed53262-5cfa-429a-820e-bf6146a00d8b |
||
|
|
5b9bcedc62 |
Add OPC UA ISA-95 Common Model and Job Control support (#4089)
# Description Adds first-class support for the OPC UA ISA-95 companion specifications: - OPC-10030 Common Model. - OPC-10031-4 Job Control V1. - OPC-10031-4 Job Control V2. The change introduces `Opc.Ua.ISA95`, `Opc.Ua.ISA95.Client`, and `Opc.Ua.ISA95.Server`, together with a NativeAOT-compatible minimal server sample and comprehensive tests. ## Highlights - Compiles the three canonical NodeSets and identifier mapping CSV files through the source generator. - Adds NodeSet identifier mapping validation, typed method arguments/results, companion event records, and generated method argument nodes. - Provides typed Common Model builders with normative relationships and an injectable `GeoSpatialLocationType` provider. - Implements lossless V1/V2 Job Control providers over a shared version-neutral store, including state paths, status events, comments, response queries, catalog changes, and cohesive DI registration. - Adds subtype-aware typed clients, standalone encodeable registration, `IIsa95ClientFactory`, and V2 status-event streaming. - Adds the `MinimalIsa95Server` sample, package documentation, and an ISA-95 guide with conformance and HA guidance. - Tracks typed RSL/GPOS integration as follow-up issue #4095. ## Validation - `Opc.Ua.ISA95.Tests`: 137/137 passed on `net10.0` and `net48`. - Source-generator suites: 81/81 model, 90/90 stack, 3718 passed / 8 skipped core. - `EventRecordFieldReaders` feedback tests: 6/6 on `net10.0` and `net48`. - `EventRecordFieldReaders` changed-method patch coverage: 100% line coverage (36/36) and 100% branch coverage (22/22). - `Opc.Ua.ISA95`, `.Client`, and `.Server` build across all configured target frameworks without new diagnostics. - Cobertura line coverage: 88.08% model, 90.04% client, 91.19% server. - NativeAOT sample publishes and passes a live typed V2 Store/status-event validation. - The ISA-95 NativeAOT smoke test passes in the source-generated native test executable. - OPC UA KB NodeSet validation reports zero errors for Common, V1, and V2. The broader NativeAOT executable still reports unrelated existing GDS and complex-type test failures; the ISA-95-specific native test passes. ## Node state generator fixes Generating method arguments inline for imported nodesets regressed every model that already emits `InputArguments` / `OutputArguments` child node factories: - The inline block ran before the child factories. `MethodState.CreateOrReplaceInputArguments` keeps the property that was assigned first, so the child carrying the well-known NodeId was dropped and a NodeId-less placeholder remained in the address space. This broke browsing (reference descriptions without a target) and made method arguments unreachable at their well-known NodeIds. - The `MethodDeclarationId` fallback keyed on an autogenerated display name redirected every declared method of the standard address space to its own NodeId, which made method calls fail. The inline block is now emitted after the child factories and reduced to a value assignment when a child factory exists. The value is only re-emitted when an argument references a namespace other than OPC UA, because the value of an imported property is the verbatim XML of the source nodeset whose namespace indices do not survive the import. The `MethodDeclarationId` fallback is restricted to declarations without a resolvable NodeId. The generated OPC UA address space is byte-identical to `master` again. ## Related Issues - Fixes #4088 - Follow-up: #4095 |
||
|
|
20d9d65a64 |
Fix generated configuration namespace resolution (#4019)
# Description Fix source-generated configuration types whose explicit namespace references constants emitted by the same generator pass. Roslyn cannot resolve those constants while `[DataType]` attributes are analyzed, so the generated XML codec silently fell back to `urn:memorybuffer` / `urn:testdata` while the shipped configuration uses the model namespace URIs. This change: - adds `MODELGEN021` to fail when an explicitly supplied `[DataType.Namespace]` expression cannot be resolved; - uses compile-time-available model namespace URIs for the MemoryBuffer and TestData configuration types; - restores production-shaped XML fixtures and exercises the `UpdateExtension<T>()` / `ParseExtension<T>()` path; - documents the source-generator namespace requirement and migration guidance. Targeted validation passed: - `TypeGeneratorTests`: 17 tests on `net10.0` and `net48`; - `ConfigurationRoundTripTests`: 4 tests on `net10.0` and `net48`. ## Related Issues - Fixes #4014 ## Checklist - [ ] I have signed the [CLA](https://opcfoundation.org/license/cla/ContributorLicenseAgreementv1.0.pdf) and read the [CONTRIBUTING](https://github.com/OPCFoundation/UA-.NETStandard/blob/master/CONTRIBUTING.md) doc. - [x] I have added tests that prove my fix is effective or that my feature works and increased code coverage. - [x] I have added all necessary documentation. - [x] I have verified that my changes do not introduce (new) build or analyzer warnings. - [ ] I ran **all** tests locally using the **UA.slnx** solution against at least .net **framework** and .net **10**, and all passed. - [ ] I fixed **all** failing and flaky tests in the CI pipelines and **all** CodeQL warnings. - [x] I have addressed **all** PR feedback received. |
||
|
|
7cec2d614d | Move repository files to the consolidated layout |