2.0 Migration Analyzer and codefixer with Agent update#3820
Draft
marcschier wants to merge 10 commits into
Draft
2.0 Migration Analyzer and codefixer with Agent update#3820marcschier wants to merge 10 commits into
marcschier wants to merge 10 commits into
Conversation
Introduces Tools/Opc.Ua.CodeFixers, a new Roslyn analyzer + code-fixer package that helps consumers migrate from OPC UA .NET Standard 1.5.378 to 2.0 by mechanizing 17 of the breaking-change patterns documented in Docs/MigrationGuide.md. Rules (UA0001-UA0020): UA0001 Utils.Trace/LogX to ILogger (diagnostic only); UA0002 removed Type Collections to List<T>/ArrayOf<T>; UA0003 == null on now-struct built-ins to .IsNull; UA0004 ?. on now-struct built-ins; UA0005 byte[] to ByteString at API boundaries; UA0006 obsolete Variant(object|DateTime|Guid|byte[]) ctors to Variant.From; UA0007 new NodeId(string) to NodeId.Parse; UA0008 Session.Call params object[] to Variant.From wrapping; UA0009 [DataContract]/[DataMember] to [DataType]/[DataTypeField]; UA0010 remove using/Dispose on CertificateIdentifier/UserIdentity/IUserIdentityTokenHandler (diagnostic only); UA0011 IUserIdentityTokenHandler sync to Async (diagnostic only); UA0012 CertificateFactory static to DefaultCertificateFactory.Instance; UA0014 DataValue.IsGood static helper to instance property; UA0015 GDS/LDS client sync/APM to Async (diagnostic only); UA0018 CertificateIdentifier.Certificate getter to ResolveAsync (diagnostic only); UA0019 obsolete new DataValue(StatusCode) to DataValue.FromStatusCode; UA0020 EncodeableFactory.GlobalFactory/Create to ServiceMessageContext.Factory/Fork. Includes Tools/Opc.Ua.CodeFixers (analyzer project, netstandard2.0, EnforceExtendedAnalyzerRules, centralized DiagnosticDescriptors and DiagnosticIds, UaSymbols + SymbolExtensions helpers, AnalyzerReleases tracking) and Tests/Opc.Ua.CodeFixers.Tests (87 NUnit tests with a custom AnalyzerHarness and OpcUaStubs). Adds Microsoft.CodeAnalysis.CSharp.Workspaces 5.3.0 and Microsoft.CodeAnalysis.Workspaces.Common 5.3.0 to Directory.Packages.props (used PrivateAssets=all by the analyzer; required by the test harness). Registers the projects in UA.slnx and Tools/SourceGeneration.slnx under a new 'CodeFixers' folder. Tests pass on net10.0 (87/87).
|
|
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## master #3820 +/- ##
==========================================
- Coverage 71.13% 71.12% -0.01%
==========================================
Files 778 781 +3
Lines 143274 143329 +55
Branches 24234 24241 +7
==========================================
+ Hits 101918 101946 +28
- Misses 33005 33026 +21
- Partials 8351 8357 +6 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
…package Introduces Tools/Opc.Ua.CodeFixers.Shim/Opc.Ua.CodeFixers.Shim.csproj which ships alongside the analyzer DLL in the OPCFoundation.NetStandard.Opc.Ua.CodeFixers NuGet. Consumer projects can drop the package in: 1.5.378-style code keeps compiling against 1.6 via the shim extension surface, and the matching UA00xx analyzer fires Info-level diagnostics so consumers can migrate off the shim incrementally. Shim contents organized under Shims/<libname>/ mirroring the source project layout: Shims/Types/, Shims/Core.Types/, Shims/Core/, Shims/Client/, Shims/Configuration/, Shims/Gds.Client.Common/. Marker [OpcUaShim(RuleId)] in Marker/OpcUaShimAttribute.cs lets the analyzer correlate shim calls back to the UA00xx migration rule. Phase 6.C moved obsolete extension surface from 8 *Obsolete*.cs files in Stack/Opc.Ua.Types, Stack/Opc.Ua.Core, Stack/Opc.Ua.Core.Types, Libraries/Opc.Ua.Client, Libraries/Opc.Ua.Configuration into the shim project. Phase 6.D added 6 NEW shims for genuinely-removed members (EncodeableFactory.GlobalFactory; CertificateIdentifier.Certificate (throwing); IUserIdentityTokenHandler.Encrypt/Decrypt/Sign/Verify sync wrappers; GlobalDiscoveryServerClient.RegisterApplication/UnregisterApplication; ServerPushConfigurationClient.ApplyChanges; LocalDiscoveryServerClient.BeginFindServers/EndFindServers APM). Phase 6.E extended the existing UA0008/UA0011/UA0015/UA0018/UA0020 analyzers to detect calls binding to shim extensions via [OpcUaShim] marker. Phase 6.F added Tests/Opc.Ua.CodeFixers.Shim.Tests with 11 runtime + meta tests (verifying every [OpcUaShim] member also carries [Obsolete] and a well-formed UA00xx id). Phase 6.G rewrote NugetREADME.md to cover both the analyzer rules and the shim. Three *Obsolete*.cs files left in-place (BLOCKED): Stack/Opc.Ua.Core/Types/Utils/UtilsObsolete.cs, Stack/Opc.Ua.Core.Types/Constants/Helpers.Obsolete.cs, Libraries/Opc.Ua.Client/CoreClientUtilsObsolete.cs. Reason: C# 14 extension(StaticClass) does NOT add real static members to a static class (per csharplang/proposals/extensions.md 131-138), so consumer call syntax like Utils.Trace(...) cannot be preserved by relocating the implementation to a separate assembly. Cross-project internal callers in Opc.Ua.Configuration/Opc.Ua.Server/ConsoleReferenceClient that called the moved IServerBase.Stop() and TraceConfiguration.ApplySettings() extensions were rewritten to inline the modern non-obsolete equivalents (Utils.SetTraceLog/SetTraceMask/SetTraceOutput, IServerBase.StopAsync). InternalsVisibleTo added on Opc.Ua.Core and Opc.Ua.Configuration so the shim can reach the internal helpers its moved factory members already depended on. Build: UA.slnx compiles 0 errors. Tests: Opc.Ua.CodeFixers.Tests 94/94 passing; Opc.Ua.CodeFixers.Shim.Tests 8 pass + 3 ignored placeholders (sealed GDS client types cannot be Moq-ed; tests deferred to integration). Tools/Opc.Ua.SourceGeneration.Core/Generators/ClientApiTemplates.cs adapted to emit modern async-with-GetAwaiter().GetResult() bodies instead of the now-moved obsolete sync/APM helpers.
…packaging Phase 7: UA0021 covers the 1.5.378 to 1.6 rename of CertificateValidator and CertificateValidationEventArgs (discovered during Phase 6.F samples dogfood). Rule is Info-level / diagnostic-only because the 1.6 replacement is structurally different (event-based -> async result + callback pattern); no auto-fix is feasible and no shim is provided. Adds analyzer at Tools/Opc.Ua.CodeFixers/Analyzers/UA0021CertificateValidatorRenameAnalyzer.cs with dual-mode detection (semantic when the legacy Obsolete symbol still resolves, syntactic fallback gated by 'using Opc.Ua' when the type is fully removed). Tests increase from 94 to 99 (5 new UA0021 tests). Phase 8: enable bundled NuGet packaging for OPCFoundation.NetStandard.Opc.Ua.CodeFixers. Adds a hand-authored Tools/Opc.Ua.CodeFixers/Opc.Ua.CodeFixers.nuspec that combines the analyzer DLL (analyzers/dotnet/cs/Opc.Ua.CodeFixers.dll) and the shim DLL (lib/<tfm>/Opc.Ua.CodeFixers.Shim.dll) for all six TFMs (net472, net48, netstandard2.1, net8.0, net9.0, net10.0). Declares the six OPCFoundation.NetStandard.Opc.Ua.* runtime dependencies per TFM group. Opc.Ua.CodeFixers.csproj switched from IsPackable=false to true with GeneratePackageOnBuild, a _BuildShimAllTfmsBeforePack target that triggers shim builds for every required TFM, and NuspecProperties set inside the GenerateNuspec target so NBGV's computed PackageVersion is captured. Smoke test on a throwaway net10.0 console project resolves the analyzer + shim cleanly and produces only the expected UA00xx warnings, zero errors. Other: Tools/Opc.Ua.CodeFixers.Shim/Opc.Ua.CodeFixers.Shim.csproj suppresses CS0419 (pre-existing baseline failure on net472/net48/netstandard2.1 from the OpcUaShimAttribute cref to ObsoleteAttribute - ambiguous on TFMs where System.Runtime forwards the type). NugetREADME.md gains the UA0021 row and a one-line RS1038 packaging note (analyzer + code-fix shipped in one assembly is deliberate, suppression documented). Verification: dotnet build 0 errors; Opc.Ua.CodeFixers.Tests 99/99 passing; Opc.Ua.CodeFixers.Shim.Tests 8 pass + 3 ignored.
Fixes three bugs surfaced by the Phase 10 samples dogfood and adds a new
analyzer rule for the CertificateValidator property rename.
F1 - analyzer auto-load via NuGet props injection.
The hand-authored .nuspec packaged the analyzer at analyzers/dotnet/cs/
but NuGet's restore-time analyzer detection did not register it in the
consumer's project.assets.json. Two coordinated fixes here:
* Renamed the build props file from OPCFoundation.Opc.Ua.CodeFixers.props
to OPCFoundation.NetStandard.Opc.Ua.CodeFixers.props so it matches the
package id exactly. NuGet auto-imports build/<package-id>.props into
consumer csprojs; the previous mismatched name prevented auto-import.
* Added an <Analyzer Include="..\analyzers\dotnet\cs\..." /> item to the
props file as a belt-and-suspenders measure. Once both routes are in
place the analyzer loads transparently, so consumers no longer need
the explicit <Analyzer> workaround.
F2 - DataValueObsolete extension(ExtensionObject) typo (Shims/Types/BuiltIn/BuiltInType.cs).
Changed extension(ExtensionObject) to extension(DataValue) so the six
obsolete static helpers (IsGood / IsBad / IsUncertain / IsNotGood /
IsNotBad / IsNotUncertain) bind as DataValue.IsGood(...) again. The bug
was inherited from upstream master at Phase 6.C move time and surfaced
as a CS1929 compile error on the dogfood sample. Adds
DataValueObsoleteShimTests with two regression tests.
F3 - UA0021 namespace heuristic relaxation
(UA0021CertificateValidatorRenameAnalyzer.cs).
Replaced the strict "using Opc.Ua;" check with a HasOpcUaContext helper
that accepts any using directive whose name is Opc.Ua or starts with
Opc.Ua. plus namespace declarations under the same prefix. Real-world
consumer code rarely imports the bare Opc.Ua namespace - sub-namespace
imports like Opc.Ua.Configuration and Opc.Ua.Server are the norm. Three
new tests cover the relaxation.
F5 / UA0022 - ApplicationConfiguration.CertificateValidator and
ServerBase.CertificateValidator removed in 2.0. New analyzer
UA0022CertificateValidatorPropertyRenameAnalyzer with a dual-mode design
that mirrors UA0021: semantic path when the legacy property is still
present as [Obsolete], syntactic fallback when the property has been
fully removed. Code-fix mechanically renames the property identifier to
CertificateManager. Five tests cover both receivers, the negative case,
and the fix. NugetREADME row added and the rule range bumped to
UA0001-UA0022.
Test counts: analyzer suite 99 -> 107; shim suite 8 active -> 10 active.
Combined build 0 errors. Dogfood re-run confirmed the F1 props
injection now auto-loads the analyzer (UA0007 fires on a probe without
manual <Analyzer> wiring).
Out of scope / deferred:
- F6 (bool -> ITelemetryContext parameter swap across multiple ctors) -
generalizes beyond a single rule; deferred to a future PR.
- Upstream issue for F2 - file separately, not blocking.
- A second-sample dogfood (e.g. ConsoleAggregationServer) - follow-up.
…Server
The 2.0 ctor inserted a required ITelemetryContext parameter BEFORE the
trailing 'bool autoApprove = true' parameter, which silently breaks
1.5.378 callers that wrote:
new GlobalDiscoverySampleServer(database, request, group, userDb, true)
because the trailing 'true' now binds to ITelemetryContext (compile
error). This was the lone F6-shape error surfaced by the Phase 11
CodeFixers dogfood run against UA-.NETStandard-Samples.
Add an [Obsolete] back-compat overload matching the 1.5.378 signature
exactly, forwarding to the modern ctor with telemetry: null!. Existing
in-tree callers (test fixtures, Aot tests) already use the new
ITelemetryContext signature, so this is purely additive and gives
sample-style code a soft landing.
Previously the single Opc.Ua.CodeFixers.dll bundled both DiagnosticAnalyzer
and CodeFixProvider types and referenced Microsoft.CodeAnalysis 5.3
(.NET SDK 10's csc-internal version). This caused csc.exe to silently
*fail* to load the analyzer: csc.exe ships only Microsoft.CodeAnalysis.dll
+ CSharp.dll in its bincore, not Workspaces. When the analyzer DLL was
JIT-loaded, lazy resolution of Workspaces types from CodeFix code paths
crashed the analyzer host, which swallowed the failure silently. Dogfood
result: 0 UA diagnostics across all 42 sample projects despite the
analyzer being on csc's /analyzer: line.
Fix:
* Split into Opc.Ua.CodeFixers.dll (analyzers only, references Microsoft.
CodeAnalysis.CSharp only) and Opc.Ua.CodeFixers.CodeFixes.dll (code-fix
providers, references Microsoft.CodeAnalysis.CSharp.Workspaces). Both
ship under analyzers/dotnet/cs/; csc.exe loads the first, Workspaces-
aware hosts (VS, dotnet format) load both.
* Pin Microsoft.CodeAnalysis.CSharp to 4.14.0 via VersionOverride in both
analyzer projects. The repo-wide 5.3 version is the csc compiler version,
not a stable analyzer API; analyzers must target the stable 4.x API.
* Share DiagnosticIds/DiagnosticDescriptors + Helpers via <Compile Link=>
to avoid a NuGet restore cycle (CodeFixes ProjectReferences would loop).
* Hoist UA0008.MethodNameProperty and UA0020.{FormProperty,FormGlobalFactory,
FormCreate} into a shared internal WellKnownProperties.cs so the analyzer
+ code-fix copies can pull from the same string constants.
* Nuspec ships both DLLs in analyzers/dotnet/cs/.
* Auto-import props (build/OPCFoundation.NetStandard.Opc.Ua.CodeFixers.props)
references both DLLs as <Analyzer> items.
Verified:
* Pack/restore produces a package with both DLLs.
* /reportAnalyzer in a real consumer build confirms all 19 analyzers
initialize and execute (UA0001-UA0022).
* All 107 unit tests pass on net10.0.
Also updates .github/agents/opcua-v20-migration.agent.md to put the
CodeFixers NuGet install at the top of the migration workflow, so any
user upgrading from 1.5.378 to 2.0 starts by adding one PackageReference
and lets the analyzer+shim do as much of the work as possible before
falling back to the categorical manual rules.
User-facing rename to better convey purpose: the package was about
"migrating" 1.5.378 callers to 2.0, not about generic Roslyn code fixers.
Directory / project / assembly / package / namespace renames:
Tools/Opc.Ua.CodeFixers -> Tools/Opc.Ua.MigrationAnalyzer
Tools/Opc.Ua.CodeFixers.CodeFixes -> Tools/Opc.Ua.MigrationAnalyzer.CodeFixes
Tools/Opc.Ua.CodeFixers.Shim -> Tools/Opc.Ua.MigrationHelpers
Tests/Opc.Ua.CodeFixers.Tests -> Tests/Opc.Ua.MigrationAnalyzer.Tests
Tests/Opc.Ua.CodeFixers.Shim.Tests -> Tests/Opc.Ua.MigrationHelpers.Tests
OPCFoundation.NetStandard.Opc.Ua.CodeFixers
-> OPCFoundation.NetStandard.Opc.Ua.MigrationAnalyzer
Assembly: Opc.Ua.CodeFixers -> Opc.Ua.MigrationAnalyzer
Opc.Ua.CodeFixers.CodeFixes -> Opc.Ua.MigrationAnalyzer.CodeFixes
Opc.Ua.CodeFixers.Shim -> Opc.Ua.MigrationHelpers
Namespaces: Opc.Ua.CodeFixers.* -> Opc.Ua.MigrationAnalyzer.*
Opc.Ua.CodeFixers.Shim -> Opc.Ua.MigrationHelpers
Solution layout:
Tools/SourceGeneration.slnx -> Tools/Roslyn.slnx
(now hosts both source-generation and migration-analyzer projects, plus
the CodeFixes project that was missing from the prior slnx.)
Central package pinning:
Microsoft.CodeAnalysis.CSharp 5.3.0 -> 4.14.0
Microsoft.CodeAnalysis.CSharp.Workspaces 5.3.0 -> 4.14.0
Microsoft.CodeAnalysis.Workspaces.Common 5.3.0 -> 4.14.0
(the analyzer assembly must target the stable 4.x analyzer API; the 5.x
range was the csc-internal version and unsafe for analyzers. Per-project
VersionOverride removed since the central pin now covers it.)
Documentation:
Docs/MigrationGuide.md - one ref updated to new package id.
.github/agents/opcua-v20-migration.agent.md - all DLL/package/namespace
references in the agent text updated to the new names.
Test fixes shaken out by the full-slnx build:
* Removed redundant async/await in AnalyzerHarness (RCS1174) - was hidden
under Roslynator's stricter analyzer that fired post-rename rebuild.
* Polyfilled [GeneratedRegex] partial method in
OpcUaShimAttributeInventoryTests for net472/net48 - the attribute is
.NET 7+ only; on legacy TFMs we fall back to a static compiled Regex.
Verified:
* dotnet build UA.slnx -c Debug succeeds (0 errors, 2 expected NU1702
warnings from the netstandard2.0 analyzer csproj cross-referencing
the multi-TFM helpers project).
* dotnet test ... MigrationAnalyzer.Tests passes 107/107 on net10.0.
* dotnet test ... MigrationHelpers.Tests passes 10/10 + 3 skipped.
* dotnet pack ... MigrationAnalyzer.csproj produces a package with two
analyzer DLLs (analyzers/dotnet/cs/) + six TFMs of helpers under lib/.
* Analyzer DLL references only Microsoft.CodeAnalysis 4.14.0 +
Microsoft.CodeAnalysis.CSharp 4.14.0 (Workspaces-free, csc-safe).
…nalyzer.Core, flatten Shims
Three follow-up renames:
Tools/Opc.Ua.MigrationAnalyzer.CodeFixes -> Tools/Opc.Ua.MigrationAnalyzer.CodeFixer
Tools/Opc.Ua.MigrationHelpers -> Tools/Opc.Ua.MigrationAnalyzer.Core
Tests/Opc.Ua.MigrationHelpers.Tests -> Tests/Opc.Ua.MigrationAnalyzer.Core.Tests
Also collapses the nested Shims/ folder in the Core project so the shim
type folders (Client/, Configuration/, Core/, Gds.Client.Common/, Types/)
sit side-by-side with the .csproj at the project root. The old
Shims/Foo/Bar.cs path now lives directly at Foo/Bar.cs. Marker/,
Properties/, readme.md are unchanged.
Assembly / namespace / package id rename in lock-step:
Opc.Ua.MigrationAnalyzer.CodeFixes (assembly + namespace)
-> Opc.Ua.MigrationAnalyzer.CodeFixer
Opc.Ua.MigrationHelpers (assembly)
-> Opc.Ua.MigrationAnalyzer.Core
Namespace inside the Core (shim) project stays Opc.Ua.* / sub-namespaces.
Package id OPCFoundation.NetStandard.Opc.Ua.MigrationAnalyzer unchanged.
UA.slnx / Tools/Roslyn.slnx project paths updated; analyzer csproj's
nuspec property paths, MSBuild self-invoked targets, and ProjectReferences
all point at the renamed directories / csproj filenames.
Verified:
* dotnet build UA.slnx -c Debug succeeds (0 errors, 572 pre-existing CA2007
/ NU1702 warnings).
* dotnet test ... MigrationAnalyzer.Tests passes 107/107 on net10.0.
* dotnet test ... MigrationAnalyzer.Core.Tests passes 10/10 (+3 skipped).
* dotnet pack ... MigrationAnalyzer.csproj produces the package with
analyzers/dotnet/cs/{Opc.Ua.MigrationAnalyzer.dll,
Opc.Ua.MigrationAnalyzer.CodeFixer.dll} + six TFMs of
Opc.Ua.MigrationAnalyzer.Core.dll under lib/.
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.
Proposed changes
Introduces
OPCFoundation.NetStandard.Opc.Ua.MigrationAnalyzer— a single NuGet package that ships three coordinated DLLs to make the 1.5.378 → 2.0 upgrade as close to "install package, rundotnet format, remove package" as possible:Opc.Ua.MigrationAnalyzer.dllanalyzers/dotnet/cs/UA0001–UA0022) covering every breaking-change pattern inDocs/MigrationGuide.md. Built against the stable Roslyn 4.14 analyzer API — loads cleanly in csc.exe (noMicrosoft.CodeAnalysis.Workspacesreference).Opc.Ua.MigrationAnalyzer.CodeFixer.dllanalyzers/dotnet/cs/CodeFixProviders; loaded only by Workspaces-aware hosts (Visual Studio,dotnet format analyzers).Opc.Ua.MigrationAnalyzer.Core.dlllib/<tfm>/fornet472, net48, netstandard2.1, net8.0, net9.0, net10.0Migration workflow the package enables
OPCFoundation.NetStandard.Opc.Ua.*PackageReference to2.0.*-*.dotnet build. Most call sites that 1.6 made obsolete still compile because the Core (shim) DLL re-supplies them. What remains are[Obsolete]warnings +UA00xxanalyzer diagnostics.UA0001/UA0011/UA0015/UA0018/UA0021diagnostics manually — they cover patterns that require human judgement (telemetry plumbing, async promotion, structural redesigns).19-rule reference
UA0001Utils.Trace/Utils.LogXUA0002<Type>CollectionwrappersList<T>/ArrayOf<T>)UA0003x == nullon now-struct built-insx.IsNull)UA0004?.on now-struct built-ins?)UA0005byte[]whereByteStringis expected.ToByteString())UA0006new Variant(object|DateTime|Guid|byte[])Variant.From(...))UA0007new NodeId(string)/new ExpandedNodeId(string)Parse)UA0008Session.Call(..., params object[])Variant.From)UA0009[DataContract]/[DataMember]on config extensions[DataType]/[DataTypeField])UA0010using/DisposeonCertificateIdentifier/UserIdentity/IUserIdentityTokenHandlerUA0011IUserIdentityTokenHandler.{Encrypt,Decrypt,Sign,Verify}UA0012CertificateFactory.*static helpersUA0014DataValue.IsGood(dv)static helperdv.IsGood)UA0015UA0018CertificateIdentifier.CertificategetterLoadCertificate2Async)UA0019new DataValue(StatusCode[, ts])UA0020EncodeableFactory.GlobalFactory/Create()ServiceMessageContext.Factory/Fork())UA0021CertificateValidator/CertificateValidationEventArgs(structural rename)UA0022ApplicationConfiguration.CertificateValidator/ServerBase.CertificateValidatorproperty rename.CertificateManager)What the Core (shim) DLL covers
Opc.Ua.MigrationAnalyzer.Core.dllships obsolete extension members (using the C# 14extensionkeyword) so 1.5.378 call sites continue to compile:NodeId/Variant/DataValuenull-check helpers,Sessionsync helpers,Subscriptionsync helpers,ApplicationInstancehelpers,ServerBase.Start/Stop,TransportChannelAPM (BeginX/EndX),ChannelBasestatic factory methods, etc.EncodeableFactory.GlobalFactory,CertificateIdentifier.Certificate(throws), sync wrappers forIUserIdentityTokenHandler.{Encrypt,Decrypt,Sign,Verify}, sync + APM wrappers for the GDS / LDS client APIs,GlobalDiscoverySampleServer1.5.378-shape ctor (in-treeLibraries/Opc.Ua.Gds.Server.Common/).What the shim cannot cover
Source-level changes the shim has no syntactic foothold for — use the listed analyzer fix:
== null/!= nullon now-struct types — UA0003?.on now-struct types — UA0004using var x = new CertificateIdentifier(...)— UA0010[DataContract]/[DataMember]on configuration extensions — UA0009<Type>Collectionwrappers — UA0002CertificateValidatortype rename — UA0021 (manual — structural rewrite)Repo layout
Documentation updates
Docs/MigrationGuide.md— adds a "Automate the migration" callout pointing at the new package..github/agents/opcua-v20-migration.agent.md— rewritten so the first step is installing the migration package; the 14-section categorical reference is preserved as a fallback for patterns the analyzers can't cover. Adds aTreatWarningsAsErrorsrecipe and a "known compatibility gaps" section for legacy.NET FrameworkWinForms projects (which don't honourDirectory.Build.targetsPackageReference injection).Central package pinning
Directory.Packages.propspinsMicrosoft.CodeAnalysis.*(Common, CSharp, CSharp.Workspaces, Workspaces.Common) to 4.14.0 — the stable analyzer API surface. The earlier 5.3 pin was the csc-internal version, which is not safe for analyzer hosts.Dogfooded against
OPCFoundation/UA-.NETStandard-SamplesThe full 42-sample dogfood pass surfaced a critical analyzer-loader bug: the analyzer DLL initially co-shipped its code-fix providers in one assembly, which transitively referenced
Microsoft.CodeAnalysis.Workspaces.dll. csc.exe's analyzer host ships onlyMicrosoft.CodeAnalysis.dll+CSharp.dllin its bincore and silently swallows load failures — net result: zero diagnostics across all samples even though/analyzer:was on the csc command line. Fix landed in commit861fa6ee1:Opc.Ua.MigrationAnalyzer.dll(Workspaces-free, csc-safe), code-fixes inOpc.Ua.MigrationAnalyzer.CodeFixer.dll(Workspaces-aware, loaded only in IDE /dotnet format).Microsoft.CodeAnalysis.CSharp 5.xis the csc compiler version and not appropriate for analyzers./p:ReportAnalyzer=trueconfirms all 19 analyzers initialise and execute on real consumer code.Additional dogfood findings documented in the migration agent's "known compatibility gaps" section:
.Net4sample projects use pre-SDK MSBuild XML (xmlns="…/2003") and ignoreDirectory.Build.targets<PackageReference>injection — consumers in this format must add the migration package to their csproj inline. Thedotnet buildresx-tooling failure (MSB3822 / MSB3823) on these projects is unrelated to this PR; users must build them with full MSBuild.exe.Reference Server.csprojdepends on the unpublishedOPCFoundation.NetStandard.Opc.Ua.Quickstarts.Serversmeta-package; consumers must switch to aProjectReferenceagainstApplications/Quickstarts.Servers.Packaging design notes
build/OPCFoundation.NetStandard.Opc.Ua.MigrationAnalyzer.propsis auto-imported by NuGet (file name must match package id exactly) and injects both analyzer DLLs as<Analyzer>items — this works around the hand-authored nuspec not auto-registeringanalyzers/dotnet/cs/assets.DiagnosticIds.cs/DiagnosticDescriptors.cs/WellKnownProperties.cs/Helpers/*.csare shared via<Compile Link=…>between the analyzer and code-fixer projects to break what would otherwise be a NuGet restore cycle (CodeFixer ProjectReferences the analyzer for shared constants; analyzer's pack pipeline MSBuild-invokes the CodeFixer build).Opc.Ua.MigrationAnalyzer.Coreis multi-TFM (net472, net48, netstandard2.1, net8.0, net9.0, net10.0) and non-packable on its own; the parent migration package's nuspec consumes each TFM's DLL by path.Verification
dotnet build UA.slnx -c Debug— 0 errors (572 pre-existing CA2007 / NU1702 warnings).dotnet test Tests/Opc.Ua.MigrationAnalyzer.Tests— 107 / 107 analyzer + code-fix tests pass onnet10.0.dotnet test Tests/Opc.Ua.MigrationAnalyzer.Core.Tests— 10 / 10 active shim tests + 3 skipped (environment-dependent).dotnet pack Tools/Opc.Ua.MigrationAnalyzer/Opc.Ua.MigrationAnalyzer.csproj— produces a single.nupkgwithanalyzers/dotnet/cs/{Opc.Ua.MigrationAnalyzer.dll, Opc.Ua.MigrationAnalyzer.CodeFixer.dll}+ 6-TFMlib/<tfm>/Opc.Ua.MigrationAnalyzer.Core.dll.Microsoft.CodeAnalysis 4.14.0+Microsoft.CodeAnalysis.CSharp 4.14.0— Workspaces-free, csc-safe.Types of changes