Skip to content

Commit 673958a

Browse files
Add -Decoration to Find-Type (#44)
Fixes #43 * Move the decoration parameter to be a shared parameter for both `Find-Member` and `Find-Type`. * Also fallback to a global search when resolving attribute type if the type is not in the BCL or embedded in the target assembly.
1 parent dde4c34 commit 673958a

File tree

9 files changed

+97
-47
lines changed

9 files changed

+97
-47
lines changed

docs/en-US/Find-Member.md

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,13 @@ Find properties, methods, fields, etc that fit specific criteria.
1616

1717
```powershell
1818
19-
Find-Member [[-FilterScript] <scriptblock>] [-ParameterType <ScriptBlockStringOrType>] [-GenericParameter <ScriptBlockStringOrType>] [-ParameterCount <RangeExpression[]>] [-GenericParameterCount <RangeExpression[]>] [-ReturnType <ScriptBlockStringOrType>] [-IncludeSpecialName] [-Decoration <ScriptBlockStringOrType>] [-MemberType <MemberTypes>] [-Static] [-Instance] [-Abstract] [-Virtual] [-Declared] [-IncludeObject] [-RecurseNestedType] [-Extension] [-Name <string>] [-Force] [-RegularExpression] [-InputObject <psobject>] [-Not] [-ResolutionMap <hashtable>] [-AccessView <AccessView>] [<CommonParameters>]
19+
Find-Member [[-FilterScript] <scriptblock>] [-ParameterType <ScriptBlockStringOrType>] [-GenericParameter <ScriptBlockStringOrType>] [-ParameterCount <RangeExpression[]>] [-GenericParameterCount <RangeExpression[]>] [-ReturnType <ScriptBlockStringOrType>] [-IncludeSpecialName] [-MemberType <MemberTypes>] [-Static] [-Instance] [-Abstract] [-Virtual] [-Declared] [-IncludeObject] [-RecurseNestedType] [-Extension] [-Name <string>] [-Force] [-RegularExpression] [-InputObject <psobject>] [-Not] [-ResolutionMap <hashtable>] [-AccessView <AccessView>] [-Decoration <ScriptBlockStringOrType>] [<CommonParameters>]
2020
```
2121

2222
### ByName
2323

2424
```powershell
25-
Find-Member [[-Name] <string>] [-ParameterType <ScriptBlockStringOrType>] [-GenericParameter <ScriptBlockStringOrType>] [-ParameterCount <RangeExpression[]>] [-GenericParameterCount <RangeExpression[]>] [-ReturnType <ScriptBlockStringOrType>] [-IncludeSpecialName] [-Decoration <ScriptBlockStringOrType>] [-MemberType <MemberTypes>] [-Static] [-Instance] [-Abstract] [-Virtual] [-Declared] [-IncludeObject] [-RecurseNestedType] [-Extension] [-FilterScript <scriptblock>] [-Force] [-RegularExpression] [-InputObject <psobject>] [-Not] [-ResolutionMap <hashtable>] [-AccessView <AccessView>] [<CommonParameters>]
25+
Find-Member [[-Name] <string>] [-ParameterType <ScriptBlockStringOrType>] [-GenericParameter <ScriptBlockStringOrType>] [-ParameterCount <RangeExpression[]>] [-GenericParameterCount <RangeExpression[]>] [-ReturnType <ScriptBlockStringOrType>] [-IncludeSpecialName] [-MemberType <MemberTypes>] [-Static] [-Instance] [-Abstract] [-Virtual] [-Declared] [-IncludeObject] [-RecurseNestedType] [-Extension] [-FilterScript <scriptblock>] [-Force] [-RegularExpression] [-InputObject <psobject>] [-Not] [-ResolutionMap <hashtable>] [-AccessView <AccessView>] [-Decoration <ScriptBlockStringOrType>] [<CommonParameters>]
2626
```
2727

2828
## DESCRIPTION
@@ -36,7 +36,7 @@ The Find-Member cmdlet searches the process for type members that fit specified
3636
```powershell
3737
Find-Member GetPowerShell
3838
39-
# ReflectedType: ScriptBlock
39+
# ReflectedType: System.Management.Automation.ScriptBlock
4040
#
4141
# Name MemberType Definition
4242
# ---- ---------- ----------
@@ -54,7 +54,7 @@ Find all members in the AppDomain with the name "GetPowerShell"
5454
```powershell
5555
[System.IO.Stream] | Find-Member -ParameterType { [anyof[Span[any], Memory[any]]] }
5656
57-
# ReflectedType: Stream
57+
# ReflectedType: System.IO.Stream
5858
#
5959
# Name MemberType Definition
6060
# ---- ---------- ----------
@@ -69,19 +69,19 @@ Find all members that take a `Span<>` or a `Memory<>` as a parameter.
6969
```powershell
7070
Find-Member -ParameterCount 0 -GenericParameter { [T[new]] }
7171
72-
# ReflectedType: InlineParserList
72+
# ReflectedType: Markdig.Parsers.InlineParserList
7373
#
7474
# Name MemberType Definition
7575
# ---- ---------- ----------
7676
# AddIfNotAlready Method public void AddIfNotAlready<TItem>();
7777
#
78-
# ReflectedType: ParserList<T, TState>
78+
# ReflectedType: Markdig.Parsers.ParserList<T, TState>
7979
#
8080
# Name MemberType Definition
8181
# ---- ---------- ----------
8282
# AddIfNotAlready Method public void AddIfNotAlready<TItem>();
8383
#
84-
# ReflectedType: OrderedList<T>
84+
# ReflectedType: Markdig.Parsers.OrderedList<T>
8585
#
8686
# Name MemberType Definition
8787
# ---- ---------- ----------
@@ -95,13 +95,13 @@ Find all methods with no parameters and with a generic parameter with the `new`
9595
```powershell
9696
Find-Member Emit -ParameterCount ..1, 7..8, 10..
9797
98-
# ReflectedType: ILGenerator
98+
# ReflectedType: System.Reflection.Emit.ILGenerator
9999
#
100100
# Name MemberType Definition
101101
# ---- ---------- ----------
102102
# Emit Method public virtual void Emit(OpCode opcode);
103103
#
104-
# ReflectedType: Compilation
104+
# ReflectedType: Microsoft.CodeAnalysis.Compilation
105105
#
106106
# Name MemberType Definition
107107
# ---- ---------- ----------
@@ -110,11 +110,11 @@ Find-Member Emit -ParameterCount ..1, 7..8, 10..
110110
# Emit Method public EmitResult Emit(Stream peStream, St…
111111
# Emit Method public EmitResult Emit(Stream peStream, St…
112112
#
113-
# ReflectedType: FileSystemExtensions
113+
# ReflectedType: Microsoft.CodeAnalysis.FileSystemExtensions
114114
#
115115
# Name MemberType Definition
116116
# ---- ---------- ----------
117-
# Emit Method public static EmitResult Emit(Compilation
117+
# Emit Method public static EmitResult Emit(this Compila
118118
```
119119

120120
Find all methods named `Emit` whose parameter count is any of the following:
@@ -128,19 +128,19 @@ Find all methods named `Emit` whose parameter count is any of the following:
128128
```powershell
129129
Find-Member -ReturnType System.Management.Automation.Language.Ast -Static
130130
131-
# ReflectedType: CommandCompletion
131+
# ReflectedType: System.Management.Automation.CommandCompletion
132132
#
133133
# Name MemberType Definition
134134
# ---- ---------- ----------
135135
# MapStringInputToPars… Method public static Tuple<Ast, Token[], IScriptPosition> MapStringI…
136136
#
137-
# ReflectedType: UsingExpressionAst
137+
# ReflectedType: System.Management.Automation.Language.UsingExpressionAst
138138
#
139139
# Name MemberType Definition
140140
# ---- ---------- ----------
141141
# ExtractUsingVariable Method public static VariableExpressionAst ExtractUsingVariable(Usin…
142142
#
143-
# ReflectedType: Parser
143+
# ReflectedType: System.Management.Automation.Language.Parser
144144
#
145145
# Name MemberType Definition
146146
# ---- ---------- ----------
@@ -156,13 +156,13 @@ Find all static members in the AppDomain that return any type of AST.
156156
```powershell
157157
Find-Member -ParameterType runspace -Virtual
158158
159-
# ReflectedType: IHostSupportsInteractiveSession
159+
# ReflectedType: System.Management.Automation.Host.IHostSupportsInteractiveSession
160160
#
161161
# Name MemberType Definition
162162
# ---- ---------- ----------
163163
# PushRunspace Method public abstract void PushRunspace(Runspace runspace);
164164
#
165-
# ReflectedType: IPSConsoleReadLineMockableMethods
165+
# ReflectedType: Microsoft.PowerShell.Internal.IPSConsoleReadLineMockableMethods
166166
#
167167
# Name MemberType Definition
168168
# ---- ---------- ----------
@@ -176,7 +176,7 @@ Find all virtual members in the AppDomain that take any runspace type as a param
176176
```powershell
177177
Find-Member Parse* -ParameterType System.Management.Automation.Language.Token
178178
179-
# ReflectedType: Parser
179+
# ReflectedType: System.Management.Automation.Language.Parser
180180
#
181181
# Name MemberType Definition
182182
# ---- ---------- ----------
@@ -193,7 +193,7 @@ demonstrates how this will even match the element of a type that is both an arra
193193
```powershell
194194
[runspace] | Find-Member -Force -Abstract | Find-Member -Not -AccessView Child
195195
196-
# ReflectedType: Runspace
196+
# ReflectedType: System.Management.Automation.Runspaces.Runspace
197197
#
198198
# Name MemberType Definition
199199
# ---- ---------- ----------

docs/en-US/Find-Type.md

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,13 @@ Find .NET classes in the AppDomain.
1515
### ByFilter (Default)
1616

1717
```powershell
18-
Find-Type [[-FilterScript] <scriptblock>] [[-Namespace] <string>] [-Name <string>] [-FullName <string>] [-InheritsType <ScriptBlockStringOrType>] [-ImplementsInterface <ScriptBlockStringOrType>] [-Signature <ScriptBlockStringOrType>] [-Abstract] [-Static] [-Sealed] [-Interface] [-ValueType] [-Force] [-RegularExpression] [-InputObject <psobject>] [-Not] [-ResolutionMap <hashtable>] [-AccessView <AccessView>] [<CommonParameters>]
18+
Find-Type [[-FilterScript] <scriptblock>] [[-Namespace] <string>] [-Name <string>] [-FullName <string>] [-InheritsType <ScriptBlockStringOrType>] [-ImplementsInterface <ScriptBlockStringOrType>] [-Signature <ScriptBlockStringOrType>] [-Abstract] [-Static] [-Sealed] [-Interface] [-ValueType] [-Force] [-RegularExpression] [-InputObject <psobject>] [-Not] [-ResolutionMap <hashtable>] [-AccessView <AccessView>] [-Decoration <ScriptBlockStringOrType>] [<CommonParameters>]
1919
```
2020

2121
### ByName
2222

2323
```powershell
24-
Find-Type [[-Name] <string>] [[-Namespace] <string>] [-FullName <string>] [-InheritsType <ScriptBlockStringOrType>] [-ImplementsInterface <ScriptBlockStringOrType>] [-Signature <ScriptBlockStringOrType>] [-Abstract] [-Static] [-Sealed] [-Interface] [-ValueType] [-FilterScript <scriptblock>] [-Force] [-RegularExpression] [-InputObject <psobject>] [-Not] [-ResolutionMap <hashtable>] [-AccessView <AccessView>] [<CommonParameters>]
24+
Find-Type [[-Name] <string>] [[-Namespace] <string>] [-FullName <string>] [-InheritsType <ScriptBlockStringOrType>] [-ImplementsInterface <ScriptBlockStringOrType>] [-Signature <ScriptBlockStringOrType>] [-Abstract] [-Static] [-Sealed] [-Interface] [-ValueType] [-FilterScript <scriptblock>] [-Force] [-RegularExpression] [-InputObject <psobject>] [-Not] [-ResolutionMap <hashtable>] [-AccessView <AccessView>] [-Decoration <ScriptBlockStringOrType>] [<CommonParameters>]
2525
```
2626

2727
## DESCRIPTION
@@ -389,6 +389,24 @@ Accept pipeline input: False
389389
Accept wildcard characters: False
390390
```
391391

392+
### -Decoration
393+
394+
Specifies that a type must be decorated with this attribute for it to be included in results. This search will be done based on type name rather than strict type identity so it is safe to use for embedded attributes.
395+
396+
This can also be a type signature (see [about_Type_Signatures](https://seemingly.dev/about-type-signatures)).
397+
398+
```yaml
399+
Type: Type
400+
Parameter Sets: (All)
401+
Aliases: HasAttr, attr
402+
403+
Required: False
404+
Position: Named
405+
Default value: None
406+
Accept pipeline input: False
407+
Accept wildcard characters: False
408+
```
409+
392410
### -ResolutionMap
393411

394412
Specifies a hashtable of `name` to `ScriptBlockStringOrType` to create your own keywords and/or override type resolution for any signature in this command.

src/ClassExplorer/Commands/FindMemberCommand.cs

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -93,15 +93,6 @@ public SwitchParameter IncludeSpecialName
9393
set => _options.IncludeSpecialName = value;
9494
}
9595

96-
[Parameter]
97-
[Alias("HasAttr", "attr")]
98-
[ArgumentCompleter(typeof(TypeFullNameArgumentCompleter))]
99-
public ScriptBlockStringOrType? Decoration
100-
{
101-
get => _options.Decoration;
102-
set => _options.Decoration = value;
103-
}
104-
10596
/// <summary>
10697
/// Gets or sets the member type to match.
10798
/// </summary>
@@ -220,6 +211,7 @@ protected override void InitializeFilters()
220211
_options.RegularExpression = RegularExpression;
221212
_options.ResolutionMap = resolutionMap;
222213
_options.AccessView = AccessView;
214+
_options.Decoration = Decoration;
223215
_search = Search.Members(_options, new PipelineEmitter<MemberInfo>(this));
224216
}
225217
}

src/ClassExplorer/Commands/FindReflectionObjectCommandBase.cs

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,11 @@ public abstract class FindReflectionObjectCommandBase<TMemberType> : PSCmdlet
6767
[Alias("as")]
6868
public virtual AccessView AccessView { get; set; }
6969

70+
[Parameter]
71+
[Alias("HasAttr", "attr")]
72+
[ArgumentCompleter(typeof(TypeFullNameArgumentCompleter))]
73+
public ScriptBlockStringOrType? Decoration { get; set; }
74+
7075
private bool _hadError;
7176

7277
/// <summary>
@@ -120,7 +125,7 @@ protected override void ProcessRecord()
120125
// you probably aren't passing the entire AppDomain like this.
121126
if (InputObject.BaseObject is IList list)
122127
{
123-
foreach (var item in list)
128+
foreach (object? item in list)
124129
{
125130
ProcessSingleObject(PSObject.AsPSObject(item));
126131
}
@@ -170,20 +175,6 @@ protected override void ProcessRecord()
170175
continue;
171176
}
172177

173-
// if (!LanguagePrimitives.TryConvertTo(entry.Value, out Type value))
174-
// {
175-
// WriteError(
176-
// new ErrorRecord(
177-
// new PSInvalidCastException(
178-
// SR.Format(
179-
// "Cannot convert the \"{0}\" value of type \"{1}\" to type \"{1}\".",
180-
// entry.Value,
181-
// entry.Value.GetType().FullName)),
182-
// "InvalidTypeResolutionMap",
183-
// ErrorCategory.InvalidArgument,
184-
// entry));
185-
// }
186-
187178
resolutionMap[key] = LanguagePrimitives.ConvertTo<ScriptBlockStringOrType>(entry.Value);
188179
}
189180

src/ClassExplorer/Commands/FindTypeCommand.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ protected override void InitializeFilters()
187187
_options.ResolutionMap = resolutionMap;
188188
_options.Signature = signature;
189189
_options.AccessView = AccessView;
190+
_options.Decoration = Decoration;
190191
_search = Search.Types(_options, new PipelineEmitter<Type>(this));
191192
}
192193
}

src/ClassExplorer/MemberSearchOptions.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@ internal class MemberSearchOptions : ReflectionSearchOptions
1616

1717
public bool IncludeSpecialName { get; set; }
1818

19-
public ScriptBlockStringOrType? Decoration { get; set; }
20-
2119
public MemberTypes MemberType { get; set; }
2220

2321
public bool Static { get; set; }

src/ClassExplorer/ReflectionSearchOptions.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,6 @@ internal abstract class ReflectionSearchOptions
2020
public Dictionary<string, ScriptBlockStringOrType>? ResolutionMap { get; set; }
2121

2222
public AccessView AccessView { get; set; }
23+
24+
public ScriptBlockStringOrType? Decoration { get; set; }
2325
}

src/ClassExplorer/Signatures/DecorationSignature.cs

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System;
12
using System.Reflection;
23

34
namespace ClassExplorer.Signatures
@@ -6,10 +7,29 @@ internal sealed class DecorationSignature : UniversialSignature
67
{
78
private readonly string _typeName;
89

10+
private readonly Lazy<Type?> _fallbackType;
11+
912
internal DecorationSignature(string typeName)
1013
{
1114
Poly.Assert(typeName is not null or { Length: < 1 });
1215
_typeName = typeName;
16+
_fallbackType = new Lazy<Type?>(() =>
17+
{
18+
Type? publicResult = Search.FirstType(
19+
new TypeSearchOptions() { FullName = _typeName });
20+
21+
if (publicResult is not null)
22+
{
23+
return publicResult;
24+
}
25+
26+
return Search.FirstType(
27+
new TypeSearchOptions()
28+
{
29+
FullName = _typeName,
30+
AccessView = AccessView.This,
31+
});
32+
});
1333
}
1434

1535
public override bool IsMatch(ParameterInfo parameter)
@@ -19,9 +39,27 @@ public override bool IsMatch(ParameterInfo parameter)
1939
return true;
2040
}
2141

42+
if (_fallbackType.Value is Type type && parameter.IsDefined(type, inherit: true))
43+
{
44+
return true;
45+
}
46+
2247
return IsMatch(parameter.ParameterType);
2348
}
2449

25-
public override bool IsMatch(MemberInfo member) => member.IsDefined(_typeName);
50+
public override bool IsMatch(MemberInfo member)
51+
{
52+
if (member.IsDefined(_typeName))
53+
{
54+
return true;
55+
}
56+
57+
if (_fallbackType.Value is Type type && member.IsDefined(type, inherit: true))
58+
{
59+
return true;
60+
}
61+
62+
return false;
63+
}
2664
}
2765
}

src/ClassExplorer/TypeSearch.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,5 +136,15 @@ protected override void InitializeOtherFilters(List<Filter<Type>> filters, Signa
136136
_options.Signature,
137137
static (type, signature) => signature.IsMatch(type));
138138
}
139+
140+
if (_options.Decoration is not null)
141+
{
142+
filters.AddFilter(
143+
new DecorationSignature(
144+
SignatureParser.ResolveAttributeTypeName(
145+
_options.Decoration,
146+
_options.ResolutionMap)),
147+
static (type, signature) => signature.IsMatch(type));
148+
}
139149
}
140150
}

0 commit comments

Comments
 (0)