Adding support for Typeinference based on runtime variable values (#2744)
* Refactored the type inference code in preparation to make it a public api. * Added type inference tests Fixes #2567
This commit is contained in:
parent
a164609eea
commit
a52adcd3cf
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -65,3 +65,7 @@ gen
|
|||
|
||||
# TestsResults
|
||||
TestsResults*.xml
|
||||
|
||||
# Resharper settings
|
||||
PowerShell.sln.DotSettings.user
|
||||
|
||||
|
|
|
@ -641,7 +641,7 @@ namespace System.Management.Automation
|
|||
char quote;
|
||||
var lastword = LastWordFinder.FindLastWord(legacyInput, out replacementIndex, out quote);
|
||||
replacementLength = legacyInput.Length - replacementIndex;
|
||||
var helper = new CompletionExecutionHelper(powershell);
|
||||
var helper = new PowerShellExecutionHelper(powershell);
|
||||
|
||||
powershell.AddCommand("TabExpansion").AddArgument(legacyInput).AddArgument(lastword);
|
||||
|
||||
|
@ -749,7 +749,7 @@ namespace System.Management.Automation
|
|||
/// <param name="quote"></param>
|
||||
/// <param name="completingAtStartOfLine"></param>
|
||||
/// <returns></returns>
|
||||
internal static List<CompletionResult> PSv2GenerateMatchSetOfCmdlets(CompletionExecutionHelper helper, string lastWord, string quote, bool completingAtStartOfLine)
|
||||
internal static List<CompletionResult> PSv2GenerateMatchSetOfCmdlets(PowerShellExecutionHelper helper, string lastWord, string quote, bool completingAtStartOfLine)
|
||||
{
|
||||
var results = new List<CompletionResult>();
|
||||
bool isSnapinSpecified;
|
||||
|
@ -864,7 +864,7 @@ namespace System.Management.Automation
|
|||
|
||||
#region "Handle File Names"
|
||||
|
||||
internal static List<CompletionResult> PSv2GenerateMatchSetOfFiles(CompletionExecutionHelper helper, string lastWord, bool completingAtStartOfLine, string quote)
|
||||
internal static List<CompletionResult> PSv2GenerateMatchSetOfFiles(PowerShellExecutionHelper helper, string lastWord, bool completingAtStartOfLine, string quote)
|
||||
{
|
||||
var results = new List<CompletionResult>();
|
||||
|
||||
|
@ -926,7 +926,7 @@ namespace System.Management.Automation
|
|||
|
||||
bool? isContainer = SafeGetProperty<bool?>(combinedMatch.Item, "PSIsContainer");
|
||||
string childName = SafeGetProperty<string>(combinedMatch.Item, "PSChildName");
|
||||
string toolTip = CompletionExecutionHelper.SafeToString(combinedMatch.ConvertedPath);
|
||||
string toolTip = PowerShellExecutionHelper.SafeToString(combinedMatch.ConvertedPath);
|
||||
|
||||
if (isContainer != null && childName != null && toolTip != null)
|
||||
{
|
||||
|
@ -1034,7 +1034,7 @@ namespace System.Management.Automation
|
|||
return default(T);
|
||||
}
|
||||
|
||||
private static bool PSv2ShouldFullyQualifyPathsPath(CompletionExecutionHelper helper, string lastWord)
|
||||
private static bool PSv2ShouldFullyQualifyPathsPath(PowerShellExecutionHelper helper, string lastWord)
|
||||
{
|
||||
// These are special cases, as they represent cases where the user expects to
|
||||
// see the full path.
|
||||
|
@ -1068,7 +1068,7 @@ namespace System.Management.Automation
|
|||
}
|
||||
}
|
||||
|
||||
private static List<PathItemAndConvertedPath> PSv2FindMatches(CompletionExecutionHelper helper, string path, bool shouldFullyQualifyPaths)
|
||||
private static List<PathItemAndConvertedPath> PSv2FindMatches(PowerShellExecutionHelper helper, string path, bool shouldFullyQualifyPaths)
|
||||
{
|
||||
Diagnostics.Assert(!String.IsNullOrEmpty(path), "path should have a value");
|
||||
var result = new List<PathItemAndConvertedPath>();
|
||||
|
@ -1113,9 +1113,9 @@ namespace System.Management.Automation
|
|||
}
|
||||
|
||||
result.Add(new PathItemAndConvertedPath(
|
||||
CompletionExecutionHelper.SafeToString(objectPath),
|
||||
PowerShellExecutionHelper.SafeToString(objectPath),
|
||||
item,
|
||||
CompletionExecutionHelper.SafeToString(convertedPath)));
|
||||
PowerShellExecutionHelper.SafeToString(convertedPath)));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ namespace System.Management.Automation
|
|||
internal Token TokenBeforeCursor { get; set; }
|
||||
internal IScriptPosition CursorPosition { get; set; }
|
||||
|
||||
internal CompletionExecutionHelper Helper { get; set; }
|
||||
internal PowerShellExecutionHelper Helper { get; set; }
|
||||
internal Hashtable Options { get; set; }
|
||||
internal Dictionary<string, ScriptBlock> CustomArgumentCompleters { get; set; }
|
||||
internal Dictionary<string, ScriptBlock> NativeArgumentCompleters { get; set; }
|
||||
|
@ -33,7 +33,7 @@ namespace System.Management.Automation
|
|||
internal int ReplacementLength { get; set; }
|
||||
internal ExecutionContext ExecutionContext { get; set; }
|
||||
internal PseudoBindingInfo PseudoBindingInfo { get; set; }
|
||||
internal TypeDefinitionAst CurrentTypeDefinitionAst { get; set; }
|
||||
internal TypeInferenceContext TypeInferenceContext { get; set; }
|
||||
|
||||
internal bool GetOption(string option, bool @default)
|
||||
{
|
||||
|
@ -96,15 +96,26 @@ namespace System.Management.Automation
|
|||
return cursor.Offset < extent.StartOffset || cursor.Offset > extent.EndOffset;
|
||||
}
|
||||
|
||||
internal CompletionContext CreateCompletionContext(ExecutionContext executionContext)
|
||||
|
||||
internal CompletionContext CreateCompletionContext(PowerShell powerShell)
|
||||
{
|
||||
var typeInferenceContext = new TypeInferenceContext(powerShell);
|
||||
return InitializeCompletionContext(typeInferenceContext);
|
||||
}
|
||||
internal CompletionContext CreateCompletionContext(TypeInferenceContext typeInferenceContext)
|
||||
{
|
||||
return InitializeCompletionContext(typeInferenceContext);
|
||||
}
|
||||
|
||||
private CompletionContext InitializeCompletionContext(TypeInferenceContext typeInferenceContext)
|
||||
{
|
||||
Token tokenBeforeCursor = null;
|
||||
IScriptPosition positionForAstSearch = _cursorPosition;
|
||||
var adjustLineAndColumn = false;
|
||||
var tokenAtCursor = _tokens.LastOrDefault(token => IsCursorWithinOrJustAfterExtent(_cursorPosition, token.Extent) && IsInterestingToken(token));
|
||||
var tokenAtCursor = InterstingTokenAtCursorOrDefault(_tokens, _cursorPosition);
|
||||
if (tokenAtCursor == null)
|
||||
{
|
||||
tokenBeforeCursor = _tokens.LastOrDefault(token => IsCursorAfterExtent(_cursorPosition, token.Extent) && IsInterestingToken(token));
|
||||
tokenBeforeCursor = InterstingTokenBeforeCursorOrDefault(_tokens, _cursorPosition);
|
||||
if (tokenBeforeCursor != null)
|
||||
{
|
||||
positionForAstSearch = tokenBeforeCursor.Extent.EndScriptPosition;
|
||||
|
@ -114,17 +125,22 @@ namespace System.Management.Automation
|
|||
else
|
||||
{
|
||||
var stringExpandableToken = tokenAtCursor as StringExpandableToken;
|
||||
if (stringExpandableToken != null && stringExpandableToken.NestedTokens != null)
|
||||
if (stringExpandableToken?.NestedTokens != null)
|
||||
{
|
||||
tokenAtCursor =
|
||||
stringExpandableToken.NestedTokens.LastOrDefault(
|
||||
token => IsCursorWithinOrJustAfterExtent(_cursorPosition, token.Extent) && IsInterestingToken(token)) ?? stringExpandableToken;
|
||||
tokenAtCursor = InterstingTokenAtCursorOrDefault(stringExpandableToken.NestedTokens, _cursorPosition) ?? stringExpandableToken;
|
||||
}
|
||||
}
|
||||
|
||||
var asts = AstSearcher.FindAll(_ast, ast => IsCursorWithinOrJustAfterExtent(positionForAstSearch, ast.Extent), searchNestedScriptBlocks: true).ToList();
|
||||
|
||||
Diagnostics.Assert(tokenAtCursor == null || tokenBeforeCursor == null, "Only one of these tokens can be non-null");
|
||||
|
||||
if (typeInferenceContext.CurrentTypeDefinitionAst == null)
|
||||
{
|
||||
typeInferenceContext.CurrentTypeDefinitionAst = Ast.GetAncestorTypeDefinitionAst(asts.Last());
|
||||
}
|
||||
ExecutionContext executionContext = typeInferenceContext.ExecutionContext;
|
||||
|
||||
return new CompletionContext
|
||||
{
|
||||
TokenAtCursor = tokenAtCursor,
|
||||
|
@ -134,12 +150,24 @@ namespace System.Management.Automation
|
|||
Options = _options,
|
||||
ExecutionContext = executionContext,
|
||||
ReplacementIndex = adjustLineAndColumn ? _cursorPosition.Offset : 0,
|
||||
CurrentTypeDefinitionAst = Ast.GetAncestorTypeDefinitionAst(asts.Last()),
|
||||
TypeInferenceContext = typeInferenceContext,
|
||||
Helper = typeInferenceContext.Helper,
|
||||
CustomArgumentCompleters = executionContext.CustomArgumentCompleters,
|
||||
NativeArgumentCompleters = executionContext.NativeArgumentCompleters,
|
||||
};
|
||||
}
|
||||
|
||||
private static Token InterstingTokenAtCursorOrDefault(IEnumerable<Token> tokens, IScriptPosition cursorPosition)
|
||||
{
|
||||
return tokens.LastOrDefault(token => IsCursorWithinOrJustAfterExtent(cursorPosition, token.Extent) && IsInterestingToken(token));
|
||||
}
|
||||
|
||||
private static Token InterstingTokenBeforeCursorOrDefault(IEnumerable<Token> tokens, IScriptPosition cursorPosition)
|
||||
{
|
||||
return tokens.LastOrDefault(token => IsCursorAfterExtent(cursorPosition, token.Extent) && IsInterestingToken(token));
|
||||
}
|
||||
|
||||
|
||||
private static Ast GetLastAstAtCursor(ScriptBlockAst scriptBlockAst, IScriptPosition cursorPosition)
|
||||
{
|
||||
var asts = AstSearcher.FindAll(scriptBlockAst, ast => IsCursorRightAfterExtent(cursorPosition, ast.Extent), searchNestedScriptBlocks: true);
|
||||
|
@ -278,8 +306,7 @@ namespace System.Management.Automation
|
|||
|
||||
internal List<CompletionResult> GetResults(PowerShell powerShell, out int replacementIndex, out int replacementLength)
|
||||
{
|
||||
var completionContext = CreateCompletionContext(powerShell.GetContextFromTLS());
|
||||
completionContext.Helper = new CompletionExecutionHelper(powerShell);
|
||||
var completionContext = CreateCompletionContext(powerShell);
|
||||
|
||||
PSLanguageMode? previousLanguageMode = null;
|
||||
try
|
||||
|
@ -1173,8 +1200,7 @@ namespace System.Management.Automation
|
|||
cursorIndexInString = strValue.Length;
|
||||
|
||||
var analysis = new CompletionAnalysis(_ast, _tokens, _cursorPosition, _options);
|
||||
var subContext = analysis.CreateCompletionContext(completionContext.ExecutionContext);
|
||||
subContext.Helper = completionContext.Helper;
|
||||
var subContext = analysis.CreateCompletionContext(completionContext.TypeInferenceContext);
|
||||
|
||||
int subReplaceIndex, subReplaceLength;
|
||||
var subResult = analysis.GetResultHelper(subContext, out subReplaceIndex, out subReplaceLength, true);
|
||||
|
|
|
@ -75,7 +75,7 @@ namespace System.Management.Automation
|
|||
return CommandCompletion.EmptyCompletionResult;
|
||||
}
|
||||
|
||||
var helper = new CompletionExecutionHelper(PowerShell.Create(RunspaceMode.CurrentRunspace));
|
||||
var helper = new PowerShellExecutionHelper(PowerShell.Create(RunspaceMode.CurrentRunspace));
|
||||
return CompleteCommand(new CompletionContext { WordToComplete = commandName, Helper = helper }, moduleName, commandTypes);
|
||||
}
|
||||
|
||||
|
@ -104,8 +104,8 @@ namespace System.Management.Automation
|
|||
lastAst = context.RelatedAsts.Last();
|
||||
}
|
||||
|
||||
var powershell = context.Helper.CurrentPowerShell;
|
||||
AddCommandWithPreferenceSetting(powershell, "Get-Command", typeof(GetCommandCommand))
|
||||
var powershell = context.Helper
|
||||
.AddCommandWithPreferenceSetting("Get-Command", typeof(GetCommandCommand))
|
||||
.AddParameter("All")
|
||||
.AddParameter("Name", commandName);
|
||||
|
||||
|
@ -169,8 +169,8 @@ namespace System.Management.Automation
|
|||
moduleName = commandName.Substring(0, indexOfFirstBackslash);
|
||||
commandName = commandName.Substring(indexOfFirstBackslash + 1);
|
||||
|
||||
var powershell = context.Helper.CurrentPowerShell;
|
||||
AddCommandWithPreferenceSetting(powershell, "Get-Command", typeof(GetCommandCommand))
|
||||
var powershell = context.Helper
|
||||
.AddCommandWithPreferenceSetting("Get-Command", typeof(GetCommandCommand))
|
||||
.AddParameter("All")
|
||||
.AddParameter("Name", commandName)
|
||||
.AddParameter("Module", moduleName);
|
||||
|
@ -443,8 +443,7 @@ namespace System.Management.Automation
|
|||
moduleName += "*";
|
||||
}
|
||||
|
||||
var powershell = context.Helper.CurrentPowerShell;
|
||||
AddCommandWithPreferenceSetting(powershell, "Get-Module", typeof(GetModuleCommand)).AddParameter("Name", moduleName);
|
||||
var powershell = context.Helper.AddCommandWithPreferenceSetting("Get-Module", typeof(GetModuleCommand)).AddParameter("Name", moduleName);
|
||||
if (!loadedModulesOnly)
|
||||
{
|
||||
powershell.AddParameter("ListAvailable", true);
|
||||
|
@ -1893,7 +1892,7 @@ namespace System.Management.Automation
|
|||
}
|
||||
}
|
||||
|
||||
foreach (PSTypeName typeName in argumentAst.GetInferredType(context))
|
||||
foreach (PSTypeName typeName in AstTypeInference.InferTypeOf(argumentAst, context.TypeInferenceContext, TypeInferenceRuntimePermissions.AllowSafeEval))
|
||||
{
|
||||
yield return typeName;
|
||||
}
|
||||
|
@ -2445,35 +2444,6 @@ namespace System.Management.Automation
|
|||
}
|
||||
}
|
||||
|
||||
private static bool NativeCompletionCimCommands_ParseTypeName(PSTypeName typename, out string cimNamespace, out string className)
|
||||
{
|
||||
cimNamespace = null;
|
||||
className = null;
|
||||
if (typename == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (typename.Type != null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var match = Regex.Match(typename.Name, "(?<NetTypeName>.*)#(?<CimNamespace>.*)[/\\\\](?<CimClassName>.*)");
|
||||
if (!match.Success)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!match.Groups["NetTypeName"].Value.Equals(typeof(CimInstance).FullName, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
cimNamespace = match.Groups["CimNamespace"].Value;
|
||||
className = match.Groups["CimClassName"].Value;
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void NativeCompletionCimCommands(
|
||||
string parameter,
|
||||
Dictionary<string, AstParameterArgumentPair> boundArguments,
|
||||
|
@ -2535,7 +2505,7 @@ namespace System.Management.Automation
|
|||
{
|
||||
foreach (PSTypeName typeName in cimClassTypeNames)
|
||||
{
|
||||
if (NativeCompletionCimCommands_ParseTypeName(typeName, out pseudoboundCimNamespace, out pseudoboundClassName))
|
||||
if (TypeInferenceContext.ParseCimCommandsTypeName(typeName, out pseudoboundCimNamespace, out pseudoboundClassName))
|
||||
{
|
||||
if (parameter.Equals("ResultClassName", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
|
@ -2905,11 +2875,11 @@ namespace System.Management.Automation
|
|||
}
|
||||
var pattern = WildcardPattern.Get(logName, WildcardOptions.IgnoreCase);
|
||||
|
||||
var powershell = context.Helper.CurrentPowerShell;
|
||||
AddCommandWithPreferenceSetting(powershell, "Microsoft.PowerShell.Management\\Get-EventLog").AddParameter("LogName", "*");
|
||||
var powerShellExecutionHelper = context.Helper;
|
||||
var powershell = powerShellExecutionHelper.AddCommandWithPreferenceSetting("Microsoft.PowerShell.Management\\Get-EventLog").AddParameter("LogName", "*");
|
||||
|
||||
Exception exceptionThrown;
|
||||
var psObjects = context.Helper.ExecuteCurrentPowerShell(out exceptionThrown);
|
||||
var psObjects = powerShellExecutionHelper.ExecuteCurrentPowerShell(out exceptionThrown);
|
||||
|
||||
if (psObjects != null)
|
||||
{
|
||||
|
@ -2948,7 +2918,6 @@ namespace System.Management.Automation
|
|||
|
||||
wordToComplete = wordToComplete ?? string.Empty;
|
||||
var quote = HandleDoubleAndSingleQuote(ref wordToComplete);
|
||||
var powershell = context.Helper.CurrentPowerShell;
|
||||
|
||||
if (!wordToComplete.EndsWith("*", StringComparison.Ordinal))
|
||||
{
|
||||
|
@ -2956,17 +2925,13 @@ namespace System.Management.Automation
|
|||
}
|
||||
var pattern = WildcardPattern.Get(wordToComplete, WildcardOptions.IgnoreCase);
|
||||
|
||||
if (paramName.Equals("Name", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
AddCommandWithPreferenceSetting(powershell, "Get-Job", typeof(GetJobCommand)).AddParameter("Name", wordToComplete);
|
||||
}
|
||||
else
|
||||
{
|
||||
AddCommandWithPreferenceSetting(powershell, "Get-Job", typeof(GetJobCommand)).AddParameter("IncludeChildJob", true);
|
||||
}
|
||||
var paramIsName = paramName.Equals("Name", StringComparison.OrdinalIgnoreCase);
|
||||
var (parameterName, value) = paramIsName ? ("Name", wordToComplete) : ("IncludeChildJob", (object)true);
|
||||
var powerShellExecutionHelper = context.Helper;
|
||||
powerShellExecutionHelper.AddCommandWithPreferenceSetting("Get-Job", typeof(GetJobCommand)).AddParameter(parameterName, value);
|
||||
|
||||
Exception exceptionThrown;
|
||||
var psObjects = context.Helper.ExecuteCurrentPowerShell(out exceptionThrown);
|
||||
var psObjects = powerShellExecutionHelper.ExecuteCurrentPowerShell(out exceptionThrown);
|
||||
if (psObjects == null)
|
||||
return;
|
||||
|
||||
|
@ -3004,7 +2969,7 @@ namespace System.Management.Automation
|
|||
|
||||
result.Add(CompletionResult.Null);
|
||||
}
|
||||
else if (paramName.Equals("Name", StringComparison.OrdinalIgnoreCase))
|
||||
else if (paramIsName)
|
||||
{
|
||||
RemoveLastNullCompletionResult(result);
|
||||
|
||||
|
@ -3039,7 +3004,6 @@ namespace System.Management.Automation
|
|||
|
||||
wordToComplete = wordToComplete ?? string.Empty;
|
||||
var quote = HandleDoubleAndSingleQuote(ref wordToComplete);
|
||||
var powershell = context.Helper.CurrentPowerShell;
|
||||
|
||||
if (!wordToComplete.EndsWith("*", StringComparison.Ordinal))
|
||||
{
|
||||
|
@ -3047,17 +3011,18 @@ namespace System.Management.Automation
|
|||
}
|
||||
var pattern = WildcardPattern.Get(wordToComplete, WildcardOptions.IgnoreCase);
|
||||
|
||||
var powerShellExecutionHelper = context.Helper;
|
||||
if (paramName.Equals("Name", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
AddCommandWithPreferenceSetting(powershell, "PSScheduledJob\\Get-ScheduledJob").AddParameter("Name", wordToComplete);
|
||||
powerShellExecutionHelper.AddCommandWithPreferenceSetting("PSScheduledJob\\Get-ScheduledJob").AddParameter("Name", wordToComplete);
|
||||
}
|
||||
else
|
||||
{
|
||||
AddCommandWithPreferenceSetting(powershell, "PSScheduledJob\\Get-ScheduledJob");
|
||||
powerShellExecutionHelper.AddCommandWithPreferenceSetting("PSScheduledJob\\Get-ScheduledJob");
|
||||
}
|
||||
|
||||
Exception exceptionThrown;
|
||||
var psObjects = context.Helper.ExecuteCurrentPowerShell(out exceptionThrown);
|
||||
var psObjects = powerShellExecutionHelper.ExecuteCurrentPowerShell(out exceptionThrown);
|
||||
if (psObjects == null)
|
||||
return;
|
||||
|
||||
|
@ -3165,24 +3130,24 @@ namespace System.Management.Automation
|
|||
|
||||
wordToComplete = wordToComplete ?? string.Empty;
|
||||
var quote = HandleDoubleAndSingleQuote(ref wordToComplete);
|
||||
var powershell = context.Helper.CurrentPowerShell;
|
||||
|
||||
if (!wordToComplete.EndsWith("*", StringComparison.Ordinal))
|
||||
{
|
||||
wordToComplete += "*";
|
||||
}
|
||||
|
||||
var powerShellExecutionHelper = context.Helper;
|
||||
if (paramName.Equals("Id", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
AddCommandWithPreferenceSetting(powershell, "Microsoft.PowerShell.Management\\Get-Process");
|
||||
powerShellExecutionHelper.AddCommandWithPreferenceSetting("Microsoft.PowerShell.Management\\Get-Process");
|
||||
}
|
||||
else
|
||||
{
|
||||
AddCommandWithPreferenceSetting(powershell, "Microsoft.PowerShell.Management\\Get-Process").AddParameter("Name", wordToComplete);
|
||||
powerShellExecutionHelper.AddCommandWithPreferenceSetting("Microsoft.PowerShell.Management\\Get-Process").AddParameter("Name", wordToComplete);
|
||||
}
|
||||
|
||||
Exception exceptionThrown;
|
||||
var psObjects = context.Helper.ExecuteCurrentPowerShell(out exceptionThrown);
|
||||
var psObjects = powerShellExecutionHelper.ExecuteCurrentPowerShell(out exceptionThrown);
|
||||
if (psObjects == null)
|
||||
return;
|
||||
|
||||
|
@ -3250,16 +3215,16 @@ namespace System.Management.Automation
|
|||
|
||||
providerName = providerName ?? string.Empty;
|
||||
var quote = HandleDoubleAndSingleQuote(ref providerName);
|
||||
var powershell = context.Helper.CurrentPowerShell;
|
||||
|
||||
|
||||
if (!providerName.EndsWith("*", StringComparison.Ordinal))
|
||||
{
|
||||
providerName += "*";
|
||||
}
|
||||
|
||||
AddCommandWithPreferenceSetting(powershell, "Microsoft.PowerShell.Management\\Get-PSProvider").AddParameter("PSProvider", providerName);
|
||||
Exception exceptionThrown;
|
||||
var psObjects = context.Helper.ExecuteCurrentPowerShell(out exceptionThrown);
|
||||
var powerShellExecutionHelper = context.Helper;
|
||||
powerShellExecutionHelper.AddCommandWithPreferenceSetting("Microsoft.PowerShell.Management\\Get-PSProvider").AddParameter("PSProvider", providerName);
|
||||
var psObjects = powerShellExecutionHelper.ExecuteCurrentPowerShell(out _);
|
||||
if (psObjects == null)
|
||||
return;
|
||||
|
||||
|
@ -3295,19 +3260,20 @@ namespace System.Management.Automation
|
|||
|
||||
wordToComplete = wordToComplete ?? string.Empty;
|
||||
var quote = HandleDoubleAndSingleQuote(ref wordToComplete);
|
||||
var powershell = context.Helper.CurrentPowerShell;
|
||||
|
||||
if (!wordToComplete.EndsWith("*", StringComparison.Ordinal))
|
||||
{
|
||||
wordToComplete += "*";
|
||||
}
|
||||
|
||||
AddCommandWithPreferenceSetting(powershell, "Microsoft.PowerShell.Management\\Get-PSDrive").AddParameter("Name", wordToComplete);
|
||||
var powerShellExecutionHelper = context.Helper;
|
||||
var powershell = powerShellExecutionHelper
|
||||
.AddCommandWithPreferenceSetting("Microsoft.PowerShell.Management\\Get-PSDrive")
|
||||
.AddParameter("Name", wordToComplete);
|
||||
if (psProvider != null)
|
||||
powershell.AddParameter("PSProvider", psProvider);
|
||||
|
||||
Exception exceptionThrown;
|
||||
var psObjects = context.Helper.ExecuteCurrentPowerShell(out exceptionThrown);
|
||||
var psObjects = powerShellExecutionHelper.ExecuteCurrentPowerShell(out _);
|
||||
if (psObjects != null)
|
||||
{
|
||||
foreach (dynamic driveInfo in psObjects)
|
||||
|
@ -3341,7 +3307,6 @@ namespace System.Management.Automation
|
|||
|
||||
wordToComplete = wordToComplete ?? string.Empty;
|
||||
var quote = HandleDoubleAndSingleQuote(ref wordToComplete);
|
||||
var powershell = context.Helper.CurrentPowerShell;
|
||||
|
||||
if (!wordToComplete.EndsWith("*", StringComparison.Ordinal))
|
||||
{
|
||||
|
@ -3349,15 +3314,17 @@ namespace System.Management.Automation
|
|||
}
|
||||
|
||||
Exception exceptionThrown;
|
||||
var powerShellExecutionHelper = context.Helper;
|
||||
if (paramName.Equals("DisplayName", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
RemoveLastNullCompletionResult(result);
|
||||
|
||||
AddCommandWithPreferenceSetting(powershell, "Microsoft.PowerShell.Management\\Get-Service")
|
||||
.AddParameter("DisplayName", wordToComplete);
|
||||
AddCommandWithPreferenceSetting(powershell, "Microsoft.PowerShell.Utility\\Sort-Object")
|
||||
powerShellExecutionHelper
|
||||
.AddCommandWithPreferenceSetting("Microsoft.PowerShell.Management\\Get-Service")
|
||||
.AddParameter("DisplayName", wordToComplete)
|
||||
.AddCommandWithPreferenceSetting("Microsoft.PowerShell.Utility\\Sort-Object")
|
||||
.AddParameter("Property", "DisplayName");
|
||||
var psObjects = context.Helper.ExecuteCurrentPowerShell(out exceptionThrown);
|
||||
var psObjects = powerShellExecutionHelper.ExecuteCurrentPowerShell(out exceptionThrown);
|
||||
if (psObjects != null)
|
||||
{
|
||||
foreach (dynamic serviceInfo in psObjects)
|
||||
|
@ -3387,8 +3354,8 @@ namespace System.Management.Automation
|
|||
{
|
||||
RemoveLastNullCompletionResult(result);
|
||||
|
||||
AddCommandWithPreferenceSetting(powershell, "Microsoft.PowerShell.Management\\Get-Service").AddParameter("Name", wordToComplete);
|
||||
var psObjects = context.Helper.ExecuteCurrentPowerShell(out exceptionThrown);
|
||||
powerShellExecutionHelper.AddCommandWithPreferenceSetting("Microsoft.PowerShell.Management\\Get-Service").AddParameter("Name", wordToComplete);
|
||||
var psObjects = powerShellExecutionHelper.ExecuteCurrentPowerShell(out exceptionThrown);
|
||||
if (psObjects != null)
|
||||
{
|
||||
foreach (dynamic serviceInfo in psObjects)
|
||||
|
@ -3427,16 +3394,14 @@ namespace System.Management.Automation
|
|||
|
||||
variableName = variableName ?? string.Empty;
|
||||
var quote = HandleDoubleAndSingleQuote(ref variableName);
|
||||
var powershell = context.Helper.CurrentPowerShell;
|
||||
|
||||
if (!variableName.EndsWith("*", StringComparison.Ordinal))
|
||||
{
|
||||
variableName += "*";
|
||||
}
|
||||
|
||||
AddCommandWithPreferenceSetting(powershell, "Microsoft.PowerShell.Utility\\Get-Variable").AddParameter("Name", variableName);
|
||||
Exception exceptionThrown;
|
||||
var psObjects = context.Helper.ExecuteCurrentPowerShell(out exceptionThrown);
|
||||
var powerShellExecutionHelper = context.Helper;
|
||||
var powershell = powerShellExecutionHelper.AddCommandWithPreferenceSetting("Microsoft.PowerShell.Utility\\Get-Variable").AddParameter("Name", variableName);
|
||||
var psObjects = powerShellExecutionHelper.ExecuteCurrentPowerShell(out _);
|
||||
if (psObjects == null)
|
||||
return;
|
||||
|
||||
|
@ -3483,11 +3448,11 @@ namespace System.Management.Automation
|
|||
|
||||
RemoveLastNullCompletionResult(result);
|
||||
|
||||
var powerShellExecutionHelper = context.Helper;
|
||||
if (paramName.Equals("Name", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
commandName = commandName ?? string.Empty;
|
||||
var quote = HandleDoubleAndSingleQuote(ref commandName);
|
||||
var powershell = context.Helper.CurrentPowerShell;
|
||||
|
||||
if (!commandName.EndsWith("*", StringComparison.Ordinal))
|
||||
{
|
||||
|
@ -3495,8 +3460,8 @@ namespace System.Management.Automation
|
|||
}
|
||||
|
||||
Exception exceptionThrown;
|
||||
AddCommandWithPreferenceSetting(powershell, "Microsoft.PowerShell.Utility\\Get-Alias").AddParameter("Name", commandName);
|
||||
var psObjects = context.Helper.ExecuteCurrentPowerShell(out exceptionThrown);
|
||||
var powershell = powerShellExecutionHelper.AddCommandWithPreferenceSetting("Microsoft.PowerShell.Utility\\Get-Alias").AddParameter("Name", commandName);
|
||||
var psObjects = powerShellExecutionHelper.ExecuteCurrentPowerShell(out exceptionThrown);
|
||||
if (psObjects != null)
|
||||
{
|
||||
foreach (dynamic aliasInfo in psObjects)
|
||||
|
@ -3525,12 +3490,12 @@ namespace System.Management.Automation
|
|||
// Complete for the parameter Definition
|
||||
// Available commands
|
||||
const CommandTypes commandTypes = CommandTypes.Cmdlet | CommandTypes.Function | CommandTypes.ExternalScript | CommandTypes.Workflow | CommandTypes.Configuration;
|
||||
var commandResults = CompleteCommand(new CompletionContext { WordToComplete = commandName, Helper = context.Helper }, null, commandTypes);
|
||||
var commandResults = CompleteCommand(new CompletionContext { WordToComplete = commandName, Helper = powerShellExecutionHelper }, null, commandTypes);
|
||||
if (commandResults != null && commandResults.Count > 0)
|
||||
result.AddRange(commandResults);
|
||||
|
||||
// The parameter Definition takes a file
|
||||
var fileResults = new List<CompletionResult>(CompleteFilename(new CompletionContext { WordToComplete = commandName, Helper = context.Helper }));
|
||||
var fileResults = new List<CompletionResult>(CompleteFilename(new CompletionContext { WordToComplete = commandName, Helper = powerShellExecutionHelper }));
|
||||
if (fileResults.Count > 0)
|
||||
result.AddRange(fileResults);
|
||||
}
|
||||
|
@ -3549,16 +3514,16 @@ namespace System.Management.Automation
|
|||
|
||||
traceSourceName = traceSourceName ?? string.Empty;
|
||||
var quote = HandleDoubleAndSingleQuote(ref traceSourceName);
|
||||
var powershell = context.Helper.CurrentPowerShell;
|
||||
|
||||
if (!traceSourceName.EndsWith("*", StringComparison.Ordinal))
|
||||
{
|
||||
traceSourceName += "*";
|
||||
}
|
||||
|
||||
AddCommandWithPreferenceSetting(powershell, "Microsoft.PowerShell.Utility\\Get-TraceSource").AddParameter("Name", traceSourceName);
|
||||
var powerShellExecutionHelper = context.Helper;
|
||||
var powershell = powerShellExecutionHelper.AddCommandWithPreferenceSetting("Microsoft.PowerShell.Utility\\Get-TraceSource").AddParameter("Name", traceSourceName);
|
||||
Exception exceptionThrown;
|
||||
var psObjects = context.Helper.ExecuteCurrentPowerShell(out exceptionThrown);
|
||||
var psObjects = powerShellExecutionHelper.ExecuteCurrentPowerShell(out exceptionThrown);
|
||||
if (psObjects == null)
|
||||
return;
|
||||
|
||||
|
@ -3786,11 +3751,11 @@ namespace System.Management.Automation
|
|||
{
|
||||
return;
|
||||
}
|
||||
prevType = astPair.Argument.GetInferredType(context);
|
||||
prevType = AstTypeInference.InferTypeOf(astPair.Argument, context.TypeInferenceContext, TypeInferenceRuntimePermissions.AllowSafeEval);
|
||||
}
|
||||
else
|
||||
{
|
||||
prevType = pipelineAst.PipelineElements[i - 1].GetInferredType(context);
|
||||
prevType = AstTypeInference.InferTypeOf(pipelineAst.PipelineElements[i - 1], context.TypeInferenceContext, TypeInferenceRuntimePermissions.AllowSafeEval);
|
||||
}
|
||||
|
||||
CompleteMemberByInferredType(context, prevType, result, wordToComplete + "*", filter: IsPropertyMember, isStatic: false);
|
||||
|
@ -4069,7 +4034,7 @@ namespace System.Management.Automation
|
|||
return CommandCompletion.EmptyCompletionResult;
|
||||
}
|
||||
|
||||
var helper = new CompletionExecutionHelper(PowerShell.Create(RunspaceMode.CurrentRunspace));
|
||||
var helper = new PowerShellExecutionHelper(PowerShell.Create(RunspaceMode.CurrentRunspace));
|
||||
return CompleteFilename(new CompletionContext { WordToComplete = fileName, Helper = helper });
|
||||
}
|
||||
|
||||
|
@ -4109,16 +4074,13 @@ namespace System.Management.Automation
|
|||
}
|
||||
else
|
||||
{
|
||||
var powershell = context.Helper.CurrentPowerShell;
|
||||
var executionContext = powershell.GetContextFromTLS();
|
||||
|
||||
// We want to prefer relative paths in a completion result unless the user has already
|
||||
// specified a drive or portion of the path.
|
||||
string unused;
|
||||
var executionContext = context.ExecutionContext;
|
||||
var defaultRelative = string.IsNullOrWhiteSpace(wordToComplete)
|
||||
|| (wordToComplete.IndexOfAny(Utils.Separators.Directory) != 0 &&
|
||||
!Regex.Match(wordToComplete, @"^~[\\/]+.*").Success &&
|
||||
!executionContext.LocationGlobber.IsAbsolutePath(wordToComplete, out unused));
|
||||
!executionContext.LocationGlobber.IsAbsolutePath(wordToComplete, out _));
|
||||
var relativePaths = context.GetOption("RelativePaths", @default: defaultRelative);
|
||||
var useLiteralPath = context.GetOption("LiteralPaths", @default: false);
|
||||
|
||||
|
@ -4127,18 +4089,20 @@ namespace System.Management.Automation
|
|||
wordToComplete = WildcardPattern.Escape(wordToComplete, Utils.Separators.StarOrQuestion);
|
||||
}
|
||||
|
||||
if (!defaultRelative && wordToComplete.Length >= 2 && wordToComplete[1] == ':' && char.IsLetter(wordToComplete[0]) && context.ExecutionContext != null)
|
||||
if (!defaultRelative && wordToComplete.Length >= 2 && wordToComplete[1] == ':' && char.IsLetter(wordToComplete[0]) && executionContext != null)
|
||||
{
|
||||
// We don't actually need the drive, but the drive must be "mounted" in PowerShell before completion
|
||||
// can succeed. This call will mount the drive if it wasn't already.
|
||||
context.ExecutionContext.SessionState.Drive.GetAtScope(wordToComplete.Substring(0, 1), "global");
|
||||
executionContext.SessionState.Drive.GetAtScope(wordToComplete.Substring(0, 1), "global");
|
||||
}
|
||||
|
||||
AddCommandWithPreferenceSetting(powershell, "Microsoft.PowerShell.Management\\Resolve-Path")
|
||||
var powerShellExecutionHelper = context.Helper;
|
||||
powerShellExecutionHelper
|
||||
.AddCommandWithPreferenceSetting("Microsoft.PowerShell.Management\\Resolve-Path")
|
||||
.AddParameter("Path", wordToComplete + "*");
|
||||
|
||||
Exception exceptionThrown;
|
||||
var psobjs = context.Helper.ExecuteCurrentPowerShell(out exceptionThrown);
|
||||
var psobjs = powerShellExecutionHelper.ExecuteCurrentPowerShell(out exceptionThrown);
|
||||
|
||||
if (psobjs != null)
|
||||
{
|
||||
|
@ -4257,11 +4221,12 @@ namespace System.Management.Automation
|
|||
|
||||
if (!hiddenFilesAreHandled)
|
||||
{
|
||||
AddCommandWithPreferenceSetting(powershell, "Microsoft.PowerShell.Management\\Get-ChildItem")
|
||||
powerShellExecutionHelper
|
||||
.AddCommandWithPreferenceSetting("Microsoft.PowerShell.Management\\Get-ChildItem")
|
||||
.AddParameter("Path", wordToComplete + "*")
|
||||
.AddParameter("Hidden", true);
|
||||
|
||||
var hiddenItems = context.Helper.ExecuteCurrentPowerShell(out exceptionThrown);
|
||||
var hiddenItems = powerShellExecutionHelper.ExecuteCurrentPowerShell(out exceptionThrown);
|
||||
if (hiddenItems != null && hiddenItems.Count > 0)
|
||||
{
|
||||
foreach (var hiddenItem in hiddenItems)
|
||||
|
@ -4396,9 +4361,10 @@ namespace System.Management.Automation
|
|||
}
|
||||
else
|
||||
{
|
||||
AddCommandWithPreferenceSetting(powershell, "Microsoft.PowerShell.Management\\Get-Item")
|
||||
powerShellExecutionHelper
|
||||
.AddCommandWithPreferenceSetting("Microsoft.PowerShell.Management\\Get-Item")
|
||||
.AddParameter("LiteralPath", path);
|
||||
var items = context.Helper.ExecuteCurrentPowerShell(out exceptionThrown);
|
||||
var items = powerShellExecutionHelper.ExecuteCurrentPowerShell(out exceptionThrown);
|
||||
if (items != null && items.Count == 1)
|
||||
{
|
||||
dynamic item = items[0];
|
||||
|
@ -4407,9 +4373,10 @@ namespace System.Management.Automation
|
|||
if (containerOnly && !isContainer)
|
||||
continue;
|
||||
|
||||
AddCommandWithPreferenceSetting(powershell, "Microsoft.PowerShell.Management\\Convert-Path")
|
||||
powerShellExecutionHelper
|
||||
.AddCommandWithPreferenceSetting("Microsoft.PowerShell.Management\\Convert-Path")
|
||||
.AddParameter("LiteralPath", item.PSPath);
|
||||
var tooltips = context.Helper.ExecuteCurrentPowerShell(out exceptionThrown);
|
||||
var tooltips = powerShellExecutionHelper.ExecuteCurrentPowerShell(out exceptionThrown);
|
||||
string tooltip = null, listItemText = item.PSChildName;
|
||||
if (tooltips != null && tooltips.Count == 1)
|
||||
{
|
||||
|
@ -4516,7 +4483,7 @@ namespace System.Management.Automation
|
|||
return CommandCompletion.EmptyCompletionResult;
|
||||
}
|
||||
|
||||
var helper = new CompletionExecutionHelper(PowerShell.Create(RunspaceMode.CurrentRunspace));
|
||||
var helper = new PowerShellExecutionHelper(PowerShell.Create(RunspaceMode.CurrentRunspace));
|
||||
return CompleteVariable(new CompletionContext { WordToComplete = variableName, Helper = helper });
|
||||
}
|
||||
|
||||
|
@ -4619,7 +4586,7 @@ namespace System.Management.Automation
|
|||
var commandAst = ast as CommandAst;
|
||||
if (commandAst != null)
|
||||
{
|
||||
PSTypeName discoveredType = ast.GetInferredType(context).FirstOrDefault<PSTypeName>();
|
||||
PSTypeName discoveredType = AstTypeInference.InferTypeOf(ast, context.TypeInferenceContext, TypeInferenceRuntimePermissions.AllowSafeEval).FirstOrDefault<PSTypeName>();
|
||||
if (discoveredType != null)
|
||||
{
|
||||
tooltip = StringUtil.Format("[{0}]${1}", discoveredType.Name, userPath);
|
||||
|
@ -4654,12 +4621,13 @@ namespace System.Management.Automation
|
|||
}
|
||||
}
|
||||
|
||||
var powershell = context.Helper.CurrentPowerShell;
|
||||
AddCommandWithPreferenceSetting(powershell, "Microsoft.PowerShell.Management\\Get-Item").AddParameter("Path", pattern);
|
||||
AddCommandWithPreferenceSetting(powershell, "Microsoft.PowerShell.Utility\\Sort-Object").AddParameter("Property", "Name");
|
||||
var powerShellExecutionHelper = context.Helper;
|
||||
powerShellExecutionHelper
|
||||
.AddCommandWithPreferenceSetting("Microsoft.PowerShell.Management\\Get-Item").AddParameter("Path", pattern)
|
||||
.AddCommandWithPreferenceSetting("Microsoft.PowerShell.Utility\\Sort-Object").AddParameter("Property", "Name");
|
||||
|
||||
Exception exceptionThrown;
|
||||
var psobjs = context.Helper.ExecuteCurrentPowerShell(out exceptionThrown);
|
||||
var psobjs = powerShellExecutionHelper.ExecuteCurrentPowerShell(out exceptionThrown);
|
||||
if (psobjs != null)
|
||||
{
|
||||
foreach (dynamic psobj in psobjs)
|
||||
|
@ -4690,11 +4658,11 @@ namespace System.Management.Automation
|
|||
|
||||
if (colon == -1 && "env".StartsWith(wordToComplete, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
powershell = context.Helper.CurrentPowerShell;
|
||||
AddCommandWithPreferenceSetting(powershell, "Microsoft.PowerShell.Management\\Get-Item").AddParameter("Path", "env:*");
|
||||
AddCommandWithPreferenceSetting(powershell, "Microsoft.PowerShell.Utility\\Sort-Object").AddParameter("Property", "Key");
|
||||
powerShellExecutionHelper
|
||||
.AddCommandWithPreferenceSetting("Microsoft.PowerShell.Management\\Get-Item").AddParameter("Path", "env:*")
|
||||
.AddCommandWithPreferenceSetting("Microsoft.PowerShell.Utility\\Sort-Object").AddParameter("Property", "Key");
|
||||
|
||||
psobjs = context.Helper.ExecuteCurrentPowerShell(out exceptionThrown);
|
||||
psobjs = powerShellExecutionHelper.ExecuteCurrentPowerShell(out exceptionThrown);
|
||||
if (psobjs != null)
|
||||
{
|
||||
foreach (dynamic psobj in psobjs)
|
||||
|
@ -4730,9 +4698,10 @@ namespace System.Management.Automation
|
|||
{
|
||||
// If no drive was specified, then look for matching drives/scopes
|
||||
pattern = wordToComplete + "*";
|
||||
AddCommandWithPreferenceSetting(powershell, "Microsoft.PowerShell.Management\\Get-PSDrive").AddParameter("Name", pattern);
|
||||
AddCommandWithPreferenceSetting(powershell, "Microsoft.PowerShell.Utility\\Sort-Object").AddParameter("Property", "Name");
|
||||
psobjs = context.Helper.ExecuteCurrentPowerShell(out exceptionThrown);
|
||||
powerShellExecutionHelper
|
||||
.AddCommandWithPreferenceSetting("Microsoft.PowerShell.Management\\Get-PSDrive").AddParameter("Name", pattern)
|
||||
.AddCommandWithPreferenceSetting("Microsoft.PowerShell.Utility\\Sort-Object").AddParameter("Property", "Name");
|
||||
psobjs = powerShellExecutionHelper.ExecuteCurrentPowerShell(out exceptionThrown);
|
||||
if (psobjs != null)
|
||||
{
|
||||
foreach (var psobj in psobjs)
|
||||
|
@ -4867,15 +4836,13 @@ namespace System.Management.Automation
|
|||
if (!matchResult.Success) { return results; }
|
||||
|
||||
string wordToComplete = matchResult.Groups[1].Value;
|
||||
PowerShell powershell = context.Helper.CurrentPowerShell;
|
||||
Collection<PSObject> psobjs;
|
||||
Exception exceptionThrown;
|
||||
|
||||
int entryId;
|
||||
if (Regex.IsMatch(wordToComplete, @"^[0-9]+$") && LanguagePrimitives.TryConvertTo(wordToComplete, out entryId))
|
||||
{
|
||||
AddCommandWithPreferenceSetting(powershell, "Get-History", typeof(GetHistoryCommand)).AddParameter("Id", entryId);
|
||||
psobjs = context.Helper.ExecuteCurrentPowerShell(out exceptionThrown);
|
||||
context.Helper.AddCommandWithPreferenceSetting("Get-History", typeof(GetHistoryCommand)).AddParameter("Id", entryId);
|
||||
psobjs = context.Helper.ExecuteCurrentPowerShell(out _);
|
||||
|
||||
if (psobjs != null && psobjs.Count == 1)
|
||||
{
|
||||
|
@ -4899,9 +4866,9 @@ namespace System.Management.Automation
|
|||
}
|
||||
|
||||
wordToComplete = "*" + wordToComplete + "*";
|
||||
AddCommandWithPreferenceSetting(powershell, "Get-History", typeof(GetHistoryCommand));
|
||||
context.Helper.AddCommandWithPreferenceSetting("Get-History", typeof(GetHistoryCommand));
|
||||
|
||||
psobjs = context.Helper.ExecuteCurrentPowerShell(out exceptionThrown);
|
||||
psobjs = context.Helper.ExecuteCurrentPowerShell(out _);
|
||||
var pattern = WildcardPattern.Get(wordToComplete, WildcardOptions.IgnoreCase);
|
||||
|
||||
if (psobjs != null)
|
||||
|
@ -5068,7 +5035,7 @@ namespace System.Management.Automation
|
|||
}
|
||||
else
|
||||
{
|
||||
inferredTypes = targetExpr.GetInferredType(context).ToArray();
|
||||
inferredTypes = AstTypeInference.InferTypeOf(targetExpr, context.TypeInferenceContext, TypeInferenceRuntimePermissions.AllowSafeEval).ToArray();
|
||||
}
|
||||
|
||||
if (inferredTypes != null && inferredTypes.Length > 0)
|
||||
|
@ -5190,7 +5157,7 @@ namespace System.Management.Automation
|
|||
continue;
|
||||
}
|
||||
typeNameUsed.Add(psTypeName.Name);
|
||||
var members = GetMembersByInferredType(psTypeName, context, isStatic, filter);
|
||||
var members = context.TypeInferenceContext.GetMembersByInferredType(psTypeName, isStatic, filter);
|
||||
foreach (var member in members)
|
||||
{
|
||||
AddInferredMember(member, memberNamePattern, results);
|
||||
|
@ -5208,11 +5175,13 @@ namespace System.Management.Automation
|
|||
if (results.Count > 0)
|
||||
{
|
||||
// Sort the results
|
||||
AddCommandWithPreferenceSetting(context.Helper.CurrentPowerShell, "Microsoft.PowerShell.Utility\\Sort-Object")
|
||||
var powerShellExecutionHelper = context.Helper;
|
||||
powerShellExecutionHelper
|
||||
.AddCommandWithPreferenceSetting("Microsoft.PowerShell.Utility\\Sort-Object")
|
||||
.AddParameter("Property", new[] { "ResultType", "ListItemText" })
|
||||
.AddParameter("Unique");
|
||||
Exception unused;
|
||||
var sortedResults = context.Helper.ExecuteCurrentPowerShell(out unused, results);
|
||||
var sortedResults = powerShellExecutionHelper.ExecuteCurrentPowerShell(out unused, results);
|
||||
results.Clear();
|
||||
results.AddRange(sortedResults.Select(psobj => PSObject.Base(psobj) as CompletionResult));
|
||||
}
|
||||
|
@ -5366,153 +5335,6 @@ namespace System.Management.Automation
|
|||
return false;
|
||||
}
|
||||
|
||||
internal static IEnumerable<object> GetMembersByInferredType(PSTypeName typename, CompletionContext context, bool @static, Func<object, bool> filter)
|
||||
{
|
||||
List<object> results = new List<object>();
|
||||
|
||||
Func<object, bool> filterToCall = filter;
|
||||
if (typename.Type != null)
|
||||
{
|
||||
if (context.CurrentTypeDefinitionAst == null || context.CurrentTypeDefinitionAst.Type != typename.Type)
|
||||
{
|
||||
if (filterToCall == null)
|
||||
filterToCall = o => !IsMemberHidden(o);
|
||||
else
|
||||
filterToCall = o => !IsMemberHidden(o) && filter(o);
|
||||
}
|
||||
IEnumerable<Type> elementTypes;
|
||||
if (typename.Type.IsArray)
|
||||
{
|
||||
elementTypes = new[] { typename.Type.GetElementType() };
|
||||
}
|
||||
else
|
||||
{
|
||||
elementTypes = typename.Type.GetInterfaces().Where(
|
||||
t => t.GetTypeInfo().IsGenericType && t.GetGenericTypeDefinition() == typeof(IEnumerable<>));
|
||||
}
|
||||
foreach (var type in elementTypes.Prepend(typename.Type))
|
||||
{
|
||||
// Look in the type table first.
|
||||
if (!@static)
|
||||
{
|
||||
var consolidatedString = DotNetAdapter.GetInternedTypeNameHierarchy(type);
|
||||
results.AddRange(context.ExecutionContext.TypeTable.GetMembers<PSMemberInfo>(consolidatedString));
|
||||
}
|
||||
|
||||
var members = @static
|
||||
? PSObject.dotNetStaticAdapter.BaseGetMembers<PSMemberInfo>(type)
|
||||
: PSObject.dotNetInstanceAdapter.GetPropertiesAndMethods(type, false);
|
||||
results.AddRange(filterToCall != null ? members.Where(filterToCall) : members);
|
||||
}
|
||||
}
|
||||
else if (typename.TypeDefinitionAst != null)
|
||||
{
|
||||
if (context.CurrentTypeDefinitionAst != typename.TypeDefinitionAst)
|
||||
{
|
||||
if (filterToCall == null)
|
||||
filterToCall = o => !IsMemberHidden(o);
|
||||
else
|
||||
filterToCall = o => !IsMemberHidden(o) && filter(o);
|
||||
}
|
||||
|
||||
bool foundConstructor = false;
|
||||
foreach (var member in typename.TypeDefinitionAst.Members)
|
||||
{
|
||||
bool add = false;
|
||||
var propertyMember = member as PropertyMemberAst;
|
||||
if (propertyMember != null)
|
||||
{
|
||||
if (propertyMember.IsStatic == @static)
|
||||
{
|
||||
add = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var functionMember = (FunctionMemberAst)member;
|
||||
if (functionMember.IsStatic == @static)
|
||||
{
|
||||
add = true;
|
||||
}
|
||||
foundConstructor |= functionMember.IsConstructor;
|
||||
}
|
||||
|
||||
if (filterToCall != null && add)
|
||||
{
|
||||
add = filterToCall(member);
|
||||
}
|
||||
|
||||
if (add)
|
||||
{
|
||||
results.Add(member);
|
||||
}
|
||||
}
|
||||
|
||||
//iterate through bases/interfaces
|
||||
foreach (var baseType in typename.TypeDefinitionAst.BaseTypes)
|
||||
{
|
||||
TypeName baseTypeName = baseType.TypeName as TypeName;
|
||||
if (baseTypeName != null)
|
||||
{
|
||||
TypeDefinitionAst baseTypeDefinitionAst = baseTypeName._typeDefinitionAst;
|
||||
results.AddRange(GetMembersByInferredType(new PSTypeName(baseTypeDefinitionAst), context, @static, filterToCall));
|
||||
}
|
||||
}
|
||||
|
||||
// Add stuff from our base class System.Object.
|
||||
if (@static)
|
||||
{
|
||||
// Don't add base class constructors
|
||||
if (filter == null)
|
||||
{
|
||||
filterToCall = o => !IsConstructor(o);
|
||||
}
|
||||
else
|
||||
{
|
||||
filterToCall = o => !IsConstructor(o) && filter(o);
|
||||
}
|
||||
|
||||
if (!foundConstructor)
|
||||
{
|
||||
results.Add(
|
||||
new CompilerGeneratedMemberFunctionAst(PositionUtilities.EmptyExtent, typename.TypeDefinitionAst,
|
||||
SpecialMemberFunctionType.DefaultConstructor));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Reset the filter because the recursive call will add IsHidden back if necessary.
|
||||
filterToCall = filter;
|
||||
}
|
||||
results.AddRange(GetMembersByInferredType(new PSTypeName(typeof(object)), context, @static, filterToCall));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Look in the type table first.
|
||||
if (!@static)
|
||||
{
|
||||
var consolidatedString = new ConsolidatedString(new string[] { typename.Name });
|
||||
results.AddRange(context.ExecutionContext.TypeTable.GetMembers<PSMemberInfo>(consolidatedString));
|
||||
}
|
||||
|
||||
string cimNamespace;
|
||||
string className;
|
||||
if (NativeCompletionCimCommands_ParseTypeName(typename, out cimNamespace, out className))
|
||||
{
|
||||
AddCommandWithPreferenceSetting(context.Helper.CurrentPowerShell, "CimCmdlets\\Get-CimClass")
|
||||
.AddParameter("Namespace", cimNamespace)
|
||||
.AddParameter("Class", className);
|
||||
Exception unused;
|
||||
var classes = context.Helper.ExecuteCurrentPowerShell(out unused);
|
||||
foreach (var @class in classes.Select(PSObject.Base).OfType<CimClass>())
|
||||
{
|
||||
results.AddRange(filterToCall != null ? @class.CimClassProperties.Where(filterToCall) : @class.CimClassProperties);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
#endregion Members
|
||||
|
||||
|
@ -6038,7 +5860,7 @@ namespace System.Management.Automation
|
|||
? PowerShell.Create()
|
||||
: PowerShell.Create(RunspaceMode.CurrentRunspace);
|
||||
|
||||
var helper = new CompletionExecutionHelper(powershell);
|
||||
var helper = new PowerShellExecutionHelper(powershell);
|
||||
return CompleteType(new CompletionContext { WordToComplete = typeName, Helper = helper });
|
||||
}
|
||||
|
||||
|
@ -6326,7 +6148,7 @@ namespace System.Management.Automation
|
|||
{
|
||||
var result = new List<CompletionResult>();
|
||||
CompleteMemberByInferredType(
|
||||
completionContext, typeAst.GetInferredType(completionContext),
|
||||
completionContext, AstTypeInference.InferTypeOf(typeAst, completionContext.TypeInferenceContext, TypeInferenceRuntimePermissions.AllowSafeEval),
|
||||
result, completionContext.WordToComplete + "*", IsWriteablePropertyMember, isStatic: false);
|
||||
return result;
|
||||
}
|
||||
|
@ -6429,7 +6251,7 @@ namespace System.Management.Automation
|
|||
switch (binding.CommandName)
|
||||
{
|
||||
case "New-Object":
|
||||
var inferredType = commandAst.GetInferredType(completionContext);
|
||||
var inferredType = AstTypeInference.InferTypeOf(commandAst, completionContext.TypeInferenceContext, TypeInferenceRuntimePermissions.AllowSafeEval);
|
||||
var result = new List<CompletionResult>();
|
||||
CompleteMemberByInferredType(
|
||||
completionContext, inferredType,
|
||||
|
@ -6470,30 +6292,6 @@ namespace System.Management.Automation
|
|||
|
||||
#region Helpers
|
||||
|
||||
internal static PowerShell AddCommandWithPreferenceSetting(PowerShell powershell, string command, Type type = null)
|
||||
{
|
||||
Diagnostics.Assert(powershell != null, "the passed-in powershell cannot be null");
|
||||
Diagnostics.Assert(!String.IsNullOrWhiteSpace(command), "the passed-in command name should not be null or whitespaces");
|
||||
|
||||
if (type != null)
|
||||
{
|
||||
var cmdletInfo = new CmdletInfo(command, type);
|
||||
powershell.AddCommand(cmdletInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
powershell.AddCommand(command);
|
||||
}
|
||||
powershell
|
||||
.AddParameter("ErrorAction", ActionPreference.Ignore)
|
||||
.AddParameter("WarningAction", ActionPreference.Ignore)
|
||||
.AddParameter("InformationAction", ActionPreference.Ignore)
|
||||
.AddParameter("Verbose", false)
|
||||
.AddParameter("Debug", false);
|
||||
|
||||
return powershell;
|
||||
}
|
||||
|
||||
internal static bool IsPathSafelyExpandable(ExpandableStringExpressionAst expandableStringAst, string extraText, ExecutionContext executionContext, out string expandedString)
|
||||
{
|
||||
expandedString = null;
|
||||
|
@ -6619,14 +6417,14 @@ namespace System.Management.Automation
|
|||
value = new[] { value };
|
||||
}
|
||||
|
||||
var powershell = context.Helper.CurrentPowerShell;
|
||||
|
||||
// Instead of Get-Member, we access the members directly and send as input to the pipe.
|
||||
AddCommandWithPreferenceSetting(powershell, "Microsoft.PowerShell.Core\\Where-Object")
|
||||
var powerShellExecutionHelper = context.Helper;
|
||||
powerShellExecutionHelper
|
||||
.AddCommandWithPreferenceSetting("Microsoft.PowerShell.Core\\Where-Object")
|
||||
.AddParameter("Property", "Name")
|
||||
.AddParameter("Like")
|
||||
.AddParameter("Value", memberName);
|
||||
AddCommandWithPreferenceSetting(powershell, "Microsoft.PowerShell.Utility\\Sort-Object")
|
||||
.AddParameter("Value", memberName)
|
||||
.AddCommandWithPreferenceSetting("Microsoft.PowerShell.Utility\\Sort-Object")
|
||||
.AddParameter("Property", new object[] { "MemberType", "Name" });
|
||||
|
||||
IEnumerable members;
|
||||
|
@ -6643,8 +6441,7 @@ namespace System.Management.Automation
|
|||
{
|
||||
members = PSObject.AsPSObject(value).Members;
|
||||
}
|
||||
Exception exceptionThrown;
|
||||
var sortedMembers = context.Helper.ExecuteCurrentPowerShell(out exceptionThrown, members);
|
||||
var sortedMembers = powerShellExecutionHelper.ExecuteCurrentPowerShell(out _, members);
|
||||
|
||||
foreach (var member in sortedMembers)
|
||||
{
|
||||
|
|
|
@ -1253,10 +1253,7 @@ namespace System.Management.Automation.Language
|
|||
var expressionArgument = _commandElements[commandIndex] as ExpressionAst;
|
||||
if (expressionArgument != null)
|
||||
{
|
||||
if (argumentsToGetDynamicParameters != null)
|
||||
{
|
||||
argumentsToGetDynamicParameters.Add(expressionArgument.Extent.Text);
|
||||
}
|
||||
argumentsToGetDynamicParameters?.Add(expressionArgument.Extent.Text);
|
||||
|
||||
_arguments.Add(new AstPair(null, expressionArgument));
|
||||
}
|
||||
|
@ -1338,79 +1335,76 @@ namespace System.Management.Automation.Language
|
|||
if (_commandAst.IsInWorkflow())
|
||||
{
|
||||
var converterType = Type.GetType(Utils.WorkflowType);
|
||||
if (converterType != null)
|
||||
var activityParameters = (Dictionary<string, Type>) converterType?.GetMethod("GetActivityParameters").Invoke(null, new object[] { _commandAst });
|
||||
if (activityParameters != null)
|
||||
{
|
||||
var activityParameters = (Dictionary<string, Type>)converterType.GetMethod("GetActivityParameters").Invoke(null, new object[] { _commandAst });
|
||||
if (activityParameters != null)
|
||||
bool needToRemoveReplacedProperty = activityParameters.ContainsKey("PSComputerName") &&
|
||||
!activityParameters.ContainsKey("ComputerName");
|
||||
|
||||
var parametersToAdd = new List<MergedCompiledCommandParameter>();
|
||||
var attrCollection = new Collection<Attribute> { new ParameterAttribute() };
|
||||
foreach (var pair in activityParameters)
|
||||
{
|
||||
bool needToRemoveReplacedProperty = activityParameters.ContainsKey("PSComputerName") &&
|
||||
!activityParameters.ContainsKey("ComputerName");
|
||||
|
||||
var parametersToAdd = new List<MergedCompiledCommandParameter>();
|
||||
var attrCollection = new Collection<Attribute> { new ParameterAttribute() };
|
||||
foreach (var pair in activityParameters)
|
||||
if (psuedoWorkflowCommand || !_bindableParameters.BindableParameters.ContainsKey(pair.Key))
|
||||
{
|
||||
if (psuedoWorkflowCommand || !_bindableParameters.BindableParameters.ContainsKey(pair.Key))
|
||||
{
|
||||
Type parameterType = GetActualActivityParameterType(pair.Value);
|
||||
var runtimeDefinedParameter = new RuntimeDefinedParameter(pair.Key, parameterType, attrCollection);
|
||||
var compiledCommandParameter = new CompiledCommandParameter(runtimeDefinedParameter, false) { IsInAllSets = true };
|
||||
var mergedCompiledCommandParameter = new MergedCompiledCommandParameter(compiledCommandParameter, ParameterBinderAssociation.DeclaredFormalParameters);
|
||||
parametersToAdd.Add(mergedCompiledCommandParameter);
|
||||
}
|
||||
Type parameterType = GetActualActivityParameterType(pair.Value);
|
||||
var runtimeDefinedParameter = new RuntimeDefinedParameter(pair.Key, parameterType, attrCollection);
|
||||
var compiledCommandParameter = new CompiledCommandParameter(runtimeDefinedParameter, false) { IsInAllSets = true };
|
||||
var mergedCompiledCommandParameter = new MergedCompiledCommandParameter(compiledCommandParameter, ParameterBinderAssociation.DeclaredFormalParameters);
|
||||
parametersToAdd.Add(mergedCompiledCommandParameter);
|
||||
}
|
||||
if (parametersToAdd.Any())
|
||||
}
|
||||
if (parametersToAdd.Any())
|
||||
{
|
||||
var mergedBindableParameters = new MergedCommandParameterMetadata();
|
||||
if (!psuedoWorkflowCommand)
|
||||
{
|
||||
var mergedBindableParameters = new MergedCommandParameterMetadata();
|
||||
if (!psuedoWorkflowCommand)
|
||||
{
|
||||
mergedBindableParameters.ReplaceMetadata(_bindableParameters);
|
||||
}
|
||||
foreach (var p in parametersToAdd)
|
||||
{
|
||||
mergedBindableParameters.BindableParameters.Add(p.Parameter.Name, p);
|
||||
}
|
||||
_bindableParameters = mergedBindableParameters;
|
||||
mergedBindableParameters.ReplaceMetadata(_bindableParameters);
|
||||
}
|
||||
|
||||
// Remove common parameters that are supported by all commands, but not
|
||||
// by workflows
|
||||
bool fixedReadOnly = false;
|
||||
foreach (var ignored in _ignoredWorkflowParameters)
|
||||
foreach (var p in parametersToAdd)
|
||||
{
|
||||
if (_bindableParameters.BindableParameters.ContainsKey(ignored))
|
||||
mergedBindableParameters.BindableParameters.Add(p.Parameter.Name, p);
|
||||
}
|
||||
_bindableParameters = mergedBindableParameters;
|
||||
}
|
||||
|
||||
// Remove common parameters that are supported by all commands, but not
|
||||
// by workflows
|
||||
bool fixedReadOnly = false;
|
||||
foreach (var ignored in _ignoredWorkflowParameters)
|
||||
{
|
||||
if (_bindableParameters.BindableParameters.ContainsKey(ignored))
|
||||
{
|
||||
// However, some ignored parameters are explicitly implemented by
|
||||
// activities, so keep them.
|
||||
if (!activityParameters.ContainsKey(ignored))
|
||||
{
|
||||
// However, some ignored parameters are explicitly implemented by
|
||||
// activities, so keep them.
|
||||
if (!activityParameters.ContainsKey(ignored))
|
||||
if (!fixedReadOnly)
|
||||
{
|
||||
if (!fixedReadOnly)
|
||||
{
|
||||
_bindableParameters.ResetReadOnly();
|
||||
fixedReadOnly = true;
|
||||
}
|
||||
|
||||
_bindableParameters.BindableParameters.Remove(ignored);
|
||||
_bindableParameters.ResetReadOnly();
|
||||
fixedReadOnly = true;
|
||||
}
|
||||
|
||||
_bindableParameters.BindableParameters.Remove(ignored);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_bindableParameters.BindableParameters.ContainsKey("ComputerName") && needToRemoveReplacedProperty)
|
||||
if (_bindableParameters.BindableParameters.ContainsKey("ComputerName") && needToRemoveReplacedProperty)
|
||||
{
|
||||
if (!fixedReadOnly)
|
||||
{
|
||||
if (!fixedReadOnly)
|
||||
{
|
||||
_bindableParameters.ResetReadOnly();
|
||||
fixedReadOnly = true;
|
||||
}
|
||||
_bindableParameters.ResetReadOnly();
|
||||
fixedReadOnly = true;
|
||||
}
|
||||
|
||||
_bindableParameters.BindableParameters.Remove("ComputerName");
|
||||
string aliasOfComputerName = (from aliasPair in _bindableParameters.AliasedParameters
|
||||
where String.Equals("ComputerName", aliasPair.Value.Parameter.Name)
|
||||
select aliasPair.Key).FirstOrDefault();
|
||||
if (aliasOfComputerName != null)
|
||||
{
|
||||
_bindableParameters.AliasedParameters.Remove(aliasOfComputerName);
|
||||
}
|
||||
_bindableParameters.BindableParameters.Remove("ComputerName");
|
||||
string aliasOfComputerName = (from aliasPair in _bindableParameters.AliasedParameters
|
||||
where String.Equals("ComputerName", aliasPair.Value.Parameter.Name)
|
||||
select aliasPair.Key).FirstOrDefault();
|
||||
if (aliasOfComputerName != null)
|
||||
{
|
||||
_bindableParameters.AliasedParameters.Remove(aliasOfComputerName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1451,32 +1445,36 @@ namespace System.Management.Automation.Language
|
|||
}
|
||||
ast.Visit(exportVisitor);
|
||||
|
||||
resolvedCommandName = _commandAst.GetCommandName();
|
||||
CommandProcessorBase commandProcessor = null;
|
||||
|
||||
string alias;
|
||||
int resolvedAliasCount = 0;
|
||||
while (exportVisitor.DiscoveredAliases.TryGetValue(resolvedCommandName, out alias))
|
||||
resolvedCommandName = _commandAst.GetCommandName();
|
||||
if (resolvedCommandName != null)
|
||||
{
|
||||
resolvedAliasCount += 1;
|
||||
if (resolvedAliasCount > 5)
|
||||
break; // give up, assume it's recursive
|
||||
resolvedCommandName = alias;
|
||||
}
|
||||
string alias;
|
||||
int resolvedAliasCount = 0;
|
||||
|
||||
FunctionDefinitionAst functionDefinitionAst;
|
||||
if (exportVisitor.DiscoveredFunctions.TryGetValue(resolvedCommandName, out functionDefinitionAst))
|
||||
{
|
||||
// We could use the IAstToScriptBlockConverter to get the actual script block, but that can be fairly expensive for workflows.
|
||||
// IAstToScriptBlockConverter is public, so we might consider converting non-workflows, but the interface isn't really designed
|
||||
// for Intellisense, so we can't really expect good performance, so instead we'll just fall back on the actual
|
||||
// parameters we see in the ast.
|
||||
var scriptBlock = functionDefinitionAst.IsWorkflow
|
||||
? CreateFakeScriptBlockForWorkflow(functionDefinitionAst)
|
||||
: new ScriptBlock(functionDefinitionAst, functionDefinitionAst.IsFilter);
|
||||
commandProcessor = CommandDiscovery.CreateCommandProcessorForScript(scriptBlock, context, true, context.EngineSessionState);
|
||||
}
|
||||
while (exportVisitor.DiscoveredAliases.TryGetValue(resolvedCommandName, out alias))
|
||||
{
|
||||
resolvedAliasCount += 1;
|
||||
if (resolvedAliasCount > 5)
|
||||
break; // give up, assume it's recursive
|
||||
resolvedCommandName = alias;
|
||||
}
|
||||
|
||||
FunctionDefinitionAst functionDefinitionAst;
|
||||
if (exportVisitor.DiscoveredFunctions.TryGetValue(resolvedCommandName, out functionDefinitionAst))
|
||||
{
|
||||
// We could use the IAstToScriptBlockConverter to get the actual script block, but that can be fairly expensive for workflows.
|
||||
// IAstToScriptBlockConverter is public, so we might consider converting non-workflows, but the interface isn't really designed
|
||||
// for Intellisense, so we can't really expect good performance, so instead we'll just fall back on the actual
|
||||
// parameters we see in the ast.
|
||||
var scriptBlock = functionDefinitionAst.IsWorkflow
|
||||
? CreateFakeScriptBlockForWorkflow(functionDefinitionAst)
|
||||
: new ScriptBlock(functionDefinitionAst, functionDefinitionAst.IsFilter);
|
||||
commandProcessor = CommandDiscovery.CreateCommandProcessorForScript(scriptBlock, context, true, context.EngineSessionState);
|
||||
}
|
||||
|
||||
}
|
||||
return commandProcessor;
|
||||
}
|
||||
|
||||
|
@ -1525,7 +1523,7 @@ namespace System.Management.Automation.Language
|
|||
var paramBlockAst = functionDefinitionAst.Body.ParamBlock;
|
||||
if (paramBlockAst != null)
|
||||
{
|
||||
var outputTypeAttrs = paramBlockAst.Attributes.Where(attribute => typeof(OutputTypeAttribute).Equals(attribute.TypeName.GetReflectionAttributeType()));
|
||||
var outputTypeAttrs = paramBlockAst.Attributes.Where(attribute => typeof(OutputTypeAttribute) == attribute.TypeName.GetReflectionAttributeType());
|
||||
|
||||
foreach (AttributeAst attributeAst in outputTypeAttrs)
|
||||
{
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -457,12 +457,6 @@ namespace System.Management.Automation.Language
|
|||
Diagnostics.Assert(false, "This code is unreachable.");
|
||||
return AstVisitAction.Continue;
|
||||
}
|
||||
|
||||
internal override IEnumerable<PSTypeName> GetInferredType(CompletionContext context)
|
||||
{
|
||||
Diagnostics.Assert(false, "This code is unreachable.");
|
||||
return Ast.EmptyPSTypeNameArray;
|
||||
}
|
||||
}
|
||||
|
||||
internal static string GetUnaliasedVariableName(string varName)
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,34 +1,28 @@
|
|||
|
||||
/********************************************************************++
|
||||
/********************************************************************++
|
||||
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
--********************************************************************/
|
||||
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Management.Automation.Runspaces;
|
||||
|
||||
namespace System.Management.Automation
|
||||
{
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Collections.Generic;
|
||||
using System.Management.Automation.Runspaces;
|
||||
using System.Collections;
|
||||
|
||||
/// <summary>
|
||||
/// Auxiliary class to the execution of commands as needed by
|
||||
/// CommandCompletion
|
||||
/// </summary>
|
||||
internal class CompletionExecutionHelper
|
||||
internal class PowerShellExecutionHelper
|
||||
{
|
||||
#region Constructors
|
||||
|
||||
// Creates a new CompletionExecutionHelper with the PowerShell instance that will be used to execute the tab expansion commands
|
||||
// Creates a new PowerShellExecutionHelper with the PowerShell instance that will be used to execute the tab expansion commands
|
||||
// Used by the ISE
|
||||
internal CompletionExecutionHelper(PowerShell powershell)
|
||||
internal PowerShellExecutionHelper(PowerShell powershell)
|
||||
{
|
||||
if (powershell == null)
|
||||
{
|
||||
throw PSTraceSource.NewArgumentNullException("powershell");
|
||||
}
|
||||
|
||||
this.CurrentPowerShell = powershell;
|
||||
CurrentPowerShell = powershell;
|
||||
}
|
||||
|
||||
#endregion Constructors
|
||||
|
@ -44,16 +38,10 @@ namespace System.Management.Automation
|
|||
internal PowerShell CurrentPowerShell { get; set; }
|
||||
|
||||
// Returns true if this instance is currently executing a command
|
||||
internal bool IsRunning
|
||||
{
|
||||
get { return CurrentPowerShell.InvocationStateInfo.State == PSInvocationState.Running; }
|
||||
}
|
||||
internal bool IsRunning => CurrentPowerShell.InvocationStateInfo.State == PSInvocationState.Running;
|
||||
|
||||
// Returns true if the command executed by this instance was stopped
|
||||
internal bool IsStopped
|
||||
{
|
||||
get { return CurrentPowerShell.InvocationStateInfo.State == PSInvocationState.Stopped; }
|
||||
}
|
||||
internal bool IsStopped => CurrentPowerShell.InvocationStateInfo.State == PSInvocationState.Stopped;
|
||||
|
||||
#endregion Fields and Properties
|
||||
|
||||
|
@ -62,7 +50,7 @@ namespace System.Management.Automation
|
|||
internal Collection<PSObject> ExecuteCommand(string command)
|
||||
{
|
||||
Exception unused;
|
||||
return this.ExecuteCommand(command, true, out unused, null);
|
||||
return ExecuteCommand(command, true, out unused, null);
|
||||
}
|
||||
|
||||
internal bool ExecuteCommandAndGetResultAsBool()
|
||||
|
@ -106,7 +94,7 @@ namespace System.Management.Automation
|
|||
exceptionThrown = null;
|
||||
|
||||
// This flag indicates a previous call to this method had its pipeline cancelled
|
||||
if (this.CancelTabCompletion)
|
||||
if (CancelTabCompletion)
|
||||
{
|
||||
return new Collection<PSObject>();
|
||||
}
|
||||
|
@ -130,10 +118,10 @@ namespace System.Management.Automation
|
|||
|
||||
// If this pipeline has been stopped lets set a flag to cancel all future tab completion calls
|
||||
// untill the next completion
|
||||
if (this.IsStopped)
|
||||
if (IsStopped)
|
||||
{
|
||||
results = new Collection<PSObject>();
|
||||
this.CancelTabCompletion = true;
|
||||
CancelTabCompletion = true;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
|
@ -149,7 +137,7 @@ namespace System.Management.Automation
|
|||
exceptionThrown = null;
|
||||
|
||||
// This flag indicates a previous call to this method had its pipeline cancelled
|
||||
if (this.CancelTabCompletion)
|
||||
if (CancelTabCompletion)
|
||||
{
|
||||
return new Collection<PSObject>();
|
||||
}
|
||||
|
@ -161,10 +149,10 @@ namespace System.Management.Automation
|
|||
|
||||
// If this pipeline has been stopped lets set a flag to cancel all future tab completion calls
|
||||
// untill the next completion
|
||||
if (this.IsStopped)
|
||||
if (IsStopped)
|
||||
{
|
||||
results = new Collection<PSObject>();
|
||||
this.CancelTabCompletion = true;
|
||||
CancelTabCompletion = true;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
|
@ -236,4 +224,39 @@ namespace System.Management.Automation
|
|||
|
||||
#endregion Helpers
|
||||
}
|
||||
}
|
||||
|
||||
internal static class PowerShellExtensionHelpers
|
||||
{
|
||||
internal static PowerShell AddCommandWithPreferenceSetting(this PowerShellExecutionHelper helper,
|
||||
string command, Type type = null)
|
||||
{
|
||||
return helper.CurrentPowerShell.AddCommandWithPreferenceSetting(command, type);
|
||||
}
|
||||
|
||||
internal static PowerShell AddCommandWithPreferenceSetting(this PowerShell powershell, string command, Type type = null)
|
||||
{
|
||||
Diagnostics.Assert(powershell != null, "the passed-in powershell cannot be null");
|
||||
Diagnostics.Assert(!String.IsNullOrWhiteSpace(command),
|
||||
"the passed-in command name should not be null or whitespaces");
|
||||
|
||||
if (type != null)
|
||||
{
|
||||
var cmdletInfo = new CmdletInfo(command, type);
|
||||
|
||||
powershell.AddCommand(cmdletInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
powershell.AddCommand(command);
|
||||
}
|
||||
powershell
|
||||
.AddParameter("ErrorAction", ActionPreference.Ignore)
|
||||
.AddParameter("WarningAction", ActionPreference.Ignore)
|
||||
.AddParameter("InformationAction", ActionPreference.Ignore)
|
||||
.AddParameter("Verbose", false)
|
||||
.AddParameter("Debug", false);
|
||||
|
||||
return powershell;
|
||||
}
|
||||
}
|
||||
}
|
859
test/powershell/engine/Api/TypeInference.Tests.ps1
Normal file
859
test/powershell/engine/Api/TypeInference.Tests.ps1
Normal file
|
@ -0,0 +1,859 @@
|
|||
using namespace System.Management.Automation
|
||||
using namespace System.Collections.Generic
|
||||
|
||||
Describe "Type inference Tests" -tags "CI" {
|
||||
BeforeAll {
|
||||
$ati = [Cmdlet].Assembly.GetType("System.Management.Automation.AstTypeInference")
|
||||
$inferType = $ati.GetMethods().Where{$_.Name -ceq "InferTypeOf"}
|
||||
$m1 = 'System.Collections.Generic.IList`1[System.Management.Automation.PSTypeName] InferTypeOf(System.Management.Automation.Language.Ast)'
|
||||
$m2 = 'System.Collections.Generic.IList`1[System.Management.Automation.PSTypeName] InferTypeOf(System.Management.Automation.Language.Ast, System.Management.Automation.TypeInferenceRuntimePermissions)'
|
||||
$m3 = 'System.Collections.Generic.IList`1[System.Management.Automation.PSTypeName] InferTypeOf(System.Management.Automation.Language.Ast, System.Management.Automation.PowerShell)'
|
||||
$m4 = 'System.Collections.Generic.IList`1[System.Management.Automation.PSTypeName] InferTypeOf(System.Management.Automation.Language.Ast, System.Management.Automation.PowerShell, System.Management.Automation.TypeInferenceRuntimePermissions)'
|
||||
|
||||
$inferTypeOf1 = $inferType.Where{$m1 -eq $_}[0]
|
||||
$inferTypeOf2 = $inferType.Where{$m2 -eq $_}[0]
|
||||
$inferTypeOf3 = $inferType.Where{$m3 -eq $_}[0]
|
||||
$inferTypeOf4 = $inferType.Where{$m4 -eq $_}[0]
|
||||
|
||||
class AstTypeInference {
|
||||
static [IList[PSTypeName]] InferTypeOf([Language.Ast] $ast) {
|
||||
return $script:inferTypeOf1.Invoke($null, $ast)
|
||||
}
|
||||
|
||||
static [IList[PSTypeName]] InferTypeOf([Language.Ast] $ast, [System.Management.Automation.TypeInferenceRuntimePermissions] $runtimePermissions) {
|
||||
return $script:inferTypeOf2.Invoke($null, @($ast, $runtimePermissions))
|
||||
}
|
||||
|
||||
static [IList[PSTypeName]] InferTypeOf([Language.Ast] $ast, [System.Management.Automation.PowerShell] $powershell) {
|
||||
return $script:inferTypeOf3.Invoke($null, @($ast, $powershell))
|
||||
}
|
||||
|
||||
static [IList[PSTypeName]] InferTypeOf([Language.Ast] $ast, [PowerShell] $powerShell, [System.Management.Automation.TypeInferenceRuntimePermissions] $runtimePermissions) {
|
||||
return $script:inferTypeOf4.Invoke($null, @($ast, $powerShell, $runtimePermissions))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
It "Infers type from integer" {
|
||||
$res = [AstTypeInference]::InferTypeOf( { 1 }.Ast)
|
||||
$res.Count | Should Be 1
|
||||
$res.Name | Should be 'System.Int32'
|
||||
}
|
||||
|
||||
|
||||
It "Infers type from string literal" {
|
||||
$res = [AstTypeInference]::InferTypeOf( { "Text" }.Ast)
|
||||
$res.Count | Should Be 1
|
||||
$res.Name | Should be 'System.String'
|
||||
}
|
||||
|
||||
It "Infers type from type expression" {
|
||||
$res = [AstTypeInference]::InferTypeOf( { [int] }.Ast)
|
||||
$res.Count | Should Be 1
|
||||
$res.Name | Should be 'System.Type'
|
||||
}
|
||||
|
||||
It "Infers type from hashtable" {
|
||||
$res = [AstTypeInference]::InferTypeOf( { @{} }.Ast)
|
||||
$res.Count | Should Be 1
|
||||
$res.Name | Should be 'System.Collections.Hashtable'
|
||||
}
|
||||
|
||||
It "Infers type from array expression" {
|
||||
$res = [AstTypeInference]::InferTypeOf( { @() }.Ast)
|
||||
$res.Count | Should Be 1
|
||||
$res.Name | Should be 'System.object[]'
|
||||
}
|
||||
|
||||
It "Infers type from Array literal" {
|
||||
$res = [AstTypeInference]::InferTypeOf( { , 1 }.Ast)
|
||||
$res.Count | Should Be 1
|
||||
$res.Name | Should be 'System.object[]'
|
||||
}
|
||||
|
||||
It "Infers type from array IndexExpresssion" {
|
||||
$res = [AstTypeInference]::InferTypeOf( { (1, 2, 3)[0] }.Ast)
|
||||
$res.Count | Should Be 1
|
||||
$res.Name | Should be 'System.object'
|
||||
}
|
||||
|
||||
It "Infers type from generic container IndexExpression" {
|
||||
$res = [AstTypeInference]::InferTypeOf( {
|
||||
[System.Collections.Generic.List[int]]::new()[0]
|
||||
}.Ast)
|
||||
$res.Count | Should Be 1
|
||||
$res.Name | Should be 'System.Int32'
|
||||
}
|
||||
|
||||
It 'Infers type of Index expression on Dictionary' {
|
||||
$ast = {
|
||||
[System.Collections.Generic.Dictionary[int, DateTime]]::new()[1]
|
||||
}.ast.EndBlock.Statements[0].PipelineElements[0].Expression
|
||||
$res = [AstTypeInference]::InferTypeOf( $ast )
|
||||
|
||||
$res.Count | Should be 1
|
||||
$res.Name | Should be System.DateTime
|
||||
}
|
||||
|
||||
It "Infers type from ScriptblockExpresssion" {
|
||||
$res = [AstTypeInference]::InferTypeOf( { {} }.Ast)
|
||||
$res.Count | Should Be 1
|
||||
$res.Name | Should be 'System.Management.Automation.Scriptblock'
|
||||
}
|
||||
|
||||
It "Infers type from paren expression" {
|
||||
$res = [AstTypeInference]::InferTypeOf( { (1) }.Ast)
|
||||
$res.Count | Should Be 1
|
||||
$res.Name | Should be 'System.Int32'
|
||||
}
|
||||
|
||||
It "Infers type from expandable string expression" {
|
||||
$res = [AstTypeInference]::InferTypeOf( { "$(1)" }.Ast)
|
||||
$res.Count | Should Be 1
|
||||
$res.Name | Should be 'System.String'
|
||||
}
|
||||
|
||||
It "Infers type from cast expression" {
|
||||
$res = [AstTypeInference]::InferTypeOf( { [int] '1'}.Ast)
|
||||
$res.Count | Should Be 1
|
||||
$res.Name | Should be 'System.Int32'
|
||||
}
|
||||
|
||||
It "Infers type from using namespace" {
|
||||
$errors = $null
|
||||
$tokens = $null
|
||||
$ast = [Language.Parser]::ParseInput("using namespace System", [ref] $tokens, [ref] $errors)
|
||||
$res = [AstTypeInference]::InferTypeOf( $ast.Find( {param($a) $a -is [System.Management.Automation.Language.UsingStatementAst] }, $true))
|
||||
$res.Count | Should Be 0
|
||||
}
|
||||
|
||||
It "Infers type from unary expression" {
|
||||
$res = [AstTypeInference]::InferTypeOf( { !$true }.Ast)
|
||||
$res.Count | Should Be 1
|
||||
$res.Name | Should be 'System.Boolean'
|
||||
}
|
||||
|
||||
It "Infers type from param block" {
|
||||
$res = [AstTypeInference]::InferTypeOf( { param() }.Ast)
|
||||
$res.Count | Should Be 0
|
||||
}
|
||||
|
||||
|
||||
It "Infers type from using statement" {
|
||||
$res = [AstTypeInference]::InferTypeOf( { $pid = 1; $using:pid }.Ast.EndBlock.Statements[1].PipelineElements[0].Expression)
|
||||
$res.Count | Should Be 1
|
||||
$res.Name | Should Be System.Int32
|
||||
}
|
||||
|
||||
It "Infers type from param block" {
|
||||
$res = [AstTypeInference]::InferTypeOf( { param([int] $i)}.Ast.ParamBlock)
|
||||
$res.Count | Should Be 0
|
||||
}
|
||||
|
||||
It "Infers type no type from Attribute" {
|
||||
$res = [AstTypeInference]::InferTypeOf( {
|
||||
[OutputType([int])]
|
||||
param(
|
||||
)}.Ast.ParamBlock.Attributes[0])
|
||||
$res.Count | Should Be 0
|
||||
}
|
||||
|
||||
It "Infers type no type from named Attribute argument" {
|
||||
$res = [AstTypeInference]::InferTypeOf( {
|
||||
[OutputType(Type = [int])]
|
||||
param(
|
||||
)}.Ast.ParamBlock.Attributes[0].NamedArguments[0])
|
||||
$res.Count | Should Be 0
|
||||
}
|
||||
|
||||
It "Infers type parameter types" {
|
||||
$res = [AstTypeInference]::InferTypeOf( {
|
||||
param([int] $i, [string] $s)
|
||||
}.Ast.ParamBlock.Parameters[0])
|
||||
$res.Count | Should Be 1
|
||||
$res.Name | Should be System.Int32
|
||||
}
|
||||
|
||||
It "Infers type parameter from PSTypeNameAttribute type" -Skip:(!$IsWindows) {
|
||||
$res = [AstTypeInference]::InferTypeOf( {
|
||||
param([int] $i, [PSTypeName('System.Management.ManagementObject#root\cimv2\Win32_Process')] $s)
|
||||
}.Ast.ParamBlock.Parameters[1])
|
||||
$res.Count | Should Be 1
|
||||
$res.Name | Should be 'System.Management.ManagementObject#root\cimv2\Win32_Process'
|
||||
}
|
||||
|
||||
It "Infers type from DATA statement" {
|
||||
$res = [AstTypeInference]::InferTypeOf( {
|
||||
DATA {
|
||||
"text"
|
||||
}
|
||||
}.Ast.EndBlock)
|
||||
$res.Count | Should Be 1
|
||||
$res.Name | Should be 'System.String'
|
||||
}
|
||||
|
||||
|
||||
It "Infers type from named block" {
|
||||
$res = [AstTypeInference]::InferTypeOf( { begin {1}}.Ast.BeginBlock)
|
||||
$res.Count | Should Be 1
|
||||
$res.Name | Should Be System.Int32
|
||||
}
|
||||
|
||||
It "Infers type from function definition" {
|
||||
$res = [AstTypeInference]::InferTypeOf( {
|
||||
function foo {
|
||||
return 1
|
||||
}
|
||||
}.Ast.EndBlock)
|
||||
$res.Count | Should Be 0
|
||||
}
|
||||
|
||||
It "Infers type from convert expression" {
|
||||
$errors = $null
|
||||
$tokens = $null
|
||||
$ast = [Language.Parser]::ParseInput('[int] "4"', [ref] $tokens, [ref] $errors)
|
||||
$res = [AstTypeInference]::InferTypeOf( $ast.EndBlock.Statements[0])
|
||||
$res.Count | Should Be 1
|
||||
$res.Name | Should Be 'System.Int32'
|
||||
}
|
||||
|
||||
It "Infers type from type constraint" {
|
||||
$errors = $null
|
||||
$tokens = $null
|
||||
$ast = [Language.Parser]::ParseInput('[int] $i', [ref] $tokens, [ref] $errors)
|
||||
$res = [AstTypeInference]::InferTypeOf( $ast.EndBlock.Statements[0].PipelineElements[0].Expression.Attribute)
|
||||
$res.Count | Should Be 0
|
||||
}
|
||||
|
||||
It "Infers type from instance member property" {
|
||||
$res = [AstTypeInference]::InferTypeOf( { 'Text'.Length }.Ast)
|
||||
$res.Count | Should Be 1
|
||||
$res.Name | Should be 'System.Int32'
|
||||
}
|
||||
|
||||
It "Infers type from static member property" {
|
||||
$res = [AstTypeInference]::InferTypeOf( { [DateTime]::Now }.Ast)
|
||||
$res.Count | Should Be 1
|
||||
$res.Name | Should be 'System.DateTime'
|
||||
}
|
||||
|
||||
It "Infers type from instance member method" {
|
||||
$res = [AstTypeInference]::InferTypeOf( { [int[]].GetElementType() }.Ast)
|
||||
$res.Count | Should Be 1
|
||||
$res.Name | Should be 'System.Type'
|
||||
}
|
||||
|
||||
It "Infers type from integer * stringliteral" {
|
||||
$res = [AstTypeInference]::InferTypeOf( { 5 * "5" }.Ast)
|
||||
$res.Count | Should Be 1
|
||||
$res.Name | Should be 'System.Int32'
|
||||
}
|
||||
|
||||
It "Infers type from string literal" {
|
||||
$res = [AstTypeInference]::InferTypeOf( { "Text" }.Ast)
|
||||
$res.Count | Should Be 1
|
||||
$res.Name | Should be 'System.String'
|
||||
}
|
||||
|
||||
It "Infers type from stringliteral * integer" {
|
||||
$res = [AstTypeInference]::InferTypeOf( { "5" * 2 }.Ast)
|
||||
$res.Count | Should Be 1
|
||||
$res.Name | Should be 'System.String'
|
||||
}
|
||||
|
||||
It "Infers type from where-object of integer" {
|
||||
$res = [AstTypeInference]::InferTypeOf( { [int[]] $i = 1..20; $i | Where-Object {$_ -gt 10} }.Ast)
|
||||
foreach ($r in $res) {
|
||||
$r.Name -in 'System.Int32', 'System.Int32[]' | Should be $true
|
||||
}
|
||||
}
|
||||
|
||||
It "Infers type from foreach-object of integer" {
|
||||
$res = [AstTypeInference]::InferTypeOf( { [int[]] $i = 1..20; $i | ForEach-Object {$_ * 10} }.Ast)
|
||||
$res.Count | Should Be 2
|
||||
foreach ($r in $res) {
|
||||
$r.Name -in 'System.Int32', 'System.Int32[]' | Should be $true
|
||||
}
|
||||
}
|
||||
|
||||
It "Infers type from generic new" {
|
||||
$res = [AstTypeInference]::InferTypeOf( { [System.Collections.Generic.List[int]]::new() }.Ast)
|
||||
$res.Count | Should Be 1
|
||||
$res.Name | Should Match 'System.Collections.Generic.List`1\[\[System.Int32.*'
|
||||
|
||||
}
|
||||
|
||||
It "Infers type from cim command" -Skip:(!$IsWindows) {
|
||||
$res = [AstTypeInference]::InferTypeOf( { Get-CimInstance -Namespace root/CIMV2 -ClassName Win32_Bios }.Ast)
|
||||
$res.Count | Should Be 2
|
||||
|
||||
foreach ($r in $res) {
|
||||
$r.Name -in 'Microsoft.Management.Infrastructure.CimInstance#root/CIMV2/Win32_Bios',
|
||||
'Microsoft.Management.Infrastructure.CimInstance' | Should be $true
|
||||
}
|
||||
}
|
||||
|
||||
It "Infers type from foreach-object with begin/end" {
|
||||
$res = [AstTypeInference]::InferTypeOf( { [int[]] $i = 1..20; $i | ForEach-Object -Begin {"Hi"} {$_ * 10} -End {[int]} }.Ast)
|
||||
$res.Count | Should Be 4
|
||||
foreach ($r in $res) {
|
||||
$r.Name -in 'System.Int32', 'System.Int32[]', 'System.String', 'System.Type' | Should be $true
|
||||
}
|
||||
}
|
||||
|
||||
It "Infers type from OutputTypeAttribute" {
|
||||
$res = [AstTypeInference]::InferTypeOf( { Get-Process -Id 2345 }.Ast)
|
||||
$gpsOutput = [Microsoft.PowerShell.Commands.GetProcessCommand].GetCustomAttributes([System.Management.Automation.OutputTypeAttribute], $false).Type
|
||||
$names = $gpsOutput.Name
|
||||
foreach ($r in $res) {
|
||||
$r.Name -in $names | Should Be $true
|
||||
}
|
||||
}
|
||||
|
||||
It "Infers type from variable with AllowSafeEval" {
|
||||
function Hide-GetProcess { Get-Process }
|
||||
$p = Hide-GetProcess
|
||||
$res = [AstTypeInference]::InferTypeOf( { $p }.Ast, [TypeInferenceRuntimePermissions]::AllowSafeEval)
|
||||
$res.Name | Should Be 'System.Diagnostics.Process'
|
||||
}
|
||||
|
||||
It "Infers type from variable with type in scope" {
|
||||
|
||||
$res = [AstTypeInference]::InferTypeOf( {
|
||||
$p = 1
|
||||
$p
|
||||
}.Ast)
|
||||
$res.Name | Should Be 'System.Int32'
|
||||
}
|
||||
|
||||
It "Infers type from block statement" {
|
||||
$errors = $null
|
||||
$tokens = $null
|
||||
$ast = [Language.Parser]::ParseInput("parallel {1}", [ref] $tokens, [ref] $errors)
|
||||
|
||||
$res = [AstTypeInference]::InferTypeOf( $ast.EndBlock.Statements[0])
|
||||
$res.Name | Should Be 'System.Int32'
|
||||
}
|
||||
|
||||
It 'Infers type from attributed expession' {
|
||||
$res = [AstTypeInference]::InferTypeOf( {
|
||||
[ValidateRange(1, 2)]
|
||||
[int]$i = 1
|
||||
}.Ast)
|
||||
|
||||
$res.Count | Should be 1
|
||||
$res.Name | Should be System.Int32
|
||||
}
|
||||
|
||||
It 'Infers type from if statement' {
|
||||
$res = [AstTypeInference]::InferTypeOf( {
|
||||
if ($true) { return 1}
|
||||
else { return 'Text'}
|
||||
}.Ast)
|
||||
|
||||
$res.Count | Should be 2
|
||||
foreach ($r in $res) {
|
||||
$r.Name -in 'System.Int32', 'System.String' | Should be $true
|
||||
}
|
||||
}
|
||||
|
||||
It 'Infers type from switch statement' {
|
||||
$res = [AstTypeInference]::InferTypeOf( {
|
||||
switch (1, 2, 3) {
|
||||
(1) { return 'Hello'}
|
||||
(2) {return [int]}
|
||||
default {return 1}
|
||||
}
|
||||
}.Ast)
|
||||
|
||||
$res.Count | Should be 3
|
||||
foreach ($r in $res) {
|
||||
$r.Name -in 'System.Type', 'System.Int32', 'System.String' | Should be $true
|
||||
}
|
||||
}
|
||||
|
||||
It 'Infers type from Foreach statement' {
|
||||
$res = [AstTypeInference]::InferTypeOf( {
|
||||
foreach ($i in 1, 2, 3) {
|
||||
if ($i -eq 1) { return 'Hello'}
|
||||
if ($i -eq 2) {return [int]}
|
||||
return 1
|
||||
}
|
||||
}.Ast)
|
||||
|
||||
$res.Count | Should be 3
|
||||
foreach ($r in $res) {
|
||||
$r.Name -in 'System.Type', 'System.Int32', 'System.String' | Should be $true
|
||||
}
|
||||
}
|
||||
|
||||
It 'Infers type from While statement' {
|
||||
$res = [AstTypeInference]::InferTypeOf( {
|
||||
while ($true) {
|
||||
if ($i -eq 1) { return 'Hello'}
|
||||
if ($i -eq 2) {return [int]}
|
||||
return 1
|
||||
}
|
||||
}.Ast)
|
||||
|
||||
$res.Count | Should be 3
|
||||
foreach ($r in $res) {
|
||||
$r.Name -in 'System.Type', 'System.Int32', 'System.String' | Should be $true
|
||||
}
|
||||
}
|
||||
|
||||
It 'Infers type from For statement' {
|
||||
$res = [AstTypeInference]::InferTypeOf( {
|
||||
for ($i = 0; $i -lt 10; $i++) {
|
||||
if ($i -eq 1) { return 'Hello'}
|
||||
if ($i -eq 2) {return [int]}
|
||||
return 1
|
||||
}
|
||||
}.Ast)
|
||||
|
||||
$res.Count | Should be 3
|
||||
foreach ($r in $res) {
|
||||
$r.Name -in 'System.Type', 'System.Int32', 'System.String' | Should be $true
|
||||
}
|
||||
}
|
||||
|
||||
It 'Infers type from Do-While statement' {
|
||||
$res = [AstTypeInference]::InferTypeOf( {
|
||||
do {
|
||||
if ($i -eq 1) { return 'Hello'}
|
||||
if ($i -eq 2) {return [int]}
|
||||
return 1
|
||||
}while ($true)
|
||||
}.Ast)
|
||||
|
||||
$res.Count | Should be 3
|
||||
foreach ($r in $res) {
|
||||
$r.Name -in 'System.Type', 'System.Int32', 'System.String' | Should be $true
|
||||
}
|
||||
}
|
||||
|
||||
It 'Infers type from Do-Until statement' {
|
||||
$res = [AstTypeInference]::InferTypeOf( {
|
||||
do {
|
||||
if ($i -eq 1) { return 'Hello'}
|
||||
if ($i -eq 2) {return [int]}
|
||||
return 1
|
||||
} until ($true)
|
||||
}.Ast)
|
||||
|
||||
$res.Count | Should be 3
|
||||
foreach ($r in $res) {
|
||||
$r.Name -in 'System.Type', 'System.Int32', 'System.String' | Should be $true
|
||||
}
|
||||
}
|
||||
|
||||
It 'Infers type from full scriptblock' {
|
||||
$res = [AstTypeInference]::InferTypeOf( {
|
||||
begin {1}
|
||||
process {"text"}
|
||||
end {[int]}
|
||||
}.Ast)
|
||||
|
||||
$res.Count | Should be 3
|
||||
foreach ($r in $res) {
|
||||
$r.Name -in 'System.Type', 'System.Int32', 'System.String' | Should be $true
|
||||
}
|
||||
}
|
||||
|
||||
It 'Infers type from sub expression' {
|
||||
$res = [AstTypeInference]::InferTypeOf( {
|
||||
$(1)
|
||||
}.Ast)
|
||||
|
||||
$res.Count | Should be 1
|
||||
$res.Name | Should be System.Int32
|
||||
}
|
||||
|
||||
It 'Infers type from Throw statement' {
|
||||
$res = [AstTypeInference]::InferTypeOf( {
|
||||
throw 'Foo'
|
||||
}.Ast)
|
||||
|
||||
$res.Count | Should be 0
|
||||
}
|
||||
|
||||
It 'Infers type from Return statement' {
|
||||
$res = [AstTypeInference]::InferTypeOf( {
|
||||
return 1
|
||||
}.Ast)
|
||||
|
||||
$res.Count | Should be 1
|
||||
$res.Name | Should be 'System.Int32'
|
||||
}
|
||||
|
||||
It 'Infers type from New-Object statement' {
|
||||
$res = [AstTypeInference]::InferTypeOf( {
|
||||
New-Object -TypeName 'System.Diagnostics.Stopwatch'
|
||||
}.Ast)
|
||||
|
||||
$res.Count | Should be 1
|
||||
$res.Name | Should be 'System.Diagnostics.Stopwatch'
|
||||
}
|
||||
|
||||
It 'Infers type from Continue statement' {
|
||||
$res = [AstTypeInference]::InferTypeOf( {
|
||||
continue
|
||||
}.Ast)
|
||||
|
||||
$res.Count | Should be 0
|
||||
}
|
||||
|
||||
It 'Infers type from Break statement' {
|
||||
$res = [AstTypeInference]::InferTypeOf( {
|
||||
break
|
||||
}.Ast)
|
||||
|
||||
$res.Count | Should be 0
|
||||
}
|
||||
|
||||
It 'Infers type from Merging redirection' {
|
||||
$errors = $null
|
||||
$tokens = $null
|
||||
$ast = [Language.Parser]::ParseInput("p4 resolve ... 2>&1", [ref] $tokens, [ref] $errors)
|
||||
$res = [AstTypeInference]::InferTypeOf( $ast.EndBlock.Statements[0].PipelineElements[0].Redirections[0] )
|
||||
$res.Count | Should be 0
|
||||
}
|
||||
|
||||
It 'Infers type from File redirection' {
|
||||
$errors = $null
|
||||
$tokens = $null
|
||||
$ast = [Language.Parser]::ParseInput("p4 resolve ... > foo.txt", [ref] $tokens, [ref] $errors)
|
||||
$res = [AstTypeInference]::InferTypeOf( $ast.EndBlock.Statements[0].PipelineElements[0].Redirections[0] )
|
||||
$res.Count | Should be 0
|
||||
}
|
||||
|
||||
|
||||
It 'Infers type of alias property' {
|
||||
class X {
|
||||
[int] $Length
|
||||
}
|
||||
Update-TypeData -Typename X -MemberType AliasProperty -MemberName AliasLength -Value Length -Force
|
||||
$res = [AstTypeInference]::InferTypeOf( {
|
||||
[x]::new().AliasLength
|
||||
}.Ast)
|
||||
|
||||
$res.Count | Should be 1
|
||||
$res.Name | Should be System.Int32
|
||||
}
|
||||
|
||||
|
||||
It 'Infers type of code property' {
|
||||
class X {
|
||||
static [int] CodeProp([psobject] $o) { return 1 }
|
||||
}
|
||||
|
||||
class Y {}
|
||||
Update-TypeData -TypeName Y -MemberName CodeProp -MemberType CodeProperty -Value ([X].GetMethod("CodeProp")) -Force
|
||||
$res = [AstTypeInference]::InferTypeOf( {
|
||||
[Y]::new().CodeProp
|
||||
}.Ast)
|
||||
|
||||
$res.Count | Should be 1
|
||||
$res.Name | Should be System.Int32
|
||||
}
|
||||
|
||||
It 'Infers type of script property' {
|
||||
class Y {}
|
||||
Update-TypeData -TypeName Y -MemberName ScriptProp -MemberType ScriptProperty -Value {1} -Force
|
||||
$res = [AstTypeInference]::InferTypeOf( {
|
||||
[Y]::new().ScriptProp
|
||||
}.Ast)
|
||||
|
||||
$res.Count | Should be 0
|
||||
}
|
||||
|
||||
It 'Infers type of script property with outputtype' {
|
||||
class Y {}
|
||||
Update-TypeData -TypeName Y -MemberName ScriptProp -MemberType ScriptProperty -Value {[OutputType([int])]param()1} -Force
|
||||
$res = [AstTypeInference]::InferTypeOf( {
|
||||
[Y]::new().ScriptProp
|
||||
}.Ast)
|
||||
|
||||
$res.Count | Should be 1
|
||||
$res.Name | Should be System.Int32
|
||||
}
|
||||
|
||||
It 'Infers type of script method with outputtype' {
|
||||
class Y {}
|
||||
Update-TypeData -TypeName Y -MemberName MyScriptMethod -MemberType ScriptMethod -Value {[OutputType([int])]param()1} -Force
|
||||
$res = [AstTypeInference]::InferTypeOf( {
|
||||
[Y]::new().MyScriptMethod
|
||||
}.Ast)
|
||||
|
||||
$res.Count | Should be 1
|
||||
$res.Name | Should be System.Int32
|
||||
}
|
||||
|
||||
|
||||
It 'Infers type of note property' {
|
||||
|
||||
$res = [AstTypeInference]::InferTypeOf( {
|
||||
[pscustomobject] @{
|
||||
A = ''
|
||||
}.A
|
||||
}.Ast)
|
||||
|
||||
$res.Count | Should be 1
|
||||
$res.Name | Should be 'System.Management.Automation.PSObject'
|
||||
}
|
||||
|
||||
It 'Infers type of try catch finally' {
|
||||
|
||||
$res = [AstTypeInference]::InferTypeOf( {
|
||||
try {
|
||||
1
|
||||
}
|
||||
catch [exception] {
|
||||
"Text"
|
||||
}
|
||||
finally {
|
||||
[int]
|
||||
}
|
||||
}.Ast)
|
||||
|
||||
$res.Count | Should be 3
|
||||
foreach ($r in $res) {
|
||||
$r.Name -in 'System.Int32', 'System.String', 'System.Type' | Should be $true
|
||||
}
|
||||
}
|
||||
|
||||
It "Infers type from trap statement" {
|
||||
$res = [AstTypeInference]::InferTypeOf( {
|
||||
trap {
|
||||
"text"
|
||||
}
|
||||
}.Ast.EndBlock.Traps[0])
|
||||
$res.Count | Should Be 1
|
||||
$res.Name | Should be 'System.String'
|
||||
}
|
||||
|
||||
It "Infers type from exit statement" {
|
||||
$res = [AstTypeInference]::InferTypeOf( {
|
||||
exit
|
||||
}.Ast.EndBlock)
|
||||
$res.Count | Should Be 0
|
||||
}
|
||||
|
||||
It 'Infers type of Where/Sort/Foreach pipeline' {
|
||||
$res = [AstTypeInference]::InferTypeOf( {
|
||||
[int[]](1..10) | Sort-Object -Descending | Where-Object {$_ -gt 3} | ForEach-Object {$_.ToString()}
|
||||
}.Ast)
|
||||
|
||||
$res.Name | Should be System.String
|
||||
}
|
||||
|
||||
It 'Infers type of Method accessed as Property' {
|
||||
$res = [AstTypeInference]::InferTypeOf( {
|
||||
''.ToString
|
||||
}.Ast)
|
||||
|
||||
$res.Count | Should be 1
|
||||
$res.Name | Should be System.Management.Automation.PSMethod
|
||||
}
|
||||
|
||||
It 'Infers int from List[int] with foreach' {
|
||||
$res = [AstTypeInference]::InferTypeOf( {
|
||||
$l = [System.Collections.Generic.List[string]]::new()
|
||||
$l | ForEach-Object {$_}
|
||||
}.Ast)
|
||||
|
||||
$res.Count | Should be 1
|
||||
$res.Name | Should be System.String
|
||||
}
|
||||
|
||||
It 'Infers class type' {
|
||||
$res = [AstTypeInference]::InferTypeOf( {
|
||||
class X {
|
||||
[int] $I
|
||||
[bool] Method() {
|
||||
return $true
|
||||
}
|
||||
}
|
||||
}.Ast)
|
||||
|
||||
$res.Count | Should be 0
|
||||
}
|
||||
|
||||
Context "TestDrivePath" {
|
||||
BeforeAll {
|
||||
$errors = $null
|
||||
$tokens = $null
|
||||
$p = Resolve-path TestDrive:/
|
||||
}
|
||||
It 'Infers type of command parameter' {
|
||||
$ast = [Language.Parser]::ParseInput("Get-ChildItem -Path $p/foo.txt", [ref] $tokens, [ref] $errors)
|
||||
$cmdParam = $ast.EndBlock.Statements[0].Pipelineelements[0].CommandElements[1]
|
||||
$res = [AstTypeInference]::InferTypeOf( $cmdParam )
|
||||
|
||||
$res.Count | Should be 0
|
||||
}
|
||||
|
||||
It 'Infers type of command parameter - second form' {
|
||||
$ast = [Language.Parser]::ParseInput("Get-ChildItem -LiteralPath $p/foo.txt", [ref] $tokens, [ref] $errors)
|
||||
$cmdParam = $ast.EndBlock.Statements[0].Pipelineelements[0].CommandElements[1]
|
||||
$res = [AstTypeInference]::InferTypeOf( $cmdParam )
|
||||
$res.Count | Should be 0
|
||||
}
|
||||
|
||||
It 'Infers type of common commands with Path parameter' {
|
||||
$ast = [Language.Parser]::ParseInput("Get-ChildItem -Path:$p/foo.txt", [ref] $tokens, [ref] $errors)
|
||||
$cmdAst = $ast.EndBlock.Statements[0].Pipelineelements[0]
|
||||
$res = [AstTypeInference]::InferTypeOf( $cmdAst )
|
||||
|
||||
$res.Count | Should be 2
|
||||
foreach ($r in $res) {
|
||||
$r.Name -in 'System.IO.FileInfo', 'System.IO.DirectoryInfo' | Should be $true
|
||||
}
|
||||
}
|
||||
|
||||
It 'Infers type of common commands with LiteralPath parameter' {
|
||||
$ast = [Language.Parser]::ParseInput("Get-ChildItem -LiteralPath:$p/foo.txt", [ref] $tokens, [ref] $errors)
|
||||
$cmdAst = $ast.EndBlock.Statements[0].Pipelineelements[0]
|
||||
$res = [AstTypeInference]::InferTypeOf( $cmdAst )
|
||||
|
||||
$res.Count | Should be 2
|
||||
foreach ($r in $res) {
|
||||
$r.Name -in 'System.IO.FileInfo', 'System.IO.DirectoryInfo' | Should be $true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
It 'Infers type of variable $_ in hashtable in command parameter' {
|
||||
$variableAst = {1..10 | Format-table @{n = 'x'; ex = {$_}}}.ast.Find( {param($a) $a -is [System.Management.Automation.Language.VariableExpressionAst]}, $true)
|
||||
$res = [AstTypeInference]::InferTypeOf( $variableAst)
|
||||
|
||||
$res.Count | Should be 1
|
||||
$res.Name | Should be System.Int32
|
||||
}
|
||||
|
||||
It 'Infers type of variable $_ in hashtable from Array' {
|
||||
$variableAst = { [int[]]::new(10) | Format-table @{n = 'x'; ex = {$_}}}.ast.Find( {param($a) $a -is [System.Management.Automation.Language.VariableExpressionAst]}, $true)
|
||||
$res = [AstTypeInference]::InferTypeOf( $variableAst)
|
||||
|
||||
$res.Count | Should be 1
|
||||
$res.Name | Should be System.Int32
|
||||
}
|
||||
|
||||
It 'Infers type of variable $_ in hashtable from generic IEnumerable ' {
|
||||
$variableAst = { [System.Collections.Generic.List[int]]::new() | Format-table @{n = 'x'; ex = {$_}}}.ast.Find( {param($a) $a -is [System.Management.Automation.Language.VariableExpressionAst]}, $true)
|
||||
$res = [AstTypeInference]::InferTypeOf( $variableAst)
|
||||
|
||||
$res.Count | Should be 1
|
||||
$res.Name | Should be System.Int32
|
||||
}
|
||||
|
||||
It 'Infers type of variable $_ command parameter' {
|
||||
$variableAst = { 1..10 | Group-Object {$_.Length}}.ast.Find( {param($a) $a -is [System.Management.Automation.Language.VariableExpressionAst]}, $true)
|
||||
$res = [AstTypeInference]::InferTypeOf( $variableAst)
|
||||
|
||||
$res.Count | Should be 1
|
||||
$res.Name | Should be System.Int32
|
||||
}
|
||||
|
||||
It 'Infers type of function member' {
|
||||
$res = [AstTypeInference]::InferTypeOf( {
|
||||
class X {
|
||||
[DateTime] GetDate() { return [datetime]::Now }
|
||||
}
|
||||
}.Ast.Find( {param($ast) $ast -is [System.Management.Automation.Language.FunctionMemberAst]}, $true))
|
||||
|
||||
$res.Count | Should be 0
|
||||
}
|
||||
|
||||
It 'Infers type of MemberExpression on class property' {
|
||||
class X {
|
||||
[DateTime] $Date
|
||||
}
|
||||
$x = [X]::new()
|
||||
$res = [AstTypeInference]::InferTypeOf( {
|
||||
$x.Date
|
||||
}.Ast.Find( {param($ast) $ast -is [System.Management.Automation.Language.MemberExpressionAst] -and $ast.Member.Value -eq 'Date'}, $true))
|
||||
|
||||
$res.Count | Should be 1
|
||||
$res.Name | Should Be System.DateTime
|
||||
}
|
||||
|
||||
It 'Infers type of MemberExpression on class Method' {
|
||||
class X {
|
||||
[DateTime] GetDate() { return [DateTime]::Now }
|
||||
}
|
||||
$x = [X]::new()
|
||||
$res = [AstTypeInference]::InferTypeOf( {
|
||||
$x.GetDate()
|
||||
}.Ast.Find( {param($ast) $ast -is [System.Management.Automation.Language.MemberExpressionAst] -and $ast.Member.Value -eq 'GetDate'}, $true))
|
||||
|
||||
$res.Count | Should be 1
|
||||
$res.Name | Should Be System.DateTime
|
||||
}
|
||||
|
||||
|
||||
It 'Infers type of note property with safe eval' -Skip {
|
||||
$res = [AstTypeInference]::InferTypeOf( {
|
||||
[pscustomobject] @{
|
||||
A = ''
|
||||
}.A
|
||||
}.Ast)
|
||||
|
||||
$res.Count | Should be 1
|
||||
$res.Name | Should be 'System.String'
|
||||
}
|
||||
|
||||
It 'Infers type of invoke operator scriptblock' -Skip {
|
||||
$res = [AstTypeInference]::InferTypeOf( {
|
||||
& {1}
|
||||
}.Ast)
|
||||
|
||||
$res.Count | Should be 1
|
||||
$res.Name | Should be System.Int32
|
||||
}
|
||||
|
||||
|
||||
|
||||
It 'Infers type of script property with safe eval' -Skip {
|
||||
class Y {}
|
||||
Update-TypeData -TypeName Y -MemberName SafeEvalScriptProp -MemberType ScriptProperty -Value {1} -Force
|
||||
$res = [AstTypeInference]::InferTypeOf( {
|
||||
[Y]::new().SafeEvalScriptProp
|
||||
}.Ast, [TypeInferenceRuntimePermissions]::AllowSafeEval)
|
||||
|
||||
$res.Count | Should be 1
|
||||
$res.Name | Should be System.Int32
|
||||
}
|
||||
|
||||
It 'Infers type of base ctor' -Skip {
|
||||
$res = [AstTypeInference]::InferTypeOf( {
|
||||
class BaseType {
|
||||
[string] $s
|
||||
BaseType([string]$s) {$this.s = $s}
|
||||
}
|
||||
class X : BaseType {
|
||||
X() : base("foo") {}
|
||||
}
|
||||
}.Ast.Find( {param($ast) $ast -is [System.Management.Automation.Language.BaseCtorInvokeMemberExpressionAst]}, $true))
|
||||
|
||||
$res.Count | Should be BaseType
|
||||
}
|
||||
}
|
||||
|
||||
Describe "AstTypeInference tests" -Tags CI {
|
||||
It "Infers type from integer with passed in powershell instance" {
|
||||
$powerShell = [PowerShell]::Create([RunspaceMode]::CurrentRunspace)
|
||||
$res = [AstTypeInference]::InferTypeOf( { 1 }.Ast, $powerShell)
|
||||
$res.Count | Should Be 1
|
||||
$res.Name | Should be 'System.Int32'
|
||||
}
|
||||
|
||||
It "Infers type from integer with passed in powershell instance and typeinferencespermissions" {
|
||||
$powerShell = [PowerShell]::Create([RunspaceMode]::CurrentRunspace)
|
||||
$v = 1
|
||||
$res = [AstTypeInference]::InferTypeOf( { $v }.Ast, $powerShell, [TypeInferenceRuntimePermissions]::AllowSafeEval)
|
||||
$res.Name | Should be 'System.Int32'
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue