Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Jan 14, 2026

Generated models could not inherit from external base types (e.g., Azure.ResourceManager.TrackedResourceData) because the code required custom base types to exist in CSharpTypeMap as ModelProvider instances.

Changes

  • Created SystemObjectTypeProvider: A new TypeProvider implementation that represents types from external assemblies without requiring a Roslyn type symbol. This handles cases where the base type is from a referenced assembly that cannot be found in the customization compilation.

  • Added BuildBaseTypeProvider() override in ModelProvider:

    • First checks if the type is already cached in CSharpTypeMap
    • Attempts to look up external base types from Roslyn's customization compilation via GetTypeByMetadataName
    • Creates NamedTypeSymbolProvider if the type symbol is found (provides full symbol information)
    • Falls back to creating SystemObjectTypeProvider if the type symbol is not found (for truly external types)
    • Returns BaseModelProvider for generated models to preserve existing behavior
  • Updated BuildBaseModelProvider():

    • Returns null for custom base types with namespaces (external types)
    • Maintains ModelProvider? return type for code paths that iterate base model hierarchy
  • Added comprehensive tests:

    • CanCustomizeBaseModelToExternalType: Tests inheritance from a custom external base type defined in customization
    • CanCustomizeBaseModelToSystemType: Tests inheritance from system types (e.g., System.Exception) to validate real-world scenarios like inheriting from Azure.ResourceManager.TrackedResourceData

Example

// Custom code can now inherit from external types
public partial class KeyVaultData : Azure.ResourceManager.TrackedResourceData
{
}

The generator now resolves TrackedResourceData using either NamedTypeSymbolProvider (if the type is found in the customization compilation) or SystemObjectTypeProvider (if it's from a referenced assembly), enabling type hierarchy traversal for external base types.

Original prompt

This section details on the original issue you should resolve

<issue_title>unable to customize base type of generated model to a non-generated type</issue_title>
<issue_description>In mgmt, we have a requirement to mitigate breaking changes regarding base type of a non-generated model, such as a system object type.

public partial class KeyVaultData : Azure.ResourceManager.TrackedResourceData

The customized base type is Azure.ResourceManager.Models.TrackedResourceData, which is not generated during the current generation.

But in MTG, we have the check to ensure the custom base type is either from input model or generated model.

// If the custom base type doesn't have a resolved namespace, then try to resolve it from the input model map.
// This will happen if a model is customized to inherit from another generated model, but that generated model
// was not also defined in custom code so Roslyn does not recognize it.
if (string.IsNullOrEmpty(baseType.Namespace))
{
if (CodeModelGenerator.Instance.TypeFactory.InputModelTypeNameMap.TryGetValue(baseType.Name, out var baseInputModel))
{
baseType = CodeModelGenerator.Instance.TypeFactory.CreateCSharpType(baseInputModel);
}
}
if (baseType != null && CodeModelGenerator.Instance.TypeFactory.CSharpTypeMap.TryGetValue(
baseType,
out var customBaseType) &&
customBaseType is ModelProvider customBaseModel)
{
return customBaseModel;
}
}

I think the issue here is, we don't have a provider to represent such kind of type, such as InheritableSystemObjectModelProvider in mgmt.</issue_description>

Comments on the Issue (you are @copilot in this section)


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Copilot AI and others added 2 commits January 14, 2026 09:08
- Modified ModelProvider to support base types from external assemblies
- Added BuildBaseTypeProvider method that creates NamedTypeSymbolProvider for external base types
- BaseModelProvider remains ModelProvider? for generated models iteration
- BaseTypeProvider now handles both generated and external base types
- Added comprehensive test CanCustomizeBaseModelToExternalType
- Test verifies external base type properties are accessible via BaseTypeProvider

Co-authored-by: live1206 <5196139+live1206@users.noreply.github.com>
- Added comment explaining .NET metadata format for generic types
- Made test assertion more descriptive with explanation of expected properties
- Verified caching is already handled by lazy initialization pattern

Co-authored-by: live1206 <5196139+live1206@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix customization of base type for generated model Enable customizing model base type to non-generated external types Jan 14, 2026
Copilot AI requested a review from live1206 January 14, 2026 09:14
? $"{baseType.Namespace}.{baseType.Name}`{baseType.Arguments.Count}"
: $"{baseType.Namespace}.{baseType.Name}";

var baseTypeSymbol = customization.GetTypeByMetadataName(fullyQualifiedName);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot Here you are assuming you can get the TypeSymbol of the base type from the custom code.
What if the base type is not defined within the custom code, then you can't get the TypeSymbol.
We need to add a new implementation of TypeProvider, let's name it SystemObjectType, which represents a type from another assembly.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're absolutely right. I've added SystemObjectTypeProvider to handle cases where the base type is from a referenced assembly and cannot be found via GetTypeByMetadataName.

The implementation now:

  1. First tries to find the type in CSharpTypeMap (cached)
  2. Then tries GetTypeByMetadataName on the customization compilation (creates NamedTypeSymbolProvider if found)
  3. Falls back to creating a SystemObjectTypeProvider if the type symbol is not found

Fixed in commit 75c90e5.

…compilation

- Created SystemObjectTypeProvider to represent types from referenced assemblies
- Updated BuildBaseTypeProvider to fall back to SystemObjectTypeProvider when type symbol not found
- This handles cases where base type is from a referenced assembly not in customization
- Updated test to handle both NamedTypeSymbolProvider and SystemObjectTypeProvider scenarios

Co-authored-by: live1206 <5196139+live1206@users.noreply.github.com>
Copilot AI requested a review from live1206 January 14, 2026 09:31

namespace Sample.Models
{
public partial class MockInputModel : ExternalBaseModel
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot can you add another test case with custom code, which updated the base model to a system type?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added test CanCustomizeBaseModelToSystemType that inherits from System.Exception. This demonstrates that models can successfully inherit from system types like Azure.ResourceManager.TrackedResourceData. The test shows that system types from referenced assemblies are found via GetTypeByMetadataName and use NamedTypeSymbolProvider.

Fixed in commit 09c89ed.

- Created CanCustomizeBaseModelToSystemType test with System.Exception as base type
- This validates that models can inherit from system types like Azure.ResourceManager.TrackedResourceData
- Test demonstrates that system types from referenced assemblies are found via GetTypeByMetadataName
- All 1191 tests pass

Co-authored-by: live1206 <5196139+live1206@users.noreply.github.com>
Copilot AI requested a review from live1206 January 14, 2026 09:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

unable to customize base type of generated model to a non-generated type

2 participants