Skip to content

Commit 62267ae

Browse files
Fix up galc and add some comments
1 parent a2122db commit 62267ae

9 files changed

Lines changed: 73 additions & 19 deletions

File tree

src/ClassExplorer/ALCPoly.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ public static string SafeGetName(AssemblyLoadContext alc)
8080
{
8181
}
8282

83-
return name ?? alc.GetType().FullName;
83+
return name ?? alc.GetType().FullName ?? "<Unnamed>";
8484
}
8585

8686
public static void AssertSupported(PSCmdlet cmdlet)
@@ -104,7 +104,7 @@ public static IEnumerable<AssemblyLoadContext> GetAll()
104104
#endif
105105
}
106106

107-
public static AssemblyLoadContext GetLoadContext(Assembly assembly)
107+
public static AssemblyLoadContext? GetLoadContext(Assembly assembly)
108108
{
109109
#if NETFRAMEWORK
110110
return AssemblyLoadContext.Default;

src/ClassExplorer/Commands/GetAssemblyCommand.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Linq;
33
using System.Management.Automation;
44
using System.Reflection;
5+
using System.Runtime.Loader;
56

67
namespace ClassExplorer.Commands
78
{
@@ -94,6 +95,12 @@ protected override void ProcessRecord()
9495
return;
9596
}
9697

98+
if (InputObject.BaseObject is AssemblyLoadContext alc)
99+
{
100+
WriteObject(ALC.SafeGetAssemblies(alc), enumerateCollection: true);
101+
return;
102+
}
103+
97104
WriteObject(InputObject.BaseObject.GetType().Assembly, enumerateCollection: false);
98105
}
99106
}

src/ClassExplorer/Commands/GetAssemblyLoadContextCommand.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ namespace ClassExplorer.Commands;
77

88
[Cmdlet(VerbsCommon.Get, "AssemblyLoadContext")]
99
[Alias("galc")]
10+
[OutputType(typeof(AssemblyLoadContext))]
1011
public sealed class GetAssemblyLoadContextCommand : PSCmdlet
1112
{
1213
[Parameter(Position = 0)]
@@ -49,7 +50,12 @@ protected override void ProcessRecord()
4950
return;
5051
}
5152

52-
AssemblyLoadContext alc = ALC.GetLoadContext(assembly);
53+
AssemblyLoadContext? alc = ALC.GetLoadContext(assembly);
54+
if (alc is null)
55+
{
56+
return;
57+
}
58+
5359
if (!(_processedAlcs ??= new()).Add(alc))
5460
{
5561
return;

src/ClassExplorer/Commands/InvokeMemberCommand.cs

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
using System.Reflection;
77
using System.Runtime.CompilerServices;
88
using ClassExplorer.Internal;
9-
9+
using ClassExplorer.Signatures;
1010
using PSAllowNull = System.Management.Automation.AllowNullAttribute;
1111

1212
namespace ClassExplorer.Commands;
@@ -33,6 +33,19 @@ public sealed class InvokeMemberCommand : PSCmdlet
3333
[Parameter]
3434
public SwitchParameter SkipPSObjectUnwrap { get; set; }
3535

36+
protected override void BeginProcessing()
37+
{
38+
if (SessionState.LanguageMode is not PSLanguageMode.FullLanguage)
39+
{
40+
ThrowTerminatingError(
41+
new ErrorRecord(
42+
new PSInvalidOperationException(SR.InvalidLanguageMode),
43+
nameof(SR.InvalidLanguageMode),
44+
ErrorCategory.InvalidOperation,
45+
targetObject: null));
46+
}
47+
}
48+
3649
protected override unsafe void ProcessRecord()
3750
{
3851
Poly.Assert(InputObject is not null);
@@ -82,8 +95,6 @@ protected override unsafe void ProcessRecord()
8295
}
8396
}
8497

85-
86-
8798
if (InputObject is not MethodBase methodBase)
8899
{
89100
ThrowTerminatingError(
@@ -166,11 +177,17 @@ protected override unsafe void ProcessRecord()
166177
return;
167178
}
168179

180+
// Go through refs and remove any that link to a `PSReference` or are for a `in` parameter.
169181
for (int i = refs.Count - 1; i >= 0; i--)
170182
{
171183
RefInfo info = refs[i];
172184
if (info.PSRef is null)
173185
{
186+
if (info.Parameter?.IsDecoratedReadOnly() ?? false)
187+
{
188+
refs.RemoveAt(i);
189+
}
190+
174191
continue;
175192
}
176193

src/ClassExplorer/Internal/_Format.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,19 @@ public static string FullType(Type value, int maxLength = -1)
6161
.ToString();
6262
}
6363

64+
[Hidden, EditorBrowsable(EditorBrowsableState.Never)]
65+
public static string FullType(string value, int maxLength = -1)
66+
{
67+
SignatureWriter w = GetWriter(maxLength);
68+
int lastPeriod = value.LastIndexOf('.');
69+
if (lastPeriod is -1 || lastPeriod == value.Length - 1)
70+
{
71+
return w.TypeInfo(value).ToString();
72+
}
73+
74+
return w.Namespace(value[..lastPeriod]).Dot().TypeInfo(value[(lastPeriod + 1)..]).ToString();
75+
}
76+
6477
[Hidden, EditorBrowsable(EditorBrowsableState.Never)]
6578
public static string Namespace(string value, int maxLength = -1)
6679
{

src/ClassExplorer/PipelineEmitter.cs

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -51,22 +51,25 @@ static PipelineEmitter()
5151

5252
public PipelineEmitter(PSCmdlet cmdlet) => _cmdlet = cmdlet;
5353

54-
public void Invoke(T value) => _cmdlet.WriteObject(value, enumerateCollection: false);
55-
56-
public void Invoke(T value, object? instance)
54+
private static PSObject AsPSObject(object obj, bool storeTypeNameAndInstanceMembersLocally)
5755
{
58-
PSObject pso;
59-
if (s_asPSObject is null || s_setHidden is null)
56+
if (s_asPSObject is null)
6057
{
61-
pso = PSObject.AsPSObject(value);
62-
pso.Properties.Add(new PSNoteProperty("__ce_Instance", instance));
63-
_cmdlet.WriteObject(pso, enumerateCollection: false);
64-
return;
58+
return PSObject.AsPSObject(obj);
6559
}
6660

67-
pso = s_asPSObject(value, true);
61+
return s_asPSObject(obj, storeTypeNameAndInstanceMembersLocally);
62+
}
63+
64+
public void Invoke(T value) => _cmdlet.WriteObject(value, enumerateCollection: false);
65+
66+
public void Invoke(T value, object? instance)
67+
{
68+
// Avoid saving to the PSObject member resurrection table if possible as
69+
// .NET caches `MemberInfo` objects.
70+
PSObject pso = AsPSObject(value!, storeTypeNameAndInstanceMembersLocally: true);
6871
PSNoteProperty instanceProp = new("__ce_Instance", instance);
69-
s_setHidden(instanceProp);
72+
s_setHidden?.Invoke(instanceProp);
7073
pso.Properties.Add(instanceProp);
7174
_cmdlet.WriteObject(pso, enumerateCollection: false);
7275
}

src/ClassExplorer/SR.resx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,4 +191,7 @@ Message: {0}</value>
191191
<data name="UnexpectedSignatureKind" xml:space="preserve">
192192
<value>Expected signature of kind "{0}" but found a "{1}" signature.</value>
193193
</data>
194+
<data name="InvalidLanguageMode" xml:space="preserve">
195+
<value>The 'Invoke-Member' command cannot be used outside of 'PSLanguageMode.FullLanguage'.</value>
196+
</data>
194197
</root>

src/ClassExplorer/Signatures/RefSignature.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,14 @@ private static bool DoesRefKindMatch(RefKind kind, ParameterInfo parameter)
3333
return kind is RefKind.Out;
3434
}
3535

36-
if (parameter.IsDefined("System.Runtime.CompilerServices.IsReadOnlyAttribute"))
36+
if (parameter.IsDecoratedReadOnly())
3737
{
3838
return kind is RefKind.In;
3939
}
4040

4141
if (parameter.Position is -1)
4242
{
43-
if (parameter.IsDefined("System.Runtime.CompilerServices.IsReadOnlyAttribute"))
43+
if (parameter.IsDecoratedReadOnly())
4444
{
4545
return kind is RefKind.In;
4646
}

src/ClassExplorer/Signatures/SignatureExtensions.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@ public static bool IsDefined(this MemberInfo member, string fullName)
4747
return member.IsDefined(type, true);
4848
}
4949

50+
public static bool IsDecoratedReadOnly(this ParameterInfo parameter)
51+
{
52+
return parameter.IsDefined("System.Runtime.CompilerServices.IsReadOnlyAttribute");
53+
}
54+
5055
public static bool IsDefined(this ParameterInfo parameter, string fullName)
5156
{
5257
Type? type = parameter.Member.Module.GetType(fullName) ?? Type.GetType(fullName);

0 commit comments

Comments
 (0)