Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 16 additions & 5 deletions src/System.Management.Automation/engine/parser/PSType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ private sealed class DefineTypeHelper
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;

Expand Down Expand Up @@ -446,9 +446,9 @@ private Type GetBaseTypes(Parser parser, TypeDefinitionAst typeDefinitionAst, ou

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.
Expand All @@ -467,12 +467,23 @@ private bool ShouldImplementProperty(string name, Type type)
{
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()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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'*"
}
}