[release/v7.4.2] Fix PowerShell class to support deriving from an abstract class with abstract properties (#21331) (#21422)

This commit is contained in:
Patrick Meinecke
2024-04-04 15:22:35 -07:00
committed by GitHub
parent 73865ce253
commit 0e4b9d74f3
2 changed files with 60 additions and 5 deletions
@@ -276,7 +276,7 @@ namespace System.Management.Automation.Language
internal readonly TypeBuilder _staticHelpersTypeBuilder;
private readonly Dictionary<string, PropertyMemberAst> _definedProperties;
private readonly Dictionary<string, List<Tuple<FunctionMemberAst, Type[]>>> _definedMethods;
private HashSet<Tuple<string, Type>> _interfaceProperties;
private HashSet<Tuple<string, Type>> _abstractProperties;
internal readonly List<(string fieldName, IParameterMetadataProvider bodyAst, bool isStatic)> _fieldsToInitForMemberFunctions;
private bool _baseClassHasDefaultCtor;
@@ -446,9 +446,9 @@ namespace System.Management.Automation.Language
private bool ShouldImplementProperty(string name, Type type)
{
if (_interfaceProperties == null)
if (_abstractProperties == null)
{
_interfaceProperties = new HashSet<Tuple<string, Type>>();
_abstractProperties = new HashSet<Tuple<string, Type>>();
var allInterfaces = new HashSet<Type>();
// TypeBuilder.GetInterfaces() returns only the interfaces that was explicitly passed to its constructor.
@@ -467,12 +467,23 @@ namespace System.Management.Automation.Language
{
foreach (var property in interfaceType.GetProperties())
{
_interfaceProperties.Add(Tuple.Create(property.Name, property.PropertyType));
_abstractProperties.Add(Tuple.Create(property.Name, property.PropertyType));
}
}
if (_typeBuilder.BaseType.IsAbstract)
{
foreach (var property in _typeBuilder.BaseType.GetProperties())
{
if (property.GetAccessors().Any(m => m.IsAbstract))
{
_abstractProperties.Add(Tuple.Create(property.Name, property.PropertyType));
}
}
}
}
return _interfaceProperties.Contains(Tuple.Create(name, type));
return _abstractProperties.Contains(Tuple.Create(name, type));
}
public void DefineMembers()
@@ -628,3 +628,47 @@ class Derived : Base
$sb.Invoke() | Should -Be 200
}
}
Describe 'Base type has abstract properties' -Tags "CI" {
It 'can derive from `FileSystemInfo`' {
## FileSystemInfo has 3 abstract members that a derived type needs to implement
## - public abstract bool Exists { get; }
## - public abstract string Name { get; }
## - public abstract void Delete ();
class myFileSystemInfo : System.IO.FileSystemInfo
{
[string] $Name
[bool] $Exists
myFileSystemInfo([string]$path)
{
# ctor
$this.Name = $path
$this.Exists = $true
}
[void] Delete()
{
}
}
$myFile = [myFileSystemInfo]::new('Hello')
$myFile.Name | Should -Be 'Hello'
$myFile.Exists | Should -BeTrue
}
It 'deriving from `FileSystemInfo` will fail when the abstract property `Exists` is not implemented' {
$script = [scriptblock]::Create('class WillFail : System.IO.FileSystemInfo { [string] $Name }')
$failure = $null
try {
& $script
} catch {
$failure = $_
}
$failure | Should -Not -BeNullOrEmpty
$failure.FullyQualifiedErrorId | Should -BeExactly "TypeCreationError"
$failure.Exception.Message | Should -BeLike "*'get_Exists'*"
}
}