From 1e01a64cc6bd0cfd71d55f4c4193c6a96c4dd457 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 6 Apr 2026 18:17:58 +0000 Subject: [PATCH 1/3] Initial plan From b5e270766385054bc1ffbc7ef32e2ef9ae97456b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 6 Apr 2026 18:23:17 +0000 Subject: [PATCH 2/3] fix: store TypeProvider references in AddTypeToKeep for lazy FQN resolution Agent-Logs-Url: https://github.com/microsoft/typespec/sessions/f4a12cd1-5ba2-4c12-bd25-9ca2677634c7 Co-authored-by: haiyuazhang <1924967+haiyuazhang@users.noreply.github.com> --- .../src/CodeModelGenerator.cs | 32 +++++++++++++++---- .../ModelProviders/ModelProviderTests.cs | 31 ++++++++++++++++++ 2 files changed, 57 insertions(+), 6 deletions(-) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/CodeModelGenerator.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/CodeModelGenerator.cs index d44b2b49305..1b934e6fa3c 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/CodeModelGenerator.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/CodeModelGenerator.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.ComponentModel.Composition; using System.Diagnostics; +using System.Linq; using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.TypeSpec.Generator.EmitterRpc; @@ -154,9 +155,16 @@ public virtual void AddSharedSourceDirectory(string sharedSourceDirectory) _sharedSourceDirectories.Add(sharedSourceDirectory); } - internal HashSet AdditionalRootTypes { get; } = []; + private readonly HashSet _additionalRootTypeNames = []; + private readonly HashSet _nonRootTypeNames = []; + private readonly List _additionalRootTypeProviders = []; + private readonly List _nonRootTypeProviders = []; - internal HashSet NonRootTypes { get; } = []; + internal HashSet AdditionalRootTypes => + [.. _additionalRootTypeNames, .. _additionalRootTypeProviders.Select(t => t.Type.FullyQualifiedName)]; + + internal HashSet NonRootTypes => + [.. _nonRootTypeNames, .. _nonRootTypeProviders.Select(t => t.Type.FullyQualifiedName)]; /// /// Adds a type to the list of types to keep. @@ -168,21 +176,33 @@ public void AddTypeToKeep(string typeName, bool isRoot = true) { if (isRoot) { - AdditionalRootTypes.Add(typeName); + _additionalRootTypeNames.Add(typeName); } else { - NonRootTypes.Add(typeName); + _nonRootTypeNames.Add(typeName); } } /// - /// Adds a type to the list of types to keep. + /// Adds a type to the list of types to keep. The type's fully qualified name is resolved lazily + /// when or is accessed, ensuring + /// that any namespace changes made by visitors are reflected. /// /// The type provider representing the type. /// Whether to treat the type as a root type. Any dependencies of root types will /// not have their accessibility changed regardless of the 'unreferenced-types-handling' value. - public void AddTypeToKeep(TypeProvider type, bool isRoot = true) => AddTypeToKeep(type.Type.FullyQualifiedName, isRoot); + public void AddTypeToKeep(TypeProvider type, bool isRoot = true) + { + if (isRoot) + { + _additionalRootTypeProviders.Add(type); + } + else + { + _nonRootTypeProviders.Add(type); + } + } /// /// Writes additional output files (e.g. configuration schemas) after the main code generation is complete. diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/ModelProviderTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/ModelProviderTests.cs index 7f6ef7ca815..df99a121b42 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/ModelProviderTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/ModelProviderTests.cs @@ -1221,6 +1221,37 @@ public void InternalModelsAreNotIncludedInAdditionalRootTypes() Assert.IsFalse(rootTypes.Contains("Sample.Models.MockInputModel")); } + [Test] + public void PublicModelTypeToKeepUpdatesAfterNamespaceChange() + { + var inputModel = InputFactory.Model( + "MockInputModel", + access: "public"); + + MockHelpers.LoadMockGenerator( + inputModelTypes: [inputModel]); + + var modelProvider = CodeModelGenerator.Instance.OutputLibrary.TypeProviders + .SingleOrDefault(t => t.Name == "MockInputModel") as ModelProvider; + Assert.IsNotNull(modelProvider); + + var originalFqn = modelProvider!.Type.FullyQualifiedName; + Assert.AreEqual("Sample.Models.MockInputModel", originalFqn); + + // Simulate a visitor changing the namespace (e.g., NamespaceVisitor) + modelProvider.Update(@namespace: "NewNamespace.Models"); + var newFqn = modelProvider.Type.FullyQualifiedName; + Assert.AreEqual("NewNamespace.Models.MockInputModel", newFqn); + + // After namespace change, AdditionalRootTypes should contain the updated FQN + var rootTypes = CodeModelGenerator.Instance.AdditionalRootTypes; + Assert.IsTrue(rootTypes.Contains(newFqn), + $"AdditionalRootTypes should contain the post-visitor FQN '{newFqn}' " + + $"but only contains: [{string.Join(", ", rootTypes)}]"); + Assert.IsFalse(rootTypes.Contains(originalFqn), + $"AdditionalRootTypes should not contain the stale pre-visitor FQN '{originalFqn}'"); + } + [TestCase(true, true, InputModelTypeUsage.Output, true, false)] [TestCase(true, false, InputModelTypeUsage.Output, true, false)] [TestCase(false, true, InputModelTypeUsage.Output, true, false)] From 6fe0b229243d6ee25f21539b41f9ca23d799f50a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 6 Apr 2026 18:27:36 +0000 Subject: [PATCH 3/3] refactor: use HashSet to prevent duplicate type references Agent-Logs-Url: https://github.com/microsoft/typespec/sessions/f4a12cd1-5ba2-4c12-bd25-9ca2677634c7 Co-authored-by: haiyuazhang <1924967+haiyuazhang@users.noreply.github.com> --- .../Microsoft.TypeSpec.Generator/src/CodeModelGenerator.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/CodeModelGenerator.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/CodeModelGenerator.cs index 1b934e6fa3c..91ed09d8594 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/CodeModelGenerator.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/CodeModelGenerator.cs @@ -157,8 +157,8 @@ public virtual void AddSharedSourceDirectory(string sharedSourceDirectory) private readonly HashSet _additionalRootTypeNames = []; private readonly HashSet _nonRootTypeNames = []; - private readonly List _additionalRootTypeProviders = []; - private readonly List _nonRootTypeProviders = []; + private readonly HashSet _additionalRootTypeProviders = []; + private readonly HashSet _nonRootTypeProviders = []; internal HashSet AdditionalRootTypes => [.. _additionalRootTypeNames, .. _additionalRootTypeProviders.Select(t => t.Type.FullyQualifiedName)];