diff --git a/src/System.Management.Automation/engine/parser/TypeInferenceVisitor.cs b/src/System.Management.Automation/engine/parser/TypeInferenceVisitor.cs index 482d212e1b4..adaa2729570 100644 --- a/src/System.Management.Automation/engine/parser/TypeInferenceVisitor.cs +++ b/src/System.Management.Automation/engine/parser/TypeInferenceVisitor.cs @@ -1603,21 +1603,7 @@ private bool TryGetTypeFromMember( if (methodCacheEntry[0].method.Name.Equals(memberName, StringComparison.OrdinalIgnoreCase)) { maybeWantDefaultCtor = false; - if (isInvokeMemberExpressionAst) - { - foreach (var method in methodCacheEntry.methodInformationStructures) - { - if (method.method is MethodInfo methodInfo && !methodInfo.ReturnType.ContainsGenericParameters) - { - result.Add(new PSTypeName(methodInfo.ReturnType)); - } - } - - return true; - } - - // Accessing a method as a property, we'd return a wrapper over the method. - result.Add(new PSTypeName(typeof(PSMethod))); + AddTypesFromMethodCacheEntry(methodCacheEntry, result, isInvokeMemberExpressionAst); return true; } @@ -1667,6 +1653,16 @@ private bool TryGetTypeFromMember( ScriptBlock scriptBlock = null; switch (memberInfo) { + case PSMethod m: + { + if (m.adapterData is DotNetAdapter.MethodCacheEntry methodCacheEntry) + { + AddTypesFromMethodCacheEntry(methodCacheEntry, result, isInvokeMemberExpressionAst); + return true; + } + + return false; + } case PSProperty p: { result.Add(new PSTypeName(p.Value.GetType())); @@ -1739,6 +1735,28 @@ private bool TryGetTypeFromMember( return false; } + private void AddTypesFromMethodCacheEntry( + DotNetAdapter.MethodCacheEntry methodCacheEntry, + List result, + bool isInvokeMemberExpressionAst) + { + if (isInvokeMemberExpressionAst) + { + foreach (var method in methodCacheEntry.methodInformationStructures) + { + if (method.method is MethodInfo methodInfo && !methodInfo.ReturnType.ContainsGenericParameters) + { + result.Add(new PSTypeName(methodInfo.ReturnType)); + } + } + + return; + } + + // Accessing a method as a property, we'd return a wrapper over the method. + result.Add(new PSTypeName(typeof(PSMethod))); + } + private PSTypeName[] GetExpressionType(ExpressionAst expression, bool isStatic) { PSTypeName[] exprType; diff --git a/test/powershell/Host/TabCompletion/TabCompletion.Tests.ps1 b/test/powershell/Host/TabCompletion/TabCompletion.Tests.ps1 index 98813c3f621..cdf07689f80 100644 --- a/test/powershell/Host/TabCompletion/TabCompletion.Tests.ps1 +++ b/test/powershell/Host/TabCompletion/TabCompletion.Tests.ps1 @@ -644,6 +644,13 @@ dir -Recurse ` $res.CompletionMatches | Should -HaveCount 1 $res.CompletionMatches[0].CompletionText | Should -BeExactly "-LiteralPath" } + + It "Test member completion of a static method invocation" { + $inputStr = '[powershell]::Create().' + $res = TabExpansion2 -inputScript $inputStr -cursorColumn $inputStr.Length + $res.CompletionMatches | Should -HaveCount 31 + $res.CompletionMatches[0].CompletionText | Should -BeExactly "Commands" + } } Context "Module completion for 'using module'" { diff --git a/test/powershell/engine/Api/TypeInference.Tests.ps1 b/test/powershell/engine/Api/TypeInference.Tests.ps1 index bdc1c25a31b..52cb88801cd 100644 --- a/test/powershell/engine/Api/TypeInference.Tests.ps1 +++ b/test/powershell/engine/Api/TypeInference.Tests.ps1 @@ -242,6 +242,12 @@ Describe "Type inference Tests" -tags "CI" { $res.Name | Should -Be 'System.Type' } + It "Infers type from static member method" { + $res = [AstTypeInference]::InferTypeOf( { [powershell]::Create() }.Ast) + $res.Count | Should -Be 1 + $res.Name | Should -Be 'System.Management.Automation.PowerShell' + } + It "Infers type from integer * stringliteral" { $res = [AstTypeInference]::InferTypeOf( { 5 * "5" }.Ast) $res.Count | Should -Be 1 @@ -412,7 +418,7 @@ Describe "Type inference Tests" -tags "CI" { It "Infers typeof Select-Object when Parameter is ExcludeProperty" { $res = [AstTypeInference]::InferTypeOf( { [io.fileinfo]::new("file") | Select-Object -ExcludeProperty *Time*, E* }.Ast) $res.Count | Should -Be 1 - $res[0].Name | Should -Be "System.Management.Automation.PSObject#Attributes:BaseName:Directory:DirectoryName:FullName:IsReadOnly:Length:LinkType:Mode:Name:Target" + $res[0].Name | Should -Be "System.Management.Automation.PSObject#Attributes:BaseName:Directory:DirectoryName:FullName:IsReadOnly:Length:LinkType:Mode:Name:Target:VersionInfo" $names = $res[0].Members.Name $names -contains "BaseName" | Should -BeTrue $names -contains "Name" | Should -BeTrue