MegaBites-AI/Windows-powershell
0308
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System.Collections;5using System.Diagnostics;6using System.Linq;7using System.Linq.Expressions;8using System.Management.Automation.Internal;9using System.Reflection;10 11namespace System.Management.Automation.Language12{13 /*14 * The IsGetPowerShellSafeValueVisitor class in SafeValues.cs used this class as the basis for implementation.15 * There is a number of similarities between these two classes, and changes (fixes) in this code16 * may need to be reflected in that class and vice versa17 */18 internal class IsConstantValueVisitor : ICustomAstVisitor219 {20 public static bool IsConstant(Ast ast, out object constantValue, bool forAttribute = false, bool forRequires = false)21 {22 try23 {24 if ((bool)ast.Accept(new IsConstantValueVisitor { CheckingAttributeArgument = forAttribute, CheckingRequiresArgument = forRequires }))25 {26 Ast parent = ast.Parent;27 while (parent != null)28 {29 if (parent is DataStatementAst)30 {31 break;32 }33 34 parent = parent.Parent;35 }36 37 if (parent == null)38 {39 constantValue = ast.Accept(new ConstantValueVisitor { AttributeArgument = forAttribute, RequiresArgument = forRequires });40 return true;41 }42 }43 }44 catch (Exception)45 {46 // If we get an exception, ignore it and assume the expression isn't constant.47 // This can happen, e.g. if a cast is invalid:48 // [int]"zed"49 }50 51 constantValue = null;52 return false;53 }54 55 internal bool CheckingAttributeArgument { get; set; }56 57 internal bool CheckingClassAttributeArguments { get; set; }58 59 internal bool CheckingRequiresArgument { get; set; }60 61 public object VisitErrorStatement(ErrorStatementAst errorStatementAst) { return false; }62 63 public object VisitErrorExpression(ErrorExpressionAst errorExpressionAst) { return false; }64 65 public object VisitScriptBlock(ScriptBlockAst scriptBlockAst) { return false; }66 67 public object VisitParamBlock(ParamBlockAst paramBlockAst) { return false; }68 69 public object VisitNamedBlock(NamedBlockAst namedBlockAst) { return false; }70 71 public object VisitTypeConstraint(TypeConstraintAst typeConstraintAst) { return false; }72 73 public object VisitAttribute(AttributeAst attributeAst) { return false; }74 75 public object VisitNamedAttributeArgument(NamedAttributeArgumentAst namedAttributeArgumentAst) { return false; }76 77 public object VisitParameter(ParameterAst parameterAst) { return false; }78 79 public object VisitFunctionDefinition(FunctionDefinitionAst functionDefinitionAst) { return false; }80 81 public object VisitIfStatement(IfStatementAst ifStmtAst) { return false; }82 83 public object VisitTrap(TrapStatementAst trapStatementAst) { return false; }84 85 public object VisitSwitchStatement(SwitchStatementAst switchStatementAst) { return false; }86 87 public object VisitDataStatement(DataStatementAst dataStatementAst) { return false; }88 89 public object VisitForEachStatement(ForEachStatementAst forEachStatementAst) { return false; }90 91 public object VisitDoWhileStatement(DoWhileStatementAst doWhileStatementAst) { return false; }92 93 public object VisitForStatement(ForStatementAst forStatementAst) { return false; }94 95 public object VisitWhileStatement(WhileStatementAst whileStatementAst) { return false; }96 97 public object VisitCatchClause(CatchClauseAst catchClauseAst) { return false; }98 99 public object VisitTryStatement(TryStatementAst tryStatementAst) { return false; }100 101 public object VisitBreakStatement(BreakStatementAst breakStatementAst) { return false; }102 103 public object VisitContinueStatement(ContinueStatementAst continueStatementAst) { return false; }104 105 public object VisitReturnStatement(ReturnStatementAst returnStatementAst) { return false; }106 107 public object VisitExitStatement(ExitStatementAst exitStatementAst) { return false; }108 109 public object VisitThrowStatement(ThrowStatementAst throwStatementAst) { return false; }110 111 public object VisitDoUntilStatement(DoUntilStatementAst doUntilStatementAst) { return false; }112 113 public object VisitAssignmentStatement(AssignmentStatementAst assignmentStatementAst) { return false; }114 115 public object VisitCommand(CommandAst commandAst) { return false; }116 117 public object VisitCommandExpression(CommandExpressionAst commandExpressionAst) { return false; }118 119 public object VisitCommandParameter(CommandParameterAst commandParameterAst) { return false; }120 121 public object VisitFileRedirection(FileRedirectionAst fileRedirectionAst) { return false; }122 123 public object VisitMergingRedirection(MergingRedirectionAst mergingRedirectionAst) { return false; }124 125 public object VisitExpandableStringExpression(ExpandableStringExpressionAst expandableStringExpressionAst) { return false; }126 127 public object VisitIndexExpression(IndexExpressionAst indexExpressionAst) { return false; }128 129 public object VisitAttributedExpression(AttributedExpressionAst attributedExpressionAst) { return false; }130 131 public object VisitBlockStatement(BlockStatementAst blockStatementAst) { return false; }132 133 public object VisitInvokeMemberExpression(InvokeMemberExpressionAst invokeMemberExpressionAst) { return false; }134 135 public object VisitTypeDefinition(TypeDefinitionAst typeDefinitionAst) { return false; }136 137 public object VisitPropertyMember(PropertyMemberAst propertyMemberAst) { return false; }138 139 public object VisitFunctionMember(FunctionMemberAst functionMemberAst) { return false; }140 141 public object VisitBaseCtorInvokeMemberExpression(BaseCtorInvokeMemberExpressionAst baseCtorInvokeMemberExpressionAst) { return false; }142 143 public object VisitUsingStatement(UsingStatementAst usingStatement) { return false; }144 145 public object VisitConfigurationDefinition(ConfigurationDefinitionAst configurationDefinitionAst) { return false; }146 147 public object VisitDynamicKeywordStatement(DynamicKeywordStatementAst dynamicKeywordAst) { return false; }148 149 public object VisitStatementBlock(StatementBlockAst statementBlockAst)150 {151 if (statementBlockAst.Traps != null) 152 {153 return false;154 }155 156 if (statementBlockAst.Statements.Count > 1)157 {158 return false;159 }160 161 var pipeline = statementBlockAst.Statements.FirstOrDefault();162 return pipeline != null && (bool)pipeline.Accept(this);163 }164 165 public object VisitPipeline(PipelineAst pipelineAst)166 {167 var expr = pipelineAst.GetPureExpression();168 return expr != null && (bool)expr.Accept(this);169 }170 171 private static bool IsNullDivisor(ExpressionAst operand)172 {173 if (!(operand is VariableExpressionAst varExpr))174 {175 return false;176 }177 178 var parent = operand.Parent as BinaryExpressionAst;179 if (parent == null || parent.Right != operand)180 {181 return false;182 }183 184 switch (parent.Operator)185 {186 case TokenKind.Divide:187 case TokenKind.DivideEquals:188 case TokenKind.Rem:189 case TokenKind.RemainderEquals:190 string name = varExpr.VariablePath.UnqualifiedPath;191 return (name.Equals(SpecialVariables.False, StringComparison.OrdinalIgnoreCase) ||192 name.Equals(SpecialVariables.Null, StringComparison.OrdinalIgnoreCase));193 }194 195 return false;196 }197 198 public object VisitTernaryExpression(TernaryExpressionAst ternaryExpressionAst)199 {200 return (bool)ternaryExpressionAst.Condition.Accept(this) &&201 (bool)ternaryExpressionAst.IfTrue.Accept(this) &&202 (bool)ternaryExpressionAst.IfFalse.Accept(this);203 }204 205 public object VisitBinaryExpression(BinaryExpressionAst binaryExpressionAst)206 {207 return binaryExpressionAst.Operator.HasTrait(TokenFlags.CanConstantFold) &&208 (bool)binaryExpressionAst.Left.Accept(this) && (bool)binaryExpressionAst.Right.Accept(this)209 && !IsNullDivisor(binaryExpressionAst.Right);210 }211 212 public object VisitUnaryExpression(UnaryExpressionAst unaryExpressionAst)213 {214 return unaryExpressionAst.TokenKind.HasTrait(TokenFlags.CanConstantFold) &&215 (bool)unaryExpressionAst.Child.Accept(this);216 }217 218 public object VisitConvertExpression(ConvertExpressionAst convertExpressionAst)219 {220 var type = convertExpressionAst.Type.TypeName.GetReflectionType();221 if (type == null)222 {223 return false;224 }225 226 if (!type.IsSafePrimitive())227 {228 // Only do conversions to built-in types - other conversions might not229 // be safe to optimize.230 return false;231 }232 233 return (bool)convertExpressionAst.Child.Accept(this);234 }235 236 public object VisitConstantExpression(ConstantExpressionAst constantExpressionAst)237 {238 return true;239 }240 241 public object VisitStringConstantExpression(StringConstantExpressionAst stringConstantExpressionAst)242 {243 return true;244 }245 246 public object VisitSubExpression(SubExpressionAst subExpressionAst)247 {248 return subExpressionAst.SubExpression.Accept(this);249 }250 251 public object VisitUsingExpression(UsingExpressionAst usingExpressionAst)252 {253 // $using:true should be constant - it's silly to write that, but not harmful.254 return usingExpressionAst.SubExpression.Accept(this);255 }256 257 public object VisitVariableExpression(VariableExpressionAst variableExpressionAst)258 {259 return variableExpressionAst.IsConstantVariable();260 }261 262 public object VisitTypeExpression(TypeExpressionAst typeExpressionAst)263 {264 // We defer trying to resolve a type expression as an attribute argument265 // until the script/function is first run, so it's OK if a type expression266 // as an attribute argument cannot be resolved yet.267 return CheckingAttributeArgument ||268 typeExpressionAst.TypeName.GetReflectionType() != null;269 }270 271 public object VisitMemberExpression(MemberExpressionAst memberExpressionAst)272 {273 if (!memberExpressionAst.Static || memberExpressionAst.Expression is not TypeExpressionAst)274 {275 return false;276 }277 278 var type = ((TypeExpressionAst)memberExpressionAst.Expression).TypeName.GetReflectionType();279 if (type == null)280 {281 return false;282 }283 284 if (!(memberExpressionAst.Member is StringConstantExpressionAst member))285 {286 return false;287 }288 289 var memberInfo = type.GetMember(member.Value, MemberTypes.Field,290 BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy);291 if (memberInfo.Length != 1)292 {293 return false;294 }295 296 return (((FieldInfo)memberInfo[0]).Attributes & FieldAttributes.Literal) != 0;297 }298 299 public object VisitArrayExpression(ArrayExpressionAst arrayExpressionAst)300 {301 return false;302 }303 304 public object VisitArrayLiteral(ArrayLiteralAst arrayLiteralAst)305 {306 // An array literal is a constant when we're generating metadata, but when307 // we're generating code, we need to create new arrays or we'd have an aliasing problem.308 return (CheckingAttributeArgument || CheckingRequiresArgument) && arrayLiteralAst.Elements.All(e => (bool)e.Accept(this));309 }310 311 public object VisitHashtable(HashtableAst hashtableAst)312 {313 return CheckingRequiresArgument &&314 hashtableAst.KeyValuePairs.All(pair => (bool)pair.Item1.Accept(this) && (bool)pair.Item2.Accept(this));315 }316 317 public object VisitScriptBlockExpression(ScriptBlockExpressionAst scriptBlockExpressionAst)318 {319 // A script block expression is a constant when we're generating metadata, but when320 // we're generating code, we need to create new script blocks so we can't use a constant.321 // Also - we have no way to describe a script block when generating .Net metadata, so322 // we must disallow script blocks as attribute arguments on/inside a class.323 return CheckingAttributeArgument && !CheckingClassAttributeArguments;324 }325 326 public object VisitParenExpression(ParenExpressionAst parenExpressionAst)327 {328 return parenExpressionAst.Pipeline.Accept(this);329 }330 }331 332 internal class ConstantValueVisitor : ICustomAstVisitor2333 {334 internal bool AttributeArgument { get; set; }335 336 internal bool RequiresArgument { get; set; }337 338 [Conditional("DEBUG")]339 [Conditional("ASSERTIONS_TRACE")]340 private void CheckIsConstant(Ast ast, string msg)341 {342 Diagnostics.Assert(343 (bool)ast.Accept(new IsConstantValueVisitor { CheckingAttributeArgument = this.AttributeArgument, CheckingRequiresArgument = RequiresArgument }), msg);344 }345 346 private static object CompileAndInvoke(Ast ast)347 {348 try349 {350 var compiler = new Compiler { CompilingConstantExpression = true };351 return Expression.Lambda((Expression)ast.Accept(compiler)).Compile().DynamicInvoke();352 }353 catch (TargetInvocationException tie)354 {355 throw tie.InnerException;356 }357 }358 359 public object VisitErrorStatement(ErrorStatementAst errorStatementAst) { return AutomationNull.Value; }360 361 public object VisitErrorExpression(ErrorExpressionAst errorExpressionAst) { return AutomationNull.Value; }362 363 public object VisitScriptBlock(ScriptBlockAst scriptBlockAst) { return AutomationNull.Value; }364 365 public object VisitParamBlock(ParamBlockAst paramBlockAst) { return AutomationNull.Value; }366 367 public object VisitNamedBlock(NamedBlockAst namedBlockAst) { return AutomationNull.Value; }368 369 public object VisitTypeConstraint(TypeConstraintAst typeConstraintAst) { return AutomationNull.Value; }370 371 public object VisitAttribute(AttributeAst attributeAst) { return AutomationNull.Value; }372 373 public object VisitNamedAttributeArgument(NamedAttributeArgumentAst namedAttributeArgumentAst) { return AutomationNull.Value; }374 375 public object VisitParameter(ParameterAst parameterAst) { return AutomationNull.Value; }376 377 public object VisitFunctionDefinition(FunctionDefinitionAst functionDefinitionAst) { return AutomationNull.Value; }378 379 public object VisitIfStatement(IfStatementAst ifStmtAst) { return AutomationNull.Value; }380 381 public object VisitTrap(TrapStatementAst trapStatementAst) { return AutomationNull.Value; }382 383 public object VisitSwitchStatement(SwitchStatementAst switchStatementAst) { return AutomationNull.Value; }384 385 public object VisitDataStatement(DataStatementAst dataStatementAst) { return AutomationNull.Value; }386 387 public object VisitForEachStatement(ForEachStatementAst forEachStatementAst) { return AutomationNull.Value; }388 389 public object VisitDoWhileStatement(DoWhileStatementAst doWhileStatementAst) { return AutomationNull.Value; }390 391 public object VisitForStatement(ForStatementAst forStatementAst) { return AutomationNull.Value; }392 393 public object VisitWhileStatement(WhileStatementAst whileStatementAst) { return AutomationNull.Value; }394 395 public object VisitCatchClause(CatchClauseAst catchClauseAst) { return AutomationNull.Value; }396 397 public object VisitTryStatement(TryStatementAst tryStatementAst) { return AutomationNull.Value; }398 399 public object VisitBreakStatement(BreakStatementAst breakStatementAst) { return AutomationNull.Value; }400 401 public object VisitContinueStatement(ContinueStatementAst continueStatementAst) { return AutomationNull.Value; }402 403 public object VisitReturnStatement(ReturnStatementAst returnStatementAst) { return AutomationNull.Value; }404 405 public object VisitExitStatement(ExitStatementAst exitStatementAst) { return AutomationNull.Value; }406 407 public object VisitThrowStatement(ThrowStatementAst throwStatementAst) { return AutomationNull.Value; }408 409 public object VisitDoUntilStatement(DoUntilStatementAst doUntilStatementAst) { return AutomationNull.Value; }410 411 public object VisitAssignmentStatement(AssignmentStatementAst assignmentStatementAst) { return AutomationNull.Value; }412 413 public object VisitCommand(CommandAst commandAst) { return AutomationNull.Value; }414 415 public object VisitCommandExpression(CommandExpressionAst commandExpressionAst) { return AutomationNull.Value; }416 417 public object VisitCommandParameter(CommandParameterAst commandParameterAst) { return AutomationNull.Value; }418 419 public object VisitFileRedirection(FileRedirectionAst fileRedirectionAst) { return AutomationNull.Value; }420 421 public object VisitMergingRedirection(MergingRedirectionAst mergingRedirectionAst) { return AutomationNull.Value; }422 423 public object VisitExpandableStringExpression(ExpandableStringExpressionAst expandableStringExpressionAst) { return AutomationNull.Value; }424 425 public object VisitIndexExpression(IndexExpressionAst indexExpressionAst) { return AutomationNull.Value; }426 427 public object VisitAttributedExpression(AttributedExpressionAst attributedExpressionAst) { return AutomationNull.Value; }428 429 public object VisitBlockStatement(BlockStatementAst blockStatementAst) { return AutomationNull.Value; }430 431 public object VisitInvokeMemberExpression(InvokeMemberExpressionAst invokeMemberExpressionAst) { return AutomationNull.Value; }432 433 public object VisitTypeDefinition(TypeDefinitionAst typeDefinitionAst) { return AutomationNull.Value; }434 435 public object VisitPropertyMember(PropertyMemberAst propertyMemberAst) { return AutomationNull.Value; }436 437 public object VisitFunctionMember(FunctionMemberAst functionMemberAst) { return AutomationNull.Value; }438 439 public object VisitBaseCtorInvokeMemberExpression(BaseCtorInvokeMemberExpressionAst baseCtorInvokeMemberExpressionAst) { return AutomationNull.Value; }440 441 public object VisitUsingStatement(UsingStatementAst usingStatement) { return AutomationNull.Value; }442 443 public object VisitConfigurationDefinition(ConfigurationDefinitionAst configurationDefinitionAst) { return AutomationNull.Value; }444 445 public object VisitDynamicKeywordStatement(DynamicKeywordStatementAst dynamicKeywordAst) { return AutomationNull.Value; }446 447 public object VisitStatementBlock(StatementBlockAst statementBlockAst)448 {449 CheckIsConstant(statementBlockAst, "Caller to verify ast is constant");450 return statementBlockAst.Statements[0].Accept(this);451 }452 453 public object VisitPipeline(PipelineAst pipelineAst)454 {455 CheckIsConstant(pipelineAst, "Caller to verify ast is constant");456 return pipelineAst.GetPureExpression().Accept(this);457 }458 459 public object VisitTernaryExpression(TernaryExpressionAst ternaryExpressionAst)460 {461 CheckIsConstant(ternaryExpressionAst, "Caller to verify ast is constant");462 463 object condition = ternaryExpressionAst.Condition.Accept(this);464 return LanguagePrimitives.IsTrue(condition)465 ? ternaryExpressionAst.IfTrue.Accept(this)466 : ternaryExpressionAst.IfFalse.Accept(this);467 }468 469 public object VisitBinaryExpression(BinaryExpressionAst binaryExpressionAst)470 {471 CheckIsConstant(binaryExpressionAst, "Caller to verify ast is constant");472 return CompileAndInvoke(binaryExpressionAst);473 }474 475 public object VisitUnaryExpression(UnaryExpressionAst unaryExpressionAst)476 {477 CheckIsConstant(unaryExpressionAst, "Caller to verify ast is constant");478 return CompileAndInvoke(unaryExpressionAst);479 }480 481 public object VisitConvertExpression(ConvertExpressionAst convertExpressionAst)482 {483 CheckIsConstant(convertExpressionAst, "Caller to verify ast is constant");484 return CompileAndInvoke(convertExpressionAst);485 }486 487 public object VisitConstantExpression(ConstantExpressionAst constantExpressionAst)488 {489 CheckIsConstant(constantExpressionAst, "Caller to verify ast is constant");490 return constantExpressionAst.Value;491 }492 493 public object VisitStringConstantExpression(StringConstantExpressionAst stringConstantExpressionAst)494 {495 CheckIsConstant(stringConstantExpressionAst, "Caller to verify ast is constant");496 return stringConstantExpressionAst.Value;497 }498 499 public object VisitSubExpression(SubExpressionAst subExpressionAst)500 {501 CheckIsConstant(subExpressionAst, "Caller to verify ast is constant");502 return subExpressionAst.SubExpression.Accept(this);503 }504 505 public object VisitUsingExpression(UsingExpressionAst usingExpressionAst)506 {507 CheckIsConstant(usingExpressionAst.SubExpression, "Caller to verify ast is constant");508 return usingExpressionAst.SubExpression.Accept(this);509 }510 511 public object VisitVariableExpression(VariableExpressionAst variableExpressionAst)512 {513 CheckIsConstant(variableExpressionAst, "Caller to verify ast is constant");514 string name = variableExpressionAst.VariablePath.UnqualifiedPath;515 if (name.Equals(SpecialVariables.True, StringComparison.OrdinalIgnoreCase))516 return true;517 518 if (name.Equals(SpecialVariables.False, StringComparison.OrdinalIgnoreCase))519 return false;520 521 Diagnostics.Assert(name.Equals(SpecialVariables.Null, StringComparison.OrdinalIgnoreCase), "Unexpected constant variable");522 return null;523 }524 525 public object VisitTypeExpression(TypeExpressionAst typeExpressionAst)526 {527 CheckIsConstant(typeExpressionAst, "Caller to verify ast is constant");528 return typeExpressionAst.TypeName.GetReflectionType();529 }530 531 public object VisitMemberExpression(MemberExpressionAst memberExpressionAst)532 {533 CheckIsConstant(memberExpressionAst, "Caller to verify ast is constant");534 535 var type = ((TypeExpressionAst)memberExpressionAst.Expression).TypeName.GetReflectionType();536 var member = ((StringConstantExpressionAst)memberExpressionAst.Member).Value;537 var memberInfo = type.GetMember(member, MemberTypes.Field,538 BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy);539 return ((FieldInfo)memberInfo[0]).GetValue(null);540 }541 542 public object VisitArrayExpression(ArrayExpressionAst arrayExpressionAst)543 {544 CheckIsConstant(arrayExpressionAst, "Caller to verify ast is constant");545 return arrayExpressionAst.SubExpression.Accept(this);546 }547 548 public object VisitArrayLiteral(ArrayLiteralAst arrayLiteralAst)549 {550 CheckIsConstant(arrayLiteralAst, "Caller to verify ast is constant");551 return arrayLiteralAst.Elements.Select(e => e.Accept(this)).ToArray();552 }553 554 public object VisitScriptBlockExpression(ScriptBlockExpressionAst scriptBlockExpressionAst)555 {556 CheckIsConstant(scriptBlockExpressionAst, "Caller to verify ast is constant");557 return new ScriptBlock(scriptBlockExpressionAst.ScriptBlock, isFilter: false);558 }559 560 public object VisitParenExpression(ParenExpressionAst parenExpressionAst)561 {562 CheckIsConstant(parenExpressionAst, "Caller to verify ast is constant");563 return parenExpressionAst.Pipeline.Accept(this);564 }565 566 public object VisitHashtable(HashtableAst hashtableAst)567 {568 CheckIsConstant(hashtableAst, "Caller to verify ast is constant");569 var result = new Hashtable();570 foreach (var pair in hashtableAst.KeyValuePairs)571 {572 result.Add(pair.Item1.Accept(this), pair.Item2.Accept(this));573 }574 575 return result;576 }577 }578}579 