diff --git a/powershell/codeql-extractor.yml b/powershell/codeql-extractor.yml index c671f2be6341..1180dd447656 100644 --- a/powershell/codeql-extractor.yml +++ b/powershell/codeql-extractor.yml @@ -10,4 +10,5 @@ file_types: display_name: powershellscripts extensions: - .ps1 - - .psd1 \ No newline at end of file + - .psd1 + - .psm1 \ No newline at end of file diff --git a/powershell/extractor/Semmle.Extraction.PowerShell.Standalone/Options.cs b/powershell/extractor/Semmle.Extraction.PowerShell.Standalone/Options.cs index caf2c6f00125..934bf7f96e7a 100644 --- a/powershell/extractor/Semmle.Extraction.PowerShell.Standalone/Options.cs +++ b/powershell/extractor/Semmle.Extraction.PowerShell.Standalone/Options.cs @@ -74,7 +74,7 @@ public override void InvalidArgument(string argument) /// /// List of extensions to include. /// - public IList Extensions { get; } = new List() { ".ps1" }; + public IList Extensions { get; } = new List() { ".ps1", ".psd1", ".psm1" }; /// /// Files/patterns to exclude. diff --git a/powershell/extractor/Semmle.Extraction/Tuples.cs b/powershell/extractor/Semmle.Extraction/Tuples.cs index 2cff4bfbdf1d..afe19295ee5b 100644 --- a/powershell/extractor/Semmle.Extraction/Tuples.cs +++ b/powershell/extractor/Semmle.Extraction/Tuples.cs @@ -30,7 +30,7 @@ internal static void folders(this System.IO.TextWriter trapFile, Folder folder, public static void locations_default(this System.IO.TextWriter trapFile, SourceLocation label, Entities.File file, int startLine, int startCol, int endLine, int endCol) { - trapFile.WriteTuple("locations_default", label, file, startLine, startCol, endLine, endCol); + trapFile.WriteTuple("locations_default", label, file, startLine, startCol, endLine, endCol - 1); } } } diff --git a/powershell/ql/lib/powershell.qll b/powershell/ql/lib/powershell.qll index 8bbfe93262ab..67ec61e3003c 100644 --- a/powershell/ql/lib/powershell.qll +++ b/powershell/ql/lib/powershell.qll @@ -1,85 +1 @@ -import semmle.code.powershell.File -import semmle.code.powershell.Location -import semmle.code.powershell.SourceLocation -import semmle.code.powershell.Ast -import semmle.code.powershell.Statement -import semmle.code.powershell.Expression -import semmle.code.powershell.CommandBase -import semmle.code.powershell.AttributeBase -import semmle.code.powershell.PipelineBase -import semmle.code.powershell.PipelineChain -import semmle.code.powershell.BaseConstantExpression -import semmle.code.powershell.ConstantExpression -import semmle.code.powershell.MemberExpressionBase -import semmle.code.powershell.Attribute -import semmle.code.powershell.NamedAttributeArgument -import semmle.code.powershell.TypeConstraint -import semmle.code.powershell.VariableExpression -import semmle.code.powershell.ModuleSpecification -import semmle.code.powershell.ParamBlock -import semmle.code.powershell.NamedBlock -import semmle.code.powershell.ScriptBlock -import semmle.code.powershell.StringLiteral -import semmle.code.powershell.AssignmentStatement -import semmle.code.powershell.BinaryExpression -import semmle.code.powershell.UnaryExpression -import semmle.code.powershell.ScriptBlockExpr -import semmle.code.powershell.TernaryExpression -import semmle.code.powershell.UsingExpression -import semmle.code.powershell.TrapStatement -import semmle.code.powershell.StatementBlock -import semmle.code.powershell.ArrayExpression -import semmle.code.powershell.ArrayLiteral -import semmle.code.powershell.CommandElement -import semmle.code.powershell.Redirection -import semmle.code.powershell.FileRedirection -import semmle.code.powershell.MergingRedirection -import semmle.code.powershell.LoopStmt -import semmle.code.powershell.DoWhileStmt -import semmle.code.powershell.DoUntilStmt -import semmle.code.powershell.WhileStmt -import semmle.code.powershell.ForStmt -import semmle.code.powershell.ForEachStmt -import semmle.code.powershell.GotoStmt -import semmle.code.powershell.ContinueStmt -import semmle.code.powershell.BreakStmt -import semmle.code.powershell.ReturnStmt -import semmle.code.powershell.UsingStmt -import semmle.code.powershell.ThrowStmt -import semmle.code.powershell.ErrorStmt -import semmle.code.powershell.Type -import semmle.code.powershell.Member -import semmle.code.powershell.PropertyMember -import semmle.code.powershell.Function -import semmle.code.powershell.TryStmt -import semmle.code.powershell.IfStmt -import semmle.code.powershell.SwitchStmt -import semmle.code.powershell.ExitStmt -import semmle.code.powershell.LabeledStmt -import semmle.code.powershell.DynamicStmt -import semmle.code.powershell.DataStmt -import semmle.code.powershell.Configuration -import semmle.code.powershell.CatchClause -import semmle.code.powershell.Command -import semmle.code.powershell.CommandExpression -import semmle.code.powershell.CommandParameter -import semmle.code.powershell.ExpandableStringExpression -import semmle.code.powershell.TypeExpression -import semmle.code.powershell.ParenExpression -import semmle.code.powershell.Chainable -import semmle.code.powershell.Pipeline -import semmle.code.powershell.StringConstantExpression -import semmle.code.powershell.MemberExpr -import semmle.code.powershell.InvokeMemberExpression -import semmle.code.powershell.Call -import semmle.code.powershell.ObjectCreation -import semmle.code.powershell.SubExpression -import semmle.code.powershell.ErrorExpr -import semmle.code.powershell.ConvertExpr -import semmle.code.powershell.IndexExpr -import semmle.code.powershell.HashTable -import semmle.code.powershell.SplitExpr -import semmle.code.powershell.CommentEntity -import semmle.code.powershell.Variable -import semmle.code.powershell.internal.Internal::Public -import semmle.code.powershell.ModuleManifest \ No newline at end of file +import semmle.code.powershell.ast.Ast \ No newline at end of file diff --git a/powershell/ql/lib/semmle/code/powershell/ApiGraphs.qll b/powershell/ql/lib/semmle/code/powershell/ApiGraphs.qll index 7fe18c97f6e9..8634161e5a01 100644 --- a/powershell/ql/lib/semmle/code/powershell/ApiGraphs.qll +++ b/powershell/ql/lib/semmle/code/powershell/ApiGraphs.qll @@ -271,7 +271,8 @@ module API { this = Impl::MkMethodAccessNode(result) or this = Impl::MkBackwardNode(result, _) or this = Impl::MkForwardNode(result, _) or - this = Impl::MkSinkNode(result) + this = Impl::MkSinkNode(result) or + this = Impl::MkNamespaceOfTypeNameNode(result) } /** Gets the location of this node. */ @@ -324,45 +325,6 @@ module API { } } - /** A node representing a module/class object with epsilon edges to its descendents. */ - private class ModuleNode extends Node, Impl::MkModule { - string qualifiedModule; - int n; - - ModuleNode() { this = Impl::MkModule(qualifiedModule, n) } - - ModuleNode getNext() { result = Impl::MkModule(qualifiedModule, n + 1) } - - ModuleNode getPred() { result.getNext() = this } - - string getComponent() { result = qualifiedModule.splitAt(".", n) } - - string getModule() { - not exists(this.getPred()) and - result = this.getComponent() - or - result = this.getPred().getModule() + "." + this.getComponent() - } - - override string toString() { result = "Module(" + this.getModule() + ")" } - } - - /** A node representing instances of a module/class with epsilon edges to its ancestors. */ - private class InstanceUp extends Node, Impl::MkInstanceUp { - /** Gets the module whose instances are represented by this API node. */ - string getType() { this = Impl::MkInstanceUp(result) } - - override string toString() { result = "ModuleInstanceUp(" + this.getType() + ")" } - } - - /** A node representing instances of a module/class with epsilon edges to its descendents. */ - private class InstanceDownNode extends Node, Impl::MkInstanceDown { - /** Gets the module whose instances are represented by this API node. */ - string getType() { this = Impl::MkInstanceDown(result) } - - override string toString() { result = "ModuleInstanceDown(" + this.getType() + ")" } - } - /** A node corresponding to the method being invoked at a method call. */ class MethodAccessNode extends Node, Impl::MkMethodAccessNode { override string toString() { result = "MethodAccessNode(" + this.asCall() + ")" } @@ -378,6 +340,22 @@ module API { override string toString() { result = "SinkNode(" + this.getInducingNode() + ")" } } + private class UsingNode extends Node, Impl::MkUsingNode { + UsingStmt using; // TODO: This should really be the cfg node, I think + + UsingNode() { this = Impl::MkUsingNode(using) } + + override string toString() { result = "UsingNode(" + using + ")" } + } + + private class NamespaceOfTypeNameNode extends Node, Impl::MkNamespaceOfTypeNameNode { + DataFlow::QualifiedTypeNameNode typeName; + + NamespaceOfTypeNameNode() { this = Impl::MkNamespaceOfTypeNameNode(typeName) } + + override string toString() { result = "NamespaceOfTypeNameNode(" + typeName + ")" } + } + /** * An API entry point. * @@ -415,11 +393,15 @@ module API { /** Gets the root node. */ Node root() { result instanceof RootNode } - /** - * Gets the node that represents the module with qualified - * name `qualifiedModule`. - */ - ModuleNode mod(string qualifiedModule, int n) { result = Impl::MkModule(qualifiedModule, n) } + bindingset[name] + pragma[inline_late] + Node namespace(string name) { + // This predicate is currently not 'inline_late' because 'n' can be an input or output + Impl::namespace(name, result) + } + + pragma[inline] + Node getTopLevelMember(string name) { Impl::topLevelMember(name, result) } /** * Gets an unqualified call at the top-level with the given method name. @@ -466,44 +448,14 @@ module API { cached private module Impl { - private predicate isGacModule(string s) { - s = - [ - "System.Management.Automation", - "Microsoft.Management.Infrastructure", - "Microsoft.PowerShell.Security", - "Microsoft.PowerShell.Commands.Management", - "Microsoft.PowerShell.Commands.Utility" - ] - } - - private predicate isModule(string s, int n) { - ( - any(UsingStmt using).getName() = s - or - any(Cmd cmd).getNamespaceQualifier() = s - or - any(TypeNameExpr tn).getName() = s - or - any(ModuleManifest manifest).getModuleName() = s - or - isGacModule(s) - ) and - exists(s.splitAt(".", n)) - } - cached newtype TApiNode = /** The root of the API graph. */ MkRoot() or /** The method accessed at `call`, synthetically treated as a separate object. */ MkMethodAccessNode(DataFlow::CallNode call) or - MkModule(string qualifiedModule, int n) { isModule(qualifiedModule, n) } or - /** Instances of `mod` with epsilon edges to its ancestors. */ - MkInstanceUp(string qualifiedType) { exists(MkModule(qualifiedType, _)) } or - /** Instances of `mod` with epsilon edges to its descendents, and to its upward node. */ - MkInstanceDown(string qualifiedType) { exists(MkModule(qualifiedType, _)) } or - /** Intermediate node for following forward data flow. */ + MkUsingNode(UsingStmt using) or + MkNamespaceOfTypeNameNode(DataFlow::QualifiedTypeNameNode typeName) or MkForwardNode(DataFlow::LocalSourceNode node, TypeTracker t) { isReachable(node, t) } or /** Intermediate node for following backward data flow. */ MkBackwardNode(DataFlow::LocalSourceNode node, TypeTracker t) { isReachable(node, t) } or @@ -523,10 +475,30 @@ module API { pragma[inline_late] private DataFlow::Node getNodeFromExpr(Expr e) { result.asExpr().getExpr() = e } + private import frameworks.data.ModelsAsData + + cached + predicate namespace(string name, Node node) { + exists(DataFlow::QualifiedTypeNameNode typeName | + typeName.getNamespace() = name and + node = MkNamespaceOfTypeNameNode(typeName) + ) + or + exists(UsingStmt using | + using.getName().toLowerCase() = name and + node = MkUsingNode(using) + ) + or + node = ModelOutput::getATypeNode(name) + } + + cached + predicate topLevelMember(string name, Node node) { memberEdge(root(), name, node) } + cached predicate toplevelCall(string name, Node node) { exists(DataFlow::CallNode call | - call.asExpr().getExpr().getEnclosingScope() instanceof TopLevel and + call.asExpr().getExpr().getEnclosingScope() instanceof TopLevelScriptBlock and call.getName() = name and node = MkMethodAccessNode(call) ) @@ -544,26 +516,25 @@ module API { cached predicate memberEdge(Node pred, string name, Node succ) { - exists(MemberExpr member | succ = getForwardStartNode(getNodeFromExpr(member)) | - pred = getForwardEndNode(getALocalSourceStrict(getNodeFromExpr(member.getQualifier()))) and - name = member.getMemberName() + exists(StringConstExpr read | + succ = getForwardStartNode(getNodeFromExpr(read)) and + pred = MkRoot() and + name = read.getValueString() + ) + or + exists(DataFlow::QualifiedTypeNameNode typeName | + typeName.getName() = name and + pred = MkNamespaceOfTypeNameNode(typeName) and + succ = getForwardStartNode(typeName) ) + // or + // TODO: Handle getAMember when the predecessor is a MkUsingNode? } cached predicate methodEdge(Node pred, string name, Node succ) { exists(DataFlow::CallNode call | succ = MkMethodAccessNode(call) and name = call.getName() | pred = getForwardEndNode(getALocalSourceStrict(call.getQualifier())) - or - exists(string qualifiedModule, ModuleManifest manifest, int n | - pred = mod(qualifiedModule, n) and - not exists(mod(qualifiedModule, n + 1)) and - manifest.getModuleName() = qualifiedModule - | - manifest.getACmdLetToExport() = name - or - manifest.getAFunctionToExport() = name - ) ) } @@ -657,24 +628,10 @@ module API { cached predicate instanceEdge(Node pred, Node succ) { - exists(string qualifiedType, int n | - pred = MkModule(qualifiedType, n) and - not exists(MkModule(qualifiedType, n + 1)) - | - exists(DataFlow::TypeNameNode typeName | - typeName.getTypeName() = qualifiedType and - succ = getForwardStartNode(typeName) - ) - or - exists(DataFlow::ObjectCreationNode objCreation | - objCreation.getConstructedTypeName() = qualifiedType and - succ = getForwardStartNode(objCreation) - ) - or - exists(DataFlow::ParameterNode p | - p.getParameter().getStaticType() = qualifiedType and - succ = getForwardStartNode(p) - ) + // TODO: Also model parameters with a given type here + exists(DataFlow::ObjectCreationNode objCreation | + pred = getForwardEndNode(objCreation.getConstructedTypeNode()) and + succ = getForwardStartNode(objCreation) ) } diff --git a/powershell/ql/lib/semmle/code/powershell/ArrayExpression.qll b/powershell/ql/lib/semmle/code/powershell/ArrayExpression.qll deleted file mode 100644 index 4228b3f34396..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/ArrayExpression.qll +++ /dev/null @@ -1,26 +0,0 @@ -import powershell - -class ArrayExpr extends @array_expression, Expr { - override SourceLocation getLocation() { array_expression_location(this, result) } - - StmtBlock getStmtBlock() { array_expression(this, result) } - - /** - * Gets the i'th element of this `ArrayExpr`, if this can be determined statically. - * - * See `getStmtBlock` when the array elements are not known statically. - */ - Expr getElement(int i) { - result = - unique( | | this.getStmtBlock().getAStmt()).(CmdExpr).getExpr().(ArrayLiteral).getElement(i) - } - - /** - * Gets an element of this `ArrayExpr`, if this can be determined statically. - * - * See `getStmtBlock` when the array elements are not known statically. - */ - Expr getAnElement() { result = this.getElement(_) } - - override string toString() { result = "@(...)" } -} diff --git a/powershell/ql/lib/semmle/code/powershell/Ast.qll b/powershell/ql/lib/semmle/code/powershell/Ast.qll deleted file mode 100644 index a5c43472bc7d..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/Ast.qll +++ /dev/null @@ -1,14 +0,0 @@ -import powershell -private import semmle.code.powershell.controlflow.internal.Scope - -class Ast extends @ast { - string toString() { none() } - - Ast getParent() { parent(this, result) } - - Location getLocation() { none() } - - Scope getEnclosingScope() { result = scopeOf(this) } - - final Function getEnclosingFunction() { this.getEnclosingScope() = result.getBody() } -} diff --git a/powershell/ql/lib/semmle/code/powershell/Call.qll b/powershell/ql/lib/semmle/code/powershell/Call.qll deleted file mode 100644 index b5516344cc60..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/Call.qll +++ /dev/null @@ -1,79 +0,0 @@ -import powershell -private import semmle.code.powershell.dataflow.internal.DataFlowImplCommon -private import semmle.code.powershell.dataflow.internal.DataFlowDispatch -private import semmle.code.powershell.controlflow.CfgNodes - -abstract private class AbstractCall extends Ast { - abstract Expr getCommand(); - - abstract string getName(); - - /** Gets the i'th argument to this call. */ - abstract Expr getArgument(int i); - - /** Gets the i'th positional argument to this call. */ - abstract Expr getPositionalArgument(int i); - - /** Holds if an argument with name `name` is provided to this call. */ - final predicate hasNamedArgument(string name) { exists(this.getNamedArgument(name)) } - - /** Gets the argument to this call with the name `name`. */ - abstract Expr getNamedArgument(string name); - - /** Gets any argument to this call. */ - final Expr getAnArgument() { result = this.getArgument(_) } - - /** Gets the qualifier of this call, if any. */ - Expr getQualifier() { none() } - - /** Gets a possible runtime target of this call. */ - abstract Function getATarget(); -} - -/** A call to a command. For example, `Write-Host "Hello, world!"`. */ -class CmdCall extends AbstractCall instanceof Cmd { - final override Expr getCommand() { result = Cmd.super.getCommand() } - - final override Expr getPositionalArgument(int i) { result = Cmd.super.getPositionalArgument(i) } - - final override string getName() { result = Cmd.super.getCommandName() } - - final override Expr getArgument(int i) { result = Cmd.super.getArgument(i) } - - final override Expr getNamedArgument(string name) { result = Cmd.super.getNamedArgument(name) } - - final override Function getATarget() { - exists(DataFlowCall call | call.asCall().(StmtNodes::CmdCfgNode).getStmt() = this | - result.getBody() = viableCallableLambda(call, _).asCfgScope() - or - result.getBody() = getTarget(call) - ) - } -} - -/** A call to a method on an object. For example, `$obj.ToString()`. */ -class MethodCall extends AbstractCall instanceof InvokeMemberExpr { - final override Expr getCommand() { result = super.getMember() } - - final override Expr getPositionalArgument(int i) { - result = InvokeMemberExpr.super.getArgument(i) - } - - final override Expr getArgument(int i) { result = this.getPositionalArgument(i) } - - final override Expr getQualifier() { result = InvokeMemberExpr.super.getQualifier() } - - final override Expr getNamedArgument(string name) { none() } - - final override Function getATarget() { - exists(DataFlowCall call | call.asCall().(ExprNodes::InvokeMemberCfgNode).getExpr() = this | - result.getBody() = viableCallableLambda(call, _).asCfgScope() - or - result.getBody() = getTarget(call) - ) - } - - final override string getName() { result = InvokeMemberExpr.super.getName() } -} - -final class Call = AbstractCall; diff --git a/powershell/ql/lib/semmle/code/powershell/CatchClause.qll b/powershell/ql/lib/semmle/code/powershell/CatchClause.qll deleted file mode 100644 index 6d3bf4cb2971..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/CatchClause.qll +++ /dev/null @@ -1,39 +0,0 @@ -import powershell - -class CatchClause extends @catch_clause, Ast { - override SourceLocation getLocation() { catch_clause_location(this, result) } - - override string toString() { result = "catch {...}" } - - StmtBlock getBody() { catch_clause(this, result, _) } - - TypeConstraint getCatchType(int i) { catch_clause_catch_type(this, i, result) } - - int getNumberOfCatchTypes() { result = count(this.getACatchType()) } - - TypeConstraint getACatchType() { result = this.getCatchType(_) } - - predicate isCatchAll() { not exists(this.getACatchType()) } - - TryStmt getTryStmt() { result.getACatchClause() = this } - - predicate isLast() { - exists(TryStmt ts, int last | - ts = this.getTryStmt() and - last = max(int i | exists(ts.getCatchClause(i))) and - this = ts.getCatchClause(last) - ) - } -} - -class GeneralCatchClause extends CatchClause { - GeneralCatchClause() { this.isCatchAll() } - - override string toString() { result = "catch {...}" } -} - -class SpecificCatchClause extends CatchClause { - SpecificCatchClause() { not this.isCatchAll() } - - override string toString() { result = "catch[...] {...}" } -} diff --git a/powershell/ql/lib/semmle/code/powershell/Command.qll b/powershell/ql/lib/semmle/code/powershell/Command.qll deleted file mode 100644 index ffc63c91ff3f..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/Command.qll +++ /dev/null @@ -1,114 +0,0 @@ -import powershell - -private predicate parseCommandName(Cmd cmd, string namespace, string name) { - exists(string qualified | command(cmd, qualified, _, _, _) | - namespace = qualified.regexpCapture("([^\\\\]+)\\\\([^\\\\]+)", 1) and - name = qualified.regexpCapture("([^\\\\]+)\\\\([^\\\\]+)", 2) - or - // Not a qualified name - not exists(qualified.indexOf("\\")) and - namespace = "" and - name = qualified - ) -} - -/** A call to a command. */ -class Cmd extends @command, CmdBase { - override string toString() { - exists(string name | name = this.getQualifiedCommandName() | - if name = "" then result = "call" else result = "call to " + name - ) - or - not exists(this.getQualifiedCommandName()) and - result = "call" - } - - override SourceLocation getLocation() { command_location(this, result) } - - /** Gets the name of the command without any qualifiers. */ - string getCommandName() { parseCommandName(this, _, result) } - - /** Holds if the command is qualified. */ - predicate isQualified() { parseCommandName(this, any(string s | s != ""), _) } - - /** Gets the namespace qualifier of this command, if any. */ - string getNamespaceQualifier() { - result != "" and - parseCommandName(this, result, _) - or - // Implicit import because it's in a module manifest - parseCommandName(this, "", _) and - exists(ModuleManifest manifest | - manifest.getACmdLetToExport() = this.getCommandName() and - result = manifest.getModuleName() - ) - } - - /** Gets the (possibly qualified) name of this command. */ - string getQualifiedCommandName() { command(this, result, _, _, _) } - - int getKind() { command(this, _, result, _, _) } - - int getNumElements() { command(this, _, _, result, _) } - - int getNumRedirection() { command(this, _, _, _, result) } - - CmdElement getElement(int i) { command_command_element(this, i, result) } - - /** Gets the expression that determines the command to invoke. */ - Expr getCommand() { result = this.getElement(0) } - - /** Gets the name of this command, if this is statically known. */ - StringConstExpr getCmdName() { result = this.getElement(0) } - - /** Gets any argument to this command. */ - Expr getAnArgument() { result = this.getArgument(_) } - - /** - * Gets the `i`th argument to this command. - * - * The argument may be named or positional. - */ - Expr getArgument(int i) { - result = - rank[i + 1](CmdElement e, int j | - e = this.getElement(j) and - not e instanceof CmdParameter and - j > 0 // 0'th element is the command name itself - | - e order by j - ) - } - - /** Gets the `i`th positional argument to this command. */ - Expr getPositionalArgument(int i) { - result = - rank[i + 1](Argument e, int j | - e = this.getArgument(j) and - e instanceof PositionalArgument - | - e order by j - ) - } - - /** Holds if this call has an argument named `name`. */ - predicate hasNamedArgument(string name) { exists(this.getNamedArgument(name)) } - - /** Gets the named argument with the given name. */ - Expr getNamedArgument(string name) { - exists(int i, CmdParameter p | - this.getElement(i) = p and - p.getName() = name and - result = p.getArgument() - ) - } - - Redirection getRedirection(int i) { command_redirection(this, i, result) } - - Redirection getARedirection() { result = this.getRedirection(_) } -} - -/** A call to operator `&`. */ -class CallOperator extends Cmd { - CallOperator() { this.getKind() = 28 } -} diff --git a/powershell/ql/lib/semmle/code/powershell/CommandParameter.qll b/powershell/ql/lib/semmle/code/powershell/CommandParameter.qll deleted file mode 100644 index e1bb400b87b6..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/CommandParameter.qll +++ /dev/null @@ -1,23 +0,0 @@ -import powershell - -class CmdParameter extends @command_parameter, CmdElement { - override SourceLocation getLocation() { command_parameter_location(this, result) } - - string getName() { command_parameter(this, result) } - - Expr getArgument() { - // When an argumnt is of the form -Name:$var - command_parameter_argument(this, result) - or - // When an argument is of the form -Name $var - exists(int i, Cmd cmd | - cmd = this.getCmd() and - cmd.getElement(i) = this and - result = cmd.getElement(i + 1) - ) - } - - Cmd getCmd() { result.getElement(_) = this } - - override string toString() { command_parameter(this, result) } -} diff --git a/powershell/ql/lib/semmle/code/powershell/ConvertExpr.qll b/powershell/ql/lib/semmle/code/powershell/ConvertExpr.qll deleted file mode 100644 index e010804adb56..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/ConvertExpr.qll +++ /dev/null @@ -1,13 +0,0 @@ -import powershell - -class ConvertExpr extends @convert_expression, Expr { - override string toString() { result = "[...]..." } - - override SourceLocation getLocation() { convert_expression_location(this, result) } - - Expr getBase() { convert_expression(this, _, result, _, _) } - - TypeConstraint getType() { convert_expression(this, _, _, result, _) } - - AttributeBase getAttribute() { convert_expression(this, result, _, _, _) } -} diff --git a/powershell/ql/lib/semmle/code/powershell/DynamicStmt.qll b/powershell/ql/lib/semmle/code/powershell/DynamicStmt.qll deleted file mode 100644 index 49c647af51d5..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/DynamicStmt.qll +++ /dev/null @@ -1,11 +0,0 @@ -import powershell - -class DynamicStmt extends @dynamic_keyword_statement, Stmt { - override SourceLocation getLocation() { dynamic_keyword_statement_location(this, result) } - - override string toString() { result = "&..." } - - CmdElement getCmd(int i) { dynamic_keyword_statement_command_elements(this, i, result) } - - CmdElement getACmd() { result = this.getCmd(_) } -} diff --git a/powershell/ql/lib/semmle/code/powershell/Expression.qll b/powershell/ql/lib/semmle/code/powershell/Expression.qll deleted file mode 100644 index 909c971f6e68..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/Expression.qll +++ /dev/null @@ -1,11 +0,0 @@ -import powershell - -/** - * An expression. - * - * This is the topmost class in the hierachy of all expression in PowerShell. - */ -class Expr extends @expression, CmdElement { - /** Gets the constant value of this expression, if this is known. */ - final ConstantValue getValue() { result.getAnExpr() = this } -} diff --git a/powershell/ql/lib/semmle/code/powershell/Function.qll b/powershell/ql/lib/semmle/code/powershell/Function.qll deleted file mode 100644 index f3b1cea97bdc..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/Function.qll +++ /dev/null @@ -1,127 +0,0 @@ -import powershell -import semmle.code.powershell.controlflow.BasicBlocks - -abstract private class AbstractFunction extends Ast { - /** Gets the name of this function. */ - abstract string getName(); - - /** Holds if this function has name `name`. */ - final predicate hasName(string name) { this.getName() = name } - - /** Gets the body of this function. */ - abstract ScriptBlock getBody(); - - /** - * Gets the i'th function parameter, if any. - * - * Note that this predicate only returns _function_ parameters. - * To also get _block_ parameters use the `getParameter` predicate. - */ - abstract Parameter getFunctionParameter(int i); - - /** Gets the declaring type of this function, if any. */ - abstract Type getDeclaringType(); - - /** - * Gets any function parameter of this function. - * - * Note that this only gets _function_ paramters. To get any parameter - * use the `getAParameter` predicate. - */ - final Parameter getAFunctionParameter() { result = this.getFunctionParameter(_) } - - /** Gets the number of function parameters. */ - final int getNumberOfFunctionParameters() { result = count(this.getAFunctionParameter()) } - - /** - * Gets the number of parameters (both function and block). - * Note: This excludes the `this` parameter. - */ - final int getNumberOfParameters() { result = count(this.getAParameter()) } - - /** - * Gets the i'th parameter of this function, if any. - * - * This does not include the `this` parameter. - * - * The implicit underscore parameter (if any) is included at index `-1`. - */ - final Parameter getParameter(int i) { - result.getFunction() = this and - result.getIndex() = i - } - - final Parameter getParameterExcludingPiplines(int i) { - result = this.getFunctionParameter(i) - or - result = this.getBody().getParamBlock().getParameterExcludingPiplines(i) - } - - final Parameter getThisParameter() { - result.isThis() and - result.getFunction() = this - } - - /** Gets any parameter of this function. */ - final Parameter getAParameter() { result = this.getParameter(_) } - - /** Gets the entry point of this function in the control-flow graph. */ - EntryBasicBlock getEntryBasicBlock() { result.getScope() = this.getBody() } -} - -final class Function = AbstractFunction; - -/** - * A function definition. - */ -private class FunctionBase extends @function_definition, Stmt, AbstractFunction { - override string toString() { result = this.getName() } - - override SourceLocation getLocation() { function_definition_location(this, result) } - - override string getName() { function_definition(this, _, result, _, _) } - - override ScriptBlock getBody() { function_definition(this, result, _, _, _) } - - predicate isFilter() { function_definition(this, _, _, true, _) } - - predicate isWorkflow() { function_definition(this, _, _, _, true) } - - override Parameter getFunctionParameter(int i) { result.isFunctionParameter(this, i) } - - override Type getDeclaringType() { none() } -} - -private predicate isMethod(Member m, ScriptBlock body) { - function_member(m, body, _, _, _, _, _, _, _) -} - -/** - * A method definition. That is, a function defined inside a class definition. - */ -class Method extends FunctionBase { - Method() { isMethod(_, super.getBody()) } - - /** Gets the member corresponding to this function definition. */ - Member getMember() { isMethod(result, super.getBody()) } - - /** Holds if this method is a constructor. */ - predicate isConstructor() { function_member(this.getMember(), _, true, _, _, _, _, _, _) } - - final override Type getDeclaringType() { result = this.getMember().getDeclaringType() } -} - -/** A constructor definition. */ -class Constructor extends Method { - Constructor() { this.isConstructor() } -} - -class TopLevel extends AbstractFunction instanceof TopLevelScriptBlock { - final override string getName() { result = "toplevel" } - - final override ScriptBlock getBody() { result = this } - - final override Parameter getFunctionParameter(int i) { none() } - - final override Type getDeclaringType() { none() } -} diff --git a/powershell/ql/lib/semmle/code/powershell/HashTable.qll b/powershell/ql/lib/semmle/code/powershell/HashTable.qll deleted file mode 100644 index 5bd825a18f49..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/HashTable.qll +++ /dev/null @@ -1,21 +0,0 @@ -import powershell - -class HashTableExpr extends @hash_table, Expr { - final override Location getLocation() { hash_table_location(this, result) } - - final override string toString() { result = "${...}" } - - Stmt getElement(Expr key) { hash_table_key_value_pairs(this, _, key, result) } // TODO: Change @ast to @expr in db scheme - - Stmt getElementFromConstant(string key) { - result = this.getElement(any(StringConstExpr sc | sc.getValue().getValue() = key)) - } - - predicate hasKey(Expr key) { exists(this.getElement(key)) } - - Stmt getAnElement() { result = this.getElement(_) } - - predicate hasEntry(int index, Expr key, Stmt value) { - hash_table_key_value_pairs(this, index, key, value) - } -} diff --git a/powershell/ql/lib/semmle/code/powershell/IndexExpr.qll b/powershell/ql/lib/semmle/code/powershell/IndexExpr.qll deleted file mode 100644 index cd31bb36b996..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/IndexExpr.qll +++ /dev/null @@ -1,30 +0,0 @@ -import powershell -private import internal.ExplicitWrite::Private - -class IndexExpr extends @index_expression, Expr { - override string toString() { result = "...[...]" } - - override SourceLocation getLocation() { index_expression_location(this, result) } - - Expr getIndex() { index_expression(this, result, _, _) } // TODO: Change @ast to @expr in the dbscheme - - Expr getBase() { index_expression(this, _, result, _) } // TODO: Change @ast to @expr in the dbscheme - - predicate isNullConditional() { index_expression(this, _, _, true) } -} - -private predicate isImplicitIndexWrite(Expr e) { none() } - -/** An index expression that is being written to. */ -class IndexExprWrite extends IndexExpr { - IndexExprWrite() { isExplicitWrite(this, _) or isImplicitIndexWrite(this) } - - predicate isExplicit(AssignStmt assign) { isExplicitWrite(this, assign) } - - predicate isImplicit() { isImplicitIndexWrite(this) } -} - -/** An index expression that is being read from. */ -class IndexExprRead extends IndexExpr { - IndexExprRead() { not this instanceof IndexExprWrite } -} diff --git a/powershell/ql/lib/semmle/code/powershell/InvokeMemberExpression.qll b/powershell/ql/lib/semmle/code/powershell/InvokeMemberExpression.qll deleted file mode 100644 index c11d542cb228..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/InvokeMemberExpression.qll +++ /dev/null @@ -1,49 +0,0 @@ -import powershell - -class InvokeMemberExpr extends @invoke_member_expression, MemberExprBase { - override SourceLocation getLocation() { invoke_member_expression_location(this, result) } - - Expr getQualifier() { invoke_member_expression(this, result, _) } - - string getName() { result = this.getMember().(StringConstExpr).getValue().getValue() } - - CmdElement getMember() { invoke_member_expression(this, _, result) } - - string getMemberName() { result = this.getMember().(StringConstExpr).getValue().getValue() } - - Expr getArgument(int i) { invoke_member_expression_argument(this, i, result) } - - Expr getAnArgument() { invoke_member_expression_argument(this, _, result) } - - override string toString() { result = "call to " + this.getName() } - - override predicate isStatic() { this.getQualifier() instanceof TypeNameExpr } -} - -/** - * A call to a constructor. For example: - * - * ```powershell - * [System.IO.FileInfo]::new("C:\\file.txt") - * ``` - */ -class ConstructorCall extends InvokeMemberExpr { - TypeNameExpr typename; - - ConstructorCall() { - this.isStatic() and typename = this.getQualifier() and this.getName() = "new" - } - - /** - * Gets the type being constructed by this constructor call. - * - * Note that the type may not exist in the database. - * - * Use `getConstructedTypeName` to get the name of the type (which will - * always exist in the database). - */ - Type getConstructedType() { result = typename.getType() } - - /** Gets the name of the type being constructed by this constructor call. */ - string getConstructedTypeName() { result = typename.getName() } -} diff --git a/powershell/ql/lib/semmle/code/powershell/Member.qll b/powershell/ql/lib/semmle/code/powershell/Member.qll deleted file mode 100644 index 15bdcad8d7e4..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/Member.qll +++ /dev/null @@ -1,17 +0,0 @@ -import powershell - -class Member extends @member, Ast { - Type getDeclaringType() { result.getAMember() = this } - - string getName() { none() } - - override string toString() { result = this.getName() } - - predicate isHidden() { none() } - - predicate isPrivate() { none() } - - predicate isPublic() { none() } - - predicate isStatic() { none() } -} diff --git a/powershell/ql/lib/semmle/code/powershell/ModuleManifest.qll b/powershell/ql/lib/semmle/code/powershell/ModuleManifest.qll deleted file mode 100644 index 691216d391d3..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/ModuleManifest.qll +++ /dev/null @@ -1,44 +0,0 @@ -import powershell - -class ModuleManifestFile extends File { - ModuleManifestFile() { this.getExtension() = "psd1" } -} - -private Expr getEntry(HashTableExpr ht, string key) { - result = ht.getElementFromConstant(key).(CmdExpr).getExpr() and - not result instanceof ArrayLiteral -} - -private Expr getAnEntry(HashTableExpr ht, string key) { - exists(Expr e | e = ht.getElementFromConstant(key).(CmdExpr).getExpr() | - not e instanceof ArrayLiteral and result = e - or - result = e.(ArrayLiteral).getAnElement() - ) -} - -class ModuleManifest extends HashTableExpr { - string moduleVersion; - - ModuleManifest() { - // The hash table is in a .psd1 file - this.getLocation().getFile() instanceof ModuleManifestFile and - // It's at the top level of the file - this.getParent().(CmdExpr).getParent().(NamedBlock).getParent() instanceof TopLevel and - // It has a `ModuleVersion` entry. The only required field is ModuleVersion. - // https://learn.microsoft.com/en-us/powershell/scripting/developer/module/how-to-write-a-powershell-module-manifest?view=powershell-7.4#to-create-and-use-a-module-manifest - moduleVersion = getEntry(this, "ModuleVersion").getValue().asString() - } - - string getModuleVersion() { result = moduleVersion } - - string getModuleName() { - result + ".psd1" = this.getLocation().getFile().getBaseName() - } - - string getAFunctionToExport() { - result = getAnEntry(this, "FunctionsToExport").getValue().asString() - } - - string getACmdLetToExport() { result = getAnEntry(this, "CmdletsToExport").getValue().asString() } -} diff --git a/powershell/ql/lib/semmle/code/powershell/ObjectCreation.qll b/powershell/ql/lib/semmle/code/powershell/ObjectCreation.qll deleted file mode 100644 index ea3ed4f2239f..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/ObjectCreation.qll +++ /dev/null @@ -1,55 +0,0 @@ -import powershell - -abstract private class AbstractObjectCreation extends Call { - /** - * The type of the object being constructed. - * Note that the type may not exist in the database. - * - * Use `getConstructedTypeName` to get the name of the type (which will - * always exist in the database). - */ - abstract Type getConstructedType(); - - /** The name of the type of the object being constructed. */ - abstract string getConstructedTypeName(); -} - -/** - * An object creation from a call to a constructor. For example: - * ```powershell - * [System.IO.FileInfo]::new("C:\\file.txt") - * ``` - */ -class NewObjectCreation extends AbstractObjectCreation instanceof ConstructorCall { - final override Type getConstructedType() { result = ConstructorCall.super.getConstructedType() } - - final override string getConstructedTypeName() { - result = ConstructorCall.super.getConstructedTypeName() - } -} - -/** - * An object creation from a call to `New-Object`. For example: - * ```powershell - * New-Object -TypeName System.IO.FileInfo -ArgumentList "C:\\file.txt" - * ``` - */ -class DotNetObjectCreation extends AbstractObjectCreation instanceof Cmd { - DotNetObjectCreation() { this.getCommandName() = "New-Object" } - - final override Type getConstructedType() { none() } - - final override string getConstructedTypeName() { - // Either it's the named argument `TypeName` - result = Cmd.super.getNamedArgument("TypeName").(StringConstExpr).getValue().getValue() - or - // Or it's the first positional argument if that's the named argument - not Cmd.super.hasNamedArgument("TypeName") and - exists(StringConstExpr arg | arg = Cmd.super.getPositionalArgument(0) | - result = arg.getValue().getValue() and - not arg = Cmd.super.getNamedArgument(["ArgumentList", "Property"]) - ) - } -} - -final class ObjectCreation = AbstractObjectCreation; diff --git a/powershell/ql/lib/semmle/code/powershell/ParamBlock.qll b/powershell/ql/lib/semmle/code/powershell/ParamBlock.qll deleted file mode 100644 index 7c35517319b8..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/ParamBlock.qll +++ /dev/null @@ -1,21 +0,0 @@ -import powershell - -class ParamBlock extends @param_block, Ast { - override string toString() { result = "param(...)" } - - override SourceLocation getLocation() { param_block_location(this, result) } - - int getNumAttributes() { param_block(this, result, _) } - - int getNumParameters() { param_block(this, _, result) } - - Attribute getAttribute(int i) { param_block_attribute(this, i, result) } - - Attribute getAnAttribute() { result = this.getAttribute(_) } - - Parameter getParameter(int i) { result.hasParameterBlock(this, i) } - - Parameter getParameterExcludingPiplines(int i) { result.hasParameterBlockExcludingPipelines(this, i) } - - Parameter getAParameter() { result = this.getParameter(_) } -} diff --git a/powershell/ql/lib/semmle/code/powershell/Redirection.qll b/powershell/ql/lib/semmle/code/powershell/Redirection.qll deleted file mode 100644 index f2a31116f615..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/Redirection.qll +++ /dev/null @@ -1,3 +0,0 @@ -import powershell - -class Redirection extends @redirection, Ast { } diff --git a/powershell/ql/lib/semmle/code/powershell/SplitExpr.qll b/powershell/ql/lib/semmle/code/powershell/SplitExpr.qll deleted file mode 100644 index f7c5df7fde99..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/SplitExpr.qll +++ /dev/null @@ -1,28 +0,0 @@ -import powershell - -abstract private class AbstractSplitExpr extends Expr { - abstract Expr getExpr(); - - /** ..., if any. */ - Expr getSeparator() { none() } -} - -final class SplitExpr = AbstractSplitExpr; - -class UnarySplitExpr extends AbstractSplitExpr, UnaryExpr { - UnarySplitExpr() { this.getKind() = 75 } - - final override string toString() { result = "-split ..." } - - final override Expr getExpr() { result = this.getOperand() } -} - -class BinarySplitExpr extends AbstractSplitExpr, BinaryExpr { - BinarySplitExpr() { this.getKind() = 75 } - - final override string toString() { result = "... -split ..." } - - final override Expr getExpr() { result = this.getLeft() } - - final override Expr getSeparator() { result = this.getRight() } -} diff --git a/powershell/ql/lib/semmle/code/powershell/TrapStatement.qll b/powershell/ql/lib/semmle/code/powershell/TrapStatement.qll deleted file mode 100644 index 34da4d2e111e..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/TrapStatement.qll +++ /dev/null @@ -1,7 +0,0 @@ -import powershell - -class TrapStmt extends @trap_statement, Stmt { - override SourceLocation getLocation() { trap_statement_location(this, result) } - - override string toString() { result = "TrapStatement at: " + this.getLocation().toString() } -} diff --git a/powershell/ql/lib/semmle/code/powershell/UsingExpression.qll b/powershell/ql/lib/semmle/code/powershell/UsingExpression.qll deleted file mode 100644 index 6c2e4eff62f0..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/UsingExpression.qll +++ /dev/null @@ -1,7 +0,0 @@ -import powershell - -class UsingExpr extends @using_expression, Expr { - override string toString() { result = "$using..." } - - override SourceLocation getLocation() { using_expression_location(this, result) } -} diff --git a/powershell/ql/lib/semmle/code/powershell/Variable.qll b/powershell/ql/lib/semmle/code/powershell/Variable.qll deleted file mode 100644 index f5cb7259e0e5..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/Variable.qll +++ /dev/null @@ -1,406 +0,0 @@ -private import powershell -private import semmle.code.powershell.controlflow.internal.Scope -private import internal.Parameter::Private as Internal - -private predicate isFunctionParameterImpl(Internal::Parameter p, Function f, int i) { - function_definition_parameter(f, i, p) -} - -private predicate hasParameterBlockImpl(Internal::Parameter p, ParamBlock block, int i) { - param_block_parameter(block, i, p) -} - -private predicate hasParameterBlockExcludingPipelinesImpl( - Internal::Parameter p, ParamBlock block, int i -) { - p = - rank[i + 1](Internal::Parameter cand, int j | - hasParameterBlockImpl(cand, block, j) and - not cand.getAnAttribute().(Attribute).getANamedArgument() instanceof - ValueFromPipelineAttribute and - not cand.getAnAttribute().(Attribute).getANamedArgument() instanceof - ValueFromPipelineByPropertyName - | - cand order by j - ) -} - -/** - * Gets the enclosing scope of `p`. - * - * For a function parameter, this is the function body. For a parameter from a - * parameter block, this is the enclosing scope of the parameter block. - * - * In both of the above cases, the enclosing scope is the function body. - */ -private Scope getEnclosingScopeImpl(Internal::Parameter p) { - exists(Function f | - isFunctionParameterImpl(p, f, _) and - result = f.getBody() - ) - or - exists(ParamBlock b | - hasParameterBlockImpl(p, b, _) and - result = b.getEnclosingScope() - ) -} - -bindingset[scope] -pragma[inline_late] -private predicate isParameterImpl(string name, Scope scope) { - exists(Internal::Parameter p | p.getName() = name and getEnclosingScopeImpl(p) = scope) - or - name = "_" -} - -private predicate isThisParameter(Scope scope, Type t) { - t = scope.getEnclosingFunction().getDeclaringType() -} - -private newtype TParameterImpl = - TInternalParameter(Internal::Parameter p) or - TUnderscore(Scope scope) { - exists(VarAccess va | va.getUserPath() = ["_", "PSItem"] and scope = va.getEnclosingScope()) - } or - TThisParameter(Scope scope) { isThisParameter(scope, _) } - -private class ParameterImpl extends TParameterImpl { - abstract Location getLocation(); - - string toString() { result = this.getName() } - - abstract string getName(); - - abstract Scope getEnclosingScope(); - - predicate hasParameterBlock(ParamBlock block, int i) { none() } - - predicate hasParameterBlockExcludingPipelines(ParamBlock block, int i) { none() } - - predicate isFunctionParameter(Function f, int i) { none() } - - Expr getDefaultValue() { none() } - - abstract Attribute getAnAttribute(); - - VarAccess getAnAccess() { - // TODO: This won't join order nicely. - result.getUserPath() = this.getName() and - result.getEnclosingScope() = this.getEnclosingScope() - } - - abstract predicate isPipeline(); - - abstract predicate isPipelineByPropertyName(); - - /** - * Gets the static type of this parameter. - * The type of this parameter at runtime may be a subtype of this static - * type. - */ - abstract string getStaticType(); -} - -private class InternalParameter extends ParameterImpl, TInternalParameter { - Internal::Parameter p; - - InternalParameter() { this = TInternalParameter(p) } - - override Location getLocation() { result = p.getLocation() } - - override string getName() { result = p.getName() } - - final override Scope getEnclosingScope() { result = getEnclosingScopeImpl(p) } - - override predicate hasParameterBlock(ParamBlock block, int i) { - hasParameterBlockImpl(p, block, i) - } - - override predicate hasParameterBlockExcludingPipelines(ParamBlock block, int i) { - hasParameterBlockExcludingPipelinesImpl(p, block, i) - } - - override predicate isFunctionParameter(Function f, int i) { isFunctionParameterImpl(p, f, i) } - - override Expr getDefaultValue() { result = p.getDefaultValue() } - - override Attribute getAnAttribute() { result = p.getAnAttribute() } - - override predicate isPipeline() { - this.getAnAttribute().getANamedArgument() instanceof ValueFromPipelineAttribute - } - - override predicate isPipelineByPropertyName() { - this.getAnAttribute().getANamedArgument() instanceof ValueFromPipelineByPropertyName - } - - final override string getStaticType() { result = p.getStaticType() } -} - -/** - * The variable that represents an element in the pipeline. - * - * This is either the variable `$_` or the variable `$PSItem`. - */ -private class Underscore extends ParameterImpl, TUnderscore { - Scope scope; - - Underscore() { this = TUnderscore(scope) } - - override Location getLocation() { - // The location is the first access (ordered by location) to the variable in the scope - exists(VarAccess va | - va = - min(VarAccess cand, Location location | - cand = this.getAnAccess() and location = cand.getLocation() - | - cand order by location.getStartLine(), location.getStartColumn() - ) and - result = va.getLocation() - ) - } - - override string getName() { result = "_" } - - final override Scope getEnclosingScope() { result = scope } - - final override Attribute getAnAttribute() { none() } - - final override predicate isPipeline() { any() } - - final override predicate isPipelineByPropertyName() { none() } - - final override predicate isFunctionParameter(Function f, int i) { f.getBody() = scope and i = -1 } - - final override string getStaticType() { none() } -} - -private class ThisParameter extends ParameterImpl, TThisParameter { - Scope scope; - - ThisParameter() { this = TThisParameter(scope) } - - override Location getLocation() { result = scope.getLocation() } - - override string getName() { result = "this" } - - final override Scope getEnclosingScope() { result = scope } - - final override Attribute getAnAttribute() { none() } - - final override predicate isPipeline() { none() } - - final override predicate isPipelineByPropertyName() { none() } - - final override string getStaticType() { - exists(Type t | - isThisParameter(scope, t) and - result = t.getName() - ) - } -} - -private predicate isPipelineIteratorVariable(ParameterImpl p, ProcessBlock pb) { - p.isPipeline() and - pb.getEnclosingScope() = p.getEnclosingScope() -} - -private predicate isPipelineByPropertyNameIteratorVariable(ParameterImpl p, ProcessBlock pb) { - p.isPipelineByPropertyName() and - pb.getEnclosingScope() = p.getEnclosingScope() -} - -private newtype TVariable = - TLocalVariable(string name, Scope scope) { - not isParameterImpl(name, scope) and - not name = "this" and // This is modeled as a parameter - exists(VarAccess va | va.getUserPath() = name and scope = va.getEnclosingScope()) - } or - TParameter(ParameterImpl p) or - TPipelineIteratorVariable(ProcessBlock pb) { isPipelineIteratorVariable(_, pb) } or - TPipelineByPropertyNameIteratorVariable(ParameterImpl p) { - isPipelineByPropertyNameIteratorVariable(p, _) - } - -private class AbstractVariable extends TVariable { - abstract Location getLocation(); - - string toString() { result = this.getName() } - - abstract string getName(); - - final predicate hasName(string s) { this.getName() = s } - - abstract Scope getDeclaringScope(); - - VarAccess getAnAccess() { - exists(string s | - s = concat(this.getAQlClass(), ", ") and - // TODO: This won't join order nicely. - result.getUserPath() = this.getName() and - result.getEnclosingScope() = this.getDeclaringScope() - ) - } -} - -final class Variable = AbstractVariable; - -abstract class AbstractLocalScopeVariable extends AbstractVariable { } - -final class LocalScopeVariable = AbstractLocalScopeVariable; - -class LocalVariable extends AbstractLocalScopeVariable, TLocalVariable { - string name; - Scope scope; - - LocalVariable() { this = TLocalVariable(name, scope) } - - override Location getLocation() { - // The location is the first access (ordered by location) to the variable in the scope - exists(VarAccess va | - va = - min(VarAccess cand, Location location | - cand = this.getAnAccess() and location = cand.getLocation() - | - cand order by location.getStartLine(), location.getStartColumn() - ) and - result = va.getLocation() - ) - } - - override string getName() { result = name } - - final override Scope getDeclaringScope() { result = scope } -} - -/** - * A variable of the form `$Env:HOME`. - */ -class EnvVariable extends Variable { - string var; - - EnvVariable() { this.getName() = ["env:", "Env:"] + var } - - /** - * Gets the part of the variable name that represens which environment - * variable. - */ - string getEnvironmentVariable() { result = var } -} - -class Parameter extends AbstractLocalScopeVariable, TParameter { - ParameterImpl p; - - Parameter() { this = TParameter(p) } - - override Location getLocation() { result = p.getLocation() } - - override string getName() { result = p.getName() } - - final predicate hasName(string name) { name = p.getName() } - - final override Scope getDeclaringScope() { result = p.getEnclosingScope() } - - predicate hasParameterBlock(ParamBlock block, int i) { p.hasParameterBlock(block, i) } - - predicate hasParameterBlockExcludingPipelines(ParamBlock block, int i) { - p.hasParameterBlockExcludingPipelines(block, i) - } - - predicate isFunctionParameter(Function f, int i) { p.isFunctionParameter(f, i) } - - Expr getDefaultValue() { result = p.getDefaultValue() } - - predicate hasDefaultValue() { exists(this.getDefaultValue()) } - - /** Holds if this is the `this` parameter. */ - predicate isThis() { p instanceof ThisParameter } - - /** - * Gets the index of this parameter, if any. - * - * The parameter may be in a parameter block or a function parameter. - */ - int getIndex() { result = this.getFunctionIndex() or result = this.getBlockIndex() } - - int getIndexExcludingPipelines() { - result = this.getFunctionIndex() or result = this.getBlockIndexExcludingPipelines() - } - - /** Gets the index of this parameter in the parameter block, if any. */ - int getBlockIndex() { this.hasParameterBlock(_, result) } - - int getBlockIndexExcludingPipelines() { this.hasParameterBlockExcludingPipelines(_, result) } - - /** Gets the index of this parameter in the function, if any. */ - int getFunctionIndex() { this.isFunctionParameter(_, result) } - - Function getFunction() { result.getBody() = this.getDeclaringScope() } - - Attribute getAnAttribute() { result = p.getAnAttribute() } - - predicate isPipeline() { p.isPipeline() } - - predicate isPipelineByPropertyName() { p.isPipelineByPropertyName() } - - string getStaticType() { result = p.getStaticType() } -} - -class PipelineParameter extends Parameter { - PipelineParameter() { this.isPipeline() } - - PipelineIteratorVariable getIteratorVariable() { - result.getProcessBlock().getEnclosingScope() = p.getEnclosingScope() - } -} - -class PipelineByPropertyNameParameter extends Parameter { - PipelineByPropertyNameParameter() { this.isPipelineByPropertyName() } - - PipelineByPropertyNameIteratorVariable getIteratorVariable() { result.getParameter() = this } -} - -/** - * The variable that represents the value of a pipeline during a process block. - * - * That is, it is _not_ the `ValueFromPipeline` variable, but the value that is obtained by reading - * from the pipeline. - */ -class PipelineIteratorVariable extends AbstractLocalScopeVariable, TPipelineIteratorVariable { - private ProcessBlock pb; - - PipelineIteratorVariable() { this = TPipelineIteratorVariable(pb) } - - override Location getLocation() { result = pb.getLocation() } - - override string getName() { result = "pipeline iterator for " + pb.toString() } - - final override Scope getDeclaringScope() { result = pb.getEnclosingScope() } - - ProcessBlock getProcessBlock() { result = pb } -} - -/** - * The variable that represents the value of a pipeline that picks out a - * property specific property during a process block. - * - * That is, it is _not_ the `PipelineByPropertyName` variable, but the value that is obtained by reading - * from the pipeline. - */ -class PipelineByPropertyNameIteratorVariable extends AbstractLocalScopeVariable, - TPipelineByPropertyNameIteratorVariable -{ - private ParameterImpl p; - - PipelineByPropertyNameIteratorVariable() { this = TPipelineByPropertyNameIteratorVariable(p) } - - override Location getLocation() { result = p.getLocation() } - - override string getName() { result = "pipeline iterator for " + p.toString() } - - final override Scope getDeclaringScope() { result = p.getEnclosingScope() } - - Parameter getParameter() { result = TParameter(p) } - - ProcessBlock getProcessBlock() { isPipelineByPropertyNameIteratorVariable(p, result) } -} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/Ast.qll b/powershell/ql/lib/semmle/code/powershell/ast/Ast.qll new file mode 100644 index 000000000000..f32a9982b51f --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/Ast.qll @@ -0,0 +1 @@ +import internal.Internal::Public \ No newline at end of file diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/ArrayExpression.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/ArrayExpression.qll new file mode 100644 index 000000000000..ae418c4d5117 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/ArrayExpression.qll @@ -0,0 +1,37 @@ +private import AstImport + +class ArrayExpr extends Expr, TArrayExpr { + StmtBlock getStmtBlock() { + exists(Raw::Ast r | r = getRawAst(this) | + synthChild(r, arrayExprStmtBlock(), result) + or + not synthChild(r, arrayExprStmtBlock(), result) and + result = getResultAst(r.(Raw::ArrayExpr).getStmtBlock()) + ) + } + + override string toString() { result = "@(...)" } + + final override Ast getChild(ChildIndex i) { + result = super.getChild(i) + or + i = arrayExprStmtBlock() and result = this.getStmtBlock() + } + + /** + * Gets the i'th element of this `ArrayExpr`, if this can be determined statically. + * + * See `getStmtBlock` when the array elements are not known statically. + */ + Expr getExpr(int i) { + result = + unique( | | this.getStmtBlock().getAStmt()).(ExprStmt).getExpr().(ArrayLiteral).getExpr(i) + } + + /** + * Gets an element of this `ArrayExpr`, if this can be determined statically. + * + * See `getStmtBlock` when the array elements are not known statically. + */ + Expr getAnExpr() { result = this.getExpr(_) } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/ArrayLiteral.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/ArrayLiteral.qll new file mode 100644 index 000000000000..21427948b8ec --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/ArrayLiteral.qll @@ -0,0 +1,25 @@ +private import AstImport + +class ArrayLiteral extends Expr, TArrayLiteral { + Expr getExpr(int index) { + exists(ChildIndex i, Raw::Ast r | i = arrayLiteralExpr(index) and r = getRawAst(this) | + synthChild(r, i, result) + or + not synthChild(r, i, _) and + result = getResultAst(r.(Raw::ArrayLiteral).getElement(index)) + ) + } + + Expr getAnExpr() { result = this.getExpr(_) } + + override string toString() { result = "...,..." } + + final override Ast getChild(ChildIndex i) { + result = super.getChild(i) + or + exists(int index | + i = arrayLiteralExpr(index) and + result = this.getExpr(index) + ) + } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/AssignmentStatement.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/AssignmentStatement.qll new file mode 100644 index 000000000000..6f4cb8d2fbfe --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/AssignmentStatement.qll @@ -0,0 +1,33 @@ +private import AstImport + +class AssignStmt extends Stmt, TAssignStmt { + Expr getRightHandSide() { + exists(Raw::Ast r | r = getRawAst(this) | + synthChild(r, assignStmtRightHandSide(), result) + or + not synthChild(r, assignStmtRightHandSide(), _) and + result = getResultAst(r.(Raw::AssignStmt).getRightHandSide()) + ) + } + + Expr getLeftHandSide() { + exists(Raw::Ast r | r = getRawAst(this) | + synthChild(r, assignStmtLeftHandSide(), result) + or + not synthChild(r, assignStmtLeftHandSide(), _) and + result = getResultAst(r.(Raw::AssignStmt).getLeftHandSide()) + ) + } + + override Ast getChild(ChildIndex i) { + result = super.getChild(i) + or + i = assignStmtLeftHandSide() and + result = this.getLeftHandSide() + or + i = assignStmtRightHandSide() and + result = this.getRightHandSide() + } + + override string toString() { result = "...=..." } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Ast.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Ast.qll new file mode 100644 index 000000000000..78d1d97876c8 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Ast.qll @@ -0,0 +1,37 @@ +private import AstImport + +class Ast extends TAst { + string toString() { none() } + + final Ast getParent() { result.getChild(_) = this } + + Location getLocation() { + result = getRawAst(this).getLocation() + or + result = any(Synthesis s).getLocation(this) + } + + Ast getChild(ChildIndex i) { + exists(Raw::Ast r | r = getRawAst(this) | + synthChild(r, i, result) + or + exists(string name | + i = RealVar(name) and + result = TVariableReal(r, name, _) + ) + ) + } + + final Ast getAChild() { result = this.getChild(_) } + + Scope getEnclosingScope() { result = scopeOf(this) } // TODO: Scope of synth? + + Function getEnclosingFunction() { + exists(Scope scope | scope = scopeOf(this) | + result.getBody() = scope + or + not scope instanceof ScriptBlock and + result = scope.getEnclosingFunction() + ) + } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/AstImport.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/AstImport.qll new file mode 100644 index 000000000000..88f3720c7962 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/AstImport.qll @@ -0,0 +1,5 @@ +import TAst +import Raw.Raw as Raw +import Internal::Private +import Internal::Public +import Synthesis diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Attribute.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Attribute.qll new file mode 100644 index 000000000000..87d70a7f18c0 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Attribute.qll @@ -0,0 +1,58 @@ +private import AstImport + +class Attribute extends AttributeBase, TAttribute { + string getName() { result = getRawAst(this).(Raw::Attribute).getName() } + + NamedAttributeArgument getNamedArgument(int i) { + exists(ChildIndex index, Raw::Ast r | index = attributeNamedArg(i) and r = getRawAst(this) | + synthChild(r, attributeNamedArg(i), result) + or + not synthChild(r, index, _) and + result = getResultAst(r.(Raw::Attribute).getNamedArgument(i)) + ) + } + + NamedAttributeArgument getANamedArgument() { result = this.getNamedArgument(_) } + + int getNumberOfArguments() { result = count(this.getAPositionalArgument()) } + + Expr getPositionalArgument(int i) { + exists(ChildIndex index, Raw::Ast r | index = attributePosArg(i) and r = getRawAst(this) | + synthChild(r, index, result) + or + not synthChild(r, index, _) and + result = getResultAst(r.(Raw::Attribute).getPositionalArgument(i)) + ) + } + + Expr getAPositionalArgument() { result = this.getPositionalArgument(_) } + + int getNumberOfPositionalArguments() { result = count(this.getAPositionalArgument()) } + + private string toStringSpecific() { + not exists(this.getAPositionalArgument()) and + result = unique( | | this.getANamedArgument()).getName() + or + not exists(this.getANamedArgument()) and + result = unique( | | this.getANamedArgument()).getName() + } + + override string toString() { + result = this.toStringSpecific() + or + not exists(this.toStringSpecific()) and + result = this.getName() + } + + final override Ast getChild(ChildIndex i) { + result = super.getChild(i) + or + exists(int index | + i = attributeNamedArg(index) and + result = this.getNamedArgument(index) + or + i = attributePosArg(index) and + result = this.getPositionalArgument(index) + ) + } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/AttributeBase.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/AttributeBase.qll new file mode 100644 index 000000000000..dbb261664be0 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/AttributeBase.qll @@ -0,0 +1,3 @@ +private import AstImport + +class AttributeBase extends Ast, TAttributeBase { } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/AttributedExpr.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/AttributedExpr.qll new file mode 100644 index 000000000000..cb8f2c7021bd --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/AttributedExpr.qll @@ -0,0 +1,32 @@ +private import AstImport + +class AttributedExpr extends AttributedExprBase, TAttributedExpr { + final override string toString() { result = "[...]" + this.getExpr().toString() } + + final override Expr getExpr() { + exists(Raw::Ast r | r = getRawAst(this) | + synthChild(r, attributedExprExpr(), result) + or + not synthChild(r, attributedExprExpr(), _) and + result = getResultAst(r.(Raw::AttributedExpr).getExpr()) + ) + } + + final override Attribute getAttribute() { + exists(Raw::Ast r | r = getRawAst(this) | + synthChild(r, attributedExprAttr(), result) + or + not synthChild(r, attributedExprAttr(), _) and + result = getResultAst(r.(Raw::AttributedExpr).getAttribute()) + ) + } + + override Ast getChild(ChildIndex i) { + result = super.getChild(i) + or + i = attributedExprExpr() and result = this.getExpr() + or + i = attributedExprAttr() and + result = this.getAttribute() + } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/AttributedExprBase.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/AttributedExprBase.qll new file mode 100644 index 000000000000..488e113577d6 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/AttributedExprBase.qll @@ -0,0 +1,7 @@ +private import AstImport + +class AttributedExprBase extends Expr, TAttributedExprBase { + Expr getExpr() { none() } + + AttributeBase getAttribute() { none() } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/AutomaticVariable.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/AutomaticVariable.qll new file mode 100644 index 000000000000..4196280a638a --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/AutomaticVariable.qll @@ -0,0 +1,11 @@ +private import AstImport + +class AutomaticVariable extends Expr, TAutomaticVariable { + final override string toString() { result = this.getName() } + + string getName() { any(Synthesis s).automaticVariableName(this, result) } +} + +class MyInvocation extends AutomaticVariable { + MyInvocation() { this.getName() = "myinvocation" } +} diff --git a/powershell/ql/lib/semmle/code/powershell/BinaryExpression.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/BinaryExpression.qll similarity index 90% rename from powershell/ql/lib/semmle/code/powershell/BinaryExpression.qll rename to powershell/ql/lib/semmle/code/powershell/ast/internal/BinaryExpression.qll index 7e7d4011b7f9..f40eba8a30a2 100644 --- a/powershell/ql/lib/semmle/code/powershell/BinaryExpression.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/BinaryExpression.qll @@ -1,29 +1,38 @@ -import powershell +private import AstImport + +class BinaryExpr extends Expr, TBinaryExpr { + /** INTERNAL: Do not use. */ + int getKind() { result = getRawAst(this).(Raw::BinaryExpr).getKind() } + + Expr getLeft() { + exists(Raw::Ast r | r = getRawAst(this) | + synthChild(r, binaryExprLeft(), result) + or + not synthChild(r, binaryExprLeft(), _) and + result = getResultAst(r.(Raw::BinaryExpr).getLeft()) + ) + } -class BinaryExpr extends @binary_expression, Expr { - override SourceLocation getLocation() { binary_expression_location(this, result) } + Expr getRight() { + exists(Raw::Ast r | r = getRawAst(this) | + synthChild(r, binaryExprRight(), result) + or + not synthChild(r, binaryExprRight(), _) and + result = getResultAst(r.(Raw::BinaryExpr).getRight()) + ) + } - int getKind() { binary_expression(this, result, _, _) } + Expr getAnOperand() { result = this.getLeft() or result = this.getRight() } - /** Gets an operand of this binary expression. */ - Expr getAnOperand() { + final override Ast getChild(ChildIndex i) { + result = super.getChild(i) + or + i = binaryExprLeft() and result = this.getLeft() or + i = binaryExprRight() and result = this.getRight() } - - /** Holds if this binary expression has the operands `e1` and `e2`. */ - predicate hasOperands(Expr e1, Expr e2) { - e1 = this.getLeft() and - e2 = this.getRight() - or - e1 = this.getRight() and - e2 = this.getLeft() - } - - Expr getLeft() { binary_expression(this, _, result, _) } - - Expr getRight() { binary_expression(this, _, _, result) } } abstract private class AbstractArithmeticExpr extends BinaryExpr { } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/BoolLiteral.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/BoolLiteral.qll new file mode 100644 index 000000000000..36fef4912da7 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/BoolLiteral.qll @@ -0,0 +1,9 @@ +private import AstImport + +class BoolLiteral extends Literal, TBoolLiteral { + final override string toString() { result = this.getValue().toString() } + + final override ConstantValue getValue() { result.asBoolean() = this.getBoolValue() } + + boolean getBoolValue() { any(Synthesis s).booleanValue(this, result) } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/BreakStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/BreakStmt.qll new file mode 100644 index 000000000000..f04899c3e81a --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/BreakStmt.qll @@ -0,0 +1,5 @@ +private import AstImport + +class BreakStmt extends GotoStmt, TBreakStmt { + override string toString() { result = "break" } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/CallExpr.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/CallExpr.qll new file mode 100644 index 000000000000..96659f6cda24 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/CallExpr.qll @@ -0,0 +1,54 @@ +private import AstImport + +class CallExpr extends Expr, TCallExpr { + /** Gets the i'th argument to this call. */ + Expr getArgument(int i) { none() } + + /** Gets the name that is used to select the callee. */ + string getName() { none() } + + /** Gets the i'th positional argument to this call. */ + Expr getPositionalArgument(int i) { none() } + + /** + * Gets the expression that represents the callee. That is, the expression + * that computes the target of the call. + */ + Expr getCallee() { none() } + + /** Holds if an argument with name `name` is provided to this call. */ + final predicate hasNamedArgument(string name) { exists(this.getNamedArgument(name)) } + + /** Gets the argument to this call with the name `name`. */ + Expr getNamedArgument(string name) { none() } + + /** Gets any argument to this call. */ + final Expr getAnArgument() { result = this.getArgument(_) } + + /** Gets the qualifier of this call, if any. */ + Expr getQualifier() { none() } + + final override string toString() { result = "Call to " + this.getName() } + + predicate isStatic() { none() } +} + +class Argument extends Expr { + CallExpr call; + + Argument() { this = call.getAnArgument() } + + int getPosition() { this = call.getPositionalArgument(result) } + + string getName() { this = call.getNamedArgument(result) } + + CallExpr getCall() { result = call } +} + +class Qualifier extends Expr { + CallExpr call; + + Qualifier() { this = call.getQualifier() } + + CallExpr getCall() { result = call } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/CatchClause.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/CatchClause.qll new file mode 100644 index 000000000000..3504e0f055ba --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/CatchClause.qll @@ -0,0 +1,62 @@ +private import AstImport + +class CatchClause extends Ast, TCatchClause { + StmtBlock getBody() { + exists(Raw::Ast r | r = getRawAst(this) | + synthChild(r, catchClauseBody(), result) + or + not synthChild(r, catchClauseBody(), _) and + result = getResultAst(r.(Raw::CatchClause).getBody()) + ) + } + + final override Ast getChild(ChildIndex i) { + result = super.getChild(i) + or + i = catchClauseBody() and result = this.getBody() + or + exists(int index | + i = catchClauseType(index) and + result = this.getCatchType(index) + ) + } + + override string toString() { result = "catch {...}" } + + TryStmt getTryStmt() { result.getACatchClause() = this } + + predicate isLast() { + exists(TryStmt ts, int last | + ts = this.getTryStmt() and + last = max(int i | exists(ts.getCatchClause(i))) and + this = ts.getCatchClause(last) + ) + } + + TypeConstraint getCatchType(int i) { + exists(ChildIndex index, Raw::Ast r | index = catchClauseType(i) and r = getRawAst(this) | + synthChild(r, index, result) + or + not synthChild(r, index, _) and + result = getResultAst(r.(Raw::CatchClause).getCatchType(i)) + ) + } + + int getNumberOfCatchTypes() { result = count(this.getACatchType()) } + + TypeConstraint getACatchType() { result = this.getCatchType(_) } + + predicate isCatchAll() { not exists(this.getACatchType()) } +} + +class GeneralCatchClause extends CatchClause { + GeneralCatchClause() { this.isCatchAll() } + + override string toString() { result = "catch {...}" } +} + +class SpecificCatchClause extends CatchClause { + SpecificCatchClause() { not this.isCatchAll() } + + override string toString() { result = "catch[...] {...}" } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/ChildIndex.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/ChildIndex.qll new file mode 100644 index 000000000000..01eefb967621 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/ChildIndex.qll @@ -0,0 +1,267 @@ +private import Raw.Raw as Raw +private import Scopes +private import TAst + +newtype ChildIndex = + RawChildIndex(Raw::ChildIndex index) or + ParamPipeline() or + ParamDefaultVal() or + ParamAttr(int i) { exists(any(Raw::Parameter p).getAttribute(i)) } or + FunctionBody() or + ScriptBlockAttr(int i) { exists(any(Raw::ParamBlock sb).getAttribute(i)) } or + FunParam(int i) { + exists(any(Raw::ParamBlock pb).getParameter(i)) + or + exists(any(Raw::FunctionDefinitionStmt func).getParameter(i)) + or + // Synth an extra parameter index for a pipeline parameter if none is provided + exists(Raw::ParamBlock pb | + not pb.getAParameter() instanceof Raw::PipelineParameter and + i = pb.getNumParameters() + ) + } or + CmdArgument(int i) { exists(any(Raw::Cmd cmd).getArgument(i)) } or + ExprStmtExpr() or + MethodBody() or + ExprRedirection(int i) { exists(any(Raw::Cmd cmdExpr).getRedirection(i)) } or + FunDefFun() or + TypeDefType() or + TypeMember(int i) { + exists(any(Raw::TypeStmt typedef).getMember(i)) + // or + // hasMemberInType(_, _, i, _) + } or + ThisVar() or + PipelineParamVar() or + // PipelineByPropertNameVar(Raw::PipelineByPropertyNameParameter p) or + PipelineIteratorVar() or + PipelineByPropertyNameIteratorVar(Raw::PipelineByPropertyNameParameter p) or + RealVar(string name) { name = variableNameInScope(_, _) } + +int synthPipelineParameterChildIndex(Raw::ScriptBlock sb) { + exists(Raw::ParamBlock pb | + pb = sb.getParamBlock() and + not pb.getAParameter() instanceof Raw::PipelineParameter and + result = pb.getNumParameters() + ) +} + +Raw::ChildIndex toRawChildIndex(ChildIndex i) { i = RawChildIndex(result) } + +ChildIndex arrayExprStmtBlock() { result = RawChildIndex(Raw::ArrayExprStmtBlock()) } + +ChildIndex arrayLiteralExpr(int i) { result = RawChildIndex(Raw::ArrayLiteralExpr(i)) } + +ChildIndex assignStmtLeftHandSide() { result = RawChildIndex(Raw::AssignStmtLeftHandSide()) } + +ChildIndex assignStmtRightHandSide() { result = RawChildIndex(Raw::AssignStmtRightHandSide()) } + +ChildIndex memberAttr(int i) { result = RawChildIndex(Raw::MemberAttr(i)) } + +ChildIndex memberTypeConstraint() { result = RawChildIndex(Raw::MemberTypeConstraint()) } + +ChildIndex attributeNamedArg(int i) { result = RawChildIndex(Raw::AttributeNamedArg(i)) } + +ChildIndex attributePosArg(int i) { result = RawChildIndex(Raw::AttributePosArg(i)) } + +ChildIndex attributedExprExpr() { result = RawChildIndex(Raw::AttributedExprExpr()) } + +ChildIndex attributedExprAttr() { result = RawChildIndex(Raw::AttributedExprAttr()) } + +ChildIndex binaryExprLeft() { result = RawChildIndex(Raw::BinaryExprLeft()) } + +ChildIndex binaryExprRight() { result = RawChildIndex(Raw::BinaryExprRight()) } + +ChildIndex catchClauseBody() { result = RawChildIndex(Raw::CatchClauseBody()) } + +ChildIndex catchClauseType(int i) { result = RawChildIndex(Raw::CatchClauseType(i)) } + +ChildIndex cmdCallee() { result = RawChildIndex(Raw::CmdCallee()) } + +ChildIndex cmdArgument(int i) { result = CmdArgument(i) } + +ChildIndex cmdRedirection(int i) { result = RawChildIndex(Raw::CmdRedirection(i)) } + +ChildIndex cmdElement_(int i) { result = RawChildIndex(Raw::CmdElement_(i)) } + +ChildIndex cmdExprExpr() { result = RawChildIndex(Raw::CmdExprExpr()) } + +ChildIndex configurationName() { result = RawChildIndex(Raw::ConfigurationName()) } + +ChildIndex configurationBody() { result = RawChildIndex(Raw::ConfigurationBody()) } + +ChildIndex convertExprExpr() { result = RawChildIndex(Raw::ConvertExprExpr()) } + +ChildIndex convertExprType() { result = RawChildIndex(Raw::ConvertExprType()) } + +ChildIndex convertExprAttr() { result = RawChildIndex(Raw::ConvertExprAttr()) } + +ChildIndex dataStmtBody() { result = RawChildIndex(Raw::DataStmtBody()) } + +ChildIndex dataStmtCmdAllowed(int i) { result = RawChildIndex(Raw::DataStmtCmdAllowed(i)) } + +ChildIndex doUntilStmtCond() { result = RawChildIndex(Raw::DoUntilStmtCond()) } + +ChildIndex doUntilStmtBody() { result = RawChildIndex(Raw::DoUntilStmtBody()) } + +ChildIndex doWhileStmtCond() { result = RawChildIndex(Raw::DoWhileStmtCond()) } + +ChildIndex doWhileStmtBody() { result = RawChildIndex(Raw::DoWhileStmtBody()) } + +ChildIndex dynamicStmtName() { result = RawChildIndex(Raw::DynamicStmtName()) } + +ChildIndex dynamicStmtBody() { result = RawChildIndex(Raw::DynamicStmtBody()) } + +ChildIndex exprStmtExpr() { result = ExprStmtExpr() } + +ChildIndex exprRedirection(int i) { result = ExprRedirection(i) } + +ChildIndex exitStmtPipeline() { result = RawChildIndex(Raw::ExitStmtPipeline()) } + +ChildIndex expandableStringExprExpr(int i) { + result = RawChildIndex(Raw::ExpandableStringExprExpr(i)) +} + +ChildIndex forEachStmtVar() { result = RawChildIndex(Raw::ForEachStmtVar()) } + +ChildIndex forEachStmtIter() { result = RawChildIndex(Raw::ForEachStmtIter()) } + +ChildIndex forEachStmtBody() { result = RawChildIndex(Raw::ForEachStmtBody()) } + +ChildIndex forStmtInit() { result = RawChildIndex(Raw::ForStmtInit()) } + +ChildIndex forStmtCond() { result = RawChildIndex(Raw::ForStmtCond()) } + +ChildIndex forStmtIter() { result = RawChildIndex(Raw::ForStmtIter()) } + +ChildIndex forStmtBody() { result = RawChildIndex(Raw::ForStmtBody()) } + +ChildIndex functionBody() { result = FunctionBody() } + +ChildIndex funDefStmtBody() { result = RawChildIndex(Raw::FunDefStmtBody()) } + +ChildIndex funDefStmtParam(int i) { result = RawChildIndex(Raw::FunDefStmtParam(i)) } + +ChildIndex funDefFun() { result = FunDefFun() } + +ChildIndex typeDefType() { result = TypeDefType() } + +ChildIndex typeMember(int i) { result = TypeMember(i) } + +ChildIndex gotoStmtLabel() { result = RawChildIndex(Raw::GotoStmtLabel()) } + +ChildIndex hashTableExprKey(int i) { result = RawChildIndex(Raw::HashTableExprKey(i)) } + +ChildIndex hashTableExprStmt(int i) { result = RawChildIndex(Raw::HashTableExprStmt(i)) } + +ChildIndex ifStmtElse() { result = RawChildIndex(Raw::IfStmtElse()) } + +ChildIndex ifStmtCond(int i) { result = RawChildIndex(Raw::IfStmtCond(i)) } + +ChildIndex ifStmtThen(int i) { result = RawChildIndex(Raw::IfStmtThen(i)) } + +ChildIndex indexExprIndex() { result = RawChildIndex(Raw::IndexExprIndex()) } + +ChildIndex indexExprBase() { result = RawChildIndex(Raw::IndexExprBase()) } + +ChildIndex invokeMemberExprQual() { result = RawChildIndex(Raw::InvokeMemberExprQual()) } + +ChildIndex invokeMemberExprCallee() { result = RawChildIndex(Raw::InvokeMemberExprCallee()) } + +ChildIndex invokeMemberExprArg(int i) { result = RawChildIndex(Raw::InvokeMemberExprArg(i)) } + +ChildIndex memberExprQual() { result = RawChildIndex(Raw::MemberExprQual()) } + +ChildIndex memberExprMember() { result = RawChildIndex(Raw::MemberExprMember()) } + +ChildIndex methodBody() { result = MethodBody() } + +ChildIndex namedAttributeArgVal() { result = RawChildIndex(Raw::NamedAttributeArgVal()) } + +ChildIndex namedBlockStmt(int i) { result = RawChildIndex(Raw::NamedBlockStmt(i)) } + +ChildIndex namedBlockTrap(int i) { result = RawChildIndex(Raw::NamedBlockTrap(i)) } + +ChildIndex paramBlockAttr(int i) { result = RawChildIndex(Raw::ParamBlockAttr(i)) } + +ChildIndex paramBlockParam(int i) { result = RawChildIndex(Raw::ParamBlockParam(i)) } + +ChildIndex paramAttr(int i) { result = ParamAttr(i) } + +ChildIndex paramDefaultVal() { result = ParamDefaultVal() } + +ChildIndex parenExprExpr() { result = RawChildIndex(Raw::ParenExprExpr()) } + +ChildIndex pipelineComp(int i) { result = RawChildIndex(Raw::PipelineComp(i)) } + +ChildIndex pipelineChainLeft() { result = RawChildIndex(Raw::PipelineChainLeft()) } + +ChildIndex pipelineChainRight() { result = RawChildIndex(Raw::PipelineChainRight()) } + +ChildIndex returnStmtPipeline() { result = RawChildIndex(Raw::ReturnStmtPipeline()) } + +ChildIndex scriptBlockUsing(int i) { result = RawChildIndex(Raw::ScriptBlockUsing(i)) } + +ChildIndex scriptBlockParamBlock() { result = RawChildIndex(Raw::ScriptBlockParamBlock()) } + +ChildIndex scriptBlockBeginBlock() { result = RawChildIndex(Raw::ScriptBlockBeginBlock()) } + +ChildIndex scriptBlockCleanBlock() { result = RawChildIndex(Raw::ScriptBlockCleanBlock()) } + +ChildIndex scriptBlockDynParamBlock() { result = RawChildIndex(Raw::ScriptBlockDynParamBlock()) } + +ChildIndex scriptBlockEndBlock() { result = RawChildIndex(Raw::ScriptBlockEndBlock()) } + +ChildIndex scriptBlockProcessBlock() { result = RawChildIndex(Raw::ScriptBlockProcessBlock()) } + +ChildIndex scriptBlockExprBody() { result = RawChildIndex(Raw::ScriptBlockExprBody()) } + +ChildIndex scriptBlockAttr(int i) { result = ScriptBlockAttr(i) } + +ChildIndex trapStmtBody() { result = RawChildIndex(Raw::TrapStmtBody()) } + +ChildIndex trapStmtTypeConstraint() { result = RawChildIndex(Raw::TrapStmtTypeConstraint()) } + +ChildIndex redirectionExpr() { result = RawChildIndex(Raw::RedirectionExpr()) } + +ChildIndex funParam(int i) { result = FunParam(i) } + +ChildIndex stmtBlockStmt(int i) { result = RawChildIndex(Raw::StmtBlockStmt(i)) } + +ChildIndex stmtBlockTrapStmt(int i) { result = RawChildIndex(Raw::StmtBlockTrapStmt(i)) } + +ChildIndex expandableSubExprExpr() { result = RawChildIndex(Raw::ExpandableSubExprExpr()) } + +ChildIndex switchStmtCond() { result = RawChildIndex(Raw::SwitchStmtCond()) } + +ChildIndex switchStmtDefault() { result = RawChildIndex(Raw::SwitchStmtDefault()) } + +ChildIndex switchStmtCase(int i) { result = RawChildIndex(Raw::SwitchStmtCase(i)) } + +ChildIndex switchStmtPat(int i) { result = RawChildIndex(Raw::SwitchStmtPat(i)) } + +ChildIndex condExprCond() { result = RawChildIndex(Raw::CondExprCond()) } + +ChildIndex condExprTrue() { result = RawChildIndex(Raw::CondExprTrue()) } + +ChildIndex condExprFalse() { result = RawChildIndex(Raw::CondExprFalse()) } + +ChildIndex throwStmtPipeline() { result = RawChildIndex(Raw::ThrowStmtPipeline()) } + +ChildIndex tryStmtBody() { result = RawChildIndex(Raw::TryStmtBody()) } + +ChildIndex tryStmtCatchClause(int i) { result = RawChildIndex(Raw::TryStmtCatchClause(i)) } + +ChildIndex tryStmtFinally() { result = RawChildIndex(Raw::TryStmtFinally()) } + +ChildIndex typeStmtMember(int i) { result = RawChildIndex(Raw::TypeStmtMember(i)) } + +ChildIndex typeStmtBaseType(int i) { result = RawChildIndex(Raw::TypeStmtBaseType(i)) } + +ChildIndex unaryExprOp() { result = RawChildIndex(Raw::UnaryExprOp()) } + +ChildIndex usingExprExpr() { result = RawChildIndex(Raw::UsingExprExpr()) } + +ChildIndex whileStmtCond() { result = RawChildIndex(Raw::WhileStmtCond()) } + +ChildIndex whileStmtBody() { result = RawChildIndex(Raw::WhileStmtBody()) } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Command.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Command.qll new file mode 100644 index 000000000000..fb8b93ff9c15 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Command.qll @@ -0,0 +1,147 @@ +private import AstImport + +class CmdCall extends CallExpr, TCmd { + final override string getName() { result = getRawAst(this).(Raw::Cmd).getCommandName() } + + final override Expr getArgument(int i) { synthChild(getRawAst(this), cmdArgument(i), result) } + + final override Expr getCallee() { + exists(Raw::Ast r | r = getRawAst(this) | + synthChild(r, cmdCallee(), result) + or + not synthChild(r, cmdCallee(), _) and + result = getResultAst(r.(Raw::Cmd).getCallee()) + ) + } + + private predicate isNamedArgument(int i, string name) { + any(Synthesis s).isNamedArgument(this, i, name) + } + + private predicate isPositionalArgument(int i) { + exists(this.getArgument(i)) and + not this.isNamedArgument(i, _) + } + + /** Gets the `i`th positional argument to this command. */ + final override Expr getPositionalArgument(int i) { + result = + rank[i + 1](Expr e, int k | + this.isPositionalArgument(k) and e = this.getArgument(k) + | + e order by k + ) + } + + /** Holds if this call has an argument named `name`. */ + predicate hasNamedArgument(string name) { exists(this.getNamedArgument(name)) } + + /** Gets the named argument with the given name. */ + final override Expr getNamedArgument(string name) { + exists(int i | + result = this.getArgument(i) and + this.isNamedArgument(i, name) + ) + } + + override Redirection getRedirection(int i) { + // TODO: Is this weird given that there's also another redirection on Expr? + exists(ChildIndex index, Raw::Ast r | index = cmdRedirection(i) and r = getRawAst(this) | + synthChild(r, index, result) + or + not synthChild(r, index, _) and + result = getResultAst(r.(Raw::Cmd).getRedirection(i)) + ) + } + + final override Ast getChild(ChildIndex i) { + result = super.getChild(i) + or + i = cmdCallee() and + result = this.getCallee() + or + exists(int index | + i = cmdArgument(index) and + result = this.getArgument(index) + or + i = cmdRedirection(index) and + result = this.getRedirection(index) + ) + } +} + +/** A call to operator `&`. */ +class CallOperator extends CmdCall { + CallOperator() { getRawAst(this) instanceof Raw::CallOperator } + + Expr getCommand() { result = this.getArgument(0) } +} + +/** A call to the dot-sourcing `.`. */ +class DotSourcingOperator extends CmdCall { + DotSourcingOperator() { getRawAst(this) instanceof Raw::DotSourcingOperator } + + Expr getPath() { result = this.getArgument(0) } +} + +class JoinPath extends CmdCall { + JoinPath() { this.getName().toLowerCase() = "join-path" } + + Expr getPath() { + result = this.getNamedArgument("path") + or + not this.hasNamedArgument("path") and + result = this.getPositionalArgument(0) + } + + Expr getChildPath() { + result = this.getNamedArgument("childpath") + or + not this.hasNamedArgument("childpath") and + result = this.getPositionalArgument(1) + } +} + +class SplitPath extends CmdCall { + SplitPath() { this.getName().toLowerCase() = "split-path" } + + Expr getPath() { + result = this.getNamedArgument("path") + or + not this.hasNamedArgument("path") and + result = this.getPositionalArgument(0) + or + // TODO: This should not be allowed, but I've seen code doing it and somehow it works + result = this.getNamedArgument("parent") + } + + predicate isParent() { this.hasNamedArgument("parent") } + + predicate isLeaf() { this.hasNamedArgument("leaf") } + + predicate isNoQualifier() { this.hasNamedArgument("noqualifier") } + + predicate isQualifier() { this.hasNamedArgument("qualifier") } + + predicate isResolve() { this.hasNamedArgument("resolve") } + + predicate isExtension() { this.hasNamedArgument("extension") } + + predicate isLeafBaseName() { this.hasNamedArgument("leafbasename") } +} + +class GetVariable extends CmdCall { + GetVariable() { this.getName().toLowerCase() = "get-variable" } + + Expr getVariable() { result = this.getPositionalArgument(0) } + + predicate isGlobalScope() { this.hasNamedArgument("global") } + + predicate isLocalScope() { this.hasNamedArgument("local") } + + predicate isScriptScope() { this.hasNamedArgument("script") } + + predicate isPrivateScope() { this.hasNamedArgument("private") } + + predicate isNumbered(Expr e) { e = this.getNamedArgument("scope") } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/CommentEntity.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/CommentEntity.qll new file mode 100644 index 000000000000..136c3346b3fb --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/CommentEntity.qll @@ -0,0 +1,2 @@ +private import AstImport +import Raw.CommentEntity \ No newline at end of file diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Configuration.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Configuration.qll new file mode 100644 index 000000000000..7856efb5d946 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Configuration.qll @@ -0,0 +1,31 @@ +private import AstImport + +class Configuration extends Stmt, TConfiguration { + override string toString() { result = this.getName().toString() } + + Expr getName() { + exists(Raw::Ast r | r = getRawAst(this) | + synthChild(r, configurationName(), result) + or + not synthChild(r, configurationName(), _) and + result = getResultAst(r.(Raw::Configuration).getName()) + ) + } + + ScriptBlockExpr getBody() { + exists(Raw::Ast r | r = getRawAst(this) | + synthChild(r, configurationBody(), result) + or + not synthChild(r, configurationBody(), _) and + result = getResultAst(r.(Raw::Configuration).getBody()) + ) + } + + final override Ast getChild(ChildIndex i) { + result = super.getChild(i) + or + i = configurationName() and result = this.getName() + or + i = configurationBody() and result = this.getBody() + } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ConstantExpression.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Constant.qll similarity index 71% rename from powershell/ql/lib/semmle/code/powershell/ConstantExpression.qll rename to powershell/ql/lib/semmle/code/powershell/ast/internal/Constant.qll index 9c9e8b7f2002..f39a9bdfff7a 100644 --- a/powershell/ql/lib/semmle/code/powershell/ConstantExpression.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Constant.qll @@ -1,25 +1,19 @@ -import powershell - -class ConstExpr extends @constant_expression, BaseConstExpr { - override SourceLocation getLocation() { constant_expression_location(this, result) } - - override string getType() { constant_expression(this, result) } - - override StringLiteral getValue() { constant_expression_value(this, result) } -} +private import AstImport private newtype TConstantValue = TConstInteger(int value) { - exists(ConstExpr ce | ce.getType() = "Int32" and ce.getValue().getValue().toInt() = value) + exists(Raw::ConstExpr ce | ce.getType() = "Int32" and ce.getValue().getValue().toInt() = value) or value = [0 .. 10] // needed for `trackKnownValue` in `DataFlowPrivate` } or TConstDouble(float double) { - exists(ConstExpr ce | ce.getType() = "Double" and ce.getValue().getValue().toFloat() = double) + exists(Raw::ConstExpr ce | + ce.getType() = "Double" and ce.getValue().getValue().toFloat() = double + ) } or - TConstString(string value) { exists(StringLiteral sl | sl.getValue() = value) } or + TConstString(string value) { exists(Raw::StringLiteral sl | sl.getValue() = value) } or TConstBoolean(boolean value) { - exists(VarAccess va | + exists(Raw::VarAccess va | value = true and va.getUserPath() = "true" or @@ -67,7 +61,9 @@ class ConstInteger extends ConstantValue, TConstInteger { final override string serialize() { result = this.getValue() } - final override ConstExpr getAnExpr() { result.getValue().getValue() = this.getValue() } + final override ConstExpr getAnExpr() { + result.getValueString() = this.getValue() + } } /** A constant floating point value. */ @@ -82,7 +78,12 @@ class ConstDouble extends ConstantValue, TConstDouble { ) } - final override ConstExpr getAnExpr() { result.getValue().getValue() = this.getValue() } + final override ConstExpr getAnExpr() { + exists(Raw::ConstExpr ce | + ce.getValue().getValue() = this.getValue() and + result = fromRaw(ce) + ) + } } /** A constant string value. */ @@ -95,7 +96,7 @@ class ConstString extends ConstantValue, TConstString { result = "\"" + this.asString().replaceAll("\"", "\\\"") + "\"" } - final override BaseConstExpr getAnExpr() { result.getValue().getValue() = this.getValue() } + final override StringConstExpr getAnExpr() { result.getValueString() = this.getValue() } } /** A constant boolean value. */ @@ -106,13 +107,7 @@ class ConstBoolean extends ConstantValue, TConstBoolean { final override string serialize() { result = this.getValue() } - final override VarAccess getAnExpr() { - this.asBoolean() = true and - result.getUserPath() = "true" - or - this.asBoolean() = false and - result.getUserPath() = "false" - } + final override BoolLiteral getAnExpr() { result.getBoolValue() = this.asBoolean() } } /** The constant null value. */ @@ -123,5 +118,5 @@ class NullConst extends ConstantValue, TNull { final override string serialize() { result = this.getValue() } - final override VarAccess getAnExpr() { result.getUserPath() = "null" } + final override NullLiteral getAnExpr() { any() } } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/ConstantExpression.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/ConstantExpression.qll new file mode 100644 index 000000000000..d2387c761b72 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/ConstantExpression.qll @@ -0,0 +1,7 @@ +private import AstImport + +class ConstExpr extends Expr, TConstExpr { + string getValueString() { result = getRawAst(this).(Raw::ConstExpr).getValue().getValue() } + + override string toString() { result = this.getValue().getValue() } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/ContinueStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/ContinueStmt.qll new file mode 100644 index 000000000000..257378bbbb49 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/ContinueStmt.qll @@ -0,0 +1,5 @@ +private import AstImport + +class ContinueStmt extends Stmt, TContinueStmt { + override string toString() { result = "continue" } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/ConvertExpr.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/ConvertExpr.qll new file mode 100644 index 000000000000..e799435c843b --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/ConvertExpr.qll @@ -0,0 +1,42 @@ +private import AstImport + +class ConvertExpr extends AttributedExprBase, TConvertExpr { + override string toString() { result = "[...]..." } + + final override Expr getExpr() { + exists(Raw::Ast r | r = getRawAst(this) | + synthChild(r, convertExprExpr(), result) + or + not synthChild(r, convertExprExpr(), _) and + result = getResultAst(r.(Raw::ConvertExpr).getExpr()) + ) + } + + TypeConstraint getType() { + exists(Raw::Ast r | r = getRawAst(this) | + synthChild(r, convertExprType(), result) + or + not synthChild(r, convertExprType(), _) and + result = getResultAst(r.(Raw::ConvertExpr).getType()) + ) + } + + final override AttributeBase getAttribute() { + exists(Raw::Ast r | r = getRawAst(this) | + synthChild(r, convertExprAttr(), result) + or + not synthChild(r, convertExprAttr(), _) and + result = getResultAst(r.(Raw::ConvertExpr).getAttribute()) + ) + } + + final override Ast getChild(ChildIndex i) { + result = super.getChild(i) + or + i = convertExprExpr() and result = this.getExpr() + or + i = convertExprType() and result = this.getType() + or + i = convertExprAttr() and result = this.getAttribute() + } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/DataStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/DataStmt.qll new file mode 100644 index 000000000000..cf32bfb84572 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/DataStmt.qll @@ -0,0 +1,37 @@ +private import AstImport + +class DataStmt extends Stmt, TDataStmt { + override string toString() { result = "data {...}" } + + Expr getCmdAllowed(int i) { + exists(ChildIndex index, Raw::Ast r | index = dataStmtCmdAllowed(i) and r = getRawAst(this) | + synthChild(r, index, result) + or + not synthChild(r, index, _) and + result = getResultAst(r.(Raw::DataStmt).getCmdAllowed(i)) + ) + } + + Expr getACmdAllowed() { result = this.getCmdAllowed(_) } + + StmtBlock getBody() { + exists(Raw::Ast r | r = getRawAst(this) | + synthChild(r, dataStmtBody(), result) + or + not synthChild(r, dataStmtBody(), _) and + result = getResultAst(r.(Raw::DataStmt).getBody()) + ) + } + + final override Ast getChild(ChildIndex i) { + result = super.getChild(i) + or + i = dataStmtBody() and + result = this.getBody() + or + exists(int index | + i = dataStmtCmdAllowed(index) and + result = this.getCmdAllowed(index) + ) + } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/DoUntilStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/DoUntilStmt.qll new file mode 100644 index 000000000000..415a248a09d3 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/DoUntilStmt.qll @@ -0,0 +1,31 @@ +private import AstImport + +class DoUntilStmt extends LoopStmt, TDoUntilStmt { + override string toString() { result = "do...until..." } + + Expr getCondition() { + exists(Raw::Ast r | r = getRawAst(this) | + synthChild(r, doUntilStmtCond(), result) + or + not synthChild(r, doUntilStmtCond(), _) and + result = getResultAst(r.(Raw::DoUntilStmt).getCondition()) + ) + } + + final override StmtBlock getBody() { + exists(Raw::Ast r | r = getRawAst(this) | + synthChild(r, doUntilStmtBody(), result) + or + not synthChild(r, doUntilStmtBody(), _) and + result = getResultAst(r.(Raw::DoUntilStmt).getBody()) + ) + } + + final override Ast getChild(ChildIndex i) { + result = super.getChild(i) + or + i = doUntilStmtCond() and result = this.getCondition() + or + i = doUntilStmtBody() and result = this.getBody() + } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/DoWhileStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/DoWhileStmt.qll new file mode 100644 index 000000000000..ab7099cefcb7 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/DoWhileStmt.qll @@ -0,0 +1,33 @@ +private import AstImport + +class DoWhileStmt extends LoopStmt, TDoWhileStmt { + override string toString() { result = "do...while..." } + + Expr getCondition() { + exists(Raw::Ast r | r = getRawAst(this) | + synthChild(r, doWhileStmtCond(), result) + or + not synthChild(r, doWhileStmtCond(), _) and + result = getResultAst(r.(Raw::DoWhileStmt).getCondition()) + ) + } + + final override StmtBlock getBody() { + exists(Raw::Ast r | r = getRawAst(this) | + synthChild(r, doWhileStmtBody(), result) + or + not synthChild(r, doWhileStmtBody(), _) and + result = getResultAst(r.(Raw::DoWhileStmt).getBody()) + ) + } + + final override Ast getChild(ChildIndex i) { + result = super.getChild(i) + or + i = doWhileStmtCond() and + result = this.getCondition() + or + i = doWhileStmtBody() and + result = this.getBody() + } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/DynamicStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/DynamicStmt.qll new file mode 100644 index 000000000000..34bef60f2da1 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/DynamicStmt.qll @@ -0,0 +1,45 @@ +private import AstImport + +class DynamicStmt extends Stmt, TDynamicStmt { + override string toString() { result = "&..." } + + Expr getName() { + exists(Raw::Ast r | r = getRawAst(this) | + synthChild(r, dynamicStmtName(), result) + or + not synthChild(r, dynamicStmtName(), _) and + result = getResultAst(r.(Raw::DynamicStmt).getName()) + ) + } + + ScriptBlockExpr getScriptBlock() { + exists(Raw::Ast r | r = getRawAst(this) | + synthChild(r, dynamicStmtBody(), result) + or + not synthChild(r, dynamicStmtBody(), _) and + result = getResultAst(r.(Raw::DynamicStmt).getScriptBlock()) + ) + } + + HashTableExpr getHashTableExpr() { + exists(Raw::Ast r | r = getRawAst(this) | + synthChild(r, dynamicStmtBody(), result) + or + not synthChild(r, dynamicStmtBody(), _) and + result = getResultAst(r.(Raw::DynamicStmt).getHashTableExpr()) + ) + } + + predicate hasScriptBlock() { exists(this.getScriptBlock()) } + + predicate hasHashTableExpr() { exists(this.getHashTableExpr()) } + + final override Ast getChild(ChildIndex i) { + result = super.getChild(i) + or + i = dynamicStmtName() and result = this.getName() + or + i = dynamicStmtBody() and + (result = this.getScriptBlock() or result = this.getHashTableExpr()) + } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/EnvVariable.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/EnvVariable.qll new file mode 100644 index 000000000000..5d61c101bd44 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/EnvVariable.qll @@ -0,0 +1,11 @@ +private import AstImport + +class EnvVariable extends Expr, TEnvVariable { + final override string toString() { result = this.getName() } + + string getName() { any(Synthesis s).envVariableName(this, result) } +} + +class SystemDrive extends EnvVariable { + SystemDrive() { this.getName() = "systemdrive" } +} \ No newline at end of file diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/ErrorExpr.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/ErrorExpr.qll new file mode 100644 index 000000000000..154b80e8e920 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/ErrorExpr.qll @@ -0,0 +1,5 @@ +private import AstImport + +class ErrorExpr extends Expr, TErrorExpr { + final override string toString() { result = "error" } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/ErrorStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/ErrorStmt.qll new file mode 100644 index 000000000000..8528cf091154 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/ErrorStmt.qll @@ -0,0 +1,5 @@ +private import AstImport + +class ErrorStmt extends Stmt, TErrorStmt { + final override string toString() { result = "error" } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/ExitStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/ExitStmt.qll new file mode 100644 index 000000000000..07cd97f343cd --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/ExitStmt.qll @@ -0,0 +1,22 @@ +private import AstImport + +class ExitStmt extends Stmt, TExitStmt { + Expr getPipeline() { + exists(Raw::Ast r | r = getRawAst(this) | + synthChild(r, exitStmtPipeline(), result) + or + not synthChild(r, exitStmtPipeline(), _) and + result = getResultAst(r.(Raw::ExitStmt).getPipeline()) + ) + } + + predicate hasPipeline() { exists(this.getPipeline()) } + + override string toString() { if this.hasPipeline() then result = "exit ..." else result = "exit" } + + final override Ast getChild(ChildIndex i) { + result = super.getChild(i) + or + i = exitStmtPipeline() and result = this.getPipeline() + } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/ExpandableStringExpression.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/ExpandableStringExpression.qll new file mode 100644 index 000000000000..98eb80f2c154 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/ExpandableStringExpression.qll @@ -0,0 +1,31 @@ +private import AstImport + +class ExpandableStringExpr extends Expr, TExpandableStringExpr { + string getUnexpandedValue() { + result = getRawAst(this).(Raw::ExpandableStringExpr).getUnexpandedValue().getValue() + } + + override string toString() { result = this.getUnexpandedValue() } + + Expr getExpr(int i) { + exists(ChildIndex index, Raw::Ast r | + index = expandableStringExprExpr(i) and r = getRawAst(this) + | + synthChild(r, index, result) + or + not synthChild(r, index, _) and + result = getResultAst(r.(Raw::ExpandableStringExpr).getExpr(i)) + ) + } + + Expr getAnExpr() { result = this.getExpr(_) } + + final override Ast getChild(ChildIndex i) { + result = super.getChild(i) + or + exists(int index | + i = expandableStringExprExpr(index) and + result = this.getExpr(index) + ) + } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Expr.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Expr.qll new file mode 100644 index 000000000000..756e467b07a8 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Expr.qll @@ -0,0 +1,22 @@ +private import AstImport + +/** + * An expression. + * + * This is the topmost class in the hierachy of all expression in PowerShell. + */ +class Expr extends Ast, TExpr { + /** Gets the constant value of this expression, if this is known. */ + ConstantValue getValue() { result.getAnExpr() = this } + + Redirection getRedirection(int i) { synthChild(getRawAst(this), exprRedirection(i), result) } + + override Ast getChild(ChildIndex i) { + result = super.getChild(i) + or + exists(int index | + i = exprRedirection(index) and + result = this.getRedirection(index) + ) + } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/ExprStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/ExprStmt.qll new file mode 100644 index 000000000000..3be667f62b46 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/ExprStmt.qll @@ -0,0 +1,16 @@ +private import AstImport + +class ExprStmt extends Stmt, TExprStmt { + override string toString() { result = "[Stmt] " + this.getExpr().toString() } + + string getName() { result = any(Synthesis s).toString(this) } + + override Ast getChild(ChildIndex i) { + result = super.getChild(i) + or + i = exprStmtExpr() and + result = this.getExpr() + } + + Expr getExpr() { any(Synthesis s).exprStmtExpr(this, result) } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/File.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/File.qll new file mode 100644 index 000000000000..0f2a89e0f4b5 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/File.qll @@ -0,0 +1 @@ +import Raw.File diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/FileRedirection.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/FileRedirection.qll new file mode 100644 index 000000000000..f3409baf4f08 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/FileRedirection.qll @@ -0,0 +1,7 @@ +private import AstImport + +class FileRedirection extends Redirection { + FileRedirection() { this = TRedirection(any(Raw::FileRedirection r)) } + + override string toString() { result = "FileRedirection" } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/ForEachStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/ForEachStmt.qll new file mode 100644 index 000000000000..a1abe00bb80d --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/ForEachStmt.qll @@ -0,0 +1,43 @@ +private import AstImport + +class ForEachStmt extends LoopStmt, TForEachStmt { + override string toString() { result = "forach(... in ...)" } + + final override StmtBlock getBody() { + exists(Raw::Ast r | r = getRawAst(this) | + synthChild(r, forEachStmtBody(), result) + or + not synthChild(r, forEachStmtBody(), _) and + result = getResultAst(r.(Raw::ForEachStmt).getBody()) + ) + } + + // TODO: Should this API change? + VarAccess getVarAccess() { + exists(Raw::Ast r | r = getRawAst(this) | + synthChild(r, forEachStmtVar(), result) + or + not synthChild(r, forEachStmtVar(), _) and + result = getResultAst(r.(Raw::ForEachStmt).getVarAccess()) + ) + } + + Expr getIterableExpr() { + exists(Raw::Ast r | r = getRawAst(this) | + synthChild(r, forEachStmtIter(), result) + or + not synthChild(r, forEachStmtIter(), _) and + result = getResultAst(r.(Raw::ForEachStmt).getIterableExpr()) + ) + } + + final override Ast getChild(ChildIndex i) { + result = super.getChild(i) + or + i = forEachStmtVar() and result = this.getVarAccess() + or + i = forEachStmtIter() and result = this.getIterableExpr() + or + i = forEachStmtBody() and result = this.getBody() + } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/ForStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/ForStmt.qll new file mode 100644 index 000000000000..81de53fc52ec --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/ForStmt.qll @@ -0,0 +1,58 @@ +private import AstImport + +class ForStmt extends LoopStmt, TForStmt { + override string toString() { result = "for(...;...;...)" } + + Ast getInitializer() { + exists(Raw::Ast r | r = getRawAst(this) | + // TODO: I think this is always an assignment? + synthChild(r, forStmtInit(), result) + or + not synthChild(r, forStmtInit(), _) and + result = getResultAst(r.(Raw::ForStmt).getInitializer()) + ) + } + + Expr getCondition() { + exists(Raw::Ast r | r = getRawAst(this) | + synthChild(r, forStmtCond(), result) + or + not synthChild(r, forStmtCond(), _) and + result = getResultAst(r.(Raw::ForStmt).getCondition()) + ) + } + + Ast getIterator() { + exists(Raw::Ast r | r = getRawAst(this) | + synthChild(r, forStmtIter(), result) + or + not synthChild(r, forStmtIter(), _) and + result = getResultAst(r.(Raw::ForStmt).getIterator()) + ) + } + + final override StmtBlock getBody() { + exists(Raw::Ast r | r = getRawAst(this) | + synthChild(r, forStmtBody(), result) + or + not synthChild(r, forStmtBody(), _) and + result = getResultAst(r.(Raw::ForStmt).getBody()) + ) + } + + final override Ast getChild(ChildIndex i) { + result = super.getChild(i) + or + i = forStmtInit() and + result = this.getInitializer() + or + i = forStmtCond() and + result = this.getCondition() + or + i = forStmtIter() and + result = this.getIterator() + or + i = forStmtBody() and + result = this.getBody() + } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Function.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Function.qll new file mode 100644 index 000000000000..e640fdbaaa4e --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Function.qll @@ -0,0 +1,15 @@ +private import AstImport + +class Function extends FunctionBase, TFunction { + final override string getName() { any(Synthesis s).functionName(this, result) } + + final override ScriptBlock getBody() { any(Synthesis s).functionScriptBlock(this, result) } + + final override Parameter getParameter(int i) { result = this.getBody().getParameter(i) } + + final override Ast getChild(ChildIndex i) { + result = super.getChild(i) + or + i = functionBody() and result = this.getBody() + } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/FunctionBase.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/FunctionBase.qll new file mode 100644 index 000000000000..e530778900e6 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/FunctionBase.qll @@ -0,0 +1,23 @@ +private import AstImport +private import semmle.code.powershell.controlflow.BasicBlocks + +class FunctionBase extends Ast, TFunctionBase { + final override string toString() { result = this.getName() } + + string getName() { none() } + + final predicate hasName(string name) { name = this.getName() } + + ScriptBlock getBody() { none() } + + Parameter getParameter(int i) { none() } + + final Parameter getAParameter() { result = this.getParameter(_) } + + /** Note: This always has a result */ + final PipelineParameter getPipelineParameter() { result = this.getAParameter() } + + final EntryBasicBlock getEntryBasicBlock() { result.getScope() = this.getBody() } + + final int getNumberOfParameters() { result = count(this.getAParameter()) } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/FunctionDefinition.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/FunctionDefinition.qll new file mode 100644 index 000000000000..9800fb647c6e --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/FunctionDefinition.qll @@ -0,0 +1,15 @@ +private import AstImport + +class FunctionDefinitionStmt extends Stmt, TFunctionDefinitionStmt { + FunctionBase getFunction() { synthChild(getRawAst(this), funDefFun(), result) } + + string getName() { result = getRawAst(this).(Raw::FunctionDefinitionStmt).getName() } + + final override string toString() { result = "def of " + this.getName() } + + final override Ast getChild(ChildIndex i) { + result = super.getChild(i) + or + i = funDefFun() and result = this.getFunction() + } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/GotoStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/GotoStmt.qll new file mode 100644 index 000000000000..af9c48ed97ca --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/GotoStmt.qll @@ -0,0 +1,18 @@ +private import AstImport + +class GotoStmt extends Stmt, TGotoStmt { + Expr getLabel() { + exists(Raw::Ast r | r = getRawAst(this) | + synthChild(r, gotoStmtLabel(), result) + or + not synthChild(r, gotoStmtLabel(), _) and + result = getResultAst(r.(Raw::GotoStmt).getLabel()) + ) + } + + final override Ast getChild(ChildIndex i) { + result = super.getChild(i) + or + i = gotoStmtLabel() and result = this.getLabel() + } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/HashTable.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/HashTable.qll new file mode 100644 index 000000000000..ec6b914a9dba --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/HashTable.qll @@ -0,0 +1,51 @@ +private import AstImport + +class HashTableExpr extends Expr, THashTableExpr { + final override string toString() { result = "${...}" } + + Expr getKey(int i) { + exists(ChildIndex index, Raw::Ast r | index = hashTableExprKey(i) and r = getRawAst(this) | + synthChild(r, index, result) + or + not synthChild(r, index, _) and + result = getResultAst(r.(Raw::HashTableExpr).getKey(i)) + ) + } + + Expr getAKey() { result = this.getKey(_) } + + Expr getValue(int i) { + exists(ChildIndex index, Raw::Ast r | index = hashTableExprStmt(i) and r = getRawAst(this) | + synthChild(r, index, result) + or + not synthChild(r, index, _) and + result = getResultAst(r.(Raw::HashTableExpr).getStmt(i)) + ) + } + + Expr getValueFromKey(Expr key) { + exists(int i | + this.getKey(i) = key and + result = this.getValue(i) + ) + } + + Expr getAValue() { result = this.getValue(_) } + + final override Ast getChild(ChildIndex i) { + result = super.getChild(i) + or + exists(int index | + i = hashTableExprKey(index) and + result = this.getKey(index) + or + i = hashTableExprStmt(index) and + result = this.getValue(index) + ) + } + + predicate hasEntry(int i, Expr key, Expr value) { + this.getKey(i) = key and + this.getValue(i) = value + } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/If.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/If.qll new file mode 100644 index 000000000000..94192397060c --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/If.qll @@ -0,0 +1,57 @@ +private import AstImport + +class If extends Expr, TIf { + override string toString() { + if this.hasElse() then result = "if (...) {...} else {...}" else result = "if (...) {...}" + } + + final override Ast getChild(ChildIndex i) { + result = super.getChild(i) + or + i = ifStmtElse() and + result = this.getElse() + or + exists(int index | + i = ifStmtCond(index) and + result = this.getCondition(index) + or + i = ifStmtThen(index) and + result = this.getThen(index) + ) + } + + Expr getCondition(int i) { + exists(ChildIndex index, Raw::Ast r | index = ifStmtCond(i) and r = getRawAst(this) | + synthChild(r, index, result) + or + not synthChild(r, index, _) and + result = getResultAst(r.(Raw::IfStmt).getCondition(i)) + ) + } + + Expr getACondition() { result = this.getCondition(_) } + + int getNumberOfConditions() { result = count(this.getACondition()) } + + StmtBlock getThen(int i) { + exists(ChildIndex index, Raw::Ast r | index = ifStmtThen(i) and r = getRawAst(this) | + synthChild(r, index, result) + or + not synthChild(r, index, _) and + result = getResultAst(r.(Raw::IfStmt).getThen(i)) + ) + } + + StmtBlock getAThen() { result = this.getThen(_) } + + StmtBlock getElse() { + exists(Raw::Ast r | r = getRawAst(this) | + synthChild(r, ifStmtElse(), result) + or + not synthChild(r, ifStmtElse(), _) and + result = getResultAst(r.(Raw::IfStmt).getElse()) + ) + } + + predicate hasElse() { exists(this.getElse()) } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/IndexExpr.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/IndexExpr.qll new file mode 100644 index 000000000000..9d52c12485c0 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/IndexExpr.qll @@ -0,0 +1,51 @@ +private import AstImport + +class IndexExpr extends Expr, TIndexExpr { + override string toString() { result = "...[...]" } + + final override Ast getChild(ChildIndex i) { + result = super.getChild(i) + or + i = indexExprIndex() and result = this.getIndex() + or + i = indexExprBase() and result = this.getBase() + } + + Expr getIndex() { + exists(Raw::Ast r | r = getRawAst(this) | + synthChild(r, indexExprIndex(), result) + or + not synthChild(r, indexExprIndex(), _) and + result = getResultAst(r.(Raw::IndexExpr).getIndex()) + ) + } + + Expr getBase() { + exists(Raw::Ast r | r = getRawAst(this) | + synthChild(r, indexExprBase(), result) + or + not synthChild(r, indexExprBase(), _) and + result = getResultAst(r.(Raw::IndexExpr).getBase()) + ) + } + + predicate isNullConditional() { getRawAst(this).(Raw::IndexExpr).isNullConditional() } + + predicate isExplicitWrite(Ast assignment) { + explicitAssignment(getRawAst(this), getRawAst(assignment)) + } + + predicate isImplicitWrite() { + implicitAssignment(getRawAst(this)) + } +} + +/** An `IndexExpr` that is being written to. */ +class IndexExprWriteAccess extends IndexExpr { + IndexExprWriteAccess() { this.isExplicitWrite(_) or this.isImplicitWrite() } +} + +/** An `IndexExpr` that is being read from. */ +class IndexExprReadAccess extends IndexExpr { + IndexExprReadAccess() { not this instanceof IndexExprWriteAccess } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Internal.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Internal.qll new file mode 100644 index 000000000000..75fb48651014 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Internal.qll @@ -0,0 +1,96 @@ +module Private { + import ChildIndex + import Variable::Private +} + +module Public { + import File + import Location + import SourceLocation + import Ast + import Statement + import Expr + import PipelineChain + import ConstantExpression + import Attribute + import AttributeBase + import NamedAttributeArgument + import FunctionBase + import Function + import FunctionDefinition + import TypeConstraint + import ModuleSpecification + import NamedBlock + import ScriptBlock + import AssignmentStatement + import BinaryExpression + import UnaryExpression + import ScriptBlockExpr + import TernaryExpression + import UsingExpression + import TrapStatement + import StatementBlock + import ArrayExpression + import ArrayLiteral + import Redirection + import FileRedirection + import MergingRedirection + import LoopStmt + import DoWhileStmt + import DoUntilStmt + import WhileStmt + import ForStmt + import ForEachStmt + import GotoStmt + import ContinueStmt + import BreakStmt + import ReturnStmt + import UsingStmt + import ThrowStmt + import ErrorStmt + import TypeDefinitionStmt + import Member + import PropertyMember + import TryStmt + import If + import SwitchStmt + import ThisExpr + import ExitStmt + import DynamicStmt + import DataStmt + import Configuration + import CatchClause + import Parameter + import ExpandableStringExpression + import TypeExpression + import ParenExpr + import Pipeline + import StringConstantExpression + import MemberExpr + import InvokeMemberExpression + import ObjectCreation + import SubExpression + import ErrorExpr + import ConvertExpr + import IndexExpr + import HashTable + import Variable::Public + import CallExpr + import Command + import ExprStmt + import Constant + import AttributeBase + import Method + import AttributedExpr + import AttributedExprBase + import Scopes + import BoolLiteral + import NullLiteral + import Operation + import Literal + import EnvVariable + import Type + import AutomaticVariable + import Operation + import CommentEntity +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/InvokeMemberExpression.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/InvokeMemberExpression.qll new file mode 100644 index 000000000000..c57b4a6fe42f --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/InvokeMemberExpression.qll @@ -0,0 +1,74 @@ +private import AstImport + +class InvokeMemberExpr extends CallExpr, TInvokeMemberExpr { + final override string getName() { result = getRawAst(this).(Raw::InvokeMemberExpr).getName() } + + final override Ast getChild(ChildIndex i) { + result = super.getChild(i) + or + i = invokeMemberExprQual() and + result = this.getQualifier() + or + i = invokeMemberExprCallee() and + result = this.getCallee() + or + exists(int index | + i = invokeMemberExprArg(index) and + result = this.getArgument(index) + ) + } + + final override Expr getCallee() { + exists(Raw::Ast r | r = getRawAst(this) and r = getRawAst(this) | + synthChild(r, invokeMemberExprCallee(), result) + or + not synthChild(r, invokeMemberExprCallee(), _) and + result = getResultAst(r.(Raw::InvokeMemberExpr).getCallee()) + ) + } + + final override Expr getArgument(int i) { + exists(ChildIndex index, Raw::Ast r | index = invokeMemberExprArg(i) and r = getRawAst(this) | + synthChild(r, index, result) + or + not synthChild(r, index, _) and + result = getResultAst(r.(Raw::InvokeMemberExpr).getArgument(i)) + ) + } + + final override Expr getPositionalArgument(int i) { + // All arguments are positional in an InvokeMemberExpr + result = this.getArgument(i) + } + + final override Expr getNamedArgument(string name) { none() } + + final override Expr getQualifier() { + exists(Raw::Ast r | r = getRawAst(this) | + synthChild(r, invokeMemberExprQual(), result) + or + not synthChild(r, invokeMemberExprQual(), _) and + result = getResultAst(r.(Raw::InvokeMemberExpr).getQualifier()) + ) + } + + override predicate isStatic() { getRawAst(this).(Raw::InvokeMemberExpr).isStatic() } +} + +/** + * A call to a constructor. For example: + * + * ```powershell + * [System.IO.FileInfo]::new("C:\\file.txt") + * ``` + */ +class ConstructorCall extends InvokeMemberExpr { + TypeNameExpr typename; + + ConstructorCall() { + this.isStatic() and typename = this.getQualifier() and this.getName() = "new" + } + + /** Gets the name of the type being constructed by this constructor call. */ + string getConstructedTypeName() { result = typename.getName() } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Literal.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Literal.qll new file mode 100644 index 000000000000..9e8ad3d44698 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Literal.qll @@ -0,0 +1,3 @@ +private import AstImport + +class Literal extends Expr, TLiteral { } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Location.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Location.qll new file mode 100644 index 000000000000..687ffe8b4152 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Location.qll @@ -0,0 +1 @@ +import Raw.Location diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/LoopStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/LoopStmt.qll new file mode 100644 index 000000000000..d7ca83ab51a4 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/LoopStmt.qll @@ -0,0 +1,5 @@ +private import AstImport + +class LoopStmt extends Stmt, TLoopStmt { + StmtBlock getBody() { none() } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Member.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Member.qll new file mode 100644 index 000000000000..e650ae947548 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Member.qll @@ -0,0 +1,41 @@ +private import AstImport + +class Member extends Ast, TMember { + string getName() { + result = getRawAst(this).(Raw::Member).getName() + or + any(Synthesis s).memberName(this, result) + } + + Type getDeclaringType() { result.getAMember() = this } + + final Attribute getAttribute(int i) { + exists(ChildIndex index, Raw::Ast r | index = memberAttr(i) and r = getRawAst(this) | + synthChild(r, index, result) + or + not synthChild(r, index, _) and + result = getResultAst(r.(Raw::Member).getAttribute(i)) + ) + } + + final TypeConstraint getTypeConstraint() { + exists(Raw::Ast r | r = getRawAst(this) | + synthChild(r, memberTypeConstraint(), result) + or + not synthChild(r, memberTypeConstraint(), _) and + result = getResultAst(r.(Raw::Member).getTypeConstraint()) + ) + } + + override Ast getChild(ChildIndex i) { + result = super.getChild(i) + or + exists(int index | + i = memberAttr(index) and + result = this.getAttribute(index) + ) + or + i = memberTypeConstraint() and + result = this.getTypeConstraint() + } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/MemberExpr.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/MemberExpr.qll new file mode 100644 index 000000000000..0af48cd6485f --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/MemberExpr.qll @@ -0,0 +1,58 @@ +private import AstImport + +class MemberExpr extends Expr, TMemberExpr { + Expr getQualifier() { + exists(Raw::Ast r | r = getRawAst(this) | + synthChild(r, memberExprQual(), result) + or + not synthChild(r, memberExprQual(), _) and + result = getResultAst(r.(Raw::MemberExpr).getQualifier()) + ) + } + + Expr getMemberExpr() { + exists(Raw::Ast r | r = getRawAst(this) | + synthChild(r, memberExprMember(), result) + or + not synthChild(r, memberExprMember(), _) and + result = getResultAst(r.(Raw::MemberExpr).getMember()) + ) + } + + final override Ast getChild(ChildIndex i) { + result = super.getChild(i) + or + i = memberExprQual() and result = this.getQualifier() + or + i = memberExprMember() and result = this.getMemberExpr() + } + + /** Gets the name of the member being looked up, if any. */ + string getMemberName() { + result = getRawAst(this).(Raw::MemberExpr).getMember().(Raw::StringConstExpr).getValue().getValue() + } + + predicate isNullConditional() { getRawAst(this).(Raw::MemberExpr).isNullConditional() } + + predicate isStatic() { getRawAst(this).(Raw::MemberExpr).isStatic() } + + final override string toString() { result = this.getMemberName() } + + predicate isExplicitWrite(Ast assignment) { + explicitAssignment(getRawAst(this), getRawAst(assignment)) + } + + predicate isImplicitWrite() { + implicitAssignment(getRawAst(this)) + } +} + +/** A `MemberExpr` that is being written to. */ +class MemberExprWriteAccess extends MemberExpr { + MemberExprWriteAccess() { this.isExplicitWrite(_) or this.isImplicitWrite() } +} + +/** A `MemberExpr` that is being read from. */ +class MemberExprReadAccess extends MemberExpr { + MemberExprReadAccess() { not this instanceof MemberExprWriteAccess } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/MergingRedirection.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/MergingRedirection.qll new file mode 100644 index 000000000000..29a8fde86bd2 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/MergingRedirection.qll @@ -0,0 +1,7 @@ +private import AstImport + +class MergingRedirection extends Redirection { + MergingRedirection() { this = TRedirection(any(Raw::MergingRedirection r)) } + + override string toString() { result = "MergingRedirection" } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Method.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Method.qll new file mode 100644 index 000000000000..ebe47dd9b9d1 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Method.qll @@ -0,0 +1,35 @@ +private import AstImport + +class Method extends Member, FunctionBase, TMethod { + final override string getName() { result = Member.super.getName() } + + final override ScriptBlock getBody() { + exists(Raw::Ast r | r = getRawAst(this) | + synthChild(r, methodBody(), result) + or + not synthChild(r, methodBody(), _) and + result = getResultAst(r.(Raw::Method).getBody()) + ) + } + + final override Parameter getParameter(int i) { result = this.getBody().getParameter(i) } + + final override Location getLocation() { result = getRawAst(this).(Raw::Method).getLocation() } + + final override Ast getChild(ChildIndex i) { + result = super.getChild(i) + or + i = methodBody() and result = this.getBody() + } + + predicate isConstructor() { getRawAst(this).(Raw::Method).isConstructor() } + + ThisParameter getThisParameter() { + result.getFunction() = this + } +} + +/** A constructor definition. */ +class Constructor extends Method { + Constructor() { this.isConstructor() } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/ModuleSpecification.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/ModuleSpecification.qll new file mode 100644 index 000000000000..c7641774c3a4 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/ModuleSpecification.qll @@ -0,0 +1 @@ +import Raw.ModuleSpecification diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/NamedAttributeArgument.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/NamedAttributeArgument.qll new file mode 100644 index 000000000000..57d8722e8b38 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/NamedAttributeArgument.qll @@ -0,0 +1,24 @@ +private import AstImport + +class NamedAttributeArgument extends Ast, TNamedAttributeArgument { + final override string toString() { result = this.getName() } + + string getName() { result = getRawAst(this).(Raw::NamedAttributeArgument).getName() } + + predicate hasName(string s) { this.getName() = s } + + Expr getValue() { + exists(Raw::Ast r | r = getRawAst(this) | + synthChild(r, namedAttributeArgVal(), result) + or + not synthChild(r, namedAttributeArgVal(), _) and + result = getResultAst(r.(Raw::NamedAttributeArgument).getValue()) + ) + } + + final override Ast getChild(ChildIndex i) { + result = super.getChild(i) + or + i = namedAttributeArgVal() and result = this.getValue() + } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/NamedBlock.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/NamedBlock.qll new file mode 100644 index 000000000000..a23106fff648 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/NamedBlock.qll @@ -0,0 +1,56 @@ +private import AstImport + +class NamedBlock extends Ast, TNamedBlock { + override string toString() { result = "{...}" } + + Stmt getStmt(int i) { + exists(ChildIndex index, Raw::Ast r | index = namedBlockStmt(i) and r = getRawAst(this) | + synthChild(r, index, result) + or + not synthChild(r, index, _) and + result = getResultAst(r.(Raw::NamedBlock).getStmt(i)) + ) + } + + TrapStmt getTrapStmt(int i) { + exists(ChildIndex index, Raw::Ast r | index = namedBlockTrap(i) and r = getRawAst(this) | + synthChild(r, index, result) + or + not synthChild(r, index, _) and + result = getResultAst(r.(Raw::NamedBlock).getTrap(i)) + ) + } + + Stmt getAStmt() { result = this.getStmt(_) } + + TrapStmt getATrapStmt() { result = this.getTrapStmt(_) } + + final override Ast getChild(ChildIndex i) { + result = super.getChild(i) + or + exists(int index | + i = namedBlockStmt(index) and + result = this.getStmt(index) + or + i = namedBlockTrap(index) and + result = this.getTrapStmt(index) + ) + } +} + +/** A `process` block. */ +class ProcessBlock extends NamedBlock { + ScriptBlock scriptBlock; + + ProcessBlock() { scriptBlock.getProcessBlock() = this } + + ScriptBlock getScriptBlock() { result = scriptBlock } + + PipelineParameter getPipelineParameter() { + result = this.getEnclosingFunction().getPipelineParameter() + } + + PipelineByPropertyNameParameter getAPipelineByPropertyNameParameter() { + result = scriptBlock.getEnclosingFunction().getAParameter() + } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/NullLiteral.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/NullLiteral.qll new file mode 100644 index 000000000000..5bba004042ca --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/NullLiteral.qll @@ -0,0 +1,7 @@ +private import AstImport + +class NullLiteral extends Literal, TNullLiteral { + final override string toString() { result = this.getValue().toString() } + + final override ConstantValue getValue() { result.isNull() } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/ObjectCreation.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/ObjectCreation.qll new file mode 100644 index 000000000000..5cb392762599 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/ObjectCreation.qll @@ -0,0 +1,48 @@ +import powershell + +abstract private class AbstractObjectCreation extends CallExpr { + /** The name of the type of the object being constructed. */ + abstract string getConstructedTypeName(); + + abstract Expr getConstructedTypeExpr(); +} + +/** + * An object creation from a call to a constructor. For example: + * ```powershell + * [System.IO.FileInfo]::new("C:\\file.txt") + * ``` + */ +class NewObjectCreation extends AbstractObjectCreation, ConstructorCall { + final override string getConstructedTypeName() { + result = ConstructorCall.super.getConstructedTypeName() + } + + final override Expr getConstructedTypeExpr() { result = typename } +} + +/** + * An object creation from a call to `New-Object`. For example: + * ```powershell + * New-Object -TypeName System.IO.FileInfo -ArgumentList "C:\\file.txt" + * ``` + */ +class DotNetObjectCreation extends AbstractObjectCreation, CmdCall { + DotNetObjectCreation() { this.getName() = "New-Object" } + + final override string getConstructedTypeName() { + result = this.getConstructedTypeExpr().(StringConstExpr).getValueString() + } + + final override Expr getConstructedTypeExpr() { + // Either it's the named argument `TypeName` + result = CmdCall.super.getNamedArgument("TypeName") + or + // Or it's the first positional argument if that's the named argument + not CmdCall.super.hasNamedArgument("TypeName") and + result = CmdCall.super.getPositionalArgument(0) and + result = CmdCall.super.getNamedArgument(["ArgumentList", "Property"]) + } +} + +final class ObjectCreation = AbstractObjectCreation; diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Operation.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Operation.qll new file mode 100644 index 000000000000..a2e1e4547e54 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Operation.qll @@ -0,0 +1,19 @@ +private import AstImport + +class Operation extends Expr, TOperation { + Expr getAnOperand() { none() } + + int getKind() { none() } +} + +class BinaryOperation extends BinaryExpr, Operation { + final override Expr getAnOperand() { result = BinaryExpr.super.getAnOperand() } + + final override int getKind() { result = BinaryExpr.super.getKind() } +} + +class UnaryOperation extends UnaryExpr, Operation { + final override Expr getAnOperand() { result = UnaryExpr.super.getOperand() } + + final override int getKind() { result = UnaryExpr.super.getKind() } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Parameter.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Parameter.qll new file mode 100644 index 000000000000..8a0a82f06ab2 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Parameter.qll @@ -0,0 +1,56 @@ +private import AstImport + +class Parameter extends Variable instanceof ParameterImpl { + string getName() { result = super.getNameImpl() } + + final predicate hasName(string name) { name = this.getName() } + + override Ast getChild(ChildIndex childIndex) { + result = Variable.super.getChild(childIndex) + or + childIndex = paramDefaultVal() and result = this.getDefaultValue() + or + exists(int index | + childIndex = paramAttr(index) and + result = this.getAttribute(index) + ) + } + + Expr getDefaultValue() { synthChild(getRawAst(this), paramDefaultVal(), result) } + + AttributeBase getAttribute(int index) { synthChild(getRawAst(this), paramAttr(index), result) } + + AttributeBase getAnAttribute() { result = this.getAttribute(_) } + + predicate hasDefaultValue() { exists(this.getDefaultValue()) } + + FunctionBase getFunction() { result.getAParameter() = this } + + int getIndex() { this.getFunction().getParameter(result) = this } + + /** ..., if any. */ + string getStaticType() { any(Synthesis s).parameterStaticType(this, result) } +} + +class ThisParameter extends Parameter instanceof ThisParameterImpl { } + +class PipelineParameter extends Parameter { + PipelineParameter() { any(Synthesis s).isPipelineParameter(this) } +} + +class PipelineByPropertyNameParameter extends Parameter { + PipelineByPropertyNameParameter() { + exists(NamedAttributeArgument namedAttribute | + this.getAnAttribute().(Attribute).getANamedArgument() = namedAttribute and + namedAttribute.getName().toLowerCase() = "valuefrompipelinebypropertyname" + | + namedAttribute.getValue().getValue().asBoolean() = true + or + not exists(namedAttribute.getValue().getValue().asBoolean()) + ) + } + + string getPropertyName() { result = this.getName() } + + PipelineByPropertyNameIteratorVariable getIteratorVariable() { result.getParameter() = this } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/ParenExpr.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/ParenExpr.qll new file mode 100644 index 000000000000..b4b9c48e4cd4 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/ParenExpr.qll @@ -0,0 +1,21 @@ +private import AstImport + +class ParenExpr extends Expr, TParenExpr { + override string toString() { result = "(...)" } + + Expr getExpr() { + exists(Raw::Ast r | r = getRawAst(this) | + synthChild(r, parenExprExpr(), result) + or + not synthChild(r, parenExprExpr(), _) and + result = getResultAst(r.(Raw::ParenExpr).getBase()) + ) + } + + final override Ast getChild(ChildIndex i) { + result = super.getChild(i) + or + i = parenExprExpr() and + result = this.getExpr() + } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Pipeline.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Pipeline.qll new file mode 100644 index 000000000000..9506badacc7d --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Pipeline.qll @@ -0,0 +1,31 @@ +private import AstImport + +class Pipeline extends Expr, TPipeline { + override string toString() { + if this.getNumberOfComponents() = 1 + then result = this.getComponent(0).toString() + else result = "...|..." + } + + Expr getComponent(int i) { + exists(ChildIndex index, Raw::Ast r | index = pipelineComp(i) and r = getRawAst(this) | + synthChild(r, index, result) + or + not synthChild(r, index, _) and + result = getResultAst(r.(Raw::Pipeline).getComponent(i)) + ) + } + + final override Ast getChild(ChildIndex i) { + result = super.getChild(i) + or + exists(int index | + i = pipelineComp(index) and + result = this.getComponent(index) + ) + } + + Expr getAComponent() { result = this.getComponent(_) } + + int getNumberOfComponents() { result = getRawAst(this).(Raw::Pipeline).getNumberOfComponents() } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/PipelineChain.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/PipelineChain.qll new file mode 100644 index 000000000000..964d5219ae0d --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/PipelineChain.qll @@ -0,0 +1,31 @@ +private import AstImport + +class PipelineChain extends Expr, TPipelineChain { + predicate isBackground() { getRawAst(this).(Raw::PipelineChain).isBackground() } + + Expr getLeft() { + exists(Raw::Ast r | r = getRawAst(this) | + synthChild(r, pipelineChainLeft(), result) + or + not synthChild(r, pipelineChainLeft(), _) and + result = getResultAst(r.(Raw::PipelineChain).getLeft()) + ) + } + + Pipeline getRight() { + exists(Raw::Ast r | r = getRawAst(this) | + synthChild(r, pipelineChainRight(), result) + or + not synthChild(r, pipelineChainRight(), _) and + result = getResultAst(r.(Raw::PipelineChain).getRight()) + ) + } + + final override Ast getChild(ChildIndex i) { + result = super.getChild(i) + or + i = pipelineChainLeft() and result = this.getLeft() + or + i = pipelineChainRight() and result = this.getRight() + } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/PropertyMember.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/PropertyMember.qll new file mode 100644 index 000000000000..29dac5861aca --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/PropertyMember.qll @@ -0,0 +1,7 @@ +private import AstImport + +class PropertyMember extends Member, TPropertyMember { + final override string getName() { result = getRawAst(this).(Raw::PropertyMember).getName() } + + final override string toString() { result = this.getName() } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ArrayExpression.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ArrayExpression.qll new file mode 100644 index 000000000000..d89c502823a3 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ArrayExpression.qll @@ -0,0 +1,11 @@ +private import Raw + +class ArrayExpr extends @array_expression, Expr { + override SourceLocation getLocation() { array_expression_location(this, result) } + + StmtBlock getStmtBlock() { array_expression(this, result) } + + final override Ast getChild(ChildIndex i) { + i = ArrayExprStmtBlock() and result = this.getStmtBlock() + } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ArrayLiteral.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ArrayLiteral.qll similarity index 61% rename from powershell/ql/lib/semmle/code/powershell/ArrayLiteral.qll rename to powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ArrayLiteral.qll index 447d26b45e36..1fe24b69d17c 100644 --- a/powershell/ql/lib/semmle/code/powershell/ArrayLiteral.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ArrayLiteral.qll @@ -1,4 +1,4 @@ -import powershell +private import Raw class ArrayLiteral extends @array_literal, Expr { override SourceLocation getLocation() { array_literal_location(this, result) } @@ -7,5 +7,10 @@ class ArrayLiteral extends @array_literal, Expr { Expr getAnElement() { array_literal_element(this, _, result) } - override string toString() { result = "...,..." } + final override Ast getChild(ChildIndex i) { + exists(int index | + i = ArrayLiteralExpr(index) and + result = this.getElement(index) + ) + } } diff --git a/powershell/ql/lib/semmle/code/powershell/AssignmentStatement.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/AssignmentStatement.qll similarity index 61% rename from powershell/ql/lib/semmle/code/powershell/AssignmentStatement.qll rename to powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/AssignmentStatement.qll index 10bfaed20661..99ff19ccf4bc 100644 --- a/powershell/ql/lib/semmle/code/powershell/AssignmentStatement.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/AssignmentStatement.qll @@ -1,4 +1,4 @@ -import powershell +private import Raw class AssignStmt extends @assignment_statement, PipelineBase { override SourceLocation getLocation() { assignment_statement_location(this, result) } @@ -9,5 +9,11 @@ class AssignStmt extends @assignment_statement, PipelineBase { Stmt getRightHandSide() { assignment_statement(this, _, _, result) } - override string toString() { result = "...=..." } + final override Ast getChild(ChildIndex i) { + i = AssignStmtLeftHandSide() and + result = this.getLeftHandSide() + or + i = AssignStmtRightHandSide() and + result = this.getRightHandSide() + } } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Ast.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Ast.qll new file mode 100644 index 000000000000..5bfb2383a69b --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Ast.qll @@ -0,0 +1,17 @@ +private import Raw +import Location +private import Scope + +class Ast extends @ast { + final string toString() { none() } + + final Ast getParent() { result.getAChild() = this } + + Ast getChild(ChildIndex i) { none() } + + final Ast getAChild() { result = this.getChild(_) } + + Location getLocation() { none() } + + Scope getScope() { result = scopeOf(this) } +} diff --git a/powershell/ql/lib/semmle/code/powershell/Attribute.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Attribute.qll similarity index 75% rename from powershell/ql/lib/semmle/code/powershell/Attribute.qll rename to powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Attribute.qll index 72a061c09f2a..10c1183bec0a 100644 --- a/powershell/ql/lib/semmle/code/powershell/Attribute.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Attribute.qll @@ -1,8 +1,6 @@ -import powershell +private import Raw class Attribute extends @attribute, AttributeBase { - override string toString() { result = this.getName() } - override SourceLocation getLocation() { attribute_location(this, result) } string getName() { attribute(this, result, _, _) } @@ -13,6 +11,16 @@ class Attribute extends @attribute, AttributeBase { NamedAttributeArgument getNamedArgument(int i) { attribute_named_argument(this, i, result) } + final override Ast getChild(ChildIndex i) { + exists(int index | + i = AttributeNamedArg(index) and + result = this.getNamedArgument(index) + or + i = AttributePosArg(index) and + result = this.getPositionalArgument(index) + ) + } + NamedAttributeArgument getANamedArgument() { result = this.getNamedArgument(_) } int getNumberOfArguments() { result = count(this.getAPositionalArgument()) } diff --git a/powershell/ql/lib/semmle/code/powershell/AttributeBase.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/AttributeBase.qll similarity index 73% rename from powershell/ql/lib/semmle/code/powershell/AttributeBase.qll rename to powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/AttributeBase.qll index a0a5a36cdb10..6c4bf907c0a1 100644 --- a/powershell/ql/lib/semmle/code/powershell/AttributeBase.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/AttributeBase.qll @@ -1,3 +1,3 @@ -import powershell +private import Raw class AttributeBase extends @attribute_base, Ast { } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/AttributedExpr.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/AttributedExpr.qll new file mode 100644 index 000000000000..8987fd203e69 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/AttributedExpr.qll @@ -0,0 +1,17 @@ +private import Raw + +class AttributedExpr extends AttributedExprBase, @attributed_expression { + final override Expr getExpr() { attributed_expression(this, _, result) } + + final override Attribute getAttribute() { attributed_expression(this, result, _) } + + override Location getLocation() { attributed_expression_location(this, result) } + + override Ast getChild(ChildIndex i) { + i = AttributedExprExpr() and + result = this.getExpr() + or + i = AttributedExprAttr() and + result = this.getAttribute() + } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/AttributedExprBase.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/AttributedExprBase.qll new file mode 100644 index 000000000000..f8eb16d2768b --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/AttributedExprBase.qll @@ -0,0 +1,7 @@ +private import Raw + +class AttributedExprBase extends @attributed_expression_ast, Expr { + Expr getExpr() { none() } + + AttributeBase getAttribute() { none() } +} diff --git a/powershell/ql/lib/semmle/code/powershell/BaseConstantExpression.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/BaseConstantExpression.qll similarity index 64% rename from powershell/ql/lib/semmle/code/powershell/BaseConstantExpression.qll rename to powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/BaseConstantExpression.qll index c495e5da1859..7592f4dfc956 100644 --- a/powershell/ql/lib/semmle/code/powershell/BaseConstantExpression.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/BaseConstantExpression.qll @@ -1,4 +1,4 @@ -import powershell +private import Raw /** The base class for constant expressions. */ class BaseConstExpr extends @base_constant_expression, Expr { @@ -7,7 +7,4 @@ class BaseConstExpr extends @base_constant_expression, Expr { /** Gets a string literal of this constant expression. */ StringLiteral getValue() { none() } - - /** Gets a string literal representing this constant expression. */ - final override string toString() { result = this.getValue().toString() } } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/BinaryExpression.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/BinaryExpression.qll new file mode 100644 index 000000000000..8c26d6394219 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/BinaryExpression.qll @@ -0,0 +1,35 @@ +private import Raw + +class BinaryExpr extends @binary_expression, Expr { + override SourceLocation getLocation() { binary_expression_location(this, result) } + + int getKind() { binary_expression(this, result, _, _) } + + /** Gets an operand of this binary expression. */ + Expr getAnOperand() { + result = this.getLeft() + or + result = this.getRight() + } + + final override Ast getChild(ChildIndex i) { + i = BinaryExprLeft() and + result = this.getLeft() + or + i = BinaryExprRight() and + result = this.getRight() + } + + /** Holds if this binary expression has the operands `e1` and `e2`. */ + predicate hasOperands(Expr e1, Expr e2) { + e1 = this.getLeft() and + e2 = this.getRight() + or + e1 = this.getRight() and + e2 = this.getLeft() + } + + Expr getLeft() { binary_expression(this, _, result, _) } + + Expr getRight() { binary_expression(this, _, _, result) } +} diff --git a/powershell/ql/lib/semmle/code/powershell/BreakStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/BreakStmt.qll similarity index 66% rename from powershell/ql/lib/semmle/code/powershell/BreakStmt.qll rename to powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/BreakStmt.qll index abd74f3e682f..2c388b865fe8 100644 --- a/powershell/ql/lib/semmle/code/powershell/BreakStmt.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/BreakStmt.qll @@ -1,7 +1,5 @@ -import powershell +import Raw class BreakStmt extends GotoStmt, @break_statement { override SourceLocation getLocation() { break_statement_location(this, result) } - - override string toString() { result = "break" } } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/CatchClause.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/CatchClause.qll new file mode 100644 index 000000000000..ee66cefc579c --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/CatchClause.qll @@ -0,0 +1,25 @@ +private import Raw + +class CatchClause extends @catch_clause, Ast { + override SourceLocation getLocation() { catch_clause_location(this, result) } + + StmtBlock getBody() { catch_clause(this, result, _) } + + final override Ast getChild(ChildIndex i) { + i = CatchClauseBody() and + result = this.getBody() + or + exists(int index | + i = CatchClauseType(index) and + result = this.getCatchType(index) + ) + } + + TypeConstraint getCatchType(int i) { catch_clause_catch_type(this, i, result) } + + int getNumberOfCatchTypes() { result = count(this.getACatchType()) } + + TypeConstraint getACatchType() { result = this.getCatchType(_) } + + predicate isCatchAll() { not exists(this.getACatchType()) } +} diff --git a/powershell/ql/lib/semmle/code/powershell/Chainable.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Chainable.qll similarity index 73% rename from powershell/ql/lib/semmle/code/powershell/Chainable.qll rename to powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Chainable.qll index 273ccc48113a..1f5419d8f1f4 100644 --- a/powershell/ql/lib/semmle/code/powershell/Chainable.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Chainable.qll @@ -1,3 +1,3 @@ -import powershell +private import Raw class Chainable extends @chainable, PipelineBase { } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ChildIndex.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ChildIndex.qll new file mode 100644 index 000000000000..8da1c5e2fb22 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ChildIndex.qll @@ -0,0 +1,101 @@ +private import Raw + +newtype ChildIndex = + ArrayExprStmtBlock() or + ArrayLiteralExpr(int i) { exists(any(ArrayLiteral lit).getElement(i)) } or + AssignStmtLeftHandSide() or + AssignStmtRightHandSide() or + AttributeNamedArg(int i) { exists(any(Attribute a).getNamedArgument(i)) } or + AttributePosArg(int i) { exists(any(Attribute a).getPositionalArgument(i)) } or + AttributedExprExpr() or + AttributedExprAttr() or + BinaryExprLeft() or + BinaryExprRight() or + CatchClauseBody() or + CatchClauseType(int i) { exists(any(CatchClause c).getCatchType(i)) } or + CmdElement_(int i) { exists(any(Cmd cmd).getElement(i)) } or // TODO: Get rid of this? + CmdCallee() or + CmdRedirection(int i) { exists(any(Cmd cmd).getRedirection(i)) } or + CmdExprExpr() or + ConfigurationName() or + ConfigurationBody() or + ConvertExprExpr() or + ConvertExprType() or + ConvertExprAttr() or + DataStmtBody() or + DataStmtCmdAllowed(int i) { exists(any(DataStmt d).getCmdAllowed(i)) } or + DoUntilStmtCond() or + DoUntilStmtBody() or + DoWhileStmtCond() or + DoWhileStmtBody() or + DynamicStmtName() or + DynamicStmtBody() or + ExitStmtPipeline() or + ExpandableStringExprExpr(int i) { exists(any(ExpandableStringExpr e).getExpr(i)) } or + ForEachStmtVar() or + ForEachStmtIter() or + ForEachStmtBody() or + ForStmtInit() or + ForStmtCond() or + ForStmtIter() or + ForStmtBody() or + FunDefStmtBody() or + FunDefStmtParam(int i) { exists(any(FunctionDefinitionStmt def).getParameter(i)) } or + GotoStmtLabel() or + HashTableExprKey(int i) { exists(any(HashTableExpr e).getKey(i)) } or + HashTableExprStmt(int i) { exists(any(HashTableExpr e).getStmt(i)) } or + IfStmtElse() or + IfStmtCond(int i) { exists(any(IfStmt ifstmt).getCondition(i)) } or + IfStmtThen(int i) { exists(any(IfStmt ifstmt).getThen(i)) } or + IndexExprIndex() or + IndexExprBase() or + InvokeMemberExprQual() or + InvokeMemberExprCallee() or + InvokeMemberExprArg(int i) { exists(any(InvokeMemberExpr e).getArgument(i)) } or + MemberExprQual() or + MemberExprMember() or + NamedAttributeArgVal() or + MemberAttr(int i) { exists(any(Member m).getAttribute(i)) } or + MemberTypeConstraint() or + NamedBlockStmt(int i) { exists(any(NamedBlock b).getStmt(i)) } or + NamedBlockTrap(int i) { exists(any(NamedBlock b).getTrap(i)) } or + ParamBlockAttr(int i) { exists(any(ParamBlock p).getAttribute(i)) } or + ParamBlockParam(int i) { exists(any(ParamBlock p).getParameter(i)) } or + ParamAttr(int i) { exists(any(Parameter p).getAttribute(i)) } or + ParamDefaultVal() or + ParenExprExpr() or + PipelineComp(int i) { exists(any(Pipeline p).getComponent(i)) } or + PipelineChainLeft() or + PipelineChainRight() or + ReturnStmtPipeline() or + RedirectionExpr() or + ScriptBlockUsing(int i) { exists(any(ScriptBlock s).getUsing(i)) } or + ScriptBlockParamBlock() or + ScriptBlockBeginBlock() or + ScriptBlockCleanBlock() or + ScriptBlockDynParamBlock() or + ScriptBlockEndBlock() or + ScriptBlockProcessBlock() or + ScriptBlockExprBody() or + StmtBlockStmt(int i) { exists(any(StmtBlock b).getStmt(i)) } or + StmtBlockTrapStmt(int i) { exists(any(StmtBlock b).getTrapStmt(i)) } or + ExpandableSubExprExpr() or + SwitchStmtCond() or + SwitchStmtDefault() or + SwitchStmtCase(int i) { exists(any(SwitchStmt s).getCase(i)) } or + SwitchStmtPat(int i) { exists(any(SwitchStmt s).getPattern(i)) } or + CondExprCond() or + CondExprTrue() or + CondExprFalse() or + ThrowStmtPipeline() or + TryStmtBody() or + TryStmtCatchClause(int i) { exists(any(TryStmt t).getCatchClause(i)) } or + TryStmtFinally() or + TypeStmtMember(int i) { exists(any(TypeStmt t).getMember(i)) } or + TypeStmtBaseType(int i) { exists(any(TypeStmt t).getBaseType(i)) } or + TrapStmtBody() or + TrapStmtTypeConstraint() or + UnaryExprOp() or + UsingExprExpr() or + WhileStmtCond() or + WhileStmtBody() diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Command.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Command.qll new file mode 100644 index 000000000000..7186de94065c --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Command.qll @@ -0,0 +1,105 @@ +private import Raw + +private predicate parseCommandName(Cmd cmd, string namespace, string name) { + exists(string qualified | command(cmd, qualified, _, _, _) | + namespace = qualified.regexpCapture("([^\\\\]+)\\\\([^\\\\]+)", 1) and + name = qualified.regexpCapture("([^\\\\]+)\\\\([^\\\\]+)", 2) + or + // Not a qualified name + not exists(qualified.indexOf("\\")) and + namespace = "" and + name = qualified + ) +} + +/** A call to a command. */ +class Cmd extends @command, CmdBase { + override SourceLocation getLocation() { command_location(this, result) } + + final override Ast getChild(ChildIndex i) { + exists(int index | + i = CmdElement_(index) and + result = this.getElement(index) + or + i = CmdRedirection(index) and + result = this.getRedirection(index) + ) + } + + // TODO: This only make sense for some commands (e.g., not dot-sourcing) + CmdElement getCallee() { result = this.getElement(0) } + + /** Gets the name of the command without any qualifiers. */ + string getCommandName() { parseCommandName(this, _, result) } + + /** Holds if the command is qualified. */ + predicate isQualified() { parseCommandName(this, any(string s | s != ""), _) } + + /** Gets the (possibly qualified) name of this command. */ + string getQualifiedCommandName() { command(this, result, _, _, _) } + + int getKind() { command(this, _, result, _, _) } + + int getNumElements() { command(this, _, _, result, _) } + + int getNumRedirection() { command(this, _, _, _, result) } + + CmdElement getElement(int i) { command_command_element(this, i, result) } + + /** Gets the expression that determines the command to invoke. */ + Expr getCommand() { result = this.getElement(0) } + + Redirection getRedirection(int i) { command_redirection(this, i, result) } + + Redirection getARedirection() { result = this.getRedirection(_) } + + Expr getArgument(int i) { + result = + rank[i + 1](CmdElement e, Expr r, int j | + ( + // For most commands the 0'th element is the command name ... + j > 0 + or + // ... but for certain commands (such as the call operator or the dot- + // sourcing operator) the 0'th element is not the command name, but + // rather the thing to invoke. These all appear to be commands with + // an empty string as the command name. + this.getCommandName() = "" + ) and + e = this.getElement(j) and + ( + not e instanceof CmdParameter and + r = e + or + r = e.(CmdParameter).getExpr() + ) + | + r order by j + ) + } + + Expr getNamedArgument(string name) { + exists(CmdParameter p, int index | + result = this.getArgument(index) and + p.getName() = name + | + p.getExpr() = result + or + exists(int jndex | + not exists(p.getExpr()) and + this.getElement(jndex) = p and + this.getElement(jndex + 1) = result + ) + ) + } +} + +/** A call to operator `&`. */ +class CallOperator extends Cmd { + CallOperator() { this.getKind() = 28 } +} + +/** A call to the dot-sourcing `.`. */ +class DotSourcingOperator extends Cmd { + DotSourcingOperator() { this.getKind() = 35 } +} diff --git a/powershell/ql/lib/semmle/code/powershell/CommandBase.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/CommandBase.qll similarity index 73% rename from powershell/ql/lib/semmle/code/powershell/CommandBase.qll rename to powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/CommandBase.qll index 2ca1342a826f..b6ba3abb738a 100644 --- a/powershell/ql/lib/semmle/code/powershell/CommandBase.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/CommandBase.qll @@ -1,3 +1,3 @@ -import powershell +private import Raw class CmdBase extends @command_base, Chainable { } diff --git a/powershell/ql/lib/semmle/code/powershell/CommandElement.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/CommandElement.qll similarity index 73% rename from powershell/ql/lib/semmle/code/powershell/CommandElement.qll rename to powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/CommandElement.qll index 6dbdffa72503..ffeccacd5ebf 100644 --- a/powershell/ql/lib/semmle/code/powershell/CommandElement.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/CommandElement.qll @@ -1,3 +1,3 @@ -import powershell +private import Raw class CmdElement extends @command_element, Ast { } diff --git a/powershell/ql/lib/semmle/code/powershell/CommandExpression.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/CommandExpression.qll similarity index 77% rename from powershell/ql/lib/semmle/code/powershell/CommandExpression.qll rename to powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/CommandExpression.qll index b8e4bdf29860..7c9343ee7854 100644 --- a/powershell/ql/lib/semmle/code/powershell/CommandExpression.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/CommandExpression.qll @@ -1,15 +1,18 @@ -import powershell +private import Raw class CmdExpr extends @command_expression, CmdBase { override SourceLocation getLocation() { command_expression_location(this, result) } Expr getExpr() { command_expression(this, result, _) } + final override Ast getChild(ChildIndex i) { + i = CmdExprExpr() and + result = this.getExpr() + } + int getNumRedirections() { command_expression(this, _, result) } Redirection getRedirection(int i) { command_expression_redirection(this, i, result) } Redirection getARedirection() { result = this.getRedirection(_) } - - override string toString() { result = this.getExpr().toString() } } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/CommandParameter.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/CommandParameter.qll new file mode 100644 index 000000000000..5a9865830bdf --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/CommandParameter.qll @@ -0,0 +1,13 @@ +private import Raw + +class CmdParameter extends @command_parameter, CmdElement { + override SourceLocation getLocation() { command_parameter_location(this, result) } + + string getName() { command_parameter(this, result) } + + Ast getExpr() { + command_parameter_argument(this, result) + } + + Cmd getCmd() { result.getElement(_) = this } +} diff --git a/powershell/ql/lib/semmle/code/powershell/CommentEntity.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/CommentEntity.qll similarity index 96% rename from powershell/ql/lib/semmle/code/powershell/CommentEntity.qll rename to powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/CommentEntity.qll index d234eb0f3c78..e270595a12c4 100644 --- a/powershell/ql/lib/semmle/code/powershell/CommentEntity.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/CommentEntity.qll @@ -1,4 +1,4 @@ -import powershell +private import Raw class Comment extends @comment_entity { Location getLocation() { comment_entity_location(this, result) } diff --git a/powershell/ql/lib/semmle/code/powershell/Configuration.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Configuration.qll similarity index 69% rename from powershell/ql/lib/semmle/code/powershell/Configuration.qll rename to powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Configuration.qll index acc265924a20..8d9461b3c4de 100644 --- a/powershell/ql/lib/semmle/code/powershell/Configuration.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Configuration.qll @@ -1,14 +1,20 @@ -import powershell +private import Raw class Configuration extends @configuration_definition, Stmt { override SourceLocation getLocation() { configuration_definition_location(this, result) } - override string toString() { result = "Configuration" } - Expr getName() { configuration_definition(this, _, _, result) } ScriptBlockExpr getBody() { configuration_definition(this, result, _, _) } + final override Ast getChild(ChildIndex i) { + i = ConfigurationName() and + result = this.getName() + or + i = ConfigurationBody() and + result = this.getBody() + } + predicate isMeta() { configuration_definition(this, _, 1, _) } predicate isResource() { configuration_definition(this, _, 0, _) } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ConstantExpression.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ConstantExpression.qll new file mode 100644 index 000000000000..3f276a643885 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ConstantExpression.qll @@ -0,0 +1,9 @@ +private import Raw + +class ConstExpr extends @constant_expression, BaseConstExpr { + override SourceLocation getLocation() { constant_expression_location(this, result) } + + override string getType() { constant_expression(this, result) } + + override StringLiteral getValue() { constant_expression_value(this, result) } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ContinueStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ContinueStmt.qll similarity index 67% rename from powershell/ql/lib/semmle/code/powershell/ContinueStmt.qll rename to powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ContinueStmt.qll index 98fe1ba3fcbb..0140a92c8639 100644 --- a/powershell/ql/lib/semmle/code/powershell/ContinueStmt.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ContinueStmt.qll @@ -1,7 +1,5 @@ -import powershell +private import Raw class ContinueStmt extends GotoStmt, @continue_statement { override SourceLocation getLocation() { continue_statement_location(this, result) } - - override string toString() { result = "continue" } } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ConvertExpr.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ConvertExpr.qll new file mode 100644 index 000000000000..0bc041740928 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ConvertExpr.qll @@ -0,0 +1,22 @@ +private import Raw + +class ConvertExpr extends @convert_expression, AttributedExprBase { + override SourceLocation getLocation() { convert_expression_location(this, result) } + + final override Expr getExpr() { convert_expression(this, _, result, _, _) } + + TypeConstraint getType() { convert_expression(this, _, _, result, _) } + + final override AttributeBase getAttribute() { convert_expression(this, result, _, _, _) } + + final override Ast getChild(ChildIndex i) { + i = ConvertExprExpr() and + result = this.getExpr() + or + i = ConvertExprType() and + result = this.getType() + or + i = ConvertExprAttr() and + result = this.getAttribute() + } +} diff --git a/powershell/ql/lib/semmle/code/powershell/DataStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/DataStmt.qll similarity index 62% rename from powershell/ql/lib/semmle/code/powershell/DataStmt.qll rename to powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/DataStmt.qll index 205cdfbd862f..c8caa6e6cb7c 100644 --- a/powershell/ql/lib/semmle/code/powershell/DataStmt.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/DataStmt.qll @@ -1,10 +1,8 @@ -import powershell +private import Raw class DataStmt extends @data_statement, Stmt { override SourceLocation getLocation() { data_statement_location(this, result) } - override string toString() { result = "data {...}" } - string getVariableName() { data_statement_variable(this, result) } Expr getCmdAllowed(int i) { data_statement_commands_allowed(this, i, result) } @@ -12,4 +10,14 @@ class DataStmt extends @data_statement, Stmt { Expr getACmdAllowed() { result = this.getCmdAllowed(_) } StmtBlock getBody() { data_statement(this, result) } + + final override Ast getChild(ChildIndex i) { + i = DataStmtBody() and + result = this.getBody() + or + exists(int index | + i = DataStmtCmdAllowed(index) and + result = this.getCmdAllowed(index) + ) + } } diff --git a/powershell/ql/lib/semmle/code/powershell/DoUntilStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/DoUntilStmt.qll similarity index 60% rename from powershell/ql/lib/semmle/code/powershell/DoUntilStmt.qll rename to powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/DoUntilStmt.qll index a226931ec2ba..ef40c5460911 100644 --- a/powershell/ql/lib/semmle/code/powershell/DoUntilStmt.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/DoUntilStmt.qll @@ -1,11 +1,17 @@ -import powershell +private import Raw class DoUntilStmt extends @do_until_statement, LoopStmt { override SourceLocation getLocation() { do_until_statement_location(this, result) } - override string toString() { result = "DoUntil" } - PipelineBase getCondition() { do_until_statement_condition(this, result) } final override StmtBlock getBody() { do_until_statement(this, result) } + + final override Ast getChild(ChildIndex i) { + i = DoUntilStmtCond() and + result = this.getCondition() + or + i = DoUntilStmtBody() and + result = this.getBody() + } } diff --git a/powershell/ql/lib/semmle/code/powershell/DoWhileStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/DoWhileStmt.qll similarity index 60% rename from powershell/ql/lib/semmle/code/powershell/DoWhileStmt.qll rename to powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/DoWhileStmt.qll index 8d29567d01de..52909c5830fe 100644 --- a/powershell/ql/lib/semmle/code/powershell/DoWhileStmt.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/DoWhileStmt.qll @@ -1,11 +1,17 @@ -import powershell +private import Raw class DoWhileStmt extends @do_while_statement, LoopStmt { override SourceLocation getLocation() { do_while_statement_location(this, result) } - override string toString() { result = "DoWhile" } - PipelineBase getCondition() { do_while_statement_condition(this, result) } final override StmtBlock getBody() { do_while_statement(this, result) } + + final override Ast getChild(ChildIndex i) { + i = DoWhileStmtCond() and + result = this.getCondition() + or + i = DoWhileStmtBody() and + result = this.getBody() + } } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/DynamicStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/DynamicStmt.qll new file mode 100644 index 000000000000..e6e1d9c010cd --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/DynamicStmt.qll @@ -0,0 +1,27 @@ +private import Raw + +class DynamicStmt extends @dynamic_keyword_statement, Stmt { + override SourceLocation getLocation() { dynamic_keyword_statement_location(this, result) } + + CmdElement getName() { dynamic_keyword_statement_command_elements(this, 1, result) } + + ScriptBlockExpr getScriptBlock() { dynamic_keyword_statement_command_elements(this, 2, result) } + + HashTableExpr getHashTableExpr() { dynamic_keyword_statement_command_elements(this, 2, result) } + + predicate hasScriptBlock() { exists(this.getScriptBlock()) } + + predicate hasHashTableExpr() { exists(this.getHashTableExpr()) } + + final override Ast getChild(ChildIndex i) { + i = DynamicStmtName() and + result = this.getName() + or + i = DynamicStmtBody() and + ( + result = this.getScriptBlock() + or + result = this.getHashTableExpr() + ) + } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ErrorExpr.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ErrorExpr.qll similarity index 65% rename from powershell/ql/lib/semmle/code/powershell/ErrorExpr.qll rename to powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ErrorExpr.qll index 2816f4390b36..1f8d0d97720f 100644 --- a/powershell/ql/lib/semmle/code/powershell/ErrorExpr.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ErrorExpr.qll @@ -1,7 +1,5 @@ -import powershell +private import Raw class ErrorExpr extends @error_expression, Expr { final override SourceLocation getLocation() { error_expression_location(this, result) } - - final override string toString() { result = "error" } } diff --git a/powershell/ql/lib/semmle/code/powershell/ErrorStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ErrorStmt.qll similarity index 66% rename from powershell/ql/lib/semmle/code/powershell/ErrorStmt.qll rename to powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ErrorStmt.qll index 13be222c9c11..451922ad7e5c 100644 --- a/powershell/ql/lib/semmle/code/powershell/ErrorStmt.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ErrorStmt.qll @@ -1,7 +1,5 @@ -import powershell +private import Raw class ErrorStmt extends @error_statement, PipelineBase { final override SourceLocation getLocation() { error_statement_location(this, result) } - - final override string toString() { result = "error" } } diff --git a/powershell/ql/lib/semmle/code/powershell/ExitStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ExitStmt.qll similarity index 69% rename from powershell/ql/lib/semmle/code/powershell/ExitStmt.qll rename to powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ExitStmt.qll index 421bc453011f..299735945cf3 100644 --- a/powershell/ql/lib/semmle/code/powershell/ExitStmt.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ExitStmt.qll @@ -1,12 +1,14 @@ -import powershell +private import Raw class ExitStmt extends @exit_statement, Stmt { override SourceLocation getLocation() { exit_statement_location(this, result) } - override string toString() { if this.hasPipeline() then result = "exit ..." else result = "exit" } - /** ..., if any. */ PipelineBase getPipeline() { exit_statement_pipeline(this, result) } predicate hasPipeline() { exists(this.getPipeline()) } + + final override Ast getChild(ChildIndex i) { + i = ExitStmtPipeline() and result = this.getPipeline() + } } diff --git a/powershell/ql/lib/semmle/code/powershell/ExpandableStringExpression.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ExpandableStringExpression.qll similarity index 72% rename from powershell/ql/lib/semmle/code/powershell/ExpandableStringExpression.qll rename to powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ExpandableStringExpression.qll index fa3a8a77ba25..86b08a5e4121 100644 --- a/powershell/ql/lib/semmle/code/powershell/ExpandableStringExpression.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ExpandableStringExpression.qll @@ -1,10 +1,8 @@ -import powershell +private import Raw class ExpandableStringExpr extends @expandable_string_expression, Expr { override SourceLocation getLocation() { expandable_string_expression_location(this, result) } - override string toString() { result = this.getUnexpandedValue().toString() } - StringLiteral getUnexpandedValue() { expandable_string_expression(this, result, _, _) } int getNumExprs() { result = count(this.getAnExpr()) } @@ -12,4 +10,11 @@ class ExpandableStringExpr extends @expandable_string_expression, Expr { Expr getExpr(int i) { expandable_string_expression_nested_expression(this, i, result) } Expr getAnExpr() { result = this.getExpr(_) } + + final override Ast getChild(ChildIndex i) { + exists(int index | + i = ExpandableStringExprExpr(index) and + result = this.getExpr(index) + ) + } } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Expression.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Expression.qll new file mode 100644 index 000000000000..930b918c472c --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Expression.qll @@ -0,0 +1,8 @@ +private import Raw + +/** + * An expression. + * + * This is the topmost class in the hierachy of all expression in PowerShell. + */ +class Expr extends @expression, CmdElement { } diff --git a/powershell/ql/lib/semmle/code/powershell/File.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/File.qll similarity index 100% rename from powershell/ql/lib/semmle/code/powershell/File.qll rename to powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/File.qll diff --git a/powershell/ql/lib/semmle/code/powershell/FileRedirection.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/FileRedirection.qll similarity index 64% rename from powershell/ql/lib/semmle/code/powershell/FileRedirection.qll rename to powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/FileRedirection.qll index 68dca062551f..c398aeb9ec9a 100644 --- a/powershell/ql/lib/semmle/code/powershell/FileRedirection.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/FileRedirection.qll @@ -1,7 +1,5 @@ -import powershell +private import Raw class FileRedirection extends @file_redirection, Redirection { - override string toString() { result = "FileRedirection" } - override Location getLocation() { file_redirection_location(this, result) } } diff --git a/powershell/ql/lib/semmle/code/powershell/ForEachStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ForEachStmt.qll similarity index 63% rename from powershell/ql/lib/semmle/code/powershell/ForEachStmt.qll rename to powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ForEachStmt.qll index 4cbcc87038f7..980c2e848949 100644 --- a/powershell/ql/lib/semmle/code/powershell/ForEachStmt.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ForEachStmt.qll @@ -1,23 +1,21 @@ -import powershell +private import Raw class ForEachStmt extends @foreach_statement, LoopStmt { override SourceLocation getLocation() { foreach_statement_location(this, result) } - override string toString() { result = "forach(... in ...)" } - final override StmtBlock getBody() { foreach_statement(this, _, _, result, _) } VarAccess getVarAccess() { foreach_statement(this, result, _, _, _) } - Variable getVariable() { - exists(VarAccess va | - va = this.getVarAccess() and - foreach_statement(this, va, _, _, _) and - result = va.getVariable() - ) - } - PipelineBase getIterableExpr() { foreach_statement(this, _, result, _, _) } predicate isParallel() { foreach_statement(this, _, _, _, 1) } + + final override Ast getChild(ChildIndex i) { + i = ForEachStmtVar() and result = this.getVarAccess() + or + i = ForEachStmtIter() and result = this.getIterableExpr() + or + i = ForEachStmtBody() and result = this.getBody() + } } diff --git a/powershell/ql/lib/semmle/code/powershell/ForStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ForStmt.qll similarity index 56% rename from powershell/ql/lib/semmle/code/powershell/ForStmt.qll rename to powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ForStmt.qll index 104d3e3e2272..e136f274b214 100644 --- a/powershell/ql/lib/semmle/code/powershell/ForStmt.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ForStmt.qll @@ -1,10 +1,8 @@ -import powershell +private import Raw class ForStmt extends @for_statement, LoopStmt { override SourceLocation getLocation() { for_statement_location(this, result) } - override string toString() { result = "for(...;...;...)" } - PipelineBase getInitializer() { for_statement_initializer(this, result) } PipelineBase getCondition() { for_statement_condition(this, result) } @@ -12,4 +10,18 @@ class ForStmt extends @for_statement, LoopStmt { PipelineBase getIterator() { for_statement_iterator(this, result) } final override StmtBlock getBody() { for_statement(this, result) } + + final override Ast getChild(ChildIndex i) { + i = ForStmtInit() and + result = this.getInitializer() + or + i = ForStmtCond() and + result = this.getCondition() + or + i = ForStmtIter() and + result = this.getIterator() + or + i = ForStmtBody() and + result = this.getBody() + } } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Function.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Function.qll new file mode 100644 index 000000000000..6b303fb36be5 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Function.qll @@ -0,0 +1,22 @@ +private import Raw + +class FunctionDefinitionStmt extends @function_definition, Stmt { + override Location getLocation() { function_definition_location(this, result) } + + ScriptBlock getBody() { function_definition(this, result, _, _, _) } + + string getName() { function_definition(this, _, result, _, _) } + + Parameter getParameter(int i) { function_definition_parameter(this, i, result) } + + Parameter getAParameter() { result = this.getParameter(_) } + + override Ast getChild(ChildIndex i) { + i = FunDefStmtBody() and result = this.getBody() + or + exists(int index | + i = FunDefStmtParam(index) and + result = this.getParameter(index) + ) + } +} diff --git a/powershell/ql/lib/semmle/code/powershell/GotoStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/GotoStmt.qll similarity index 59% rename from powershell/ql/lib/semmle/code/powershell/GotoStmt.qll rename to powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/GotoStmt.qll index 64cc20bf8002..bae96f4aa51f 100644 --- a/powershell/ql/lib/semmle/code/powershell/GotoStmt.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/GotoStmt.qll @@ -1,8 +1,9 @@ -import powershell +private import Raw /** A `break` or `continue` statement. */ class GotoStmt extends @labelled_statement, Stmt { - /** ..., if any. */ Expr getLabel() { statement_label(this, result) } + + final override Ast getChild(ChildIndex i) { i = GotoStmtLabel() and result = this.getLabel() } } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/HashTable.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/HashTable.qll new file mode 100644 index 000000000000..200c1b13a803 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/HashTable.qll @@ -0,0 +1,23 @@ +private import Raw + +class HashTableExpr extends @hash_table, Expr { + final override Location getLocation() { hash_table_location(this, result) } + + Expr getKey(int i) { hash_table_key_value_pairs(this, i, result, _) } + + Expr getAKey() { result = this.getKey(_) } + + Stmt getStmt(int i) { hash_table_key_value_pairs(this, i, _, result) } + + Stmt getAStmt() { result = this.getStmt(_) } + + final override Ast getChild(ChildIndex i) { + exists(int index | + i = HashTableExprKey(index) and + result = this.getKey(index) + or + i = HashTableExprStmt(index) and + result = this.getStmt(index) + ) + } +} diff --git a/powershell/ql/lib/semmle/code/powershell/IfStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/IfStmt.qll similarity index 66% rename from powershell/ql/lib/semmle/code/powershell/IfStmt.qll rename to powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/IfStmt.qll index 21ce4d68fc8b..35754f5740a1 100644 --- a/powershell/ql/lib/semmle/code/powershell/IfStmt.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/IfStmt.qll @@ -1,12 +1,8 @@ -import powershell +private import Raw class IfStmt extends @if_statement, Stmt { override SourceLocation getLocation() { if_statement_location(this, result) } - override string toString() { - if this.hasElse() then result = "if (...) {...} else {...}" else result = "if (...) {...}" - } - PipelineBase getCondition(int i) { if_statement_clause(this, i, result, _) } PipelineBase getACondition() { result = this.getCondition(_) } @@ -21,4 +17,17 @@ class IfStmt extends @if_statement, Stmt { StmtBlock getElse() { if_statement_else(this, result) } predicate hasElse() { exists(this.getElse()) } + + final override Ast getChild(ChildIndex i) { + i = IfStmtElse() and + result = this.getElse() + or + exists(int index | + i = IfStmtCond(index) and + result = this.getCondition(index) + or + i = IfStmtThen(index) and + result = this.getThen(index) + ) + } } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/IndexExpr.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/IndexExpr.qll new file mode 100644 index 000000000000..9b98e364480a --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/IndexExpr.qll @@ -0,0 +1,18 @@ +private import Raw + +class IndexExpr extends @index_expression, Expr { + override SourceLocation getLocation() { index_expression_location(this, result) } + + Expr getIndex() { index_expression(this, result, _, _) } // TODO: Change @ast to @expr in the dbscheme + + Expr getBase() { index_expression(this, _, result, _) } // TODO: Change @ast to @expr in the dbscheme + + predicate isNullConditional() { index_expression(this, _, _, true) } + + final override Ast getChild(ChildIndex i) { + i = IndexExprIndex() and + result = this.getIndex() + or + i = IndexExprBase() and result = this.getBase() + } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/InvokeMemberExpression.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/InvokeMemberExpression.qll new file mode 100644 index 000000000000..a2fa623f3957 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/InvokeMemberExpression.qll @@ -0,0 +1,32 @@ +private import Raw + +class InvokeMemberExpr extends @invoke_member_expression, MemberExprBase { + override SourceLocation getLocation() { invoke_member_expression_location(this, result) } + + Expr getQualifier() { invoke_member_expression(this, result, _) } + + string getName() { result = this.getCallee().(StringConstExpr).getValue().getValue() } + + Expr getCallee() { invoke_member_expression(this, _, result) } + + string getMemberName() { result = this.getCallee().(StringConstExpr).getValue().getValue() } + + Expr getArgument(int i) { invoke_member_expression_argument(this, i, result) } + + Expr getAnArgument() { invoke_member_expression_argument(this, _, result) } + + final override Ast getChild(ChildIndex i) { + i = InvokeMemberExprQual() and + result = this.getQualifier() + or + i = InvokeMemberExprCallee() and + result = this.getCallee() + or + exists(int index | + i = InvokeMemberExprArg(index) and + result = this.getArgument(index) + ) + } + + override predicate isStatic() { this.getQualifier() instanceof TypeNameExpr } +} diff --git a/powershell/ql/lib/semmle/code/powershell/LabeledStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/LabeledStmt.qll similarity index 84% rename from powershell/ql/lib/semmle/code/powershell/LabeledStmt.qll rename to powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/LabeledStmt.qll index fff4e1712ccb..058d15922dfe 100644 --- a/powershell/ql/lib/semmle/code/powershell/LabeledStmt.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/LabeledStmt.qll @@ -1,4 +1,4 @@ -import powershell +private import Raw class LabeledStmt extends @labeled_statement, Stmt { string getLabel() { label(this, result) } diff --git a/powershell/ql/lib/semmle/code/powershell/Location.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Location.qll similarity index 84% rename from powershell/ql/lib/semmle/code/powershell/Location.qll rename to powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Location.qll index c08dcb83af11..574d5598578f 100644 --- a/powershell/ql/lib/semmle/code/powershell/Location.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Location.qll @@ -44,6 +44,14 @@ class Location extends @location { /** Gets the 1-based column number (inclusive) where this location ends. */ int getEndColumn() { this.hasLocationInfo(_, _, _, _, result) } + + /** Holds if this location starts strictly before the specified location. */ + pragma[inline] + predicate strictlyBefore(Location other) { + this.getStartLine() < other.getStartLine() + or + this.getStartLine() = other.getStartLine() and this.getStartColumn() < other.getStartColumn() + } } /** An empty location. */ diff --git a/powershell/ql/lib/semmle/code/powershell/LoopStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/LoopStmt.qll similarity index 82% rename from powershell/ql/lib/semmle/code/powershell/LoopStmt.qll rename to powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/LoopStmt.qll index edd9417a4951..2889b1c7d8d7 100644 --- a/powershell/ql/lib/semmle/code/powershell/LoopStmt.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/LoopStmt.qll @@ -1,4 +1,4 @@ -import powershell +private import Raw class LoopStmt extends @loop_statement, LabeledStmt { StmtBlock getBody() { none() } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Member.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Member.qll new file mode 100644 index 000000000000..9c0c2d29ba0b --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Member.qll @@ -0,0 +1,62 @@ +private import Raw + +class Member extends @member, Ast { + TypeStmt getDeclaringType() { result.getAMember() = this } + + string getName() { none() } + + predicate isHidden() { none() } + + predicate isPrivate() { none() } + + predicate isPublic() { none() } + + predicate isStatic() { none() } + + Attribute getAttribute(int i) { none() } + + final Attribute getAnAttribute() { result = this.getAttribute(_) } + + TypeConstraint getTypeConstraint() { none() } + + override Ast getChild(ChildIndex i) { + exists(int index | + i = MemberAttr(index) and + result = this.getAttribute(index) + ) + or + i = MemberTypeConstraint() and + result = this.getTypeConstraint() + } +} + +/** + * A method definition. That is, a function defined inside a class definition. + */ +class Method extends Member { + Method() { function_member(this, _, _, _, _, _, _, _, _) } + + ScriptBlock getBody() { function_member(this, result, _, _, _, _, _, _, _) } + + final override predicate isStatic() { function_member(this, _, _, _, _, _, true, _, _) } + + final override string getName() { function_member(this, _, _, _, _, _, _, result, _) } + + predicate isConstructor() { function_member(this, _, true, _, _, _, _, _, _) } + + override Location getLocation() { function_member_location(this, result) } + + override Attribute getAttribute(int i) { function_member_attribute(this, i, result) } + + override TypeConstraint getTypeConstraint() { function_member_return_type(this, result) } + + FunctionDefinitionStmt getFunctionDefinitionStmt() { result.getBody() = this.getBody() } +} + +class MethodScriptBlock extends ScriptBlock { + Method m; + + MethodScriptBlock() { m.getBody() = this } + + Method getMethod() { result = m } +} diff --git a/powershell/ql/lib/semmle/code/powershell/MemberExpr.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/MemberExpr.qll similarity index 82% rename from powershell/ql/lib/semmle/code/powershell/MemberExpr.qll rename to powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/MemberExpr.qll index 1d6d143c053e..26f4996f52ca 100644 --- a/powershell/ql/lib/semmle/code/powershell/MemberExpr.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/MemberExpr.qll @@ -1,4 +1,4 @@ -import powershell +private import Raw class MemberExpr extends @member_expression, MemberExprBase { final override Location getLocation() { member_expression_location(this, result) } @@ -14,7 +14,12 @@ class MemberExpr extends @member_expression, MemberExprBase { override predicate isStatic() { member_expression(this, _, _, _, true) } - final override string toString() { result = this.getMember().toString() } + final override Ast getChild(ChildIndex i) { + i = MemberExprQual() and result = this.getQualifier() + or + i = MemberExprMember() and + result = this.getMember() + } } /** A `MemberExpr` that is being written to. */ diff --git a/powershell/ql/lib/semmle/code/powershell/MemberExpressionBase.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/MemberExpressionBase.qll similarity index 83% rename from powershell/ql/lib/semmle/code/powershell/MemberExpressionBase.qll rename to powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/MemberExpressionBase.qll index 81db24f00196..02758e5a7867 100644 --- a/powershell/ql/lib/semmle/code/powershell/MemberExpressionBase.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/MemberExpressionBase.qll @@ -1,4 +1,4 @@ -import powershell +private import Raw class MemberExprBase extends @member_expression_base, Expr { predicate isStatic() { none() } diff --git a/powershell/ql/lib/semmle/code/powershell/MergingRedirection.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/MergingRedirection.qll similarity index 65% rename from powershell/ql/lib/semmle/code/powershell/MergingRedirection.qll rename to powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/MergingRedirection.qll index b227fc3c585f..491dbada6bb0 100644 --- a/powershell/ql/lib/semmle/code/powershell/MergingRedirection.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/MergingRedirection.qll @@ -1,7 +1,5 @@ -import powershell +private import Raw class MergingRedirection extends @merging_redirection, Redirection { - override string toString() { result = "MergingRedirection" } - override Location getLocation() { merging_redirection_location(this, result) } } diff --git a/powershell/ql/lib/semmle/code/powershell/ModuleSpecification.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ModuleSpecification.qll similarity index 96% rename from powershell/ql/lib/semmle/code/powershell/ModuleSpecification.qll rename to powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ModuleSpecification.qll index 5e2a3d3d3918..9a512d62690c 100644 --- a/powershell/ql/lib/semmle/code/powershell/ModuleSpecification.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ModuleSpecification.qll @@ -1,4 +1,4 @@ -import powershell +private import Raw class ModuleSpecification extends @module_specification { string toString() { result = this.getName() } diff --git a/powershell/ql/lib/semmle/code/powershell/NamedAttributeArgument.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/NamedAttributeArgument.qll similarity index 83% rename from powershell/ql/lib/semmle/code/powershell/NamedAttributeArgument.qll rename to powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/NamedAttributeArgument.qll index 1d05343b87ea..324dec4d27e7 100644 --- a/powershell/ql/lib/semmle/code/powershell/NamedAttributeArgument.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/NamedAttributeArgument.qll @@ -1,8 +1,6 @@ -import powershell +private import Raw class NamedAttributeArgument extends @named_attribute_argument, Ast { - final override string toString() { result = this.getName() } - final override SourceLocation getLocation() { named_attribute_argument_location(this, result) } string getName() { named_attribute_argument(this, result, _) } @@ -10,6 +8,10 @@ class NamedAttributeArgument extends @named_attribute_argument, Ast { predicate hasName(string s) { this.getName() = s } Expr getValue() { named_attribute_argument(this, _, result) } + + final override Ast getChild(ChildIndex i) { + i = NamedAttributeArgVal() and result = this.getValue() + } } class ValueFromPipelineAttribute extends NamedAttributeArgument { diff --git a/powershell/ql/lib/semmle/code/powershell/NamedBlock.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/NamedBlock.qll similarity index 50% rename from powershell/ql/lib/semmle/code/powershell/NamedBlock.qll rename to powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/NamedBlock.qll index 5bf4de25cb38..f11e621e74d0 100644 --- a/powershell/ql/lib/semmle/code/powershell/NamedBlock.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/NamedBlock.qll @@ -1,8 +1,6 @@ -import powershell +private import Raw class NamedBlock extends @named_block, Ast { - override string toString() { result = "{...}" } - override SourceLocation getLocation() { named_block_location(this, result) } int getNumStatements() { named_block(this, result, _) } @@ -16,4 +14,23 @@ class NamedBlock extends @named_block, Ast { TrapStmt getTrap(int i) { named_block_trap(this, i, result) } TrapStmt getATrap() { result = this.getTrap(_) } + + final override Ast getChild(ChildIndex i) { + exists(int index | + i = NamedBlockStmt(index) and + result = this.getStmt(index) + or + i = NamedBlockTrap(index) and + result = this.getTrap(index) + ) + } +} + +/** A `process` block. */ +class ProcessBlock extends NamedBlock { + ScriptBlock scriptBlock; + + ProcessBlock() { scriptBlock.getProcessBlock() = this } + + ScriptBlock getScriptBlock() { result = scriptBlock } } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ParamBlock.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ParamBlock.qll new file mode 100644 index 000000000000..0ebae92854af --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ParamBlock.qll @@ -0,0 +1,36 @@ +private import Raw + +class ParamBlock extends @param_block, Ast { + override SourceLocation getLocation() { param_block_location(this, result) } + + int getNumAttributes() { param_block(this, result, _) } + + int getNumParameters() { param_block(this, _, result) } + + Attribute getAttribute(int i) { param_block_attribute(this, i, result) } + + Attribute getAnAttribute() { result = this.getAttribute(_) } + + Parameter getParameter(int i) { param_block_parameter(this, i, result) } + + Parameter getAParameter() { result = this.getParameter(_) } + + PipelineParameter getPipelineParameter() { result = this.getAParameter() } + + PipelineByPropertyNameParameter getAPipelineByPropertyNameParameter() { + result = this.getAParameter() + } + + final override Ast getChild(ChildIndex i) { + exists(int index | + i = ParamBlockAttr(index) and + result = this.getAttribute(index) + or + i = ParamBlockParam(index) and + result = this.getParameter(index) + ) + } + + /** Gets the script block, if any. */ + ScriptBlock getScriptBlock() { result.getParamBlock() = this } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Parameter.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Parameter.qll new file mode 100644 index 000000000000..32669d0141ea --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Parameter.qll @@ -0,0 +1,60 @@ +private import Raw + +class Parameter extends @parameter, Ast { + string getName() { + exists(@variable_expression va | + parameter(this, va, _, _) and + variable_expression(va, result, _, _, _, _, _, _, _, _, _, _) + ) + } + + override SourceLocation getLocation() { parameter_location(this, result) } + + AttributeBase getAttribute(int i) { parameter_attribute(this, i, result) } + + AttributeBase getAnAttribute() { result = this.getAttribute(_) } + + Expr getDefaultValue() { parameter_default_value(this, result) } + + final override Ast getChild(ChildIndex i) { + exists(int index | + i = ParamAttr(index) and + result = this.getAttribute(index) + ) + or + i = ParamDefaultVal() and + result = this.getDefaultValue() + } + + string getStaticType() { parameter(this, _, result, _) } +} + +class PipelineParameter extends Parameter { + PipelineParameter() { + exists(NamedAttributeArgument namedAttribute | + this.getAnAttribute().(Attribute).getANamedArgument() = namedAttribute and + namedAttribute.getName().toLowerCase() = "valuefrompipeline" + | + namedAttribute.getValue().(ConstExpr).getValue().getValue() = "true" + or + not exists(namedAttribute.getValue().(ConstExpr).getValue().getValue()) + ) + } + + ScriptBlock getScriptBlock() { result.getParamBlock().getAParameter() = this } +} + +class PipelineByPropertyNameParameter extends Parameter { + PipelineByPropertyNameParameter() { + exists(NamedAttributeArgument namedAttribute | + this.getAnAttribute().(Attribute).getANamedArgument() = namedAttribute and + namedAttribute.getName().toLowerCase() = "valuefrompipelinebypropertyname" + | + namedAttribute.getValue().(ConstExpr).getValue().getValue() = "true" + or + not exists(namedAttribute.getValue().(ConstExpr).getValue().getValue()) + ) + } + + ScriptBlock getScriptBlock() { result.getParamBlock().getAParameter() = this } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ParenExpression.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ParenExpression.qll similarity index 63% rename from powershell/ql/lib/semmle/code/powershell/ParenExpression.qll rename to powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ParenExpression.qll index 6a71d2681307..5e767329b165 100644 --- a/powershell/ql/lib/semmle/code/powershell/ParenExpression.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ParenExpression.qll @@ -1,9 +1,9 @@ -import powershell +private import Raw class ParenExpr extends @paren_expression, Expr { PipelineBase getBase() { paren_expression(this, result) } override SourceLocation getLocation() { paren_expression_location(this, result) } - override string toString() { result = "(...)" } + final override Ast getChild(ChildIndex i) { i = ParenExprExpr() and result = this.getBase() } } diff --git a/powershell/ql/lib/semmle/code/powershell/Pipeline.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Pipeline.qll similarity index 66% rename from powershell/ql/lib/semmle/code/powershell/Pipeline.qll rename to powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Pipeline.qll index f630a117e547..c8d24d6f8ba6 100644 --- a/powershell/ql/lib/semmle/code/powershell/Pipeline.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Pipeline.qll @@ -1,12 +1,6 @@ -import powershell +private import Raw class Pipeline extends @pipeline, Chainable { - override string toString() { - if this.getNumberOfComponents() = 1 - then result = this.getComponent(0).toString() - else result = "...|..." - } - override SourceLocation getLocation() { pipeline_location(this, result) } int getNumberOfComponents() { result = count(this.getAComponent()) } @@ -14,4 +8,11 @@ class Pipeline extends @pipeline, Chainable { CmdBase getComponent(int i) { pipeline_component(this, i, result) } CmdBase getAComponent() { result = this.getComponent(_) } + + final override Ast getChild(ChildIndex i) { + exists(int index | + i = PipelineComp(index) and + result = this.getComponent(index) + ) + } } diff --git a/powershell/ql/lib/semmle/code/powershell/PipelineBase.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/PipelineBase.qll similarity index 73% rename from powershell/ql/lib/semmle/code/powershell/PipelineBase.qll rename to powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/PipelineBase.qll index bb2d8cab85e4..9c1e793a4e5c 100644 --- a/powershell/ql/lib/semmle/code/powershell/PipelineBase.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/PipelineBase.qll @@ -1,3 +1,3 @@ -import powershell +private import Raw class PipelineBase extends @pipeline_base, Stmt { } diff --git a/powershell/ql/lib/semmle/code/powershell/PipelineChain.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/PipelineChain.qll similarity index 64% rename from powershell/ql/lib/semmle/code/powershell/PipelineChain.qll rename to powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/PipelineChain.qll index ee5dd56cec0a..f7e08c9b41e5 100644 --- a/powershell/ql/lib/semmle/code/powershell/PipelineChain.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/PipelineChain.qll @@ -1,4 +1,4 @@ -import powershell +private import Raw class PipelineChain extends @pipeline_chain, Chainable { final override SourceLocation getLocation() { pipeline_chain_location(this, result) } @@ -8,4 +8,10 @@ class PipelineChain extends @pipeline_chain, Chainable { Chainable getLeft() { pipeline_chain(this, _, _, result, _) } Pipeline getRight() { pipeline_chain(this, _, _, _, result) } + + final override Ast getChild(ChildIndex i) { + i = PipelineChainLeft() and result = this.getLeft() + or + i = PipelineChainRight() and result = this.getRight() + } } diff --git a/powershell/ql/lib/semmle/code/powershell/PropertyMember.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/PropertyMember.qll similarity index 72% rename from powershell/ql/lib/semmle/code/powershell/PropertyMember.qll rename to powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/PropertyMember.qll index e9144dc78e45..b7830927ed9a 100644 --- a/powershell/ql/lib/semmle/code/powershell/PropertyMember.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/PropertyMember.qll @@ -1,12 +1,10 @@ -import powershell +private import Raw class PropertyMember extends @property_member, Member { override string getName() { property_member(this, _, _, _, _, result, _) } override SourceLocation getLocation() { property_member_location(this, result) } - override string toString() { result = this.getName() } - override predicate isHidden() { property_member(this, true, _, _, _, _, _) } override predicate isPrivate() { property_member(this, _, true, _, _, _, _) } @@ -14,4 +12,8 @@ class PropertyMember extends @property_member, Member { override predicate isPublic() { property_member(this, _, _, true, _, _, _) } override predicate isStatic() { property_member(this, _, _, _, true, _, _) } + + override Attribute getAttribute(int i) { property_member_attribute(this, i, result) } + + override TypeConstraint getTypeConstraint() { property_member_property_type(this, result) } } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Raw.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Raw.qll new file mode 100644 index 000000000000..537161ac3111 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Raw.qll @@ -0,0 +1,84 @@ +import ChildIndex +import ArrayExpression +import ArrayLiteral +import AssignmentStatement +import Ast +import Attribute +import AttributeBase +import BaseConstantExpression +import BinaryExpression +import BreakStmt +import CatchClause +import Chainable +import Command +import CommandBase +import CommandElement +import CommandExpression +import CommandParameter +import CommentEntity +import Configuration +import ConstantExpression +import ContinueStmt +import ConvertExpr +import DataStmt +import DoUntilStmt +import DoWhileStmt +import DynamicStmt +import ErrorExpr +import ErrorStmt +import ExitStmt +import ExpandableStringExpression +import Expression +import File +import FileRedirection +import ForEachStmt +import ForStmt +import Function +import GotoStmt +import HashTable +import IfStmt +import IndexExpr +import InvokeMemberExpression +import LabeledStmt +import Location +import LoopStmt +import Member +import MemberExpr +import MemberExpressionBase +import MergingRedirection +import ModuleSpecification +import NamedAttributeArgument +import NamedBlock +import ParamBlock +import Parameter +import ParenExpression +import Pipeline +import PipelineBase +import PipelineChain +import PropertyMember +import Redirection +import ReturnStmt +import ScriptBlock +import ScriptBlockExpr +import SourceLocation +import Statement +import StatementBlock +import StringConstantExpression +import StringLiteral +import SubExpression +import SwitchStmt +import TernaryExpression +import ThrowStmt +import TrapStatement +import TryStmt +import Type +import TypeConstraint +import TypeExpression +import UnaryExpression +import UsingExpression +import UsingStmt +import VariableExpression +import WhileStmt +import AttributedExpr +import AttributedExprBase +import Scope \ No newline at end of file diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Redirection.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Redirection.qll new file mode 100644 index 000000000000..e4303171df3f --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Redirection.qll @@ -0,0 +1,10 @@ +private import Raw + +class Redirection extends @redirection, Ast { + Expr getExpr() { parent(result, this) } // TODO: Is there really no other way to get this? + + final override Ast getChild(ChildIndex i) { + i = RedirectionExpr() and + result = this.getExpr() + } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ReturnStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ReturnStmt.qll similarity index 67% rename from powershell/ql/lib/semmle/code/powershell/ReturnStmt.qll rename to powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ReturnStmt.qll index aa8ad6732514..a007dec2ffec 100644 --- a/powershell/ql/lib/semmle/code/powershell/ReturnStmt.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ReturnStmt.qll @@ -1,13 +1,11 @@ -import powershell +private import Raw class ReturnStmt extends @return_statement, Stmt { override SourceLocation getLocation() { return_statement_location(this, result) } - override string toString() { - if this.hasPipeline() then result = "return ..." else result = "return" - } - PipelineBase getPipeline() { return_statement_pipeline(this, result) } predicate hasPipeline() { exists(this.getPipeline()) } + + final override Ast getChild(ChildIndex i) { i = ReturnStmtPipeline() and result = this.getPipeline() } } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Scope.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Scope.qll new file mode 100644 index 000000000000..6c8488e1a1a8 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Scope.qll @@ -0,0 +1,59 @@ +private import Raw + +/** Gets the enclosing scope of `n`. */ +Scope scopeOf(Ast n) { + exists(Ast m | m = n.getParent() | + m = result + or + not m instanceof Scope and result = scopeOf(m) + ) +} + +module Parameter { + abstract class Scope extends Ast { + abstract string getName(); + } + + private class ParameterScope extends Scope instanceof Parameter { + final override string getName() { result = Parameter.super.getName() } + } +} + +abstract private class ScopeImpl extends Ast { + abstract Scope getOuterScopeImpl(); + + abstract Ast getParameterImpl(int index); +} + +class Scope instanceof ScopeImpl { + Scope getOuterScope() { result = super.getOuterScopeImpl() } + + string toString() { result = super.toString() } + + Parameter getParameter(int index) { result = super.getParameterImpl(index) } + + Parameter getAParameter() { result = this.getParameter(_) } + + Location getLocation() { result = super.getLocation() } +} + +/** + * A variable scope. This is either a top-level (file), a module, a class, + * or a callable. + */ +private class ScriptBlockScope extends ScopeImpl instanceof ScriptBlock { + /** Gets the outer scope, if any. */ + override Scope getOuterScopeImpl() { result = scopeOf(this) } + + override Parameter getParameterImpl(int index) { + exists(ParamBlock pb | + pb.getParameter(index) = result and + pb.getScriptBlock() = this + ) + or + exists(FunctionDefinitionStmt func | + func.getParameter(index) = result and + func.getBody() = this + ) + } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ScriptBlock.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ScriptBlock.qll similarity index 50% rename from powershell/ql/lib/semmle/code/powershell/ScriptBlock.qll rename to powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ScriptBlock.qll index 4e6c77352234..4b923136aa38 100644 --- a/powershell/ql/lib/semmle/code/powershell/ScriptBlock.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ScriptBlock.qll @@ -1,15 +1,8 @@ -import powershell -private import semmle.code.powershell.controlflow.internal.Scope +private import Raw class ScriptBlock extends @script_block, Ast { predicate isTopLevel() { not exists(this.getParent()) } - override string toString() { - if this.isTopLevel() - then result = this.getLocation().getFile().getBaseName() - else result = "{...}" - } - override Location getLocation() { script_block_location(this, result) } int getNumUsings() { script_block(this, result, _, _, _, _) } @@ -50,59 +43,29 @@ class ScriptBlock extends @script_block, Ast { ModuleSpecification getAModuleSpecification() { result = this.getModuleSpecification(_) } - final override Scope getEnclosingScope() { result = this } - - /** - * Gets the `i`'th paramter in this scope. - * - * This may be both function paramters and parameter block parameters. - */ - Parameter getParameter(int i) { - exists(Function func | - func.getBody() = this and - result = func.getParameter(i) + final override Ast getChild(ChildIndex i) { + exists(int index | + i = ScriptBlockUsing(index) and + result = this.getUsing(index) ) or - this.isTopLevel() and - result = this.getParamBlock().getParameter(i) - } - - /** - * Gets a paramter in this scope. - * - * This may be both function parameters and parameter block parameters. - */ - Parameter getAParameter() { result = this.getParameter(_) } - - Parameter getThisParameter() { - exists(Function func | - func.getBody() = this and - result = func.getThisParameter() - ) - } - - /** Gets the number of function parameters. */ - final int getNumberOfParameters() { result = count(this.getAParameter()) } - - final Parameter getParameterExcludingPiplines(int i) { - result = this.getParamBlock().getParameterExcludingPiplines(i) - } -} - -/** A `process` block. */ -class ProcessBlock extends NamedBlock { - ScriptBlock scriptBlock; - - ProcessBlock() { scriptBlock.getProcessBlock() = this } - - ScriptBlock getScriptBlock() { result = scriptBlock } - - PipelineParameter getPipelineParameter() { - result = scriptBlock.getEnclosingFunction().getAParameter() - } - - PipelineByPropertyNameParameter getAPipelineByPropertyNameParameter() { - result = scriptBlock.getEnclosingFunction().getAParameter() + i = ScriptBlockParamBlock() and + result = this.getParamBlock() + or + i = ScriptBlockBeginBlock() and + result = this.getBeginBlock() + or + i = ScriptBlockCleanBlock() and + result = this.getCleanBlock() + or + i = ScriptBlockDynParamBlock() and + result = this.getDynamicParamBlock() + or + i = ScriptBlockEndBlock() and + result = this.getEndBlock() + or + i = ScriptBlockProcessBlock() and + result = this.getProcessBlock() } } diff --git a/powershell/ql/lib/semmle/code/powershell/ScriptBlockExpr.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ScriptBlockExpr.qll similarity index 65% rename from powershell/ql/lib/semmle/code/powershell/ScriptBlockExpr.qll rename to powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ScriptBlockExpr.qll index 78dd5abbc2e6..288daed9b0ee 100644 --- a/powershell/ql/lib/semmle/code/powershell/ScriptBlockExpr.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ScriptBlockExpr.qll @@ -1,9 +1,9 @@ -import powershell +private import Raw class ScriptBlockExpr extends @script_block_expression, Expr { override SourceLocation getLocation() { script_block_expression_location(this, result) } - override string toString() { result = "{...}" } - ScriptBlock getBody() { script_block_expression(this, result) } + + final override Ast getChild(ChildIndex i) { i = ScriptBlockExprBody() and result = this.getBody() } } diff --git a/powershell/ql/lib/semmle/code/powershell/SourceLocation.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/SourceLocation.qll similarity index 97% rename from powershell/ql/lib/semmle/code/powershell/SourceLocation.qll rename to powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/SourceLocation.qll index 8c70f06f7bc1..569de5e4229e 100644 --- a/powershell/ql/lib/semmle/code/powershell/SourceLocation.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/SourceLocation.qll @@ -1,4 +1,4 @@ -import powershell +private import Raw /** * A location in source code, comprising of a source file and a segment of text diff --git a/powershell/ql/lib/semmle/code/powershell/Statement.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Statement.qll similarity index 67% rename from powershell/ql/lib/semmle/code/powershell/Statement.qll rename to powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Statement.qll index 19bed527915a..881f86e94f26 100644 --- a/powershell/ql/lib/semmle/code/powershell/Statement.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Statement.qll @@ -1,3 +1,3 @@ -import powershell +private import Raw class Stmt extends @statement, Ast { } diff --git a/powershell/ql/lib/semmle/code/powershell/StatementBlock.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/StatementBlock.qll similarity index 53% rename from powershell/ql/lib/semmle/code/powershell/StatementBlock.qll rename to powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/StatementBlock.qll index c0dd9939079c..8fc5b4b238d6 100644 --- a/powershell/ql/lib/semmle/code/powershell/StatementBlock.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/StatementBlock.qll @@ -1,12 +1,4 @@ -import powershell -private import semmle.code.powershell.internal.AstEscape::Private - -private module ReturnContainerInterpreter implements InterpretAstInputSig { - class T = Ast; - - pragma[inline] - T interpret(Ast a) { result = a } -} +private import Raw class StmtBlock extends @statement_block, Ast { override SourceLocation getLocation() { statement_block_location(this, result) } @@ -23,10 +15,13 @@ class StmtBlock extends @statement_block, Ast { TrapStmt getATrapStmt() { result = this.getTrapStmt(_) } - override string toString() { result = "{...}" } - - /** Gets an element that may escape this `StmtBlock`. */ - Ast getAnElement() { - result = this.(AstEscape::Element).getAnEscapingElement() + final override Ast getChild(ChildIndex i) { + exists(int index | + i = StmtBlockStmt(index) and + result = this.getStmt(index) + or + i = StmtBlockTrapStmt(index) and + result = this.getTrapStmt(index) + ) } } diff --git a/powershell/ql/lib/semmle/code/powershell/StringConstantExpression.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/StringConstantExpression.qll similarity index 94% rename from powershell/ql/lib/semmle/code/powershell/StringConstantExpression.qll rename to powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/StringConstantExpression.qll index d640817f99b3..dabbc2e2e73f 100644 --- a/powershell/ql/lib/semmle/code/powershell/StringConstantExpression.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/StringConstantExpression.qll @@ -1,4 +1,4 @@ -import powershell +private import Raw /** A string constant. */ class StringConstExpr extends @string_constant_expression, BaseConstExpr { diff --git a/powershell/ql/lib/semmle/code/powershell/StringLiteral.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/StringLiteral.qll similarity index 96% rename from powershell/ql/lib/semmle/code/powershell/StringLiteral.qll rename to powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/StringLiteral.qll index a7f85ece8e42..e24ed143cdf1 100644 --- a/powershell/ql/lib/semmle/code/powershell/StringLiteral.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/StringLiteral.qll @@ -1,4 +1,4 @@ -import powershell +private import Raw class StringLiteral extends @string_literal { int getNumContinuations() { result = strictcount(int i | exists(this.getContinuation(i))) } diff --git a/powershell/ql/lib/semmle/code/powershell/SubExpression.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/SubExpression.qll similarity index 65% rename from powershell/ql/lib/semmle/code/powershell/SubExpression.qll rename to powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/SubExpression.qll index df39df46a48a..b2caafdc304d 100644 --- a/powershell/ql/lib/semmle/code/powershell/SubExpression.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/SubExpression.qll @@ -1,4 +1,4 @@ -import powershell +private import Raw // TODO: Should we remove this from the dbscheme? class ExpandableSubExpr extends @sub_expression, Expr { @@ -6,5 +6,7 @@ class ExpandableSubExpr extends @sub_expression, Expr { StmtBlock getExpr() { sub_expression(this, result) } - final override string toString() { result = "$(...)" } + final override Ast getChild(ChildIndex i) { + i = ExpandableSubExprExpr() and result = this.getExpr() + } } diff --git a/powershell/ql/lib/semmle/code/powershell/SwitchStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/SwitchStmt.qll similarity index 65% rename from powershell/ql/lib/semmle/code/powershell/SwitchStmt.qll rename to powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/SwitchStmt.qll index 8dca8f0b91c2..bb8a30b6bd34 100644 --- a/powershell/ql/lib/semmle/code/powershell/SwitchStmt.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/SwitchStmt.qll @@ -1,4 +1,4 @@ -import powershell +private import Raw class SwitchStmt extends LabeledStmt, @switch_statement { final override Location getLocation() { switch_statement_location(this, result) } @@ -21,5 +21,19 @@ class SwitchStmt extends LabeledStmt, @switch_statement { int getNumberOfCases() { result = count(this.getACase()) } - final override string toString() { result = "switch(...) {...}" } + final override Ast getChild(ChildIndex i) { + i = SwitchStmtCond() and + result = this.getCondition() + or + i = SwitchStmtDefault() and + result = this.getDefault() + or + exists(int index | + i = SwitchStmtCase(index) and + result = this.getCase(index) + or + i = SwitchStmtPat(index) and + result = this.getPattern(index) + ) + } } diff --git a/powershell/ql/lib/semmle/code/powershell/TernaryExpression.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/TernaryExpression.qll similarity index 67% rename from powershell/ql/lib/semmle/code/powershell/TernaryExpression.qll rename to powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/TernaryExpression.qll index 19af31478fcf..9b6e49e6ddb5 100644 --- a/powershell/ql/lib/semmle/code/powershell/TernaryExpression.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/TernaryExpression.qll @@ -1,7 +1,6 @@ -import powershell +private import Raw class ConditionalExpr extends @ternary_expression, Expr { - override string toString() { result = "...?...:..." } override SourceLocation getLocation() { ternary_expression_location(this, result) } @@ -20,4 +19,15 @@ class ConditionalExpr extends @ternary_expression, Expr { } Expr getABranch() { result = this.getBranch(_) } + + final override Ast getChild(ChildIndex i) { + i = CondExprCond() and + result = this.getCondition() + or + i = CondExprTrue() and + result = this.getIfTrue() + or + i = CondExprFalse() and + result = this.getIfFalse() + } } diff --git a/powershell/ql/lib/semmle/code/powershell/ThrowStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ThrowStmt.qll similarity index 67% rename from powershell/ql/lib/semmle/code/powershell/ThrowStmt.qll rename to powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ThrowStmt.qll index af8ccaab5f5b..58f357a8efeb 100644 --- a/powershell/ql/lib/semmle/code/powershell/ThrowStmt.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ThrowStmt.qll @@ -1,13 +1,11 @@ -import powershell +private import Raw class ThrowStmt extends @throw_statement, Stmt { override SourceLocation getLocation() { throw_statement_location(this, result) } - override string toString() { - if this.hasPipeline() then result = "throw ..." else result = "throw" - } - PipelineBase getPipeline() { throw_statement_pipeline(this, result) } predicate hasPipeline() { exists(this.getPipeline()) } + + final override Ast getChild(ChildIndex i) { i = ThrowStmtPipeline() and result = this.getPipeline() } } diff --git a/powershell/ql/lib/semmle/code/powershell/TokenKind.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/TokenKind.qll similarity index 100% rename from powershell/ql/lib/semmle/code/powershell/TokenKind.qll rename to powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/TokenKind.qll diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/TrapStatement.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/TrapStatement.qll new file mode 100644 index 000000000000..d03605161a08 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/TrapStatement.qll @@ -0,0 +1,17 @@ +private import Raw + +class TrapStmt extends @trap_statement, Stmt { + override SourceLocation getLocation() { trap_statement_location(this, result) } + + StmtBlock getBody() { trap_statement(this, result) } // TODO: Fix type in dbscheme + + TypeConstraint getTypeConstraint() { trap_statement_type(this, result) } + + override Ast getChild(ChildIndex i) { + i = TrapStmtBody() and + result = this.getBody() + or + i = TrapStmtTypeConstraint() and + result = this.getTypeConstraint() + } +} diff --git a/powershell/ql/lib/semmle/code/powershell/TryStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/TryStmt.qll similarity index 61% rename from powershell/ql/lib/semmle/code/powershell/TryStmt.qll rename to powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/TryStmt.qll index 300c59712e6b..149aacbf040b 100644 --- a/powershell/ql/lib/semmle/code/powershell/TryStmt.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/TryStmt.qll @@ -1,10 +1,8 @@ -import powershell +private import Raw class TryStmt extends @try_statement, Stmt { override SourceLocation getLocation() { try_statement_location(this, result) } - override string toString() { result = "try {...}" } - CatchClause getCatchClause(int i) { try_statement_catch_clause(this, i, result) } CatchClause getACatchClause() { result = this.getCatchClause(_) } @@ -15,4 +13,17 @@ class TryStmt extends @try_statement, Stmt { StmtBlock getBody() { try_statement(this, result) } predicate hasFinally() { exists(this.getFinally()) } + + final override Ast getChild(ChildIndex i) { + i = TryStmtBody() and + result = this.getBody() + or + exists(int index | + i = TryStmtCatchClause(index) and + result = this.getCatchClause(index) + ) + or + i = TryStmtFinally() and + result = this.getFinally() + } } diff --git a/powershell/ql/lib/semmle/code/powershell/Type.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Type.qll similarity index 51% rename from powershell/ql/lib/semmle/code/powershell/Type.qll rename to powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Type.qll index d67aea74ad15..bd386eb461ff 100644 --- a/powershell/ql/lib/semmle/code/powershell/Type.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Type.qll @@ -1,10 +1,8 @@ -import powershell +private import Raw -class Type extends @type_definition, Stmt { +class TypeStmt extends @type_definition, Stmt { override SourceLocation getLocation() { type_definition_location(this, result) } - override string toString() { result = this.getName() } - string getName() { type_definition(this, result, _, _, _, _) } Member getMember(int i) { type_definition_members(this, i, result) } @@ -12,20 +10,23 @@ class Type extends @type_definition, Stmt { Member getAMember() { result = this.getMember(_) } Method getMethod(string name) { - result.getMember() = this.getAMember() and - result.hasName(name) - } - - Constructor getAConstructor() { - result = this.getAMethod() and - result.getName() = this.getName() + result = this.getAMember() and + result.getName() = name } - Method getAMethod() { result = this.getMethod(_) } - TypeConstraint getBaseType(int i) { type_definition_base_type(this, i, result) } TypeConstraint getABaseType() { result = this.getBaseType(_) } - Type getASubtype() { result.getABaseType().getName() = this.getName() } + TypeStmt getASubtype() { result.getABaseType().getName() = this.getName() } + + final override Ast getChild(ChildIndex i) { + exists(int index | + i = TypeStmtMember(index) and + result = this.getMember(index) + or + i = TypeStmtBaseType(index) and + result = this.getBaseType(index) + ) + } } diff --git a/powershell/ql/lib/semmle/code/powershell/TypeConstraint.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/TypeConstraint.qll similarity index 83% rename from powershell/ql/lib/semmle/code/powershell/TypeConstraint.qll rename to powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/TypeConstraint.qll index 970afcb5b70c..c5552aaf1731 100644 --- a/powershell/ql/lib/semmle/code/powershell/TypeConstraint.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/TypeConstraint.qll @@ -1,4 +1,4 @@ -import powershell +private import Raw class TypeConstraint extends @type_constraint, AttributeBase { override SourceLocation getLocation() { type_constraint_location(this, result) } @@ -8,6 +8,4 @@ class TypeConstraint extends @type_constraint, AttributeBase { /** Gets the full name of this type constraint including namespaces. */ string getFullName() { type_constraint(this, _, result) } - - override string toString() { result = this.getName() } } diff --git a/powershell/ql/lib/semmle/code/powershell/TypeExpression.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/TypeExpression.qll similarity index 55% rename from powershell/ql/lib/semmle/code/powershell/TypeExpression.qll rename to powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/TypeExpression.qll index 9817a5ca07a7..50fbc41bbac3 100644 --- a/powershell/ql/lib/semmle/code/powershell/TypeExpression.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/TypeExpression.qll @@ -1,14 +1,10 @@ -import powershell +private import Raw class TypeNameExpr extends @type_expression, Expr { string getName() { type_expression(this, result, _) } - string getFullyQualifiedName() { type_expression(this, _, result) } - - override string toString() { result = this.getName() } - override SourceLocation getLocation() { type_expression_location(this, result) } /** Gets the type referred to by this `TypeNameExpr`. */ - Type getType() { result.getName() = this.getName() } + TypeStmt getType() { result.getName() = this.getName() } } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/UnaryExpression.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/UnaryExpression.qll new file mode 100644 index 000000000000..74370a61b19e --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/UnaryExpression.qll @@ -0,0 +1,11 @@ +private import Raw + +class UnaryExpr extends @unary_expression, Expr { + override SourceLocation getLocation() { unary_expression_location(this, result) } + + int getKind() { unary_expression(this, _, result, _) } + + Expr getOperand() { unary_expression(this, result, _, _) } + + final override Ast getChild(ChildIndex i) { i = UnaryExprOp() and result = this.getOperand() } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/UsingExpression.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/UsingExpression.qll new file mode 100644 index 000000000000..527b17c0668a --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/UsingExpression.qll @@ -0,0 +1,12 @@ +private import Raw + +class UsingExpr extends @using_expression, Expr { + override SourceLocation getLocation() { using_expression_location(this, result) } + + Expr getExpr() { using_expression(this, result) } + + override Ast getChild(ChildIndex i) { + i = UsingExprExpr() and + result = this.getExpr() + } +} diff --git a/powershell/ql/lib/semmle/code/powershell/UsingStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/UsingStmt.qll similarity index 87% rename from powershell/ql/lib/semmle/code/powershell/UsingStmt.qll rename to powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/UsingStmt.qll index 2278409c0a55..46614401daa9 100644 --- a/powershell/ql/lib/semmle/code/powershell/UsingStmt.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/UsingStmt.qll @@ -1,10 +1,8 @@ -import powershell +private import Raw class UsingStmt extends @using_statement, Stmt { override SourceLocation getLocation() { using_statement_location(this, result) } - override string toString() { result = "using ..." } - string getName() { exists(StringConstExpr const | using_statement_name(this, const) and // TODO: Change dbscheme diff --git a/powershell/ql/lib/semmle/code/powershell/VariableExpression.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/VariableExpression.qll similarity index 51% rename from powershell/ql/lib/semmle/code/powershell/VariableExpression.qll rename to powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/VariableExpression.qll index b07774a29246..00bc726699c5 100644 --- a/powershell/ql/lib/semmle/code/powershell/VariableExpression.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/VariableExpression.qll @@ -1,13 +1,6 @@ -import powershell -private import internal.ExplicitWrite::Private - -private predicate isParameterName(@variable_expression ve) { parameter(_, ve, _, _) } +private import Raw class VarAccess extends @variable_expression, Expr { - VarAccess() { not isParameterName(this) } - - override string toString() { result = this.getUserPath() } - override SourceLocation getLocation() { variable_expression_location(this, result) } string getUserPath() { variable_expression(this, result, _, _, _, _, _, _, _, _, _, _) } @@ -31,29 +24,25 @@ class VarAccess extends @variable_expression, Expr { boolean isVariable() { variable_expression(this, _, _, _, _, _, _, _, _, _, result, _) } boolean isDriveQualified() { variable_expression(this, _, _, _, _, _, _, _, _, _, _, result) } - - Variable getVariable() { result.getAnAccess() = this } } -private predicate isImplicitVariableWriteAccess(Expr e) { none() } - -class VarReadAccess extends VarAccess { - VarReadAccess() { not this instanceof VarWriteAccess } +class ThisAccess extends VarAccess { + ThisAccess() { this.getUserPath() = "this" } } -class VarWriteAccess extends VarAccess { - VarWriteAccess() { isExplicitWrite(this, _) or isImplicitVariableWriteAccess(this) } - - predicate isExplicit(AssignStmt assign) { isExplicitWrite(this, assign) } - - predicate isImplicit() { isImplicitVariableWriteAccess(this) } +predicate isEnvVariableAccess(VarAccess va, string env) { + va.getUserPath().toLowerCase() = "env:" + env } -/** An access to an environment variable such as `$Env:PATH` */ -class EnvVarAccess extends VarAccess { - EnvVarAccess() { super.getVariable() instanceof EnvVariable } - - override EnvVariable getVariable() { result = super.getVariable() } - - string getEnvironmentVariable() { result = this.getVariable().getEnvironmentVariable() } +predicate isAutomaticVariableAccess(VarAccess va, string var) { + va.getUserPath().toLowerCase() = + [ + "args", "consolefilename", "enabledexperimentalfeatures", "error", "event", "eventargs", + "eventsubscriber", "executioncontext", "home", "host", "input", "iscoreclr", "islinux", + "ismacos", "iswindows", "lastexitcode", "myinvocation", "nestedpromptlevel", "pid", "profile", + "psboundparameters", "pscmdlet", "pscommandpath", "psculture", "psdebugcontext", "psedition", + "pshome", "psitem", "psscriptroot", "pssenderinfo", "psuiculture", "psversiontable", "pwd", + "sender", "shellid", "stacktrace" + ] and + var = va.getUserPath().toLowerCase() } diff --git a/powershell/ql/lib/semmle/code/powershell/WhileStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/WhileStmt.qll similarity index 60% rename from powershell/ql/lib/semmle/code/powershell/WhileStmt.qll rename to powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/WhileStmt.qll index 9f244d3ed78a..92ced49b4230 100644 --- a/powershell/ql/lib/semmle/code/powershell/WhileStmt.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/WhileStmt.qll @@ -1,11 +1,15 @@ -import powershell +private import Raw class WhileStmt extends @while_statement, LoopStmt { override SourceLocation getLocation() { while_statement_location(this, result) } - override string toString() { result = "while(...) {...}" } - PipelineBase getCondition() { while_statement_condition(this, result) } final override StmtBlock getBody() { while_statement(this, result) } + + final override Ast getChild(ChildIndex i) { + i = WhileStmtCond() and result = this.getCondition() + or + i = WhileStmtBody() and result = this.getBody() + } } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Redirection.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Redirection.qll new file mode 100644 index 000000000000..050c59286e13 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Redirection.qll @@ -0,0 +1,18 @@ +private import AstImport + +class Redirection extends Ast, TRedirection { + Expr getExpr() { + exists(Raw::Ast r | r = getRawAst(this) | + synthChild(r, redirectionExpr(), result) + or + not synthChild(r, redirectionExpr(), _) and + result = getResultAst(r.(Raw::Redirection).getExpr()) + ) + } + + override Ast getChild(ChildIndex i) { + result = super.getChild(i) + or + i = redirectionExpr() and result = this.getExpr() + } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/ReturnStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/ReturnStmt.qll new file mode 100644 index 000000000000..d54937316547 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/ReturnStmt.qll @@ -0,0 +1,25 @@ +private import AstImport + +class ReturnStmt extends Stmt, TReturnStmt { + override string toString() { + if this.hasPipeline() then result = "return ..." else result = "return" + } + + override Ast getChild(ChildIndex i) { + result = super.getChild(i) + or + i = returnStmtPipeline() and + result = this.getPipeline() + } + + predicate hasPipeline() { exists(this.getPipeline()) } + + Expr getPipeline() { + exists(Raw::Ast r | r = getRawAst(this) | + synthChild(r, returnStmtPipeline(), result) + or + not synthChild(r, returnStmtPipeline(), _) and + result = getResultAst(r.(Raw::ReturnStmt).getPipeline()) + ) + } +} diff --git a/powershell/ql/lib/semmle/code/powershell/controlflow/internal/Scope.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Scopes.qll similarity index 53% rename from powershell/ql/lib/semmle/code/powershell/controlflow/internal/Scope.qll rename to powershell/ql/lib/semmle/code/powershell/ast/internal/Scopes.qll index 49d182548fdd..52212cf5ea22 100644 --- a/powershell/ql/lib/semmle/code/powershell/controlflow/internal/Scope.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Scopes.qll @@ -1,5 +1,4 @@ -private import powershell -private import ControlFlowGraphImpl +private import AstImport /** Gets the enclosing scope of `n`. */ Scope scopeOf(Ast n) { @@ -10,11 +9,15 @@ Scope scopeOf(Ast n) { ) } -/** - * A variable scope. This is either a top-level (file), a module, a class, - * or a callable. - */ -class Scope extends Ast, ScriptBlock { +class Scope extends Ast { + Scope() { getRawAst(this) instanceof Raw::Scope } + /** Gets the outer scope, if any. */ Scope getOuterScope() { result = scopeOf(this) } + + UsingStmt getAnActiveUsingStmt() { result.getAnAffectedScope() = this } +} + +module Scope { + class Range extends Raw::Scope { } } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/ScriptBlock.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/ScriptBlock.qll new file mode 100644 index 000000000000..ad71dd424263 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/ScriptBlock.qll @@ -0,0 +1,122 @@ +private import AstImport + +class ScriptBlock extends Ast, TScriptBlock { + override string toString() { + if this.isTopLevel() + then result = this.getLocation().getFile().getBaseName() + else result = "{...}" + } + + NamedBlock getProcessBlock() { + exists(Raw::Ast r | r = getRawAst(this) | + synthChild(r, scriptBlockProcessBlock(), result) + or + not synthChild(r, scriptBlockProcessBlock(), _) and + result = getResultAst(r.(Raw::ScriptBlock).getProcessBlock()) + ) + } + + NamedBlock getBeginBlock() { + exists(Raw::Ast r | r = getRawAst(this) | + synthChild(r, scriptBlockBeginBlock(), result) + or + not synthChild(r, scriptBlockBeginBlock(), _) and + result = getResultAst(r.(Raw::ScriptBlock).getBeginBlock()) + ) + } + + UsingStmt getUsingStmt(int i) { + exists(ChildIndex index, Raw::Ast r | index = scriptBlockUsing(i) and r = getRawAst(this) | + synthChild(r, index, result) + or + not synthChild(r, index, _) and + result = getResultAst(r.(Raw::ScriptBlock).getUsing(i)) + ) + } + + UsingStmt getAUsingStmt() { result = this.getUsingStmt(_) } + + NamedBlock getEndBlock() { + exists(Raw::Ast r | r = getRawAst(this) | + synthChild(r, scriptBlockEndBlock(), result) + or + not synthChild(r, scriptBlockEndBlock(), _) and + result = getResultAst(r.(Raw::ScriptBlock).getEndBlock()) + ) + } + + NamedBlock getDynamicBlock() { + exists(Raw::Ast r | r = getRawAst(this) | + synthChild(r, scriptBlockDynParamBlock(), result) + or + not synthChild(r, scriptBlockDynParamBlock(), _) and + result = getResultAst(r.(Raw::ScriptBlock).getDynamicParamBlock()) + ) + } + + final override Ast getChild(ChildIndex i) { + result = super.getChild(i) + or + i = scriptBlockBeginBlock() and + result = this.getBeginBlock() + or + i = scriptBlockProcessBlock() and + result = this.getProcessBlock() + or + i = scriptBlockEndBlock() and + result = this.getEndBlock() + or + i = scriptBlockDynParamBlock() and + result = this.getDynamicBlock() + or + exists(int index | + i = scriptBlockAttr(index) and + result = this.getAttribute(index) + ) + or + exists(int index | + i = funParam(index) and + result = this.getParameter(index) + ) + or + exists(int index | + i = scriptBlockUsing(index) and + result = this.getUsingStmt(index) + ) + } + + Parameter getParameter(int i) { + synthChild(getRawAst(this), funParam(i), result) + or + any(Synthesis s).pipelineParameterHasIndex(this, i) and + synthChild(getRawAst(this), PipelineParamVar(), result) + or + i = -1 and + synthChild(getRawAst(this), ThisVar(), result) + } + + /** + * Gets a parameter of this block. + */ + Parameter getAParameter() { result = this.getParameter(_) } + + int getNumberOfParameters() { result = count(this.getAParameter()) } + + predicate isTopLevel() { not exists(this.getParent()) } + + Attribute getAttribute(int i) { + // We attach the attributes to the function since we got rid of parameter blocks + exists(ChildIndex index, Raw::Ast r | index = scriptBlockAttr(i) and r = getRawAst(this) | + synthChild(r, index, result) + or + not synthChild(r, index, _) and + result = getResultAst(r.(Raw::ScriptBlock).getParamBlock().getAttribute(i)) + ) + } + + Attribute getAnAttribute() { result = this.getAttribute(_) } +} + +class TopLevelScriptBlock extends ScriptBlock { + TopLevelScriptBlock() { this.isTopLevel() } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/ScriptBlockExpr.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/ScriptBlockExpr.qll new file mode 100644 index 000000000000..1bfc559e66a7 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/ScriptBlockExpr.qll @@ -0,0 +1,20 @@ +private import AstImport + +class ScriptBlockExpr extends Expr, TScriptBlockExpr { + override string toString() { result = "{...}" } + + ScriptBlock getBody() { + exists(Raw::Ast r | r = getRawAst(this) | + synthChild(r, scriptBlockExprBody(), result) + or + not synthChild(r, scriptBlockExprBody(), _) and + result = getResultAst(r.(Raw::ScriptBlockExpr).getBody()) + ) + } + + final override Ast getChild(ChildIndex i) { + result = super.getChild(i) + or + i = scriptBlockExprBody() and result = this.getBody() + } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/SourceLocation.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/SourceLocation.qll new file mode 100644 index 000000000000..270befbece57 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/SourceLocation.qll @@ -0,0 +1 @@ +import Raw.SourceLocation diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Statement.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Statement.qll new file mode 100644 index 000000000000..802413b3865e --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Statement.qll @@ -0,0 +1,3 @@ +private import AstImport + +class Stmt extends Ast, TStmt { } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/StatementBlock.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/StatementBlock.qll new file mode 100644 index 000000000000..58a0fb1a19aa --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/StatementBlock.qll @@ -0,0 +1,42 @@ +private import AstImport + +class StmtBlock extends Stmt, TStmtBlock { + pragma[nomagic] + Stmt getStmt(int i) { + exists(ChildIndex index, Raw::Ast r | index = stmtBlockStmt(i) and r = getRawAst(this) | + synthChild(r, index, result) + or + not synthChild(r, index, _) and + result = getResultAst(r.(Raw::StmtBlock).getStmt(i)) + ) + } + + Stmt getAStmt() { result = this.getStmt(_) } + + TrapStmt getTrapStmt(int i) { + exists(ChildIndex index, Raw::Ast r | index = stmtBlockTrapStmt(i) and r = getRawAst(this) | + synthChild(r, index, result) + or + not synthChild(r, index, _) and + result = getResultAst(r.(Raw::StmtBlock).getTrapStmt(i)) + ) + } + + TrapStmt getATrapStmt() { result = this.getTrapStmt(_) } + + int getNumberOfStmts() { result = count(this.getAStmt()) } + + final override Ast getChild(ChildIndex i) { + result = super.getChild(i) + or + exists(int index | + i = stmtBlockStmt(index) and + result = this.getStmt(index) + or + i = stmtBlockTrapStmt(index) and + result = this.getTrapStmt(index) + ) + } + + override string toString() { result = "{...}" } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Stmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Stmt.qll new file mode 100644 index 000000000000..802413b3865e --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Stmt.qll @@ -0,0 +1,3 @@ +private import AstImport + +class Stmt extends Ast, TStmt { } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/StringConstantExpression.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/StringConstantExpression.qll new file mode 100644 index 000000000000..95261d31052f --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/StringConstantExpression.qll @@ -0,0 +1,7 @@ +private import AstImport + +class StringConstExpr extends Expr, TStringConstExpr { + string getValueString() { result = getRawAst(this).(Raw::StringConstExpr).getValue().getValue() } + + override string toString() { result = this.getValueString() } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/SubExpression.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/SubExpression.qll new file mode 100644 index 000000000000..2208828595a8 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/SubExpression.qll @@ -0,0 +1,20 @@ +private import AstImport + +class ExpandableSubExpr extends Expr, TExpandableSubExpr { + StmtBlock getExpr() { + exists(Raw::Ast r | r = getRawAst(this) | + synthChild(r, expandableSubExprExpr(), result) + or + not synthChild(r, expandableSubExprExpr(), _) and + result = getResultAst(r.(Raw::ExpandableSubExpr).getExpr()) + ) + } + + final override string toString() { result = "$(...)" } + + final override Ast getChild(ChildIndex i) { + result = super.getChild(i) + or + i = expandableSubExprExpr() and result = this.getExpr() + } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/SwitchStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/SwitchStmt.qll new file mode 100644 index 000000000000..ed3ec27ef2fe --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/SwitchStmt.qll @@ -0,0 +1,65 @@ +private import AstImport + +class SwitchStmt extends Stmt, TSwitchStmt { + final override string toString() { result = "switch(...) {...}" } + + Expr getCondition() { + exists(Raw::Ast r | r = getRawAst(this) | + synthChild(r, switchStmtCond(), result) + or + not synthChild(r, switchStmtCond(), _) and + result = getResultAst(r.(Raw::SwitchStmt).getCondition()) + ) + } + + StmtBlock getDefault() { + exists(Raw::Ast r | r = getRawAst(this) | + synthChild(r, switchStmtDefault(), result) + or + not synthChild(r, switchStmtDefault(), _) and + result = getResultAst(r.(Raw::SwitchStmt).getDefault()) + ) + } + + StmtBlock getCase(int i) { + exists(ChildIndex index, Raw::Ast r | index = switchStmtCase(i) and r = getRawAst(this) | + synthChild(r, index, result) + or + not synthChild(r, index, _) and + result = getResultAst(r.(Raw::SwitchStmt).getCase(i)) + ) + } + + StmtBlock getACase() { result = this.getCase(_) } + + int getNumberOfCases() { result = getRawAst(this).(Raw::SwitchStmt).getNumberOfCases() } + + Expr getPattern(int i) { + exists(ChildIndex index, Raw::Ast r | index = switchStmtPat(i) and r = getRawAst(this) | + synthChild(r, index, result) + or + not synthChild(r, index, _) and + result = getResultAst(r.(Raw::SwitchStmt).getPattern(i)) + ) + } + + final override Ast getChild(ChildIndex i) { + result = super.getChild(i) + or + i = switchStmtCond() and + result = this.getCondition() + or + i = switchStmtDefault() and + result = this.getDefault() + or + exists(int index | + i = switchStmtCase(index) and + result = this.getCase(index) + or + i = switchStmtPat(index) and + result = this.getPattern(index) + ) + } + + Expr getAPattern() { result = this.getPattern(_) } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Synthesis.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Synthesis.qll new file mode 100644 index 000000000000..8aa76fd11a49 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Synthesis.qll @@ -0,0 +1,772 @@ +private import TAst +private import Ast +private import Location +private import Variable +private import TypeConstraint +private import Expr +private import Parameter +private import ExprStmt +private import NamedBlock +private import FunctionBase +private import ScriptBlock +private import Command +private import Internal::Private +private import Type +private import Scopes +private import BoolLiteral +private import Member +private import EnvVariable +private import Raw.Raw as Raw +private import codeql.util.Boolean +private import AutomaticVariable + +newtype VarKind = + ThisVarKind() or + ParamVarRealKind() or + ParamVarPipelineKind() or + PipelineIteratorKind() or + PipelineByPropertyNameIteratorKind(string name) { + exists(Raw::ProcessBlock pb | + name = pb.getScriptBlock().getParamBlock().getAPipelineByPropertyNameParameter().getName() + ) + } + +newtype SynthKind = + ExprStmtKind() or + VarAccessRealKind(VariableReal v) or + VarAccessSynthKind(VariableSynth v) or + FunctionSynthKind() or + TypeSynthKind() or + BoolLiteralKind(Boolean b) or + NullLiteralKind() or + EnvVariableKind(string var) { Raw::isEnvVariableAccess(_, var) } or + AutomaticVariableKind(string var) { Raw::isAutomaticVariableAccess(_, var) } or + VarSynthKind(VarKind k) + +newtype Child = + SynthChild(SynthKind kind) or + RealChildRef(TAstReal n) or + SynthChildRef(TAstSynth n) + +pragma[inline] +private Child childRef(TAst n) { + result = RealChildRef(n) + or + result = SynthChildRef(n) +} + +private newtype TSynthesis = MkSynthesis() + +class Synthesis extends TSynthesis { + predicate child(Raw::Ast parent, ChildIndex i, Child child) { none() } + + Location getLocation(Ast n) { none() } + + predicate isRelevant(Raw::Ast a) { none() } + + string toString(Ast n) { none() } + + Ast getResultAstImpl(Raw::Ast r) { none() } + + predicate explicitAssignment(Raw::Ast dest, string name, Raw::Ast assignment) { none() } + + predicate implicitAssignment(Raw::Ast dest, string name) { none() } + + predicate variableSynthName(VariableSynth v, string name) { none() } + + predicate exprStmtExpr(ExprStmt e, Expr expr) { none() } + + predicate parameterStaticType(Parameter p, string type) { none() } + + predicate isPipelineParameter(Parameter p) { none() } + + predicate pipelineParameterHasIndex(ScriptBlock s, int i) { none() } + + predicate functionName(FunctionBase f, string name) { none() } + + predicate memberName(Member m, string name) { none() } + + predicate typeName(Type t, string name) { none() } + + predicate typeMember(Type t, int i, Member m) { none() } + + predicate functionScriptBlock(FunctionBase f, ScriptBlock block) { none() } + + predicate isNamedArgument(CmdCall call, int i, string name) { none() } + + predicate booleanValue(BoolLiteral b, boolean value) { none() } + + predicate envVariableName(EnvVariable var, string name) { none() } + + predicate automaticVariableName(AutomaticVariable var, string name) { none() } + + final string toString() { none() } +} + +/** Gets the user-facing AST element that is generated from `r`. */ +Ast getResultAst(Raw::Ast r) { + not any(Synthesis s).isRelevant(r) and + toRaw(result) = r + or + any(Synthesis s).isRelevant(r) and + result = any(Synthesis s).getResultAstImpl(r) +} + +Raw::Ast getRawAst(Ast r) { r = getResultAst(result) } + +private module ThisSynthesis { + private class ThisSynthesis extends Synthesis { + override predicate child(Raw::Ast parent, ChildIndex i, Child child) { + parent instanceof Raw::MethodScriptBlock and + i = ThisVar() and + child = SynthChild(VarSynthKind(ThisVarKind())) + or + parent.getChild(toRawChildIndex(i)).(Raw::VarAccess).getUserPath().toLowerCase() = "this" and + child = SynthChild(VarAccessSynthKind(TVariableSynth(parent.getScope(), ThisVar()))) + } + + override predicate variableSynthName(VariableSynth v, string name) { + v = TVariableSynth(_, ThisVar()) and + name = "this" + } + + override Location getLocation(Ast n) { + exists(Raw::Ast scope | + n = TVariableSynth(scope, ThisVar()) and + result = scope.getLocation() + ) + } + } +} + +private module SetVariableAssignment { + private class SetVariableAssignment extends Synthesis { + override predicate explicitAssignment(Raw::Ast dest, string name, Raw::Ast assignment) { + exists(Raw::Cmd cmd | + assignment = cmd and + cmd.getCommandName().toLowerCase() = "set-variable" and + cmd.getNamedArgument("name") = dest and + name = dest.(Raw::StringConstExpr).getValue().getValue() + ) + } + } +} + +/** + * Syntesize parameters from parameter blocks and function definitions + * so that they have a uniform API. + */ +private module ParameterSynth { + private class ParameterSynth extends Synthesis { + final override predicate isRelevant(Raw::Ast a) { a = any(Scope::Range r).getAParameter() } + + private predicate parameter( + Raw::Ast parent, ChildIndex i, Raw::Parameter p, Child child, boolean isPipelineParameter + ) { + exists(Scope::Range r, int index | + p = r.getParameter(index) and + parent = r and + i = funParam(index) and + child = SynthChild(VarSynthKind(ParamVarRealKind())) and + if p instanceof Raw::PipelineParameter + then isPipelineParameter = true + else isPipelineParameter = false + ) + } + + final override predicate isPipelineParameter(Parameter p) { + exists(Raw::Ast parent, ChildIndex i | + parent = getRawAst(p.getFunction().getBody()) and + this.isPipelineParameterChild(parent, _, i) and + p = TVariableSynth(parent, i) + ) + } + + override predicate implicitAssignment(Raw::Ast dest, string name) { + exists(Raw::Parameter p | + dest = p and + name = p.getName() + ) + } + + final override predicate variableSynthName(VariableSynth v, string name) { + exists(Raw::Ast parent, int i, Raw::Parameter p | + this.parameter(parent, FunParam(i), p, _, false) and + v = TVariableSynth(parent, FunParam(i)) and + name = p.getName() + ) + or + exists(Raw::Ast parent | + this.child(parent, PipelineParamVar(), _) and + v = TVariableSynth(parent, PipelineParamVar()) and + name = "[synth] pipeline" + ) + } + + private predicate isPipelineParameterChild(Raw::Ast parent, int index, ChildIndex i) { + exists(Scope::Range r | parent = r and i = PipelineParamVar() | + r.getParameter(index) instanceof Raw::PipelineParameter + or + not r.getAParameter() instanceof Raw::PipelineParameter and + index = synthPipelineParameterChildIndex(r) + ) + } + + final override predicate pipelineParameterHasIndex(ScriptBlock s, int i) { + exists(Raw::ScriptBlock scriptBlock | + s = TScriptBlock(scriptBlock) and + this.isPipelineParameterChild(scriptBlock, i, _) + ) + } + + final override predicate child(Raw::Ast parent, ChildIndex i, Child child) { + // Synthesize parameters + this.parameter(parent, i, _, child, false) + or + // Synthesize pipeline parameter + child = SynthChild(VarSynthKind(ParamVarPipelineKind())) and + this.isPipelineParameterChild(parent, _, i) + or + // Synthesize default values + exists(Raw::Parameter q | + parent = q and + this.parameter(_, _, q, _, _) + | + i = paramDefaultVal() and + child = childRef(getResultAst(q.getDefaultValue())) + or + exists(int index | + i = paramAttr(index) and + child = childRef(getResultAst(q.getAttribute(index))) + ) + ) + } + + final override Parameter getResultAstImpl(Raw::Ast r) { + exists(Raw::Ast parent, int i | + this.parameter(parent, FunParam(i), r, _, false) and + result = TVariableSynth(parent, FunParam(i)) + ) + or + exists(Scope::Range scope, int i, ChildIndex index | + scope.getParameter(i) = r and + this.isPipelineParameterChild(scope, i, index) and + result = TVariableSynth(scope, index) + ) + } + + final override Location getLocation(Ast n) { + exists(Raw::Ast parent, Raw::Parameter p, int i | + this.parameter(parent, _, p, _, _) and + n = TVariableSynth(parent, FunParam(i)) and + result = p.getLocation() + ) + } + + final override predicate parameterStaticType(Parameter n, string type) { + exists(Raw::Ast parent, int i, Raw::Parameter p | + this.parameter(parent, FunParam(i), p, _, false) and + n = TVariableSynth(parent, FunParam(i)) and + type = p.getStaticType() + ) + } + } +} + +/** + * Holds if `child` is a child of `n` that is a `Stmt` in the raw AST, but should + * be mapped to an `Expr` in the synthesized AST. + */ +private predicate mustHaveExprChild(Raw::Ast n, Raw::Stmt child) { + n.(Raw::AssignStmt).getRightHandSide() = child + or + n.(Raw::Pipeline).getAComponent() = child + or + n.(Raw::ReturnStmt).getPipeline() = child + or + n.(Raw::HashTableExpr).getAStmt() = child + or + n.(Raw::ParenExpr).getBase() = child + or + n.(Raw::DoUntilStmt).getCondition() = child + or + n.(Raw::DoWhileStmt).getCondition() = child + or + n.(Raw::ExitStmt).getPipeline() = child + or + n.(Raw::ForEachStmt).getIterableExpr() = child + or + // TODO: What to do about initializer and iterator? + exists(Raw::ForStmt for | n = for | for.getCondition() = child) + or + n.(Raw::IfStmt).getACondition() = child + or + n.(Raw::SwitchStmt).getCondition() = child + or + n.(Raw::ThrowStmt).getPipeline() = child + or + n.(Raw::WhileStmt).getCondition() = child +} + +private class RawStmtThatShouldBeExpr extends Raw::Stmt { + RawStmtThatShouldBeExpr() { + this instanceof Raw::Cmd or + this instanceof Raw::Pipeline or + this instanceof Raw::PipelineChain or + this instanceof Raw::IfStmt + } + + Expr getExpr() { + result = TCmd(this) + or + result = TPipeline(this) + or + result = TPipelineChain(this) + or + result = TIf(this) + } +} + +/** + * Insert expr-to-stmt conversions where needed. + */ +private module ExprToStmtSynth { + private class ExprToStmtSynth extends Synthesis { + private predicate exprToSynthStmtChild(Raw::Ast parent, ChildIndex i, Raw::Stmt stmt, Expr e) { + this.child(parent, i, SynthChild(ExprStmtKind()), stmt) and + e = stmt.(RawStmtThatShouldBeExpr).getExpr() + } + + private predicate child(Raw::Ast parent, ChildIndex i, Child child, Raw::Stmt stmt) { + // Synthesize the expr-to-stmt conversion + child = SynthChild(ExprStmtKind()) and + stmt instanceof RawStmtThatShouldBeExpr and + parent.getChild(toRawChildIndex(i)) = stmt and + not mustHaveExprChild(parent, stmt) + } + + final override predicate child(Raw::Ast parent, ChildIndex i, Child child) { + this.child(parent, i, child, _) + } + + final override predicate exprStmtExpr(ExprStmt e, Expr expr) { + exists(Raw::Ast parent, ChildIndex i, Raw::Stmt stmt | + e = TExprStmtSynth(parent, i) and + this.exprToSynthStmtChild(parent, i, stmt, expr) + ) + } + + final override Location getLocation(Ast n) { + exists(Raw::Ast parent, ChildIndex i, Raw::Stmt stmt | + n = TExprStmtSynth(parent, i) and + this.exprToSynthStmtChild(parent, i, stmt, _) and + result = stmt.getLocation() + ) + } + + final override string toString(Ast n) { + exists(Raw::Ast parent, ChildIndex i, Raw::Stmt stmt | + n = TExprStmtSynth(parent, i) and + this.exprToSynthStmtChild(parent, i, stmt, _) and + result = stmt.toString() + ) + } + } +} + +predicate excludeFunctionDefinitionStmt(Raw::FunctionDefinitionStmt f) { + // We don't care about function definition statements which define methods + // because they live inside a type anyway (and we don't have control-flow + // inside a type). + parent(f, any(Raw::Method m)) +} + +/** + * Synthesize function "declarations" from function definitions statements. + */ +private module FunctionSynth { + private class FunctionSynth extends Synthesis { + override predicate child(Raw::Ast parent, ChildIndex i, Child child) { + i = funDefFun() and + child = SynthChild(FunctionSynthKind()) and + exists(Raw::FunctionDefinitionStmt fundefStmt | + if excludeFunctionDefinitionStmt(fundefStmt) + then parent(fundefStmt, parent) + else parent = fundefStmt + ) + } + + override predicate functionName(FunctionBase f, string name) { + exists(Raw::FunctionDefinitionStmt fundefStmt | + f = TFunctionSynth(fundefStmt, _) and + fundefStmt.getName() = name + ) + or + exists(Raw::TopLevelScriptBlock topLevelScriptBlock | + f = TTopLevelFunction(topLevelScriptBlock) and + name = "toplevel function for " + topLevelScriptBlock.getLocation().getFile().getBaseName() + ) + } + + override predicate functionScriptBlock(FunctionBase f, ScriptBlock block) { + exists(Raw::FunctionDefinitionStmt fundefStmt | + f = TFunctionSynth(fundefStmt, _) and + getResultAst(fundefStmt.getBody()) = block + ) + or + exists(Raw::TopLevelScriptBlock topLevelScriptBlock | + block = getResultAst(topLevelScriptBlock) and + f = TTopLevelFunction(topLevelScriptBlock) + ) + } + + override Location getLocation(Ast n) { + exists(Raw::FunctionDefinitionStmt fundefStmt | + n = TFunctionSynth(fundefStmt, _) and + result = fundefStmt.getLocation() + ) + } + } +} + +private module TypeSynth { + private class TypeSynth extends Synthesis { + override predicate child(Raw::Ast parent, ChildIndex i, Child child) { + parent instanceof Raw::TypeStmt and + i = typeDefType() and + child = SynthChild(TypeSynthKind()) + } + + final override predicate typeMember(Type t, int i, Member m) { + exists(Raw::TypeStmt typeStmt | + t = TTypeSynth(typeStmt, _) and + m = getResultAst(typeStmt.getMember(i)) + ) + } + + override predicate typeName(Type t, string name) { + exists(Raw::TypeStmt typeStmt | + t = TTypeSynth(typeStmt, _) and + typeStmt.getName() = name + ) + } + + override Location getLocation(Ast n) { + exists(Raw::TypeStmt typeStmt | + n = TTypeSynth(typeStmt, _) and + result = typeStmt.getLocation() + ) + } + } +} + +/** + * Remove the implicit expr-to-pipeline conversion. + */ +private module CmdExprRemoval { + private class CmdExprRemoval extends Synthesis { + final override predicate isRelevant(Raw::Ast a) { a instanceof Raw::CmdExpr } + + override predicate child(Raw::Ast parent, ChildIndex i, Child child) { + // Remove the CmdExpr. There are two cases: + // - If the expression under the cmd expr exists in a place an expr is expected, then we're done + // - Otherwise, we need to synthesize an expr-to-stmt conversion with the expression as a child + exists(Raw::CmdExpr e, boolean exprCtx | this.parentHasCmdExpr(parent, i, e, exprCtx) | + if exprCtx = true + then child = childRef(getResultAst(e.getExpr())) + else child = SynthChild(ExprStmtKind()) + ) + or + // Synthesize the redirections from the redirections on the CmdExpr + exists(int index, Raw::CmdExpr e | + parent = e.getExpr() and + i = exprRedirection(index) and + child = childRef(getResultAst(e.getRedirection(index))) + ) + } + + final override predicate exprStmtExpr(ExprStmt e, Expr expr) { + exists(Raw::Ast parent, ChildIndex i, Raw::CmdExpr cmd, Raw::Expr e0 | + e = TExprStmtSynth(parent, i) and + this.parentHasCmdExpr(parent, i, cmd, _) and + e0 = cmd.getExpr() and + expr = getResultAst(e0) + ) + } + + final override Ast getResultAstImpl(Raw::Ast r) { + exists( + Raw::CmdExpr cmdExpr, Raw::Expr e, Raw::ChildIndex rawIndex, Raw::Ast cmdParent, + ChildIndex i + | + r = cmdExpr and + cmdExpr.getExpr() = e and + cmdParent.getChild(rawIndex) = cmdExpr and + not mustHaveExprChild(cmdParent, cmdExpr) and + rawIndex = toRawChildIndex(i) and + result = TExprStmtSynth(cmdParent, i) + ) + } + + pragma[nomagic] + private predicate parentHasCmdExpr( + Raw::Ast parent, ChildIndex i, Raw::CmdExpr cmdExpr, boolean exprCtx + ) { + exists(Raw::ChildIndex rawIndex | + rawIndex = toRawChildIndex(i) and + parent.getChild(rawIndex) = cmdExpr and + if mustHaveExprChild(parent, cmdExpr) then exprCtx = true else exprCtx = false + ) + } + + final override Location getLocation(Ast n) { + exists(Raw::Ast parent, ChildIndex i, Raw::CmdExpr cmdStmt | + n = TExprStmtSynth(parent, i) and + this.parentHasCmdExpr(parent, i, cmdStmt, false) and + result = cmdStmt.getLocation() + ) + } + } +} + +/** + * Clean up arguments to commands by: + * - Removing the parameter name as an argument. + */ +private module CmdArguments { + private class CmdParameterRemoval extends Synthesis { + override predicate child(Raw::Ast parent, ChildIndex i, Child child) { + exists(Raw::Expr e | + this.rawChild(parent, i, e) and + child = childRef(getResultAst(e)) + ) + } + + private predicate rawChild(Raw::Cmd cmd, ChildIndex i, Raw::Expr child) { + exists(int index | + i = cmdArgument(index) and + child = cmd.getArgument(index) + ) + } + + override predicate isNamedArgument(CmdCall call, int i, string name) { + exists(Raw::Cmd cmd, Raw::Expr e, Raw::CmdParameter p | + this.rawChild(cmd, cmdArgument(i), e) and + call = getResultAst(cmd) and + p.getName().toLowerCase() = name + | + p.getExpr() = e + or + exists(ChildIndex j, int jndex | + j = cmdElement_(jndex) and + not exists(p.getExpr()) and + cmd.getChild(toRawChildIndex(j)) = p and + cmd.getChild(toRawChildIndex(cmdElement_(jndex + 1))) = e + ) + ) + } + } +} + +/** + * Synthesize literals from known constant strings. + */ +private module LiteralSynth { + private class LiteralSynth extends Synthesis { + final override predicate isRelevant(Raw::Ast a) { + exists(Raw::VarAccess va | a = va | + va.getUserPath().toLowerCase() = "true" + or + va.getUserPath().toLowerCase() = "false" + or + va.getUserPath().toLowerCase() = "null" + or + Raw::isEnvVariableAccess(va, _) + or + Raw::isAutomaticVariableAccess(va, _) + ) + } + + final override Expr getResultAstImpl(Raw::Ast r) { + exists(Raw::Ast parent, ChildIndex i | this.child(parent, i, _, r) | + result = TBoolLiteral(parent, i) or + result = TNullLiteral(parent, i) or + result = TEnvVariable(parent, i) or + result = TAutomaticVariable(parent, i) + ) + } + + private predicate child(Raw::Ast parent, ChildIndex i, Child child, Raw::VarAccess va) { + exists(string s | + parent.getChild(toRawChildIndex(i)) = va and + va.getUserPath().toLowerCase() = s + | + s = "true" and + child = SynthChild(BoolLiteralKind(true)) + or + s = "false" and + child = SynthChild(BoolLiteralKind(false)) + or + s = "null" and + child = SynthChild(NullLiteralKind()) + or + Raw::isEnvVariableAccess(va, s) and + child = SynthChild(EnvVariableKind(s)) + or + Raw::isAutomaticVariableAccess(va, s) and + child = SynthChild(AutomaticVariableKind(s)) + ) + } + + override predicate child(Raw::Ast parent, ChildIndex i, Child child) { + this.child(parent, i, child, _) + } + + final override predicate booleanValue(BoolLiteral b, boolean value) { + exists(Raw::Ast parent, ChildIndex i | + b = TBoolLiteral(parent, i) and + this.child(parent, i, SynthChild(BoolLiteralKind(value))) + ) + } + + final override predicate envVariableName(EnvVariable var, string name) { + exists(Raw::Ast parent, ChildIndex i | + var = TEnvVariable(parent, i) and + this.child(parent, i, SynthChild(EnvVariableKind(name))) + ) + } + + final override predicate automaticVariableName(AutomaticVariable var, string name) { + exists(Raw::Ast parent, ChildIndex i | + var = TAutomaticVariable(parent, i) and + this.child(parent, i, SynthChild(AutomaticVariableKind(name))) + ) + } + + final override Location getLocation(Ast n) { + exists(Raw::VarAccess va | + this.child(_, _, _, va) and + n = getResultAst(va) and + result = va.getLocation() + ) + } + } +} + +/** + * Synthesize variable accesses for pipeline iterators inside a process block. + */ +private module IteratorAccessSynth { + private class PipelineOrPipelineByPropertyNameIteratorVariable extends VariableSynth { + PipelineOrPipelineByPropertyNameIteratorVariable() { + this instanceof PipelineIteratorVariable + or + this instanceof PipelineByPropertyNameIteratorVariable + } + + string getPropertyName() { + result = this.(PipelineByPropertyNameIteratorVariable).getPropertyName() + } + + predicate isPipelineIterator() { this instanceof PipelineIteratorVariable } + } + + bindingset[pb, v] + private string getAPipelineIteratorName( + Raw::ProcessBlock pb, PipelineOrPipelineByPropertyNameIteratorVariable v + ) { + v.isPipelineIterator() and + ( + result = "_" + or + // or + // result = "psitem" // TODO: This is also an automatic variable + result = pb.getScriptBlock().getParamBlock().getPipelineParameter().getName().toLowerCase() + ) + or + // TODO: We could join on something other than the string if we wanted (i.e., the raw parameter). + v.getPropertyName().toLowerCase() = result and + result = + pb.getScriptBlock() + .getParamBlock() + .getAPipelineByPropertyNameParameter() + .getName() + .toLowerCase() + } + + private class IteratorAccessSynth extends Synthesis { + private predicate expr(Raw::Ast rawParent, ChildIndex i, Raw::VarAccess va, Child child) { + rawParent.getChild(toRawChildIndex(i)) = va and + child = SynthChild(VarAccessSynthKind(this.varAccess(va))) + } + + private predicate stmt(Raw::Ast rawParent, ChildIndex i, Raw::CmdExpr cmdExpr, Child child) { + rawParent.getChild(toRawChildIndex(i)) = cmdExpr and + not mustHaveExprChild(rawParent, cmdExpr) and + child = SynthChild(ExprStmtKind()) + } + + private PipelineOrPipelineByPropertyNameIteratorVariable varAccess(Raw::VarAccess va) { + exists(Raw::ProcessBlock pb | + pb = va.getParent+() and + result = TVariableSynth(pb, _) and + va.getUserPath().toLowerCase() = getAPipelineIteratorName(pb, result) + ) + } + + override predicate child(Raw::Ast parent, ChildIndex i, Child child) { + this.expr(parent, i, _, child) + or + this.stmt(parent, i, _, child) + or + exists(Raw::ProcessBlock pb | parent = pb | + i = PipelineIteratorVar() and + child = SynthChild(VarSynthKind(PipelineIteratorKind())) + or + exists(Raw::Parameter p | + p = pb.getScriptBlock().getParamBlock().getAPipelineByPropertyNameParameter() and + child = SynthChild(VarSynthKind(PipelineByPropertyNameIteratorKind(p.getName()))) and + i = PipelineByPropertyNameIteratorVar(p) + ) + ) + } + + override predicate exprStmtExpr(ExprStmt e, Expr expr) { + exists(Raw::Ast p, Raw::VarAccess va, Raw::CmdExpr cmdExpr, ChildIndex i1, ChildIndex i2 | + this.stmt(p, i1, _, _) and + this.expr(cmdExpr, i2, va, _) and + e = TExprStmtSynth(p, i1) and + expr = TVarAccessSynth(cmdExpr, i2, this.varAccess(va)) + ) + } + + final override Expr getResultAstImpl(Raw::Ast r) { + exists(Raw::Ast parent, ChildIndex i | this.expr(parent, i, r, _) | + result = TVarAccessSynth(parent, i, this.varAccess(r)) + ) + } + + override predicate variableSynthName(VariableSynth v, string name) { + v = TVariableSynth(_, PipelineIteratorVar()) and + name = "__pipeline_iterator" + or + exists(Raw::PipelineByPropertyNameParameter p | + v = TVariableSynth(_, PipelineByPropertyNameIteratorVar(p)) and + name = "__pipeline_iterator for " + p.getName() + ) + } + + final override Location getLocation(Ast n) { + exists(Raw::Ast parent, ChildIndex i, Raw::CmdExpr cmdExpr | + this.stmt(parent, i, cmdExpr, _) and + n = TExprStmtSynth(parent, i) and + result = cmdExpr.getLocation() + ) + or + exists(Raw::Ast parent | + n = TVariableSynth(parent, _) and + result = parent.getLocation() + ) + } + } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/TAst.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/TAst.qll new file mode 100644 index 000000000000..6bc4bf7a8bdb --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/TAst.qll @@ -0,0 +1,328 @@ +private import Raw.Raw as Raw +private import Location +private import Ast as Ast +private import Synthesis +private import Expr +private import Internal::Private +private import Internal::Public + +private predicate mkSynthChild(SynthKind kind, Raw::Ast parent, ChildIndex i) { + any(Synthesis s).child(parent, i, SynthChild(kind)) +} + +string variableNameInScope(Raw::Ast n, Scope::Range scope) { + scope = Raw::scopeOf(n) and + ( + result = n.(Raw::VarAccess).getUserPath() and + not scope.getAParameter().(Raw::PipelineByPropertyNameParameter).getName() = result and + not result.toLowerCase() = ["_", "this", "false", "true", "null"] and + not parameter(_, n, _, _) and + not Raw::isEnvVariableAccess(n, _) and + not Raw::isAutomaticVariableAccess(n, _) + or + any(Synthesis s).explicitAssignment(n, result, _) + or + any(Synthesis s).implicitAssignment(n, result) + ) +} + +private predicate scopeAssigns(Scope::Range scope, string name, Raw::Ast n) { + (explicitAssignment(n, _) or implicitAssignment(n)) and + name = variableNameInScope(n, scope) +} + +private predicate scopeDefinesParameterVariable(Scope::Range scope, string name) { + exists(Raw::Parameter p | + any(Synthesis s).implicitAssignment(p, name) and + p.getScope() = scope + ) +} + +private predicate inherits(Scope::Range scope, string name, Scope::Range outer) { + not scopeDefinesParameterVariable(scope, name) and + ( + outer = scope.getOuterScope() and + ( + scopeDefinesParameterVariable(outer, name) + or + exists(Raw::Ast n | + scopeAssigns(outer, name, n) and + n.getLocation().strictlyBefore(scope.getLocation()) + ) + ) + or + inherits(scope.getOuterScope(), name, outer) + ) +} + +pragma[nomagic] +private predicate hasScopeAndName(VariableImpl variable, Scope::Range scope, string name) { + variable.getNameImpl() = name and + scope = variable.getDeclaringScopeImpl() +} + +private predicate access(Raw::VarAccess va, VariableImpl v) { + exists(string name, Scope::Range scope | + pragma[only_bind_into](name) = variableNameInScope(va, scope) + | + hasScopeAndName(v, scope, name) + or + exists(Scope::Range declScope | + hasScopeAndName(v, declScope, pragma[only_bind_into](name)) and + inherits(scope, name, declScope) + ) + ) +} + +cached +private module Cached { + private predicate excludeStringConstExpr(Raw::StringConstExpr e) { + // i.e., "Node" or "Script" + dynamic_keyword_statement_command_elements(_, 0, e) + } + + cached + newtype TAst = + TAttributedExpr(Raw::AttributedExpr a) or + TArrayExpr(Raw::ArrayExpr e) or + TArrayLiteral(Raw::ArrayLiteral lit) or + TAssignStmt(Raw::AssignStmt s) or + TAttribute(Raw::Attribute a) or + TBinaryExpr(Raw::BinaryExpr bin) or + TBreakStmt(Raw::BreakStmt br) or + TCatchClause(Raw::CatchClause cc) or + TCmd(Raw::Cmd c) or + TExprStmtSynth(Raw::Ast parent, ChildIndex i) { mkSynthChild(ExprStmtKind(), parent, i) } or + TTopLevelFunction(Raw::TopLevelScriptBlock scriptBlock) or + TFunctionSynth(Raw::Ast parent, ChildIndex i) { mkSynthChild(FunctionSynthKind(), parent, i) } or + TConfiguration(Raw::Configuration c) or + TConstExpr(Raw::ConstExpr c) or + TContinueStmt(Raw::ContinueStmt c) or + TConvertExpr(Raw::ConvertExpr c) or + TDataStmt(Raw::DataStmt d) or + TDoUntilStmt(Raw::DoUntilStmt d) or + TDoWhileStmt(Raw::DoWhileStmt d) or + TDynamicStmt(Raw::DynamicStmt d) or + TErrorExpr(Raw::ErrorExpr e) or + TErrorStmt(Raw::ErrorStmt e) or + TExitStmt(Raw::ExitStmt e) or + TExpandableStringExpr(Raw::ExpandableStringExpr e) or + TFunctionDefinitionStmt(Raw::FunctionDefinitionStmt f) { not excludeFunctionDefinitionStmt(f) } or + TForEachStmt(Raw::ForEachStmt f) or + TForStmt(Raw::ForStmt f) or + THashTableExpr(Raw::HashTableExpr h) or + TIf(Raw::IfStmt i) or + TIndexExpr(Raw::IndexExpr i) or + TInvokeMemberExpr(Raw::InvokeMemberExpr i) or + TMethod(Raw::Method m) or + TMemberExpr(Raw::MemberExpr m) or + TNamedAttributeArgument(Raw::NamedAttributeArgument n) or + TNamedBlock(Raw::NamedBlock n) or + TParenExpr(Raw::ParenExpr p) or + TPipeline(Raw::Pipeline p) or + TPipelineChain(Raw::PipelineChain p) or + TPropertyMember(Raw::PropertyMember p) or + TRedirection(Raw::Redirection r) or + TReturnStmt(Raw::ReturnStmt r) or + TScriptBlock(Raw::ScriptBlock s) or + TScriptBlockExpr(Raw::ScriptBlockExpr s) or + TExpandableSubExpr(Raw::ExpandableSubExpr e) or + TStmtBlock(Raw::StmtBlock s) or + TStringConstExpr(Raw::StringConstExpr s) { not excludeStringConstExpr(s) } or + TSwitchStmt(Raw::SwitchStmt s) or + TConditionalExpr(Raw::ConditionalExpr t) or + TThrowStmt(Raw::ThrowStmt t) or + TTrapStmt(Raw::TrapStmt t) or + TThisExprReal(Raw::ThisAccess t) or + TTryStmt(Raw::TryStmt t) or + TTypeDefinitionStmt(Raw::TypeStmt t) or + TTypeSynth(Raw::Ast parent, ChildIndex i) { mkSynthChild(TypeSynthKind(), parent, i) } or + TTypeConstraint(Raw::TypeConstraint t) or + TUnaryExpr(Raw::UnaryExpr u) or + TUsingStmt(Raw::UsingStmt u) or + TVariableReal(Scope::Range scope, string name, Raw::Ast n) { + not n instanceof Raw::Parameter and // we synthesize all parameters + n = + min(Raw::Ast other | + scopeAssigns(scope, name, other) + | + other order by other.getLocation().getStartLine(), other.getLocation().getStartColumn() + ) + } or + TVariableSynth(Raw::Ast scope, ChildIndex i) { mkSynthChild(VarSynthKind(_), scope, i) } or + TVarAccessReal(Raw::VarAccess va, Variable v) { access(va, v) } or + TVarAccessSynth(Raw::Ast parent, ChildIndex i, Variable v) { + mkSynthChild(VarAccessRealKind(v), parent, i) + or + mkSynthChild(VarAccessSynthKind(v), parent, i) + } or + TWhileStmt(Raw::WhileStmt w) or + TTypeNameExpr(Raw::TypeNameExpr t) or + TUsingExpr(Raw::UsingExpr u) or + TBoolLiteral(Raw::Ast parent, ChildIndex i) { mkSynthChild(BoolLiteralKind(_), parent, i) } or + TNullLiteral(Raw::Ast parent, ChildIndex i) { mkSynthChild(NullLiteralKind(), parent, i) } or + TEnvVariable(Raw::Ast parent, ChildIndex i) { mkSynthChild(EnvVariableKind(_), parent, i) } or + TAutomaticVariable(Raw::Ast parent, ChildIndex i) { + mkSynthChild(AutomaticVariableKind(_), parent, i) + } + + class TAstReal = + TArrayExpr or TArrayLiteral or TAssignStmt or TAttribute or TOperation or TBreakStmt or + TCatchClause or TCmd or TConfiguration or TConstExpr or TContinueStmt or TConvertExpr or + TDataStmt or TDoUntilStmt or TDoWhileStmt or TDynamicStmt or TErrorExpr or TErrorStmt or + TExitStmt or TExpandableStringExpr or TForEachStmt or TForStmt or TGotoStmt or + THashTableExpr or TIf or TIndexExpr or TInvokeMemberExpr or TMemberExpr or + TNamedAttributeArgument or TNamedBlock or TPipeline or TPipelineChain or TPropertyMember or + TRedirection or TReturnStmt or TScriptBlock or TScriptBlockExpr or TStmtBlock or + TStringConstExpr or TSwitchStmt or TConditionalExpr or TThrowStmt or TTrapStmt or + TTryStmt or TTypeDefinitionStmt or TTypeConstraint or TUsingStmt or TVarAccessReal or + TWhileStmt or TFunctionDefinitionStmt or TExpandableSubExpr or TMethod or TTypeNameExpr or + TAttributedExpr or TUsingExpr or TThisExprReal or TParenExpr or TVariableReal; + + class TAstSynth = + TExprStmtSynth or TFunctionSynth or TBoolLiteral or TNullLiteral or TVarAccessSynth or + TEnvVariable or TTypeSynth or TAutomaticVariable or TVariableSynth; + + class TExpr = + TArrayExpr or TArrayLiteral or TOperation or TConstExpr or TConvertExpr or TErrorExpr or + THashTableExpr or TIndexExpr or TInvokeMemberExpr or TCmd or TMemberExpr or TPipeline or + TPipelineChain or TStringConstExpr or TConditionalExpr or TVarAccess or + TExpandableStringExpr or TScriptBlockExpr or TExpandableSubExpr or TTypeNameExpr or + TUsingExpr or TAttributedExpr or TIf or TBoolLiteral or TNullLiteral or TThisExpr or + TEnvVariable or TAutomaticVariable or TParenExpr; + + class TStmt = + TAssignStmt or TBreakStmt or TContinueStmt or TDataStmt or TDoUntilStmt or TDoWhileStmt or + TDynamicStmt or TErrorStmt or TExitStmt or TForEachStmt or TForStmt or TGotoStmt or + TReturnStmt or TStmtBlock or TSwitchStmt or TThrowStmt or TTrapStmt or TTryStmt or + TUsingStmt or TWhileStmt or TConfiguration or TTypeDefinitionStmt or + TFunctionDefinitionStmt or TExprStmt; + + class TType = TTypeSynth; + + class TOperation = TBinaryExpr or TUnaryExpr; + + class TMember = TPropertyMember or TMethod; + + class TExprStmt = TExprStmtSynth; + + class TAttributeBase = TAttribute or TTypeConstraint; + + class TFunction = TFunctionSynth or TTopLevelFunction; + + class TFunctionBase = TFunction or TMethod; + + class TAttributedExprBase = TAttributedExpr or TConvertExpr; + + class TCallExpr = TCmd or TInvokeMemberExpr; + + class TLoopStmt = TDoUntilStmt or TDoWhileStmt or TForEachStmt or TForStmt or TWhileStmt; + + class TVarAccess = TVarAccessReal or TVarAccessSynth; + + class TLiteral = TBoolLiteral or TNullLiteral; + + class TGotoStmt = TContinueStmt or TBreakStmt; + + class TThisExpr = TThisExprReal; + + cached + Raw::Ast toRaw(TAstReal n) { + n = TArrayExpr(result) or + n = TArrayLiteral(result) or + n = TAssignStmt(result) or + n = TAttribute(result) or + n = TBinaryExpr(result) or + n = TBreakStmt(result) or + n = TCatchClause(result) or + n = TCmd(result) or + n = TConfiguration(result) or + n = TConstExpr(result) or + n = TContinueStmt(result) or + n = TConvertExpr(result) or + n = TDataStmt(result) or + n = TDoUntilStmt(result) or + n = TDoWhileStmt(result) or + n = TDynamicStmt(result) or + n = TErrorExpr(result) or + n = TErrorStmt(result) or + n = TExitStmt(result) or + n = TExpandableStringExpr(result) or + n = TForEachStmt(result) or + n = TForStmt(result) or + n = THashTableExpr(result) or + n = TIf(result) or + n = TIndexExpr(result) or + n = TInvokeMemberExpr(result) or + n = TMemberExpr(result) or + n = TNamedAttributeArgument(result) or + n = TNamedBlock(result) or + n = TPipeline(result) or + n = TParenExpr(result) or + n = TPipelineChain(result) or + n = TPropertyMember(result) or + n = TRedirection(result) or + n = TReturnStmt(result) or + n = TScriptBlock(result) or + n = TScriptBlockExpr(result) or + n = TStmtBlock(result) or + n = TStringConstExpr(result) or + n = TSwitchStmt(result) or + n = TConditionalExpr(result) or + n = TThrowStmt(result) or + n = TTrapStmt(result) or + n = TTryStmt(result) or + n = TTypeDefinitionStmt(result) or + n = TThisExprReal(result) or + n = TTypeConstraint(result) or + n = TUnaryExpr(result) or + n = TUsingStmt(result) or + n = TVarAccessReal(result, _) or + n = TWhileStmt(result) or + n = TFunctionDefinitionStmt(result) or + n = TExpandableSubExpr(result) or + n = TTypeNameExpr(result) or + n = TMethod(result) or + n = TAttributedExpr(result) or + n = TUsingExpr(result) or + n = TVariableReal(_, _, result) + } + + cached + Raw::Ast toRawIncludingSynth(Ast::Ast n) { + result = toRaw(n) + or + not exists(toRaw(n)) and + exists(Raw::Ast parent | + synthChild(parent, _, n) and + result = parent + ) + } + + cached + TAstReal fromRaw(Raw::Ast a) { toRaw(result) = a } + + cached + Ast::Ast getSynthChild(Raw::Ast parent, ChildIndex i) { + result = TExprStmtSynth(parent, i) or + result = TFunctionSynth(parent, i) or + result = TBoolLiteral(parent, i) or + result = TNullLiteral(parent, i) or + result = TVarAccessSynth(parent, i, _) or + result = TEnvVariable(parent, i) or + result = TTypeSynth(parent, i) or + result = TAutomaticVariable(parent, i) or + result = TVariableSynth(parent, i) + } + + cached + predicate synthChild(Raw::Ast parent, ChildIndex i, Ast::Ast child) { + child = getSynthChild(parent, i) + or + any(Synthesis s).child(parent, i, RealChildRef(child)) + or + any(Synthesis s).child(parent, i, SynthChildRef(child)) + } +} + +import Cached diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/TernaryExpression.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/TernaryExpression.qll new file mode 100644 index 000000000000..022a3675dcd4 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/TernaryExpression.qll @@ -0,0 +1,55 @@ +private import AstImport + +class ConditionalExpr extends Expr, TConditionalExpr { + override string toString() { result = "...?...:..." } + + final override Ast getChild(ChildIndex i) { + result = super.getChild(i) + or + i = condExprCond() and + result = this.getCondition() + or + i = condExprTrue() and + result = this.getIfTrue() + or + i = condExprFalse() and + result = this.getIfFalse() + } + + Expr getCondition() { + exists(Raw::Ast r | r = getRawAst(this) | + synthChild(r, condExprCond(), result) + or + not synthChild(r, condExprCond(), _) and + result = getResultAst(r.(Raw::ConditionalExpr).getCondition()) + ) + } + + Expr getIfFalse() { + exists(Raw::Ast r | r = getRawAst(this) | + synthChild(r, condExprFalse(), result) + or + not synthChild(r, condExprCond(), _) and + result = getResultAst(r.(Raw::ConditionalExpr).getIfFalse()) + ) + } + + Expr getIfTrue() { + exists(Raw::Ast r | r = getRawAst(this) | + synthChild(r, condExprTrue(), result) + or + not synthChild(r, condExprTrue(), _) and + result = getResultAst(r.(Raw::ConditionalExpr).getIfTrue()) + ) + } + + Expr getBranch(boolean value) { + value = true and + result = this.getIfTrue() + or + value = false and + result = this.getIfFalse() + } + + Expr getABranch() { result = this.getBranch(_) } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/ThisExpr.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/ThisExpr.qll new file mode 100644 index 000000000000..e93e01f6399c --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/ThisExpr.qll @@ -0,0 +1,6 @@ +private import AstImport + +class ThisExpr extends Expr, TThisExpr { + final override string toString() { result = "this" } + +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/ThrowStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/ThrowStmt.qll new file mode 100644 index 000000000000..0b8ed0fe7c80 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/ThrowStmt.qll @@ -0,0 +1,24 @@ +private import AstImport + +class ThrowStmt extends Stmt, TThrowStmt { + Expr getPipeline() { + exists(Raw::Ast r | r = getRawAst(this) | + synthChild(r, throwStmtPipeline(), result) + or + not synthChild(r, throwStmtPipeline(), _) and + result = getResultAst(r.(Raw::ThrowStmt).getPipeline()) + ) + } + + predicate hasPipeline() { exists(this.getPipeline()) } + + override string toString() { + if this.hasPipeline() then result = "throw ..." else result = "throw" + } + + final override Ast getChild(ChildIndex i) { + result = super.getChild(i) + or + i = throwStmtPipeline() and result = this.getPipeline() + } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/TrapStatement.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/TrapStatement.qll new file mode 100644 index 000000000000..498522051253 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/TrapStatement.qll @@ -0,0 +1,33 @@ +private import AstImport + +class TrapStmt extends Stmt, TTrapStmt { + StmtBlock getBody() { + exists(Raw::Ast r | r = getRawAst(this) | + synthChild(r, trapStmtBody(), result) + or + not synthChild(r, trapStmtBody(), _) and + result = getResultAst(r.(Raw::TrapStmt).getBody()) + ) + } + + TypeConstraint getTypeConstraint() { + exists(Raw::Ast r | r = getRawAst(this) | + synthChild(r, trapStmtTypeConstraint(), result) + or + not synthChild(r, trapStmtTypeConstraint(), _) and + result = getResultAst(r.(Raw::TrapStmt).getTypeConstraint()) + ) + } + + override Ast getChild(ChildIndex i) { + result = super.getChild(i) + or + i = trapStmtBody() and + result = this.getBody() + or + i = trapStmtTypeConstraint() and + result = this.getTypeConstraint() + } + + override string toString() { result = "trap {...}" } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/TryStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/TryStmt.qll new file mode 100644 index 000000000000..78d6dd8eba69 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/TryStmt.qll @@ -0,0 +1,52 @@ +private import AstImport + +class TryStmt extends Stmt, TTryStmt { + CatchClause getCatchClause(int i) { + exists(ChildIndex index, Raw::Ast r | index = tryStmtCatchClause(i) and r = getRawAst(this) | + synthChild(r, index, result) + or + not synthChild(r, index, _) and + result = getResultAst(r.(Raw::TryStmt).getCatchClause(i)) + ) + } + + CatchClause getACatchClause() { result = this.getCatchClause(_) } + + /** ..., if any. */ + StmtBlock getFinally() { + exists(Raw::Ast r | r = getRawAst(this) | + synthChild(r, tryStmtFinally(), result) + or + not synthChild(r, tryStmtFinally(), _) and + result = getResultAst(r.(Raw::TryStmt).getFinally()) + ) + } + + predicate hasFinally() { exists(this.getFinally()) } + + StmtBlock getBody() { + exists(Raw::Ast r | r = getRawAst(this) | + synthChild(r, tryStmtBody(), result) + or + not synthChild(r, tryStmtBody(), _) and + result = getResultAst(r.(Raw::TryStmt).getBody()) + ) + } + + override string toString() { result = "try {...}" } + + final override Ast getChild(ChildIndex i) { + result = super.getChild(i) + or + i = tryStmtBody() and + result = this.getBody() + or + exists(int index | + i = tryStmtCatchClause(index) and + result = this.getCatchClause(index) + ) + or + i = tryStmtFinally() and + result = this.getFinally() + } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Type.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Type.qll new file mode 100644 index 000000000000..5f7c739c9d43 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Type.qll @@ -0,0 +1,38 @@ +private import AstImport + +class Type extends Ast, TTypeSynth { + override string toString() { result = this.getName() } + + Member getMember(int i) { any(Synthesis s).typeMember(this, i, result) } + + string getName() { any(Synthesis s).typeName(this, result) } + + Member getAMember() { result = this.getMember(_) } + + Method getMethod(string name) { result = this.getAMember() and result.getName() = name } + + Method getAMethod() { result = this.getMethod(_) } + + Constructor getAConstructor() { + result = this.getAMethod() and + result.getName() = this.getName() + } + + TypeConstraint getBaseType(int i) { none() } + + TypeConstraint getABaseType() { result = this.getBaseType(_) } + + Type getASubtype() { none() } + + final override Ast getChild(ChildIndex i) { + result = super.getChild(i) + or + exists(int index | + i = typeMember(index) and + result = this.getMember(index) + or + i = typeStmtBaseType(index) and + result = this.getBaseType(index) + ) + } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/TypeConstraint.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/TypeConstraint.qll new file mode 100644 index 000000000000..8085a3832aee --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/TypeConstraint.qll @@ -0,0 +1,7 @@ +private import AstImport + +class TypeConstraint extends Ast, TTypeConstraint { + string getName() { result = getRawAst(this).(Raw::TypeConstraint).getName() } + + override string toString() { result = this.getName() } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/TypeDefinitionStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/TypeDefinitionStmt.qll new file mode 100644 index 000000000000..e630c2728141 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/TypeDefinitionStmt.qll @@ -0,0 +1,50 @@ +private import AstImport + +class TypeDefinitionStmt extends Stmt, TTypeDefinitionStmt { + string getName() { result = getRawAst(this).(Raw::TypeStmt).getName() } + + override string toString() { result = this.getName() } + + Member getMember(int i) { + exists(ChildIndex index, Raw::Ast r | index = typeStmtMember(i) and r = getRawAst(this) | + synthChild(r, index, result) + or + not synthChild(r, index, _) and + result = getResultAst(r.(Raw::TypeStmt).getMember(i)) + ) + } + + Member getAMember() { result = this.getMember(_) } + + Method getMethod(string name) { + result = getResultAst(getRawAst(this).(Raw::TypeStmt).getMethod(name)) + } + + Method getAMethod() { result = this.getMethod(_) } + + Constructor getAConstructor() { + result = this.getAMethod() and + result.getName() = this.getName() + } + + TypeConstraint getBaseType(int i) { + exists(ChildIndex index, Raw::Ast r | index = typeStmtBaseType(i) and r = getRawAst(this) | + synthChild(r, index, result) + or + not synthChild(r, index, _) and + result = getResultAst(r.(Raw::TypeStmt).getBaseType(i)) + ) + } + + TypeConstraint getABaseType() { result = this.getBaseType(_) } + + TypeDefinitionStmt getASubtype() { result.getABaseType().getName() = this.getName() } + + Type getType() { synthChild(getRawAst(this), typeDefType(), result) } + + final override Ast getChild(ChildIndex i) { + result = super.getChild(i) + or + i = typeDefType() and result = this.getType() + } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/TypeExpression.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/TypeExpression.qll new file mode 100644 index 000000000000..73f1d1fe3714 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/TypeExpression.qll @@ -0,0 +1,32 @@ +private import AstImport + +class TypeNameExpr extends Expr, TTypeNameExpr { + private predicate parseName(string namespace, string typename) { + exists(string fullName | fullName = this.getPossiblyQualifiedName() | + if fullName.matches("%.%") + then + namespace = fullName.regexpCapture("([a-zA-Z0-9\\.]+)\\.([a-zA-Z0-9]+)", 1) and + typename = fullName.regexpCapture("([a-zA-Z0-9\\.]+)\\.([a-zA-Z0-9]+)", 2) + else ( + namespace = "" and + typename = fullName + ) + ) + } + + string getName() { this.parseName(_, result) } + + /** If any */ + string getPossiblyQualifiedName() { result = getRawAst(this).(Raw::TypeNameExpr).getName() } + + // TODO: What to do when System is omitted? + string getNamespace() { this.parseName(result, _) } + + override string toString() { result = this.getName() } + + predicate isQualified() { this.getNamespace() != "" } +} + +class QualifiedTypeNameExpr extends TypeNameExpr { + QualifiedTypeNameExpr() { this.isQualified() } +} diff --git a/powershell/ql/lib/semmle/code/powershell/UnaryExpression.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/UnaryExpression.qll similarity index 77% rename from powershell/ql/lib/semmle/code/powershell/UnaryExpression.qll rename to powershell/ql/lib/semmle/code/powershell/ast/internal/UnaryExpression.qll index 6a42360d7dcf..860dddfc65b3 100644 --- a/powershell/ql/lib/semmle/code/powershell/UnaryExpression.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/UnaryExpression.qll @@ -1,11 +1,23 @@ -import powershell +private import AstImport -class UnaryExpr extends @unary_expression, Expr { - override SourceLocation getLocation() { unary_expression_location(this, result) } +class UnaryExpr extends Expr, TUnaryExpr { + final override Ast getChild(ChildIndex i) { + result = super.getChild(i) + or + i = unaryExprOp() and result = this.getOperand() + } - int getKind() { unary_expression(this, _, result, _) } + /** INTERNAL: Do not use. */ + int getKind() { result = getRawAst(this).(Raw::UnaryExpr).getKind() } - Expr getOperand() { unary_expression(this, result, _, _) } + Expr getOperand() { + exists(Raw::Ast r | r = getRawAst(this) | + synthChild(r, unaryExprOp(), result) + or + not synthChild(r, unaryExprOp(), _) and + result = getResultAst(r.(Raw::UnaryExpr).getOperand()) + ) + } } class NotExpr extends UnaryExpr { diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/UsingExpression.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/UsingExpression.qll new file mode 100644 index 000000000000..32848d397dd1 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/UsingExpression.qll @@ -0,0 +1,21 @@ +private import AstImport + +class UsingExpr extends Expr, TUsingExpr { + override string toString() { result = "$using..." } + + Expr getExpr() { + exists(Raw::Ast r | r = getRawAst(this) | + synthChild(r, usingExprExpr(), result) + or + not synthChild(r, usingExprExpr(), _) and + result = getResultAst(r.(Raw::UsingExpr).getExpr()) + ) + } + + override Ast getChild(ChildIndex i) { + result = super.getChild(i) + or + i = usingExprExpr() and + result = this.getExpr() + } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/UsingStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/UsingStmt.qll new file mode 100644 index 000000000000..d649560bcd98 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/UsingStmt.qll @@ -0,0 +1,9 @@ +private import AstImport + +class UsingStmt extends Stmt, TUsingStmt { + override string toString() { result = "using ..." } + + string getName() { result = getRawAst(this).(Raw::UsingStmt).getName() } + + Scope getAnAffectedScope() { result.getEnclosingScope*() = this.getEnclosingScope() } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Variable.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Variable.qll new file mode 100644 index 000000000000..27c2ac5063d7 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Variable.qll @@ -0,0 +1,181 @@ +private import TAst +private import AstImport + +module Private { + class TVariable = TVariableReal or TVariableSynth; + + class VariableImpl extends Ast, TVariable { + abstract string getNameImpl(); + + final override string toString() { result = this.getNameImpl() } + + abstract Location getLocationImpl(); + + abstract Scope::Range getDeclaringScopeImpl(); + } + + class VariableReal extends VariableImpl, TVariableReal { + Scope::Range scope; + string name; + Raw::Ast n; + + VariableReal() { this = TVariableReal(scope, name, n) } + + override string getNameImpl() { result = name } + + override Location getLocationImpl() { result = n.getLocation() } + + final override Scope::Range getDeclaringScopeImpl() { result = scope } + + predicate isParameter(Raw::Parameter p) { n = p } + } + + class VariableSynth extends VariableImpl, TVariableSynth { + Raw::Ast scope; + ChildIndex i; + + VariableSynth() { this = TVariableSynth(scope, i) } + + override string getNameImpl() { any(Synthesis s).variableSynthName(this, result) } + + override Location getLocationImpl() { result = scope.getLocation() } + + override Scope::Range getDeclaringScopeImpl() { result = scope } + } + + class ParameterImpl extends VariableSynth { + ParameterImpl() { + i instanceof FunParam or i instanceof PipelineParamVar or i instanceof ThisVar + } + } + + class ThisParameterImpl extends VariableSynth { + override ThisVar i; + } + + class PipelineVariableImpl extends ParameterImpl { + override PipelineParamVar i; + + ScriptBlock getScriptBlock() { this = TVariableSynth(getRawAst(result), _) } + } + + class PipelineIteratorVariableImpl extends VariableSynth { + override PipelineIteratorVar i; + + ProcessBlock getProcessBlock() { this = TVariableSynth(getRawAst(result), _) } + } + + class PipelineByPropertyNameIteratorVariableImpl extends VariableSynth { + override PipelineByPropertyNameIteratorVar i; + + ProcessBlock getProcessBlock() { this = TVariableSynth(getRawAst(result), _) } + + /** + * Note: No result if this is not a pipeline-by-property-name. + */ + string getPropertyName() { + exists(Raw::PipelineByPropertyNameParameter p | + i = PipelineByPropertyNameIteratorVar(p) and + result = p.getName() + ) + } + + PipelineByPropertyNameParameter getParameter() { + exists(Raw::PipelineByPropertyNameParameter p | + i = PipelineByPropertyNameIteratorVar(p) and + p.getScriptBlock() = getRawAst(result.getEnclosingFunction().getBody()) and + p.getName() = result.getName() + ) + } + } + + abstract class VarAccessImpl extends Expr, TVarAccess { + abstract VariableImpl getVariableImpl(); + } + + class VarAccessReal extends VarAccessImpl, TVarAccessReal { + Raw::VarAccess va; + Variable v; + + VarAccessReal() { this = TVarAccessReal(va, v) } + + final override Variable getVariableImpl() { result = v } + + final override string toString() { result = v.getName() } + } + + class VarAccessSynth extends VarAccessImpl, TVarAccessSynth { + Raw::Ast parent; + ChildIndex i; + Variable v; + + VarAccessSynth() { this = TVarAccessSynth(parent, i, v) } + + final override Variable getVariableImpl() { result = v } + + final override string toString() { result = v.getName() } + + final override Location getLocation() { result = parent.getLocation() } + } + + predicate explicitAssignment(Raw::Ast dest, Raw::Ast assignment) { + assignment.(Raw::AssignStmt).getLeftHandSide() = dest + or + any(Synthesis s).explicitAssignment(dest, _, assignment) + } + + predicate implicitAssignment(Raw::Ast n) { any(Synthesis s).implicitAssignment(n, _) } +} + +private import Private + +module Public { + class Variable extends Ast instanceof VariableImpl { + final string getName() { result = super.getNameImpl() } + + final override string toString() { result = this.getName() } + + final override Location getLocation() { result = super.getLocationImpl() } + + Scope getDeclaringScope() { getRawAst(result) = super.getDeclaringScopeImpl() } + + VarAccess getAnAccess() { result.getVariable() = this } + } + + class VarAccess extends Expr instanceof VarAccessImpl { + Variable getVariable() { result = super.getVariableImpl() } + + predicate isExplicitWrite(Ast assignment) { + explicitAssignment(getRawAst(this), getRawAst(assignment)) + } + + predicate isImplicitWrite() { implicitAssignment(getRawAst(this)) } + } + + class VarWriteAccess extends VarAccess { + VarWriteAccess() { this.isExplicitWrite(_) or this.isImplicitWrite() } + } + + class VarReadAccess extends VarAccess { + VarReadAccess() { not this instanceof VarWriteAccess } + } + + class PipelineByPropertyNameIteratorVariable extends Variable instanceof PipelineByPropertyNameIteratorVariableImpl + { + ProcessBlock getProcessBlock() { result = super.getProcessBlock() } + + string getPropertyName() { result = super.getPropertyName() } + + PipelineByPropertyNameParameter getParameter() { result = super.getParameter() } + } + + class PipelineVariable extends Variable instanceof PipelineVariableImpl { + ScriptBlock getScriptBlock() { result = super.getScriptBlock() } + } + + class PipelineIteratorVariable extends Variable instanceof PipelineIteratorVariableImpl { + ProcessBlock getProcessBlock() { result = super.getProcessBlock() } + } +} + +import Public diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/WhileStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/WhileStmt.qll new file mode 100644 index 000000000000..d8817a6b0371 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/WhileStmt.qll @@ -0,0 +1,33 @@ +private import AstImport + +class WhileStmt extends LoopStmt, TWhileStmt { + override string toString() { result = "while(...) {...}" } + + Expr getCondition() { + exists(Raw::Ast r | r = getRawAst(this) | + synthChild(r, whileStmtCond(), result) + or + not synthChild(r, whileStmtCond(), _) and + result = getResultAst(r.(Raw::WhileStmt).getCondition()) + ) + } + + final override StmtBlock getBody() { + exists(Raw::Ast r | r = getRawAst(this) | + synthChild(r, whileStmtBody(), result) + or + not synthChild(r, whileStmtBody(), _) and + result = getResultAst(r.(Raw::WhileStmt).getBody()) + ) + } + + final override Ast getChild(ChildIndex i) { + result = super.getChild(i) + or + i = whileStmtCond() and + result = this.getCondition() + or + i = whileStmtBody() and + result = this.getBody() + } +} diff --git a/powershell/ql/lib/semmle/code/powershell/controlflow/CfgNodes.qll b/powershell/ql/lib/semmle/code/powershell/controlflow/CfgNodes.qll index 8c8efcbb42d0..809ef64f8724 100644 --- a/powershell/ql/lib/semmle/code/powershell/controlflow/CfgNodes.qll +++ b/powershell/ql/lib/semmle/code/powershell/controlflow/CfgNodes.qll @@ -127,433 +127,849 @@ abstract private class NonExprChildMapping extends ChildMapping { } } -abstract private class AbstractCallCfgNode extends AstCfgNode { - override string getAPrimaryQlClass() { result = "CfgCall" } +private class AttributeBaseChildMapping extends NonExprChildMapping, AttributeBase { + override predicate relevantChild(Ast child) { none() } +} + +class AttributeBaseCfgNode extends AstCfgNode { + AttributeBaseCfgNode() { attr = this.getAstNode() } - /** Holds if this call invokes a function with the name `name`. */ - final predicate hasName(string name) { this.getName() = name } + override string getAPrimaryQlClass() { result = "AttributeBaseCfgNode" } + + AttributeBaseChildMapping attr; +} - /** Gets the name of the function that is invoked by this call. */ - abstract string getName(); +private class AttributeChildMapping extends AttributeBaseChildMapping, Attribute { + override predicate relevantChild(Ast child) { + this.relevantChild(child) + or + child = this.getANamedArgument() + or + child = this.getAPositionalArgument() + } +} - /** Gets the qualifier of this call, if any. */ - ExprCfgNode getQualifier() { none() } +private class NamedAttributeArgumentChildMapping extends NonExprChildMapping, NamedAttributeArgument +{ + override predicate relevantChild(Ast child) { child = this.getValue() } +} - /** Gets the i'th argument to this call. */ - abstract ExprCfgNode getArgument(int i); +class NamedAttributeArgumentCfgNode extends AstCfgNode { + NamedAttributeArgumentCfgNode() { attr = this.getAstNode() } - /** Gets the i'th positional argument to this call. */ - abstract ExprCfgNode getPositionalArgument(int i); + override string getAPrimaryQlClass() { result = "NamedAttributeArgumentCfgNode" } - /** Gets the argument with the name `name`, if any. */ - abstract ExprCfgNode getNamedArgument(string name); + NamedAttributeArgumentChildMapping attr; - /** - * Gets any argument of this call. - * - * Note that this predicate doesn't get the pipeline argument, if any. - */ - abstract ExprCfgNode getAnArgument(); + NamedAttributeArgument getAttr() { result = attr } - /** - * Gets the expression that provides the call target of this call, if any. - */ - abstract ExprCfgNode getCommand(); + ExprCfgNode getValue() { attr.hasCfgChild(attr.getValue(), this, result) } + + string getName() { result = attr.getName() } +} + +class AttributeCfgNode extends AttributeBaseCfgNode { + override string getAPrimaryQlClass() { result = "AttributeCfgNode" } + + override AttributeChildMapping attr; + + NamedAttributeArgumentCfgNode getNamedArgument(int i) { + attr.hasCfgChild(attr.getNamedArgument(i), this, result) + } + + ExprCfgNode getPositionalArgument(int i) { + attr.hasCfgChild(attr.getPositionalArgument(i), this, result) + } +} + +private class ScriptBlockChildMapping extends NonExprChildMapping, ScriptBlock { + override predicate relevantChild(Ast child) { + child = this.getProcessBlock() + or + child = this.getBeginBlock() + or + child = this.getEndBlock() + or + child = this.getDynamicBlock() + or + child = this.getAnAttribute() + or + child = this.getAParameter() + } +} - int getNumberOfArguments() { result = count(this.getAnArgument()) } +private class ParameterChildMapping extends NonExprChildMapping, Parameter { + override predicate relevantChild(Ast child) { + child = this.getAnAttribute() or child = this.getDefaultValue() + } } -final class CallCfgNode = AbstractCallCfgNode; +class ParameterCfgNode extends AstCfgNode { + ParameterCfgNode() { param = this.getAstNode() } + + override string getAPrimaryQlClass() { result = "ParameterCfgNode" } -class ObjectCreationCfgNode extends CallCfgNode { - ObjectCreation objectCreation; + ParameterChildMapping param; - ObjectCreationCfgNode() { this.getAstNode() = objectCreation } + Parameter getParameter() { result = param } - ObjectCreation getObjectCreation() { result = objectCreation } + ExprCfgNode getDefaultValue() { param.hasCfgChild(param.getDefaultValue(), this, result) } - Type getConstructedType() { result = objectCreation.getConstructedType() } + AttributeCfgNode getAttribute(int i) { param.hasCfgChild(param.getAttribute(i), this, result) } - string getConstructedTypeName() { result = objectCreation.getConstructedTypeName() } + AttributeCfgNode getAnAttribute() { result = this.getAttribute(_) } +} + +class ScriptBlockCfgNode extends AstCfgNode { + ScriptBlockCfgNode() { block = this.getAstNode() } + + override string getAPrimaryQlClass() { result = "ScriptBlockCfgNode" } + + ScriptBlockChildMapping block; + + ScriptBlock getBlock() { result = block } + + ProcessBlockCfgNode getProcessBlock() { block.hasCfgChild(block.getProcessBlock(), this, result) } + + NamedBlockCfgNode getBeginBlock() { block.hasCfgChild(block.getBeginBlock(), this, result) } + + NamedBlockCfgNode getEndBlock() { block.hasCfgChild(block.getEndBlock(), this, result) } + + NamedBlockCfgNode getDynamicBlock() { block.hasCfgChild(block.getDynamicBlock(), this, result) } + + AttributeCfgNode getAttribute(int i) { block.hasCfgChild(block.getAttribute(i), this, result) } + + AttributeCfgNode getAnAttribute() { result = this.getAttribute(_) } + + ParameterCfgNode getParameter(int i) { block.hasCfgChild(block.getParameter(i), this, result) } + + ParameterCfgNode getAParameter() { result = this.getParameter(_) } } private class NamedBlockChildMapping extends NonExprChildMapping, NamedBlock { - override predicate relevantChild(Ast n) { n = this.getAStmt() } // TODO: Handle getATrap + override predicate relevantChild(Ast child) { + child = this.getAStmt() or child = this.getATrapStmt() + } } class NamedBlockCfgNode extends AstCfgNode { - NamedBlockChildMapping block; + NamedBlockCfgNode() { block = this.getAstNode() } - NamedBlockCfgNode() { this.getAstNode() = block } + override string getAPrimaryQlClass() { result = "NamedBlockCfgNode" } + + NamedBlockChildMapping block; NamedBlock getBlock() { result = block } StmtCfgNode getStmt(int i) { block.hasCfgChild(block.getStmt(i), this, result) } - StmtCfgNode getAStmt() { block.hasCfgChild(block.getAStmt(), this, result) } + StmtCfgNode getAStmt() { result = this.getStmt(_) } + + StmtNodes::TrapStmtCfgNode getTrapStmt(int i) { + block.hasCfgChild(block.getTrapStmt(i), this, result) + } + + StmtNodes::TrapStmtCfgNode getATrapStmt() { result = this.getTrapStmt(_) } } private class ProcessBlockChildMapping extends NamedBlockChildMapping, ProcessBlock { } class ProcessBlockCfgNode extends NamedBlockCfgNode { + override string getAPrimaryQlClass() { result = "ProcessBlockCfgNode" } + override ProcessBlockChildMapping block; override ProcessBlock getBlock() { result = block } - PipelineParameter getPipelineParameter() { result = block.getPipelineParameter() } - - PipelineByPropertyNameParameter getAPipelineByPropertyNameParameter() { - result = block.getAPipelineByPropertyNameParameter() - } + ScriptBlockCfgNode getScriptBlock() { result.getProcessBlock() = this } } -private class StmtBlockChildMapping extends NonExprChildMapping, StmtBlock { - override predicate relevantChild(Ast n) { n = this.getAStmt() or n = this.getAnElement() } -} +module ExprNodes { + private class ArrayExprChildMapping extends ExprChildMapping, ArrayExpr { + override predicate relevantChild(Ast child) { + child = this.getAnExpr() + or + child = this.getStmtBlock() + } + } -class StmtBlockCfgNode extends AstCfgNode { - StmtBlockChildMapping block; + class ArrayExprCfgNode extends ExprCfgNode { + override string getAPrimaryQlClass() { result = "ArrayExprCfgNode" } - StmtBlockCfgNode() { this.getAstNode() = block } + override ArrayExprChildMapping e; - StmtBlock getBlock() { result = block } + override ArrayExpr getExpr() { result = e } - StmtCfgNode getStmt(int i) { block.hasCfgChild(block.getStmt(i), this, result) } + ExprCfgNode getExpr(int i) { e.hasCfgChild(e.getExpr(i), this, result) } - StmtCfgNode getAStmt() { block.hasCfgChild(block.getAStmt(), this, result) } + ExprCfgNode getAnExpr() { result = this.getExpr(_) } - /** Gets an AST element that may be returned from this `StmtBlockCfgNode`. */ - AstCfgNode getAnElement() { block.hasCfgChild(block.getAnElement(), this, result) } -} + StmtCfgNode getStmtBlock() { e.hasCfgChild(e.getStmtBlock(), this, result) } + } -/** Provides classes for control-flow nodes that wrap AST expressions. */ -module ExprNodes { - private class VarAccessChildMapping extends ExprChildMapping, VarAccess { - override predicate relevantChild(Ast n) { none() } + private class ArrayLiteralChildMapping extends ExprChildMapping, ArrayLiteral { + override predicate relevantChild(Ast child) { child = this.getAnExpr() } } - class VarAccessCfgNode extends ExprCfgNode { - override string getAPrimaryQlClass() { result = "VarAccessCfgNode" } + class ArrayLiteralCfgNode extends ExprCfgNode { + override string getAPrimaryQlClass() { result = "ArrayLiteralCfgNode" } - override VarAccessChildMapping e; + override ArrayLiteralChildMapping e; - override VarAccess getExpr() { result = super.getExpr() } + override ArrayLiteral getExpr() { result = e } - Variable getVariable() { result = e.getVariable() } + ExprCfgNode getExpr(int i) { e.hasCfgChild(e.getExpr(i), this, result) } + + ExprCfgNode getAnExpr() { result = this.getExpr(_) } } - private class VarReadAccessChildMapping extends VarAccessChildMapping, VarReadAccess { } + private class ParenExprChildMapping extends ExprChildMapping, ParenExpr { + override predicate relevantChild(Ast child) { child = this.getExpr() } + } - class VarReadAccessCfgNode extends VarAccessCfgNode { - override string getAPrimaryQlClass() { result = "VarReadAccessCfgNode" } + class ParenExprCfgNode extends ExprCfgNode { + override string getAPrimaryQlClass() { result = "ParenExprCfgNode" } - override VarReadAccessChildMapping e; + override ParenExprChildMapping e; + + override ParenExpr getExpr() { result = e } - override VarReadAccess getExpr() { result = super.getExpr() } + ExprCfgNode getSubExpr() { e.hasCfgChild(e.getExpr(), this, result) } } - private class VarWriteAccessChildMapping extends VarAccessChildMapping, VarWriteAccess { } + private class BinaryExprChildMapping extends ExprChildMapping, BinaryExpr { + override predicate relevantChild(Ast child) { + child = this.getLeft() + or + child = this.getRight() + } + } - class VarWriteAccessCfgNode extends VarAccessCfgNode { - override string getAPrimaryQlClass() { result = "VarWriteAccessCfgNode" } + class BinaryExprCfgNode extends ExprCfgNode { + override string getAPrimaryQlClass() { result = "BinaryExprCfgNode" } - override VarWriteAccessChildMapping e; + override BinaryExprChildMapping e; - override VarWriteAccess getExpr() { result = super.getExpr() } + override BinaryExpr getExpr() { result = e } - predicate isExplicitWrite(StmtNodes::AssignStmtCfgNode assignment) { - this = assignment.getLeftHandSide() - } + ExprCfgNode getLeft() { e.hasCfgChild(e.getLeft(), this, result) } - predicate isImplicitWrite() { e.isImplicit() } + ExprCfgNode getRight() { e.hasCfgChild(e.getRight(), this, result) } } - /** A control-flow node that wraps an argument expression. */ - class ArgumentCfgNode extends ExprCfgNode { - override string getAPrimaryQlClass() { result = "ArgumentCfgNode" } + private class UnaryExprChildMapping extends ExprChildMapping, UnaryExpr { + override predicate relevantChild(Ast child) { child = this.getOperand() } + } - override Argument e; + class UnaryExprCfgNode extends ExprCfgNode { + override string getAPrimaryQlClass() { result = "UnaryExprCfgNode" } - final override Argument getExpr() { result = super.getExpr() } + override UnaryExprChildMapping e; - /** Gets the position of this argument, if any. */ - int getPosition() { result = e.getPosition() } + override UnaryExpr getExpr() { result = e } - /** Gets the name of this argument, if any. */ - string getName() { result = e.getName() } + ExprCfgNode getOperand() { e.hasCfgChild(e.getOperand(), this, result) } + } - /** Holds if `this` is a qualifier to a call. */ - predicate isQualifier() { e.isQualifier() } + class ConstExprChildMapping extends ExprChildMapping, ConstExpr { + override predicate relevantChild(Ast child) { none() } + } + + class ConstExprCfgNode extends ExprCfgNode { + override string getAPrimaryQlClass() { result = "ConstExprCfgNode" } + + override ConstExprChildMapping e; - /** Gets the call for which this is an argument. */ - CallCfgNode getCall() { result.getAnArgument() = this or result.getQualifier() = this } + override ConstExpr getExpr() { result = e } } - private class InvokeMemberChildMapping extends ExprChildMapping, InvokeMemberExpr { - override predicate relevantChild(Ast n) { n = this.getQualifier() or n = this.getAnArgument() } + class ConvertExprChildMapping extends ExprChildMapping, ConvertExpr { + override predicate relevantChild(Ast child) { child = this.getExpr() } } - /** A control-flow node that wraps an `InvokeMemberExpr` expression. */ - class InvokeMemberCfgNode extends ExprCfgNode, AbstractCallCfgNode { - override string getAPrimaryQlClass() { result = "InvokeMemberCfgNode" } + class ConvertExprCfgNode extends ExprCfgNode { + override string getAPrimaryQlClass() { result = "ConvertExprCfgNode" } + + override ConvertExprChildMapping e; - override InvokeMemberChildMapping e; + override ConvertExpr getExpr() { result = e } - override InvokeMemberExpr getExpr() { result = super.getExpr() } + ExprCfgNode getSubExpr() { e.hasCfgChild(e.getExpr(), this, result) } + } - final override ExprCfgNode getQualifier() { e.hasCfgChild(e.getQualifier(), this, result) } + class IndexExprChildMapping extends ExprChildMapping, IndexExpr { + override predicate relevantChild(Ast child) { + child = this.getBase() + or + child = this.getIndex() + } + } - final override ExprCfgNode getArgument(int i) { e.hasCfgChild(e.getArgument(i), this, result) } + class IndexExprCfgNode extends ExprCfgNode { + override string getAPrimaryQlClass() { result = "IndexExprCfgNode" } - final override ExprCfgNode getPositionalArgument(int i) { result = this.getArgument(i) } + override IndexExprChildMapping e; - final override ExprCfgNode getNamedArgument(string name) { none() } + override IndexExpr getExpr() { result = e } - final override ExprCfgNode getAnArgument() { e.hasCfgChild(e.getAnArgument(), this, result) } + ExprCfgNode getBase() { e.hasCfgChild(e.getBase(), this, result) } - final override string getName() { result = e.getName() } + ExprCfgNode getIndex() { e.hasCfgChild(e.getIndex(), this, result) } + } - final override ExprCfgNode getCommand() { none() } + private class IndexExprWriteAccessChildMapping extends IndexExprChildMapping, IndexExprWriteAccess + { + override predicate relevantChild(Ast child) { + super.relevantChild(child) or + this.isExplicitWrite(child) + } } - /** A control-flow node that wraps an `ConstructorCall` expression. */ - class ConstructorCallCfgNode extends InvokeMemberCfgNode { - ConstructorCallCfgNode() { super.getExpr() instanceof ConstructorCall } + class IndexExprWriteAccessCfgNode extends IndexExprCfgNode { + override IndexExprWriteAccessChildMapping e; + + override string getAPrimaryQlClass() { result = "IndexExprWriteAccessCfgNode" } - final override ConstructorCall getExpr() { result = super.getExpr() } + override IndexExprWriteAccess getExpr() { result = e } - Type getConstructedType() { result = this.getExpr().getConstructedType() } + final StmtNodes::AssignStmtCfgNode getAssignStmt() { this.isExplicitWrite(result) } + + predicate isExplicitWrite(AstCfgNode assignmentCfg) { + exists(Ast assignment | + // this.isExplicitWrite(assignment) and + e.isExplicitWrite(assignment) and + e.hasCfgChild(assignment, this, assignmentCfg) + ) + } + + predicate isImplicitWrite() { e.isImplicitWrite() } } - /** A control-flow node that wraps a qualifier expression. */ - class QualifierCfgNode extends ExprCfgNode { - QualifierCfgNode() { this = any(InvokeMemberCfgNode invoke).getQualifier() } + private class IndexExprReadAccessChildMapping extends IndexExprChildMapping, IndexExprReadAccess { + override predicate relevantChild(Ast child) { super.relevantChild(child) } + } + + class IndexExprReadAccessCfgNode extends IndexExprCfgNode { + override IndexExprReadAccessChildMapping e; - InvokeMemberCfgNode getInvokeMember() { this = result.getQualifier() } + override string getAPrimaryQlClass() { result = "IndexExprAccessCfgNode" } + + override IndexExprReadAccess getExpr() { result = e } } - class TypeNameChildMapping extends ExprChildMapping, TypeNameExpr { - override predicate relevantChild(Ast n) { none() } + class CallExprChildMapping extends ExprChildMapping, CallExpr { + override predicate relevantChild(Ast child) { + child = this.getQualifier() + or + child = this.getAnArgument() + or + child = this.getCallee() + } } - /** A control-flow node that wraps a `TypeName` expression. */ - class TypeNameCfgNode extends ExprCfgNode { - override string getAPrimaryQlClass() { result = "TypeNameCfgNode" } + class CallExprCfgNode extends ExprCfgNode { + override string getAPrimaryQlClass() { result = "CallExprCfgNode" } + + override CallExprChildMapping e; + + override CallExpr getExpr() { result = e } - override TypeNameChildMapping e; + ExprCfgNode getQualifier() { e.hasCfgChild(e.getQualifier(), this, result) } - override TypeNameExpr getExpr() { result = super.getExpr() } + ExprCfgNode getArgument(int i) { e.hasCfgChild(e.getArgument(i), this, result) } + + ExprCfgNode getAnArgument() { result = this.getArgument(_) } + + /** Gets the name that is used to select the callee. */ + string getName() { result = e.getName() } + + predicate hasName(string name) { this.getName() = name } + + /** Gets the i'th positional argument to this call. */ + ExprCfgNode getPositionalArgument(int i) { + e.hasCfgChild(e.getPositionalArgument(i), this, result) + } + + /** Holds if an argument with name `name` is provided to this call. */ + final predicate hasNamedArgument(string name) { exists(this.getNamedArgument(name)) } + + /** Gets the argument to this call with the name `name`. */ + ExprCfgNode getNamedArgument(string name) { + e.hasCfgChild(e.getNamedArgument(name), this, result) + } - Type getType() { result = this.getExpr().getType() } + ExprCfgNode getCallee() { e.hasCfgChild(e.getCallee(), this, result) } - string getTypeName() { result = this.getExpr().getName() } + predicate isStatic() { this.getExpr().isStatic() } } - class ConditionalChildMapping extends ExprChildMapping, ConditionalExpr { - override predicate relevantChild(Ast n) { n = this.getCondition() or n = this.getABranch() } + class ObjectCreationChildMapping extends CallExprChildMapping instanceof ObjectCreation { + override predicate relevantChild(Ast child) { child = super.getConstructedTypeExpr() } } - /** A control-flow node that wraps a `ConditionalExpr` expression. */ - class ConditionalCfgNode extends ExprCfgNode { - override string getAPrimaryQlClass() { result = "ConditionalCfgNode" } + class ObjectCreationCfgNode extends CallExprCfgNode { + // TODO: Also calls to Activator.CreateInstance + override string getAPrimaryQlClass() { result = "CallExprCfgNode" } - override ConditionalChildMapping e; + override ObjectCreationChildMapping e; - final override ConditionalExpr getExpr() { result = super.getExpr() } + override ObjectCreation getExpr() { result = e } - final ExprCfgNode getCondition() { e.hasCfgChild(e.getCondition(), this, result) } + string getConstructedTypeName() { result = this.getExpr().getConstructedTypeName() } - final ExprCfgNode getBranch(boolean value) { e.hasCfgChild(e.getBranch(value), this, result) } + ExprCfgNode getConstructedTypeExpr() { + e.hasCfgChild(this.getExpr().getConstructedTypeExpr(), this, result) + } + } + + class CallOperatorChildMapping extends CallExprChildMapping instanceof CallOperator { + override predicate relevantChild(Ast child) { none() } + } - final ExprCfgNode getABranch() { result = this.getBranch(_) } + class CallOperatorCfgNode extends CallExprCfgNode { + override string getAPrimaryQlClass() { result = "CallOperatorCfgNode" } - final ExprCfgNode getIfTrue() { e.hasCfgChild(e.getIfTrue(), this, result) } + override CallOperatorChildMapping e; - final ExprCfgNode getIfFalse() { e.hasCfgChild(e.getIfFalse(), this, result) } + override CallOperator getExpr() { result = e } + + ExprCfgNode getCommand() { result = this.getArgument(0) } } - class MemberChildMapping extends ExprChildMapping, MemberExpr { - override predicate relevantChild(Ast n) { n = this.getQualifier() or n = this.getMember() } + class MemberExprChildMapping extends ExprChildMapping, MemberExpr { + override predicate relevantChild(Ast child) { + child = this.getQualifier() + or + child = this.getMemberExpr() + } } - /** A control-flow node that wraps a `MemberExpr` expression. */ - class MemberCfgNode extends ExprCfgNode { - override string getAPrimaryQlClass() { result = "MemberCfgNode" } + class MemberExprCfgNode extends ExprCfgNode { + override string getAPrimaryQlClass() { result = "MemberExprCfgNode" } + + override MemberExprChildMapping e; - override MemberChildMapping e; + override MemberExpr getExpr() { result = e } - final override MemberExpr getExpr() { result = super.getExpr() } + ExprCfgNode getQualifier() { e.hasCfgChild(e.getQualifier(), this, result) } - final ExprCfgNode getQualifier() { e.hasCfgChild(e.getQualifier(), this, result) } + ExprCfgNode getMemberExpr() { e.hasCfgChild(e.getMemberExpr(), this, result) } - final string getMemberName() { result = e.getMemberName() } + string getMemberName() { result = e.getMemberName() } predicate isStatic() { e.isStatic() } } - /** A control-flow node that wraps a `MemberExpr` expression that is being written to. */ - class MemberCfgWriteAccessNode extends MemberCfgNode { - MemberCfgWriteAccessNode() { this.getExpr() instanceof MemberExprWriteAccess } + private class MemberExprWriteAccessChildMapping extends MemberExprChildMapping, + MemberExprWriteAccess + { + override predicate relevantChild(Ast child) { + super.relevantChild(child) or + this.isExplicitWrite(child) + } + } + + class MemberExprWriteAccessCfgNode extends MemberExprCfgNode { + override MemberExprWriteAccessChildMapping e; + + override string getAPrimaryQlClass() { result = "MemberExprWriteAccessCfgNode" } - StmtNodes::AssignStmtCfgNode getAssignStmt() { result.getLeftHandSide() = this } + override MemberExprWriteAccess getExpr() { result = e } + + final StmtNodes::AssignStmtCfgNode getAssignStmt() { this.isExplicitWrite(result) } + + predicate isExplicitWrite(AstCfgNode assignmentCfg) { + exists(Ast assignment | + // this.isExplicitWrite(assignment) and + e.isExplicitWrite(assignment) and + e.hasCfgChild(assignment, this, assignmentCfg) + ) + } + + predicate isImplicitWrite() { e.isImplicitWrite() } } - /** A control-flow node that wraps a `MemberExpr` expression that is being read from. */ - class MemberCfgReadAccessNode extends MemberCfgNode { - MemberCfgReadAccessNode() { this.getExpr() instanceof MemberExprReadAccess } + private class MemberExprReadAccessChildMapping extends MemberExprChildMapping, + MemberExprReadAccess + { + override predicate relevantChild(Ast child) { super.relevantChild(child) } } - class ArrayLiteralChildMapping extends ExprChildMapping, ArrayLiteral { - override predicate relevantChild(Ast n) { n = this.getAnElement() } + class MemberExprReadAccessCfgNode extends MemberExprCfgNode { + override MemberExprReadAccessChildMapping e; + + override string getAPrimaryQlClass() { result = "MemberExprReadAccessCfgNode" } + + override MemberExprReadAccess getExpr() { result = e } } - class ArrayLiteralCfgNode extends ExprCfgNode { - override string getAPrimaryQlClass() { result = "ArrayLiteralCfgNode" } + class TypeNameExprChildMapping extends ExprChildMapping, TypeNameExpr { + override predicate relevantChild(Ast child) { none() } + } - override ArrayLiteralChildMapping e; + class TypeNameExprCfgNode extends ExprCfgNode { + override string getAPrimaryQlClass() { result = "TypeExprCfgNode" } + + override TypeNameExprChildMapping e; + + override TypeNameExpr getExpr() { result = e } + + string getName() { result = e.getName() } + + string getNamespace() { result = e.getNamespace() } - ExprCfgNode getElement(int i) { e.hasCfgChild(e.getElement(i), this, result) } + string getPossiblyQualifiedName() { result = e.getPossiblyQualifiedName() } - ExprCfgNode getAnElement() { e.hasCfgChild(e.getAnElement(), this, result) } + predicate isQualified() { e.isQualified() } } - class IndexChildMapping extends ExprChildMapping, IndexExpr { - override predicate relevantChild(Ast n) { n = this.getBase() or n = this.getIndex() } + class QualifiedTypeNameExprCfgNode extends TypeNameExprCfgNode { + QualifiedTypeNameExprCfgNode() { e.isQualified() } + + override string getAPrimaryQlClass() { result = "QualifiedTypeNameExprCfgNode" } + + override QualifiedTypeNameExpr getExpr() { result = e } } - /** A control-flow node that wraps a `MemberExpr` expression. */ - class IndexCfgNode extends ExprCfgNode { - override string getAPrimaryQlClass() { result = "IndexCfgNode" } + class ErrorExprChildMapping extends ExprChildMapping, ErrorExpr { + override predicate relevantChild(Ast child) { none() } + } - override IndexChildMapping e; + class ErrorExprCfgNode extends ExprCfgNode { + override string getAPrimaryQlClass() { result = "ErrorExprCfgNode" } - final ExprCfgNode getBase() { e.hasCfgChild(e.getBase(), this, result) } + override ErrorExprChildMapping e; - final ExprCfgNode getIndex() { e.hasCfgChild(e.getIndex(), this, result) } + override ErrorExpr getExpr() { result = e } } - /** A control-flow node that wraps a `MemberExpr` expression that is being written to. */ - class IndexCfgWriteNode extends IndexCfgNode { - IndexCfgWriteNode() { this.getExpr() instanceof IndexExprWrite } + class ScriptBlockExprChildMapping extends ExprChildMapping, ScriptBlockExpr { + override predicate relevantChild(Ast child) { child = this.getBody() } + } + + class ScriptBlockExprCfgNode extends ExprCfgNode { + override string getAPrimaryQlClass() { result = "ScriptBlockExprCfgNode" } + + override ScriptBlockExprChildMapping e; + + override ScriptBlockExpr getExpr() { result = e } - StmtNodes::AssignStmtCfgNode getAssignStmt() { result.getLeftHandSide() = this } + ScriptBlockCfgNode getBody() { e.hasCfgChild(e.getBody(), this, result) } } - /** A control-flow node that wraps a `MemberExpr` expression that is being read from. */ - class IndexCfgReadNode extends IndexCfgNode { - IndexCfgReadNode() { this.getExpr() instanceof IndexExprRead } + class StringLiteralExprChildMapping extends ExprChildMapping, StringConstExpr { + override predicate relevantChild(Ast child) { none() } } - class ArrayExprChildMapping extends ExprChildMapping, ArrayExpr { - override predicate relevantChild(Ast n) { n = this.getStmtBlock() or n = this.getAnElement() } + class StringLiteralExprCfgNode extends ExprCfgNode { + override string getAPrimaryQlClass() { result = "StringLiteralExprCfgNode" } + + override StringLiteralExprChildMapping e; + + override StringConstExpr getExpr() { result = e } + + string getValueString() { result = e.getValueString() } } - class ArrayExprCfgNode extends ExprCfgNode { - override string getAPrimaryQlClass() { result = "ArrayExprCfgNode" } + class ExpandableStringExprChildMapping extends ExprChildMapping, ExpandableStringExpr { + override predicate relevantChild(Ast child) { child = this.getAnExpr() } + } - override ArrayExprChildMapping e; + class ExpandableStringExprCfgNode extends ExprCfgNode { + override string getAPrimaryQlClass() { result = "ExpandableStringExprCfgNode" } - ExprCfgNode getElement(int i) { e.hasCfgChild(e.getElement(i), this, result) } + override ExpandableStringExprChildMapping e; - ExprCfgNode getAnElement() { result = this.getElement(_) } + override ExpandableStringExpr getExpr() { result = e } + + ExprCfgNode getExpr(int i) { e.hasCfgChild(e.getExpr(i), this, result) } - StmtBlockCfgNode getStmtBlock() { e.hasCfgChild(e.getStmtBlock(), this, result) } + ExprCfgNode getAnExpr() { result = this.getExpr(_) } } - class HashTableChildMapping extends ExprChildMapping, HashTableExpr { - override predicate relevantChild(Ast n) { this.hasEntry(_, _, n) or this.hasEntry(_, n, _) } + class VarAccessCfgNode extends ExprCfgNode { + override string getAPrimaryQlClass() { result = "VarAccessExprCfgNode" } + + override VarAccess e; + + override VarAccess getExpr() { result = e } + + Variable getVariable() { result = e.getVariable() } + } + + private class VarWriteAccessChildMapping extends ExprChildMapping, VarWriteAccess { + override predicate relevantChild(Ast child) { this.isExplicitWrite(child) } } - class HashTableCfgNode extends ExprCfgNode { - override string getAPrimaryQlClass() { result = "HashMapCfgNode" } + class VarWriteAccessCfgNode extends VarAccessCfgNode { + override VarWriteAccessChildMapping e; + + override string getAPrimaryQlClass() { result = "VarWriteAccessCfgNode" } - override HashTableChildMapping e; + override VarWriteAccess getExpr() { result = e } - override HashTableExpr getExpr() { result = super.getExpr() } + final StmtNodes::AssignStmtCfgNode getAssignStmt() { this.isExplicitWrite(result) } - StmtCfgNode getElement(ExprCfgNode key) { - exists(Expr eKey | - eKey = key.getAstNode() and - e.hasCfgChild(eKey, this, key) and - e.hasCfgChild(e.getElement(eKey), this, result) + predicate isExplicitWrite(AstCfgNode assignmentCfg) { + exists(Ast assignment | + e.isExplicitWrite(assignment) and + e.hasCfgChild(assignment, this, assignmentCfg) ) } - predicate hasKey(ExprCfgNode key) { exists(this.getElement(key)) } + predicate isImplicitWrite() { e.isImplicitWrite() } + } + + class VarReadAccessCfgNode extends VarAccessCfgNode { + override VarReadAccess e; + + override string getAPrimaryQlClass() { result = "VarReadAccessCfgNode" } + + override VarReadAccess getExpr() { result = e } + } + + class HashTableExprChildMapping extends ExprChildMapping, HashTableExpr { + override predicate relevantChild(Ast child) { + child = this.getAKey() + or + child = this.getAValue() + } + } + + class HashTableExprCfgNode extends ExprCfgNode { + override string getAPrimaryQlClass() { result = "HashTableExprCfgNode" } + + override HashTableExprChildMapping e; - StmtCfgNode getAnElement() { result = this.getElement(_) } + override HashTableExpr getExpr() { result = e } - predicate hasEntry(int index, ExprCfgNode key, StmtCfgNode value) { - exists(Expr eKey, Stmt sValue | - e.hasCfgChild(eKey, this, key) and - e.hasCfgChild(sValue, this, value) and - e.hasEntry(index, eKey, sValue) + ExprCfgNode getKey(int i) { e.hasCfgChild(e.getKey(i), this, result) } + + ExprCfgNode getAnKey() { result = this.getKey(_) } + + ExprCfgNode getValue(int i) { e.hasCfgChild(e.getKey(i), this, result) } + + ExprCfgNode getValueFromKey(ExprCfgNode key) { + exists(int i | + this.getKey(i) = key and + result = this.getValue(i) ) } + + ExprCfgNode getAValue() { result = this.getValue(_) } } - class ConvertExprChildMapping extends ExprChildMapping, ConvertExpr { - override predicate relevantChild(Ast n) { n = this.getBase() } + class PipelineChildMapping extends ExprChildMapping, Pipeline { + override predicate relevantChild(Ast child) { child = this.getAComponent() } } - class ConvertCfgNode extends ExprCfgNode { - override string getAPrimaryQlClass() { result = "ConvertCfgNode" } + class PipelineCfgNode extends ExprCfgNode { + override string getAPrimaryQlClass() { result = "PipelineCfgNode" } - override ConvertExprChildMapping e; + override PipelineChildMapping e; - override ConvertExpr getExpr() { result = e } + override Pipeline getExpr() { result = e } - final ExprCfgNode getBase() { e.hasCfgChild(e.getBase(), this, result) } + ExprCfgNode getComponent(int i) { e.hasCfgChild(e.getComponent(i), this, result) } - TypeConstraint getType() { result = e.getType() } + ExprCfgNode getAComponent() { result = this.getComponent(_) } } - class ParenExprChildMapping extends ExprChildMapping, ParenExpr { - override predicate relevantChild(Ast n) { n = this.getBase() } + class PipelineChainChildMapping extends ExprChildMapping, PipelineChain { + override predicate relevantChild(Ast child) { + child = this.getLeft() or child = this.getRight() + } } - class ParenCfgNode extends ExprCfgNode { - override string getAPrimaryQlClass() { result = "ParenExprCfgNode" } + class PipelineChainCfgNode extends ExprCfgNode { + override string getAPrimaryQlClass() { result = "PipelineChainCfgNode" } - override ParenExprChildMapping e; + override PipelineChainChildMapping e; - override ParenExpr getExpr() { result = e } + override PipelineChain getExpr() { result = e } - final StmtCfgNode getBase() { e.hasCfgChild(e.getBase(), this, result) } + ExprCfgNode getLeft() { e.hasCfgChild(e.getLeft(), this, result) } + + ExprCfgNode getRight() { e.hasCfgChild(e.getRight(), this, result) } } - class UnaryExprChildMapping extends ExprChildMapping, UnaryExpr { - override predicate relevantChild(Ast n) { n = this.getOperand() } + class ConditionalExprChildMapping extends ExprChildMapping, ConditionalExpr { + override predicate relevantChild(Ast child) { + child = this.getCondition() + or + child = this.getIfTrue() + or + child = this.getIfFalse() + } } - class UnaryCfgNode extends ExprCfgNode { - override string getAPrimaryQlClass() { result = "UnaryExprCfgNode" } + class ConditionalExprCfgNode extends ExprCfgNode { + override string getAPrimaryQlClass() { result = "ConditionalExprCfgNode" } - override UnaryExprChildMapping e; + override ConditionalExprChildMapping e; - override UnaryExpr getExpr() { result = e } + override ConditionalExpr getExpr() { result = e } + + ExprCfgNode getCondition() { e.hasCfgChild(e.getCondition(), this, result) } + + ExprCfgNode getIfTrue() { e.hasCfgChild(e.getIfTrue(), this, result) } - final ExprCfgNode getOperand() { e.hasCfgChild(e.getOperand(), this, result) } + ExprCfgNode getIfFalse() { e.hasCfgChild(e.getIfFalse(), this, result) } + + ExprCfgNode getBranch(boolean b) { + b = true and + result = this.getIfTrue() + or + b = false and + result = this.getIfFalse() + } + + ExprCfgNode getABranch() { result = this.getBranch(_) } } - class BinaryExprChildMapping extends ExprChildMapping, BinaryExpr { - override predicate relevantChild(Ast n) { n = this.getLeft() or n = this.getRight() } + class ExpandableSubExprChildMapping extends ExprChildMapping, ExpandableSubExpr { + override predicate relevantChild(Ast child) { child = this.getExpr() } } - class BinaryCfgNode extends ExprCfgNode { - override string getAPrimaryQlClass() { result = "BinaryExprCfgNode" } + class ExpandableSubExprCfgNode extends ExprCfgNode { + override string getAPrimaryQlClass() { result = "ExpandableSubExprCfgNode" } - override BinaryExprChildMapping e; + override ExpandableSubExprChildMapping e; - override BinaryExpr getExpr() { result = e } + override ExpandableSubExpr getExpr() { result = e } + + ExprCfgNode getSubExpr() { e.hasCfgChild(e.getExpr(), this, result) } + } + + class UsingExprChildMapping extends ExprChildMapping, UsingExpr { + override predicate relevantChild(Ast child) { child = this.getExpr() } + } + + class UsingExprCfgNode extends ExprCfgNode { + override string getAPrimaryQlClass() { result = "UsingExprCfgNode" } + + override UsingExprChildMapping e; + + override UsingExpr getExpr() { result = e } + + ExprCfgNode getSubExpr() { e.hasCfgChild(e.getExpr(), this, result) } + } + + class AttributedExprChildMapping extends ExprChildMapping, AttributedExpr { + override predicate relevantChild(Ast child) { + child = this.getExpr() or + child = this.getAttribute() + } + } + + class AttributedExprCfgNode extends ExprCfgNode { + override string getAPrimaryQlClass() { result = "TAttributedExprCfgNode" } + + override AttributedExprChildMapping e; + + override AttributedExpr getExpr() { result = e } + + ExprCfgNode getSubExpr() { e.hasCfgChild(e.getExpr(), this, result) } + + ExprCfgNode getAttribute() { e.hasCfgChild(e.getAttribute(), this, result) } + } + + class IfChildMapping extends ExprChildMapping, If { + override predicate relevantChild(Ast child) { + child = this.getACondition() + or + child = this.getAThen() + or + child = this.getElse() + } + } + + class IfCfgNode extends ExprCfgNode { + override string getAPrimaryQlClass() { result = "IfCfgNode" } + + override IfChildMapping e; + + override If getExpr() { result = e } + + ExprCfgNode getCondition(int i) { e.hasCfgChild(e.getCondition(i), this, result) } + + ExprCfgNode getACondition() { result = this.getCondition(_) } + + StmtCfgNode getThen(int i) { e.hasCfgChild(e.getThen(i), this, result) } + + StmtCfgNode getAThen() { result = this.getThen(_) } + + StmtCfgNode getElse() { e.hasCfgChild(e.getElse(), this, result) } + } + + class LiteralChildMapping extends ExprChildMapping, Literal { + override predicate relevantChild(Ast child) { none() } + } + + class LiteralCfgNode extends ExprCfgNode { + override string getAPrimaryQlClass() { result = "LiteralCfgNode" } + + override LiteralChildMapping e; + + override Literal getExpr() { result = e } + } + + class BoolLiteralChildMapping extends ExprChildMapping, BoolLiteral { + override predicate relevantChild(Ast child) { none() } + } + + class BoolLiteralCfgNode extends ExprCfgNode { + override string getAPrimaryQlClass() { result = "BoolLiteralCfgNode" } + + override BoolLiteralChildMapping e; + + override BoolLiteral getExpr() { result = e } + } + + class NullLiteralChildMapping extends ExprChildMapping, NullLiteral { + override predicate relevantChild(Ast child) { none() } + } + + class NullLiteralCfgNode extends ExprCfgNode { + override string getAPrimaryQlClass() { result = "NullLiteralCfgNode" } - final ExprCfgNode getLeft() { e.hasCfgChild(e.getLeft(), this, result) } + override NullLiteralChildMapping e; - final ExprCfgNode getRight() { e.hasCfgChild(e.getRight(), this, result) } + override NullLiteral getExpr() { result = e } } - class OperationChildMapping extends ExprChildMapping instanceof Operation { - override predicate relevantChild(Ast n) { n = super.getAnOperand() } + class ArgumentCfgNode extends ExprCfgNode { + override Argument e; + + CallExprCfgNode getCall() { result.getAnArgument() = this } + + string getName() { result = e.getName() } + + int getPosition() { result = e.getPosition() } + } + + class QualifierCfgNode extends ExprCfgNode { + override Qualifier e; + + CallExprCfgNode getCall() { result.getQualifier() = this } + } + + private class EnvVariableChildMapping extends ExprChildMapping, EnvVariable { + override predicate relevantChild(Ast child) { none() } + } + + class EnvVariableCfgNode extends ExprCfgNode { + override string getAPrimaryQlClass() { result = "EnvVariableCfgNode" } + + override EnvVariableChildMapping e; + + override EnvVariable getExpr() { result = e } + + string getName() { result = e.getName() } + } + + private class OperationChildMapping extends ExprChildMapping, Operation { + override predicate relevantChild(Ast child) { child = this.getAnOperand() } } class OperationCfgNode extends ExprCfgNode { @@ -563,166 +979,421 @@ module ExprNodes { override Operation getExpr() { result = e } - final ExprCfgNode getAnOperand() { e.hasCfgChild(this.getExpr().getAnOperand(), this, result) } + ExprCfgNode getAnOperand() { e.hasCfgChild(e.getAnOperand(), this, result) } + } +} + +module StmtNodes { + private class AssignStmtChildMapping extends NonExprChildMapping, AssignStmt { + override predicate relevantChild(Ast child) { + child = this.getLeftHandSide() + or + child = this.getRightHandSide() + } } - class ExpandableStringChildMappinig extends ExprChildMapping, ExpandableStringExpr { - override predicate relevantChild(Ast n) { n = this.getAnExpr() } + class AssignStmtCfgNode extends StmtCfgNode { + override string getAPrimaryQlClass() { result = "AssignStmtCfgNode" } + + override AssignStmtChildMapping s; + + override AssignStmt getStmt() { result = s } + + ExprCfgNode getLeftHandSide() { s.hasCfgChild(s.getLeftHandSide(), this, result) } + + ExprCfgNode getRightHandSide() { s.hasCfgChild(s.getRightHandSide(), this, result) } } - class ExpandableStringCfgNode extends ExprCfgNode { - override string getAPrimaryQlClass() { result = "ExpandableStringCfgNode" } + class BreakStmtChildMapping extends NonExprChildMapping, BreakStmt { + override predicate relevantChild(Ast child) { none() } + } - override ExpandableStringChildMappinig e; + class BreakStmtCfgNode extends StmtCfgNode { + override string getAPrimaryQlClass() { result = "BreakStmtCfgNode" } - override ExpandableStringExpr getExpr() { result = e } + override BreakStmtChildMapping s; - ExprCfgNode getExpr(int i) { e.hasCfgChild(e.getExpr(i), this, result) } + override BreakStmt getStmt() { result = s } + } - ExprCfgNode getAnExpr() { result = this.getExpr(_) } + class ContinueStmtChildMapping extends NonExprChildMapping, ContinueStmt { + override predicate relevantChild(Ast child) { none() } } -} -module StmtNodes { - private class CmdChildMapping extends CmdBaseChildMapping, Cmd { - override predicate relevantChild(Ast n) { n = this.getAnArgument() or n = this.getCommand() } + class ContinueStmtCfgNode extends StmtCfgNode { + override string getAPrimaryQlClass() { result = "ContinueStmtCfgNode" } + + override ContinueStmtChildMapping s; + + override ContinueStmt getStmt() { result = s } + } + + class DataStmtChildMapping extends NonExprChildMapping, DataStmt { + override predicate relevantChild(Ast child) { + child = this.getACmdAllowed() or child = this.getBody() + } + } + + class DataStmtCfgNode extends StmtCfgNode { + override string getAPrimaryQlClass() { result = "DataStmtCfgNode" } + + override DataStmtChildMapping s; + + override DataStmt getStmt() { result = s } + + ExprCfgNode getCmdAllowed(int i) { s.hasCfgChild(s.getCmdAllowed(i), this, result) } + + ExprCfgNode getACmdAllowed() { result = this.getCmdAllowed(_) } + + StmtCfgNode getBody() { s.hasCfgChild(s.getBody(), this, result) } } - /** A control-flow node that wraps a `Cmd` AST expression. */ - class CmdCfgNode extends CmdBaseCfgNode, AbstractCallCfgNode { - override string getAPrimaryQlClass() { result = "CmdCfgNode" } + class DoUntilStmtChildMapping extends NonExprChildMapping, DoUntilStmt { + override predicate relevantChild(Ast child) { + child = this.getCondition() or child = this.getBody() + } + } - override CmdChildMapping s; + class DoUntilStmtCfgNode extends StmtCfgNode { + override string getAPrimaryQlClass() { result = "DoUntilStmtCfgNode" } - override Cmd getStmt() { result = super.getStmt() } + override DoUntilStmtChildMapping s; - override ExprCfgNode getArgument(int i) { s.hasCfgChild(s.getArgument(i), this, result) } + override DoUntilStmt getStmt() { result = s } - override ExprCfgNode getPositionalArgument(int i) { - s.hasCfgChild(s.getPositionalArgument(i), this, result) + ExprCfgNode getCondition() { s.hasCfgChild(s.getCondition(), this, result) } + + StmtCfgNode getBody() { s.hasCfgChild(s.getBody(), this, result) } + } + + class DoWhileStmtChildMapping extends NonExprChildMapping, DoWhileStmt { + override predicate relevantChild(Ast child) { + child = this.getCondition() or child = this.getBody() } + } + + class DoWhileStmtCfgNode extends StmtCfgNode { + override string getAPrimaryQlClass() { result = "DoWhileStmtCfgNode" } + + override DoWhileStmtChildMapping s; + + override DoWhileStmt getStmt() { result = s } + + ExprCfgNode getCondition() { s.hasCfgChild(s.getCondition(), this, result) } + + StmtCfgNode getBody() { s.hasCfgChild(s.getBody(), this, result) } + } + + class ErrorStmtChildMapping extends NonExprChildMapping, ErrorStmt { + override predicate relevantChild(Ast child) { none() } + } - override ExprCfgNode getNamedArgument(string name) { - s.hasCfgChild(s.getNamedArgument(name), this, result) + class ErrorStmtCfgNode extends StmtCfgNode { + override string getAPrimaryQlClass() { result = "ErrorStmtCfgNode" } + + override ErrorStmtChildMapping s; + + override ErrorStmt getStmt() { result = s } + } + + class ExitStmtChildMapping extends NonExprChildMapping, ExitStmt { + override predicate relevantChild(Ast child) { child = this.getPipeline() } + } + + class ExitStmtCfgNode extends StmtCfgNode { + override string getAPrimaryQlClass() { result = "ExitStmtCfgNode" } + + override ExitStmtChildMapping s; + + override ExitStmt getStmt() { result = s } + + ExprCfgNode getPipeline() { s.hasCfgChild(s.getPipeline(), this, result) } + } + + class DynamicStmtChildMapping extends NonExprChildMapping, DynamicStmt { + override predicate relevantChild(Ast child) { + child = this.getName() or child = this.getScriptBlock() or child = this.getHashTableExpr() } + } + + class DynamicStmtCfgNode extends StmtCfgNode { + override string getAPrimaryQlClass() { result = "DynamicStmtCfgNode" } - override ExprCfgNode getAnArgument() { s.hasCfgChild(s.getAnArgument(), this, result) } + override DynamicStmtChildMapping s; - final override ExprCfgNode getCommand() { s.hasCfgChild(s.getCommand(), this, result) } + override DynamicStmt getStmt() { result = s } - final override string getName() { result = s.getCommandName() } + ExprCfgNode getName() { s.hasCfgChild(s.getName(), this, result) } - /** Holds if the command is qualified. */ - predicate isQualified() { s.isQualified() } + ExprCfgNode getScriptBlock() { s.hasCfgChild(s.getScriptBlock(), this, result) } - /** Gets the namespace qualifier of this command, if any. */ - string getNamespaceQualifier() { result = s.getNamespaceQualifier() } + ExprCfgNode getHashTableExpr() { s.hasCfgChild(s.getHashTableExpr(), this, result) } } - /** A control-flow node that wraps a call to operator `&` */ - class CallOperatorCfgNode extends CmdCfgNode { - CallOperatorCfgNode() { this.getStmt() instanceof CallOperator } + class ForEachStmtChildMapping extends NonExprChildMapping, ForEachStmt { + override predicate relevantChild(Ast child) { + child = this.getVarAccess() or child = this.getIterableExpr() or child = this.getBody() + } + } + + class ForEachStmtCfgNode extends StmtCfgNode { + override string getAPrimaryQlClass() { result = "ForEachStmtCfgNode" } + + override ForEachStmtChildMapping s; + + override ForEachStmt getStmt() { result = s } + + ExprCfgNode getVarAccess() { s.hasCfgChild(s.getVarAccess(), this, result) } + + ExprCfgNode getIterableExpr() { s.hasCfgChild(s.getIterableExpr(), this, result) } + + StmtCfgNode getBody() { s.hasCfgChild(s.getBody(), this, result) } } - private class AssignStmtChildMapping extends PipelineBaseChildMapping, AssignStmt { - override predicate relevantChild(Ast n) { - n = this.getLeftHandSide() or n = this.getRightHandSide() + class ForStmtChildMapping extends NonExprChildMapping, ForStmt { + override predicate relevantChild(Ast child) { + child = this.getInitializer() or + child = this.getCondition() or + child = this.getIterator() or + child = this.getBody() } } - /** A control-flow node that wraps an `AssignStmt` AST expression. */ - class AssignStmtCfgNode extends PipelineBaseCfgNode { - override string getAPrimaryQlClass() { result = "AssignCfgNode" } + class ForStmtCfgNode extends StmtCfgNode { + override string getAPrimaryQlClass() { result = "ForStmtCfgNode" } - override AssignStmtChildMapping s; + override ForStmtChildMapping s; + + override ForStmt getStmt() { result = s } + + AstCfgNode getInitializer() { s.hasCfgChild(s.getInitializer(), this, result) } - override AssignStmt getStmt() { result = super.getStmt() } + ExprCfgNode getCondition() { s.hasCfgChild(s.getCondition(), this, result) } - /** Gets the LHS of this assignment. */ - final ExprCfgNode getLeftHandSide() { s.hasCfgChild(s.getLeftHandSide(), this, result) } + AstCfgNode getIterator() { s.hasCfgChild(s.getIterator(), this, result) } - /** Gets the RHS of this assignment. */ - final StmtCfgNode getRightHandSide() { s.hasCfgChild(s.getRightHandSide(), this, result) } + StmtCfgNode getBody() { s.hasCfgChild(s.getBody(), this, result) } } - class CmdExprChildMapping extends CmdBaseChildMapping, CmdExpr { - override predicate relevantChild(Ast n) { n = this.getExpr() } + class GotoStmtChildMapping extends NonExprChildMapping, GotoStmt { + override predicate relevantChild(Ast child) { child = this.getLabel() } } - /** A control-flow node that wraps a `CmdExpr` expression. */ - class CmdExprCfgNode extends CmdBaseCfgNode { - override string getAPrimaryQlClass() { result = "CmdExprCfgNode" } + class GotoStmtCfgNode extends StmtCfgNode { + override string getAPrimaryQlClass() { result = "GotoStmtCfgNode" } - override CmdExprChildMapping s; + override GotoStmtChildMapping s; - override CmdExpr getStmt() { result = super.getStmt() } + override GotoStmt getStmt() { result = s } - final ExprCfgNode getExpr() { s.hasCfgChild(s.getExpr(), this, result) } + ExprCfgNode getLabel() { s.hasCfgChild(s.getLabel(), this, result) } } - class PipelineBaseChildMapping extends NonExprChildMapping, PipelineBase { - override predicate relevantChild(Ast n) { none() } + class ReturnStmtChildMapping extends NonExprChildMapping, ReturnStmt { + override predicate relevantChild(Ast child) { child = this.getPipeline() } } - class PipelineBaseCfgNode extends StmtCfgNode { - override string getAPrimaryQlClass() { result = "PipelineBaseCfgNode" } + class ReturnStmtCfgNode extends StmtCfgNode { + override string getAPrimaryQlClass() { result = "ReturnStmtCfgNode" } - override PipelineBaseChildMapping s; + override ReturnStmtChildMapping s; - override PipelineBase getStmt() { result = super.getStmt() } + override ReturnStmt getStmt() { result = s } + + ExprCfgNode getPipeline() { s.hasCfgChild(s.getPipeline(), this, result) } } - class ChainableChildMapping extends PipelineBaseChildMapping, Chainable { - override predicate relevantChild(Ast n) { none() } + class StmtBlockChildMapping extends NonExprChildMapping, StmtBlock { + override predicate relevantChild(Ast child) { child = this.getAStmt() } } - class ChainableCfgNode extends PipelineBaseCfgNode { - override string getAPrimaryQlClass() { result = "ChainableCfgNode" } + class StmtBlockCfgNode extends StmtCfgNode { + override string getAPrimaryQlClass() { result = "StmtBlockCfgNode" } + + override StmtBlockChildMapping s; + + override StmtBlock getStmt() { result = s } - override ChainableChildMapping s; + StmtCfgNode getStmt(int i) { s.hasCfgChild(s.getStmt(i), this, result) } - override Chainable getStmt() { result = super.getStmt() } + StmtCfgNode getAStmt() { result = this.getStmt(_) } } - class PipelineChainChildMapping extends ChainableChildMapping, PipelineChain { - override predicate relevantChild(Ast n) { n = this.getLeft() or n = this.getRight() } + class SwitchStmtChildMapping extends NonExprChildMapping, SwitchStmt { + override predicate relevantChild(Ast child) { + child = this.getCondition() or + child = this.getDefault() or + child = this.getACase() or + child = this.getAPattern() + } } - class PipelineChainCfgNode extends ChainableCfgNode { - override string getAPrimaryQlClass() { result = "PipelineChainCfgNode" } + class SwitchStmtCfgNode extends StmtCfgNode { + override string getAPrimaryQlClass() { result = "SwitchStmtCfgNode" } + + override SwitchStmtChildMapping s; + + override SwitchStmt getStmt() { result = s } - override PipelineChainChildMapping s; + ExprCfgNode getCondition() { s.hasCfgChild(s.getCondition(), this, result) } - override PipelineChain getStmt() { result = super.getStmt() } + StmtCfgNode getDefault() { s.hasCfgChild(s.getDefault(), this, result) } - final ChainableCfgNode getLeft() { s.hasCfgChild(s.getLeft(), this, result) } + StmtCfgNode getCase(int i) { s.hasCfgChild(s.getCase(i), this, result) } - final ChainableCfgNode getRight() { s.hasCfgChild(s.getRight(), this, result) } + StmtCfgNode getACase() { result = this.getCase(_) } + + ExprCfgNode getPattern(int i) { s.hasCfgChild(s.getPattern(i), this, result) } + + ExprCfgNode getAPattern() { result = this.getPattern(_) } } - class CmdBaseChildMapping extends ChainableChildMapping, CmdBase { } + class ThrowStmtChildMapping extends NonExprChildMapping, ThrowStmt { + override predicate relevantChild(Ast child) { child = this.getPipeline() } + } - class CmdBaseCfgNode extends ChainableCfgNode { - override string getAPrimaryQlClass() { result = "CmdBaseCfgNode" } + class ThrowStmtCfgNode extends StmtCfgNode { + override string getAPrimaryQlClass() { result = "ThrowStmtCfgNode" } - override CmdBaseChildMapping s; + override ThrowStmtChildMapping s; - override CmdBase getStmt() { result = super.getStmt() } + override ThrowStmt getStmt() { result = s } + + ExprCfgNode getPipeline() { s.hasCfgChild(s.getPipeline(), this, result) } } - class PipelineChildMapping extends ChainableChildMapping, Pipeline { - override predicate relevantChild(Ast n) { n = this.getAComponent() } + class TrapStmtChildMapping extends NonExprChildMapping, TrapStmt { + override predicate relevantChild(Ast child) { child = this.getBody() } } - class PipelineCfgNode extends ChainableCfgNode { - override string getAPrimaryQlClass() { result = "PipelineCfgNode" } + class TrapStmtCfgNode extends StmtCfgNode { + override string getAPrimaryQlClass() { result = "TrapStmtCfgNode" } + + override TrapStmtChildMapping s; + + override TrapStmt getStmt() { result = s } + + StmtCfgNode getBody() { s.hasCfgChild(s.getBody(), this, result) } + } + + class TryStmtChildMapping extends NonExprChildMapping, TryStmt { + override predicate relevantChild(Ast child) { + child = this.getBody() or + child = this.getFinally() or + child = this.getACatchClause() + } + } + + class TryStmtCfgNode extends StmtCfgNode { + override string getAPrimaryQlClass() { result = "TryStmtCfgNode" } + + override TryStmtChildMapping s; + + override TryStmt getStmt() { result = s } + + StmtCfgNode getBody() { s.hasCfgChild(s.getBody(), this, result) } + + StmtCfgNode getFinally() { s.hasCfgChild(s.getFinally(), this, result) } + + StmtCfgNode getCatchClause(int i) { s.hasCfgChild(s.getCatchClause(i), this, result) } + } + + class UsingStmtChildMapping extends NonExprChildMapping, UsingStmt { + override predicate relevantChild(Ast child) { none() } + } + + class UsingStmtCfgNode extends StmtCfgNode { + override string getAPrimaryQlClass() { result = "UsingStmtCfgNode" } + + override UsingStmtChildMapping s; + + override UsingStmt getStmt() { result = s } + } + + class WhileStmtChildMapping extends NonExprChildMapping, WhileStmt { + override predicate relevantChild(Ast child) { + child = this.getCondition() or + child = this.getBody() + } + } + + class WhileStmtCfgNode extends StmtCfgNode { + override string getAPrimaryQlClass() { result = "WhileStmtCfgNode" } + + override WhileStmtChildMapping s; + + override WhileStmt getStmt() { result = s } + + ExprCfgNode getCondition() { s.hasCfgChild(s.getCondition(), this, result) } + + StmtCfgNode getBody() { s.hasCfgChild(s.getBody(), this, result) } + } + + class ConfigurationChildMapping extends NonExprChildMapping, Configuration { + override predicate relevantChild(Ast child) { child = this.getName() or child = this.getBody() } + } + + class ConfigurationCfgNode extends StmtCfgNode { + override string getAPrimaryQlClass() { result = "ConfigurationCfgNode" } + + override ConfigurationChildMapping s; + + override Configuration getStmt() { result = s } + + ExprCfgNode getName() { s.hasCfgChild(s.getName(), this, result) } + + StmtCfgNode getBody() { s.hasCfgChild(s.getBody(), this, result) } + } + + class TypeStmtChildMapping extends NonExprChildMapping, TypeDefinitionStmt { + override predicate relevantChild(Ast child) { none() } + } + + class TypeDefinitionStmtCfgNode extends StmtCfgNode { + override string getAPrimaryQlClass() { result = "TypeStmtCfgNode" } + + override TypeStmtChildMapping s; + + override TypeDefinitionStmt getStmt() { result = s } + + Member getMember(int i) { result = s.getMember(i) } + + Member getAMember() { result = this.getMember(_) } + + TypeConstraint getBaseType(int i) { result = s.getBaseType(i) } + + TypeConstraint getABaseType() { result = this.getBaseType(_) } + + Type getType() { result = s.getType() } + + string getName() { result = s.getName() } + } + + class FunctionDefinitionChildMapping extends NonExprChildMapping, FunctionDefinitionStmt { + override predicate relevantChild(Ast child) { none() } + } + + class FunctionDefinitionCfgNode extends StmtCfgNode { + override string getAPrimaryQlClass() { result = "FunctionDefinitionCfgNode" } + + override FunctionDefinitionChildMapping s; + + override FunctionDefinitionStmt getStmt() { result = s } + + FunctionBase getFunction() { result = s.getFunction() } + } + + class ExprStmtChildMapping extends NonExprChildMapping, ExprStmt { + override predicate relevantChild(Ast child) { child = this.getExpr() } + } - override PipelineChildMapping s; + class ExprStmtCfgNode extends StmtCfgNode { + override string getAPrimaryQlClass() { result = "ExprStmtCfgNode" } - override Pipeline getStmt() { result = super.getStmt() } + override ExprStmtChildMapping s; - final CmdBaseCfgNode getComponent(int i) { s.hasCfgChild(s.getComponent(i), this, result) } + override ExprStmt getStmt() { result = s } - final CmdBaseCfgNode getAComponent() { s.hasCfgChild(s.getAComponent(), this, result) } + ExprCfgNode getExpr() { s.hasCfgChild(s.getExpr(), this, result) } } } diff --git a/powershell/ql/lib/semmle/code/powershell/controlflow/ControlFlowGraph.qll b/powershell/ql/lib/semmle/code/powershell/controlflow/ControlFlowGraph.qll index b986bafc9337..d8ec9bb88020 100644 --- a/powershell/ql/lib/semmle/code/powershell/controlflow/ControlFlowGraph.qll +++ b/powershell/ql/lib/semmle/code/powershell/controlflow/ControlFlowGraph.qll @@ -6,7 +6,6 @@ private import SuccessorTypes private import internal.ControlFlowGraphImpl as CfgImpl private import internal.Splitting as Splitting private import internal.Completion -private import internal.Scope /** * An AST node with an associated control-flow graph. @@ -16,7 +15,16 @@ private import internal.Scope * Note that module declarations are not themselves CFG scopes, as they are part of * the CFG of the enclosing top-level or callable. */ -class CfgScope extends Scope instanceof CfgImpl::CfgScope { } +class CfgScope extends Scope instanceof CfgImpl::CfgScope { + final CfgScope getOuterCfgScope() { + exists(Ast parent | + parent = this.getParent() and + result = CfgImpl::getCfgScope(parent) + ) + } + + Parameter getAParameter() { result = super.getAParameter() } +} /** * A control flow node. diff --git a/powershell/ql/lib/semmle/code/powershell/controlflow/internal/Completion.qll b/powershell/ql/lib/semmle/code/powershell/controlflow/internal/Completion.qll index 31669a955ab8..68b602dfd93e 100644 --- a/powershell/ql/lib/semmle/code/powershell/controlflow/internal/Completion.qll +++ b/powershell/ql/lib/semmle/code/powershell/controlflow/internal/Completion.qll @@ -22,9 +22,9 @@ private newtype TCompletion = TMatchingCompletion(Boolean b) or TEmptinessCompletion(Boolean isEmpty) -private predicate commandThrows(Cmd c, boolean unconditional) { - c.getNamedArgument("ErrorAction").(StringConstExpr).getValue().getValue() = "Stop" and - if c.getCommandName() = "Write-Error" then unconditional = true else unconditional = false +private predicate commandThrows(CallExpr c, boolean unconditional) { + c.getNamedArgument("ErrorAction").getValue().asString() = "Stop" and + if c.getName() = "Write-Error" then unconditional = true else unconditional = false } pragma[noinline] @@ -127,7 +127,7 @@ private predicate mustHaveMatchingCompletion(Ast n) { inMatchingContext(n) } * that `n` evaluates to determines a true/false branch successor. */ private predicate inBooleanContext(Ast n) { - n = any(IfStmt ifStmt).getACondition() + n = any(If ifStmt).getACondition() or n = any(WhileStmt whileStmt).getCondition() or @@ -165,10 +165,7 @@ private predicate inBooleanContext(Ast n) { n = pipeline.getComponent(pipeline.getNumberOfComponents() - 1) ) or - exists(CmdExpr cmdExpr | - inBooleanContext(cmdExpr) and - n = cmdExpr.getExpr() - ) + n = any(ParenExpr parent | inBooleanContext(parent)).getExpr() } /** diff --git a/powershell/ql/lib/semmle/code/powershell/controlflow/internal/ControlFlowGraphImpl.qll b/powershell/ql/lib/semmle/code/powershell/controlflow/internal/ControlFlowGraphImpl.qll index 909545088fa2..25d0773b0c07 100644 --- a/powershell/ql/lib/semmle/code/powershell/controlflow/internal/ControlFlowGraphImpl.qll +++ b/powershell/ql/lib/semmle/code/powershell/controlflow/internal/ControlFlowGraphImpl.qll @@ -8,6 +8,8 @@ private import codeql.controlflow.Cfg as CfgShared private import codeql.util.Boolean private import semmle.code.powershell.controlflow.ControlFlowGraph private import Completion +private import semmle.code.powershell.ast.internal.Raw.Raw as Raw +private import semmle.code.powershell.ast.internal.TAst private module CfgInput implements CfgShared::InputSig { private import ControlFlowGraphImpl as Impl @@ -51,11 +53,11 @@ private module CfgInput implements CfgShared::InputSig { t instanceof Cfg::SuccessorTypes::ExitSuccessor } - private predicate id(Ast node1, Ast node2) { node1 = node2 } + private predicate id(Raw::Ast node1, Raw::Ast node2) { node1 = node2 } - private predicate idOf(Ast node, int id) = equivalenceRelation(id/2)(node, id) + private predicate idOf(Raw::Ast node, int id) = equivalenceRelation(id/2)(node, id) - int idOfAstNode(AstNode node) { idOf(node, result) } + int idOfAstNode(AstNode node) { idOf(toRawIncludingSynth(node), result) } int idOfCfgScope(CfgScope node) { result = idOfAstNode(node) } } @@ -78,7 +80,7 @@ private module ConditionalCompletionSplittingInput implements import CfgShared::MakeWithSplitting -class CfgScope extends Scope { +class CfgScope extends ScriptBlock { predicate entry(Ast first) { first(this, first) } predicate exit(Ast last, Completion c) { last(this, last, c) } @@ -94,9 +96,24 @@ predicate succExit(CfgScope scope, Ast last, Completion c) { scope.exit(last, c) /** Defines the CFG by dispatch on the various AST types. */ module Trees { - class ParameterBlockTree extends StandardPostOrderTree instanceof ParamBlock { - override AstNode getChildNode(int i) { - exists(Parameter p | p = super.getParameter(i) | result = p.getDefaultValue()) + class ParameterTree extends ControlFlowTree instanceof Parameter { + final override predicate propagatesAbnormal(AstNode child) { child = super.getDefaultValue() } + + final override predicate first(AstNode first) { first = this } + + final override predicate last(AstNode last, Completion c) { + last(super.getDefaultValue(), last, c) and + completionIsNormal(c) + or + not super.hasDefaultValue() and + last = this and + completionIsSimple(c) + } + + final override predicate succ(AstNode pred, AstNode succ, Completion c) { + pred = this and + first(super.getDefaultValue(), succ) and + completionIsSimple(c) } } @@ -128,12 +145,6 @@ module Trees { not exists(super.getEndBlock()) and not exists(super.getProcessBlock()) and not exists(super.getBeginBlock()) and - last(super.getParamBlock(), last, c) - or - not exists(super.getEndBlock()) and - not exists(super.getProcessBlock()) and - not exists(super.getBeginBlock()) and - not exists(super.getParamBlock()) and // No blocks at all. We end where we started this.succEntry(last, c) } @@ -141,22 +152,28 @@ module Trees { override predicate succ(AstNode pred, AstNode succ, Completion c) { this.succEntry(pred, c) and ( - first(super.getParamBlock(), succ) + first(super.getParameter(0), succ) or - not exists(super.getParamBlock()) and + not exists(super.getAParameter()) and first(super.getBeginBlock(), succ) or - not exists(super.getParamBlock()) and + not exists(super.getAParameter()) and not exists(super.getBeginBlock()) and first(super.getProcessBlock(), succ) or - not exists(super.getParamBlock()) and + not exists(super.getAParameter()) and not exists(super.getBeginBlock()) and not exists(super.getProcessBlock()) and first(super.getEndBlock(), succ) ) or - last(super.getParamBlock(), pred, c) and + exists(int i | + last(super.getParameter(i), pred, c) and + completionIsNormal(c) and + first(super.getParameter(i + 1), succ) + ) + or + last(super.getParameter(super.getNumberOfParameters() - 1), pred, c) and completionIsNormal(c) and ( first(super.getBeginBlock(), succ) @@ -190,7 +207,7 @@ module Trees { } final override predicate propagatesAbnormal(AstNode child) { - child = super.getParamBlock() or + child = super.getAParameter() or child = super.getBeginBlock() or child = super.getProcessBlock() or child = super.getEndBlock() @@ -198,7 +215,7 @@ module Trees { } class FunctionScriptBlockTree extends PreOrderTree, ScriptBlockTree { - Function func; + FunctionBase func; FunctionScriptBlockTree() { func.getBody() = this } @@ -206,7 +223,7 @@ module Trees { exists(Parameter p | p = rank[i + 1](Parameter cand, int j | - cand.hasDefaultValue() and func.getFunctionParameter(j) = cand + cand.hasDefaultValue() and func.getParameter(j) = cand | cand order by j ) and @@ -478,13 +495,11 @@ module Trees { override AstNode getChildNode(int i) { i = 0 and result = super.getQualifier() or - i = 1 and result = super.getMember() + i = 1 and result = super.getMemberExpr() } } - class CmdParameterTree extends LeafTree instanceof CmdParameter { } - - class IfStmtTree extends PreOrderTree instanceof IfStmt { + class IfTree extends PostOrderTree instanceof If { final override predicate propagatesAbnormal(AstNode child) { child = super.getACondition() or @@ -493,17 +508,9 @@ module Trees { child = super.getElse() } - final override predicate last(AstNode last, Completion c) { - last(super.getAThen(), last, c) - or - last(super.getElse(), last, c) - } + final override predicate first(AstNode first) { first(super.getCondition(0), first) } final override predicate succ(AstNode pred, AstNode succ, Completion c) { - this = pred and - first(super.getCondition(0), succ) and - completionIsSimple(c) - or exists(int i, boolean value | last(super.getCondition(i), pred, c) and value = c.(BooleanCompletion).getValue() | @@ -515,9 +522,21 @@ module Trees { first(super.getCondition(i + 1), succ) or i = super.getNumberOfConditions() - 1 and - first(super.getElse(), succ) + ( + first(super.getElse(), succ) + or + not exists(super.getElse()) and + succ = this + ) ) ) + or + ( + last(super.getAThen(), pred, c) or + last(super.getElse(), pred, c) + ) and + completionIsNormal(c) and + succ = this } } @@ -592,6 +611,12 @@ module Trees { class VarAccessTree extends LeafTree instanceof VarAccess { } + class VarTree extends LeafTree instanceof Variable { } + + class EnvVariableTree extends LeafTree instanceof EnvVariable { } + + class AutomaticVariableTree extends LeafTree instanceof AutomaticVariable { } + class BinaryExprTree extends StandardPostOrderTree instanceof BinaryExpr { override AstNode getChildNode(int i) { i = 0 and result = super.getLeft() @@ -607,7 +632,7 @@ module Trees { class ScriptBlockExprTree extends LeafTree instanceof ScriptBlockExpr { } class ConvertExprTree extends StandardPostOrderTree instanceof ConvertExpr { - override AstNode getChildNode(int i) { i = 0 and result = super.getBase() } + override AstNode getChildNode(int i) { i = 0 and result = super.getExpr() } } class IndexExprTree extends StandardPostOrderTree instanceof IndexExpr { @@ -619,13 +644,13 @@ module Trees { } class ParenExprTree extends StandardPostOrderTree instanceof ParenExpr { - override AstNode getChildNode(int i) { i = 0 and result = super.getBase() } + override AstNode getChildNode(int i) { i = 0 and result = super.getExpr() } } class TypeNameExprTree extends LeafTree instanceof TypeNameExpr { } class ArrayLiteralTree extends StandardPostOrderTree instanceof ArrayLiteral { - override AstNode getChildNode(int i) { result = super.getElement(i) } + override AstNode getChildNode(int i) { result = super.getExpr(i) } } class ArrayExprTree extends StandardPostOrderTree instanceof ArrayExpr { @@ -671,7 +696,7 @@ module Trees { class TypeConstraintTree extends LeafTree instanceof TypeConstraint { } - class TypeTree extends LeafTree instanceof Type { } + class TypeDefinitionTree extends LeafTree instanceof TypeDefinitionStmt { } class TryStmtBlock extends PreOrderTree instanceof TryStmt { final override predicate propagatesAbnormal(AstNode child) { child = super.getFinally() } @@ -745,34 +770,30 @@ module Trees { } } - class CmdExprTree extends StandardPostOrderTree instanceof CmdExpr { - override AstNode getChildNode(int i) { i = 0 and result = super.getExpr() } - } - - class CmdTree extends StandardPostOrderTree instanceof Cmd { + class CallExprTree extends StandardPostOrderTree instanceof CallExpr { override AstNode getChildNode(int i) { - i = -1 and result = super.getCommand() + i = -2 and result = super.getQualifier() + or + i = -1 and result = super.getCallee() or result = super.getArgument(i) } } + class ExprStmtTree extends StandardPreOrderTree instanceof ExprStmt { + override AstNode getChildNode(int i) { i = 0 and result = super.getExpr() } + } + class StringConstTree extends LeafTree instanceof StringConstExpr { } class PipelineTree extends StandardPreOrderTree instanceof Pipeline { override AstNode getChildNode(int i) { result = super.getComponent(i) } } - class InvokeMemberExprTree extends StandardPostOrderTree instanceof InvokeMemberExpr { - override AstNode getChildNode(int i) { - i = -1 and result = super.getQualifier() - or - result = super.getArgument(i) - } - } -} + class FunctionDefinitionStmtTree extends LeafTree instanceof FunctionDefinitionStmt { } -private import Scope + class LiteralTree extends LeafTree instanceof Literal { } +} cached private CfgScope getCfgScopeImpl(Ast n) { result = scopeOf(n) } diff --git a/powershell/ql/lib/semmle/code/powershell/controlflow/internal/Splitting.qll b/powershell/ql/lib/semmle/code/powershell/controlflow/internal/Splitting.qll index 012f284eb445..b2734c98194d 100644 --- a/powershell/ql/lib/semmle/code/powershell/controlflow/internal/Splitting.qll +++ b/powershell/ql/lib/semmle/code/powershell/controlflow/internal/Splitting.qll @@ -69,6 +69,8 @@ module ConditionalCompletionSplitting { child = parent.(LogicalOrExpr).getAnOperand() or child = parent.(ConditionalExpr).getBranch(_) + or + child = parent.(ParenExpr).getExpr() ) } diff --git a/powershell/ql/lib/semmle/code/powershell/dataflow/FlowSummary.qll b/powershell/ql/lib/semmle/code/powershell/dataflow/FlowSummary.qll index 0f236704fef0..4e1b38358f2a 100644 --- a/powershell/ql/lib/semmle/code/powershell/dataflow/FlowSummary.qll +++ b/powershell/ql/lib/semmle/code/powershell/dataflow/FlowSummary.qll @@ -53,12 +53,12 @@ abstract class SummarizedCallable extends LibraryCallable, Impl::Public::Summari * calls to a method with the same name are considered relevant. */ abstract class SimpleSummarizedCallable extends SummarizedCallable { - Call c; + CallExpr c; bindingset[this] SimpleSummarizedCallable() { c.getName() = this } - final override Call getACall() { result = c } + final override CallExpr getACall() { result = c } - final override Call getACallSimple() { result = c } + final override CallExpr getACallSimple() { result = c } } diff --git a/powershell/ql/lib/semmle/code/powershell/dataflow/Ssa.qll b/powershell/ql/lib/semmle/code/powershell/dataflow/Ssa.qll index 7c0bd28dc107..e023162d437f 100644 --- a/powershell/ql/lib/semmle/code/powershell/dataflow/Ssa.qll +++ b/powershell/ql/lib/semmle/code/powershell/dataflow/Ssa.qll @@ -6,11 +6,10 @@ * Provides classes for working with static single assignment (SSA) form. */ module Ssa { - private import semmle.code.powershell.Cfg private import powershell + private import semmle.code.powershell.Cfg private import internal.SsaImpl as SsaImpl - private import CfgNodes - private import ExprNodes + private import CfgNodes::ExprNodes /** A static single assignment (SSA) definition. */ class Definition extends SsaImpl::Definition { @@ -23,8 +22,10 @@ module Ssa { exists(BasicBlock bb, int i | this.definesAt(_, bb, i) | result = bb.getNode(i)) } - /** Gets a control-flow node that reads the value of this SSA definition. */ - final AstCfgNode getARead() { result = SsaImpl::getARead(this) } + /** + * Gets a control-flow node that reads the value of this SSA definition. + */ + final VarReadAccessCfgNode getARead() { result = SsaImpl::getARead(this) } /** * Gets a first control-flow node that reads the value of this SSA definition. @@ -38,16 +39,14 @@ module Ssa { * That is, a read that can reach the end of the enclosing CFG scope, or another * SSA definition for the source variable, without passing through any other read. */ - final VarReadAccessCfgNode getALastRead() { SsaImpl::lastRead(this, result) } + deprecated final VarReadAccessCfgNode getALastRead() { SsaImpl::lastRead(this, result) } /** * Holds if `read1` and `read2` are adjacent reads of this SSA definition. * That is, `read2` can be reached from `read1` without passing through * another read. */ - final predicate hasAdjacentReads( - VarReadAccessCfgNode read1, VarReadAccessCfgNode read2 - ) { + final predicate hasAdjacentReads(VarReadAccessCfgNode read1, VarReadAccessCfgNode read2) { SsaImpl::adjacentReadPair(this, read1, read2) } @@ -91,7 +90,7 @@ module Ssa { /** * Holds if this SSA definition assigns `value` to the underlying variable. */ - predicate assigns(CfgNodes::StmtCfgNode value) { + predicate assigns(CfgNodes::ExprCfgNode value) { exists(CfgNodes::StmtNodes::AssignStmtCfgNode a, BasicBlock bb, int i | this.definesAt(_, bb, i) and a = bb.getNode(i) and @@ -104,19 +103,19 @@ module Ssa { final override Location getLocation() { result = write.getLocation() } } - class ParameterDefinition extends Definition, SsaImpl::WriteDefinition { - private Variable v; + /** + * An SSA definition that corresponds to the value of `this` upon entry to a method. + */ + class ThisDefinition extends Definition, SsaImpl::WriteDefinition { + private ThisParameter v; - ParameterDefinition() { - exists(BasicBlock bb, int i | - this.definesAt(v, bb, i) and - SsaImpl::parameterWrite(bb, i, v) - ) - } + ThisDefinition() { exists(BasicBlock bb, int i | this.definesAt(v, bb, i)) } + + override ThisParameter getSourceVariable() { result = v } - final override string toString() { result = " " + v } + final override string toString() { result = "self (" + v.getDeclaringScope() + ")" } - final override Location getLocation() { result = v.getLocation() } + final override Location getLocation() { result = this.getControlFlowNode().getLocation() } } /** @@ -138,7 +137,7 @@ module Ssa { final override Location getLocation() { result = this.getBasicBlock().getLocation() } } - /** A phi node. */ + /** phi node. */ class PhiNode extends Definition, SsaImpl::PhiNode { /** Gets an input of this phi node. */ final Definition getAnInput() { this.hasInputFromBlock(result, _) } @@ -148,7 +147,20 @@ module Ssa { inp = SsaImpl::phiHasInputFromBlock(this, bb) } - override string toString() { result = "phi" } + private string getSplitString() { + result = this.getBasicBlock().getFirstNode().(CfgNodes::AstCfgNode).getSplitsString() + } + + override string toString() { + exists(string prefix | + prefix = "[" + this.getSplitString() + "] " + or + not exists(this.getSplitString()) and + prefix = "" + | + result = prefix + "phi" + ) + } /** * The location of a phi node is the same as the location of the first node diff --git a/powershell/ql/lib/semmle/code/powershell/dataflow/flowsources/Local.qll b/powershell/ql/lib/semmle/code/powershell/dataflow/flowsources/Local.qll index b27d24a051c6..d0e2e2601fbd 100644 --- a/powershell/ql/lib/semmle/code/powershell/dataflow/flowsources/Local.qll +++ b/powershell/ql/lib/semmle/code/powershell/dataflow/flowsources/Local.qll @@ -31,9 +31,7 @@ abstract class EnvironmentVariableSource extends LocalFlowSource { } private class EnvironmentVariableEnv extends EnvironmentVariableSource { - EnvironmentVariableEnv() { - this.asExpr().getExpr().(VarReadAccess).getVariable() instanceof EnvVariable - } + EnvironmentVariableEnv() { this.asExpr().getExpr() instanceof EnvVariable } } private class ExternalEnvironmentVariableSource extends EnvironmentVariableSource { @@ -61,7 +59,7 @@ private class ExternalCommandLineArgumentSource extends CommandLineArgumentSourc * A data flow source that represents the parameters of the `Main` method of a program. */ private class MainMethodArgumentSource extends CommandLineArgumentSource { - MainMethodArgumentSource() { this.asParameter().getFunction() instanceof TopLevel } + MainMethodArgumentSource() { this.asParameter().getParent() instanceof TopLevelScriptBlock } } /** diff --git a/powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowDispatch.qll b/powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowDispatch.qll index 4c397fbdd9a6..6619cb9887d7 100644 --- a/powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowDispatch.qll +++ b/powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowDispatch.qll @@ -5,6 +5,7 @@ private import DataFlowPublic private import semmle.code.powershell.typetracking.internal.TypeTrackingImpl private import FlowSummaryImpl as FlowSummaryImpl private import semmle.code.powershell.dataflow.FlowSummary +private import SsaImpl as SsaImpl private import codeql.util.Boolean private import codeql.util.Unit @@ -39,10 +40,10 @@ abstract class LibraryCallable extends string { LibraryCallable() { any() } /** Gets a call to this library callable. */ - Call getACall() { none() } + CallExpr getACall() { none() } /** Same as `getACall()` except this does not depend on the call graph or API graph. */ - Call getACallSimple() { none() } + CallExpr getACallSimple() { none() } } /** A callable defined in library code, which should be taken into account in type tracking. */ @@ -90,7 +91,7 @@ abstract class DataFlowCall extends TDataFlowCall { abstract DataFlowCallable getEnclosingCallable(); /** Gets the underlying source code call, if any. */ - abstract CfgNodes::CallCfgNode asCall(); + abstract CfgNodes::ExprNodes::CallExprCfgNode asCall(); /** Gets a textual representation of this call. */ abstract string toString(); @@ -130,7 +131,7 @@ class SummaryCall extends DataFlowCall, TSummaryCall { override DataFlowCallable getEnclosingCallable() { result.asLibraryCallable() = c } - override CfgNodes::CallCfgNode asCall() { none() } + override CfgNodes::ExprNodes::CallExprCfgNode asCall() { none() } override string toString() { result = "[summary] call to " + receiver + " in " + c } @@ -138,11 +139,11 @@ class SummaryCall extends DataFlowCall, TSummaryCall { } class NormalCall extends DataFlowCall, TNormalCall { - private CfgNodes::CallCfgNode c; + private CfgNodes::ExprNodes::CallExprCfgNode c; NormalCall() { this = TNormalCall(c) } - override CfgNodes::CallCfgNode asCall() { result = c } + override CfgNodes::ExprNodes::CallExprCfgNode asCall() { result = c } override DataFlowCallable getEnclosingCallable() { result = TCfgScope(c.getScope()) } @@ -161,7 +162,7 @@ private module TrackInstanceInput implements CallGraphConstruction::InputSig { start.(ObjectCreationNode).getObjectCreationNode().getConstructedTypeName() = typename and exact = true or - start.asExpr().(CfgNodes::ExprNodes::TypeNameCfgNode).getTypeName() = typename and + start.asExpr().(CfgNodes::ExprNodes::TypeNameExprCfgNode).getName() = typename and exact = true or start.asParameter().getStaticType() = typename and @@ -195,7 +196,9 @@ private module TrackInstanceInput implements CallGraphConstruction::InputSig { predicate filter(Node n, Unit u) { none() } } -private predicate qualifiedCall(CfgNodes::CallCfgNode call, Node receiver, string method) { +private predicate qualifiedCall( + CfgNodes::ExprNodes::CallExprCfgNode call, Node receiver, string method +) { call.getQualifier() = receiver.asExpr() and call.getName() = method } @@ -214,7 +217,7 @@ private Type getTypeWithName(string s, boolean exact) { exact = false } -private CfgScope getTargetInstance(CfgNodes::CallCfgNode call) { +private CfgScope getTargetInstance(CfgNodes::ExprNodes::CallExprCfgNode call) { // TODO: Also match argument/parameter types exists(Node receiver, string method, string typename, Type t, boolean exact | qualifiedCall(call, receiver, method) and @@ -236,7 +239,7 @@ class AdditionalCallTarget extends Unit { /** * Gets a viable target for `call`. */ - abstract DataFlowCallable viableTarget(CfgNodes::CallCfgNode call); + abstract DataFlowCallable viableTarget(CfgNodes::ExprNodes::CallExprCfgNode call); } /** Holds if `call` may resolve to the returned summarized library method. */ @@ -256,7 +259,7 @@ private module Cached { cached newtype TDataFlowCall = - TNormalCall(CfgNodes::CallCfgNode c) or + TNormalCall(CfgNodes::ExprNodes::CallExprCfgNode c) or TSummaryCall( FlowSummaryImpl::Public::SummarizedCallable c, FlowSummaryImpl::Private::SummaryNode receiver ) { @@ -283,7 +286,7 @@ private module Cached { FlowSummaryImpl::ParsePositions::isParsedKeywordParameterPosition(_, name) } or TPositionalArgumentPosition(int pos, NamedSet ns) { - exists(CfgNodes::CallCfgNode call | + exists(CfgNodes::ExprNodes::CallExprCfgNode call | call = ns.getABindingCall() and exists(call.getArgument(pos)) ) @@ -297,7 +300,7 @@ private module Cached { TThisParameterPosition() or TKeywordParameter(string name) { name = any(Argument p).getName() } or TPositionalParameter(int pos, NamedSet ns) { - exists(CfgNodes::CallCfgNode call | + exists(CfgNodes::ExprNodes::CallExprCfgNode call | call = ns.getABindingCall() and exists(call.getArgument(pos)) ) @@ -306,7 +309,7 @@ private module Cached { // `ns.getABindingCall()`, but those parameters should still have // positions since SSA depends on this. // In particular, global scope is also an uncalled function. - any(Parameter p).getIndexExcludingPipelines() = pos and + any(SsaImpl::NormalParameter p).getIndexExcludingPipelines() = pos and ns.isEmpty() } or TPipelineParameter() diff --git a/powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowPrivate.qll b/powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowPrivate.qll index 1825df4bfbe1..c5aa29ceff98 100644 --- a/powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowPrivate.qll +++ b/powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowPrivate.qll @@ -46,20 +46,12 @@ private class ExprNodeImpl extends ExprNode, NodeImpl { override string toStringImpl() { result = this.getExprNode().toString() } } -private class StmtNodeImpl extends StmtNode, NodeImpl { - override CfgScope getCfgScope() { result = this.getStmtNode().getStmt().getEnclosingScope() } - - override Location getLocationImpl() { result = this.getStmtNode().getLocation() } - - override string toStringImpl() { result = this.getStmtNode().toString() } -} - /** Gets the SSA definition node corresponding to parameter `p`. */ pragma[nomagic] SsaImpl::DefinitionExt getParameterDef(Parameter p) { exists(EntryBasicBlock bb, int i | - SsaImpl::parameterWrite(bb, i, p) and - result.definesAt(p, bb, i, _) + bb.getNode(i).getAstNode() = p and + result.definesAt(_, bb, i, _) ) } @@ -76,8 +68,6 @@ module SsaFlow { or result.(Impl::ExprNode).getExpr() = n.asExpr() or - result.(Impl::ExprNode).getExpr() = n.asStmt() - or result.(Impl::ExprNode).getExpr() = [n.(ProcessNode).getProcessBlock(), n.(ProcessPropertyByNameNode).getProcessBlock()] or @@ -99,15 +89,13 @@ module SsaFlow { module LocalFlow { pragma[nomagic] predicate localFlowStepCommon(Node nodeFrom, Node nodeTo) { - nodeFrom.asExpr() = nodeTo.asExpr().(CfgNodes::ExprNodes::ConditionalCfgNode).getABranch() - or - nodeFrom.asStmt() = nodeTo.asStmt().(CfgNodes::StmtNodes::AssignStmtCfgNode).getRightHandSide() + nodeFrom.asExpr() = nodeTo.asExpr().(CfgNodes::ExprNodes::ConditionalExprCfgNode).getABranch() or - nodeFrom.asExpr() = nodeTo.asStmt().(CfgNodes::StmtNodes::CmdExprCfgNode).getExpr() + nodeFrom.asExpr() = nodeTo.asExpr().(CfgNodes::StmtNodes::AssignStmtCfgNode).getRightHandSide() or - nodeFrom.asExpr() = nodeTo.asExpr().(CfgNodes::ExprNodes::ConvertCfgNode).getBase() + nodeFrom.asExpr() = nodeTo.asExpr().(CfgNodes::ExprNodes::ConvertExprCfgNode).getSubExpr() or - nodeFrom.asStmt() = nodeTo.asExpr().(CfgNodes::ExprNodes::ParenCfgNode).getBase() + nodeFrom.asExpr() = nodeTo.asExpr().(CfgNodes::ExprNodes::ParenExprCfgNode).getSubExpr() or exists( CfgNodes::ExprNodes::ArrayExprCfgNode arrayExpr, EscapeContainer::EscapeContainer container @@ -149,8 +137,6 @@ module LocalFlow { predicate localMustFlowStep(Node nodeFrom, Node nodeTo) { SsaFlow::localMustFlowStep(_, nodeFrom, nodeTo) or - nodeFrom.asStmt() = nodeTo.asStmt().(CfgNodes::StmtNodes::AssignStmtCfgNode).getRightHandSide() - or nodeFrom = unique(FlowSummaryNode n1 | FlowSummaryImpl::Private::Steps::summaryLocalStep(n1.getSummaryNode(), @@ -167,7 +153,7 @@ module VariableCapture { private predicate isProcessPropertyByNameNode( PipelineByPropertyNameIteratorVariable iter, ProcessBlock pb ) { - pb.getEnclosingScope() = iter.getDeclaringScope() + pb = iter.getProcessBlock() } /** A collection of cached types and predicates to be evaluated in the same stage. */ @@ -180,18 +166,21 @@ private module Cached { TExprNode(CfgNodes::ExprCfgNode n) or TStmtNode(CfgNodes::StmtCfgNode n) or TSsaNode(SsaImpl::DataFlowIntegration::SsaNode node) or - TNormalParameterNode(Parameter p) or + TNormalParameterNode(SsaImpl::NormalParameter p) or + TThisParameterNode(Method m) or + TPipelineByPropertyNameParameterNode(PipelineByPropertyNameParameter p) or + TPipelineParamaterNode(PipelineParameter p) or TExprPostUpdateNode(CfgNodes::ExprCfgNode n) { n instanceof CfgNodes::ExprNodes::ArgumentCfgNode or n instanceof CfgNodes::ExprNodes::QualifierCfgNode or - exists(CfgNodes::ExprNodes::MemberCfgNode member | + exists(CfgNodes::ExprNodes::MemberExprCfgNode member | n = member.getQualifier() and not member.isStatic() ) or - n = any(CfgNodes::ExprNodes::IndexCfgNode index).getBase() + n = any(CfgNodes::ExprNodes::IndexExprCfgNode index).getBase() } or TFlowSummaryNode(FlowSummaryImpl::Private::SummaryNode sn) or TPreReturnNodeImpl(CfgNodes::AstCfgNode n, Boolean isArray) { isMultiReturned(n) } or @@ -202,7 +191,6 @@ private module Cached { isProcessPropertyByNameNode(iter, _) } or TScriptBlockNode(ScriptBlock scriptBlock) or - TTypePathNode(int n, CfgNode cfg) { isTypePathNode(_, n, cfg) } or TForbiddenRecursionGuard() { none() and // We want to prune irrelevant models before materialising data flow nodes, so types contributed @@ -289,34 +277,12 @@ private module Cached { TypeTrackingInput::withoutContentStepImpl(_, n, _) } - private predicate isAutomaticVariable(Node n) { - n.asExpr().(CfgNodes::ExprNodes::VarReadAccessCfgNode).getVariable().getName() = - [ - "args", "ConsoleFileName", "EnabledExperimentalFeatures", "Error", "Event", "EventArgs", - "EventSubscriber", "ExecutionContext", "HOME", "Host", "input", "IsCoreCLR", "IsLinux", - "IsMacOS", "IsWindows", "LASTEXITCODE", "MyInvocation", "NestedPromptLevel", "PID", - "PROFILE", "PSBoundParameters", "PSCmdlet", "PSCommandPath", "PSCulture", "PSDebugContext", - "PSEdition", "PSHOME", "PSItem", "PSScriptRoot", "PSSenderInfo", "PSUICulture", - "PSVersionTable", "PWD", "Sender", "ShellId", "StackTrace" - ] - } - cached predicate isLocalSourceNode(Node n) { n instanceof ParameterNode or - isAutomaticVariable(n) - or // Expressions that can't be reached from another entry definition or expression - ( - n instanceof ExprNode - or - exists(CfgNodes::StmtNodes::AssignStmtCfgNode assign | assign.getRightHandSide() = n.asStmt()) - or - n.asStmt() instanceof CfgNodes::StmtNodes::CmdCfgNode - or - exists(CfgNodes::StmtNodes::PipelineCfgNode pipeline | n.asStmt() = pipeline.getAComponent()) - ) and + n instanceof ExprNode and not reachedFromExprOrEntrySsaDef(n) or // Ensure all entry SSA definitions are local sources, except those that correspond @@ -442,10 +408,12 @@ class SsaInputNode extends SsaNode { override CfgScope getCfgScope() { result = node.getDefinitionExt().getBasicBlock().getScope() } } -private string getANamedArgument(CfgNodes::CallCfgNode c) { exists(c.getNamedArgument(result)) } +private string getANamedArgument(CfgNodes::ExprNodes::CallExprCfgNode c) { + exists(c.getNamedArgument(result)) +} private module NamedSetModule = - QlBuiltins::InternSets; + QlBuiltins::InternSets; private newtype NamedSet0 = TEmptyNamedSet() or @@ -475,7 +443,7 @@ class NamedSet extends NamedSet0 { * * NOTE: The `CfgNodes::CallCfgNode` may also provide more names. */ - CfgNodes::CallCfgNode getABindingCall() { + CfgNodes::ExprNodes::CallExprCfgNode getABindingCall() { forex(string name | name = this.getAName() | exists(result.getNamedArgument(name))) or this.isEmpty() and @@ -486,7 +454,7 @@ class NamedSet extends NamedSet0 { * Gets a `Cmd` that provides exactly the named parameters represented by * this set. */ - CfgNodes::CallCfgNode getAnExactBindingCall() { + CfgNodes::ExprNodes::CallExprCfgNode getAnExactBindingCall() { forex(string name | name = this.getAName() | exists(result.getNamedArgument(name))) and forex(string name | exists(result.getNamedArgument(name)) | name = this.getAName()) or @@ -505,6 +473,11 @@ class NamedSet extends NamedSet0 { NamedSet emptyNamedSet() { result.isEmpty() } +SsaImpl::NormalParameter getNormalParameter(FunctionBase f, int index) { + result.getFunction() = f and + result.getIndexExcludingPipelines() = index +} + private module ParameterNodes { abstract class ParameterNodeImpl extends NodeImpl { abstract Parameter getParameter(); @@ -524,18 +497,15 @@ private module ParameterNodes { * flow graph. */ class NormalParameterNode extends ParameterNodeImpl, TNormalParameterNode { - Parameter parameter; + SsaImpl::NormalParameter parameter; NormalParameterNode() { this = TNormalParameterNode(parameter) } override Parameter getParameter() { result = parameter } override predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) { - parameter.getDeclaringScope() = c.asCfgScope() and + parameter.getEnclosingScope() = c.asCfgScope() and ( - pos.isThis() and - parameter.isThis() - or pos.isKeyword(parameter.getName()) or // Given a function f with parameters x, y we map @@ -549,7 +519,7 @@ private module ParameterNodes { // 3. position(1, {}) // The interpretation of `position(i, S)` is the position of the i'th unnamed parameter when the // keywords in S are specified. - exists(int i, int j, string name, NamedSet ns, Function f | + exists(int i, int j, string name, NamedSet ns, FunctionBase f | pos.isPositional(j, ns) and parameter.getIndexExcludingPipelines() = i and f = parameter.getFunction() and @@ -560,29 +530,79 @@ private module ParameterNodes { i - count(int k, Parameter p | k < i and - p = f.getParameterExcludingPiplines(k) and + p = getNormalParameter(f, k) and p.getName() = ns.getAName() ) ) - or - (parameter.isPipeline() or parameter.isPipelineByPropertyName()) and - pos.isPipeline() ) } - override CfgScope getCfgScope() { - result.getAParameter() = parameter or result.getThisParameter() = parameter - } + override CfgScope getCfgScope() { result.getAParameter() = parameter } override Location getLocationImpl() { result = parameter.getLocation() } override string toStringImpl() { result = parameter.toString() } } - class PipelineByPropertyNameParameterNode extends NormalParameterNode { - PipelineByPropertyNameParameterNode() { this.getParameter().isPipelineByPropertyName() } + class ThisParameterNode extends ParameterNodeImpl, TThisParameterNode { + Method m; + + ThisParameterNode() { this = TThisParameterNode(m) } + + override Parameter getParameter() { none() } + + override predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) { + m.getBody() = c.asCfgScope() and + pos.isThis() + } + + override CfgScope getCfgScope() { result = m.getBody() } + + override Location getLocationImpl() { result = m.getLocation() } + + override string toStringImpl() { result = "this" } + } + + class PipelineParamaterNode extends ParameterNodeImpl, TPipelineParamaterNode { + private PipelineParameter parameter; - string getPropretyName() { result = this.getParameter().getName() } + PipelineParamaterNode() { this = TPipelineParamaterNode(parameter) } + + override PipelineParameter getParameter() { result = parameter } + + override predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) { + pos.isPipeline() and // what about when it is applied as a normal parameter? + c.asCfgScope() = parameter.getEnclosingScope() + } + + override CfgScope getCfgScope() { result = parameter.getEnclosingScope() } + + override Location getLocationImpl() { result = this.getParameter().getLocation() } + + override string toStringImpl() { result = this.getParameter().toString() } + } + + class PipelineByPropertyNameParameterNode extends ParameterNodeImpl, + TPipelineByPropertyNameParameterNode + { + private PipelineByPropertyNameParameter parameter; + + PipelineByPropertyNameParameterNode() { this = TPipelineByPropertyNameParameterNode(parameter) } + + override PipelineParameter getParameter() { result = parameter } + + override predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) { + pos.isPipeline() and // what about when it is applied as a normal parameter? + c.asCfgScope() = parameter.getEnclosingScope() + } + + override CfgScope getCfgScope() { result = parameter.getEnclosingScope() } + + override Location getLocationImpl() { result = this.getParameter().getLocation() } + + override string toStringImpl() { result = this.getParameter().toString() } + + string getPropertyName() { result = parameter.getPropertyName() } } /** A parameter for a library callable with a flow summary. */ @@ -628,7 +648,9 @@ abstract class ArgumentNode extends Node { /** Holds if this argument occurs at the given position in the given call. */ abstract predicate argumentOf(DataFlowCall call, ArgumentPosition pos); - abstract predicate sourceArgumentOf(CfgNodes::CallCfgNode call, ArgumentPosition pos); + abstract predicate sourceArgumentOf( + CfgNodes::ExprNodes::CallExprCfgNode call, ArgumentPosition pos + ); /** Gets the call in which this node is an argument. */ final DataFlowCall getCall() { this.argumentOf(result, _) } @@ -644,7 +666,9 @@ module ArgumentNodes { this.sourceArgumentOf(call.asCall(), pos) } - override predicate sourceArgumentOf(CfgNodes::CallCfgNode call, ArgumentPosition pos) { + override predicate sourceArgumentOf( + CfgNodes::ExprNodes::CallExprCfgNode call, ArgumentPosition pos + ) { arg.getCall() = call and ( pos.isKeyword(arg.getName()) @@ -654,32 +678,46 @@ module ArgumentNodes { ns.getAnExactBindingCall() = call and pos.isPositional(i, ns) ) - or - arg.isQualifier() and - pos.isThis() ) } } - private predicate isPipelineInput( - CfgNodes::StmtNodes::CmdBaseCfgNode input, CfgNodes::StmtNodes::CmdBaseCfgNode consumer - ) { - exists(CfgNodes::StmtNodes::PipelineCfgNode pipeline, int i | + class ThisArgumentNode extends ArgumentNode { + CfgNodes::ExprNodes::QualifierCfgNode qual; + + ThisArgumentNode() { this.asExpr() = qual } + + override predicate argumentOf(DataFlowCall call, ArgumentPosition pos) { + this.sourceArgumentOf(call.asCall(), pos) + } + + override predicate sourceArgumentOf( + CfgNodes::ExprNodes::CallExprCfgNode call, ArgumentPosition pos + ) { + qual.getCall() = call and + pos.isThis() + } + } + + private predicate isPipelineInput(CfgNodes::ExprCfgNode input, CfgNodes::ExprCfgNode consumer) { + exists(CfgNodes::ExprNodes::PipelineCfgNode pipeline, int i | input = pipeline.getComponent(i) and consumer = pipeline.getComponent(i + 1) ) } - class PipelineArgumentNode extends ArgumentNode, StmtNode { - CfgNodes::StmtNodes::CmdBaseCfgNode consumer; + class PipelineArgumentNode extends ArgumentNode, ExprNode { + CfgNodes::ExprCfgNode consumer; - PipelineArgumentNode() { isPipelineInput(this.getStmtNode(), consumer) } + PipelineArgumentNode() { isPipelineInput(this.getExprNode(), consumer) } override predicate argumentOf(DataFlowCall call, ArgumentPosition pos) { this.sourceArgumentOf(call.asCall(), pos) } - override predicate sourceArgumentOf(CfgNodes::CallCfgNode call, ArgumentPosition pos) { + override predicate sourceArgumentOf( + CfgNodes::ExprNodes::CallExprCfgNode call, ArgumentPosition pos + ) { call = consumer and pos.isPipeline() } @@ -697,7 +735,11 @@ module ArgumentNodes { call.(SummaryCall).getReceiver() = receiver and pos = pos_ } - override predicate sourceArgumentOf(CfgNodes::CallCfgNode call, ArgumentPosition pos) { none() } + override predicate sourceArgumentOf( + CfgNodes::ExprNodes::CallExprCfgNode call, ArgumentPosition pos + ) { + none() + } } } @@ -715,11 +757,7 @@ private module EscapeContainer { private module ReturnContainerInterpreter implements InterpretAstInputSig { class T = CfgNodes::AstCfgNode; - T interpret(Ast a) { - result.(CfgNodes::ExprCfgNode).getExpr() = a - or - result.(CfgNodes::StmtCfgNode).getStmt() = a.(Cmd) - } + T interpret(Ast a) { result.(CfgNodes::ExprCfgNode).getExpr() = a } // TODO: Recutse into expr-to-stmt conversions } class EscapeContainer extends AstEscape::Element { @@ -818,16 +856,16 @@ predicate jumpStep(Node pred, Node succ) { * content `c`. */ predicate storeStep(Node node1, ContentSet c, Node node2) { - exists(CfgNodes::ExprNodes::MemberCfgWriteAccessNode var, Content::FieldContent fc | + exists(CfgNodes::ExprNodes::MemberExprWriteAccessCfgNode var, Content::FieldContent fc | node2.(PostUpdateNode).getPreUpdateNode().asExpr() = var.getQualifier() and - node1.asStmt() = var.getAssignStmt().getRightHandSide() and + node1.asExpr() = var.getAssignStmt().getRightHandSide() and fc.getName() = var.getMemberName() and c.isSingleton(fc) ) or - exists(CfgNodes::ExprNodes::IndexCfgWriteNode var, CfgNodes::ExprCfgNode e | + exists(CfgNodes::ExprNodes::IndexExprWriteAccessCfgNode var, CfgNodes::ExprCfgNode e | node2.(PostUpdateNode).getPreUpdateNode().asExpr() = var.getBase() and - node1.asStmt() = var.getAssignStmt().getRightHandSide() and + node1.asExpr() = var.getAssignStmt().getRightHandSide() and e = var.getIndex() | exists(Content::KnownElementContent ec | @@ -840,13 +878,13 @@ predicate storeStep(Node node1, ContentSet c, Node node2) { ) or exists(Content::KnownElementContent ec, int index | - node2.asExpr().(CfgNodes::ExprNodes::ArrayLiteralCfgNode).getElement(index) = node1.asExpr() and + node2.asExpr().(CfgNodes::ExprNodes::ArrayLiteralCfgNode).getExpr(index) = node1.asExpr() and c.isKnownOrUnknownElement(ec) and index = ec.getIndex().asInt() ) or exists(CfgNodes::ExprCfgNode key | - node2.asExpr().(CfgNodes::ExprNodes::HashTableCfgNode).getElement(key) = node1.asStmt() + node2.asExpr().(CfgNodes::ExprNodes::HashTableExprCfgNode).getValueFromKey(key) = node1.asExpr() | exists(Content::KnownElementContent ec | c.isKnownOrUnknownElement(ec) and @@ -887,14 +925,14 @@ predicate storeStep(Node node1, ContentSet c, Node node2) { * Holds if there is a read step of content `c` from `node1` to `node2`. */ predicate readStep(Node node1, ContentSet c, Node node2) { - exists(CfgNodes::ExprNodes::MemberCfgReadAccessNode var, Content::FieldContent fc | + exists(CfgNodes::ExprNodes::MemberExprReadAccessCfgNode var, Content::FieldContent fc | node2.asExpr() = var and node1.asExpr() = var.getQualifier() and fc.getName() = var.getMemberName() and c.isSingleton(fc) ) or - exists(CfgNodes::ExprNodes::IndexCfgReadNode var, CfgNodes::ExprCfgNode e | + exists(CfgNodes::ExprNodes::IndexExprReadAccessCfgNode var, CfgNodes::ExprCfgNode e | node2.asExpr() = var and node1.asExpr() = var.getBase() and e = var.getIndex() @@ -915,7 +953,7 @@ predicate readStep(Node node1, ContentSet c, Node node2) { ) or c.isAnyElement() and - exists(SsaImpl::DefinitionExt def, ProcessNode processNode, LocalScopeVariable iterator | + exists(SsaImpl::DefinitionExt def, ProcessNode processNode, Variable iterator | processNode = node1 and iterator = def.getSourceVariable() | processNode.getIteratorVariable() = iterator and @@ -937,8 +975,8 @@ predicate readStep(Node node1, ContentSet c, Node node2) { or exists(Content::KnownElementContent ec, SsaImpl::DefinitionExt def | c.isSingleton(ec) and - node1.(PipelineByPropertyNameParameterNode).getPropretyName() = ec.getIndex().asString() and - def.getSourceVariable() = node1.(PipelineByPropertyNameParameterNode).getParameter() and + node1.(PipelineByPropertyNameParameterNode).getPropertyName() = ec.getIndex().asString() and + def = SsaImpl::getParameterDef(node1.(PipelineByPropertyNameParameterNode).getParameter()) and SsaImpl::firstRead(def, node2.asExpr()) ) or @@ -1163,64 +1201,6 @@ class ScriptBlockNode extends TScriptBlockNode, NodeImpl { override predicate nodeIsHidden() { any() } } -private predicate isTypePathNode(string type, int n, CfgNode cfg) { - exists(CfgNodes::ExprNodes::TypeNameCfgNode typeName, string s | - cfg = typeName and - type = typeName.getTypeName() and - s = type.splitAt(".", n) - ) - or - exists(CfgNodes::StmtNodes::CmdCfgNode cmd, string s | - cfg = cmd.getCommand() and - type = cmd.getNamespaceQualifier() and - s = type.splitAt(".", n) - ) -} - -/** - * A dataflow node that represents a component of a type or module path. - * - * For example, `System`, `System.Management`, `System.Management.Automation`, - * and `System.Management.Automation.PowerShell` in the type - * name `[System.Management.Automation.PowerShell]`. - */ -class TypePathNodeImpl extends TTypePathNode, NodeImpl { - int n; - CfgNode cfg; - - TypePathNodeImpl() { this = TTypePathNode(n, cfg) } - - string getType() { isTypePathNode(result, n, cfg) } - - predicate isComplete() { not exists(this.getNext()) } - - int getIndex() { result = n } - - string getComponent() { result = this.getType().splitAt(".", n) } - - override CfgScope getCfgScope() { result = cfg.getScope() } - - override Location getLocationImpl() { result = cfg.getLocation() } - - override string toStringImpl() { - not exists(this.getPrev()) and - result = this.getComponent() - or - result = this.getPrev() + "." + this.getComponent() - } - - override predicate nodeIsHidden() { any() } - - TypePathNodeImpl getNext() { result = TTypePathNode(n + 1, cfg) } - - TypePathNodeImpl getPrev() { result.getNext() = this } - - TypePathNodeImpl getConstant(string s) { - s = result.getComponent() and - result = this.getNext() - } -} - /** A node that performs a type cast. */ class CastNode extends Node { CastNode() { none() } @@ -1250,16 +1230,19 @@ predicate isUnreachableInCall(NodeRegion nr, DataFlowCall call) { none() } newtype LambdaCallKind = TLambdaCallKind() -private class CmdName extends StringConstExpr { - CmdName() { this = any(Cmd c).getCmdName() } +private class CmdName extends CfgNodes::ExprNodes::StringLiteralExprCfgNode { + CmdName() { this = any(CfgNodes::ExprNodes::CallExprCfgNode c).getCallee() } - string getName() { result = this.getValue().getValue() } + string getName() { result = this.getValueString() } } /** Holds if `creation` is an expression that creates a lambda of kind `kind` for `c`. */ predicate lambdaCreation(Node creation, LambdaCallKind kind, DataFlowCallable c) { - creation.asExpr().getExpr().(CmdName).getName() = c.asCfgScope().getEnclosingFunction().getName() and - exists(kind) + exists(kind) and + exists(FunctionBase f | + f.getBody() = c.asCfgScope() and + creation.asExpr().(CmdName).getName() = f.getName() + ) } /** @@ -1267,7 +1250,7 @@ predicate lambdaCreation(Node creation, LambdaCallKind kind, DataFlowCallable c) * where `receiver` is the lambda expression. */ predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) { - call.asCall().getCommand() = receiver.asExpr() and exists(kind) + call.asCall().getCallee() = receiver.asExpr() and exists(kind) } /** Extra data-flow steps needed for lambda flow analysis. */ diff --git a/powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowPublic.qll b/powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowPublic.qll index b8ae6a48e385..7848fb6e2a7d 100644 --- a/powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowPublic.qll +++ b/powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowPublic.qll @@ -13,8 +13,6 @@ class Node extends TNode { /** Gets the expression corresponding to this node, if any. */ CfgNodes::ExprCfgNode asExpr() { result = this.(ExprNode).getExprNode() } - CfgNodes::StmtCfgNode asStmt() { result = this.(StmtNode).getStmtNode() } - ScriptBlock asCallable() { result = this.(CallableNode).asCallableAstNode() } /** Gets the parameter corresponding to this node, if any. */ @@ -69,22 +67,6 @@ class ExprNode extends AbstractAstNode, TExprNode { CfgNodes::ExprCfgNode getExprNode() { result = n } } -/** - * A statement, viewed as a node in a data flow graph. - * - * Note that because of control-flow splitting, one `Stmt` may correspond - * to multiple `StmtNode`s, just like it may correspond to multiple - * `ControlFlow::Node`s. - */ -class StmtNode extends AbstractAstNode, TStmtNode { - override CfgNodes::StmtCfgNode n; - - StmtNode() { this = TStmtNode(n) } - - /** Gets the expression corresponding to this node. */ - CfgNodes::StmtCfgNode getStmtNode() { result = n } -} - /** * The value of a parameter at function entry, viewed as a node in a data * flow graph. @@ -193,21 +175,6 @@ class PostUpdateNode extends Node { Node getPreUpdateNode() { result = pre } } -/** - * A dataflow node that represents a component of a type or module path. - * - * For example, `System`, `System.Management`, `System.Management.Automation`, - * and `System.Management.Automation.PowerShell` in the type - * name `[System.Management.Automation.PowerShell]`. - */ -class TypePathNode extends Node instanceof TypePathNodeImpl { - string getComponent() { result = super.getComponent() } - - TypePathNode getConstant(string s) { result = super.getConstant(s) } - - API::Node track() { result = API::mod(super.getType(), super.getIndex()) } -} - cached private module Cached { cached @@ -247,9 +214,6 @@ private import Cached /** Gets a node corresponding to expression `e`. */ ExprNode exprNode(CfgNodes::ExprCfgNode e) { result.getExprNode() = e } -/** Gets a node corresponding to statement `s`. */ -StmtNode stmtNode(CfgNodes::StmtCfgNode e) { result.getStmtNode() = e } - /** * Gets the node corresponding to the value of parameter `p` at function entry. */ @@ -437,27 +401,34 @@ module BarrierGuard { * * For example, `[Foo]::new()` or `New-Object Foo`. */ -class ObjectCreationNode extends Node { - CfgNodes::ObjectCreationCfgNode objectCreation; +class ObjectCreationNode extends ExprNode { + CfgNodes::ExprNodes::ObjectCreationCfgNode objectCreation; - ObjectCreationNode() { - this.asExpr() = objectCreation - or - this.asStmt() = objectCreation + ObjectCreationNode() { this.getExprNode() = objectCreation } + + final CfgNodes::ExprNodes::ObjectCreationCfgNode getObjectCreationNode() { + result = objectCreation } - final CfgNodes::ObjectCreationCfgNode getObjectCreationNode() { result = objectCreation } + /** + * Gets the node corresponding to the expression that decides which type + * to allocate. + * + * For example, in `[Foo]::new()`, this would be `Foo`, and in + * `New-Object Foo`, this would be `Foo`. + */ + Node getConstructedTypeNode() { result.asExpr() = objectCreation.getConstructedTypeExpr() } string getConstructedTypeName() { result = this.getObjectCreationNode().getConstructedTypeName() } } /** A call, viewed as a node in a data flow graph. */ -class CallNode extends AstNode { - CfgNodes::CallCfgNode call; +class CallNode extends ExprNode { + CfgNodes::ExprNodes::CallExprCfgNode call; CallNode() { call = this.getCfgNode() } - CfgNodes::CallCfgNode getCallNode() { result = call } + CfgNodes::ExprNodes::CallExprCfgNode getCallNode() { result = call } string getName() { result = call.getName() } @@ -478,22 +449,33 @@ class CallNode extends AstNode { * Note that this predicate doesn't get the pipeline argument, if any. */ Node getAnArgument() { result.asExpr() = call.getAnArgument() } - - int getNumberOfArguments() { result = call.getNumberOfArguments() } } /** A call to operator `&`, viwed as a node in a data flow graph. */ class CallOperatorNode extends CallNode { - override CfgNodes::StmtNodes::CallOperatorCfgNode call; + override CfgNodes::ExprNodes::CallOperatorCfgNode call; - Node getCommand() { result.asExpr() = call.getCommand() } + Node getCommand() { result.asExpr() = call.getCommand() } // TODO: Alternatively, we could remap calls to & as command expressions. } /** A use of a type name, viewed as a node in a data flow graph. */ class TypeNameNode extends ExprNode { - override CfgNodes::ExprNodes::TypeNameCfgNode n; + override CfgNodes::ExprNodes::TypeNameExprCfgNode n; + + override CfgNodes::ExprNodes::TypeNameExprCfgNode getExprNode() { result = n } + + string getName() { result = n.getName() } + + predicate isQualified() { n.isQualified() } + + string getNamespace() { result = n.getNamespace() } + + string getPossiblyQualifiedName() { result = n.getPossiblyQualifiedName() } +} - final override CfgNodes::ExprNodes::TypeNameCfgNode getExprNode() { result = n } +/** A use of a qualified type name, viewed as a node in a data flow graph. */ +class QualifiedTypeNameNode extends TypeNameNode { + override CfgNodes::ExprNodes::QualifiedTypeNameExprCfgNode n; - string getTypeName() { result = n.getTypeName() } + final override CfgNodes::ExprNodes::QualifiedTypeNameExprCfgNode getExprNode() { result = n } } diff --git a/powershell/ql/lib/semmle/code/powershell/dataflow/internal/SsaImpl.qll b/powershell/ql/lib/semmle/code/powershell/dataflow/internal/SsaImpl.qll index deb814e50854..d9dceb4d27a4 100644 --- a/powershell/ql/lib/semmle/code/powershell/dataflow/internal/SsaImpl.qll +++ b/powershell/ql/lib/semmle/code/powershell/dataflow/internal/SsaImpl.qll @@ -19,7 +19,7 @@ module SsaInput implements SsaImplCommon::InputSig { BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() } - class SourceVariable = LocalScopeVariable; + class SourceVariable = Variable; /** * Holds if the statement at index `i` of basic block `bb` contains a write to variable `v`. @@ -27,23 +27,21 @@ module SsaInput implements SsaImplCommon::InputSig { */ predicate variableWrite(BasicBlock bb, int i, SourceVariable v, boolean certain) { ( - uninitializedWrite(bb, i, v) + exists(Scope scope | scope = v.(ThisParameter).getDeclaringScope() | + // We consider the `this` variable to have a single write at the entry to a method block + scope = bb.(BasicBlocks::EntryBasicBlock).getScope() and + i = 0 + ) or - parameterWrite(bb, i, v) + uninitializedWrite(bb, i, v) or variableWriteActual(bb, i, v, _) - or - pipelineIteratorWrite(bb, i, v) ) and certain = true } - predicate variableRead(BasicBlock bb, int i, SourceVariable v, boolean certain) { - ( - variableReadActual(bb, i, v) - or - pipelineRead(bb, i, v) - ) and + predicate variableRead(BasicBlock bb, int i, Variable v, boolean certain) { + variableReadActual(bb, i, v) and certain = true } } @@ -61,101 +59,20 @@ class PhiNode = Impl::PhiNode; module Consistency = Impl::Consistency; /** Holds if `v` is uninitialized at index `i` in entry block `bb`. */ -predicate uninitializedWrite(Cfg::EntryBasicBlock bb, int i, LocalVariable v) { - v.getDeclaringScope() = bb.getScope() and - i = -1 -} - -predicate pipelineIteratorWrite(Cfg::BasicBlock bb, int i, LocalScopeVariable v) { - exists(ProcessBlockCfgNode process | process = bb.getNode(i) | - v.(PipelineIteratorVariable).getProcessBlock() = process.getAstNode() - or - v.(PipelineByPropertyNameIteratorVariable).getProcessBlock() = process.getAstNode() - ) -} - -/** - * Gets index of `p` in a version of the enclosing function where the parameter - * list is reversed. - * - * For example, given - * ```ps - * function f($a, $b) { ... } - * ``` - * the inverted index of `$a` is 1, and the inverted index of `$b` is 0. - * - * The inverted index of `$this` is always always the number of - * parameters (excluding `this`). - */ -private int getInvertedIndex(Parameter p) { - p.isThis() and - result = p.getFunction().getNumberOfParameters() - or - exists(int i | - p.getIndex() = i or - p.hasParameterBlock(_, i) - | - result = p.getFunction().getNumberOfParameters() - i - 1 - ) -} - -/** - * Holds if the the SSA definition of `p` should be placed at index `i` in - * block `bb`. Note that the index may be negative. - */ -predicate parameterWrite(Cfg::EntryBasicBlock bb, int i, Parameter p) { - exists(Function f | - f.getEntryBasicBlock() = bb and - p.getFunction() = f and - // If the enclosing function has 2 parameters we map the index of parameter - // 0 to -2, the index of parameter 1 to -1. - i = -getInvertedIndex(p) - 1 - ) -} - -private LocalScopeVariable getPipelineIterator(LocalScopeVariable pipelineParam) { - result.(PipelineIteratorVariable).getProcessBlock().getScriptBlock() = - pipelineParam.(PipelineParameter).getDeclaringScope() - or - result.(PipelineByPropertyNameIteratorVariable).getParameter() = - pipelineParam.(PipelineByPropertyNameParameter) -} - -private predicate isPipelineIteratorVarAccess(VarAccessCfgNode va) { - ( - va.getVariable() instanceof PipelineParameter or - va.getVariable() instanceof PipelineByPropertyNameParameter - ) and - va.getAstNode().getParent*() instanceof ProcessBlock +predicate uninitializedWrite(Cfg::EntryBasicBlock bb, int i, Variable v) { + bb.getNode(i).getAstNode() = v } /** Holds if `v` is read at index `i` in basic block `bb`. */ -private predicate variableReadActual(Cfg::BasicBlock bb, int i, SsaInput::SourceVariable v) { - exists(VarReadAccessCfgNode read, SsaInput::SourceVariable w | - read.getVariable() = w and read = bb.getNode(i) - | - if isPipelineIteratorVarAccess(read) then v = getPipelineIterator(w) else v = w - ) -} - -private predicate pipelineRead(Cfg::BasicBlock bb, int i, SsaInput::SourceVariable v) { - exists(ProcessBlockCfgNode process | process = bb.getNode(i) | - v = process.getPipelineParameter() or - v = process.getAPipelineByPropertyNameParameter() +private predicate variableReadActual(Cfg::BasicBlock bb, int i, Variable v) { + exists(VarReadAccess read | + read.getVariable() = v and + read = bb.getNode(i).getAstNode() ) } pragma[noinline] -private predicate adjacentDefRead( - Definition def, SsaInput::BasicBlock bb1, int i1, SsaInput::BasicBlock bb2, int i2, - SsaInput::SourceVariable v -) { - Impl::adjacentDefRead(def, bb1, i1, bb2, i2) and - v = def.getSourceVariable() -} - -pragma[noinline] -private predicate adjacentDefReadExt( +deprecated private predicate adjacentDefReadExt( DefinitionExt def, SsaInput::BasicBlock bb1, int i1, SsaInput::BasicBlock bb2, int i2, SsaInput::SourceVariable v ) { @@ -163,23 +80,7 @@ private predicate adjacentDefReadExt( v = def.getSourceVariable() } -private predicate adjacentDefReachesRead( - Definition def, SsaInput::BasicBlock bb1, int i1, SsaInput::BasicBlock bb2, int i2 -) { - exists(SsaInput::SourceVariable v | adjacentDefRead(def, bb1, i1, bb2, i2, v) | - def.definesAt(v, bb1, i1) - or - SsaInput::variableRead(bb1, i1, v, true) - ) - or - exists(SsaInput::BasicBlock bb3, int i3 | - adjacentDefReachesRead(def, bb1, i1, bb3, i3) and - SsaInput::variableRead(bb3, i3, _, false) and - Impl::adjacentDefRead(def, bb3, i3, bb2, i2) - ) -} - -private predicate adjacentDefReachesReadExt( +deprecated private predicate adjacentDefReachesReadExt( DefinitionExt def, SsaInput::BasicBlock bb1, int i1, SsaInput::BasicBlock bb2, int i2 ) { exists(SsaInput::SourceVariable v | adjacentDefReadExt(def, bb1, i1, bb2, i2, v) | @@ -195,16 +96,7 @@ private predicate adjacentDefReachesReadExt( ) } -/** Same as `adjacentDefRead`, but skips uncertain reads. */ -pragma[nomagic] -private predicate adjacentDefSkipUncertainReads( - Definition def, SsaInput::BasicBlock bb1, int i1, SsaInput::BasicBlock bb2, int i2 -) { - adjacentDefReachesRead(def, bb1, i1, bb2, i2) and - SsaInput::variableRead(bb2, i2, _, true) -} - -private predicate adjacentDefReachesUncertainReadExt( +deprecated private predicate adjacentDefReachesUncertainReadExt( DefinitionExt def, SsaInput::BasicBlock bb1, int i1, SsaInput::BasicBlock bb2, int i2 ) { adjacentDefReachesReadExt(def, bb1, i1, bb2, i2) and @@ -213,7 +105,9 @@ private predicate adjacentDefReachesUncertainReadExt( /** Same as `lastRefRedef`, but skips uncertain reads. */ pragma[nomagic] -private predicate lastRefSkipUncertainReadsExt(DefinitionExt def, SsaInput::BasicBlock bb, int i) { +deprecated private predicate lastRefSkipUncertainReadsExt( + DefinitionExt def, SsaInput::BasicBlock bb, int i +) { Impl::lastRef(def, bb, i) and not SsaInput::variableRead(bb, i, def.getSourceVariable(), false) or @@ -223,6 +117,20 @@ private predicate lastRefSkipUncertainReadsExt(DefinitionExt def, SsaInput::Basi ) } +/** + * Holds if the read of `def` at `read` may be a last read. That is, `read` + * can either reach another definition of the underlying source variable or + * the end of the CFG scope, without passing through another non-pseudo read. + */ +pragma[nomagic] +deprecated predicate lastRead(Definition def, VarReadAccessCfgNode read) { + exists(Cfg::BasicBlock bb, int i | + lastRefSkipUncertainReadsExt(def, bb, i) and + variableReadActual(bb, i, _) and + read = bb.getNode(i) + ) +} + cached private module Cached { /** @@ -231,12 +139,11 @@ private module Cached { */ cached predicate variableWriteActual( - Cfg::BasicBlock bb, int i, SsaInput::SourceVariable v, VarWriteAccessCfgNode write + Cfg::BasicBlock bb, int i, Variable v, VarWriteAccessCfgNode write ) { - exists(Cfg::CfgNode n, SsaInput::SourceVariable w | - write.getVariable() = w and - n = bb.getNode(i) and - if isPipelineIteratorVarAccess(write) then v = getPipelineIterator(w) else v = w + exists(Cfg::CfgNode n | + write.getVariable() = v and + n = bb.getNode(i) | write.isExplicitWrite(n) or @@ -246,10 +153,10 @@ private module Cached { } cached - AstCfgNode getARead(Definition def) { - exists(SsaInput::SourceVariable v, Cfg::BasicBlock bb, int i | + VarReadAccessCfgNode getARead(Definition def) { + exists(Variable v, Cfg::BasicBlock bb, int i | Impl::ssaDefReachesRead(v, def, bb, i) and - SsaInput::variableRead(bb, i, v, true) and + variableReadActual(bb, i, v) and result = bb.getNode(i) ) } @@ -267,11 +174,7 @@ private module Cached { */ cached predicate firstRead(Definition def, VarReadAccessCfgNode read) { - exists(Cfg::BasicBlock bb1, int i1, Cfg::BasicBlock bb2, int i2 | - def.definesAt(_, bb1, i1) and - adjacentDefSkipUncertainReads(def, bb1, i1, bb2, i2) and - read = bb2.getNode(i2) - ) + exists(Cfg::BasicBlock bb, int i | Impl::firstUse(def, bb, i, true) and read = bb.getNode(i)) } /** @@ -281,28 +184,14 @@ private module Cached { */ cached predicate adjacentReadPair(Definition def, VarReadAccessCfgNode read1, VarReadAccessCfgNode read2) { - exists(Cfg::BasicBlock bb1, int i1, Cfg::BasicBlock bb2, int i2 | + exists(Cfg::BasicBlock bb1, int i1, Cfg::BasicBlock bb2, int i2, Variable v | + Impl::ssaDefReachesRead(v, def, bb1, i1) and + Impl::adjacentUseUse(bb1, i1, bb2, i2, v, true) and read1 = bb1.getNode(i1) and - variableReadActual(bb1, i1, _) and - adjacentDefSkipUncertainReads(def, bb1, i1, bb2, i2) and read2 = bb2.getNode(i2) ) } - /** - * Holds if the read of `def` at `read` may be a last read. That is, `read` - * can either reach another definition of the underlying source variable or - * the end of the CFG scope, without passing through another non-pseudo read. - */ - cached - predicate lastRead(Definition def, VarReadAccessCfgNode read) { - exists(Cfg::BasicBlock bb, int i | - lastRefSkipUncertainReadsExt(def, bb, i) and - variableReadActual(bb, i, _) and - read = bb.getNode(i) - ) - } - cached Definition uncertainWriteDefinitionInput(UncertainWriteDefinition def) { Impl::uncertainWriteDefinitionInput(def, result) @@ -326,8 +215,14 @@ private module Cached { cached // nothing is actually cached module BarrierGuard { + private predicate guardChecksAdjTypes( + DataFlowIntegrationInput::Guard g, DataFlowIntegrationInput::Expr e, boolean branch + ) { + guardChecks(g, e, branch) + } + private Node getABarrierNodeImpl() { - none() // TODO + result = DataFlowIntegrationImpl::BarrierGuard::getABarrierNode() } predicate getABarrierNode = getABarrierNodeImpl/0; @@ -346,7 +241,7 @@ import Cached * Only intended for internal use. */ class DefinitionExt extends Impl::DefinitionExt { - AstCfgNode getARead() { result = getARead(this) } + VarReadAccessCfgNode getARead() { result = getARead(this) } override string toString() { result = this.(Ssa::Definition).toString() } @@ -367,29 +262,64 @@ class PhiReadNode extends DefinitionExt, Impl::PhiReadNode { /** Gets the SSA definition node corresponding to parameter `p`. */ pragma[nomagic] DefinitionExt getParameterDef(Parameter p) { - exists(Cfg::EntryBasicBlock bb, int i | - parameterWrite(bb, i, p) and - result.definesAt(p, bb, i, _) + exists(Cfg::BasicBlock bb, int i | + bb.getNode(i).getAstNode() = p and + result.definesAt(_, bb, i, _) ) } -private newtype TParameterExt = TNormalParameter(Parameter p) +private Parameter getANonPipelineParameter(FunctionBase f) { + result = f.getAParameter() and + not result instanceof PipelineParameter and + not result instanceof PipelineByPropertyNameParameter +} + +class NormalParameter extends Parameter { + NormalParameter() { + not this instanceof PipelineParameter and + not this instanceof PipelineByPropertyNameParameter + } + + int getIndexExcludingPipelines() { + exists(FunctionBase f | + f = this.getFunction() and + this = + rank[result + 1](int index, Parameter p | + p = getANonPipelineParameter(f) and index = p.getIndex() + | + p order by index + ) + ) + } +} + +private newtype TParameterExt = + TNormalParameter(NormalParameter p) or + TSelfMethodParameter(Method m) /** A normal parameter or an implicit `self` parameter. */ class ParameterExt extends TParameterExt { - Parameter asParameter() { this = TNormalParameter(result) } + NormalParameter asParameter() { this = TNormalParameter(result) } - predicate isInitializedBy(WriteDefinition def) { def = getParameterDef(this.asParameter()) } + Method asThis() { this = TSelfMethodParameter(result) } - string toString() { result = this.asParameter().toString() } + predicate isInitializedBy(WriteDefinition def) { + def = getParameterDef(this.asParameter()) + or + def.(Ssa::ThisDefinition).getSourceVariable().getDeclaringScope() = this.asThis().(Scope) + } + + string toString() { result = [this.asParameter().toString(), this.asThis().toString()] } - Location getLocation() { result = this.asParameter().getLocation() } + Location getLocation() { + result = [this.asParameter().getLocation(), this.asThis().getLocation()] + } } private module DataFlowIntegrationInput implements Impl::DataFlowIntegrationInputSig { class Parameter = ParameterExt; - class Expr extends Cfg::CfgNodes::AstCfgNode { + class Expr extends Cfg::CfgNodes::ExprCfgNode { predicate hasCfgNode(SsaInput::BasicBlock bb, int i) { this = bb.getNode(i) } } @@ -406,9 +336,7 @@ private module DataFlowIntegrationInput implements Impl::DataFlowIntegrationInpu } /** Holds if the guard `guard` controls block `bb` upon evaluating to `branch`. */ - predicate guardControlsBlock(Guard guard, SsaInput::BasicBlock bb, boolean branch) { - none() // TODO - } + predicate guardControlsBlock(Guard guard, SsaInput::BasicBlock bb, boolean branch) { none() } /** Gets an immediate conditional successor of basic block `bb`, if any. */ SsaInput::BasicBlock getAConditionalBasicBlockSuccessor(SsaInput::BasicBlock bb, boolean branch) { diff --git a/powershell/ql/lib/semmle/code/powershell/dataflow/internal/TaintTrackingPrivate.qll b/powershell/ql/lib/semmle/code/powershell/dataflow/internal/TaintTrackingPrivate.qll index 8cc0f0a87223..9c6132c7a291 100644 --- a/powershell/ql/lib/semmle/code/powershell/dataflow/internal/TaintTrackingPrivate.qll +++ b/powershell/ql/lib/semmle/code/powershell/dataflow/internal/TaintTrackingPrivate.qll @@ -41,7 +41,7 @@ private module Cached { ) or // Flow through string interpolation - exists(CfgNodes::ExprNodes::ExpandableStringCfgNode es | + exists(CfgNodes::ExprNodes::ExpandableStringExprCfgNode es | nodeFrom.asExpr() = es.getAnExpr() and nodeTo.asExpr() = es ) diff --git a/powershell/ql/lib/semmle/code/powershell/frameworks/SystemManagementAutomationEngineIntrinsics/EngineIntrinsics.qll b/powershell/ql/lib/semmle/code/powershell/frameworks/SystemManagementAutomationEngineIntrinsics/EngineIntrinsics.qll index 9f856f289495..b22dd618246a 100644 --- a/powershell/ql/lib/semmle/code/powershell/frameworks/SystemManagementAutomationEngineIntrinsics/EngineIntrinsics.qll +++ b/powershell/ql/lib/semmle/code/powershell/frameworks/SystemManagementAutomationEngineIntrinsics/EngineIntrinsics.qll @@ -6,7 +6,7 @@ module EngineIntrinsics { private class EngineIntrinsicsGlobalEntry extends ModelInput::TypeModel { override DataFlow::Node getASource(string type) { type = "System.Management.Automation.EngineIntrinsics" and - result.asExpr().getExpr().(VarReadAccess).getUserPath().toLowerCase() = "executioncontext" + result.asExpr().getExpr().(VarReadAccess).getVariable().getName().toLowerCase() = "executioncontext" } } } diff --git a/powershell/ql/lib/semmle/code/powershell/frameworks/data/ModelsAsData.qll b/powershell/ql/lib/semmle/code/powershell/frameworks/data/ModelsAsData.qll index ddacb7b2d258..d18fdce39242 100644 --- a/powershell/ql/lib/semmle/code/powershell/frameworks/data/ModelsAsData.qll +++ b/powershell/ql/lib/semmle/code/powershell/frameworks/data/ModelsAsData.qll @@ -30,7 +30,7 @@ private class SummarizedCallableFromModel extends SummarizedCallable { this = type + ";" + path } - override Call getACall() { + override CallExpr getACall() { exists(API::MethodAccessNode base | ModelOutput::resolvedSummaryBase(type, path, base) and result = base.asCall().asExpr().getExpr() diff --git a/powershell/ql/lib/semmle/code/powershell/frameworks/data/internal/ApiGraphModelsSpecific.qll b/powershell/ql/lib/semmle/code/powershell/frameworks/data/internal/ApiGraphModelsSpecific.qll index 9bf974f325b1..c2061c238b25 100644 --- a/powershell/ql/lib/semmle/code/powershell/frameworks/data/internal/ApiGraphModelsSpecific.qll +++ b/powershell/ql/lib/semmle/code/powershell/frameworks/data/internal/ApiGraphModelsSpecific.qll @@ -55,27 +55,6 @@ predicate hasImplicitTypeModel(string type, string otherType) { parseType(otherType, type, _) } -pragma[nomagic] -string getConstComponent(string consts, int n) { - parseRelevantType(_, consts, _) and - result = consts.splitAt(".", n) -} - -private int getNumConstComponents(string consts) { - result = strictcount(int n | exists(getConstComponent(consts, n))) -} - -private DataFlow::TypePathNode getConstantFromConstPath(string consts, int n) { - n = 1 and - result.getComponent() = getConstComponent(consts, 0) - or - result = getConstantFromConstPath(consts, n - 1).getConstant(getConstComponent(consts, n - 1)) -} - -private DataFlow::TypePathNode getConstantFromConstPath(string consts) { - result = getConstantFromConstPath(consts, getNumConstComponents(consts)) -} - /** Gets a Powershell-specific interpretation of the `(type, path)` tuple after resolving the first `n` access path tokens. */ bindingset[type, path] API::Node getExtraNodeFromPath(string type, AccessPath path, int n) { @@ -91,15 +70,8 @@ API::Node getExtraNodeFromPath(string type, AccessPath path, int n) { /** Gets a Powershell-specific interpretation of the given `type`. */ API::Node getExtraNodeFromType(string type) { - exists(string consts, string suffix, DataFlow::TypePathNode constRef | - parseRelevantType(type, consts, suffix) and - constRef = getConstantFromConstPath(consts) - | - suffix = "!" and - result = constRef.track() - or - suffix = "" and - result = constRef.track().getInstance() + exists(string consts, string suffix | parseRelevantType(type, consts, suffix) | + none() // TODO ) or type = "" and @@ -187,7 +159,7 @@ predicate invocationMatchesExtraCallSiteFilter(InvokeNode invoke, AccessPathToke /** An API graph node representing a method call. */ class InvokeNode extends API::MethodAccessNode { /** Gets the number of arguments to the call. */ - int getNumArgument() { result = this.asCall().getNumberOfArguments() } + int getNumArgument() { result = count(this.asCall().getAnArgument()) } } /** Gets the `InvokeNode` corresponding to a specific invocation of `node`. */ diff --git a/powershell/ql/lib/semmle/code/powershell/internal/AstEscape.qll b/powershell/ql/lib/semmle/code/powershell/internal/AstEscape.qll index 07148719f31f..7e031d537bdb 100644 --- a/powershell/ql/lib/semmle/code/powershell/internal/AstEscape.qll +++ b/powershell/ql/lib/semmle/code/powershell/internal/AstEscape.qll @@ -47,7 +47,7 @@ module Private { final override Element getAChild() { result = super.getAStmt() } } - private class CmdExprElement extends ElementImpl instanceof PS::CmdExpr { + private class ExprStmtElement extends ElementImpl instanceof PS::ExprStmt { final override T getANode() { result = interpret(super.getExpr()) } final override Element getAChild() { none() } @@ -78,18 +78,6 @@ module Private { private class SwitchStmtElement extends ElementImpl instanceof PS::SwitchStmt { final override Element getAChild() { result = super.getACase() } } - - private class CmdBaseElement extends ElementImpl instanceof PS::CmdExpr { - final override T getANode() { result = interpret(super.getExpr()) } - - final override Element getAChild() { none() } - } - - private class CmdElement extends ElementImpl instanceof PS::Cmd { - final override T getANode() { result = interpret(this) } - - final override Element getAChild() { none() } - } } } diff --git a/powershell/ql/lib/semmle/code/powershell/internal/Internal.qll b/powershell/ql/lib/semmle/code/powershell/internal/Internal.qll deleted file mode 100644 index 853a9a247f52..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/internal/Internal.qll +++ /dev/null @@ -1,13 +0,0 @@ -module Private { - import Parameter::Private - import ExplicitWrite::Private - import Argument::Private - import Operation::Private -} - -module Public { - import Parameter::Public - import ExplicitWrite::Public - import Argument::Public - import Operation::Public -} diff --git a/powershell/ql/lib/semmle/code/powershell/internal/Operation.qll b/powershell/ql/lib/semmle/code/powershell/internal/Operation.qll deleted file mode 100644 index a5e758d10b56..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/internal/Operation.qll +++ /dev/null @@ -1,31 +0,0 @@ -import powershell - -module Private { - abstract private class AbstractOperation extends Expr { - abstract Expr getAnOperand(); - - abstract int getKind(); - } - - class BinaryOperation extends BinaryExpr, AbstractOperation { - final override Expr getAnOperand() { result = BinaryExpr.super.getAnOperand() } - - final override int getKind() { result = BinaryExpr.super.getKind() } - } - - class UnaryOperation extends UnaryExpr, AbstractOperation { - final override Expr getAnOperand() { result = UnaryExpr.super.getOperand() } - - final override int getKind() { result = UnaryExpr.super.getKind() } - } - - final class Operation = AbstractOperation; -} - -module Public { - class Operation = Private::Operation; - - class BinaryOperation = Private::BinaryOperation; - - class UnaryOperation = Private::UnaryOperation; -} diff --git a/powershell/ql/lib/semmle/code/powershell/internal/Parameter.qll b/powershell/ql/lib/semmle/code/powershell/internal/Parameter.qll deleted file mode 100644 index 15f4136e22e9..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/internal/Parameter.qll +++ /dev/null @@ -1,28 +0,0 @@ -import powershell - -module Private { - class Parameter extends @parameter, Ast { - override string toString() { result = this.getName().toString() } - - string getName() { - exists(@variable_expression ve | - parameter(this, ve, _, _) and - variable_expression(ve, result, _, _, _, _, _, _, _, _, _, _) - ) - } - - string getStaticType() { parameter(this, _, result, _) } - - int getNumAttributes() { parameter(this, _, _, result) } - - AttributeBase getAttribute(int i) { parameter_attribute(this, i, result) } - - AttributeBase getAnAttribute() { result = this.getAttribute(_) } - - Expr getDefaultValue() { parameter_default_value(this, result) } - - override SourceLocation getLocation() { parameter_location(this, result) } - } -} - -module Public { } diff --git a/powershell/ql/lib/semmle/code/powershell/typetracking/internal/TypeTrackingImpl.qll b/powershell/ql/lib/semmle/code/powershell/typetracking/internal/TypeTrackingImpl.qll index dcebe6117b54..36a605c25dc7 100644 --- a/powershell/ql/lib/semmle/code/powershell/typetracking/internal/TypeTrackingImpl.qll +++ b/powershell/ql/lib/semmle/code/powershell/typetracking/internal/TypeTrackingImpl.qll @@ -15,7 +15,8 @@ private import codeql.util.Unit pragma[noinline] private predicate sourceArgumentPositionMatch( - CallCfgNode call, DataFlowPrivate::ArgumentNode arg, DataFlowDispatch::ParameterPosition ppos + ExprNodes::CallExprCfgNode call, DataFlowPrivate::ArgumentNode arg, + DataFlowDispatch::ParameterPosition ppos ) { exists(DataFlowDispatch::ArgumentPosition apos | arg.sourceArgumentOf(call, apos) and @@ -213,7 +214,7 @@ module TypeTrackingInput implements Shared::TypeTrackingInput { * Holds if `nodeFrom` steps to `nodeTo` by being returned from a call. */ predicate returnStep(Node nodeFrom, LocalSourceNode nodeTo) { - exists(CallCfgNode call | + exists(ExprNodes::CallExprCfgNode call | nodeFrom instanceof DataFlowPrivate::ReturnNode and nodeFrom.(DataFlowPrivate::NodeImpl).getCfgScope() = DataFlowDispatch::getTarget(DataFlowDispatch::TNormalCall(call)) and diff --git a/powershell/ql/src/experimental/CommandInjection.ql b/powershell/ql/src/experimental/CommandInjection.ql index 695c69a573e4..9f4696533ea9 100644 --- a/powershell/ql/src/experimental/CommandInjection.ql +++ b/powershell/ql/src/experimental/CommandInjection.ql @@ -11,7 +11,7 @@ import powershell predicate containsScope(VarAccess outer, VarAccess inner) { - outer.getUserPath() = inner.getUserPath() and + outer.getVariable().getName() = inner.getVariable().getName() and outer != inner } @@ -23,16 +23,16 @@ predicate constantBinaryExpression(BinaryExpr binary) { onlyConstantExpressions(binary.getLeft()) and onlyConstantExpressions(binary.getRight()) } -predicate onlyConstantExpressions(Expr expr){ - expr instanceof StringConstExpr or constantBinaryExpression(expr) or constantTernaryExpression(expr) +predicate onlyConstantExpressions(Expr expr) { + expr instanceof StringConstExpr or + constantBinaryExpression(expr) or + constantTernaryExpression(expr) } VarAccess getNonConstantVariableAssignment(VarAccess varexpr) { - ( - exists(AssignStmt assignment | - not onlyConstantExpressions(assignment.getRightHandSide().(CmdExpr).getExpr()) and - result = assignment.getLeftHandSide() - ) + exists(AssignStmt assignment | + not onlyConstantExpressions(assignment.getRightHandSide()) and + result = assignment.getLeftHandSide() ) and containsScope(result, varexpr) } @@ -44,31 +44,35 @@ VarAccess getParameterWithVariableScope(VarAccess varexpr) { ) } -Expr getAllSubExpressions(Expr expr) -{ +Expr getAllSubExpressions(Expr expr) { result = expr or - result = getAllSubExpressions(expr.(ArrayLiteral).getAnElement()) or - result = getAllSubExpressions(expr.(ArrayExpr).getStmtBlock().getAStmt().(Pipeline).getAComponent().(CmdExpr).getExpr()) + result = getAllSubExpressions(expr.(ArrayLiteral).getAnExpr()) or + result = + getAllSubExpressions(expr.(ArrayExpr) + .getStmtBlock() + .getAStmt() + .(ExprStmt) + .getExpr() + .(Pipeline) + .getAComponent()) } -Expr dangerousCommandElement(Cmd command) -{ +Expr dangerousCommandElement(CallExpr command) { ( - command.getKind() = 28 or - command.getCommandName() = "Invoke-Expression" + command instanceof CallOperator or + command.getName() = "Invoke-Expression" ) and result = getAllSubExpressions(command.getAnArgument()) } from Expr commandarg, VarAccess unknownDeclaration where - exists(Cmd command | + exists(CallExpr command | ( unknownDeclaration = getNonConstantVariableAssignment(commandarg) or unknownDeclaration = getParameterWithVariableScope(commandarg) - ) - and + ) and commandarg = dangerousCommandElement(command) ) select commandarg.(VarAccess).getLocation(), "Unsafe flow to command argument from $@.", - unknownDeclaration, unknownDeclaration.getUserPath() + unknownDeclaration, unknownDeclaration.getVariable().getName() diff --git a/powershell/ql/test/TestUtilities/InlineFlowTestUtil.qll b/powershell/ql/test/TestUtilities/InlineFlowTestUtil.qll index 0712a6500344..96fe15ea7a96 100644 --- a/powershell/ql/test/TestUtilities/InlineFlowTestUtil.qll +++ b/powershell/ql/test/TestUtilities/InlineFlowTestUtil.qll @@ -6,19 +6,19 @@ import powershell import semmle.code.powershell.dataflow.DataFlow predicate defaultSource(DataFlow::Node src) { - src.asStmt().getStmt().(Cmd).getCommandName() = ["Source", "Taint"] + src.asExpr().getExpr().(CmdCall).getName() = ["Source", "Taint"] or src.asParameter().getName().matches(["Source%", "Taint%"]) } predicate defaultSink(DataFlow::Node sink) { - exists(Cmd cmd | cmd.getCommandName() = "Sink" | sink.asExpr().getExpr() = cmd.getAnArgument()) + exists(CmdCall cmd | cmd.getName() = "Sink" | sink.asExpr().getExpr() = cmd.getAnArgument()) } string getSourceArgString(DataFlow::Node src) { defaultSource(src) and ( - src.asStmt().getStmt().(Cmd).getAnArgument().(StringConstExpr).getValue().getValue() = result + src.asExpr().getExpr().(CmdCall).getAnArgument().(StringConstExpr).getValue().getValue() = result or src.asParameter().getName().regexpCapture(["Source(.+)", "Taint(.+)"], 1) = result ) diff --git a/powershell/ql/test/library-tests/ast/Arrays/arrays.expected b/powershell/ql/test/library-tests/ast/Arrays/arrays.expected index 1c50d2710a1b..9830fe986bd6 100644 --- a/powershell/ql/test/library-tests/ast/Arrays/arrays.expected +++ b/powershell/ql/test/library-tests/ast/Arrays/arrays.expected @@ -1,23 +1,23 @@ arrayExpr -| Arrays.ps1:11:11:11:25 | @(...) | Arrays.ps1:11:13:11:24 | {...} | -| Arrays.ps1:14:41:14:44 | @(...) | Arrays.ps1:0:0:0:0 | {...} | +| Arrays.ps1:11:11:11:24 | @(...) | Arrays.ps1:11:13:11:23 | {...} | +| Arrays.ps1:14:41:14:43 | @(...) | Arrays.ps1:0:0:0:-1 | {...} | arrayLiteral -| Arrays.ps1:1:11:1:37 | ...,... | 0 | Arrays.ps1:1:11:1:12 | 1 | -| Arrays.ps1:1:11:1:37 | ...,... | 1 | Arrays.ps1:1:13:1:14 | 2 | -| Arrays.ps1:1:11:1:37 | ...,... | 2 | Arrays.ps1:1:15:1:18 | a | -| Arrays.ps1:1:11:1:37 | ...,... | 3 | Arrays.ps1:1:19:1:24 | true | -| Arrays.ps1:1:11:1:37 | ...,... | 4 | Arrays.ps1:1:25:1:31 | false | -| Arrays.ps1:1:11:1:37 | ...,... | 5 | Arrays.ps1:1:32:1:37 | null | -| Arrays.ps1:5:34:5:37 | ...,... | 0 | Arrays.ps1:5:34:5:35 | 2 | -| Arrays.ps1:5:34:5:37 | ...,... | 1 | Arrays.ps1:5:36:5:37 | 2 | -| Arrays.ps1:6:9:6:12 | ...,... | 0 | Arrays.ps1:6:9:6:10 | 0 | -| Arrays.ps1:6:9:6:12 | ...,... | 1 | Arrays.ps1:6:11:6:12 | 0 | -| Arrays.ps1:7:9:7:12 | ...,... | 0 | Arrays.ps1:7:9:7:10 | 1 | -| Arrays.ps1:7:9:7:12 | ...,... | 1 | Arrays.ps1:7:11:7:12 | 0 | -| Arrays.ps1:8:9:8:12 | ...,... | 0 | Arrays.ps1:8:9:8:10 | 0 | -| Arrays.ps1:8:9:8:12 | ...,... | 1 | Arrays.ps1:8:11:8:12 | 1 | -| Arrays.ps1:9:9:9:12 | ...,... | 0 | Arrays.ps1:9:9:9:10 | 1 | -| Arrays.ps1:9:9:9:12 | ...,... | 1 | Arrays.ps1:9:11:9:12 | 1 | -| Arrays.ps1:11:13:11:24 | ...,... | 0 | Arrays.ps1:11:13:11:16 | a | -| Arrays.ps1:11:13:11:24 | ...,... | 1 | Arrays.ps1:11:17:11:20 | b | -| Arrays.ps1:11:13:11:24 | ...,... | 2 | Arrays.ps1:11:21:11:24 | c | +| Arrays.ps1:1:11:1:36 | ...,... | 0 | Arrays.ps1:1:11:1:11 | 1 | +| Arrays.ps1:1:11:1:36 | ...,... | 1 | Arrays.ps1:1:13:1:13 | 2 | +| Arrays.ps1:1:11:1:36 | ...,... | 2 | Arrays.ps1:1:15:1:17 | a | +| Arrays.ps1:1:11:1:36 | ...,... | 3 | Arrays.ps1:1:19:1:23 | true | +| Arrays.ps1:1:11:1:36 | ...,... | 4 | Arrays.ps1:1:25:1:30 | false | +| Arrays.ps1:1:11:1:36 | ...,... | 5 | Arrays.ps1:1:32:1:36 | null | +| Arrays.ps1:5:34:5:36 | ...,... | 0 | Arrays.ps1:5:34:5:34 | 2 | +| Arrays.ps1:5:34:5:36 | ...,... | 1 | Arrays.ps1:5:36:5:36 | 2 | +| Arrays.ps1:6:9:6:11 | ...,... | 0 | Arrays.ps1:6:9:6:9 | 0 | +| Arrays.ps1:6:9:6:11 | ...,... | 1 | Arrays.ps1:6:11:6:11 | 0 | +| Arrays.ps1:7:9:7:11 | ...,... | 0 | Arrays.ps1:7:9:7:9 | 1 | +| Arrays.ps1:7:9:7:11 | ...,... | 1 | Arrays.ps1:7:11:7:11 | 0 | +| Arrays.ps1:8:9:8:11 | ...,... | 0 | Arrays.ps1:8:9:8:9 | 0 | +| Arrays.ps1:8:9:8:11 | ...,... | 1 | Arrays.ps1:8:11:8:11 | 1 | +| Arrays.ps1:9:9:9:11 | ...,... | 0 | Arrays.ps1:9:9:9:9 | 1 | +| Arrays.ps1:9:9:9:11 | ...,... | 1 | Arrays.ps1:9:11:9:11 | 1 | +| Arrays.ps1:11:13:11:23 | ...,... | 0 | Arrays.ps1:11:13:11:15 | a | +| Arrays.ps1:11:13:11:23 | ...,... | 1 | Arrays.ps1:11:17:11:19 | b | +| Arrays.ps1:11:13:11:23 | ...,... | 2 | Arrays.ps1:11:21:11:23 | c | diff --git a/powershell/ql/test/library-tests/ast/Arrays/arrays.ql b/powershell/ql/test/library-tests/ast/Arrays/arrays.ql index 087ee78e4ef9..3eaaa38503f5 100644 --- a/powershell/ql/test/library-tests/ast/Arrays/arrays.ql +++ b/powershell/ql/test/library-tests/ast/Arrays/arrays.ql @@ -3,5 +3,5 @@ import powershell query predicate arrayExpr(ArrayExpr arrayExpr, StmtBlock subExpr) { subExpr = arrayExpr.getStmtBlock() } query predicate arrayLiteral(ArrayLiteral arrayLiteral, int i, Expr e) { - e = arrayLiteral.getElement(i) + e = arrayLiteral.getExpr(i) } diff --git a/powershell/ql/test/library-tests/ast/Blocks/blocks.expected b/powershell/ql/test/library-tests/ast/Blocks/blocks.expected index 1d23ed850efe..0d4882c4c417 100644 --- a/powershell/ql/test/library-tests/ast/Blocks/blocks.expected +++ b/powershell/ql/test/library-tests/ast/Blocks/blocks.expected @@ -1 +1,2 @@ -| ParamBlock.ps1:2:1:5:2 | param(...) | 0 | ParamBlock.ps1:3:5:4:23 | Parameter | +| ParamBlock.ps1:1:1:5:1 | {...} | 0 | ParamBlock.ps1:1:1:5:1 | Parameter | +| ParamBlock.ps1:1:1:5:1 | {...} | 1 | ParamBlock.ps1:1:1:5:1 | [synth] pipeline | diff --git a/powershell/ql/test/library-tests/ast/Blocks/blocks.ql b/powershell/ql/test/library-tests/ast/Blocks/blocks.ql index 9c4288d35601..6140e96a2058 100644 --- a/powershell/ql/test/library-tests/ast/Blocks/blocks.ql +++ b/powershell/ql/test/library-tests/ast/Blocks/blocks.ql @@ -1,5 +1,5 @@ import powershell -query predicate paramBlockHasParam(ParamBlock block, int i, Parameter p) { +query predicate paramBlockHasParam(ScriptBlock block, int i, Parameter p) { p = block.getParameter(i) } \ No newline at end of file diff --git a/powershell/ql/test/library-tests/ast/Expressions/expressions.expected b/powershell/ql/test/library-tests/ast/Expressions/expressions.expected index 30aabf5cb277..7deaa7795dd4 100644 --- a/powershell/ql/test/library-tests/ast/Expressions/expressions.expected +++ b/powershell/ql/test/library-tests/ast/Expressions/expressions.expected @@ -1,19 +1,15 @@ binaryExpr -| BinaryExpression.ps1:3:11:3:24 | ...+... | BinaryExpression.ps1:3:11:3:16 | val1 | BinaryExpression.ps1:3:19:3:24 | val2 | -| TernaryExpression.ps1:1:9:1:16 | ... -gt ... | TernaryExpression.ps1:1:9:1:10 | 6 | TernaryExpression.ps1:1:15:1:16 | 7 | +| BinaryExpression.ps1:3:11:3:23 | ...+... | BinaryExpression.ps1:3:11:3:15 | val1 | BinaryExpression.ps1:3:19:3:23 | val2 | +| TernaryExpression.ps1:1:9:1:15 | ... -gt ... | TernaryExpression.ps1:1:9:1:9 | 6 | TernaryExpression.ps1:1:15:1:15 | 7 | cmdExpr -| BinaryExpression.ps1:1:9:1:10 | 1 | BinaryExpression.ps1:1:9:1:10 | 1 | -| BinaryExpression.ps1:2:9:2:10 | 2 | BinaryExpression.ps1:2:9:2:10 | 2 | -| BinaryExpression.ps1:3:11:3:24 | ...+... | BinaryExpression.ps1:3:11:3:24 | ...+... | -| BinaryExpression.ps1:4:1:4:8 | result | BinaryExpression.ps1:4:1:4:8 | result | -| ExpandableString.ps1:1:1:1:40 | Date: $([DateTime]::Now)\nName: $name | ExpandableString.ps1:1:1:1:40 | Date: $([DateTime]::Now)\nName: $name | -| ExpandableString.ps1:1:23:1:38 | Now | ExpandableString.ps1:1:23:1:38 | Now | -| SubExpression.ps1:1:1:1:24 | call to AddDays | SubExpression.ps1:1:1:1:24 | call to AddDays | -| SubExpression.ps1:2:1:2:22 | call to AddDays | SubExpression.ps1:2:1:2:22 | call to AddDays | -| TernaryExpression.ps1:1:8:1:23 | ...?...:... | TernaryExpression.ps1:1:8:1:23 | ...?...:... | -| TernaryExpression.ps1:1:9:1:16 | ... -gt ... | TernaryExpression.ps1:1:9:1:16 | ... -gt ... | +| BinaryExpression.ps1:4:1:4:7 | [Stmt] result | BinaryExpression.ps1:4:1:4:7 | result | +| ExpandableString.ps1:1:1:1:39 | [Stmt] Date: $([DateTime]::Now)\nName: $name | ExpandableString.ps1:1:1:1:39 | Date: $([DateTime]::Now)\nName: $name | +| ExpandableString.ps1:1:23:1:37 | [Stmt] Now | ExpandableString.ps1:1:23:1:37 | Now | +| SubExpression.ps1:1:1:1:23 | [Stmt] Call to AddDays | SubExpression.ps1:1:1:1:23 | Call to AddDays | +| SubExpression.ps1:1:3:1:10 | [Stmt] Call to Get-Date | SubExpression.ps1:1:3:1:10 | Call to Get-Date | +| SubExpression.ps1:2:1:2:21 | [Stmt] Call to AddDays | SubExpression.ps1:2:1:2:21 | Call to AddDays | +| SubExpression.ps1:2:3:2:10 | [Stmt] Call to Get-Date | SubExpression.ps1:2:3:2:10 | Call to Get-Date | invokeMemoryExpression -| SubExpression.ps1:1:1:1:24 | call to AddDays | SubExpression.ps1:1:1:1:12 | $(...) | 0 | SubExpression.ps1:1:21:1:23 | 10 | +| SubExpression.ps1:1:1:1:23 | Call to AddDays | SubExpression.ps1:1:1:1:11 | $(...) | 0 | SubExpression.ps1:1:21:1:22 | 10 | expandableString -| ExpandableString.ps1:1:1:1:40 | Date: $([DateTime]::Now)\nName: $name | 0 | ExpandableString.ps1:1:8:1:13 | name | -| ExpandableString.ps1:1:1:1:40 | Date: $([DateTime]::Now)\nName: $name | 1 | ExpandableString.ps1:1:21:1:39 | $(...) | +| ExpandableString.ps1:1:1:1:39 | Date: $([DateTime]::Now)\nName: $name | 1 | ExpandableString.ps1:1:21:1:38 | $(...) | diff --git a/powershell/ql/test/library-tests/ast/Expressions/expressions.ql b/powershell/ql/test/library-tests/ast/Expressions/expressions.ql index 6f3064f5c40c..2583cdef4b81 100644 --- a/powershell/ql/test/library-tests/ast/Expressions/expressions.ql +++ b/powershell/ql/test/library-tests/ast/Expressions/expressions.ql @@ -5,8 +5,8 @@ query predicate binaryExpr(BinaryExpr e, Expr e1, Expr e2) { e2 = e.getRight() } -query predicate cmdExpr(CmdExpr cmd, Expr e) { - e = cmd.getExpr() +query predicate cmdExpr(ExprStmt exprStmt, Expr e) { + e = exprStmt.getExpr() } query predicate invokeMemoryExpression(InvokeMemberExpr invoke, Expr e, int i, Expr arg) { diff --git a/powershell/ql/test/library-tests/ast/Loops/loops.expected b/powershell/ql/test/library-tests/ast/Loops/loops.expected index 503d8894a46a..0015ed68b0d0 100644 --- a/powershell/ql/test/library-tests/ast/Loops/loops.expected +++ b/powershell/ql/test/library-tests/ast/Loops/loops.expected @@ -1,6 +1,6 @@ doUntil -| DoUntil.ps1:1:1:7:19 | DoUntil | DoUntil.ps1:7:10:7:18 | ... -le ... | DoUntil.ps1:2:1:7:2 | {...} | +| DoUntil.ps1:1:1:7:18 | do...until... | DoUntil.ps1:7:10:7:17 | ... -le ... | DoUntil.ps1:2:1:7:1 | {...} | doWhile -| DoWhile.ps1:1:1:7:19 | DoWhile | DoWhile.ps1:7:10:7:18 | ... -le ... | DoWhile.ps1:2:1:7:2 | {...} | +| DoWhile.ps1:1:1:7:18 | do...while... | DoWhile.ps1:7:10:7:17 | ... -le ... | DoWhile.ps1:2:1:7:1 | {...} | while -| While.ps1:2:1:13:2 | while(...) {...} | While.ps1:2:8:2:18 | ... -le ... | While.ps1:3:1:13:2 | {...} | +| While.ps1:2:1:13:1 | while(...) {...} | While.ps1:2:8:2:17 | ... -le ... | While.ps1:3:1:13:1 | {...} | diff --git a/powershell/ql/test/library-tests/ast/Loops/loops.ql b/powershell/ql/test/library-tests/ast/Loops/loops.ql index 55c750da7cb6..1a4e3d678110 100644 --- a/powershell/ql/test/library-tests/ast/Loops/loops.ql +++ b/powershell/ql/test/library-tests/ast/Loops/loops.ql @@ -1,16 +1,16 @@ import powershell -query predicate doUntil(DoUntilStmt s, PipelineBase e, StmtBlock body) { +query predicate doUntil(DoUntilStmt s, Expr e, StmtBlock body) { e = s.getCondition() and body = s.getBody() } -query predicate doWhile(DoWhileStmt s, PipelineBase e, StmtBlock body) { +query predicate doWhile(DoWhileStmt s, Expr e, StmtBlock body) { e = s.getCondition() and body = s.getBody() } -query predicate while(WhileStmt s, PipelineBase e, StmtBlock body) { +query predicate while(WhileStmt s, Expr e, StmtBlock body) { e = s.getCondition() and body = s.getBody() } diff --git a/powershell/ql/test/library-tests/ast/Redirections/redirections.expected b/powershell/ql/test/library-tests/ast/Redirections/redirections.expected index 968fcee62ee2..c48b8b8df703 100644 --- a/powershell/ql/test/library-tests/ast/Redirections/redirections.expected +++ b/powershell/ql/test/library-tests/ast/Redirections/redirections.expected @@ -1,2 +1,2 @@ -| FileRedirection.ps1:3:3:3:7 | MergingRedirection | -| FileRedirection.ps1:3:8:3:20 | FileRedirection | +| FileRedirection.ps1:3:3:3:6 | MergingRedirection | +| FileRedirection.ps1:3:8:3:19 | FileRedirection | diff --git a/powershell/ql/test/library-tests/ast/Statements/statements.expected b/powershell/ql/test/library-tests/ast/Statements/statements.expected index 52cf8de5795b..f8994f476941 100644 --- a/powershell/ql/test/library-tests/ast/Statements/statements.expected +++ b/powershell/ql/test/library-tests/ast/Statements/statements.expected @@ -1,24 +1,25 @@ -| ExitStatement.ps1:1:1:1:8 | exit ... | -| ExitStatement.ps1:1:6:1:8 | -1 | -| IfStatement.ps1:1:1:1:7 | ...=... | -| IfStatement.ps1:1:6:1:7 | 4 | -| IfStatement.ps1:3:1:8:2 | if (...) {...} else {...} | -| IfStatement.ps1:3:5:3:13 | ... -ge ... | -| IfStatement.ps1:4:2:4:36 | $x is greater than or equal to 3 | -| IfStatement.ps1:7:2:7:21 | $x is less than 3 | -| TrapStatement.ps1:1:1:4:2 | TrapTest | -| TrapStatement.ps1:2:5:2:26 | TrapStatement at: TrapStatement.ps1:2:5:2:26 | -| TrapStatement.ps1:2:11:2:25 | Error found. | -| TrapStatement.ps1:3:5:3:19 | call to nonsenseString | -| TrapStatement.ps1:6:1:6:9 | call to TrapTest | -| Try.ps1:1:1:13:2 | try {...} | -| Try.ps1:2:4:2:95 | ...=... | -| Try.ps1:2:17:2:95 | call to New-Object | -| Try.ps1:2:69:2:94 | ...,... | -| Try.ps1:3:5:3:21 | throw ... | -| Try.ps1:3:11:3:21 | Exception | -| Try.ps1:6:5:6:64 | Unable to download MyDoc.doc from http://www.contoso.com. | -| Try.ps1:9:5:9:52 | An error occurred that could not be resolved. | -| Try.ps1:12:5:12:37 | The finally block is executed. | -| UseProcessBlockForPipelineCommand.ps1:1:1:11:2 | Get-Number | -| UseProcessBlockForPipelineCommand.ps1:10:5:10:12 | Number | +| ExitStatement.ps1:1:1:1:7 | exit ... | +| IfStatement.ps1:1:1:1:6 | ...=... | +| IfStatement.ps1:3:1:8:1 | [Stmt] if (...) {...} else {...} | +| IfStatement.ps1:3:15:5:1 | {...} | +| IfStatement.ps1:4:2:4:35 | [Stmt] $x is greater than or equal to 3 | +| IfStatement.ps1:6:6:8:1 | {...} | +| IfStatement.ps1:7:2:7:20 | [Stmt] $x is less than 3 | +| TrapStatement.ps1:1:1:4:1 | def of TrapTest | +| TrapStatement.ps1:2:5:2:25 | trap {...} | +| TrapStatement.ps1:2:10:2:25 | {...} | +| TrapStatement.ps1:2:11:2:24 | [Stmt] Error found. | +| TrapStatement.ps1:3:5:3:18 | [Stmt] Call to nonsenseString | +| TrapStatement.ps1:6:1:6:8 | [Stmt] Call to TrapTest | +| Try.ps1:1:1:13:1 | try {...} | +| Try.ps1:1:5:4:1 | {...} | +| Try.ps1:2:4:2:94 | ...=... | +| Try.ps1:3:5:3:20 | throw ... | +| Try.ps1:5:57:7:1 | {...} | +| Try.ps1:6:5:6:63 | [Stmt] Unable to download MyDoc.doc from http://www.contoso.com. | +| Try.ps1:8:7:10:1 | {...} | +| Try.ps1:9:5:9:51 | [Stmt] An error occurred that could not be resolved. | +| Try.ps1:11:9:13:1 | {...} | +| Try.ps1:12:5:12:36 | [Stmt] The finally block is executed. | +| UseProcessBlockForPipelineCommand.ps1:1:1:11:1 | def of Get-Number | +| UseProcessBlockForPipelineCommand.ps1:10:5:10:11 | [Stmt] Number | diff --git a/powershell/ql/test/library-tests/ast/parent.expected b/powershell/ql/test/library-tests/ast/parent.expected index 61bba880ae0a..13a4da5ff1c0 100644 --- a/powershell/ql/test/library-tests/ast/parent.expected +++ b/powershell/ql/test/library-tests/ast/parent.expected @@ -1,385 +1,388 @@ -| Arrays/Arrays.ps1:0:0:0:0 | {...} | Arrays/Arrays.ps1:14:41:14:44 | @(...) | -| Arrays/Arrays.ps1:1:1:1:8 | array1 | Arrays/Arrays.ps1:1:1:1:37 | ...=... | -| Arrays/Arrays.ps1:1:1:1:37 | ...=... | Arrays/Arrays.ps1:1:1:15:15 | {...} | -| Arrays/Arrays.ps1:1:1:15:15 | {...} | Arrays/Arrays.ps1:1:1:15:15 | Arrays.ps1 | -| Arrays/Arrays.ps1:1:11:1:12 | 1 | Arrays/Arrays.ps1:1:11:1:37 | ...,... | -| Arrays/Arrays.ps1:1:11:1:37 | ...,... | Arrays/Arrays.ps1:1:1:1:37 | ...=... | -| Arrays/Arrays.ps1:1:11:1:37 | ...,... | Arrays/Arrays.ps1:1:11:1:37 | ...,... | -| Arrays/Arrays.ps1:1:13:1:14 | 2 | Arrays/Arrays.ps1:1:11:1:37 | ...,... | -| Arrays/Arrays.ps1:1:15:1:18 | a | Arrays/Arrays.ps1:1:11:1:37 | ...,... | -| Arrays/Arrays.ps1:1:19:1:24 | true | Arrays/Arrays.ps1:1:11:1:37 | ...,... | -| Arrays/Arrays.ps1:1:25:1:31 | false | Arrays/Arrays.ps1:1:11:1:37 | ...,... | -| Arrays/Arrays.ps1:1:32:1:37 | null | Arrays/Arrays.ps1:1:11:1:37 | ...,... | -| Arrays/Arrays.ps1:2:1:2:8 | array1 | Arrays/Arrays.ps1:2:1:2:11 | ...[...] | -| Arrays/Arrays.ps1:2:1:2:11 | ...[...] | Arrays/Arrays.ps1:2:1:2:15 | ...=... | -| Arrays/Arrays.ps1:2:1:2:15 | ...=... | Arrays/Arrays.ps1:1:1:15:15 | {...} | -| Arrays/Arrays.ps1:2:9:2:10 | 1 | Arrays/Arrays.ps1:2:1:2:11 | ...[...] | -| Arrays/Arrays.ps1:2:14:2:15 | 3 | Arrays/Arrays.ps1:2:1:2:15 | ...=... | -| Arrays/Arrays.ps1:2:14:2:15 | 3 | Arrays/Arrays.ps1:2:14:2:15 | 3 | -| Arrays/Arrays.ps1:3:1:3:8 | array1 | Arrays/Arrays.ps1:3:1:3:11 | ...[...] | -| Arrays/Arrays.ps1:3:1:3:11 | ...[...] | Arrays/Arrays.ps1:3:1:3:17 | ...=... | -| Arrays/Arrays.ps1:3:1:3:17 | ...=... | Arrays/Arrays.ps1:1:1:15:15 | {...} | -| Arrays/Arrays.ps1:3:9:3:10 | 2 | Arrays/Arrays.ps1:3:1:3:11 | ...[...] | -| Arrays/Arrays.ps1:3:14:3:17 | b | Arrays/Arrays.ps1:3:1:3:17 | ...=... | -| Arrays/Arrays.ps1:3:14:3:17 | b | Arrays/Arrays.ps1:3:14:3:17 | b | -| Arrays/Arrays.ps1:5:1:5:8 | array2 | Arrays/Arrays.ps1:5:1:5:37 | ...=... | -| Arrays/Arrays.ps1:5:1:5:37 | ...=... | Arrays/Arrays.ps1:1:1:15:15 | {...} | -| Arrays/Arrays.ps1:5:11:5:21 | New-Object | Arrays/Arrays.ps1:5:11:5:37 | call to New-Object | -| Arrays/Arrays.ps1:5:11:5:37 | call to New-Object | Arrays/Arrays.ps1:5:1:5:37 | ...=... | -| Arrays/Arrays.ps1:5:22:5:33 | object[,] | Arrays/Arrays.ps1:5:11:5:37 | call to New-Object | -| Arrays/Arrays.ps1:5:34:5:35 | 2 | Arrays/Arrays.ps1:5:34:5:37 | ...,... | -| Arrays/Arrays.ps1:5:34:5:37 | ...,... | Arrays/Arrays.ps1:5:11:5:37 | call to New-Object | -| Arrays/Arrays.ps1:5:36:5:37 | 2 | Arrays/Arrays.ps1:5:34:5:37 | ...,... | -| Arrays/Arrays.ps1:6:1:6:8 | array2 | Arrays/Arrays.ps1:6:1:6:13 | ...[...] | -| Arrays/Arrays.ps1:6:1:6:13 | ...[...] | Arrays/Arrays.ps1:6:1:6:22 | ...=... | -| Arrays/Arrays.ps1:6:1:6:22 | ...=... | Arrays/Arrays.ps1:1:1:15:15 | {...} | -| Arrays/Arrays.ps1:6:9:6:10 | 0 | Arrays/Arrays.ps1:6:9:6:12 | ...,... | -| Arrays/Arrays.ps1:6:9:6:12 | ...,... | Arrays/Arrays.ps1:6:1:6:13 | ...[...] | -| Arrays/Arrays.ps1:6:11:6:12 | 0 | Arrays/Arrays.ps1:6:9:6:12 | ...,... | -| Arrays/Arrays.ps1:6:16:6:22 | key1 | Arrays/Arrays.ps1:6:1:6:22 | ...=... | -| Arrays/Arrays.ps1:6:16:6:22 | key1 | Arrays/Arrays.ps1:6:16:6:22 | key1 | -| Arrays/Arrays.ps1:7:1:7:8 | array2 | Arrays/Arrays.ps1:7:1:7:13 | ...[...] | -| Arrays/Arrays.ps1:7:1:7:13 | ...[...] | Arrays/Arrays.ps1:7:1:7:22 | ...=... | -| Arrays/Arrays.ps1:7:1:7:22 | ...=... | Arrays/Arrays.ps1:1:1:15:15 | {...} | -| Arrays/Arrays.ps1:7:9:7:10 | 1 | Arrays/Arrays.ps1:7:9:7:12 | ...,... | -| Arrays/Arrays.ps1:7:9:7:12 | ...,... | Arrays/Arrays.ps1:7:1:7:13 | ...[...] | -| Arrays/Arrays.ps1:7:11:7:12 | 0 | Arrays/Arrays.ps1:7:9:7:12 | ...,... | -| Arrays/Arrays.ps1:7:16:7:22 | key1 | Arrays/Arrays.ps1:7:1:7:22 | ...=... | -| Arrays/Arrays.ps1:7:16:7:22 | key1 | Arrays/Arrays.ps1:7:16:7:22 | key1 | -| Arrays/Arrays.ps1:8:1:8:8 | array2 | Arrays/Arrays.ps1:8:1:8:13 | ...[...] | -| Arrays/Arrays.ps1:8:1:8:13 | ...[...] | Arrays/Arrays.ps1:8:1:8:24 | ...=... | -| Arrays/Arrays.ps1:8:1:8:24 | ...=... | Arrays/Arrays.ps1:1:1:15:15 | {...} | -| Arrays/Arrays.ps1:8:9:8:10 | 0 | Arrays/Arrays.ps1:8:9:8:12 | ...,... | -| Arrays/Arrays.ps1:8:9:8:12 | ...,... | Arrays/Arrays.ps1:8:1:8:13 | ...[...] | -| Arrays/Arrays.ps1:8:11:8:12 | 1 | Arrays/Arrays.ps1:8:9:8:12 | ...,... | -| Arrays/Arrays.ps1:8:16:8:24 | value1 | Arrays/Arrays.ps1:8:1:8:24 | ...=... | -| Arrays/Arrays.ps1:8:16:8:24 | value1 | Arrays/Arrays.ps1:8:16:8:24 | value1 | -| Arrays/Arrays.ps1:9:1:9:8 | array2 | Arrays/Arrays.ps1:9:1:9:13 | ...[...] | -| Arrays/Arrays.ps1:9:1:9:13 | ...[...] | Arrays/Arrays.ps1:9:1:9:21 | ...=... | -| Arrays/Arrays.ps1:9:1:9:21 | ...=... | Arrays/Arrays.ps1:1:1:15:15 | {...} | -| Arrays/Arrays.ps1:9:9:9:10 | 1 | Arrays/Arrays.ps1:9:9:9:12 | ...,... | -| Arrays/Arrays.ps1:9:9:9:12 | ...,... | Arrays/Arrays.ps1:9:1:9:13 | ...[...] | -| Arrays/Arrays.ps1:9:11:9:12 | 1 | Arrays/Arrays.ps1:9:9:9:12 | ...,... | -| Arrays/Arrays.ps1:9:16:9:21 | null | Arrays/Arrays.ps1:9:1:9:21 | ...=... | -| Arrays/Arrays.ps1:9:16:9:21 | null | Arrays/Arrays.ps1:9:16:9:21 | null | -| Arrays/Arrays.ps1:11:1:11:8 | array3 | Arrays/Arrays.ps1:11:1:11:25 | ...=... | -| Arrays/Arrays.ps1:11:1:11:25 | ...=... | Arrays/Arrays.ps1:1:1:15:15 | {...} | -| Arrays/Arrays.ps1:11:11:11:25 | @(...) | Arrays/Arrays.ps1:11:1:11:25 | ...=... | -| Arrays/Arrays.ps1:11:11:11:25 | @(...) | Arrays/Arrays.ps1:11:11:11:25 | @(...) | -| Arrays/Arrays.ps1:11:13:11:16 | a | Arrays/Arrays.ps1:11:13:11:24 | ...,... | -| Arrays/Arrays.ps1:11:13:11:24 | ...,... | Arrays/Arrays.ps1:11:13:11:24 | ...,... | -| Arrays/Arrays.ps1:11:13:11:24 | ...,... | Arrays/Arrays.ps1:11:13:11:24 | {...} | -| Arrays/Arrays.ps1:11:13:11:24 | {...} | Arrays/Arrays.ps1:11:11:11:25 | @(...) | -| Arrays/Arrays.ps1:11:17:11:20 | b | Arrays/Arrays.ps1:11:13:11:24 | ...,... | -| Arrays/Arrays.ps1:11:21:11:24 | c | Arrays/Arrays.ps1:11:13:11:24 | ...,... | -| Arrays/Arrays.ps1:12:1:12:8 | array3 | Arrays/Arrays.ps1:12:1:12:14 | count | -| Arrays/Arrays.ps1:12:1:12:14 | count | Arrays/Arrays.ps1:1:1:15:15 | {...} | -| Arrays/Arrays.ps1:12:1:12:14 | count | Arrays/Arrays.ps1:12:1:12:14 | count | -| Arrays/Arrays.ps1:12:9:12:14 | count | Arrays/Arrays.ps1:12:1:12:14 | count | -| Arrays/Arrays.ps1:14:1:14:8 | array4 | Arrays/Arrays.ps1:14:1:14:44 | ...=... | -| Arrays/Arrays.ps1:14:1:14:44 | ...=... | Arrays/Arrays.ps1:1:1:15:15 | {...} | -| Arrays/Arrays.ps1:14:11:14:41 | System.Collections.ArrayList | Arrays/Arrays.ps1:14:11:14:44 | [...]... | -| Arrays/Arrays.ps1:14:11:14:44 | [...]... | Arrays/Arrays.ps1:14:1:14:44 | ...=... | -| Arrays/Arrays.ps1:14:11:14:44 | [...]... | Arrays/Arrays.ps1:14:11:14:44 | [...]... | -| Arrays/Arrays.ps1:14:41:14:44 | @(...) | Arrays/Arrays.ps1:14:11:14:44 | [...]... | -| Arrays/Arrays.ps1:15:1:15:8 | array4 | Arrays/Arrays.ps1:15:1:15:15 | call to Add | -| Arrays/Arrays.ps1:15:1:15:15 | call to Add | Arrays/Arrays.ps1:1:1:15:15 | {...} | -| Arrays/Arrays.ps1:15:1:15:15 | call to Add | Arrays/Arrays.ps1:15:1:15:15 | call to Add | -| Arrays/Arrays.ps1:15:9:15:12 | Add | Arrays/Arrays.ps1:15:1:15:15 | call to Add | -| Arrays/Arrays.ps1:15:13:15:14 | 1 | Arrays/Arrays.ps1:15:1:15:15 | call to Add | -| Blocks/ParamBlock.ps1:1:1:1:18 | CmdletBinding | Blocks/ParamBlock.ps1:2:1:5:2 | param(...) | -| Blocks/ParamBlock.ps1:2:1:5:2 | param(...) | Blocks/ParamBlock.ps1:1:1:5:2 | ParamBlock.ps1 | -| Blocks/ParamBlock.ps1:2:1:5:2 | {...} | Blocks/ParamBlock.ps1:1:1:5:2 | ParamBlock.ps1 | -| Blocks/ParamBlock.ps1:3:5:3:18 | Parameter | Blocks/ParamBlock.ps1:3:5:4:23 | Parameter | -| Blocks/ParamBlock.ps1:3:5:4:23 | Parameter | Blocks/ParamBlock.ps1:2:1:5:2 | param(...) | -| Blocks/ParamBlock.ps1:4:5:4:13 | string | Blocks/ParamBlock.ps1:3:5:4:23 | Parameter | -| Dynamic/DynamicExecution.ps1:1:1:1:5 | foo | Dynamic/DynamicExecution.ps1:1:1:1:17 | ...=... | -| Dynamic/DynamicExecution.ps1:1:1:1:17 | ...=... | Dynamic/DynamicExecution.ps1:1:1:5:8 | {...} | -| Dynamic/DynamicExecution.ps1:1:1:5:8 | {...} | Dynamic/DynamicExecution.ps1:1:1:5:8 | DynamicExecution.ps1 | -| Dynamic/DynamicExecution.ps1:1:8:1:17 | cmd.exe | Dynamic/DynamicExecution.ps1:1:1:1:17 | ...=... | -| Dynamic/DynamicExecution.ps1:1:8:1:17 | cmd.exe | Dynamic/DynamicExecution.ps1:1:8:1:17 | cmd.exe | -| Dynamic/DynamicExecution.ps1:2:1:2:18 | Invoke-Expression | Dynamic/DynamicExecution.ps1:2:1:2:23 | call to Invoke-Expression | -| Dynamic/DynamicExecution.ps1:2:1:2:23 | call to Invoke-Expression | Dynamic/DynamicExecution.ps1:1:1:5:8 | {...} | -| Dynamic/DynamicExecution.ps1:2:19:2:23 | foo | Dynamic/DynamicExecution.ps1:2:1:2:23 | call to Invoke-Expression | -| Dynamic/DynamicExecution.ps1:3:1:3:14 | scriptblock | Dynamic/DynamicExecution.ps1:3:1:3:28 | call to Create | -| Dynamic/DynamicExecution.ps1:3:1:3:28 | call to Create | Dynamic/DynamicExecution.ps1:1:1:5:8 | {...} | -| Dynamic/DynamicExecution.ps1:3:1:3:28 | call to Create | Dynamic/DynamicExecution.ps1:3:1:3:28 | call to Create | -| Dynamic/DynamicExecution.ps1:3:16:3:22 | Create | Dynamic/DynamicExecution.ps1:3:1:3:28 | call to Create | -| Dynamic/DynamicExecution.ps1:3:23:3:27 | foo | Dynamic/DynamicExecution.ps1:3:1:3:28 | call to Create | -| Dynamic/DynamicExecution.ps1:4:1:4:32 | call | Dynamic/DynamicExecution.ps1:1:1:5:8 | {...} | -| Dynamic/DynamicExecution.ps1:4:3:4:32 | (...) | Dynamic/DynamicExecution.ps1:4:1:4:32 | call | -| Dynamic/DynamicExecution.ps1:4:4:4:17 | scriptblock | Dynamic/DynamicExecution.ps1:4:4:4:31 | call to Create | -| Dynamic/DynamicExecution.ps1:4:4:4:31 | call to Create | Dynamic/DynamicExecution.ps1:4:3:4:32 | (...) | -| Dynamic/DynamicExecution.ps1:4:4:4:31 | call to Create | Dynamic/DynamicExecution.ps1:4:4:4:31 | call to Create | -| Dynamic/DynamicExecution.ps1:4:19:4:25 | Create | Dynamic/DynamicExecution.ps1:4:4:4:31 | call to Create | -| Dynamic/DynamicExecution.ps1:4:26:4:30 | foo | Dynamic/DynamicExecution.ps1:4:4:4:31 | call to Create | -| Dynamic/DynamicExecution.ps1:5:1:5:8 | call | Dynamic/DynamicExecution.ps1:1:1:5:8 | {...} | -| Dynamic/DynamicExecution.ps1:5:2:5:8 | $foo | Dynamic/DynamicExecution.ps1:5:1:5:8 | call | -| Dynamic/DynamicExecution.ps1:5:3:5:7 | foo | Dynamic/DynamicExecution.ps1:5:2:5:8 | $foo | -| Dynamic/DynamicExecutionWithFunc.ps1:1:1:11:2 | ExecuteAThing | Dynamic/DynamicExecutionWithFunc.ps1:1:1:11:2 | {...} | -| Dynamic/DynamicExecutionWithFunc.ps1:1:1:11:2 | {...} | Dynamic/DynamicExecutionWithFunc.ps1:1:1:11:2 | DynamicExecutionWithFunc.ps1 | -| Dynamic/DynamicExecutionWithFunc.ps1:1:24:11:2 | {...} | Dynamic/DynamicExecutionWithFunc.ps1:1:1:11:2 | ExecuteAThing | -| Dynamic/DynamicExecutionWithFunc.ps1:2:5:4:6 | param(...) | Dynamic/DynamicExecutionWithFunc.ps1:1:24:11:2 | {...} | -| Dynamic/DynamicExecutionWithFunc.ps1:2:5:10:30 | {...} | Dynamic/DynamicExecutionWithFunc.ps1:1:24:11:2 | {...} | -| Dynamic/DynamicExecutionWithFunc.ps1:3:9:3:19 | userInput | Dynamic/DynamicExecutionWithFunc.ps1:2:5:4:6 | param(...) | -| Dynamic/DynamicExecutionWithFunc.ps1:5:5:5:9 | foo | Dynamic/DynamicExecutionWithFunc.ps1:5:5:5:34 | ...=... | -| Dynamic/DynamicExecutionWithFunc.ps1:5:5:5:34 | ...=... | Dynamic/DynamicExecutionWithFunc.ps1:2:5:10:30 | {...} | -| Dynamic/DynamicExecutionWithFunc.ps1:5:12:5:21 | cmd.exe | Dynamic/DynamicExecutionWithFunc.ps1:5:12:5:34 | ...+... | -| Dynamic/DynamicExecutionWithFunc.ps1:5:12:5:34 | ...+... | Dynamic/DynamicExecutionWithFunc.ps1:5:5:5:34 | ...=... | -| Dynamic/DynamicExecutionWithFunc.ps1:5:12:5:34 | ...+... | Dynamic/DynamicExecutionWithFunc.ps1:5:12:5:34 | ...+... | -| Dynamic/DynamicExecutionWithFunc.ps1:5:24:5:34 | userInput | Dynamic/DynamicExecutionWithFunc.ps1:5:12:5:34 | ...+... | -| Dynamic/DynamicExecutionWithFunc.ps1:6:5:6:22 | Invoke-Expression | Dynamic/DynamicExecutionWithFunc.ps1:6:5:6:27 | call to Invoke-Expression | -| Dynamic/DynamicExecutionWithFunc.ps1:6:5:6:27 | call to Invoke-Expression | Dynamic/DynamicExecutionWithFunc.ps1:2:5:10:30 | {...} | -| Dynamic/DynamicExecutionWithFunc.ps1:6:23:6:27 | foo | Dynamic/DynamicExecutionWithFunc.ps1:6:5:6:27 | call to Invoke-Expression | -| Dynamic/DynamicExecutionWithFunc.ps1:7:5:7:18 | scriptblock | Dynamic/DynamicExecutionWithFunc.ps1:7:5:7:32 | call to Create | -| Dynamic/DynamicExecutionWithFunc.ps1:7:5:7:32 | call to Create | Dynamic/DynamicExecutionWithFunc.ps1:2:5:10:30 | {...} | -| Dynamic/DynamicExecutionWithFunc.ps1:7:5:7:32 | call to Create | Dynamic/DynamicExecutionWithFunc.ps1:7:5:7:32 | call to Create | -| Dynamic/DynamicExecutionWithFunc.ps1:7:20:7:26 | Create | Dynamic/DynamicExecutionWithFunc.ps1:7:5:7:32 | call to Create | -| Dynamic/DynamicExecutionWithFunc.ps1:7:27:7:31 | foo | Dynamic/DynamicExecutionWithFunc.ps1:7:5:7:32 | call to Create | -| Dynamic/DynamicExecutionWithFunc.ps1:8:5:8:36 | call | Dynamic/DynamicExecutionWithFunc.ps1:2:5:10:30 | {...} | -| Dynamic/DynamicExecutionWithFunc.ps1:8:7:8:36 | (...) | Dynamic/DynamicExecutionWithFunc.ps1:8:5:8:36 | call | -| Dynamic/DynamicExecutionWithFunc.ps1:8:8:8:21 | scriptblock | Dynamic/DynamicExecutionWithFunc.ps1:8:8:8:35 | call to Create | -| Dynamic/DynamicExecutionWithFunc.ps1:8:8:8:35 | call to Create | Dynamic/DynamicExecutionWithFunc.ps1:8:7:8:36 | (...) | -| Dynamic/DynamicExecutionWithFunc.ps1:8:8:8:35 | call to Create | Dynamic/DynamicExecutionWithFunc.ps1:8:8:8:35 | call to Create | -| Dynamic/DynamicExecutionWithFunc.ps1:8:23:8:29 | Create | Dynamic/DynamicExecutionWithFunc.ps1:8:8:8:35 | call to Create | -| Dynamic/DynamicExecutionWithFunc.ps1:8:30:8:34 | foo | Dynamic/DynamicExecutionWithFunc.ps1:8:8:8:35 | call to Create | -| Dynamic/DynamicExecutionWithFunc.ps1:9:5:9:12 | call | Dynamic/DynamicExecutionWithFunc.ps1:2:5:10:30 | {...} | -| Dynamic/DynamicExecutionWithFunc.ps1:9:6:9:12 | $foo | Dynamic/DynamicExecutionWithFunc.ps1:9:5:9:12 | call | -| Dynamic/DynamicExecutionWithFunc.ps1:9:7:9:11 | foo | Dynamic/DynamicExecutionWithFunc.ps1:9:6:9:12 | $foo | -| Dynamic/DynamicExecutionWithFunc.ps1:10:5:10:30 | call to cmd.exe | Dynamic/DynamicExecutionWithFunc.ps1:2:5:10:30 | {...} | -| Dynamic/DynamicExecutionWithFunc.ps1:10:7:10:16 | cmd.exe | Dynamic/DynamicExecutionWithFunc.ps1:10:5:10:30 | call to cmd.exe | -| Dynamic/DynamicExecutionWithFunc.ps1:10:17:10:30 | @(...) | Dynamic/DynamicExecutionWithFunc.ps1:10:5:10:30 | call to cmd.exe | -| Dynamic/DynamicExecutionWithFunc.ps1:10:19:10:29 | userInput | Dynamic/DynamicExecutionWithFunc.ps1:10:19:10:29 | userInput | -| Dynamic/DynamicExecutionWithFunc.ps1:10:19:10:29 | userInput | Dynamic/DynamicExecutionWithFunc.ps1:10:19:10:29 | {...} | -| Dynamic/DynamicExecutionWithFunc.ps1:10:19:10:29 | {...} | Dynamic/DynamicExecutionWithFunc.ps1:10:17:10:30 | @(...) | -| Expressions/BinaryExpression.ps1:1:1:1:6 | val1 | Expressions/BinaryExpression.ps1:1:1:1:10 | ...=... | -| Expressions/BinaryExpression.ps1:1:1:1:10 | ...=... | Expressions/BinaryExpression.ps1:1:1:4:8 | {...} | -| Expressions/BinaryExpression.ps1:1:1:4:8 | {...} | Expressions/BinaryExpression.ps1:1:1:4:8 | BinaryExpression.ps1 | -| Expressions/BinaryExpression.ps1:1:9:1:10 | 1 | Expressions/BinaryExpression.ps1:1:1:1:10 | ...=... | -| Expressions/BinaryExpression.ps1:1:9:1:10 | 1 | Expressions/BinaryExpression.ps1:1:9:1:10 | 1 | -| Expressions/BinaryExpression.ps1:2:1:2:6 | val2 | Expressions/BinaryExpression.ps1:2:1:2:10 | ...=... | -| Expressions/BinaryExpression.ps1:2:1:2:10 | ...=... | Expressions/BinaryExpression.ps1:1:1:4:8 | {...} | -| Expressions/BinaryExpression.ps1:2:9:2:10 | 2 | Expressions/BinaryExpression.ps1:2:1:2:10 | ...=... | -| Expressions/BinaryExpression.ps1:2:9:2:10 | 2 | Expressions/BinaryExpression.ps1:2:9:2:10 | 2 | -| Expressions/BinaryExpression.ps1:3:1:3:8 | result | Expressions/BinaryExpression.ps1:3:1:3:24 | ...=... | -| Expressions/BinaryExpression.ps1:3:1:3:24 | ...=... | Expressions/BinaryExpression.ps1:1:1:4:8 | {...} | -| Expressions/BinaryExpression.ps1:3:11:3:16 | val1 | Expressions/BinaryExpression.ps1:3:11:3:24 | ...+... | -| Expressions/BinaryExpression.ps1:3:11:3:24 | ...+... | Expressions/BinaryExpression.ps1:3:1:3:24 | ...=... | -| Expressions/BinaryExpression.ps1:3:11:3:24 | ...+... | Expressions/BinaryExpression.ps1:3:11:3:24 | ...+... | -| Expressions/BinaryExpression.ps1:3:19:3:24 | val2 | Expressions/BinaryExpression.ps1:3:11:3:24 | ...+... | -| Expressions/BinaryExpression.ps1:4:1:4:8 | result | Expressions/BinaryExpression.ps1:1:1:4:8 | {...} | -| Expressions/BinaryExpression.ps1:4:1:4:8 | result | Expressions/BinaryExpression.ps1:4:1:4:8 | result | -| Expressions/ConvertWithSecureString.ps1:1:1:1:11 | UserInput | Expressions/ConvertWithSecureString.ps1:1:1:1:55 | ...=... | -| Expressions/ConvertWithSecureString.ps1:1:1:1:55 | ...=... | Expressions/ConvertWithSecureString.ps1:1:1:2:80 | {...} | -| Expressions/ConvertWithSecureString.ps1:1:1:2:80 | {...} | Expressions/ConvertWithSecureString.ps1:1:1:2:80 | ConvertWithSecureString.ps1 | -| Expressions/ConvertWithSecureString.ps1:1:14:1:23 | Read-Host | Expressions/ConvertWithSecureString.ps1:1:14:1:55 | call to Read-Host | -| Expressions/ConvertWithSecureString.ps1:1:14:1:55 | call to Read-Host | Expressions/ConvertWithSecureString.ps1:1:1:1:55 | ...=... | -| Expressions/ConvertWithSecureString.ps1:1:24:1:55 | Please enter your secure code | Expressions/ConvertWithSecureString.ps1:1:14:1:55 | call to Read-Host | -| Expressions/ConvertWithSecureString.ps1:2:1:2:16 | EncryptedInput | Expressions/ConvertWithSecureString.ps1:2:1:2:80 | ...=... | -| Expressions/ConvertWithSecureString.ps1:2:1:2:80 | ...=... | Expressions/ConvertWithSecureString.ps1:1:1:2:80 | {...} | -| Expressions/ConvertWithSecureString.ps1:2:19:2:41 | ConvertTo-SecureString | Expressions/ConvertWithSecureString.ps1:2:19:2:80 | call to ConvertTo-SecureString | -| Expressions/ConvertWithSecureString.ps1:2:19:2:80 | call to ConvertTo-SecureString | Expressions/ConvertWithSecureString.ps1:2:1:2:80 | ...=... | -| Expressions/ConvertWithSecureString.ps1:2:42:2:49 | String | Expressions/ConvertWithSecureString.ps1:2:19:2:80 | call to ConvertTo-SecureString | -| Expressions/ConvertWithSecureString.ps1:2:50:2:60 | UserInput | Expressions/ConvertWithSecureString.ps1:2:19:2:80 | call to ConvertTo-SecureString | -| Expressions/ConvertWithSecureString.ps1:2:61:2:73 | AsPlainText | Expressions/ConvertWithSecureString.ps1:2:19:2:80 | call to ConvertTo-SecureString | -| Expressions/ConvertWithSecureString.ps1:2:74:2:80 | Force | Expressions/ConvertWithSecureString.ps1:2:19:2:80 | call to ConvertTo-SecureString | -| Expressions/ExpandableString.ps1:1:1:1:40 | Date: $([DateTime]::Now)\nName: $name | Expressions/ExpandableString.ps1:1:1:1:40 | Date: $([DateTime]::Now)\nName: $name | -| Expressions/ExpandableString.ps1:1:1:1:40 | Date: $([DateTime]::Now)\nName: $name | Expressions/ExpandableString.ps1:1:1:1:40 | {...} | -| Expressions/ExpandableString.ps1:1:1:1:40 | {...} | Expressions/ExpandableString.ps1:1:1:1:40 | ExpandableString.ps1 | -| Expressions/ExpandableString.ps1:1:8:1:13 | name | Expressions/ExpandableString.ps1:1:1:1:40 | Date: $([DateTime]::Now)\nName: $name | -| Expressions/ExpandableString.ps1:1:21:1:39 | $(...) | Expressions/ExpandableString.ps1:1:1:1:40 | Date: $([DateTime]::Now)\nName: $name | -| Expressions/ExpandableString.ps1:1:23:1:33 | DateTime | Expressions/ExpandableString.ps1:1:23:1:38 | Now | -| Expressions/ExpandableString.ps1:1:23:1:38 | Now | Expressions/ExpandableString.ps1:1:23:1:38 | Now | -| Expressions/ExpandableString.ps1:1:23:1:38 | Now | Expressions/ExpandableString.ps1:1:23:1:38 | {...} | -| Expressions/ExpandableString.ps1:1:23:1:38 | {...} | Expressions/ExpandableString.ps1:1:21:1:39 | $(...) | -| Expressions/ExpandableString.ps1:1:35:1:38 | Now | Expressions/ExpandableString.ps1:1:23:1:38 | Now | -| Expressions/SubExpression.ps1:1:1:1:12 | $(...) | Expressions/SubExpression.ps1:1:1:1:24 | call to AddDays | -| Expressions/SubExpression.ps1:1:1:1:24 | call to AddDays | Expressions/SubExpression.ps1:1:1:1:24 | call to AddDays | -| Expressions/SubExpression.ps1:1:1:1:24 | call to AddDays | Expressions/SubExpression.ps1:1:1:2:22 | {...} | -| Expressions/SubExpression.ps1:1:1:2:22 | {...} | Expressions/SubExpression.ps1:1:1:2:22 | SubExpression.ps1 | -| Expressions/SubExpression.ps1:1:3:1:11 | Get-Date | Expressions/SubExpression.ps1:1:3:1:11 | call to Get-Date | -| Expressions/SubExpression.ps1:1:3:1:11 | call to Get-Date | Expressions/SubExpression.ps1:1:3:1:11 | {...} | -| Expressions/SubExpression.ps1:1:3:1:11 | {...} | Expressions/SubExpression.ps1:1:1:1:12 | $(...) | -| Expressions/SubExpression.ps1:1:13:1:20 | AddDays | Expressions/SubExpression.ps1:1:1:1:24 | call to AddDays | -| Expressions/SubExpression.ps1:1:21:1:23 | 10 | Expressions/SubExpression.ps1:1:1:1:24 | call to AddDays | -| Expressions/SubExpression.ps1:2:1:2:12 | $(...) | Expressions/SubExpression.ps1:2:1:2:22 | call to AddDays | -| Expressions/SubExpression.ps1:2:1:2:22 | call to AddDays | Expressions/SubExpression.ps1:1:1:2:22 | {...} | -| Expressions/SubExpression.ps1:2:1:2:22 | call to AddDays | Expressions/SubExpression.ps1:2:1:2:22 | call to AddDays | -| Expressions/SubExpression.ps1:2:3:2:11 | Get-Date | Expressions/SubExpression.ps1:2:3:2:11 | call to Get-Date | -| Expressions/SubExpression.ps1:2:3:2:11 | call to Get-Date | Expressions/SubExpression.ps1:2:3:2:11 | {...} | -| Expressions/SubExpression.ps1:2:3:2:11 | {...} | Expressions/SubExpression.ps1:2:1:2:12 | $(...) | -| Expressions/SubExpression.ps1:2:13:2:20 | AddDays | Expressions/SubExpression.ps1:2:1:2:22 | call to AddDays | -| Expressions/TernaryExpression.ps1:1:1:1:5 | var | Expressions/TernaryExpression.ps1:1:1:1:23 | ...=... | -| Expressions/TernaryExpression.ps1:1:1:1:23 | ...=... | Expressions/TernaryExpression.ps1:1:1:1:23 | {...} | -| Expressions/TernaryExpression.ps1:1:1:1:23 | {...} | Expressions/TernaryExpression.ps1:1:1:1:23 | TernaryExpression.ps1 | -| Expressions/TernaryExpression.ps1:1:8:1:17 | (...) | Expressions/TernaryExpression.ps1:1:8:1:23 | ...?...:... | -| Expressions/TernaryExpression.ps1:1:8:1:23 | ...?...:... | Expressions/TernaryExpression.ps1:1:1:1:23 | ...=... | -| Expressions/TernaryExpression.ps1:1:8:1:23 | ...?...:... | Expressions/TernaryExpression.ps1:1:8:1:23 | ...?...:... | -| Expressions/TernaryExpression.ps1:1:9:1:10 | 6 | Expressions/TernaryExpression.ps1:1:9:1:16 | ... -gt ... | -| Expressions/TernaryExpression.ps1:1:9:1:16 | ... -gt ... | Expressions/TernaryExpression.ps1:1:8:1:17 | (...) | -| Expressions/TernaryExpression.ps1:1:9:1:16 | ... -gt ... | Expressions/TernaryExpression.ps1:1:9:1:16 | ... -gt ... | -| Expressions/TernaryExpression.ps1:1:15:1:16 | 7 | Expressions/TernaryExpression.ps1:1:9:1:16 | ... -gt ... | -| Expressions/TernaryExpression.ps1:1:20:1:21 | 1 | Expressions/TernaryExpression.ps1:1:8:1:23 | ...?...:... | -| Expressions/TernaryExpression.ps1:1:22:1:23 | 2 | Expressions/TernaryExpression.ps1:1:8:1:23 | ...?...:... | -| Loops/DoUntil.ps1:1:1:7:19 | DoUntil | Loops/DoUntil.ps1:1:1:7:19 | {...} | -| Loops/DoUntil.ps1:1:1:7:19 | {...} | Loops/DoUntil.ps1:1:1:7:19 | DoUntil.ps1 | -| Loops/DoUntil.ps1:2:1:7:2 | {...} | Loops/DoUntil.ps1:1:1:7:19 | DoUntil | -| Loops/DoUntil.ps1:3:2:3:20 | Starting Loop $a | Loops/DoUntil.ps1:2:1:7:2 | {...} | -| Loops/DoUntil.ps1:3:2:3:20 | Starting Loop $a | Loops/DoUntil.ps1:3:2:3:20 | Starting Loop $a | -| Loops/DoUntil.ps1:3:17:3:19 | a | Loops/DoUntil.ps1:3:2:3:20 | Starting Loop $a | -| Loops/DoUntil.ps1:4:2:4:4 | a | Loops/DoUntil.ps1:2:1:7:2 | {...} | -| Loops/DoUntil.ps1:4:2:4:4 | a | Loops/DoUntil.ps1:4:2:4:4 | a | -| Loops/DoUntil.ps1:5:2:5:4 | a | Loops/DoUntil.ps1:5:2:5:6 | ...++ | -| Loops/DoUntil.ps1:5:2:5:6 | ...++ | Loops/DoUntil.ps1:2:1:7:2 | {...} | -| Loops/DoUntil.ps1:5:2:5:6 | ...++ | Loops/DoUntil.ps1:5:2:5:6 | ...++ | -| Loops/DoUntil.ps1:6:2:6:17 | Now $a is $a | Loops/DoUntil.ps1:2:1:7:2 | {...} | -| Loops/DoUntil.ps1:6:2:6:17 | Now $a is $a | Loops/DoUntil.ps1:6:2:6:17 | Now $a is $a | -| Loops/DoUntil.ps1:6:14:6:16 | a | Loops/DoUntil.ps1:6:2:6:17 | Now $a is $a | -| Loops/DoUntil.ps1:7:10:7:12 | a | Loops/DoUntil.ps1:7:10:7:18 | ... -le ... | -| Loops/DoUntil.ps1:7:10:7:18 | ... -le ... | Loops/DoUntil.ps1:1:1:7:19 | DoUntil | -| Loops/DoUntil.ps1:7:10:7:18 | ... -le ... | Loops/DoUntil.ps1:7:10:7:18 | ... -le ... | -| Loops/DoUntil.ps1:7:17:7:18 | 5 | Loops/DoUntil.ps1:7:10:7:18 | ... -le ... | -| Loops/DoWhile.ps1:1:1:7:19 | DoWhile | Loops/DoWhile.ps1:1:1:7:19 | {...} | -| Loops/DoWhile.ps1:1:1:7:19 | {...} | Loops/DoWhile.ps1:1:1:7:19 | DoWhile.ps1 | -| Loops/DoWhile.ps1:2:1:7:2 | {...} | Loops/DoWhile.ps1:1:1:7:19 | DoWhile | -| Loops/DoWhile.ps1:3:2:3:20 | Starting Loop $a | Loops/DoWhile.ps1:2:1:7:2 | {...} | -| Loops/DoWhile.ps1:3:2:3:20 | Starting Loop $a | Loops/DoWhile.ps1:3:2:3:20 | Starting Loop $a | -| Loops/DoWhile.ps1:3:17:3:19 | a | Loops/DoWhile.ps1:3:2:3:20 | Starting Loop $a | -| Loops/DoWhile.ps1:4:2:4:4 | a | Loops/DoWhile.ps1:2:1:7:2 | {...} | -| Loops/DoWhile.ps1:4:2:4:4 | a | Loops/DoWhile.ps1:4:2:4:4 | a | -| Loops/DoWhile.ps1:5:2:5:4 | a | Loops/DoWhile.ps1:5:2:5:6 | ...++ | -| Loops/DoWhile.ps1:5:2:5:6 | ...++ | Loops/DoWhile.ps1:2:1:7:2 | {...} | -| Loops/DoWhile.ps1:5:2:5:6 | ...++ | Loops/DoWhile.ps1:5:2:5:6 | ...++ | -| Loops/DoWhile.ps1:6:2:6:17 | Now $a is $a | Loops/DoWhile.ps1:2:1:7:2 | {...} | -| Loops/DoWhile.ps1:6:2:6:17 | Now $a is $a | Loops/DoWhile.ps1:6:2:6:17 | Now $a is $a | -| Loops/DoWhile.ps1:6:14:6:16 | a | Loops/DoWhile.ps1:6:2:6:17 | Now $a is $a | -| Loops/DoWhile.ps1:7:10:7:12 | a | Loops/DoWhile.ps1:7:10:7:18 | ... -le ... | -| Loops/DoWhile.ps1:7:10:7:18 | ... -le ... | Loops/DoWhile.ps1:1:1:7:19 | DoWhile | -| Loops/DoWhile.ps1:7:10:7:18 | ... -le ... | Loops/DoWhile.ps1:7:10:7:18 | ... -le ... | -| Loops/DoWhile.ps1:7:17:7:18 | 5 | Loops/DoWhile.ps1:7:10:7:18 | ... -le ... | -| Loops/While.ps1:1:1:1:5 | var | Loops/While.ps1:1:1:1:9 | ...=... | -| Loops/While.ps1:1:1:1:9 | ...=... | Loops/While.ps1:1:1:13:2 | {...} | -| Loops/While.ps1:1:1:13:2 | {...} | Loops/While.ps1:1:1:13:2 | While.ps1 | -| Loops/While.ps1:1:8:1:9 | 1 | Loops/While.ps1:1:1:1:9 | ...=... | -| Loops/While.ps1:1:8:1:9 | 1 | Loops/While.ps1:1:8:1:9 | 1 | -| Loops/While.ps1:2:1:13:2 | while(...) {...} | Loops/While.ps1:1:1:13:2 | {...} | -| Loops/While.ps1:2:8:2:12 | var | Loops/While.ps1:2:8:2:18 | ... -le ... | -| Loops/While.ps1:2:8:2:18 | ... -le ... | Loops/While.ps1:2:1:13:2 | while(...) {...} | -| Loops/While.ps1:2:8:2:18 | ... -le ... | Loops/While.ps1:2:8:2:18 | ... -le ... | -| Loops/While.ps1:2:17:2:18 | 5 | Loops/While.ps1:2:8:2:18 | ... -le ... | -| Loops/While.ps1:3:1:13:2 | {...} | Loops/While.ps1:2:1:13:2 | while(...) {...} | -| Loops/While.ps1:4:5:4:15 | Write-Host | Loops/While.ps1:4:5:4:41 | call to Write-Host | -| Loops/While.ps1:4:5:4:41 | call to Write-Host | Loops/While.ps1:3:1:13:2 | {...} | -| Loops/While.ps1:4:16:4:19 | The | Loops/While.ps1:4:5:4:41 | call to Write-Host | -| Loops/While.ps1:4:20:4:25 | value | Loops/While.ps1:4:5:4:41 | call to Write-Host | -| Loops/While.ps1:4:26:4:28 | of | Loops/While.ps1:4:5:4:41 | call to Write-Host | -| Loops/While.ps1:4:29:4:32 | Var | Loops/While.ps1:4:5:4:41 | call to Write-Host | -| Loops/While.ps1:4:33:4:36 | is: | Loops/While.ps1:4:5:4:41 | call to Write-Host | -| Loops/While.ps1:4:37:4:41 | var | Loops/While.ps1:4:5:4:41 | call to Write-Host | -| Loops/While.ps1:5:5:5:9 | var | Loops/While.ps1:5:5:5:11 | ...++ | -| Loops/While.ps1:5:5:5:11 | ...++ | Loops/While.ps1:3:1:13:2 | {...} | -| Loops/While.ps1:5:5:5:11 | ...++ | Loops/While.ps1:5:5:5:11 | ...++ | -| Loops/While.ps1:6:5:12:6 | if (...) {...} else {...} | Loops/While.ps1:3:1:13:2 | {...} | -| Loops/While.ps1:6:9:6:13 | var | Loops/While.ps1:6:9:6:19 | ... -le ... | -| Loops/While.ps1:6:9:6:19 | ... -le ... | Loops/While.ps1:6:5:12:6 | if (...) {...} else {...} | -| Loops/While.ps1:6:9:6:19 | ... -le ... | Loops/While.ps1:6:9:6:19 | ... -le ... | -| Loops/While.ps1:6:18:6:19 | 3 | Loops/While.ps1:6:9:6:19 | ... -le ... | -| Loops/While.ps1:6:20:8:6 | {...} | Loops/While.ps1:6:5:12:6 | if (...) {...} else {...} | -| Loops/While.ps1:7:9:7:17 | continue | Loops/While.ps1:6:20:8:6 | {...} | -| Loops/While.ps1:10:5:12:6 | {...} | Loops/While.ps1:6:5:12:6 | if (...) {...} else {...} | -| Loops/While.ps1:11:9:11:14 | break | Loops/While.ps1:10:5:12:6 | {...} | -| Redirections/FileRedirection.ps1:1:1:3:2 | $(...) | Redirections/FileRedirection.ps1:1:1:3:20 | $(...) | -| Redirections/FileRedirection.ps1:1:1:3:20 | $(...) | Redirections/FileRedirection.ps1:1:1:3:20 | {...} | -| Redirections/FileRedirection.ps1:1:1:3:20 | {...} | Redirections/FileRedirection.ps1:1:1:3:20 | FileRedirection.ps1 | -| Redirections/FileRedirection.ps1:2:5:2:9 | Here | Redirections/FileRedirection.ps1:2:5:2:32 | call to Here | -| Redirections/FileRedirection.ps1:2:5:2:32 | call to Here | Redirections/FileRedirection.ps1:2:5:2:32 | {...} | -| Redirections/FileRedirection.ps1:2:5:2:32 | {...} | Redirections/FileRedirection.ps1:1:1:3:2 | $(...) | -| Redirections/FileRedirection.ps1:2:10:2:12 | is | Redirections/FileRedirection.ps1:2:5:2:32 | call to Here | -| Redirections/FileRedirection.ps1:2:13:2:17 | your | Redirections/FileRedirection.ps1:2:5:2:32 | call to Here | -| Redirections/FileRedirection.ps1:2:18:2:25 | current | Redirections/FileRedirection.ps1:2:5:2:32 | call to Here | -| Redirections/FileRedirection.ps1:2:26:2:32 | script | Redirections/FileRedirection.ps1:2:5:2:32 | call to Here | -| Redirections/FileRedirection.ps1:3:3:3:7 | MergingRedirection | Redirections/FileRedirection.ps1:1:1:3:20 | $(...) | -| Redirections/FileRedirection.ps1:3:8:3:20 | FileRedirection | Redirections/FileRedirection.ps1:1:1:3:20 | $(...) | -| Redirections/FileRedirection.ps1:3:10:3:20 | output.txt | Redirections/FileRedirection.ps1:3:8:3:20 | FileRedirection | -| Statements/ExitStatement.ps1:1:1:1:8 | exit ... | Statements/ExitStatement.ps1:1:1:1:8 | {...} | -| Statements/ExitStatement.ps1:1:1:1:8 | {...} | Statements/ExitStatement.ps1:1:1:1:8 | ExitStatement.ps1 | -| Statements/ExitStatement.ps1:1:6:1:8 | -1 | Statements/ExitStatement.ps1:1:1:1:8 | exit ... | -| Statements/ExitStatement.ps1:1:6:1:8 | -1 | Statements/ExitStatement.ps1:1:6:1:8 | -1 | -| Statements/IfStatement.ps1:1:1:1:3 | x | Statements/IfStatement.ps1:1:1:1:7 | ...=... | -| Statements/IfStatement.ps1:1:1:1:7 | ...=... | Statements/IfStatement.ps1:1:1:8:2 | {...} | -| Statements/IfStatement.ps1:1:1:8:2 | {...} | Statements/IfStatement.ps1:1:1:8:2 | IfStatement.ps1 | -| Statements/IfStatement.ps1:1:6:1:7 | 4 | Statements/IfStatement.ps1:1:1:1:7 | ...=... | -| Statements/IfStatement.ps1:1:6:1:7 | 4 | Statements/IfStatement.ps1:1:6:1:7 | 4 | -| Statements/IfStatement.ps1:3:1:8:2 | if (...) {...} else {...} | Statements/IfStatement.ps1:1:1:8:2 | {...} | -| Statements/IfStatement.ps1:3:5:3:7 | x | Statements/IfStatement.ps1:3:5:3:13 | ... -ge ... | -| Statements/IfStatement.ps1:3:5:3:13 | ... -ge ... | Statements/IfStatement.ps1:3:1:8:2 | if (...) {...} else {...} | -| Statements/IfStatement.ps1:3:5:3:13 | ... -ge ... | Statements/IfStatement.ps1:3:5:3:13 | ... -ge ... | -| Statements/IfStatement.ps1:3:12:3:13 | 3 | Statements/IfStatement.ps1:3:5:3:13 | ... -ge ... | -| Statements/IfStatement.ps1:3:15:5:2 | {...} | Statements/IfStatement.ps1:3:1:8:2 | if (...) {...} else {...} | -| Statements/IfStatement.ps1:4:2:4:36 | $x is greater than or equal to 3 | Statements/IfStatement.ps1:3:15:5:2 | {...} | -| Statements/IfStatement.ps1:4:2:4:36 | $x is greater than or equal to 3 | Statements/IfStatement.ps1:4:2:4:36 | $x is greater than or equal to 3 | -| Statements/IfStatement.ps1:4:3:4:5 | x | Statements/IfStatement.ps1:4:2:4:36 | $x is greater than or equal to 3 | -| Statements/IfStatement.ps1:6:6:8:2 | {...} | Statements/IfStatement.ps1:3:1:8:2 | if (...) {...} else {...} | -| Statements/IfStatement.ps1:7:2:7:21 | $x is less than 3 | Statements/IfStatement.ps1:6:6:8:2 | {...} | -| Statements/IfStatement.ps1:7:2:7:21 | $x is less than 3 | Statements/IfStatement.ps1:7:2:7:21 | $x is less than 3 | -| Statements/IfStatement.ps1:7:3:7:5 | x | Statements/IfStatement.ps1:7:2:7:21 | $x is less than 3 | -| Statements/TrapStatement.ps1:1:1:4:2 | TrapTest | Statements/TrapStatement.ps1:1:1:6:9 | {...} | -| Statements/TrapStatement.ps1:1:1:6:9 | {...} | Statements/TrapStatement.ps1:1:1:6:9 | TrapStatement.ps1 | -| Statements/TrapStatement.ps1:1:19:4:2 | {...} | Statements/TrapStatement.ps1:1:1:4:2 | TrapTest | -| Statements/TrapStatement.ps1:2:5:2:26 | TrapStatement at: Statements/TrapStatement.ps1:2:5:2:26 | Statements/TrapStatement.ps1:2:5:3:19 | {...} | -| Statements/TrapStatement.ps1:2:5:3:19 | {...} | Statements/TrapStatement.ps1:1:19:4:2 | {...} | -| Statements/TrapStatement.ps1:2:10:2:26 | {...} | Statements/TrapStatement.ps1:2:5:2:26 | TrapStatement at: Statements/TrapStatement.ps1:2:5:2:26 | -| Statements/TrapStatement.ps1:2:11:2:25 | Error found. | Statements/TrapStatement.ps1:2:10:2:26 | {...} | -| Statements/TrapStatement.ps1:2:11:2:25 | Error found. | Statements/TrapStatement.ps1:2:11:2:25 | Error found. | -| Statements/TrapStatement.ps1:3:5:3:19 | call to nonsenseString | Statements/TrapStatement.ps1:2:5:3:19 | {...} | -| Statements/TrapStatement.ps1:3:5:3:19 | nonsenseString | Statements/TrapStatement.ps1:3:5:3:19 | call to nonsenseString | -| Statements/TrapStatement.ps1:6:1:6:9 | TrapTest | Statements/TrapStatement.ps1:6:1:6:9 | call to TrapTest | -| Statements/TrapStatement.ps1:6:1:6:9 | call to TrapTest | Statements/TrapStatement.ps1:1:1:6:9 | {...} | -| Statements/Try.ps1:1:1:13:2 | try {...} | Statements/Try.ps1:1:1:13:2 | {...} | -| Statements/Try.ps1:1:1:13:2 | {...} | Statements/Try.ps1:1:1:13:2 | Try.ps1 | -| Statements/Try.ps1:1:5:4:2 | {...} | Statements/Try.ps1:1:1:13:2 | try {...} | -| Statements/Try.ps1:2:4:2:14 | Exception | Statements/Try.ps1:2:4:2:95 | ...=... | -| Statements/Try.ps1:2:4:2:95 | ...=... | Statements/Try.ps1:1:5:4:2 | {...} | -| Statements/Try.ps1:2:17:2:27 | New-Object | Statements/Try.ps1:2:17:2:95 | call to New-Object | -| Statements/Try.ps1:2:17:2:95 | call to New-Object | Statements/Try.ps1:2:4:2:95 | ...=... | -| Statements/Try.ps1:2:28:2:53 | System.Xaml.XamlException | Statements/Try.ps1:2:17:2:95 | call to New-Object | -| Statements/Try.ps1:2:54:2:67 | ArgumentList | Statements/Try.ps1:2:17:2:95 | call to New-Object | -| Statements/Try.ps1:2:68:2:95 | (...) | Statements/Try.ps1:2:17:2:95 | call to New-Object | -| Statements/Try.ps1:2:69:2:80 | Bad XAML! | Statements/Try.ps1:2:69:2:94 | ...,... | -| Statements/Try.ps1:2:69:2:94 | ...,... | Statements/Try.ps1:2:68:2:95 | (...) | -| Statements/Try.ps1:2:69:2:94 | ...,... | Statements/Try.ps1:2:69:2:94 | ...,... | -| Statements/Try.ps1:2:82:2:87 | null | Statements/Try.ps1:2:69:2:94 | ...,... | -| Statements/Try.ps1:2:89:2:91 | 10 | Statements/Try.ps1:2:69:2:94 | ...,... | -| Statements/Try.ps1:2:93:2:94 | 2 | Statements/Try.ps1:2:69:2:94 | ...,... | -| Statements/Try.ps1:3:5:3:21 | throw ... | Statements/Try.ps1:1:5:4:2 | {...} | -| Statements/Try.ps1:3:11:3:21 | Exception | Statements/Try.ps1:3:5:3:21 | throw ... | -| Statements/Try.ps1:3:11:3:21 | Exception | Statements/Try.ps1:3:11:3:21 | Exception | -| Statements/Try.ps1:5:1:7:2 | catch[...] {...} | Statements/Try.ps1:1:1:13:2 | try {...} | -| Statements/Try.ps1:5:7:5:32 | System.Net.WebException | Statements/Try.ps1:5:1:7:2 | catch[...] {...} | -| Statements/Try.ps1:5:33:5:56 | System.IO.IOException | Statements/Try.ps1:5:1:7:2 | catch[...] {...} | -| Statements/Try.ps1:5:57:7:2 | {...} | Statements/Try.ps1:5:1:7:2 | catch[...] {...} | -| Statements/Try.ps1:6:5:6:64 | Unable to download MyDoc.doc from http://www.contoso.com. | Statements/Try.ps1:5:57:7:2 | {...} | -| Statements/Try.ps1:6:5:6:64 | Unable to download MyDoc.doc from http://www.contoso.com. | Statements/Try.ps1:6:5:6:64 | Unable to download MyDoc.doc from http://www.contoso.com. | -| Statements/Try.ps1:8:1:10:2 | catch {...} | Statements/Try.ps1:1:1:13:2 | try {...} | -| Statements/Try.ps1:8:7:10:2 | {...} | Statements/Try.ps1:8:1:10:2 | catch {...} | -| Statements/Try.ps1:9:5:9:52 | An error occurred that could not be resolved. | Statements/Try.ps1:8:7:10:2 | {...} | -| Statements/Try.ps1:9:5:9:52 | An error occurred that could not be resolved. | Statements/Try.ps1:9:5:9:52 | An error occurred that could not be resolved. | -| Statements/Try.ps1:11:9:13:2 | {...} | Statements/Try.ps1:1:1:13:2 | try {...} | -| Statements/Try.ps1:12:5:12:37 | The finally block is executed. | Statements/Try.ps1:11:9:13:2 | {...} | -| Statements/Try.ps1:12:5:12:37 | The finally block is executed. | Statements/Try.ps1:12:5:12:37 | The finally block is executed. | -| Statements/UseProcessBlockForPipelineCommand.ps1:1:1:11:2 | Get-Number | Statements/UseProcessBlockForPipelineCommand.ps1:1:1:11:2 | {...} | -| Statements/UseProcessBlockForPipelineCommand.ps1:1:1:11:2 | {...} | Statements/UseProcessBlockForPipelineCommand.ps1:1:1:11:2 | UseProcessBlockForPipelineCommand.ps1 | -| Statements/UseProcessBlockForPipelineCommand.ps1:2:1:11:2 | {...} | Statements/UseProcessBlockForPipelineCommand.ps1:1:1:11:2 | Get-Number | -| Statements/UseProcessBlockForPipelineCommand.ps1:3:5:3:22 | CmdletBinding | Statements/UseProcessBlockForPipelineCommand.ps1:4:5:8:6 | param(...) | -| Statements/UseProcessBlockForPipelineCommand.ps1:4:5:8:6 | param(...) | Statements/UseProcessBlockForPipelineCommand.ps1:2:1:11:2 | {...} | -| Statements/UseProcessBlockForPipelineCommand.ps1:4:5:10:12 | {...} | Statements/UseProcessBlockForPipelineCommand.ps1:2:1:11:2 | {...} | -| Statements/UseProcessBlockForPipelineCommand.ps1:5:9:5:39 | Parameter | Statements/UseProcessBlockForPipelineCommand.ps1:5:9:7:16 | Number | -| Statements/UseProcessBlockForPipelineCommand.ps1:5:9:7:16 | Number | Statements/UseProcessBlockForPipelineCommand.ps1:4:5:8:6 | param(...) | -| Statements/UseProcessBlockForPipelineCommand.ps1:5:20:5:37 | True | Statements/UseProcessBlockForPipelineCommand.ps1:5:20:5:37 | ValueFromPipeline | -| Statements/UseProcessBlockForPipelineCommand.ps1:5:20:5:37 | ValueFromPipeline | Statements/UseProcessBlockForPipelineCommand.ps1:5:9:5:39 | Parameter | -| Statements/UseProcessBlockForPipelineCommand.ps1:6:9:6:14 | int | Statements/UseProcessBlockForPipelineCommand.ps1:5:9:7:16 | Number | -| Statements/UseProcessBlockForPipelineCommand.ps1:10:5:10:12 | Number | Statements/UseProcessBlockForPipelineCommand.ps1:4:5:10:12 | {...} | -| Statements/UseProcessBlockForPipelineCommand.ps1:10:5:10:12 | Number | Statements/UseProcessBlockForPipelineCommand.ps1:10:5:10:12 | Number | -| file://:0:0:0:0 | (no string representation) | Blocks/ParamBlock.ps1:3:5:4:23 | Parameter | -| file://:0:0:0:0 | (no string representation) | Dynamic/DynamicExecutionWithFunc.ps1:3:9:3:19 | userInput | -| file://:0:0:0:0 | (no string representation) | Statements/UseProcessBlockForPipelineCommand.ps1:5:9:7:16 | Number | +| Arrays/Arrays.ps1:0:0:0:-1 | {...} | Arrays/Arrays.ps1:14:41:14:43 | @(...) | +| Arrays/Arrays.ps1:1:1:1:7 | array1 | Arrays/Arrays.ps1:1:1:1:36 | ...=... | +| Arrays/Arrays.ps1:1:1:1:7 | array1 | Arrays/Arrays.ps1:1:1:15:14 | {...} | +| Arrays/Arrays.ps1:1:1:1:36 | ...=... | Arrays/Arrays.ps1:1:1:15:14 | {...} | +| Arrays/Arrays.ps1:1:1:15:14 | {...} | Arrays/Arrays.ps1:1:1:15:14 | {...} | +| Arrays/Arrays.ps1:1:1:15:14 | {...} | file://:0:0:0:0 | toplevel function for Arrays.ps1 | +| Arrays/Arrays.ps1:1:11:1:11 | 1 | Arrays/Arrays.ps1:1:11:1:36 | ...,... | +| Arrays/Arrays.ps1:1:11:1:36 | ...,... | Arrays/Arrays.ps1:1:1:1:36 | ...=... | +| Arrays/Arrays.ps1:1:13:1:13 | 2 | Arrays/Arrays.ps1:1:11:1:36 | ...,... | +| Arrays/Arrays.ps1:1:15:1:17 | a | Arrays/Arrays.ps1:1:11:1:36 | ...,... | +| Arrays/Arrays.ps1:1:19:1:23 | true | Arrays/Arrays.ps1:1:11:1:36 | ...,... | +| Arrays/Arrays.ps1:1:25:1:30 | false | Arrays/Arrays.ps1:1:11:1:36 | ...,... | +| Arrays/Arrays.ps1:1:32:1:36 | null | Arrays/Arrays.ps1:1:11:1:36 | ...,... | +| Arrays/Arrays.ps1:2:1:2:7 | array1 | Arrays/Arrays.ps1:2:1:2:10 | ...[...] | +| Arrays/Arrays.ps1:2:1:2:10 | ...[...] | Arrays/Arrays.ps1:2:1:2:14 | ...=... | +| Arrays/Arrays.ps1:2:1:2:14 | ...=... | Arrays/Arrays.ps1:1:1:15:14 | {...} | +| Arrays/Arrays.ps1:2:9:2:9 | 1 | Arrays/Arrays.ps1:2:1:2:10 | ...[...] | +| Arrays/Arrays.ps1:2:14:2:14 | 3 | Arrays/Arrays.ps1:2:1:2:14 | ...=... | +| Arrays/Arrays.ps1:3:1:3:7 | array1 | Arrays/Arrays.ps1:3:1:3:10 | ...[...] | +| Arrays/Arrays.ps1:3:1:3:10 | ...[...] | Arrays/Arrays.ps1:3:1:3:16 | ...=... | +| Arrays/Arrays.ps1:3:1:3:16 | ...=... | Arrays/Arrays.ps1:1:1:15:14 | {...} | +| Arrays/Arrays.ps1:3:9:3:9 | 2 | Arrays/Arrays.ps1:3:1:3:10 | ...[...] | +| Arrays/Arrays.ps1:3:14:3:16 | b | Arrays/Arrays.ps1:3:1:3:16 | ...=... | +| Arrays/Arrays.ps1:5:1:5:7 | array2 | Arrays/Arrays.ps1:1:1:15:14 | {...} | +| Arrays/Arrays.ps1:5:1:5:7 | array2 | Arrays/Arrays.ps1:5:1:5:36 | ...=... | +| Arrays/Arrays.ps1:5:1:5:36 | ...=... | Arrays/Arrays.ps1:1:1:15:14 | {...} | +| Arrays/Arrays.ps1:5:11:5:20 | New-Object | Arrays/Arrays.ps1:5:11:5:36 | Call to New-Object | +| Arrays/Arrays.ps1:5:11:5:36 | Call to New-Object | Arrays/Arrays.ps1:5:1:5:36 | ...=... | +| Arrays/Arrays.ps1:5:22:5:32 | object[,] | Arrays/Arrays.ps1:5:11:5:36 | Call to New-Object | +| Arrays/Arrays.ps1:5:34:5:34 | 2 | Arrays/Arrays.ps1:5:34:5:36 | ...,... | +| Arrays/Arrays.ps1:5:34:5:36 | ...,... | Arrays/Arrays.ps1:5:11:5:36 | Call to New-Object | +| Arrays/Arrays.ps1:5:36:5:36 | 2 | Arrays/Arrays.ps1:5:34:5:36 | ...,... | +| Arrays/Arrays.ps1:6:1:6:7 | array2 | Arrays/Arrays.ps1:6:1:6:12 | ...[...] | +| Arrays/Arrays.ps1:6:1:6:12 | ...[...] | Arrays/Arrays.ps1:6:1:6:21 | ...=... | +| Arrays/Arrays.ps1:6:1:6:21 | ...=... | Arrays/Arrays.ps1:1:1:15:14 | {...} | +| Arrays/Arrays.ps1:6:9:6:9 | 0 | Arrays/Arrays.ps1:6:9:6:11 | ...,... | +| Arrays/Arrays.ps1:6:9:6:11 | ...,... | Arrays/Arrays.ps1:6:1:6:12 | ...[...] | +| Arrays/Arrays.ps1:6:11:6:11 | 0 | Arrays/Arrays.ps1:6:9:6:11 | ...,... | +| Arrays/Arrays.ps1:6:16:6:21 | key1 | Arrays/Arrays.ps1:6:1:6:21 | ...=... | +| Arrays/Arrays.ps1:7:1:7:7 | array2 | Arrays/Arrays.ps1:7:1:7:12 | ...[...] | +| Arrays/Arrays.ps1:7:1:7:12 | ...[...] | Arrays/Arrays.ps1:7:1:7:21 | ...=... | +| Arrays/Arrays.ps1:7:1:7:21 | ...=... | Arrays/Arrays.ps1:1:1:15:14 | {...} | +| Arrays/Arrays.ps1:7:9:7:9 | 1 | Arrays/Arrays.ps1:7:9:7:11 | ...,... | +| Arrays/Arrays.ps1:7:9:7:11 | ...,... | Arrays/Arrays.ps1:7:1:7:12 | ...[...] | +| Arrays/Arrays.ps1:7:11:7:11 | 0 | Arrays/Arrays.ps1:7:9:7:11 | ...,... | +| Arrays/Arrays.ps1:7:16:7:21 | key1 | Arrays/Arrays.ps1:7:1:7:21 | ...=... | +| Arrays/Arrays.ps1:8:1:8:7 | array2 | Arrays/Arrays.ps1:8:1:8:12 | ...[...] | +| Arrays/Arrays.ps1:8:1:8:12 | ...[...] | Arrays/Arrays.ps1:8:1:8:23 | ...=... | +| Arrays/Arrays.ps1:8:1:8:23 | ...=... | Arrays/Arrays.ps1:1:1:15:14 | {...} | +| Arrays/Arrays.ps1:8:9:8:9 | 0 | Arrays/Arrays.ps1:8:9:8:11 | ...,... | +| Arrays/Arrays.ps1:8:9:8:11 | ...,... | Arrays/Arrays.ps1:8:1:8:12 | ...[...] | +| Arrays/Arrays.ps1:8:11:8:11 | 1 | Arrays/Arrays.ps1:8:9:8:11 | ...,... | +| Arrays/Arrays.ps1:8:16:8:23 | value1 | Arrays/Arrays.ps1:8:1:8:23 | ...=... | +| Arrays/Arrays.ps1:9:1:9:7 | array2 | Arrays/Arrays.ps1:9:1:9:12 | ...[...] | +| Arrays/Arrays.ps1:9:1:9:12 | ...[...] | Arrays/Arrays.ps1:9:1:9:20 | ...=... | +| Arrays/Arrays.ps1:9:1:9:20 | ...=... | Arrays/Arrays.ps1:1:1:15:14 | {...} | +| Arrays/Arrays.ps1:9:9:9:9 | 1 | Arrays/Arrays.ps1:9:9:9:11 | ...,... | +| Arrays/Arrays.ps1:9:9:9:11 | ...,... | Arrays/Arrays.ps1:9:1:9:12 | ...[...] | +| Arrays/Arrays.ps1:9:11:9:11 | 1 | Arrays/Arrays.ps1:9:9:9:11 | ...,... | +| Arrays/Arrays.ps1:9:16:9:20 | null | Arrays/Arrays.ps1:9:1:9:20 | ...=... | +| Arrays/Arrays.ps1:11:1:11:7 | array3 | Arrays/Arrays.ps1:1:1:15:14 | {...} | +| Arrays/Arrays.ps1:11:1:11:7 | array3 | Arrays/Arrays.ps1:11:1:11:24 | ...=... | +| Arrays/Arrays.ps1:11:1:11:24 | ...=... | Arrays/Arrays.ps1:1:1:15:14 | {...} | +| Arrays/Arrays.ps1:11:11:11:24 | @(...) | Arrays/Arrays.ps1:11:1:11:24 | ...=... | +| Arrays/Arrays.ps1:11:13:11:15 | a | Arrays/Arrays.ps1:11:13:11:23 | ...,... | +| Arrays/Arrays.ps1:11:13:11:23 | ...,... | Arrays/Arrays.ps1:11:13:11:23 | [Stmt] ...,... | +| Arrays/Arrays.ps1:11:13:11:23 | [Stmt] ...,... | Arrays/Arrays.ps1:11:13:11:23 | {...} | +| Arrays/Arrays.ps1:11:13:11:23 | {...} | Arrays/Arrays.ps1:11:11:11:24 | @(...) | +| Arrays/Arrays.ps1:11:17:11:19 | b | Arrays/Arrays.ps1:11:13:11:23 | ...,... | +| Arrays/Arrays.ps1:11:21:11:23 | c | Arrays/Arrays.ps1:11:13:11:23 | ...,... | +| Arrays/Arrays.ps1:12:1:12:7 | array3 | Arrays/Arrays.ps1:12:1:12:13 | count | +| Arrays/Arrays.ps1:12:1:12:13 | [Stmt] count | Arrays/Arrays.ps1:1:1:15:14 | {...} | +| Arrays/Arrays.ps1:12:1:12:13 | count | Arrays/Arrays.ps1:12:1:12:13 | [Stmt] count | +| Arrays/Arrays.ps1:12:9:12:13 | count | Arrays/Arrays.ps1:12:1:12:13 | count | +| Arrays/Arrays.ps1:14:1:14:7 | array4 | Arrays/Arrays.ps1:1:1:15:14 | {...} | +| Arrays/Arrays.ps1:14:1:14:7 | array4 | Arrays/Arrays.ps1:14:1:14:43 | ...=... | +| Arrays/Arrays.ps1:14:1:14:43 | ...=... | Arrays/Arrays.ps1:1:1:15:14 | {...} | +| Arrays/Arrays.ps1:14:11:14:40 | System.Collections.ArrayList | Arrays/Arrays.ps1:14:11:14:43 | [...]... | +| Arrays/Arrays.ps1:14:11:14:43 | [...]... | Arrays/Arrays.ps1:14:1:14:43 | ...=... | +| Arrays/Arrays.ps1:14:41:14:43 | @(...) | Arrays/Arrays.ps1:14:11:14:43 | [...]... | +| Arrays/Arrays.ps1:15:1:15:7 | array4 | Arrays/Arrays.ps1:15:1:15:14 | Call to Add | +| Arrays/Arrays.ps1:15:1:15:14 | Call to Add | Arrays/Arrays.ps1:15:1:15:14 | [Stmt] Call to Add | +| Arrays/Arrays.ps1:15:1:15:14 | [Stmt] Call to Add | Arrays/Arrays.ps1:1:1:15:14 | {...} | +| Arrays/Arrays.ps1:15:9:15:11 | Add | Arrays/Arrays.ps1:15:1:15:14 | Call to Add | +| Arrays/Arrays.ps1:15:13:15:13 | 1 | Arrays/Arrays.ps1:15:1:15:14 | Call to Add | +| Blocks/ParamBlock.ps1:1:1:1:17 | CmdletBinding | Blocks/ParamBlock.ps1:1:1:5:1 | {...} | +| Blocks/ParamBlock.ps1:1:1:5:1 | Parameter | Blocks/ParamBlock.ps1:1:1:5:1 | {...} | +| Blocks/ParamBlock.ps1:1:1:5:1 | [synth] pipeline | Blocks/ParamBlock.ps1:1:1:5:1 | {...} | +| Blocks/ParamBlock.ps1:1:1:5:1 | {...} | file://:0:0:0:0 | toplevel function for ParamBlock.ps1 | +| Blocks/ParamBlock.ps1:2:1:5:1 | {...} | Blocks/ParamBlock.ps1:1:1:5:1 | {...} | +| Blocks/ParamBlock.ps1:3:5:3:17 | Parameter | Blocks/ParamBlock.ps1:1:1:5:1 | Parameter | +| Blocks/ParamBlock.ps1:4:5:4:12 | string | Blocks/ParamBlock.ps1:1:1:5:1 | Parameter | +| Dynamic/DynamicExecution.ps1:1:1:1:4 | foo | Dynamic/DynamicExecution.ps1:1:1:1:16 | ...=... | +| Dynamic/DynamicExecution.ps1:1:1:1:4 | foo | Dynamic/DynamicExecution.ps1:1:1:5:7 | {...} | +| Dynamic/DynamicExecution.ps1:1:1:1:16 | ...=... | Dynamic/DynamicExecution.ps1:1:1:5:7 | {...} | +| Dynamic/DynamicExecution.ps1:1:1:5:7 | {...} | Dynamic/DynamicExecution.ps1:1:1:5:7 | {...} | +| Dynamic/DynamicExecution.ps1:1:1:5:7 | {...} | file://:0:0:0:0 | toplevel function for DynamicExecution.ps1 | +| Dynamic/DynamicExecution.ps1:1:8:1:16 | cmd.exe | Dynamic/DynamicExecution.ps1:1:1:1:16 | ...=... | +| Dynamic/DynamicExecution.ps1:2:1:2:17 | Invoke-Expression | Dynamic/DynamicExecution.ps1:2:1:2:22 | Call to Invoke-Expression | +| Dynamic/DynamicExecution.ps1:2:1:2:22 | Call to Invoke-Expression | Dynamic/DynamicExecution.ps1:2:1:2:22 | [Stmt] Call to Invoke-Expression | +| Dynamic/DynamicExecution.ps1:2:1:2:22 | [Stmt] Call to Invoke-Expression | Dynamic/DynamicExecution.ps1:1:1:5:7 | {...} | +| Dynamic/DynamicExecution.ps1:2:19:2:22 | foo | Dynamic/DynamicExecution.ps1:2:1:2:22 | Call to Invoke-Expression | +| Dynamic/DynamicExecution.ps1:3:1:3:13 | scriptblock | Dynamic/DynamicExecution.ps1:3:1:3:27 | Call to Create | +| Dynamic/DynamicExecution.ps1:3:1:3:27 | Call to Create | Dynamic/DynamicExecution.ps1:3:1:3:27 | [Stmt] Call to Create | +| Dynamic/DynamicExecution.ps1:3:1:3:27 | [Stmt] Call to Create | Dynamic/DynamicExecution.ps1:1:1:5:7 | {...} | +| Dynamic/DynamicExecution.ps1:3:16:3:21 | Create | Dynamic/DynamicExecution.ps1:3:1:3:27 | Call to Create | +| Dynamic/DynamicExecution.ps1:3:23:3:26 | foo | Dynamic/DynamicExecution.ps1:3:1:3:27 | Call to Create | +| Dynamic/DynamicExecution.ps1:4:1:4:31 | Call to | Dynamic/DynamicExecution.ps1:4:1:4:31 | [Stmt] Call to | +| Dynamic/DynamicExecution.ps1:4:1:4:31 | [Stmt] Call to | Dynamic/DynamicExecution.ps1:1:1:5:7 | {...} | +| Dynamic/DynamicExecution.ps1:4:3:4:31 | (...) | Dynamic/DynamicExecution.ps1:4:1:4:31 | Call to | +| Dynamic/DynamicExecution.ps1:4:4:4:16 | scriptblock | Dynamic/DynamicExecution.ps1:4:4:4:30 | Call to Create | +| Dynamic/DynamicExecution.ps1:4:4:4:30 | Call to Create | Dynamic/DynamicExecution.ps1:4:3:4:31 | (...) | +| Dynamic/DynamicExecution.ps1:4:19:4:24 | Create | Dynamic/DynamicExecution.ps1:4:4:4:30 | Call to Create | +| Dynamic/DynamicExecution.ps1:4:26:4:29 | foo | Dynamic/DynamicExecution.ps1:4:4:4:30 | Call to Create | +| Dynamic/DynamicExecution.ps1:5:1:5:7 | Call to | Dynamic/DynamicExecution.ps1:5:1:5:7 | [Stmt] Call to | +| Dynamic/DynamicExecution.ps1:5:1:5:7 | [Stmt] Call to | Dynamic/DynamicExecution.ps1:1:1:5:7 | {...} | +| Dynamic/DynamicExecution.ps1:5:2:5:7 | $foo | Dynamic/DynamicExecution.ps1:5:1:5:7 | Call to | +| Dynamic/DynamicExecution.ps1:5:3:5:6 | foo | Dynamic/DynamicExecution.ps1:5:2:5:7 | $foo | +| Dynamic/DynamicExecutionWithFunc.ps1:1:1:11:1 | ExecuteAThing | Dynamic/DynamicExecutionWithFunc.ps1:1:1:11:1 | def of ExecuteAThing | +| Dynamic/DynamicExecutionWithFunc.ps1:1:1:11:1 | def of ExecuteAThing | Dynamic/DynamicExecutionWithFunc.ps1:1:1:11:1 | {...} | +| Dynamic/DynamicExecutionWithFunc.ps1:1:1:11:1 | {...} | Dynamic/DynamicExecutionWithFunc.ps1:1:1:11:1 | {...} | +| Dynamic/DynamicExecutionWithFunc.ps1:1:1:11:1 | {...} | file://:0:0:0:0 | toplevel function for DynamicExecutionWithFunc.ps1 | +| Dynamic/DynamicExecutionWithFunc.ps1:1:24:11:1 | [synth] pipeline | Dynamic/DynamicExecutionWithFunc.ps1:1:24:11:1 | {...} | +| Dynamic/DynamicExecutionWithFunc.ps1:1:24:11:1 | userInput | Dynamic/DynamicExecutionWithFunc.ps1:1:24:11:1 | {...} | +| Dynamic/DynamicExecutionWithFunc.ps1:1:24:11:1 | {...} | Dynamic/DynamicExecutionWithFunc.ps1:1:1:11:1 | ExecuteAThing | +| Dynamic/DynamicExecutionWithFunc.ps1:2:5:10:29 | {...} | Dynamic/DynamicExecutionWithFunc.ps1:1:24:11:1 | {...} | +| Dynamic/DynamicExecutionWithFunc.ps1:5:5:5:8 | foo | Dynamic/DynamicExecutionWithFunc.ps1:1:24:11:1 | {...} | +| Dynamic/DynamicExecutionWithFunc.ps1:5:5:5:8 | foo | Dynamic/DynamicExecutionWithFunc.ps1:5:5:5:33 | ...=... | +| Dynamic/DynamicExecutionWithFunc.ps1:5:5:5:33 | ...=... | Dynamic/DynamicExecutionWithFunc.ps1:2:5:10:29 | {...} | +| Dynamic/DynamicExecutionWithFunc.ps1:5:12:5:20 | cmd.exe | Dynamic/DynamicExecutionWithFunc.ps1:5:12:5:33 | ...+... | +| Dynamic/DynamicExecutionWithFunc.ps1:5:12:5:33 | ...+... | Dynamic/DynamicExecutionWithFunc.ps1:5:5:5:33 | ...=... | +| Dynamic/DynamicExecutionWithFunc.ps1:5:24:5:33 | userInput | Dynamic/DynamicExecutionWithFunc.ps1:5:12:5:33 | ...+... | +| Dynamic/DynamicExecutionWithFunc.ps1:6:5:6:21 | Invoke-Expression | Dynamic/DynamicExecutionWithFunc.ps1:6:5:6:26 | Call to Invoke-Expression | +| Dynamic/DynamicExecutionWithFunc.ps1:6:5:6:26 | Call to Invoke-Expression | Dynamic/DynamicExecutionWithFunc.ps1:6:5:6:26 | [Stmt] Call to Invoke-Expression | +| Dynamic/DynamicExecutionWithFunc.ps1:6:5:6:26 | [Stmt] Call to Invoke-Expression | Dynamic/DynamicExecutionWithFunc.ps1:2:5:10:29 | {...} | +| Dynamic/DynamicExecutionWithFunc.ps1:6:23:6:26 | foo | Dynamic/DynamicExecutionWithFunc.ps1:6:5:6:26 | Call to Invoke-Expression | +| Dynamic/DynamicExecutionWithFunc.ps1:7:5:7:17 | scriptblock | Dynamic/DynamicExecutionWithFunc.ps1:7:5:7:31 | Call to Create | +| Dynamic/DynamicExecutionWithFunc.ps1:7:5:7:31 | Call to Create | Dynamic/DynamicExecutionWithFunc.ps1:7:5:7:31 | [Stmt] Call to Create | +| Dynamic/DynamicExecutionWithFunc.ps1:7:5:7:31 | [Stmt] Call to Create | Dynamic/DynamicExecutionWithFunc.ps1:2:5:10:29 | {...} | +| Dynamic/DynamicExecutionWithFunc.ps1:7:20:7:25 | Create | Dynamic/DynamicExecutionWithFunc.ps1:7:5:7:31 | Call to Create | +| Dynamic/DynamicExecutionWithFunc.ps1:7:27:7:30 | foo | Dynamic/DynamicExecutionWithFunc.ps1:7:5:7:31 | Call to Create | +| Dynamic/DynamicExecutionWithFunc.ps1:8:5:8:35 | Call to | Dynamic/DynamicExecutionWithFunc.ps1:8:5:8:35 | [Stmt] Call to | +| Dynamic/DynamicExecutionWithFunc.ps1:8:5:8:35 | [Stmt] Call to | Dynamic/DynamicExecutionWithFunc.ps1:2:5:10:29 | {...} | +| Dynamic/DynamicExecutionWithFunc.ps1:8:7:8:35 | (...) | Dynamic/DynamicExecutionWithFunc.ps1:8:5:8:35 | Call to | +| Dynamic/DynamicExecutionWithFunc.ps1:8:8:8:20 | scriptblock | Dynamic/DynamicExecutionWithFunc.ps1:8:8:8:34 | Call to Create | +| Dynamic/DynamicExecutionWithFunc.ps1:8:8:8:34 | Call to Create | Dynamic/DynamicExecutionWithFunc.ps1:8:7:8:35 | (...) | +| Dynamic/DynamicExecutionWithFunc.ps1:8:23:8:28 | Create | Dynamic/DynamicExecutionWithFunc.ps1:8:8:8:34 | Call to Create | +| Dynamic/DynamicExecutionWithFunc.ps1:8:30:8:33 | foo | Dynamic/DynamicExecutionWithFunc.ps1:8:8:8:34 | Call to Create | +| Dynamic/DynamicExecutionWithFunc.ps1:9:5:9:11 | Call to | Dynamic/DynamicExecutionWithFunc.ps1:9:5:9:11 | [Stmt] Call to | +| Dynamic/DynamicExecutionWithFunc.ps1:9:5:9:11 | [Stmt] Call to | Dynamic/DynamicExecutionWithFunc.ps1:2:5:10:29 | {...} | +| Dynamic/DynamicExecutionWithFunc.ps1:9:6:9:11 | $foo | Dynamic/DynamicExecutionWithFunc.ps1:9:5:9:11 | Call to | +| Dynamic/DynamicExecutionWithFunc.ps1:9:7:9:10 | foo | Dynamic/DynamicExecutionWithFunc.ps1:9:6:9:11 | $foo | +| Dynamic/DynamicExecutionWithFunc.ps1:10:5:10:29 | Call to cmd.exe | Dynamic/DynamicExecutionWithFunc.ps1:10:5:10:29 | [Stmt] Call to cmd.exe | +| Dynamic/DynamicExecutionWithFunc.ps1:10:5:10:29 | [Stmt] Call to cmd.exe | Dynamic/DynamicExecutionWithFunc.ps1:2:5:10:29 | {...} | +| Dynamic/DynamicExecutionWithFunc.ps1:10:7:10:15 | cmd.exe | Dynamic/DynamicExecutionWithFunc.ps1:10:5:10:29 | Call to cmd.exe | +| Dynamic/DynamicExecutionWithFunc.ps1:10:17:10:29 | @(...) | Dynamic/DynamicExecutionWithFunc.ps1:10:5:10:29 | Call to cmd.exe | +| Dynamic/DynamicExecutionWithFunc.ps1:10:19:10:28 | [Stmt] userInput | Dynamic/DynamicExecutionWithFunc.ps1:10:19:10:28 | {...} | +| Dynamic/DynamicExecutionWithFunc.ps1:10:19:10:28 | userInput | Dynamic/DynamicExecutionWithFunc.ps1:10:19:10:28 | [Stmt] userInput | +| Dynamic/DynamicExecutionWithFunc.ps1:10:19:10:28 | {...} | Dynamic/DynamicExecutionWithFunc.ps1:10:17:10:29 | @(...) | +| Expressions/BinaryExpression.ps1:1:1:1:5 | val1 | Expressions/BinaryExpression.ps1:1:1:1:9 | ...=... | +| Expressions/BinaryExpression.ps1:1:1:1:5 | val1 | Expressions/BinaryExpression.ps1:1:1:4:7 | {...} | +| Expressions/BinaryExpression.ps1:1:1:1:9 | ...=... | Expressions/BinaryExpression.ps1:1:1:4:7 | {...} | +| Expressions/BinaryExpression.ps1:1:1:4:7 | {...} | Expressions/BinaryExpression.ps1:1:1:4:7 | {...} | +| Expressions/BinaryExpression.ps1:1:1:4:7 | {...} | file://:0:0:0:0 | toplevel function for BinaryExpression.ps1 | +| Expressions/BinaryExpression.ps1:1:9:1:9 | 1 | Expressions/BinaryExpression.ps1:1:1:1:9 | ...=... | +| Expressions/BinaryExpression.ps1:2:1:2:5 | val2 | Expressions/BinaryExpression.ps1:1:1:4:7 | {...} | +| Expressions/BinaryExpression.ps1:2:1:2:5 | val2 | Expressions/BinaryExpression.ps1:2:1:2:9 | ...=... | +| Expressions/BinaryExpression.ps1:2:1:2:9 | ...=... | Expressions/BinaryExpression.ps1:1:1:4:7 | {...} | +| Expressions/BinaryExpression.ps1:2:9:2:9 | 2 | Expressions/BinaryExpression.ps1:2:1:2:9 | ...=... | +| Expressions/BinaryExpression.ps1:3:1:3:7 | result | Expressions/BinaryExpression.ps1:1:1:4:7 | {...} | +| Expressions/BinaryExpression.ps1:3:1:3:7 | result | Expressions/BinaryExpression.ps1:3:1:3:23 | ...=... | +| Expressions/BinaryExpression.ps1:3:1:3:23 | ...=... | Expressions/BinaryExpression.ps1:1:1:4:7 | {...} | +| Expressions/BinaryExpression.ps1:3:11:3:15 | val1 | Expressions/BinaryExpression.ps1:3:11:3:23 | ...+... | +| Expressions/BinaryExpression.ps1:3:11:3:23 | ...+... | Expressions/BinaryExpression.ps1:3:1:3:23 | ...=... | +| Expressions/BinaryExpression.ps1:3:19:3:23 | val2 | Expressions/BinaryExpression.ps1:3:11:3:23 | ...+... | +| Expressions/BinaryExpression.ps1:4:1:4:7 | [Stmt] result | Expressions/BinaryExpression.ps1:1:1:4:7 | {...} | +| Expressions/BinaryExpression.ps1:4:1:4:7 | result | Expressions/BinaryExpression.ps1:4:1:4:7 | [Stmt] result | +| Expressions/ConvertWithSecureString.ps1:1:1:1:10 | UserInput | Expressions/ConvertWithSecureString.ps1:1:1:1:54 | ...=... | +| Expressions/ConvertWithSecureString.ps1:1:1:1:10 | UserInput | Expressions/ConvertWithSecureString.ps1:1:1:2:79 | {...} | +| Expressions/ConvertWithSecureString.ps1:1:1:1:54 | ...=... | Expressions/ConvertWithSecureString.ps1:1:1:2:79 | {...} | +| Expressions/ConvertWithSecureString.ps1:1:1:2:79 | {...} | Expressions/ConvertWithSecureString.ps1:1:1:2:79 | {...} | +| Expressions/ConvertWithSecureString.ps1:1:1:2:79 | {...} | file://:0:0:0:0 | toplevel function for ConvertWithSecureString.ps1 | +| Expressions/ConvertWithSecureString.ps1:1:14:1:22 | Read-Host | Expressions/ConvertWithSecureString.ps1:1:14:1:54 | Call to Read-Host | +| Expressions/ConvertWithSecureString.ps1:1:14:1:54 | Call to Read-Host | Expressions/ConvertWithSecureString.ps1:1:1:1:54 | ...=... | +| Expressions/ConvertWithSecureString.ps1:1:24:1:54 | Please enter your secure code | Expressions/ConvertWithSecureString.ps1:1:14:1:54 | Call to Read-Host | +| Expressions/ConvertWithSecureString.ps1:2:1:2:15 | EncryptedInput | Expressions/ConvertWithSecureString.ps1:1:1:2:79 | {...} | +| Expressions/ConvertWithSecureString.ps1:2:1:2:15 | EncryptedInput | Expressions/ConvertWithSecureString.ps1:2:1:2:79 | ...=... | +| Expressions/ConvertWithSecureString.ps1:2:1:2:79 | ...=... | Expressions/ConvertWithSecureString.ps1:1:1:2:79 | {...} | +| Expressions/ConvertWithSecureString.ps1:2:19:2:40 | ConvertTo-SecureString | Expressions/ConvertWithSecureString.ps1:2:19:2:79 | Call to ConvertTo-SecureString | +| Expressions/ConvertWithSecureString.ps1:2:19:2:79 | Call to ConvertTo-SecureString | Expressions/ConvertWithSecureString.ps1:2:1:2:79 | ...=... | +| Expressions/ConvertWithSecureString.ps1:2:50:2:59 | UserInput | Expressions/ConvertWithSecureString.ps1:2:19:2:79 | Call to ConvertTo-SecureString | +| Expressions/ExpandableString.ps1:1:1:1:39 | Date: $([DateTime]::Now)\nName: $name | Expressions/ExpandableString.ps1:1:1:1:39 | [Stmt] Date: $([DateTime]::Now)\nName: $name | +| Expressions/ExpandableString.ps1:1:1:1:39 | [Stmt] Date: $([DateTime]::Now)\nName: $name | Expressions/ExpandableString.ps1:1:1:1:39 | {...} | +| Expressions/ExpandableString.ps1:1:1:1:39 | {...} | Expressions/ExpandableString.ps1:1:1:1:39 | {...} | +| Expressions/ExpandableString.ps1:1:1:1:39 | {...} | file://:0:0:0:0 | toplevel function for ExpandableString.ps1 | +| Expressions/ExpandableString.ps1:1:21:1:38 | $(...) | Expressions/ExpandableString.ps1:1:1:1:39 | Date: $([DateTime]::Now)\nName: $name | +| Expressions/ExpandableString.ps1:1:23:1:32 | DateTime | Expressions/ExpandableString.ps1:1:23:1:37 | Now | +| Expressions/ExpandableString.ps1:1:23:1:37 | Now | Expressions/ExpandableString.ps1:1:23:1:37 | [Stmt] Now | +| Expressions/ExpandableString.ps1:1:23:1:37 | [Stmt] Now | Expressions/ExpandableString.ps1:1:23:1:37 | {...} | +| Expressions/ExpandableString.ps1:1:23:1:37 | {...} | Expressions/ExpandableString.ps1:1:21:1:38 | $(...) | +| Expressions/ExpandableString.ps1:1:35:1:37 | Now | Expressions/ExpandableString.ps1:1:23:1:37 | Now | +| Expressions/SubExpression.ps1:1:1:1:11 | $(...) | Expressions/SubExpression.ps1:1:1:1:23 | Call to AddDays | +| Expressions/SubExpression.ps1:1:1:1:23 | Call to AddDays | Expressions/SubExpression.ps1:1:1:1:23 | [Stmt] Call to AddDays | +| Expressions/SubExpression.ps1:1:1:1:23 | [Stmt] Call to AddDays | Expressions/SubExpression.ps1:1:1:2:21 | {...} | +| Expressions/SubExpression.ps1:1:1:2:21 | {...} | Expressions/SubExpression.ps1:1:1:2:21 | {...} | +| Expressions/SubExpression.ps1:1:1:2:21 | {...} | file://:0:0:0:0 | toplevel function for SubExpression.ps1 | +| Expressions/SubExpression.ps1:1:3:1:10 | Call to Get-Date | Expressions/SubExpression.ps1:1:3:1:10 | [Stmt] Call to Get-Date | +| Expressions/SubExpression.ps1:1:3:1:10 | Get-Date | Expressions/SubExpression.ps1:1:3:1:10 | Call to Get-Date | +| Expressions/SubExpression.ps1:1:3:1:10 | [Stmt] Call to Get-Date | Expressions/SubExpression.ps1:1:3:1:10 | {...} | +| Expressions/SubExpression.ps1:1:3:1:10 | {...} | Expressions/SubExpression.ps1:1:1:1:11 | $(...) | +| Expressions/SubExpression.ps1:1:13:1:19 | AddDays | Expressions/SubExpression.ps1:1:1:1:23 | Call to AddDays | +| Expressions/SubExpression.ps1:1:21:1:22 | 10 | Expressions/SubExpression.ps1:1:1:1:23 | Call to AddDays | +| Expressions/SubExpression.ps1:2:1:2:11 | $(...) | Expressions/SubExpression.ps1:2:1:2:21 | Call to AddDays | +| Expressions/SubExpression.ps1:2:1:2:21 | Call to AddDays | Expressions/SubExpression.ps1:2:1:2:21 | [Stmt] Call to AddDays | +| Expressions/SubExpression.ps1:2:1:2:21 | [Stmt] Call to AddDays | Expressions/SubExpression.ps1:1:1:2:21 | {...} | +| Expressions/SubExpression.ps1:2:3:2:10 | Call to Get-Date | Expressions/SubExpression.ps1:2:3:2:10 | [Stmt] Call to Get-Date | +| Expressions/SubExpression.ps1:2:3:2:10 | Get-Date | Expressions/SubExpression.ps1:2:3:2:10 | Call to Get-Date | +| Expressions/SubExpression.ps1:2:3:2:10 | [Stmt] Call to Get-Date | Expressions/SubExpression.ps1:2:3:2:10 | {...} | +| Expressions/SubExpression.ps1:2:3:2:10 | {...} | Expressions/SubExpression.ps1:2:1:2:11 | $(...) | +| Expressions/SubExpression.ps1:2:13:2:19 | AddDays | Expressions/SubExpression.ps1:2:1:2:21 | Call to AddDays | +| Expressions/TernaryExpression.ps1:1:1:1:4 | var | Expressions/TernaryExpression.ps1:1:1:1:22 | ...=... | +| Expressions/TernaryExpression.ps1:1:1:1:4 | var | Expressions/TernaryExpression.ps1:1:1:1:22 | {...} | +| Expressions/TernaryExpression.ps1:1:1:1:22 | ...=... | Expressions/TernaryExpression.ps1:1:1:1:22 | {...} | +| Expressions/TernaryExpression.ps1:1:1:1:22 | {...} | Expressions/TernaryExpression.ps1:1:1:1:22 | {...} | +| Expressions/TernaryExpression.ps1:1:1:1:22 | {...} | file://:0:0:0:0 | toplevel function for TernaryExpression.ps1 | +| Expressions/TernaryExpression.ps1:1:8:1:16 | (...) | Expressions/TernaryExpression.ps1:1:8:1:22 | ...?...:... | +| Expressions/TernaryExpression.ps1:1:8:1:22 | ...?...:... | Expressions/TernaryExpression.ps1:1:1:1:22 | ...=... | +| Expressions/TernaryExpression.ps1:1:9:1:9 | 6 | Expressions/TernaryExpression.ps1:1:9:1:15 | ... -gt ... | +| Expressions/TernaryExpression.ps1:1:9:1:15 | ... -gt ... | Expressions/TernaryExpression.ps1:1:8:1:16 | (...) | +| Expressions/TernaryExpression.ps1:1:15:1:15 | 7 | Expressions/TernaryExpression.ps1:1:9:1:15 | ... -gt ... | +| Expressions/TernaryExpression.ps1:1:20:1:20 | 1 | Expressions/TernaryExpression.ps1:1:8:1:22 | ...?...:... | +| Expressions/TernaryExpression.ps1:1:22:1:22 | 2 | Expressions/TernaryExpression.ps1:1:8:1:22 | ...?...:... | +| Loops/DoUntil.ps1:1:1:7:18 | do...until... | Loops/DoUntil.ps1:1:1:7:18 | {...} | +| Loops/DoUntil.ps1:1:1:7:18 | {...} | Loops/DoUntil.ps1:1:1:7:18 | {...} | +| Loops/DoUntil.ps1:1:1:7:18 | {...} | file://:0:0:0:0 | toplevel function for DoUntil.ps1 | +| Loops/DoUntil.ps1:2:1:7:1 | {...} | Loops/DoUntil.ps1:1:1:7:18 | do...until... | +| Loops/DoUntil.ps1:3:2:3:19 | Starting Loop $a | Loops/DoUntil.ps1:3:2:3:19 | [Stmt] Starting Loop $a | +| Loops/DoUntil.ps1:3:2:3:19 | [Stmt] Starting Loop $a | Loops/DoUntil.ps1:2:1:7:1 | {...} | +| Loops/DoUntil.ps1:4:2:4:3 | (no string representation) | Loops/DoUntil.ps1:2:1:7:1 | {...} | +| Loops/DoUntil.ps1:5:2:5:5 | ...++ | Loops/DoUntil.ps1:5:2:5:5 | [Stmt] ...++ | +| Loops/DoUntil.ps1:5:2:5:5 | [Stmt] ...++ | Loops/DoUntil.ps1:2:1:7:1 | {...} | +| Loops/DoUntil.ps1:6:2:6:16 | Now $a is $a | Loops/DoUntil.ps1:6:2:6:16 | [Stmt] Now $a is $a | +| Loops/DoUntil.ps1:6:2:6:16 | [Stmt] Now $a is $a | Loops/DoUntil.ps1:2:1:7:1 | {...} | +| Loops/DoUntil.ps1:7:10:7:17 | ... -le ... | Loops/DoUntil.ps1:1:1:7:18 | do...until... | +| Loops/DoUntil.ps1:7:17:7:17 | 5 | Loops/DoUntil.ps1:7:10:7:17 | ... -le ... | +| Loops/DoWhile.ps1:1:1:7:18 | do...while... | Loops/DoWhile.ps1:1:1:7:18 | {...} | +| Loops/DoWhile.ps1:1:1:7:18 | {...} | Loops/DoWhile.ps1:1:1:7:18 | {...} | +| Loops/DoWhile.ps1:1:1:7:18 | {...} | file://:0:0:0:0 | toplevel function for DoWhile.ps1 | +| Loops/DoWhile.ps1:2:1:7:1 | {...} | Loops/DoWhile.ps1:1:1:7:18 | do...while... | +| Loops/DoWhile.ps1:3:2:3:19 | Starting Loop $a | Loops/DoWhile.ps1:3:2:3:19 | [Stmt] Starting Loop $a | +| Loops/DoWhile.ps1:3:2:3:19 | [Stmt] Starting Loop $a | Loops/DoWhile.ps1:2:1:7:1 | {...} | +| Loops/DoWhile.ps1:4:2:4:3 | (no string representation) | Loops/DoWhile.ps1:2:1:7:1 | {...} | +| Loops/DoWhile.ps1:5:2:5:5 | ...++ | Loops/DoWhile.ps1:5:2:5:5 | [Stmt] ...++ | +| Loops/DoWhile.ps1:5:2:5:5 | [Stmt] ...++ | Loops/DoWhile.ps1:2:1:7:1 | {...} | +| Loops/DoWhile.ps1:6:2:6:16 | Now $a is $a | Loops/DoWhile.ps1:6:2:6:16 | [Stmt] Now $a is $a | +| Loops/DoWhile.ps1:6:2:6:16 | [Stmt] Now $a is $a | Loops/DoWhile.ps1:2:1:7:1 | {...} | +| Loops/DoWhile.ps1:7:10:7:17 | ... -le ... | Loops/DoWhile.ps1:1:1:7:18 | do...while... | +| Loops/DoWhile.ps1:7:17:7:17 | 5 | Loops/DoWhile.ps1:7:10:7:17 | ... -le ... | +| Loops/While.ps1:1:1:1:4 | var | Loops/While.ps1:1:1:1:8 | ...=... | +| Loops/While.ps1:1:1:1:4 | var | Loops/While.ps1:1:1:13:1 | {...} | +| Loops/While.ps1:1:1:1:8 | ...=... | Loops/While.ps1:1:1:13:1 | {...} | +| Loops/While.ps1:1:1:13:1 | {...} | Loops/While.ps1:1:1:13:1 | {...} | +| Loops/While.ps1:1:1:13:1 | {...} | file://:0:0:0:0 | toplevel function for While.ps1 | +| Loops/While.ps1:1:8:1:8 | 1 | Loops/While.ps1:1:1:1:8 | ...=... | +| Loops/While.ps1:2:1:13:1 | while(...) {...} | Loops/While.ps1:1:1:13:1 | {...} | +| Loops/While.ps1:2:8:2:11 | var | Loops/While.ps1:2:8:2:17 | ... -le ... | +| Loops/While.ps1:2:8:2:17 | ... -le ... | Loops/While.ps1:2:1:13:1 | while(...) {...} | +| Loops/While.ps1:2:17:2:17 | 5 | Loops/While.ps1:2:8:2:17 | ... -le ... | +| Loops/While.ps1:3:1:13:1 | {...} | Loops/While.ps1:2:1:13:1 | while(...) {...} | +| Loops/While.ps1:4:5:4:14 | Write-Host | Loops/While.ps1:4:5:4:40 | Call to Write-Host | +| Loops/While.ps1:4:5:4:40 | Call to Write-Host | Loops/While.ps1:4:5:4:40 | [Stmt] Call to Write-Host | +| Loops/While.ps1:4:5:4:40 | [Stmt] Call to Write-Host | Loops/While.ps1:3:1:13:1 | {...} | +| Loops/While.ps1:4:16:4:18 | The | Loops/While.ps1:4:5:4:40 | Call to Write-Host | +| Loops/While.ps1:4:20:4:24 | value | Loops/While.ps1:4:5:4:40 | Call to Write-Host | +| Loops/While.ps1:4:26:4:27 | of | Loops/While.ps1:4:5:4:40 | Call to Write-Host | +| Loops/While.ps1:4:29:4:31 | Var | Loops/While.ps1:4:5:4:40 | Call to Write-Host | +| Loops/While.ps1:4:33:4:35 | is: | Loops/While.ps1:4:5:4:40 | Call to Write-Host | +| Loops/While.ps1:4:37:4:40 | var | Loops/While.ps1:4:5:4:40 | Call to Write-Host | +| Loops/While.ps1:5:5:5:8 | var | Loops/While.ps1:5:5:5:10 | ...++ | +| Loops/While.ps1:5:5:5:10 | ...++ | Loops/While.ps1:5:5:5:10 | [Stmt] ...++ | +| Loops/While.ps1:5:5:5:10 | [Stmt] ...++ | Loops/While.ps1:3:1:13:1 | {...} | +| Loops/While.ps1:6:5:12:5 | [Stmt] if (...) {...} else {...} | Loops/While.ps1:3:1:13:1 | {...} | +| Loops/While.ps1:6:5:12:5 | if (...) {...} else {...} | Loops/While.ps1:6:5:12:5 | [Stmt] if (...) {...} else {...} | +| Loops/While.ps1:6:9:6:12 | var | Loops/While.ps1:6:9:6:18 | ... -le ... | +| Loops/While.ps1:6:9:6:18 | ... -le ... | Loops/While.ps1:6:5:12:5 | if (...) {...} else {...} | +| Loops/While.ps1:6:18:6:18 | 3 | Loops/While.ps1:6:9:6:18 | ... -le ... | +| Loops/While.ps1:6:20:8:5 | {...} | Loops/While.ps1:6:5:12:5 | if (...) {...} else {...} | +| Loops/While.ps1:7:9:7:16 | continue | Loops/While.ps1:6:20:8:5 | {...} | +| Loops/While.ps1:10:5:12:5 | {...} | Loops/While.ps1:6:5:12:5 | if (...) {...} else {...} | +| Loops/While.ps1:11:9:11:13 | break | Loops/While.ps1:10:5:12:5 | {...} | +| Redirections/FileRedirection.ps1:1:1:3:1 | $(...) | Redirections/FileRedirection.ps1:1:1:3:19 | [Stmt] $(...) | +| Redirections/FileRedirection.ps1:1:1:3:19 | [Stmt] $(...) | Redirections/FileRedirection.ps1:1:1:3:19 | {...} | +| Redirections/FileRedirection.ps1:1:1:3:19 | {...} | Redirections/FileRedirection.ps1:1:1:3:19 | {...} | +| Redirections/FileRedirection.ps1:1:1:3:19 | {...} | file://:0:0:0:0 | toplevel function for FileRedirection.ps1 | +| Redirections/FileRedirection.ps1:2:5:2:8 | Here | Redirections/FileRedirection.ps1:2:5:2:31 | Call to Here | +| Redirections/FileRedirection.ps1:2:5:2:31 | Call to Here | Redirections/FileRedirection.ps1:2:5:2:31 | [Stmt] Call to Here | +| Redirections/FileRedirection.ps1:2:5:2:31 | [Stmt] Call to Here | Redirections/FileRedirection.ps1:2:5:2:31 | {...} | +| Redirections/FileRedirection.ps1:2:5:2:31 | {...} | Redirections/FileRedirection.ps1:1:1:3:1 | $(...) | +| Redirections/FileRedirection.ps1:2:10:2:11 | is | Redirections/FileRedirection.ps1:2:5:2:31 | Call to Here | +| Redirections/FileRedirection.ps1:2:13:2:16 | your | Redirections/FileRedirection.ps1:2:5:2:31 | Call to Here | +| Redirections/FileRedirection.ps1:2:18:2:24 | current | Redirections/FileRedirection.ps1:2:5:2:31 | Call to Here | +| Redirections/FileRedirection.ps1:2:26:2:31 | script | Redirections/FileRedirection.ps1:2:5:2:31 | Call to Here | +| Redirections/FileRedirection.ps1:3:10:3:19 | output.txt | Redirections/FileRedirection.ps1:3:8:3:19 | FileRedirection | +| Statements/ExitStatement.ps1:1:1:1:7 | exit ... | Statements/ExitStatement.ps1:1:1:1:7 | {...} | +| Statements/ExitStatement.ps1:1:1:1:7 | {...} | Statements/ExitStatement.ps1:1:1:1:7 | {...} | +| Statements/ExitStatement.ps1:1:1:1:7 | {...} | file://:0:0:0:0 | toplevel function for ExitStatement.ps1 | +| Statements/ExitStatement.ps1:1:6:1:7 | -1 | Statements/ExitStatement.ps1:1:1:1:7 | exit ... | +| Statements/IfStatement.ps1:1:1:1:2 | x | Statements/IfStatement.ps1:1:1:1:6 | ...=... | +| Statements/IfStatement.ps1:1:1:1:2 | x | Statements/IfStatement.ps1:1:1:8:1 | {...} | +| Statements/IfStatement.ps1:1:1:1:6 | ...=... | Statements/IfStatement.ps1:1:1:8:1 | {...} | +| Statements/IfStatement.ps1:1:1:8:1 | {...} | Statements/IfStatement.ps1:1:1:8:1 | {...} | +| Statements/IfStatement.ps1:1:1:8:1 | {...} | file://:0:0:0:0 | toplevel function for IfStatement.ps1 | +| Statements/IfStatement.ps1:1:6:1:6 | 4 | Statements/IfStatement.ps1:1:1:1:6 | ...=... | +| Statements/IfStatement.ps1:3:1:8:1 | [Stmt] if (...) {...} else {...} | Statements/IfStatement.ps1:1:1:8:1 | {...} | +| Statements/IfStatement.ps1:3:1:8:1 | if (...) {...} else {...} | Statements/IfStatement.ps1:3:1:8:1 | [Stmt] if (...) {...} else {...} | +| Statements/IfStatement.ps1:3:5:3:6 | x | Statements/IfStatement.ps1:3:5:3:12 | ... -ge ... | +| Statements/IfStatement.ps1:3:5:3:12 | ... -ge ... | Statements/IfStatement.ps1:3:1:8:1 | if (...) {...} else {...} | +| Statements/IfStatement.ps1:3:12:3:12 | 3 | Statements/IfStatement.ps1:3:5:3:12 | ... -ge ... | +| Statements/IfStatement.ps1:3:15:5:1 | {...} | Statements/IfStatement.ps1:3:1:8:1 | if (...) {...} else {...} | +| Statements/IfStatement.ps1:4:2:4:35 | $x is greater than or equal to 3 | Statements/IfStatement.ps1:4:2:4:35 | [Stmt] $x is greater than or equal to 3 | +| Statements/IfStatement.ps1:4:2:4:35 | [Stmt] $x is greater than or equal to 3 | Statements/IfStatement.ps1:3:15:5:1 | {...} | +| Statements/IfStatement.ps1:4:3:4:4 | x | Statements/IfStatement.ps1:4:2:4:35 | $x is greater than or equal to 3 | +| Statements/IfStatement.ps1:6:6:8:1 | {...} | Statements/IfStatement.ps1:3:1:8:1 | if (...) {...} else {...} | +| Statements/IfStatement.ps1:7:2:7:20 | $x is less than 3 | Statements/IfStatement.ps1:7:2:7:20 | [Stmt] $x is less than 3 | +| Statements/IfStatement.ps1:7:2:7:20 | [Stmt] $x is less than 3 | Statements/IfStatement.ps1:6:6:8:1 | {...} | +| Statements/IfStatement.ps1:7:3:7:4 | x | Statements/IfStatement.ps1:7:2:7:20 | $x is less than 3 | +| Statements/TrapStatement.ps1:1:1:4:1 | TrapTest | Statements/TrapStatement.ps1:1:1:4:1 | def of TrapTest | +| Statements/TrapStatement.ps1:1:1:4:1 | def of TrapTest | Statements/TrapStatement.ps1:1:1:6:8 | {...} | +| Statements/TrapStatement.ps1:1:1:6:8 | {...} | Statements/TrapStatement.ps1:1:1:6:8 | {...} | +| Statements/TrapStatement.ps1:1:1:6:8 | {...} | file://:0:0:0:0 | toplevel function for TrapStatement.ps1 | +| Statements/TrapStatement.ps1:1:19:4:1 | {...} | Statements/TrapStatement.ps1:1:1:4:1 | TrapTest | +| Statements/TrapStatement.ps1:2:5:2:25 | trap {...} | Statements/TrapStatement.ps1:2:5:3:18 | {...} | +| Statements/TrapStatement.ps1:2:5:3:18 | {...} | Statements/TrapStatement.ps1:1:19:4:1 | {...} | +| Statements/TrapStatement.ps1:2:10:2:25 | {...} | Statements/TrapStatement.ps1:2:5:2:25 | trap {...} | +| Statements/TrapStatement.ps1:2:11:2:24 | Error found. | Statements/TrapStatement.ps1:2:11:2:24 | [Stmt] Error found. | +| Statements/TrapStatement.ps1:2:11:2:24 | [Stmt] Error found. | Statements/TrapStatement.ps1:2:10:2:25 | {...} | +| Statements/TrapStatement.ps1:3:5:3:18 | Call to nonsenseString | Statements/TrapStatement.ps1:3:5:3:18 | [Stmt] Call to nonsenseString | +| Statements/TrapStatement.ps1:3:5:3:18 | [Stmt] Call to nonsenseString | Statements/TrapStatement.ps1:2:5:3:18 | {...} | +| Statements/TrapStatement.ps1:3:5:3:18 | nonsenseString | Statements/TrapStatement.ps1:3:5:3:18 | Call to nonsenseString | +| Statements/TrapStatement.ps1:6:1:6:8 | Call to TrapTest | Statements/TrapStatement.ps1:6:1:6:8 | [Stmt] Call to TrapTest | +| Statements/TrapStatement.ps1:6:1:6:8 | TrapTest | Statements/TrapStatement.ps1:6:1:6:8 | Call to TrapTest | +| Statements/TrapStatement.ps1:6:1:6:8 | [Stmt] Call to TrapTest | Statements/TrapStatement.ps1:1:1:6:8 | {...} | +| Statements/Try.ps1:1:1:13:1 | try {...} | Statements/Try.ps1:1:1:13:1 | {...} | +| Statements/Try.ps1:1:1:13:1 | {...} | Statements/Try.ps1:1:1:13:1 | {...} | +| Statements/Try.ps1:1:1:13:1 | {...} | file://:0:0:0:0 | toplevel function for Try.ps1 | +| Statements/Try.ps1:1:5:4:1 | {...} | Statements/Try.ps1:1:1:13:1 | try {...} | +| Statements/Try.ps1:2:4:2:13 | Exception | Statements/Try.ps1:1:1:13:1 | {...} | +| Statements/Try.ps1:2:4:2:13 | Exception | Statements/Try.ps1:2:4:2:94 | ...=... | +| Statements/Try.ps1:2:4:2:94 | ...=... | Statements/Try.ps1:1:5:4:1 | {...} | +| Statements/Try.ps1:2:17:2:26 | New-Object | Statements/Try.ps1:2:17:2:94 | Call to New-Object | +| Statements/Try.ps1:2:17:2:94 | Call to New-Object | Statements/Try.ps1:2:4:2:94 | ...=... | +| Statements/Try.ps1:2:28:2:52 | System.Xaml.XamlException | Statements/Try.ps1:2:17:2:94 | Call to New-Object | +| Statements/Try.ps1:2:68:2:94 | (...) | Statements/Try.ps1:2:17:2:94 | Call to New-Object | +| Statements/Try.ps1:2:69:2:79 | Bad XAML! | Statements/Try.ps1:2:69:2:93 | ...,... | +| Statements/Try.ps1:2:69:2:93 | ...,... | Statements/Try.ps1:2:68:2:94 | (...) | +| Statements/Try.ps1:2:82:2:86 | null | Statements/Try.ps1:2:69:2:93 | ...,... | +| Statements/Try.ps1:2:89:2:90 | 10 | Statements/Try.ps1:2:69:2:93 | ...,... | +| Statements/Try.ps1:2:93:2:93 | 2 | Statements/Try.ps1:2:69:2:93 | ...,... | +| Statements/Try.ps1:3:5:3:20 | throw ... | Statements/Try.ps1:1:5:4:1 | {...} | +| Statements/Try.ps1:3:11:3:20 | Exception | Statements/Try.ps1:3:5:3:20 | throw ... | +| Statements/Try.ps1:5:1:7:1 | catch[...] {...} | Statements/Try.ps1:1:1:13:1 | try {...} | +| Statements/Try.ps1:5:7:5:31 | System.Net.WebException | Statements/Try.ps1:5:1:7:1 | catch[...] {...} | +| Statements/Try.ps1:5:33:5:55 | System.IO.IOException | Statements/Try.ps1:5:1:7:1 | catch[...] {...} | +| Statements/Try.ps1:5:57:7:1 | {...} | Statements/Try.ps1:5:1:7:1 | catch[...] {...} | +| Statements/Try.ps1:6:5:6:63 | Unable to download MyDoc.doc from http://www.contoso.com. | Statements/Try.ps1:6:5:6:63 | [Stmt] Unable to download MyDoc.doc from http://www.contoso.com. | +| Statements/Try.ps1:6:5:6:63 | [Stmt] Unable to download MyDoc.doc from http://www.contoso.com. | Statements/Try.ps1:5:57:7:1 | {...} | +| Statements/Try.ps1:8:1:10:1 | catch {...} | Statements/Try.ps1:1:1:13:1 | try {...} | +| Statements/Try.ps1:8:7:10:1 | {...} | Statements/Try.ps1:8:1:10:1 | catch {...} | +| Statements/Try.ps1:9:5:9:51 | An error occurred that could not be resolved. | Statements/Try.ps1:9:5:9:51 | [Stmt] An error occurred that could not be resolved. | +| Statements/Try.ps1:9:5:9:51 | [Stmt] An error occurred that could not be resolved. | Statements/Try.ps1:8:7:10:1 | {...} | +| Statements/Try.ps1:11:9:13:1 | {...} | Statements/Try.ps1:1:1:13:1 | try {...} | +| Statements/Try.ps1:12:5:12:36 | The finally block is executed. | Statements/Try.ps1:12:5:12:36 | [Stmt] The finally block is executed. | +| Statements/Try.ps1:12:5:12:36 | [Stmt] The finally block is executed. | Statements/Try.ps1:11:9:13:1 | {...} | +| Statements/UseProcessBlockForPipelineCommand.ps1:1:1:11:1 | Get-Number | Statements/UseProcessBlockForPipelineCommand.ps1:1:1:11:1 | def of Get-Number | +| Statements/UseProcessBlockForPipelineCommand.ps1:1:1:11:1 | def of Get-Number | Statements/UseProcessBlockForPipelineCommand.ps1:1:1:11:1 | {...} | +| Statements/UseProcessBlockForPipelineCommand.ps1:1:1:11:1 | {...} | Statements/UseProcessBlockForPipelineCommand.ps1:1:1:11:1 | {...} | +| Statements/UseProcessBlockForPipelineCommand.ps1:1:1:11:1 | {...} | file://:0:0:0:0 | toplevel function for UseProcessBlockForPipelineCommand.ps1 | +| Statements/UseProcessBlockForPipelineCommand.ps1:2:1:11:1 | Number | Statements/UseProcessBlockForPipelineCommand.ps1:2:1:11:1 | {...} | +| Statements/UseProcessBlockForPipelineCommand.ps1:2:1:11:1 | [synth] pipeline | Statements/UseProcessBlockForPipelineCommand.ps1:2:1:11:1 | {...} | +| Statements/UseProcessBlockForPipelineCommand.ps1:2:1:11:1 | {...} | Statements/UseProcessBlockForPipelineCommand.ps1:1:1:11:1 | Get-Number | +| Statements/UseProcessBlockForPipelineCommand.ps1:3:5:3:21 | CmdletBinding | Statements/UseProcessBlockForPipelineCommand.ps1:2:1:11:1 | {...} | +| Statements/UseProcessBlockForPipelineCommand.ps1:4:5:10:11 | {...} | Statements/UseProcessBlockForPipelineCommand.ps1:2:1:11:1 | {...} | +| Statements/UseProcessBlockForPipelineCommand.ps1:5:9:5:38 | ValueFromPipeline | Statements/UseProcessBlockForPipelineCommand.ps1:2:1:11:1 | Number | +| Statements/UseProcessBlockForPipelineCommand.ps1:5:20:5:36 | (no string representation) | Statements/UseProcessBlockForPipelineCommand.ps1:5:20:5:36 | ValueFromPipeline | +| Statements/UseProcessBlockForPipelineCommand.ps1:5:20:5:36 | ValueFromPipeline | Statements/UseProcessBlockForPipelineCommand.ps1:5:9:5:38 | ValueFromPipeline | +| Statements/UseProcessBlockForPipelineCommand.ps1:6:9:6:13 | int | Statements/UseProcessBlockForPipelineCommand.ps1:2:1:11:1 | Number | +| Statements/UseProcessBlockForPipelineCommand.ps1:10:5:10:11 | Number | Statements/UseProcessBlockForPipelineCommand.ps1:10:5:10:11 | [Stmt] Number | +| Statements/UseProcessBlockForPipelineCommand.ps1:10:5:10:11 | [Stmt] Number | Statements/UseProcessBlockForPipelineCommand.ps1:4:5:10:11 | {...} | diff --git a/powershell/ql/test/library-tests/controlflow/graph/Cfg.expected b/powershell/ql/test/library-tests/controlflow/graph/Cfg.expected index 65f28412b3a1..c2432f65b155 100644 --- a/powershell/ql/test/library-tests/controlflow/graph/Cfg.expected +++ b/powershell/ql/test/library-tests/controlflow/graph/Cfg.expected @@ -1,812 +1,759 @@ -| conditionals.ps1:1:1:9:2 | test-if | conditionals.ps1:11:1:22:2 | test-if-else | | -| conditionals.ps1:1:1:129:2 | conditionals.ps1 | conditionals.ps1:1:1:129:2 | exit conditionals.ps1 (normal) | | -| conditionals.ps1:1:1:129:2 | conditionals.ps1 | conditionals.ps1:1:1:129:2 | {...} | | -| conditionals.ps1:1:1:129:2 | enter conditionals.ps1 | conditionals.ps1:1:1:129:2 | conditionals.ps1 | | -| conditionals.ps1:1:1:129:2 | exit conditionals.ps1 (normal) | conditionals.ps1:1:1:129:2 | exit conditionals.ps1 | | -| conditionals.ps1:1:1:129:2 | {...} | conditionals.ps1:1:1:9:2 | test-if | | -| conditionals.ps1:1:18:9:2 | enter {...} | conditionals.ps1:1:18:9:2 | {...} | | -| conditionals.ps1:1:18:9:2 | exit {...} (normal) | conditionals.ps1:1:18:9:2 | exit {...} | | -| conditionals.ps1:1:18:9:2 | {...} | conditionals.ps1:2:5:2:19 | param(...) | | -| conditionals.ps1:2:5:2:19 | param(...) | conditionals.ps1:2:5:8:14 | {...} | | -| conditionals.ps1:2:5:8:14 | {...} | conditionals.ps1:4:5:7:6 | if (...) {...} | | -| conditionals.ps1:4:5:7:6 | if (...) {...} | conditionals.ps1:4:8:4:15 | myBool | | -| conditionals.ps1:4:8:4:15 | myBool | conditionals.ps1:4:8:4:15 | myBool | false, true | -| conditionals.ps1:4:8:4:15 | myBool | conditionals.ps1:5:5:7:6 | {...} | true | -| conditionals.ps1:5:5:7:6 | {...} | conditionals.ps1:6:9:6:18 | return ... | | -| conditionals.ps1:6:9:6:18 | return ... | conditionals.ps1:6:16:6:18 | 10 | | -| conditionals.ps1:6:16:6:18 | 10 | conditionals.ps1:6:16:6:18 | 10 | | -| conditionals.ps1:6:16:6:18 | 10 | conditionals.ps1:8:5:8:14 | return ... | | -| conditionals.ps1:8:5:8:14 | return ... | conditionals.ps1:8:12:8:14 | 11 | | -| conditionals.ps1:8:12:8:14 | 11 | conditionals.ps1:1:18:9:2 | exit {...} (normal) | | -| conditionals.ps1:8:12:8:14 | 11 | conditionals.ps1:8:12:8:14 | 11 | | -| conditionals.ps1:11:1:22:2 | test-if-else | conditionals.ps1:24:1:32:2 | test-if-conj | | -| conditionals.ps1:11:23:22:2 | enter {...} | conditionals.ps1:11:23:22:2 | {...} | | -| conditionals.ps1:11:23:22:2 | exit {...} (normal) | conditionals.ps1:11:23:22:2 | exit {...} | | -| conditionals.ps1:11:23:22:2 | {...} | conditionals.ps1:12:5:12:19 | param(...) | | -| conditionals.ps1:12:5:12:19 | param(...) | conditionals.ps1:12:5:21:6 | {...} | | -| conditionals.ps1:12:5:21:6 | {...} | conditionals.ps1:14:5:21:6 | if (...) {...} else {...} | | -| conditionals.ps1:14:5:21:6 | if (...) {...} else {...} | conditionals.ps1:14:8:14:15 | myBool | | -| conditionals.ps1:14:8:14:15 | myBool | conditionals.ps1:14:8:14:15 | myBool | false, true | -| conditionals.ps1:14:8:14:15 | myBool | conditionals.ps1:15:5:17:6 | {...} | true | -| conditionals.ps1:14:8:14:15 | myBool | conditionals.ps1:19:5:21:6 | {...} | false | -| conditionals.ps1:15:5:17:6 | {...} | conditionals.ps1:16:9:16:18 | return ... | | -| conditionals.ps1:16:9:16:18 | return ... | conditionals.ps1:16:16:16:18 | 10 | | -| conditionals.ps1:16:16:16:18 | 10 | conditionals.ps1:11:23:22:2 | exit {...} (normal) | | -| conditionals.ps1:16:16:16:18 | 10 | conditionals.ps1:16:16:16:18 | 10 | | -| conditionals.ps1:19:5:21:6 | {...} | conditionals.ps1:20:9:20:18 | return ... | | -| conditionals.ps1:20:9:20:18 | return ... | conditionals.ps1:20:16:20:18 | 11 | | -| conditionals.ps1:20:16:20:18 | 11 | conditionals.ps1:11:23:22:2 | exit {...} (normal) | | -| conditionals.ps1:20:16:20:18 | 11 | conditionals.ps1:20:16:20:18 | 11 | | -| conditionals.ps1:24:1:32:2 | test-if-conj | conditionals.ps1:34:1:45:2 | test-if-else-conj | | -| conditionals.ps1:24:23:32:2 | enter {...} | conditionals.ps1:24:23:32:2 | {...} | | -| conditionals.ps1:24:23:32:2 | exit {...} (normal) | conditionals.ps1:24:23:32:2 | exit {...} | | -| conditionals.ps1:24:23:32:2 | {...} | conditionals.ps1:25:5:25:30 | param(...) | | -| conditionals.ps1:25:5:25:30 | param(...) | conditionals.ps1:25:5:31:14 | {...} | | -| conditionals.ps1:25:5:31:14 | {...} | conditionals.ps1:27:5:30:6 | if (...) {...} | | -| conditionals.ps1:27:5:30:6 | if (...) {...} | conditionals.ps1:27:8:27:16 | myBool1 | | -| conditionals.ps1:27:8:27:16 | myBool1 | conditionals.ps1:27:22:27:30 | myBool2 | false, true | -| conditionals.ps1:27:8:27:30 | ... -and ... | conditionals.ps1:28:5:30:6 | {...} | true | -| conditionals.ps1:27:8:27:30 | [false] ... -and ... | conditionals.ps1:27:8:27:30 | ... -and ... | false | -| conditionals.ps1:27:8:27:30 | [true] ... -and ... | conditionals.ps1:27:8:27:30 | ... -and ... | true | -| conditionals.ps1:27:22:27:30 | myBool2 | conditionals.ps1:27:8:27:30 | [false] ... -and ... | false | -| conditionals.ps1:27:22:27:30 | myBool2 | conditionals.ps1:27:8:27:30 | [true] ... -and ... | true | -| conditionals.ps1:28:5:30:6 | {...} | conditionals.ps1:29:9:29:18 | return ... | | -| conditionals.ps1:29:9:29:18 | return ... | conditionals.ps1:29:16:29:18 | 10 | | -| conditionals.ps1:29:16:29:18 | 10 | conditionals.ps1:29:16:29:18 | 10 | | -| conditionals.ps1:29:16:29:18 | 10 | conditionals.ps1:31:5:31:14 | return ... | | -| conditionals.ps1:31:5:31:14 | return ... | conditionals.ps1:31:12:31:14 | 11 | | -| conditionals.ps1:31:12:31:14 | 11 | conditionals.ps1:24:23:32:2 | exit {...} (normal) | | -| conditionals.ps1:31:12:31:14 | 11 | conditionals.ps1:31:12:31:14 | 11 | | -| conditionals.ps1:34:1:45:2 | test-if-else-conj | conditionals.ps1:47:1:55:2 | test-if-disj | | -| conditionals.ps1:34:28:45:2 | enter {...} | conditionals.ps1:34:28:45:2 | {...} | | -| conditionals.ps1:34:28:45:2 | exit {...} (normal) | conditionals.ps1:34:28:45:2 | exit {...} | | -| conditionals.ps1:34:28:45:2 | {...} | conditionals.ps1:35:5:35:30 | param(...) | | -| conditionals.ps1:35:5:35:30 | param(...) | conditionals.ps1:35:5:44:6 | {...} | | -| conditionals.ps1:35:5:44:6 | {...} | conditionals.ps1:37:5:44:6 | if (...) {...} else {...} | | -| conditionals.ps1:37:5:44:6 | if (...) {...} else {...} | conditionals.ps1:37:8:37:16 | myBool1 | | -| conditionals.ps1:37:8:37:16 | myBool1 | conditionals.ps1:37:22:37:30 | myBool2 | false, true | -| conditionals.ps1:37:8:37:30 | ... -and ... | conditionals.ps1:38:5:40:6 | {...} | true | -| conditionals.ps1:37:8:37:30 | ... -and ... | conditionals.ps1:42:5:44:6 | {...} | false | -| conditionals.ps1:37:8:37:30 | [false] ... -and ... | conditionals.ps1:37:8:37:30 | ... -and ... | false | -| conditionals.ps1:37:8:37:30 | [true] ... -and ... | conditionals.ps1:37:8:37:30 | ... -and ... | true | -| conditionals.ps1:37:22:37:30 | myBool2 | conditionals.ps1:37:8:37:30 | [false] ... -and ... | false | -| conditionals.ps1:37:22:37:30 | myBool2 | conditionals.ps1:37:8:37:30 | [true] ... -and ... | true | -| conditionals.ps1:38:5:40:6 | {...} | conditionals.ps1:39:9:39:18 | return ... | | -| conditionals.ps1:39:9:39:18 | return ... | conditionals.ps1:39:16:39:18 | 10 | | -| conditionals.ps1:39:16:39:18 | 10 | conditionals.ps1:34:28:45:2 | exit {...} (normal) | | -| conditionals.ps1:39:16:39:18 | 10 | conditionals.ps1:39:16:39:18 | 10 | | -| conditionals.ps1:42:5:44:6 | {...} | conditionals.ps1:43:9:43:18 | return ... | | -| conditionals.ps1:43:9:43:18 | return ... | conditionals.ps1:43:16:43:18 | 11 | | -| conditionals.ps1:43:16:43:18 | 11 | conditionals.ps1:34:28:45:2 | exit {...} (normal) | | -| conditionals.ps1:43:16:43:18 | 11 | conditionals.ps1:43:16:43:18 | 11 | | -| conditionals.ps1:47:1:55:2 | test-if-disj | conditionals.ps1:57:1:68:2 | test-if-else-disj | | -| conditionals.ps1:47:23:55:2 | enter {...} | conditionals.ps1:47:23:55:2 | {...} | | -| conditionals.ps1:47:23:55:2 | exit {...} (normal) | conditionals.ps1:47:23:55:2 | exit {...} | | -| conditionals.ps1:47:23:55:2 | {...} | conditionals.ps1:48:5:48:30 | param(...) | | -| conditionals.ps1:48:5:48:30 | param(...) | conditionals.ps1:48:5:54:14 | {...} | | -| conditionals.ps1:48:5:54:14 | {...} | conditionals.ps1:50:5:53:6 | if (...) {...} | | -| conditionals.ps1:50:5:53:6 | if (...) {...} | conditionals.ps1:50:8:50:16 | myBool1 | | -| conditionals.ps1:50:8:50:16 | myBool1 | conditionals.ps1:50:21:50:29 | myBool2 | false, true | -| conditionals.ps1:50:8:50:29 | ... -or ... | conditionals.ps1:51:5:53:6 | {...} | true | -| conditionals.ps1:50:8:50:29 | [false] ... -or ... | conditionals.ps1:50:8:50:29 | ... -or ... | false | -| conditionals.ps1:50:8:50:29 | [true] ... -or ... | conditionals.ps1:50:8:50:29 | ... -or ... | true | -| conditionals.ps1:50:21:50:29 | myBool2 | conditionals.ps1:50:8:50:29 | [false] ... -or ... | false | -| conditionals.ps1:50:21:50:29 | myBool2 | conditionals.ps1:50:8:50:29 | [true] ... -or ... | true | -| conditionals.ps1:51:5:53:6 | {...} | conditionals.ps1:52:9:52:18 | return ... | | -| conditionals.ps1:52:9:52:18 | return ... | conditionals.ps1:52:16:52:18 | 10 | | -| conditionals.ps1:52:16:52:18 | 10 | conditionals.ps1:52:16:52:18 | 10 | | -| conditionals.ps1:52:16:52:18 | 10 | conditionals.ps1:54:5:54:14 | return ... | | -| conditionals.ps1:54:5:54:14 | return ... | conditionals.ps1:54:12:54:14 | 11 | | -| conditionals.ps1:54:12:54:14 | 11 | conditionals.ps1:47:23:55:2 | exit {...} (normal) | | -| conditionals.ps1:54:12:54:14 | 11 | conditionals.ps1:54:12:54:14 | 11 | | -| conditionals.ps1:57:1:68:2 | test-if-else-disj | conditionals.ps1:70:1:82:2 | test-else-if | | -| conditionals.ps1:57:28:68:2 | enter {...} | conditionals.ps1:57:28:68:2 | {...} | | -| conditionals.ps1:57:28:68:2 | exit {...} (normal) | conditionals.ps1:57:28:68:2 | exit {...} | | -| conditionals.ps1:57:28:68:2 | {...} | conditionals.ps1:58:5:58:30 | param(...) | | -| conditionals.ps1:58:5:58:30 | param(...) | conditionals.ps1:58:5:67:6 | {...} | | -| conditionals.ps1:58:5:67:6 | {...} | conditionals.ps1:60:5:67:6 | if (...) {...} else {...} | | -| conditionals.ps1:60:5:67:6 | if (...) {...} else {...} | conditionals.ps1:60:8:60:16 | myBool1 | | -| conditionals.ps1:60:8:60:16 | myBool1 | conditionals.ps1:60:21:60:29 | myBool2 | false, true | -| conditionals.ps1:60:8:60:29 | ... -or ... | conditionals.ps1:61:5:63:6 | {...} | true | -| conditionals.ps1:60:8:60:29 | ... -or ... | conditionals.ps1:65:5:67:6 | {...} | false | -| conditionals.ps1:60:8:60:29 | [false] ... -or ... | conditionals.ps1:60:8:60:29 | ... -or ... | false | -| conditionals.ps1:60:8:60:29 | [true] ... -or ... | conditionals.ps1:60:8:60:29 | ... -or ... | true | -| conditionals.ps1:60:21:60:29 | myBool2 | conditionals.ps1:60:8:60:29 | [false] ... -or ... | false | -| conditionals.ps1:60:21:60:29 | myBool2 | conditionals.ps1:60:8:60:29 | [true] ... -or ... | true | -| conditionals.ps1:61:5:63:6 | {...} | conditionals.ps1:62:9:62:18 | return ... | | -| conditionals.ps1:62:9:62:18 | return ... | conditionals.ps1:62:16:62:18 | 10 | | -| conditionals.ps1:62:16:62:18 | 10 | conditionals.ps1:57:28:68:2 | exit {...} (normal) | | -| conditionals.ps1:62:16:62:18 | 10 | conditionals.ps1:62:16:62:18 | 10 | | -| conditionals.ps1:65:5:67:6 | {...} | conditionals.ps1:66:9:66:18 | return ... | | -| conditionals.ps1:66:9:66:18 | return ... | conditionals.ps1:66:16:66:18 | 11 | | -| conditionals.ps1:66:16:66:18 | 11 | conditionals.ps1:57:28:68:2 | exit {...} (normal) | | -| conditionals.ps1:66:16:66:18 | 11 | conditionals.ps1:66:16:66:18 | 11 | | -| conditionals.ps1:70:1:82:2 | test-else-if | conditionals.ps1:84:1:99:2 | test-else-if-else | | -| conditionals.ps1:70:23:82:2 | enter {...} | conditionals.ps1:70:23:82:2 | {...} | | -| conditionals.ps1:70:23:82:2 | exit {...} (normal) | conditionals.ps1:70:23:82:2 | exit {...} | | -| conditionals.ps1:70:23:82:2 | {...} | conditionals.ps1:71:5:71:30 | param(...) | | -| conditionals.ps1:71:5:71:30 | param(...) | conditionals.ps1:71:5:81:14 | {...} | | -| conditionals.ps1:71:5:81:14 | {...} | conditionals.ps1:73:5:80:6 | if (...) {...} | | -| conditionals.ps1:73:5:80:6 | if (...) {...} | conditionals.ps1:73:8:73:16 | myBool1 | | -| conditionals.ps1:73:8:73:16 | myBool1 | conditionals.ps1:73:8:73:16 | myBool1 | false, true | -| conditionals.ps1:73:8:73:16 | myBool1 | conditionals.ps1:74:5:76:6 | {...} | true | -| conditionals.ps1:73:8:73:16 | myBool1 | conditionals.ps1:77:12:77:19 | myBoo2 | false | -| conditionals.ps1:74:5:76:6 | {...} | conditionals.ps1:75:9:75:18 | return ... | | -| conditionals.ps1:75:9:75:18 | return ... | conditionals.ps1:75:16:75:18 | 10 | | -| conditionals.ps1:75:16:75:18 | 10 | conditionals.ps1:75:16:75:18 | 10 | | -| conditionals.ps1:75:16:75:18 | 10 | conditionals.ps1:81:5:81:14 | return ... | | -| conditionals.ps1:77:12:77:19 | myBoo2 | conditionals.ps1:77:12:77:19 | myBoo2 | false, true | -| conditionals.ps1:77:12:77:19 | myBoo2 | conditionals.ps1:78:5:80:6 | {...} | true | -| conditionals.ps1:78:5:80:6 | {...} | conditionals.ps1:79:9:79:18 | return ... | | -| conditionals.ps1:79:9:79:18 | return ... | conditionals.ps1:79:16:79:18 | 11 | | -| conditionals.ps1:79:16:79:18 | 11 | conditionals.ps1:79:16:79:18 | 11 | | -| conditionals.ps1:79:16:79:18 | 11 | conditionals.ps1:81:5:81:14 | return ... | | -| conditionals.ps1:81:5:81:14 | return ... | conditionals.ps1:81:12:81:14 | 12 | | -| conditionals.ps1:81:12:81:14 | 12 | conditionals.ps1:70:23:82:2 | exit {...} (normal) | | -| conditionals.ps1:81:12:81:14 | 12 | conditionals.ps1:81:12:81:14 | 12 | | -| conditionals.ps1:84:1:99:2 | test-else-if-else | conditionals.ps1:101:1:108:2 | test-switch | | -| conditionals.ps1:84:28:99:2 | enter {...} | conditionals.ps1:84:28:99:2 | {...} | | -| conditionals.ps1:84:28:99:2 | exit {...} (normal) | conditionals.ps1:84:28:99:2 | exit {...} | | -| conditionals.ps1:84:28:99:2 | {...} | conditionals.ps1:85:5:85:30 | param(...) | | -| conditionals.ps1:85:5:85:30 | param(...) | conditionals.ps1:85:5:98:6 | {...} | | -| conditionals.ps1:85:5:98:6 | {...} | conditionals.ps1:87:5:98:6 | if (...) {...} else {...} | | -| conditionals.ps1:87:5:98:6 | if (...) {...} else {...} | conditionals.ps1:87:8:87:16 | myBool1 | | -| conditionals.ps1:87:8:87:16 | myBool1 | conditionals.ps1:87:8:87:16 | myBool1 | false, true | -| conditionals.ps1:87:8:87:16 | myBool1 | conditionals.ps1:88:5:90:6 | {...} | true | -| conditionals.ps1:87:8:87:16 | myBool1 | conditionals.ps1:91:12:91:19 | myBoo2 | false | -| conditionals.ps1:88:5:90:6 | {...} | conditionals.ps1:89:9:89:18 | return ... | | -| conditionals.ps1:89:9:89:18 | return ... | conditionals.ps1:89:16:89:18 | 10 | | -| conditionals.ps1:89:16:89:18 | 10 | conditionals.ps1:84:28:99:2 | exit {...} (normal) | | -| conditionals.ps1:89:16:89:18 | 10 | conditionals.ps1:89:16:89:18 | 10 | | -| conditionals.ps1:91:12:91:19 | myBoo2 | conditionals.ps1:91:12:91:19 | myBoo2 | false, true | -| conditionals.ps1:91:12:91:19 | myBoo2 | conditionals.ps1:92:5:94:6 | {...} | true | -| conditionals.ps1:91:12:91:19 | myBoo2 | conditionals.ps1:96:5:98:6 | {...} | false | -| conditionals.ps1:92:5:94:6 | {...} | conditionals.ps1:93:9:93:18 | return ... | | -| conditionals.ps1:93:9:93:18 | return ... | conditionals.ps1:93:16:93:18 | 11 | | -| conditionals.ps1:93:16:93:18 | 11 | conditionals.ps1:84:28:99:2 | exit {...} (normal) | | -| conditionals.ps1:93:16:93:18 | 11 | conditionals.ps1:93:16:93:18 | 11 | | -| conditionals.ps1:96:5:98:6 | {...} | conditionals.ps1:97:9:97:18 | return ... | | -| conditionals.ps1:97:9:97:18 | return ... | conditionals.ps1:97:16:97:18 | 12 | | -| conditionals.ps1:97:16:97:18 | 12 | conditionals.ps1:84:28:99:2 | exit {...} (normal) | | -| conditionals.ps1:97:16:97:18 | 12 | conditionals.ps1:97:16:97:18 | 12 | | -| conditionals.ps1:101:1:108:2 | test-switch | conditionals.ps1:110:1:121:2 | test-switch-default | | -| conditionals.ps1:101:26:108:2 | enter {...} | conditionals.ps1:101:26:108:2 | {...} | | -| conditionals.ps1:101:26:108:2 | exit {...} (normal) | conditionals.ps1:101:26:108:2 | exit {...} | | -| conditionals.ps1:101:26:108:2 | {...} | conditionals.ps1:102:5:107:6 | {...} | | -| conditionals.ps1:102:5:107:6 | switch(...) {...} | conditionals.ps1:102:12:102:14 | n | | -| conditionals.ps1:102:5:107:6 | {...} | conditionals.ps1:102:5:107:6 | switch(...) {...} | | -| conditionals.ps1:102:12:102:14 | n | conditionals.ps1:102:12:102:14 | n | | -| conditionals.ps1:102:12:102:14 | n | conditionals.ps1:104:9:104:11 | 0: | | -| conditionals.ps1:104:9:104:11 | 0: | conditionals.ps1:104:12:104:25 | {...} | true | -| conditionals.ps1:104:9:104:11 | 0: | conditionals.ps1:105:9:105:11 | 1: | false | -| conditionals.ps1:104:12:104:25 | {...} | conditionals.ps1:104:14:104:22 | return ... | | -| conditionals.ps1:104:14:104:22 | return ... | conditionals.ps1:104:21:104:22 | 0 | | -| conditionals.ps1:104:21:104:22 | 0 | conditionals.ps1:101:26:108:2 | exit {...} (normal) | | -| conditionals.ps1:104:21:104:22 | 0 | conditionals.ps1:104:21:104:22 | 0 | | -| conditionals.ps1:105:9:105:11 | 1: | conditionals.ps1:105:12:105:25 | {...} | true | -| conditionals.ps1:105:9:105:11 | 1: | conditionals.ps1:106:9:106:11 | 2: | false | -| conditionals.ps1:105:12:105:25 | {...} | conditionals.ps1:105:14:105:22 | return ... | | -| conditionals.ps1:105:14:105:22 | return ... | conditionals.ps1:105:21:105:22 | 1 | | -| conditionals.ps1:105:21:105:22 | 1 | conditionals.ps1:101:26:108:2 | exit {...} (normal) | | -| conditionals.ps1:105:21:105:22 | 1 | conditionals.ps1:105:21:105:22 | 1 | | -| conditionals.ps1:106:9:106:11 | 2: | conditionals.ps1:101:26:108:2 | exit {...} (normal) | false | -| conditionals.ps1:106:9:106:11 | 2: | conditionals.ps1:106:12:106:25 | {...} | true | -| conditionals.ps1:106:12:106:25 | {...} | conditionals.ps1:106:14:106:22 | return ... | | -| conditionals.ps1:106:14:106:22 | return ... | conditionals.ps1:106:21:106:22 | 2 | | -| conditionals.ps1:106:21:106:22 | 2 | conditionals.ps1:101:26:108:2 | exit {...} (normal) | | -| conditionals.ps1:106:21:106:22 | 2 | conditionals.ps1:106:21:106:22 | 2 | | -| conditionals.ps1:110:1:121:2 | test-switch-default | conditionals.ps1:123:1:129:2 | test-switch-assign | | -| conditionals.ps1:110:34:121:2 | enter {...} | conditionals.ps1:110:34:121:2 | {...} | | -| conditionals.ps1:110:34:121:2 | exit {...} (normal) | conditionals.ps1:110:34:121:2 | exit {...} | | -| conditionals.ps1:110:34:121:2 | {...} | conditionals.ps1:111:5:120:6 | {...} | | -| conditionals.ps1:111:5:120:6 | switch(...) {...} | conditionals.ps1:111:12:111:14 | n | | -| conditionals.ps1:111:5:120:6 | {...} | conditionals.ps1:111:5:120:6 | switch(...) {...} | | -| conditionals.ps1:111:12:111:14 | n | conditionals.ps1:111:12:111:14 | n | | -| conditionals.ps1:111:12:111:14 | n | conditionals.ps1:113:9:113:11 | 0: | | -| conditionals.ps1:113:9:113:11 | 0: | conditionals.ps1:113:12:113:25 | {...} | true | -| conditionals.ps1:113:9:113:11 | 0: | conditionals.ps1:114:9:114:11 | 1: | false | -| conditionals.ps1:113:12:113:25 | {...} | conditionals.ps1:113:14:113:22 | return ... | | -| conditionals.ps1:113:14:113:22 | return ... | conditionals.ps1:113:21:113:22 | 0 | | -| conditionals.ps1:113:21:113:22 | 0 | conditionals.ps1:110:34:121:2 | exit {...} (normal) | | -| conditionals.ps1:113:21:113:22 | 0 | conditionals.ps1:113:21:113:22 | 0 | | -| conditionals.ps1:114:9:114:11 | 1: | conditionals.ps1:114:12:114:25 | {...} | true | -| conditionals.ps1:114:9:114:11 | 1: | conditionals.ps1:115:9:115:11 | 2: | false | -| conditionals.ps1:114:12:114:25 | {...} | conditionals.ps1:114:14:114:22 | return ... | | -| conditionals.ps1:114:14:114:22 | return ... | conditionals.ps1:114:21:114:22 | 1 | | -| conditionals.ps1:114:21:114:22 | 1 | conditionals.ps1:110:34:121:2 | exit {...} (normal) | | -| conditionals.ps1:114:21:114:22 | 1 | conditionals.ps1:114:21:114:22 | 1 | | -| conditionals.ps1:115:9:115:11 | 2: | conditionals.ps1:115:12:115:25 | {...} | true | -| conditionals.ps1:115:9:115:11 | 2: | conditionals.ps1:116:9:116:17 | default: | false | -| conditionals.ps1:115:12:115:25 | {...} | conditionals.ps1:115:14:115:22 | return ... | | -| conditionals.ps1:115:14:115:22 | return ... | conditionals.ps1:115:21:115:22 | 2 | | -| conditionals.ps1:115:21:115:22 | 2 | conditionals.ps1:110:34:121:2 | exit {...} (normal) | | -| conditionals.ps1:115:21:115:22 | 2 | conditionals.ps1:115:21:115:22 | 2 | | -| conditionals.ps1:116:9:116:17 | default: | conditionals.ps1:110:34:121:2 | exit {...} (normal) | false | -| conditionals.ps1:116:9:116:17 | default: | conditionals.ps1:116:18:119:10 | {...} | true | -| conditionals.ps1:116:18:119:10 | {...} | conditionals.ps1:117:13:117:25 | Write-Output | | -| conditionals.ps1:117:13:117:25 | Write-Output | conditionals.ps1:117:26:117:34 | Error! | | -| conditionals.ps1:117:13:117:34 | call to Write-Output | conditionals.ps1:118:13:118:21 | return ... | | -| conditionals.ps1:117:26:117:34 | Error! | conditionals.ps1:117:13:117:34 | call to Write-Output | | -| conditionals.ps1:118:13:118:21 | return ... | conditionals.ps1:118:20:118:21 | 3 | | -| conditionals.ps1:118:20:118:21 | 3 | conditionals.ps1:110:34:121:2 | exit {...} (normal) | | -| conditionals.ps1:118:20:118:21 | 3 | conditionals.ps1:118:20:118:21 | 3 | | -| conditionals.ps1:123:1:129:2 | test-switch-assign | conditionals.ps1:1:1:129:2 | exit conditionals.ps1 (normal) | | -| conditionals.ps1:123:33:129:2 | enter {...} | conditionals.ps1:123:33:129:2 | {...} | | -| conditionals.ps1:123:33:129:2 | exit {...} (normal) | conditionals.ps1:123:33:129:2 | exit {...} | | -| conditionals.ps1:123:33:129:2 | {...} | conditionals.ps1:124:5:128:6 | {...} | | -| conditionals.ps1:124:5:124:7 | a | conditionals.ps1:124:10:128:6 | switch(...) {...} | | -| conditionals.ps1:124:5:128:6 | ...=... | conditionals.ps1:124:5:124:7 | a | | -| conditionals.ps1:124:5:128:6 | {...} | conditionals.ps1:124:5:128:6 | ...=... | | -| conditionals.ps1:124:10:128:6 | switch(...) {...} | conditionals.ps1:124:17:124:19 | n | | -| conditionals.ps1:124:17:124:19 | n | conditionals.ps1:124:17:124:19 | n | | -| conditionals.ps1:124:17:124:19 | n | conditionals.ps1:125:9:125:11 | 0: | | -| conditionals.ps1:125:9:125:11 | 0: | conditionals.ps1:125:12:125:19 | {...} | true | -| conditionals.ps1:125:9:125:11 | 0: | conditionals.ps1:126:9:126:11 | 1: | false | -| conditionals.ps1:125:12:125:19 | {...} | conditionals.ps1:125:14:125:17 | 0 | | -| conditionals.ps1:125:14:125:17 | 0 | conditionals.ps1:123:33:129:2 | exit {...} (normal) | | -| conditionals.ps1:125:14:125:17 | 0 | conditionals.ps1:125:14:125:17 | 0 | | -| conditionals.ps1:126:9:126:11 | 1: | conditionals.ps1:126:12:126:19 | {...} | true | -| conditionals.ps1:126:9:126:11 | 1: | conditionals.ps1:127:9:127:11 | 2: | false | -| conditionals.ps1:126:12:126:19 | {...} | conditionals.ps1:126:14:126:17 | 1 | | -| conditionals.ps1:126:14:126:17 | 1 | conditionals.ps1:123:33:129:2 | exit {...} (normal) | | -| conditionals.ps1:126:14:126:17 | 1 | conditionals.ps1:126:14:126:17 | 1 | | -| conditionals.ps1:127:9:127:11 | 2: | conditionals.ps1:123:33:129:2 | exit {...} (normal) | false | -| conditionals.ps1:127:9:127:11 | 2: | conditionals.ps1:127:12:127:19 | {...} | true | -| conditionals.ps1:127:12:127:19 | {...} | conditionals.ps1:127:14:127:17 | 2 | | -| conditionals.ps1:127:14:127:17 | 2 | conditionals.ps1:123:33:129:2 | exit {...} (normal) | | -| conditionals.ps1:127:14:127:17 | 2 | conditionals.ps1:127:14:127:17 | 2 | | -| functions.ps1:1:1:9:2 | Add-Numbers-Arguments | functions.ps1:11:1:11:29 | foo | | -| functions.ps1:1:1:52:2 | {...} | functions.ps1:1:1:9:2 | Add-Numbers-Arguments | | -| functions.ps1:1:1:54:1 | enter functions.ps1 | functions.ps1:1:1:54:1 | functions.ps1 | | -| functions.ps1:1:1:54:1 | exit functions.ps1 (normal) | functions.ps1:1:1:54:1 | exit functions.ps1 | | -| functions.ps1:1:1:54:1 | functions.ps1 | functions.ps1:1:1:52:2 | {...} | | -| functions.ps1:1:1:54:1 | functions.ps1 | functions.ps1:1:1:54:1 | exit functions.ps1 (normal) | | -| functions.ps1:1:32:9:2 | enter {...} | functions.ps1:1:32:9:2 | {...} | | -| functions.ps1:1:32:9:2 | exit {...} (normal) | functions.ps1:1:32:9:2 | exit {...} | | -| functions.ps1:1:32:9:2 | {...} | functions.ps1:3:5:6:6 | param(...) | | -| functions.ps1:3:5:6:6 | param(...) | functions.ps1:3:5:8:24 | {...} | | -| functions.ps1:3:5:8:24 | {...} | functions.ps1:8:5:8:13 | number1 | | -| functions.ps1:8:5:8:13 | number1 | functions.ps1:8:16:8:24 | number2 | | -| functions.ps1:8:5:8:24 | ...+... | functions.ps1:1:32:9:2 | exit {...} (normal) | | -| functions.ps1:8:5:8:24 | ...+... | functions.ps1:8:5:8:24 | ...+... | | -| functions.ps1:8:16:8:24 | number2 | functions.ps1:8:5:8:24 | ...+... | | -| functions.ps1:11:1:11:29 | foo | functions.ps1:13:1:20:2 | Default-Arguments | | -| functions.ps1:11:16:11:29 | enter {...} | functions.ps1:11:16:11:29 | {...} | | -| functions.ps1:11:16:11:29 | exit {...} (normal) | functions.ps1:11:16:11:29 | exit {...} | | -| functions.ps1:11:16:11:29 | {...} | functions.ps1:11:18:11:27 | param(...) | | -| functions.ps1:11:18:11:27 | param(...) | functions.ps1:11:18:11:27 | {...} | | -| functions.ps1:11:18:11:27 | {...} | functions.ps1:11:16:11:29 | exit {...} (normal) | | -| functions.ps1:13:1:20:2 | Default-Arguments | functions.ps1:22:1:34:2 | Add-Numbers-From-Array | | -| functions.ps1:13:28:20:2 | enter {...} | functions.ps1:13:28:20:2 | {...} | | -| functions.ps1:13:28:20:2 | exit {...} (normal) | functions.ps1:13:28:20:2 | exit {...} | | -| functions.ps1:13:28:20:2 | {...} | functions.ps1:16:24:16:25 | 0 | | -| functions.ps1:14:5:18:6 | param(...) | functions.ps1:14:5:19:19 | {...} | | -| functions.ps1:14:5:19:19 | {...} | functions.ps1:19:5:19:10 | name | | -| functions.ps1:16:24:16:25 | 0 | functions.ps1:17:24:17:30 | name1 | | -| functions.ps1:17:24:17:30 | name1 | functions.ps1:17:33:17:34 | 1 | | -| functions.ps1:17:24:17:34 | ...+... | functions.ps1:14:5:18:6 | param(...) | | -| functions.ps1:17:33:17:34 | 1 | functions.ps1:17:24:17:34 | ...+... | | -| functions.ps1:19:5:19:10 | name | functions.ps1:19:13:19:19 | name2 | | -| functions.ps1:19:5:19:19 | ...+... | functions.ps1:13:28:20:2 | exit {...} (normal) | | -| functions.ps1:19:5:19:19 | ...+... | functions.ps1:19:5:19:19 | ...+... | | -| functions.ps1:19:13:19:19 | name2 | functions.ps1:19:5:19:19 | ...+... | | -| functions.ps1:22:1:34:2 | Add-Numbers-From-Array | functions.ps1:36:1:52:2 | Add-Numbers-From-Pipeline | | -| functions.ps1:22:33:34:2 | enter {...} | functions.ps1:22:33:34:2 | {...} | | -| functions.ps1:22:33:34:2 | exit {...} (normal) | functions.ps1:22:33:34:2 | exit {...} | | -| functions.ps1:22:33:34:2 | {...} | functions.ps1:24:5:26:6 | param(...) | | -| functions.ps1:24:5:26:6 | param(...) | functions.ps1:24:5:33:9 | {...} | | -| functions.ps1:24:5:33:9 | {...} | functions.ps1:28:5:28:13 | ...=... | | -| functions.ps1:28:5:28:9 | sum | functions.ps1:28:12:28:13 | 0 | | -| functions.ps1:28:5:28:13 | ...=... | functions.ps1:28:5:28:9 | sum | | -| functions.ps1:28:12:28:13 | 0 | functions.ps1:28:12:28:13 | 0 | | -| functions.ps1:28:12:28:13 | 0 | functions.ps1:29:25:29:33 | numbers | | -| functions.ps1:29:5:32:6 | forach(... in ...) | functions.ps1:29:14:29:21 | number | non-empty | -| functions.ps1:29:5:32:6 | forach(... in ...) | functions.ps1:33:5:33:9 | sum | empty | -| functions.ps1:29:14:29:21 | number | functions.ps1:29:35:32:6 | {...} | | -| functions.ps1:29:25:29:33 | numbers | functions.ps1:29:5:32:6 | forach(... in ...) | | -| functions.ps1:29:25:29:33 | numbers | functions.ps1:29:25:29:33 | numbers | | -| functions.ps1:29:35:32:6 | {...} | functions.ps1:31:9:31:24 | ...=... | | -| functions.ps1:31:9:31:13 | sum | functions.ps1:31:17:31:24 | number | | -| functions.ps1:31:9:31:24 | ...=... | functions.ps1:31:9:31:13 | sum | | -| functions.ps1:31:17:31:24 | number | functions.ps1:29:5:32:6 | forach(... in ...) | | -| functions.ps1:31:17:31:24 | number | functions.ps1:31:17:31:24 | number | | -| functions.ps1:33:5:33:9 | sum | functions.ps1:22:33:34:2 | exit {...} (normal) | | -| functions.ps1:33:5:33:9 | sum | functions.ps1:33:5:33:9 | sum | | -| functions.ps1:36:1:52:2 | Add-Numbers-From-Pipeline | functions.ps1:1:1:54:1 | exit functions.ps1 (normal) | | -| functions.ps1:36:36:52:2 | enter {...} | functions.ps1:36:36:52:2 | {...} | | -| functions.ps1:36:36:52:2 | exit {...} (normal) | functions.ps1:36:36:52:2 | exit {...} | | -| functions.ps1:36:36:52:2 | {...} | functions.ps1:38:5:40:6 | param(...) | | -| functions.ps1:38:5:40:6 | param(...) | functions.ps1:41:5:43:6 | {...} | | -| functions.ps1:41:5:43:6 | {...} | functions.ps1:42:9:42:17 | ...=... | | -| functions.ps1:42:9:42:13 | sum | functions.ps1:42:16:42:17 | 0 | | -| functions.ps1:42:9:42:17 | ...=... | functions.ps1:42:9:42:13 | sum | | -| functions.ps1:42:16:42:17 | 0 | functions.ps1:42:16:42:17 | 0 | | -| functions.ps1:42:16:42:17 | 0 | functions.ps1:44:5:47:6 | {...} | | -| functions.ps1:44:5:47:6 | {...} | functions.ps1:46:9:46:19 | ...=... | | -| functions.ps1:46:9:46:13 | sum | functions.ps1:46:17:46:19 | _ | | -| functions.ps1:46:9:46:19 | ...=... | functions.ps1:46:9:46:13 | sum | | -| functions.ps1:46:17:46:19 | _ | functions.ps1:44:5:47:6 | {...} | | -| functions.ps1:46:17:46:19 | _ | functions.ps1:46:17:46:19 | _ | | -| functions.ps1:46:17:46:19 | _ | functions.ps1:48:5:51:6 | {...} | | -| functions.ps1:48:5:51:6 | {...} | functions.ps1:50:9:50:13 | sum | | -| functions.ps1:50:9:50:13 | sum | functions.ps1:36:36:52:2 | exit {...} (normal) | | -| functions.ps1:50:9:50:13 | sum | functions.ps1:50:9:50:13 | sum | | -| global.ps1:1:1:4:2 | {...} | global.ps1:2:5:2:11 | ...=... | | -| global.ps1:1:1:7:2 | enter global.ps1 | global.ps1:1:1:7:2 | global.ps1 | | -| global.ps1:1:1:7:2 | exit global.ps1 (normal) | global.ps1:1:1:7:2 | exit global.ps1 | | -| global.ps1:1:1:7:2 | global.ps1 | global.ps1:1:1:4:2 | {...} | | -| global.ps1:1:1:7:2 | global.ps1 | global.ps1:1:1:7:2 | exit global.ps1 (normal) | | -| global.ps1:2:5:2:7 | a | global.ps1:2:10:2:11 | 1 | | -| global.ps1:2:5:2:11 | ...=... | global.ps1:2:5:2:7 | a | | -| global.ps1:2:10:2:11 | 1 | global.ps1:2:10:2:11 | 1 | | -| global.ps1:2:10:2:11 | 1 | global.ps1:3:5:3:11 | ...=... | | -| global.ps1:3:5:3:7 | b | global.ps1:3:10:3:11 | 2 | | -| global.ps1:3:5:3:11 | ...=... | global.ps1:3:5:3:7 | b | | -| global.ps1:3:10:3:11 | 2 | global.ps1:3:10:3:11 | 2 | | -| global.ps1:3:10:3:11 | 2 | global.ps1:5:1:7:2 | {...} | | -| global.ps1:5:1:7:2 | {...} | global.ps1:6:5:6:17 | ...=... | | -| global.ps1:6:5:6:7 | c | global.ps1:6:10:6:12 | a | | -| global.ps1:6:5:6:17 | ...=... | global.ps1:6:5:6:7 | c | | -| global.ps1:6:10:6:12 | a | global.ps1:6:15:6:17 | b | | -| global.ps1:6:10:6:17 | ...+... | global.ps1:1:1:7:2 | exit global.ps1 (normal) | | -| global.ps1:6:10:6:17 | ...+... | global.ps1:6:10:6:17 | ...+... | | -| global.ps1:6:15:6:17 | b | global.ps1:6:10:6:17 | ...+... | | -| loops.ps1:1:1:7:2 | Test-While | loops.ps1:9:1:15:2 | Test-Break | | -| loops.ps1:1:1:68:2 | {...} | loops.ps1:1:1:7:2 | Test-While | | -| loops.ps1:1:1:70:1 | enter loops.ps1 | loops.ps1:1:1:70:1 | loops.ps1 | | -| loops.ps1:1:1:70:1 | exit loops.ps1 (normal) | loops.ps1:1:1:70:1 | exit loops.ps1 | | -| loops.ps1:1:1:70:1 | loops.ps1 | loops.ps1:1:1:68:2 | {...} | | -| loops.ps1:1:1:70:1 | loops.ps1 | loops.ps1:1:1:70:1 | exit loops.ps1 (normal) | | -| loops.ps1:1:21:7:2 | enter {...} | loops.ps1:1:21:7:2 | {...} | | -| loops.ps1:1:21:7:2 | exit {...} (normal) | loops.ps1:1:21:7:2 | exit {...} | | -| loops.ps1:1:21:7:2 | {...} | loops.ps1:2:5:6:6 | {...} | | -| loops.ps1:2:5:2:7 | a | loops.ps1:2:10:2:11 | 0 | | -| loops.ps1:2:5:2:11 | ...=... | loops.ps1:2:5:2:7 | a | | -| loops.ps1:2:5:6:6 | {...} | loops.ps1:2:5:2:11 | ...=... | | -| loops.ps1:2:10:2:11 | 0 | loops.ps1:2:10:2:11 | 0 | | -| loops.ps1:2:10:2:11 | 0 | loops.ps1:4:5:6:6 | while(...) {...} | | -| loops.ps1:4:5:6:6 | while(...) {...} | loops.ps1:4:11:4:13 | a | | -| loops.ps1:4:11:4:13 | a | loops.ps1:4:18:4:20 | 10 | | -| loops.ps1:4:11:4:20 | ... -le ... | loops.ps1:1:21:7:2 | exit {...} (normal) | false | -| loops.ps1:4:11:4:20 | ... -le ... | loops.ps1:4:11:4:20 | ... -le ... | false, true | -| loops.ps1:4:11:4:20 | ... -le ... | loops.ps1:4:22:6:6 | {...} | true | -| loops.ps1:4:18:4:20 | 10 | loops.ps1:4:11:4:20 | ... -le ... | | -| loops.ps1:4:22:6:6 | {...} | loops.ps1:5:9:5:20 | ...=... | | -| loops.ps1:5:9:5:11 | a | loops.ps1:5:14:5:16 | a | | -| loops.ps1:5:9:5:20 | ...=... | loops.ps1:5:9:5:11 | a | | -| loops.ps1:5:14:5:16 | a | loops.ps1:5:19:5:20 | 1 | | -| loops.ps1:5:14:5:20 | ...+... | loops.ps1:4:11:4:13 | a | | -| loops.ps1:5:14:5:20 | ...+... | loops.ps1:5:14:5:20 | ...+... | | -| loops.ps1:5:19:5:20 | 1 | loops.ps1:5:14:5:20 | ...+... | | -| loops.ps1:9:1:15:2 | Test-Break | loops.ps1:17:1:23:2 | Test-Continue | | -| loops.ps1:9:21:15:2 | enter {...} | loops.ps1:9:21:15:2 | {...} | | -| loops.ps1:9:21:15:2 | exit {...} (normal) | loops.ps1:9:21:15:2 | exit {...} | | -| loops.ps1:9:21:15:2 | {...} | loops.ps1:10:5:14:6 | {...} | | -| loops.ps1:10:5:10:7 | a | loops.ps1:10:10:10:11 | 0 | | -| loops.ps1:10:5:10:11 | ...=... | loops.ps1:10:5:10:7 | a | | -| loops.ps1:10:5:14:6 | {...} | loops.ps1:10:5:10:11 | ...=... | | -| loops.ps1:10:10:10:11 | 0 | loops.ps1:10:10:10:11 | 0 | | -| loops.ps1:10:10:10:11 | 0 | loops.ps1:11:5:14:6 | while(...) {...} | | -| loops.ps1:11:5:14:6 | while(...) {...} | loops.ps1:11:11:11:13 | a | | -| loops.ps1:11:11:11:13 | a | loops.ps1:11:18:11:20 | 10 | | -| loops.ps1:11:11:11:20 | ... -le ... | loops.ps1:9:21:15:2 | exit {...} (normal) | false | -| loops.ps1:11:11:11:20 | ... -le ... | loops.ps1:11:11:11:20 | ... -le ... | false, true | -| loops.ps1:11:11:11:20 | ... -le ... | loops.ps1:11:22:14:6 | {...} | true | -| loops.ps1:11:18:11:20 | 10 | loops.ps1:11:11:11:20 | ... -le ... | | -| loops.ps1:11:22:14:6 | {...} | loops.ps1:12:9:12:14 | break | | -| loops.ps1:12:9:12:14 | break | loops.ps1:9:21:15:2 | exit {...} (normal) | break | -| loops.ps1:17:1:23:2 | Test-Continue | loops.ps1:25:1:31:2 | Test-DoWhile | | -| loops.ps1:17:24:23:2 | enter {...} | loops.ps1:17:24:23:2 | {...} | | -| loops.ps1:17:24:23:2 | exit {...} (normal) | loops.ps1:17:24:23:2 | exit {...} | | -| loops.ps1:17:24:23:2 | {...} | loops.ps1:18:5:22:6 | {...} | | -| loops.ps1:18:5:18:7 | a | loops.ps1:18:10:18:11 | 0 | | -| loops.ps1:18:5:18:11 | ...=... | loops.ps1:18:5:18:7 | a | | -| loops.ps1:18:5:22:6 | {...} | loops.ps1:18:5:18:11 | ...=... | | -| loops.ps1:18:10:18:11 | 0 | loops.ps1:18:10:18:11 | 0 | | -| loops.ps1:18:10:18:11 | 0 | loops.ps1:19:5:22:6 | while(...) {...} | | -| loops.ps1:19:5:22:6 | while(...) {...} | loops.ps1:19:11:19:13 | a | | -| loops.ps1:19:11:19:13 | a | loops.ps1:19:18:19:20 | 10 | | -| loops.ps1:19:11:19:20 | ... -le ... | loops.ps1:17:24:23:2 | exit {...} (normal) | false | -| loops.ps1:19:11:19:20 | ... -le ... | loops.ps1:19:11:19:20 | ... -le ... | false, true | -| loops.ps1:19:11:19:20 | ... -le ... | loops.ps1:19:22:22:6 | {...} | true | -| loops.ps1:19:18:19:20 | 10 | loops.ps1:19:11:19:20 | ... -le ... | | -| loops.ps1:19:22:22:6 | {...} | loops.ps1:20:9:20:17 | continue | | -| loops.ps1:20:9:20:17 | continue | loops.ps1:19:11:19:13 | a | continue | -| loops.ps1:25:1:31:2 | Test-DoWhile | loops.ps1:33:1:39:2 | Test-DoUntil | | -| loops.ps1:25:23:31:2 | enter {...} | loops.ps1:25:23:31:2 | {...} | | -| loops.ps1:25:23:31:2 | exit {...} (normal) | loops.ps1:25:23:31:2 | exit {...} | | -| loops.ps1:25:23:31:2 | {...} | loops.ps1:26:5:30:24 | {...} | | -| loops.ps1:26:5:26:7 | a | loops.ps1:26:10:26:11 | 0 | | -| loops.ps1:26:5:26:11 | ...=... | loops.ps1:26:5:26:7 | a | | -| loops.ps1:26:5:30:24 | {...} | loops.ps1:26:5:26:11 | ...=... | | -| loops.ps1:26:10:26:11 | 0 | loops.ps1:26:10:26:11 | 0 | | -| loops.ps1:26:10:26:11 | 0 | loops.ps1:28:5:30:24 | DoWhile | | -| loops.ps1:28:5:30:24 | DoWhile | loops.ps1:28:8:30:6 | {...} | | -| loops.ps1:28:8:30:6 | {...} | loops.ps1:29:9:29:20 | ...=... | | -| loops.ps1:29:9:29:11 | a | loops.ps1:29:14:29:16 | a | | -| loops.ps1:29:9:29:20 | ...=... | loops.ps1:29:9:29:11 | a | | -| loops.ps1:29:14:29:16 | a | loops.ps1:29:19:29:20 | 1 | | -| loops.ps1:29:14:29:20 | ...+... | loops.ps1:29:14:29:20 | ...+... | | -| loops.ps1:29:14:29:20 | ...+... | loops.ps1:30:14:30:16 | a | | -| loops.ps1:29:19:29:20 | 1 | loops.ps1:29:14:29:20 | ...+... | | -| loops.ps1:30:14:30:16 | a | loops.ps1:30:21:30:23 | 10 | | -| loops.ps1:30:14:30:23 | ... -le ... | loops.ps1:25:23:31:2 | exit {...} (normal) | false | -| loops.ps1:30:14:30:23 | ... -le ... | loops.ps1:28:8:30:6 | {...} | true | -| loops.ps1:30:14:30:23 | ... -le ... | loops.ps1:30:14:30:23 | ... -le ... | false, true | -| loops.ps1:30:21:30:23 | 10 | loops.ps1:30:14:30:23 | ... -le ... | | -| loops.ps1:33:1:39:2 | Test-DoUntil | loops.ps1:41:1:47:2 | Test-For | | -| loops.ps1:33:23:39:2 | enter {...} | loops.ps1:33:23:39:2 | {...} | | -| loops.ps1:33:23:39:2 | exit {...} (normal) | loops.ps1:33:23:39:2 | exit {...} | | -| loops.ps1:33:23:39:2 | {...} | loops.ps1:34:5:38:24 | {...} | | -| loops.ps1:34:5:34:7 | a | loops.ps1:34:10:34:11 | 0 | | -| loops.ps1:34:5:34:11 | ...=... | loops.ps1:34:5:34:7 | a | | -| loops.ps1:34:5:38:24 | {...} | loops.ps1:34:5:34:11 | ...=... | | -| loops.ps1:34:10:34:11 | 0 | loops.ps1:34:10:34:11 | 0 | | -| loops.ps1:34:10:34:11 | 0 | loops.ps1:36:5:38:24 | DoUntil | | -| loops.ps1:36:5:38:24 | DoUntil | loops.ps1:36:8:38:6 | {...} | | -| loops.ps1:36:8:38:6 | {...} | loops.ps1:37:9:37:20 | ...=... | | -| loops.ps1:37:9:37:11 | a | loops.ps1:37:14:37:16 | a | | -| loops.ps1:37:9:37:20 | ...=... | loops.ps1:37:9:37:11 | a | | -| loops.ps1:37:14:37:16 | a | loops.ps1:37:19:37:20 | 1 | | -| loops.ps1:37:14:37:20 | ...+... | loops.ps1:37:14:37:20 | ...+... | | -| loops.ps1:37:14:37:20 | ...+... | loops.ps1:38:14:38:16 | a | | -| loops.ps1:37:19:37:20 | 1 | loops.ps1:37:14:37:20 | ...+... | | -| loops.ps1:38:14:38:16 | a | loops.ps1:38:21:38:23 | 10 | | -| loops.ps1:38:14:38:23 | ... -ge ... | loops.ps1:33:23:39:2 | exit {...} (normal) | true | -| loops.ps1:38:14:38:23 | ... -ge ... | loops.ps1:36:8:38:6 | {...} | false | -| loops.ps1:38:14:38:23 | ... -ge ... | loops.ps1:38:14:38:23 | ... -ge ... | false, true | -| loops.ps1:38:21:38:23 | 10 | loops.ps1:38:14:38:23 | ... -ge ... | | -| loops.ps1:41:1:47:2 | Test-For | loops.ps1:49:1:56:2 | Test-ForEach | | -| loops.ps1:41:19:47:2 | enter {...} | loops.ps1:41:19:47:2 | {...} | | -| loops.ps1:41:19:47:2 | exit {...} (normal) | loops.ps1:41:19:47:2 | exit {...} | | -| loops.ps1:41:19:47:2 | {...} | loops.ps1:42:5:46:6 | {...} | | -| loops.ps1:42:5:42:7 | a | loops.ps1:42:10:42:11 | 0 | | -| loops.ps1:42:5:42:11 | ...=... | loops.ps1:42:5:42:7 | a | | -| loops.ps1:42:5:46:6 | {...} | loops.ps1:42:5:42:11 | ...=... | | -| loops.ps1:42:10:42:11 | 0 | loops.ps1:42:10:42:11 | 0 | | -| loops.ps1:42:10:42:11 | 0 | loops.ps1:44:5:46:6 | for(...;...;...) | | -| loops.ps1:44:5:46:6 | for(...;...;...) | loops.ps1:44:10:44:16 | ...=... | | -| loops.ps1:44:10:44:12 | i | loops.ps1:44:15:44:16 | 0 | | -| loops.ps1:44:10:44:16 | ...=... | loops.ps1:44:10:44:12 | i | | -| loops.ps1:44:15:44:16 | 0 | loops.ps1:44:15:44:16 | 0 | | -| loops.ps1:44:15:44:16 | 0 | loops.ps1:44:18:44:20 | i | | -| loops.ps1:44:18:44:20 | i | loops.ps1:44:25:44:27 | 10 | | -| loops.ps1:44:18:44:27 | ... -le ... | loops.ps1:41:19:47:2 | exit {...} (normal) | false | -| loops.ps1:44:18:44:27 | ... -le ... | loops.ps1:44:18:44:27 | ... -le ... | false, true | -| loops.ps1:44:18:44:27 | ... -le ... | loops.ps1:44:42:46:6 | {...} | true | -| loops.ps1:44:25:44:27 | 10 | loops.ps1:44:18:44:27 | ... -le ... | | -| loops.ps1:44:29:44:31 | i | loops.ps1:44:34:44:36 | i | | -| loops.ps1:44:29:44:40 | ...=... | loops.ps1:44:29:44:31 | i | | -| loops.ps1:44:34:44:36 | i | loops.ps1:44:39:44:40 | 1 | | -| loops.ps1:44:34:44:40 | ...+... | loops.ps1:44:18:44:20 | i | | -| loops.ps1:44:34:44:40 | ...+... | loops.ps1:44:34:44:40 | ...+... | | -| loops.ps1:44:39:44:40 | 1 | loops.ps1:44:34:44:40 | ...+... | | -| loops.ps1:44:42:46:6 | {...} | loops.ps1:45:9:45:20 | ...=... | | -| loops.ps1:45:9:45:11 | a | loops.ps1:45:14:45:16 | a | | -| loops.ps1:45:9:45:20 | ...=... | loops.ps1:45:9:45:11 | a | | -| loops.ps1:45:14:45:16 | a | loops.ps1:45:19:45:20 | 1 | | -| loops.ps1:45:14:45:20 | ...+... | loops.ps1:44:18:44:20 | i | | -| loops.ps1:45:14:45:20 | ...+... | loops.ps1:44:29:44:40 | ...=... | | -| loops.ps1:45:14:45:20 | ...+... | loops.ps1:45:14:45:20 | ...+... | | -| loops.ps1:45:19:45:20 | 1 | loops.ps1:45:14:45:20 | ...+... | | -| loops.ps1:49:1:56:2 | Test-ForEach | loops.ps1:58:1:68:2 | Test-For-Ever | | -| loops.ps1:49:23:56:2 | enter {...} | loops.ps1:49:23:56:2 | {...} | | -| loops.ps1:49:23:56:2 | exit {...} (normal) | loops.ps1:49:23:56:2 | exit {...} | | -| loops.ps1:49:23:56:2 | {...} | loops.ps1:50:5:55:6 | {...} | | -| loops.ps1:50:5:50:17 | letterArray | loops.ps1:50:20:50:23 | a | | -| loops.ps1:50:5:50:35 | ...=... | loops.ps1:50:5:50:17 | letterArray | | -| loops.ps1:50:5:55:6 | {...} | loops.ps1:50:5:50:35 | ...=... | | -| loops.ps1:50:20:50:23 | a | loops.ps1:50:24:50:27 | b | | -| loops.ps1:50:20:50:35 | ...,... | loops.ps1:50:20:50:35 | ...,... | | -| loops.ps1:50:20:50:35 | ...,... | loops.ps1:51:5:51:11 | ...=... | | -| loops.ps1:50:24:50:27 | b | loops.ps1:50:28:50:31 | c | | -| loops.ps1:50:28:50:31 | c | loops.ps1:50:32:50:35 | d | | -| loops.ps1:50:32:50:35 | d | loops.ps1:50:20:50:35 | ...,... | | -| loops.ps1:51:5:51:7 | a | loops.ps1:51:10:51:11 | 0 | | -| loops.ps1:51:5:51:11 | ...=... | loops.ps1:51:5:51:7 | a | | -| loops.ps1:51:10:51:11 | 0 | loops.ps1:51:10:51:11 | 0 | | -| loops.ps1:51:10:51:11 | 0 | loops.ps1:52:25:52:37 | letterArray | | -| loops.ps1:52:5:55:6 | forach(... in ...) | loops.ps1:49:23:56:2 | exit {...} (normal) | empty | -| loops.ps1:52:5:55:6 | forach(... in ...) | loops.ps1:52:14:52:21 | letter | non-empty | -| loops.ps1:52:14:52:21 | letter | loops.ps1:53:5:55:6 | {...} | | -| loops.ps1:52:25:52:37 | letterArray | loops.ps1:52:5:55:6 | forach(... in ...) | | -| loops.ps1:52:25:52:37 | letterArray | loops.ps1:52:25:52:37 | letterArray | | -| loops.ps1:53:5:55:6 | {...} | loops.ps1:54:9:54:20 | ...=... | | -| loops.ps1:54:9:54:11 | a | loops.ps1:54:14:54:16 | a | | -| loops.ps1:54:9:54:20 | ...=... | loops.ps1:54:9:54:11 | a | | -| loops.ps1:54:14:54:16 | a | loops.ps1:54:19:54:20 | 1 | | -| loops.ps1:54:14:54:20 | ...+... | loops.ps1:52:5:55:6 | forach(... in ...) | | -| loops.ps1:54:14:54:20 | ...+... | loops.ps1:54:14:54:20 | ...+... | | -| loops.ps1:54:19:54:20 | 1 | loops.ps1:54:14:54:20 | ...+... | | -| loops.ps1:58:1:68:2 | Test-For-Ever | loops.ps1:1:1:70:1 | exit loops.ps1 (normal) | | -| loops.ps1:58:24:68:2 | enter {...} | loops.ps1:58:24:68:2 | {...} | | -| loops.ps1:58:24:68:2 | exit {...} (normal) | loops.ps1:58:24:68:2 | exit {...} | | -| loops.ps1:58:24:68:2 | {...} | loops.ps1:59:5:67:6 | {...} | | -| loops.ps1:59:5:59:7 | a | loops.ps1:59:10:59:11 | 0 | | -| loops.ps1:59:5:59:11 | ...=... | loops.ps1:59:5:59:7 | a | | -| loops.ps1:59:5:67:6 | {...} | loops.ps1:59:5:59:11 | ...=... | | -| loops.ps1:59:10:59:11 | 0 | loops.ps1:59:10:59:11 | 0 | | -| loops.ps1:59:10:59:11 | 0 | loops.ps1:61:5:67:6 | for(...;...;...) | | -| loops.ps1:61:5:67:6 | for(...;...;...) | loops.ps1:62:5:67:6 | {...} | | -| loops.ps1:62:5:67:6 | {...} | loops.ps1:63:9:66:10 | if (...) {...} | | -| loops.ps1:63:9:66:10 | if (...) {...} | loops.ps1:63:12:63:14 | a | | -| loops.ps1:63:12:63:14 | a | loops.ps1:63:19:63:21 | 10 | | -| loops.ps1:63:12:63:21 | ... -le ... | loops.ps1:63:12:63:21 | ... -le ... | false, true | -| loops.ps1:63:12:63:21 | ... -le ... | loops.ps1:64:9:66:10 | {...} | true | -| loops.ps1:63:19:63:21 | 10 | loops.ps1:63:12:63:21 | ... -le ... | | -| loops.ps1:64:9:66:10 | {...} | loops.ps1:65:13:65:18 | break | | -| loops.ps1:65:13:65:18 | break | loops.ps1:58:24:68:2 | exit {...} (normal) | break | -| try.ps1:1:1:8:2 | test-try-catch | try.ps1:10:1:19:2 | test-try-with-throw-catch | | -| try.ps1:1:1:194:2 | enter try.ps1 | try.ps1:1:1:194:2 | try.ps1 | | -| try.ps1:1:1:194:2 | exit try.ps1 (normal) | try.ps1:1:1:194:2 | exit try.ps1 | | -| try.ps1:1:1:194:2 | try.ps1 | try.ps1:1:1:194:2 | exit try.ps1 (normal) | | -| try.ps1:1:1:194:2 | try.ps1 | try.ps1:1:1:194:2 | {...} | | -| try.ps1:1:1:194:2 | {...} | try.ps1:1:1:8:2 | test-try-catch | | -| try.ps1:1:25:8:2 | enter {...} | try.ps1:1:25:8:2 | {...} | | -| try.ps1:1:25:8:2 | exit {...} (normal) | try.ps1:1:25:8:2 | exit {...} | | -| try.ps1:1:25:8:2 | {...} | try.ps1:2:5:7:13 | {...} | | -| try.ps1:2:5:6:6 | try {...} | try.ps1:2:9:4:6 | {...} | | -| try.ps1:2:5:7:13 | {...} | try.ps1:2:5:6:6 | try {...} | | -| try.ps1:2:9:4:6 | {...} | try.ps1:3:9:3:21 | Write-Output | | -| try.ps1:3:9:3:21 | Write-Output | try.ps1:3:22:3:30 | Hello! | | -| try.ps1:3:9:3:30 | call to Write-Output | try.ps1:7:5:7:13 | return ... | | -| try.ps1:3:22:3:30 | Hello! | try.ps1:3:9:3:30 | call to Write-Output | | -| try.ps1:7:5:7:13 | return ... | try.ps1:7:12:7:13 | 1 | | -| try.ps1:7:12:7:13 | 1 | try.ps1:1:25:8:2 | exit {...} (normal) | | -| try.ps1:7:12:7:13 | 1 | try.ps1:7:12:7:13 | 1 | | -| try.ps1:10:1:19:2 | test-try-with-throw-catch | try.ps1:21:1:30:2 | test-try-with-throw-catch-with-throw | | -| try.ps1:10:40:19:2 | enter {...} | try.ps1:10:40:19:2 | {...} | | -| try.ps1:10:40:19:2 | exit {...} (normal) | try.ps1:10:40:19:2 | exit {...} | | -| try.ps1:10:40:19:2 | {...} | try.ps1:11:5:18:13 | {...} | | -| try.ps1:11:5:17:6 | try {...} | try.ps1:11:9:15:6 | {...} | | -| try.ps1:11:5:18:13 | {...} | try.ps1:11:5:17:6 | try {...} | | -| try.ps1:11:9:15:6 | {...} | try.ps1:12:9:14:10 | if (...) {...} | | -| try.ps1:12:9:14:10 | if (...) {...} | try.ps1:12:12:12:14 | b | | -| try.ps1:12:12:12:14 | b | try.ps1:12:12:12:14 | b | false, true | -| try.ps1:12:12:12:14 | b | try.ps1:12:16:14:10 | {...} | true | -| try.ps1:12:16:14:10 | {...} | try.ps1:13:13:13:21 | throw ... | | -| try.ps1:13:13:13:21 | throw ... | try.ps1:13:19:13:21 | 42 | | -| try.ps1:13:19:13:21 | 42 | try.ps1:13:19:13:21 | 42 | | -| try.ps1:13:19:13:21 | 42 | try.ps1:18:5:18:13 | return ... | | -| try.ps1:18:5:18:13 | return ... | try.ps1:18:12:18:13 | 1 | | -| try.ps1:18:12:18:13 | 1 | try.ps1:10:40:19:2 | exit {...} (normal) | | -| try.ps1:18:12:18:13 | 1 | try.ps1:18:12:18:13 | 1 | | -| try.ps1:21:1:30:2 | test-try-with-throw-catch-with-throw | try.ps1:32:1:41:2 | test-try-with-throw-catch-with-rethrow | | -| try.ps1:21:51:30:2 | enter {...} | try.ps1:21:51:30:2 | {...} | | -| try.ps1:21:51:30:2 | exit {...} (normal) | try.ps1:21:51:30:2 | exit {...} | | -| try.ps1:21:51:30:2 | {...} | try.ps1:22:5:29:13 | {...} | | -| try.ps1:22:5:28:6 | try {...} | try.ps1:22:9:26:6 | {...} | | -| try.ps1:22:5:29:13 | {...} | try.ps1:22:5:28:6 | try {...} | | -| try.ps1:22:9:26:6 | {...} | try.ps1:23:9:25:10 | if (...) {...} | | -| try.ps1:23:9:25:10 | if (...) {...} | try.ps1:23:12:23:14 | b | | -| try.ps1:23:12:23:14 | b | try.ps1:23:12:23:14 | b | false, true | -| try.ps1:23:12:23:14 | b | try.ps1:23:16:25:10 | {...} | true | -| try.ps1:23:16:25:10 | {...} | try.ps1:24:13:24:21 | throw ... | | -| try.ps1:24:13:24:21 | throw ... | try.ps1:24:19:24:21 | 42 | | -| try.ps1:24:19:24:21 | 42 | try.ps1:24:19:24:21 | 42 | | -| try.ps1:24:19:24:21 | 42 | try.ps1:29:5:29:13 | return ... | | -| try.ps1:29:5:29:13 | return ... | try.ps1:29:12:29:13 | 1 | | -| try.ps1:29:12:29:13 | 1 | try.ps1:21:51:30:2 | exit {...} (normal) | | -| try.ps1:29:12:29:13 | 1 | try.ps1:29:12:29:13 | 1 | | -| try.ps1:32:1:41:2 | test-try-with-throw-catch-with-rethrow | try.ps1:43:1:50:2 | test-try-catch-specific-1 | | -| try.ps1:32:53:41:2 | enter {...} | try.ps1:32:53:41:2 | {...} | | -| try.ps1:32:53:41:2 | exit {...} (normal) | try.ps1:32:53:41:2 | exit {...} | | -| try.ps1:32:53:41:2 | {...} | try.ps1:33:5:40:13 | {...} | | -| try.ps1:33:5:39:6 | try {...} | try.ps1:33:9:37:6 | {...} | | -| try.ps1:33:5:40:13 | {...} | try.ps1:33:5:39:6 | try {...} | | -| try.ps1:33:9:37:6 | {...} | try.ps1:34:9:36:10 | if (...) {...} | | -| try.ps1:34:9:36:10 | if (...) {...} | try.ps1:34:12:34:14 | b | | -| try.ps1:34:12:34:14 | b | try.ps1:34:12:34:14 | b | false, true | -| try.ps1:34:12:34:14 | b | try.ps1:34:16:36:10 | {...} | true | -| try.ps1:34:16:36:10 | {...} | try.ps1:35:13:35:21 | throw ... | | -| try.ps1:35:13:35:21 | throw ... | try.ps1:35:19:35:21 | 42 | | -| try.ps1:35:19:35:21 | 42 | try.ps1:35:19:35:21 | 42 | | -| try.ps1:35:19:35:21 | 42 | try.ps1:40:5:40:13 | return ... | | -| try.ps1:40:5:40:13 | return ... | try.ps1:40:12:40:13 | 1 | | -| try.ps1:40:12:40:13 | 1 | try.ps1:32:53:41:2 | exit {...} (normal) | | -| try.ps1:40:12:40:13 | 1 | try.ps1:40:12:40:13 | 1 | | -| try.ps1:43:1:50:2 | test-try-catch-specific-1 | try.ps1:52:1:59:2 | test-try-catch-specific-1 | | -| try.ps1:43:36:50:2 | enter {...} | try.ps1:43:36:50:2 | {...} | | -| try.ps1:43:36:50:2 | exit {...} (normal) | try.ps1:43:36:50:2 | exit {...} | | -| try.ps1:43:36:50:2 | {...} | try.ps1:44:5:49:13 | {...} | | -| try.ps1:44:5:48:6 | try {...} | try.ps1:44:9:46:6 | {...} | | -| try.ps1:44:5:49:13 | {...} | try.ps1:44:5:48:6 | try {...} | | -| try.ps1:44:9:46:6 | {...} | try.ps1:45:9:45:21 | Write-Output | | -| try.ps1:45:9:45:21 | Write-Output | try.ps1:45:22:45:30 | Hello! | | -| try.ps1:45:9:45:30 | call to Write-Output | try.ps1:49:5:49:13 | return ... | | -| try.ps1:45:22:45:30 | Hello! | try.ps1:45:9:45:30 | call to Write-Output | | -| try.ps1:49:5:49:13 | return ... | try.ps1:49:12:49:13 | 1 | | -| try.ps1:49:12:49:13 | 1 | try.ps1:43:36:50:2 | exit {...} (normal) | | -| try.ps1:49:12:49:13 | 1 | try.ps1:49:12:49:13 | 1 | | -| try.ps1:52:1:59:2 | test-try-catch-specific-1 | try.ps1:61:1:70:2 | test-try-two-catch-specific-1 | | -| try.ps1:52:36:59:2 | enter {...} | try.ps1:52:36:59:2 | {...} | | -| try.ps1:52:36:59:2 | exit {...} (normal) | try.ps1:52:36:59:2 | exit {...} | | -| try.ps1:52:36:59:2 | {...} | try.ps1:53:5:58:13 | {...} | | -| try.ps1:53:5:57:6 | try {...} | try.ps1:53:9:55:6 | {...} | | -| try.ps1:53:5:58:13 | {...} | try.ps1:53:5:57:6 | try {...} | | -| try.ps1:53:9:55:6 | {...} | try.ps1:54:9:54:21 | Write-Output | | -| try.ps1:54:9:54:21 | Write-Output | try.ps1:54:22:54:30 | Hello! | | -| try.ps1:54:9:54:30 | call to Write-Output | try.ps1:58:5:58:13 | return ... | | -| try.ps1:54:22:54:30 | Hello! | try.ps1:54:9:54:30 | call to Write-Output | | -| try.ps1:58:5:58:13 | return ... | try.ps1:58:12:58:13 | 1 | | -| try.ps1:58:12:58:13 | 1 | try.ps1:52:36:59:2 | exit {...} (normal) | | -| try.ps1:58:12:58:13 | 1 | try.ps1:58:12:58:13 | 1 | | -| try.ps1:61:1:70:2 | test-try-two-catch-specific-1 | try.ps1:72:1:79:2 | test-try-catch-specific-2 | | -| try.ps1:61:40:70:2 | enter {...} | try.ps1:61:40:70:2 | {...} | | -| try.ps1:61:40:70:2 | exit {...} (normal) | try.ps1:61:40:70:2 | exit {...} | | -| try.ps1:61:40:70:2 | {...} | try.ps1:62:5:69:13 | {...} | | -| try.ps1:62:5:68:6 | try {...} | try.ps1:62:9:64:6 | {...} | | -| try.ps1:62:5:69:13 | {...} | try.ps1:62:5:68:6 | try {...} | | -| try.ps1:62:9:64:6 | {...} | try.ps1:63:9:63:21 | Write-Output | | -| try.ps1:63:9:63:21 | Write-Output | try.ps1:63:22:63:30 | Hello! | | -| try.ps1:63:9:63:30 | call to Write-Output | try.ps1:69:5:69:13 | return ... | | -| try.ps1:63:22:63:30 | Hello! | try.ps1:63:9:63:30 | call to Write-Output | | -| try.ps1:69:5:69:13 | return ... | try.ps1:69:12:69:13 | 2 | | -| try.ps1:69:12:69:13 | 2 | try.ps1:61:40:70:2 | exit {...} (normal) | | -| try.ps1:69:12:69:13 | 2 | try.ps1:69:12:69:13 | 2 | | -| try.ps1:72:1:79:2 | test-try-catch-specific-2 | try.ps1:81:1:90:2 | test-try-two-catch-specific-2 | | -| try.ps1:72:36:79:2 | enter {...} | try.ps1:72:36:79:2 | {...} | | -| try.ps1:72:36:79:2 | exit {...} (normal) | try.ps1:72:36:79:2 | exit {...} | | -| try.ps1:72:36:79:2 | {...} | try.ps1:73:5:78:13 | {...} | | -| try.ps1:73:5:77:6 | try {...} | try.ps1:73:9:75:6 | {...} | | -| try.ps1:73:5:78:13 | {...} | try.ps1:73:5:77:6 | try {...} | | -| try.ps1:73:9:75:6 | {...} | try.ps1:74:9:74:21 | Write-Output | | -| try.ps1:74:9:74:21 | Write-Output | try.ps1:74:22:74:30 | Hello! | | -| try.ps1:74:9:74:30 | call to Write-Output | try.ps1:78:5:78:13 | return ... | | -| try.ps1:74:22:74:30 | Hello! | try.ps1:74:9:74:30 | call to Write-Output | | -| try.ps1:78:5:78:13 | return ... | try.ps1:78:12:78:13 | 1 | | -| try.ps1:78:12:78:13 | 1 | try.ps1:72:36:79:2 | exit {...} (normal) | | -| try.ps1:78:12:78:13 | 1 | try.ps1:78:12:78:13 | 1 | | -| try.ps1:81:1:90:2 | test-try-two-catch-specific-2 | try.ps1:92:1:103:2 | test-try-three-catch-specific-2 | | -| try.ps1:81:40:90:2 | enter {...} | try.ps1:81:40:90:2 | {...} | | -| try.ps1:81:40:90:2 | exit {...} (normal) | try.ps1:81:40:90:2 | exit {...} | | -| try.ps1:81:40:90:2 | {...} | try.ps1:82:5:89:13 | {...} | | -| try.ps1:82:5:88:6 | try {...} | try.ps1:82:9:84:6 | {...} | | -| try.ps1:82:5:89:13 | {...} | try.ps1:82:5:88:6 | try {...} | | -| try.ps1:82:9:84:6 | {...} | try.ps1:83:9:83:21 | Write-Output | | -| try.ps1:83:9:83:21 | Write-Output | try.ps1:83:22:83:30 | Hello! | | -| try.ps1:83:9:83:30 | call to Write-Output | try.ps1:89:5:89:13 | return ... | | -| try.ps1:83:22:83:30 | Hello! | try.ps1:83:9:83:30 | call to Write-Output | | -| try.ps1:89:5:89:13 | return ... | try.ps1:89:12:89:13 | 2 | | -| try.ps1:89:12:89:13 | 2 | try.ps1:81:40:90:2 | exit {...} (normal) | | -| try.ps1:89:12:89:13 | 2 | try.ps1:89:12:89:13 | 2 | | -| try.ps1:92:1:103:2 | test-try-three-catch-specific-2 | try.ps1:105:1:114:2 | test-try-catch-finally | | -| try.ps1:92:42:103:2 | enter {...} | try.ps1:92:42:103:2 | {...} | | -| try.ps1:92:42:103:2 | exit {...} (normal) | try.ps1:92:42:103:2 | exit {...} | | -| try.ps1:92:42:103:2 | {...} | try.ps1:93:5:102:13 | {...} | | -| try.ps1:93:5:101:6 | try {...} | try.ps1:93:9:95:6 | {...} | | -| try.ps1:93:5:102:13 | {...} | try.ps1:93:5:101:6 | try {...} | | -| try.ps1:93:9:95:6 | {...} | try.ps1:94:9:94:21 | Write-Output | | -| try.ps1:94:9:94:21 | Write-Output | try.ps1:94:22:94:30 | Hello! | | -| try.ps1:94:9:94:30 | call to Write-Output | try.ps1:102:5:102:13 | return ... | | -| try.ps1:94:22:94:30 | Hello! | try.ps1:94:9:94:30 | call to Write-Output | | -| try.ps1:102:5:102:13 | return ... | try.ps1:102:12:102:13 | 3 | | -| try.ps1:102:12:102:13 | 3 | try.ps1:92:42:103:2 | exit {...} (normal) | | -| try.ps1:102:12:102:13 | 3 | try.ps1:102:12:102:13 | 3 | | -| try.ps1:105:1:114:2 | test-try-catch-finally | try.ps1:116:1:123:2 | test-try-finally | | -| try.ps1:105:33:114:2 | enter {...} | try.ps1:105:33:114:2 | {...} | | -| try.ps1:105:33:114:2 | exit {...} (normal) | try.ps1:105:33:114:2 | exit {...} | | -| try.ps1:105:33:114:2 | {...} | try.ps1:106:5:113:13 | {...} | | -| try.ps1:106:5:112:6 | try {...} | try.ps1:106:9:108:6 | {...} | | -| try.ps1:106:5:113:13 | {...} | try.ps1:106:5:112:6 | try {...} | | -| try.ps1:106:9:108:6 | {...} | try.ps1:107:9:107:21 | Write-Output | | -| try.ps1:107:9:107:21 | Write-Output | try.ps1:107:22:107:30 | Hello! | | -| try.ps1:107:9:107:30 | call to Write-Output | try.ps1:110:15:112:6 | {...} | | -| try.ps1:107:22:107:30 | Hello! | try.ps1:107:9:107:30 | call to Write-Output | | -| try.ps1:110:15:112:6 | {...} | try.ps1:111:9:111:21 | Write-Output | | -| try.ps1:111:9:111:21 | Write-Output | try.ps1:111:22:111:32 | Finally! | | -| try.ps1:111:9:111:32 | call to Write-Output | try.ps1:113:5:113:13 | return ... | | -| try.ps1:111:22:111:32 | Finally! | try.ps1:111:9:111:32 | call to Write-Output | | -| try.ps1:113:5:113:13 | return ... | try.ps1:113:12:113:13 | 1 | | -| try.ps1:113:12:113:13 | 1 | try.ps1:105:33:114:2 | exit {...} (normal) | | -| try.ps1:113:12:113:13 | 1 | try.ps1:113:12:113:13 | 1 | | -| try.ps1:116:1:123:2 | test-try-finally | try.ps1:125:1:134:2 | test-try-finally-catch-specific-1 | | -| try.ps1:116:27:123:2 | enter {...} | try.ps1:116:27:123:2 | {...} | | -| try.ps1:116:27:123:2 | exit {...} (normal) | try.ps1:116:27:123:2 | exit {...} | | -| try.ps1:116:27:123:2 | {...} | try.ps1:117:5:122:13 | {...} | | -| try.ps1:117:5:121:6 | try {...} | try.ps1:117:9:119:6 | {...} | | -| try.ps1:117:5:122:13 | {...} | try.ps1:117:5:121:6 | try {...} | | -| try.ps1:117:9:119:6 | {...} | try.ps1:118:9:118:21 | Write-Output | | -| try.ps1:118:9:118:21 | Write-Output | try.ps1:118:22:118:30 | Hello! | | -| try.ps1:118:9:118:30 | call to Write-Output | try.ps1:119:15:121:6 | {...} | | -| try.ps1:118:22:118:30 | Hello! | try.ps1:118:9:118:30 | call to Write-Output | | -| try.ps1:119:15:121:6 | {...} | try.ps1:120:9:120:21 | Write-Output | | -| try.ps1:120:9:120:21 | Write-Output | try.ps1:120:22:120:32 | Finally! | | -| try.ps1:120:9:120:32 | call to Write-Output | try.ps1:122:5:122:13 | return ... | | -| try.ps1:120:22:120:32 | Finally! | try.ps1:120:9:120:32 | call to Write-Output | | -| try.ps1:122:5:122:13 | return ... | try.ps1:122:12:122:13 | 1 | | -| try.ps1:122:12:122:13 | 1 | try.ps1:116:27:123:2 | exit {...} (normal) | | -| try.ps1:122:12:122:13 | 1 | try.ps1:122:12:122:13 | 1 | | -| try.ps1:125:1:134:2 | test-try-finally-catch-specific-1 | try.ps1:136:1:147:2 | test-nested-try-inner-finally | | -| try.ps1:125:44:134:2 | enter {...} | try.ps1:125:44:134:2 | {...} | | -| try.ps1:125:44:134:2 | exit {...} (normal) | try.ps1:125:44:134:2 | exit {...} | | -| try.ps1:125:44:134:2 | {...} | try.ps1:126:5:133:13 | {...} | | -| try.ps1:126:5:132:6 | try {...} | try.ps1:126:9:128:6 | {...} | | -| try.ps1:126:5:133:13 | {...} | try.ps1:126:5:132:6 | try {...} | | -| try.ps1:126:9:128:6 | {...} | try.ps1:127:9:127:21 | Write-Output | | -| try.ps1:127:9:127:21 | Write-Output | try.ps1:127:22:127:30 | Hello! | | -| try.ps1:127:9:127:30 | call to Write-Output | try.ps1:130:15:132:6 | {...} | | -| try.ps1:127:22:127:30 | Hello! | try.ps1:127:9:127:30 | call to Write-Output | | -| try.ps1:130:15:132:6 | {...} | try.ps1:131:9:131:21 | Write-Output | | -| try.ps1:131:9:131:21 | Write-Output | try.ps1:131:22:131:32 | Finally! | | -| try.ps1:131:9:131:32 | call to Write-Output | try.ps1:133:5:133:13 | return ... | | -| try.ps1:131:22:131:32 | Finally! | try.ps1:131:9:131:32 | call to Write-Output | | -| try.ps1:133:5:133:13 | return ... | try.ps1:133:12:133:13 | 1 | | -| try.ps1:133:12:133:13 | 1 | try.ps1:125:44:134:2 | exit {...} (normal) | | -| try.ps1:133:12:133:13 | 1 | try.ps1:133:12:133:13 | 1 | | -| try.ps1:136:1:147:2 | test-nested-try-inner-finally | try.ps1:149:1:162:2 | test-nested-try-inner-finally | | -| try.ps1:136:40:147:2 | enter {...} | try.ps1:136:40:147:2 | {...} | | -| try.ps1:136:40:147:2 | exit {...} (normal) | try.ps1:136:40:147:2 | exit {...} | | -| try.ps1:136:40:147:2 | {...} | try.ps1:137:5:146:13 | {...} | | -| try.ps1:137:5:145:6 | try {...} | try.ps1:137:9:143:6 | {...} | | -| try.ps1:137:5:146:13 | {...} | try.ps1:137:5:145:6 | try {...} | | -| try.ps1:137:9:143:6 | {...} | try.ps1:138:9:142:10 | try {...} | | -| try.ps1:138:9:142:10 | try {...} | try.ps1:138:13:140:10 | {...} | | -| try.ps1:138:13:140:10 | {...} | try.ps1:139:13:139:25 | Write-Output | | -| try.ps1:139:13:139:25 | Write-Output | try.ps1:139:26:139:34 | Hello! | | -| try.ps1:139:13:139:34 | call to Write-Output | try.ps1:146:5:146:13 | return ... | | -| try.ps1:139:26:139:34 | Hello! | try.ps1:139:13:139:34 | call to Write-Output | | -| try.ps1:146:5:146:13 | return ... | try.ps1:146:12:146:13 | 1 | | -| try.ps1:146:12:146:13 | 1 | try.ps1:136:40:147:2 | exit {...} (normal) | | -| try.ps1:146:12:146:13 | 1 | try.ps1:146:12:146:13 | 1 | | -| try.ps1:149:1:162:2 | test-nested-try-inner-finally | try.ps1:164:1:177:2 | test-nested-try-outer-finally | | -| try.ps1:149:40:162:2 | enter {...} | try.ps1:149:40:162:2 | {...} | | -| try.ps1:149:40:162:2 | exit {...} (normal) | try.ps1:149:40:162:2 | exit {...} | | -| try.ps1:149:40:162:2 | {...} | try.ps1:150:5:161:13 | {...} | | -| try.ps1:150:5:160:6 | try {...} | try.ps1:150:9:158:6 | {...} | | -| try.ps1:150:5:161:13 | {...} | try.ps1:150:5:160:6 | try {...} | | -| try.ps1:150:9:158:6 | {...} | try.ps1:151:9:157:10 | try {...} | | -| try.ps1:151:9:157:10 | try {...} | try.ps1:151:13:153:10 | {...} | | -| try.ps1:151:13:153:10 | {...} | try.ps1:152:13:152:25 | Write-Output | | -| try.ps1:152:13:152:25 | Write-Output | try.ps1:152:26:152:34 | Hello! | | -| try.ps1:152:13:152:34 | call to Write-Output | try.ps1:155:19:157:10 | {...} | | -| try.ps1:152:26:152:34 | Hello! | try.ps1:152:13:152:34 | call to Write-Output | | -| try.ps1:155:19:157:10 | {...} | try.ps1:156:13:156:25 | Write-Output | | -| try.ps1:156:13:156:25 | Write-Output | try.ps1:156:26:156:36 | Finally! | | -| try.ps1:156:13:156:36 | call to Write-Output | try.ps1:161:5:161:13 | return ... | | -| try.ps1:156:26:156:36 | Finally! | try.ps1:156:13:156:36 | call to Write-Output | | -| try.ps1:161:5:161:13 | return ... | try.ps1:161:12:161:13 | 1 | | -| try.ps1:161:12:161:13 | 1 | try.ps1:149:40:162:2 | exit {...} (normal) | | -| try.ps1:161:12:161:13 | 1 | try.ps1:161:12:161:13 | 1 | | -| try.ps1:164:1:177:2 | test-nested-try-outer-finally | try.ps1:179:1:194:2 | test-nested-try-inner-outer-finally | | -| try.ps1:164:40:177:2 | enter {...} | try.ps1:164:40:177:2 | {...} | | -| try.ps1:164:40:177:2 | exit {...} (normal) | try.ps1:164:40:177:2 | exit {...} | | -| try.ps1:164:40:177:2 | {...} | try.ps1:165:5:176:13 | {...} | | -| try.ps1:165:5:175:6 | try {...} | try.ps1:165:9:171:6 | {...} | | -| try.ps1:165:5:176:13 | {...} | try.ps1:165:5:175:6 | try {...} | | -| try.ps1:165:9:171:6 | {...} | try.ps1:166:9:170:10 | try {...} | | -| try.ps1:166:9:170:10 | try {...} | try.ps1:166:13:168:10 | {...} | | -| try.ps1:166:13:168:10 | {...} | try.ps1:167:13:167:25 | Write-Output | | -| try.ps1:167:13:167:25 | Write-Output | try.ps1:167:26:167:34 | Hello! | | -| try.ps1:167:13:167:34 | call to Write-Output | try.ps1:173:15:175:6 | {...} | | -| try.ps1:167:26:167:34 | Hello! | try.ps1:167:13:167:34 | call to Write-Output | | -| try.ps1:173:15:175:6 | {...} | try.ps1:174:9:174:21 | Write-Output | | -| try.ps1:174:9:174:21 | Write-Output | try.ps1:174:22:174:32 | Finally! | | -| try.ps1:174:9:174:32 | call to Write-Output | try.ps1:176:5:176:13 | return ... | | -| try.ps1:174:22:174:32 | Finally! | try.ps1:174:9:174:32 | call to Write-Output | | -| try.ps1:176:5:176:13 | return ... | try.ps1:176:12:176:13 | 1 | | -| try.ps1:176:12:176:13 | 1 | try.ps1:164:40:177:2 | exit {...} (normal) | | -| try.ps1:176:12:176:13 | 1 | try.ps1:176:12:176:13 | 1 | | -| try.ps1:179:1:194:2 | test-nested-try-inner-outer-finally | try.ps1:1:1:194:2 | exit try.ps1 (normal) | | -| try.ps1:179:46:194:2 | enter {...} | try.ps1:179:46:194:2 | {...} | | -| try.ps1:179:46:194:2 | exit {...} (normal) | try.ps1:179:46:194:2 | exit {...} | | -| try.ps1:179:46:194:2 | {...} | try.ps1:180:5:193:13 | {...} | | -| try.ps1:180:5:192:6 | try {...} | try.ps1:180:9:188:6 | {...} | | -| try.ps1:180:5:193:13 | {...} | try.ps1:180:5:192:6 | try {...} | | -| try.ps1:180:9:188:6 | {...} | try.ps1:181:9:187:10 | try {...} | | -| try.ps1:181:9:187:10 | try {...} | try.ps1:181:13:183:10 | {...} | | -| try.ps1:181:13:183:10 | {...} | try.ps1:182:13:182:25 | Write-Output | | -| try.ps1:182:13:182:25 | Write-Output | try.ps1:182:26:182:34 | Hello! | | -| try.ps1:182:13:182:34 | call to Write-Output | try.ps1:185:19:187:10 | {...} | | -| try.ps1:182:26:182:34 | Hello! | try.ps1:182:13:182:34 | call to Write-Output | | -| try.ps1:185:19:187:10 | {...} | try.ps1:186:13:186:25 | Write-Output | | -| try.ps1:186:13:186:25 | Write-Output | try.ps1:186:26:186:36 | Finally! | | -| try.ps1:186:13:186:36 | call to Write-Output | try.ps1:190:15:192:6 | {...} | | -| try.ps1:186:26:186:36 | Finally! | try.ps1:186:13:186:36 | call to Write-Output | | -| try.ps1:190:15:192:6 | {...} | try.ps1:191:9:191:21 | Write-Output | | -| try.ps1:191:9:191:21 | Write-Output | try.ps1:191:22:191:32 | Finally! | | -| try.ps1:191:9:191:32 | call to Write-Output | try.ps1:193:5:193:13 | return ... | | -| try.ps1:191:22:191:32 | Finally! | try.ps1:191:9:191:32 | call to Write-Output | | -| try.ps1:193:5:193:13 | return ... | try.ps1:193:12:193:13 | 1 | | -| try.ps1:193:12:193:13 | 1 | try.ps1:179:46:194:2 | exit {...} (normal) | | -| try.ps1:193:12:193:13 | 1 | try.ps1:193:12:193:13 | 1 | | +| conditionals.ps1:1:1:9:1 | def of test-if | conditionals.ps1:11:1:22:1 | def of test-if-else | | +| conditionals.ps1:1:1:129:1 | enter {...} | conditionals.ps1:1:1:129:1 | {...} | | +| conditionals.ps1:1:1:129:1 | exit {...} (normal) | conditionals.ps1:1:1:129:1 | exit {...} | | +| conditionals.ps1:1:1:129:1 | {...} | conditionals.ps1:1:1:9:1 | def of test-if | | +| conditionals.ps1:1:1:129:1 | {...} | conditionals.ps1:1:1:129:1 | {...} | | +| conditionals.ps1:1:18:9:1 | [synth] pipeline | conditionals.ps1:2:5:8:13 | {...} | | +| conditionals.ps1:1:18:9:1 | enter {...} | conditionals.ps1:1:18:9:1 | {...} | | +| conditionals.ps1:1:18:9:1 | exit {...} (normal) | conditionals.ps1:1:18:9:1 | exit {...} | | +| conditionals.ps1:1:18:9:1 | myBool | conditionals.ps1:1:18:9:1 | [synth] pipeline | | +| conditionals.ps1:1:18:9:1 | {...} | conditionals.ps1:1:18:9:1 | myBool | | +| conditionals.ps1:2:5:8:13 | {...} | conditionals.ps1:4:5:7:5 | [Stmt] if (...) {...} | | +| conditionals.ps1:4:5:7:5 | [Stmt] if (...) {...} | conditionals.ps1:4:8:4:14 | myBool | | +| conditionals.ps1:4:5:7:5 | if (...) {...} | conditionals.ps1:8:5:8:13 | return ... | | +| conditionals.ps1:4:8:4:14 | myBool | conditionals.ps1:4:5:7:5 | if (...) {...} | false | +| conditionals.ps1:4:8:4:14 | myBool | conditionals.ps1:5:5:7:5 | {...} | true | +| conditionals.ps1:5:5:7:5 | {...} | conditionals.ps1:6:9:6:17 | return ... | | +| conditionals.ps1:6:9:6:17 | return ... | conditionals.ps1:6:16:6:17 | 10 | | +| conditionals.ps1:6:16:6:17 | 10 | conditionals.ps1:4:5:7:5 | if (...) {...} | | +| conditionals.ps1:8:5:8:13 | return ... | conditionals.ps1:8:12:8:13 | 11 | | +| conditionals.ps1:8:12:8:13 | 11 | conditionals.ps1:1:18:9:1 | exit {...} (normal) | | +| conditionals.ps1:11:1:22:1 | def of test-if-else | conditionals.ps1:24:1:32:1 | def of test-if-conj | | +| conditionals.ps1:11:23:22:1 | [synth] pipeline | conditionals.ps1:12:5:21:5 | {...} | | +| conditionals.ps1:11:23:22:1 | enter {...} | conditionals.ps1:11:23:22:1 | {...} | | +| conditionals.ps1:11:23:22:1 | exit {...} (normal) | conditionals.ps1:11:23:22:1 | exit {...} | | +| conditionals.ps1:11:23:22:1 | myBool | conditionals.ps1:11:23:22:1 | [synth] pipeline | | +| conditionals.ps1:11:23:22:1 | {...} | conditionals.ps1:11:23:22:1 | myBool | | +| conditionals.ps1:12:5:21:5 | {...} | conditionals.ps1:14:5:21:5 | [Stmt] if (...) {...} else {...} | | +| conditionals.ps1:14:5:21:5 | [Stmt] if (...) {...} else {...} | conditionals.ps1:14:8:14:14 | myBool | | +| conditionals.ps1:14:5:21:5 | if (...) {...} else {...} | conditionals.ps1:11:23:22:1 | exit {...} (normal) | | +| conditionals.ps1:14:8:14:14 | myBool | conditionals.ps1:15:5:17:5 | {...} | true | +| conditionals.ps1:14:8:14:14 | myBool | conditionals.ps1:19:5:21:5 | {...} | false | +| conditionals.ps1:15:5:17:5 | {...} | conditionals.ps1:16:9:16:17 | return ... | | +| conditionals.ps1:16:9:16:17 | return ... | conditionals.ps1:16:16:16:17 | 10 | | +| conditionals.ps1:16:16:16:17 | 10 | conditionals.ps1:14:5:21:5 | if (...) {...} else {...} | | +| conditionals.ps1:19:5:21:5 | {...} | conditionals.ps1:20:9:20:17 | return ... | | +| conditionals.ps1:20:9:20:17 | return ... | conditionals.ps1:20:16:20:17 | 11 | | +| conditionals.ps1:20:16:20:17 | 11 | conditionals.ps1:14:5:21:5 | if (...) {...} else {...} | | +| conditionals.ps1:24:1:32:1 | def of test-if-conj | conditionals.ps1:34:1:45:1 | def of test-if-else-conj | | +| conditionals.ps1:24:23:32:1 | [synth] pipeline | conditionals.ps1:25:5:31:13 | {...} | | +| conditionals.ps1:24:23:32:1 | enter {...} | conditionals.ps1:24:23:32:1 | {...} | | +| conditionals.ps1:24:23:32:1 | exit {...} (normal) | conditionals.ps1:24:23:32:1 | exit {...} | | +| conditionals.ps1:24:23:32:1 | myBool1 | conditionals.ps1:24:23:32:1 | myBool2 | | +| conditionals.ps1:24:23:32:1 | myBool2 | conditionals.ps1:24:23:32:1 | [synth] pipeline | | +| conditionals.ps1:24:23:32:1 | {...} | conditionals.ps1:24:23:32:1 | myBool1 | | +| conditionals.ps1:25:5:31:13 | {...} | conditionals.ps1:27:5:30:5 | [Stmt] if (...) {...} | | +| conditionals.ps1:27:5:30:5 | [Stmt] if (...) {...} | conditionals.ps1:27:8:27:15 | myBool1 | | +| conditionals.ps1:27:5:30:5 | if (...) {...} | conditionals.ps1:31:5:31:13 | return ... | | +| conditionals.ps1:27:8:27:15 | myBool1 | conditionals.ps1:27:22:27:29 | myBool2 | false, true | +| conditionals.ps1:27:8:27:29 | [false] ... -and ... | conditionals.ps1:27:5:30:5 | if (...) {...} | false | +| conditionals.ps1:27:8:27:29 | [true] ... -and ... | conditionals.ps1:28:5:30:5 | {...} | true | +| conditionals.ps1:27:22:27:29 | myBool2 | conditionals.ps1:27:8:27:29 | [false] ... -and ... | false | +| conditionals.ps1:27:22:27:29 | myBool2 | conditionals.ps1:27:8:27:29 | [true] ... -and ... | true | +| conditionals.ps1:28:5:30:5 | {...} | conditionals.ps1:29:9:29:17 | return ... | | +| conditionals.ps1:29:9:29:17 | return ... | conditionals.ps1:29:16:29:17 | 10 | | +| conditionals.ps1:29:16:29:17 | 10 | conditionals.ps1:27:5:30:5 | if (...) {...} | | +| conditionals.ps1:31:5:31:13 | return ... | conditionals.ps1:31:12:31:13 | 11 | | +| conditionals.ps1:31:12:31:13 | 11 | conditionals.ps1:24:23:32:1 | exit {...} (normal) | | +| conditionals.ps1:34:1:45:1 | def of test-if-else-conj | conditionals.ps1:47:1:55:1 | def of test-if-disj | | +| conditionals.ps1:34:28:45:1 | [synth] pipeline | conditionals.ps1:35:5:44:5 | {...} | | +| conditionals.ps1:34:28:45:1 | enter {...} | conditionals.ps1:34:28:45:1 | {...} | | +| conditionals.ps1:34:28:45:1 | exit {...} (normal) | conditionals.ps1:34:28:45:1 | exit {...} | | +| conditionals.ps1:34:28:45:1 | myBool1 | conditionals.ps1:34:28:45:1 | myBool2 | | +| conditionals.ps1:34:28:45:1 | myBool2 | conditionals.ps1:34:28:45:1 | [synth] pipeline | | +| conditionals.ps1:34:28:45:1 | {...} | conditionals.ps1:34:28:45:1 | myBool1 | | +| conditionals.ps1:35:5:44:5 | {...} | conditionals.ps1:37:5:44:5 | [Stmt] if (...) {...} else {...} | | +| conditionals.ps1:37:5:44:5 | [Stmt] if (...) {...} else {...} | conditionals.ps1:37:8:37:15 | myBool1 | | +| conditionals.ps1:37:5:44:5 | if (...) {...} else {...} | conditionals.ps1:34:28:45:1 | exit {...} (normal) | | +| conditionals.ps1:37:8:37:15 | myBool1 | conditionals.ps1:37:22:37:29 | myBool2 | false, true | +| conditionals.ps1:37:8:37:29 | [false] ... -and ... | conditionals.ps1:42:5:44:5 | {...} | false | +| conditionals.ps1:37:8:37:29 | [true] ... -and ... | conditionals.ps1:38:5:40:5 | {...} | true | +| conditionals.ps1:37:22:37:29 | myBool2 | conditionals.ps1:37:8:37:29 | [false] ... -and ... | false | +| conditionals.ps1:37:22:37:29 | myBool2 | conditionals.ps1:37:8:37:29 | [true] ... -and ... | true | +| conditionals.ps1:38:5:40:5 | {...} | conditionals.ps1:39:9:39:17 | return ... | | +| conditionals.ps1:39:9:39:17 | return ... | conditionals.ps1:39:16:39:17 | 10 | | +| conditionals.ps1:39:16:39:17 | 10 | conditionals.ps1:37:5:44:5 | if (...) {...} else {...} | | +| conditionals.ps1:42:5:44:5 | {...} | conditionals.ps1:43:9:43:17 | return ... | | +| conditionals.ps1:43:9:43:17 | return ... | conditionals.ps1:43:16:43:17 | 11 | | +| conditionals.ps1:43:16:43:17 | 11 | conditionals.ps1:37:5:44:5 | if (...) {...} else {...} | | +| conditionals.ps1:47:1:55:1 | def of test-if-disj | conditionals.ps1:57:1:68:1 | def of test-if-else-disj | | +| conditionals.ps1:47:23:55:1 | [synth] pipeline | conditionals.ps1:48:5:54:13 | {...} | | +| conditionals.ps1:47:23:55:1 | enter {...} | conditionals.ps1:47:23:55:1 | {...} | | +| conditionals.ps1:47:23:55:1 | exit {...} (normal) | conditionals.ps1:47:23:55:1 | exit {...} | | +| conditionals.ps1:47:23:55:1 | myBool1 | conditionals.ps1:47:23:55:1 | myBool2 | | +| conditionals.ps1:47:23:55:1 | myBool2 | conditionals.ps1:47:23:55:1 | [synth] pipeline | | +| conditionals.ps1:47:23:55:1 | {...} | conditionals.ps1:47:23:55:1 | myBool1 | | +| conditionals.ps1:48:5:54:13 | {...} | conditionals.ps1:50:5:53:5 | [Stmt] if (...) {...} | | +| conditionals.ps1:50:5:53:5 | [Stmt] if (...) {...} | conditionals.ps1:50:8:50:15 | myBool1 | | +| conditionals.ps1:50:5:53:5 | if (...) {...} | conditionals.ps1:54:5:54:13 | return ... | | +| conditionals.ps1:50:8:50:15 | myBool1 | conditionals.ps1:50:21:50:28 | myBool2 | false, true | +| conditionals.ps1:50:8:50:28 | [false] ... -or ... | conditionals.ps1:50:5:53:5 | if (...) {...} | false | +| conditionals.ps1:50:8:50:28 | [true] ... -or ... | conditionals.ps1:51:5:53:5 | {...} | true | +| conditionals.ps1:50:21:50:28 | myBool2 | conditionals.ps1:50:8:50:28 | [false] ... -or ... | false | +| conditionals.ps1:50:21:50:28 | myBool2 | conditionals.ps1:50:8:50:28 | [true] ... -or ... | true | +| conditionals.ps1:51:5:53:5 | {...} | conditionals.ps1:52:9:52:17 | return ... | | +| conditionals.ps1:52:9:52:17 | return ... | conditionals.ps1:52:16:52:17 | 10 | | +| conditionals.ps1:52:16:52:17 | 10 | conditionals.ps1:50:5:53:5 | if (...) {...} | | +| conditionals.ps1:54:5:54:13 | return ... | conditionals.ps1:54:12:54:13 | 11 | | +| conditionals.ps1:54:12:54:13 | 11 | conditionals.ps1:47:23:55:1 | exit {...} (normal) | | +| conditionals.ps1:57:1:68:1 | def of test-if-else-disj | conditionals.ps1:70:1:82:1 | def of test-else-if | | +| conditionals.ps1:57:28:68:1 | [synth] pipeline | conditionals.ps1:58:5:67:5 | {...} | | +| conditionals.ps1:57:28:68:1 | enter {...} | conditionals.ps1:57:28:68:1 | {...} | | +| conditionals.ps1:57:28:68:1 | exit {...} (normal) | conditionals.ps1:57:28:68:1 | exit {...} | | +| conditionals.ps1:57:28:68:1 | myBool1 | conditionals.ps1:57:28:68:1 | myBool2 | | +| conditionals.ps1:57:28:68:1 | myBool2 | conditionals.ps1:57:28:68:1 | [synth] pipeline | | +| conditionals.ps1:57:28:68:1 | {...} | conditionals.ps1:57:28:68:1 | myBool1 | | +| conditionals.ps1:58:5:67:5 | {...} | conditionals.ps1:60:5:67:5 | [Stmt] if (...) {...} else {...} | | +| conditionals.ps1:60:5:67:5 | [Stmt] if (...) {...} else {...} | conditionals.ps1:60:8:60:15 | myBool1 | | +| conditionals.ps1:60:5:67:5 | if (...) {...} else {...} | conditionals.ps1:57:28:68:1 | exit {...} (normal) | | +| conditionals.ps1:60:8:60:15 | myBool1 | conditionals.ps1:60:21:60:28 | myBool2 | false, true | +| conditionals.ps1:60:8:60:28 | [false] ... -or ... | conditionals.ps1:65:5:67:5 | {...} | false | +| conditionals.ps1:60:8:60:28 | [true] ... -or ... | conditionals.ps1:61:5:63:5 | {...} | true | +| conditionals.ps1:60:21:60:28 | myBool2 | conditionals.ps1:60:8:60:28 | [false] ... -or ... | false | +| conditionals.ps1:60:21:60:28 | myBool2 | conditionals.ps1:60:8:60:28 | [true] ... -or ... | true | +| conditionals.ps1:61:5:63:5 | {...} | conditionals.ps1:62:9:62:17 | return ... | | +| conditionals.ps1:62:9:62:17 | return ... | conditionals.ps1:62:16:62:17 | 10 | | +| conditionals.ps1:62:16:62:17 | 10 | conditionals.ps1:60:5:67:5 | if (...) {...} else {...} | | +| conditionals.ps1:65:5:67:5 | {...} | conditionals.ps1:66:9:66:17 | return ... | | +| conditionals.ps1:66:9:66:17 | return ... | conditionals.ps1:66:16:66:17 | 11 | | +| conditionals.ps1:66:16:66:17 | 11 | conditionals.ps1:60:5:67:5 | if (...) {...} else {...} | | +| conditionals.ps1:70:1:82:1 | def of test-else-if | conditionals.ps1:84:1:99:1 | def of test-else-if-else | | +| conditionals.ps1:70:23:82:1 | [synth] pipeline | conditionals.ps1:71:5:81:13 | {...} | | +| conditionals.ps1:70:23:82:1 | enter {...} | conditionals.ps1:70:23:82:1 | {...} | | +| conditionals.ps1:70:23:82:1 | exit {...} (normal) | conditionals.ps1:70:23:82:1 | exit {...} | | +| conditionals.ps1:70:23:82:1 | myBool1 | conditionals.ps1:70:23:82:1 | myBool2 | | +| conditionals.ps1:70:23:82:1 | myBool2 | conditionals.ps1:70:23:82:1 | [synth] pipeline | | +| conditionals.ps1:70:23:82:1 | {...} | conditionals.ps1:70:23:82:1 | myBool1 | | +| conditionals.ps1:71:5:81:13 | {...} | conditionals.ps1:73:5:80:5 | [Stmt] if (...) {...} | | +| conditionals.ps1:73:5:80:5 | [Stmt] if (...) {...} | conditionals.ps1:73:8:73:15 | myBool1 | | +| conditionals.ps1:73:5:80:5 | if (...) {...} | conditionals.ps1:81:5:81:13 | return ... | | +| conditionals.ps1:73:8:73:15 | myBool1 | conditionals.ps1:73:5:80:5 | if (...) {...} | false | +| conditionals.ps1:73:8:73:15 | myBool1 | conditionals.ps1:74:5:76:5 | {...} | true | +| conditionals.ps1:74:5:76:5 | {...} | conditionals.ps1:75:9:75:17 | return ... | | +| conditionals.ps1:75:9:75:17 | return ... | conditionals.ps1:75:16:75:17 | 10 | | +| conditionals.ps1:75:16:75:17 | 10 | conditionals.ps1:73:5:80:5 | if (...) {...} | | +| conditionals.ps1:81:5:81:13 | return ... | conditionals.ps1:81:12:81:13 | 12 | | +| conditionals.ps1:81:12:81:13 | 12 | conditionals.ps1:70:23:82:1 | exit {...} (normal) | | +| conditionals.ps1:84:1:99:1 | def of test-else-if-else | conditionals.ps1:101:1:108:1 | def of test-switch | | +| conditionals.ps1:84:28:99:1 | [synth] pipeline | conditionals.ps1:85:5:98:5 | {...} | | +| conditionals.ps1:84:28:99:1 | enter {...} | conditionals.ps1:84:28:99:1 | {...} | | +| conditionals.ps1:84:28:99:1 | exit {...} (normal) | conditionals.ps1:84:28:99:1 | exit {...} | | +| conditionals.ps1:84:28:99:1 | myBool1 | conditionals.ps1:84:28:99:1 | myBool2 | | +| conditionals.ps1:84:28:99:1 | myBool2 | conditionals.ps1:84:28:99:1 | [synth] pipeline | | +| conditionals.ps1:84:28:99:1 | {...} | conditionals.ps1:84:28:99:1 | myBool1 | | +| conditionals.ps1:85:5:98:5 | {...} | conditionals.ps1:87:5:98:5 | [Stmt] if (...) {...} else {...} | | +| conditionals.ps1:87:5:98:5 | [Stmt] if (...) {...} else {...} | conditionals.ps1:87:8:87:15 | myBool1 | | +| conditionals.ps1:87:5:98:5 | if (...) {...} else {...} | conditionals.ps1:84:28:99:1 | exit {...} (normal) | | +| conditionals.ps1:87:8:87:15 | myBool1 | conditionals.ps1:88:5:90:5 | {...} | true | +| conditionals.ps1:87:8:87:15 | myBool1 | conditionals.ps1:96:5:98:5 | {...} | false | +| conditionals.ps1:88:5:90:5 | {...} | conditionals.ps1:89:9:89:17 | return ... | | +| conditionals.ps1:89:9:89:17 | return ... | conditionals.ps1:89:16:89:17 | 10 | | +| conditionals.ps1:89:16:89:17 | 10 | conditionals.ps1:87:5:98:5 | if (...) {...} else {...} | | +| conditionals.ps1:96:5:98:5 | {...} | conditionals.ps1:97:9:97:17 | return ... | | +| conditionals.ps1:97:9:97:17 | return ... | conditionals.ps1:97:16:97:17 | 12 | | +| conditionals.ps1:97:16:97:17 | 12 | conditionals.ps1:87:5:98:5 | if (...) {...} else {...} | | +| conditionals.ps1:101:1:108:1 | def of test-switch | conditionals.ps1:110:1:121:1 | def of test-switch-default | | +| conditionals.ps1:101:26:108:1 | enter {...} | conditionals.ps1:101:26:108:1 | {...} | | +| conditionals.ps1:101:26:108:1 | exit {...} (normal) | conditionals.ps1:101:26:108:1 | exit {...} | | +| conditionals.ps1:101:26:108:1 | n | conditionals.ps1:102:5:107:5 | {...} | | +| conditionals.ps1:101:26:108:1 | {...} | conditionals.ps1:101:26:108:1 | n | | +| conditionals.ps1:102:5:107:5 | switch(...) {...} | conditionals.ps1:102:12:102:13 | n | | +| conditionals.ps1:102:5:107:5 | {...} | conditionals.ps1:102:5:107:5 | switch(...) {...} | | +| conditionals.ps1:102:12:102:13 | n | conditionals.ps1:104:9:104:10 | 0: | | +| conditionals.ps1:104:9:104:10 | 0: | conditionals.ps1:104:12:104:24 | {...} | true | +| conditionals.ps1:104:9:104:10 | 0: | conditionals.ps1:105:9:105:10 | 1: | false | +| conditionals.ps1:104:12:104:24 | {...} | conditionals.ps1:104:14:104:21 | return ... | | +| conditionals.ps1:104:14:104:21 | return ... | conditionals.ps1:104:21:104:21 | 0 | | +| conditionals.ps1:104:21:104:21 | 0 | conditionals.ps1:101:26:108:1 | exit {...} (normal) | | +| conditionals.ps1:105:9:105:10 | 1: | conditionals.ps1:105:12:105:24 | {...} | true | +| conditionals.ps1:105:9:105:10 | 1: | conditionals.ps1:106:9:106:10 | 2: | false | +| conditionals.ps1:105:12:105:24 | {...} | conditionals.ps1:105:14:105:21 | return ... | | +| conditionals.ps1:105:14:105:21 | return ... | conditionals.ps1:105:21:105:21 | 1 | | +| conditionals.ps1:105:21:105:21 | 1 | conditionals.ps1:101:26:108:1 | exit {...} (normal) | | +| conditionals.ps1:106:9:106:10 | 2: | conditionals.ps1:101:26:108:1 | exit {...} (normal) | false | +| conditionals.ps1:106:9:106:10 | 2: | conditionals.ps1:106:12:106:24 | {...} | true | +| conditionals.ps1:106:12:106:24 | {...} | conditionals.ps1:106:14:106:21 | return ... | | +| conditionals.ps1:106:14:106:21 | return ... | conditionals.ps1:106:21:106:21 | 2 | | +| conditionals.ps1:106:21:106:21 | 2 | conditionals.ps1:101:26:108:1 | exit {...} (normal) | | +| conditionals.ps1:110:1:121:1 | def of test-switch-default | conditionals.ps1:123:1:129:1 | def of test-switch-assign | | +| conditionals.ps1:110:34:121:1 | enter {...} | conditionals.ps1:110:34:121:1 | {...} | | +| conditionals.ps1:110:34:121:1 | exit {...} (normal) | conditionals.ps1:110:34:121:1 | exit {...} | | +| conditionals.ps1:110:34:121:1 | n | conditionals.ps1:111:5:120:5 | {...} | | +| conditionals.ps1:110:34:121:1 | {...} | conditionals.ps1:110:34:121:1 | n | | +| conditionals.ps1:111:5:120:5 | switch(...) {...} | conditionals.ps1:111:12:111:13 | n | | +| conditionals.ps1:111:5:120:5 | {...} | conditionals.ps1:111:5:120:5 | switch(...) {...} | | +| conditionals.ps1:111:12:111:13 | n | conditionals.ps1:113:9:113:10 | 0: | | +| conditionals.ps1:113:9:113:10 | 0: | conditionals.ps1:113:12:113:24 | {...} | true | +| conditionals.ps1:113:9:113:10 | 0: | conditionals.ps1:114:9:114:10 | 1: | false | +| conditionals.ps1:113:12:113:24 | {...} | conditionals.ps1:113:14:113:21 | return ... | | +| conditionals.ps1:113:14:113:21 | return ... | conditionals.ps1:113:21:113:21 | 0 | | +| conditionals.ps1:113:21:113:21 | 0 | conditionals.ps1:110:34:121:1 | exit {...} (normal) | | +| conditionals.ps1:114:9:114:10 | 1: | conditionals.ps1:114:12:114:24 | {...} | true | +| conditionals.ps1:114:9:114:10 | 1: | conditionals.ps1:115:9:115:10 | 2: | false | +| conditionals.ps1:114:12:114:24 | {...} | conditionals.ps1:114:14:114:21 | return ... | | +| conditionals.ps1:114:14:114:21 | return ... | conditionals.ps1:114:21:114:21 | 1 | | +| conditionals.ps1:114:21:114:21 | 1 | conditionals.ps1:110:34:121:1 | exit {...} (normal) | | +| conditionals.ps1:115:9:115:10 | 2: | conditionals.ps1:115:12:115:24 | {...} | true | +| conditionals.ps1:115:9:115:10 | 2: | conditionals.ps1:116:9:116:16 | default: | false | +| conditionals.ps1:115:12:115:24 | {...} | conditionals.ps1:115:14:115:21 | return ... | | +| conditionals.ps1:115:14:115:21 | return ... | conditionals.ps1:115:21:115:21 | 2 | | +| conditionals.ps1:115:21:115:21 | 2 | conditionals.ps1:110:34:121:1 | exit {...} (normal) | | +| conditionals.ps1:116:9:116:16 | default: | conditionals.ps1:110:34:121:1 | exit {...} (normal) | false | +| conditionals.ps1:116:9:116:16 | default: | conditionals.ps1:116:18:119:9 | {...} | true | +| conditionals.ps1:116:18:119:9 | {...} | conditionals.ps1:117:13:117:33 | [Stmt] Call to Write-Output | | +| conditionals.ps1:117:13:117:24 | Write-Output | conditionals.ps1:117:26:117:33 | Error! | | +| conditionals.ps1:117:13:117:33 | Call to Write-Output | conditionals.ps1:118:13:118:20 | return ... | | +| conditionals.ps1:117:13:117:33 | [Stmt] Call to Write-Output | conditionals.ps1:117:13:117:24 | Write-Output | | +| conditionals.ps1:117:26:117:33 | Error! | conditionals.ps1:117:13:117:33 | Call to Write-Output | | +| conditionals.ps1:118:13:118:20 | return ... | conditionals.ps1:118:20:118:20 | 3 | | +| conditionals.ps1:118:20:118:20 | 3 | conditionals.ps1:110:34:121:1 | exit {...} (normal) | | +| conditionals.ps1:123:1:129:1 | def of test-switch-assign | conditionals.ps1:1:1:129:1 | exit {...} (normal) | | +| conditionals.ps1:123:33:129:1 | enter {...} | conditionals.ps1:123:33:129:1 | {...} | | +| conditionals.ps1:123:33:129:1 | exit {...} (normal) | conditionals.ps1:123:33:129:1 | exit {...} | | +| conditionals.ps1:123:33:129:1 | n | conditionals.ps1:124:5:128:5 | {...} | | +| conditionals.ps1:123:33:129:1 | {...} | conditionals.ps1:123:33:129:1 | n | | +| conditionals.ps1:124:5:124:6 | a | conditionals.ps1:123:33:129:1 | exit {...} (normal) | | +| conditionals.ps1:124:5:128:5 | ...=... | conditionals.ps1:124:5:124:6 | a | | +| conditionals.ps1:124:5:128:5 | {...} | conditionals.ps1:124:5:128:5 | ...=... | | +| functions.ps1:1:1:9:1 | def of Add-Numbers-Arguments | functions.ps1:11:1:11:28 | def of foo | | +| functions.ps1:1:1:52:1 | {...} | functions.ps1:1:1:9:1 | def of Add-Numbers-Arguments | | +| functions.ps1:1:1:54:0 | enter {...} | functions.ps1:1:1:54:0 | {...} | | +| functions.ps1:1:1:54:0 | exit {...} (normal) | functions.ps1:1:1:54:0 | exit {...} | | +| functions.ps1:1:1:54:0 | {...} | functions.ps1:1:1:52:1 | {...} | | +| functions.ps1:1:32:9:1 | [synth] pipeline | functions.ps1:3:5:8:23 | {...} | | +| functions.ps1:1:32:9:1 | enter {...} | functions.ps1:1:32:9:1 | {...} | | +| functions.ps1:1:32:9:1 | exit {...} (normal) | functions.ps1:1:32:9:1 | exit {...} | | +| functions.ps1:1:32:9:1 | number1 | functions.ps1:1:32:9:1 | number2 | | +| functions.ps1:1:32:9:1 | number2 | functions.ps1:1:32:9:1 | [synth] pipeline | | +| functions.ps1:1:32:9:1 | {...} | functions.ps1:1:32:9:1 | number1 | | +| functions.ps1:3:5:8:23 | {...} | functions.ps1:8:5:8:23 | [Stmt] ...+... | | +| functions.ps1:3:5:8:23 | {...} | functions.ps1:8:5:8:23 | [Stmt] __pipeline_iterator | | +| functions.ps1:8:5:8:12 | number1 | functions.ps1:8:16:8:23 | number2 | | +| functions.ps1:8:5:8:23 | ...+... | functions.ps1:1:32:9:1 | exit {...} (normal) | | +| functions.ps1:8:5:8:23 | [Stmt] ...+... | functions.ps1:8:5:8:12 | number1 | | +| functions.ps1:8:5:8:23 | [Stmt] ...+... | functions.ps1:46:17:46:18 | __pipeline_iterator | | +| functions.ps1:8:5:8:23 | [Stmt] __pipeline_iterator | functions.ps1:8:5:8:12 | number1 | | +| functions.ps1:8:5:8:23 | [Stmt] __pipeline_iterator | functions.ps1:46:17:46:18 | __pipeline_iterator | | +| functions.ps1:8:16:8:23 | number2 | functions.ps1:8:5:8:23 | ...+... | | +| functions.ps1:11:1:11:28 | def of foo | functions.ps1:13:1:20:1 | def of Default-Arguments | | +| functions.ps1:11:16:11:28 | [synth] pipeline | functions.ps1:11:18:11:26 | {...} | | +| functions.ps1:11:16:11:28 | a | functions.ps1:11:16:11:28 | [synth] pipeline | | +| functions.ps1:11:16:11:28 | enter {...} | functions.ps1:11:16:11:28 | {...} | | +| functions.ps1:11:16:11:28 | exit {...} (normal) | functions.ps1:11:16:11:28 | exit {...} | | +| functions.ps1:11:16:11:28 | {...} | functions.ps1:11:16:11:28 | a | | +| functions.ps1:11:18:11:26 | {...} | functions.ps1:11:16:11:28 | exit {...} (normal) | | +| functions.ps1:13:1:20:1 | def of Default-Arguments | functions.ps1:22:1:34:1 | def of Add-Numbers-From-Array | | +| functions.ps1:13:28:20:1 | [synth] pipeline | functions.ps1:14:5:19:18 | {...} | | +| functions.ps1:13:28:20:1 | enter {...} | functions.ps1:13:28:20:1 | {...} | | +| functions.ps1:13:28:20:1 | exit {...} (normal) | functions.ps1:13:28:20:1 | exit {...} | | +| functions.ps1:13:28:20:1 | name0 | functions.ps1:13:28:20:1 | name1 | | +| functions.ps1:13:28:20:1 | name1 | functions.ps1:16:24:16:24 | 0 | | +| functions.ps1:13:28:20:1 | name2 | functions.ps1:17:24:17:29 | name1 | | +| functions.ps1:13:28:20:1 | {...} | functions.ps1:16:24:16:24 | 0 | | +| functions.ps1:14:5:19:18 | {...} | functions.ps1:19:5:19:18 | [Stmt] ...+... | | +| functions.ps1:14:5:19:18 | {...} | functions.ps1:19:5:19:18 | [Stmt] __pipeline_iterator | | +| functions.ps1:16:24:16:24 | 0 | functions.ps1:13:28:20:1 | name2 | | +| functions.ps1:16:24:16:24 | 0 | functions.ps1:17:24:17:29 | name1 | | +| functions.ps1:17:24:17:29 | name1 | functions.ps1:17:33:17:33 | 1 | | +| functions.ps1:17:24:17:33 | ...+... | functions.ps1:13:28:20:1 | [synth] pipeline | | +| functions.ps1:17:24:17:33 | ...+... | functions.ps1:13:28:20:1 | name0 | | +| functions.ps1:17:33:17:33 | 1 | functions.ps1:17:24:17:33 | ...+... | | +| functions.ps1:19:5:19:18 | ...+... | functions.ps1:13:28:20:1 | exit {...} (normal) | | +| functions.ps1:19:5:19:18 | [Stmt] ...+... | functions.ps1:19:13:19:18 | name2 | | +| functions.ps1:19:5:19:18 | [Stmt] ...+... | functions.ps1:46:17:46:18 | __pipeline_iterator | | +| functions.ps1:19:5:19:18 | [Stmt] __pipeline_iterator | functions.ps1:19:13:19:18 | name2 | | +| functions.ps1:19:5:19:18 | [Stmt] __pipeline_iterator | functions.ps1:46:17:46:18 | __pipeline_iterator | | +| functions.ps1:19:13:19:18 | name2 | functions.ps1:19:5:19:18 | ...+... | | +| functions.ps1:22:1:34:1 | def of Add-Numbers-From-Array | functions.ps1:36:1:52:1 | def of Add-Numbers-From-Pipeline | | +| functions.ps1:22:33:34:1 | [synth] pipeline | functions.ps1:24:5:33:8 | {...} | | +| functions.ps1:22:33:34:1 | enter {...} | functions.ps1:22:33:34:1 | {...} | | +| functions.ps1:22:33:34:1 | exit {...} (normal) | functions.ps1:22:33:34:1 | exit {...} | | +| functions.ps1:22:33:34:1 | numbers | functions.ps1:22:33:34:1 | [synth] pipeline | | +| functions.ps1:22:33:34:1 | {...} | functions.ps1:22:33:34:1 | numbers | | +| functions.ps1:24:5:33:8 | {...} | functions.ps1:28:5:28:12 | ...=... | | +| functions.ps1:28:5:28:8 | sum | functions.ps1:28:12:28:12 | 0 | | +| functions.ps1:28:5:28:12 | ...=... | functions.ps1:28:5:28:8 | sum | | +| functions.ps1:28:12:28:12 | 0 | functions.ps1:29:25:29:32 | numbers | | +| functions.ps1:29:5:32:5 | forach(... in ...) | functions.ps1:33:5:33:8 | [Stmt] __pipeline_iterator | empty | +| functions.ps1:29:5:32:5 | forach(... in ...) | functions.ps1:33:5:33:8 | [Stmt] sum | empty | +| functions.ps1:29:25:29:32 | numbers | functions.ps1:29:5:32:5 | forach(... in ...) | | +| functions.ps1:33:5:33:8 | [Stmt] __pipeline_iterator | functions.ps1:33:5:33:8 | sum | | +| functions.ps1:33:5:33:8 | [Stmt] __pipeline_iterator | functions.ps1:46:17:46:18 | __pipeline_iterator | | +| functions.ps1:33:5:33:8 | [Stmt] sum | functions.ps1:33:5:33:8 | sum | | +| functions.ps1:33:5:33:8 | [Stmt] sum | functions.ps1:46:17:46:18 | __pipeline_iterator | | +| functions.ps1:33:5:33:8 | sum | functions.ps1:22:33:34:1 | exit {...} (normal) | | +| functions.ps1:36:1:52:1 | def of Add-Numbers-From-Pipeline | functions.ps1:1:1:54:0 | exit {...} (normal) | | +| functions.ps1:36:36:52:1 | [synth] pipeline | functions.ps1:41:5:43:5 | {...} | | +| functions.ps1:36:36:52:1 | enter {...} | functions.ps1:36:36:52:1 | {...} | | +| functions.ps1:36:36:52:1 | exit {...} (normal) | functions.ps1:36:36:52:1 | exit {...} | | +| functions.ps1:36:36:52:1 | numbers | functions.ps1:36:36:52:1 | [synth] pipeline | | +| functions.ps1:36:36:52:1 | {...} | functions.ps1:36:36:52:1 | numbers | | +| functions.ps1:41:5:43:5 | {...} | functions.ps1:42:9:42:16 | ...=... | | +| functions.ps1:42:9:42:12 | sum | functions.ps1:42:16:42:16 | 0 | | +| functions.ps1:42:9:42:16 | ...=... | functions.ps1:42:9:42:12 | sum | | +| functions.ps1:42:16:42:16 | 0 | functions.ps1:44:5:47:5 | {...} | | +| functions.ps1:44:5:47:5 | {...} | functions.ps1:46:9:46:18 | ...=... | | +| functions.ps1:46:9:46:12 | sum | functions.ps1:44:5:47:5 | {...} | | +| functions.ps1:46:9:46:12 | sum | functions.ps1:48:5:51:5 | {...} | | +| functions.ps1:46:9:46:18 | ...=... | functions.ps1:46:9:46:12 | sum | | +| functions.ps1:46:17:46:18 | __pipeline_iterator | functions.ps1:1:32:9:1 | exit {...} (normal) | | +| functions.ps1:46:17:46:18 | __pipeline_iterator | functions.ps1:13:28:20:1 | exit {...} (normal) | | +| functions.ps1:46:17:46:18 | __pipeline_iterator | functions.ps1:22:33:34:1 | exit {...} (normal) | | +| functions.ps1:46:17:46:18 | __pipeline_iterator | functions.ps1:36:36:52:1 | exit {...} (normal) | | +| functions.ps1:48:5:51:5 | {...} | functions.ps1:50:9:50:12 | [Stmt] __pipeline_iterator | | +| functions.ps1:48:5:51:5 | {...} | functions.ps1:50:9:50:12 | [Stmt] sum | | +| functions.ps1:50:9:50:12 | [Stmt] __pipeline_iterator | functions.ps1:46:17:46:18 | __pipeline_iterator | | +| functions.ps1:50:9:50:12 | [Stmt] __pipeline_iterator | functions.ps1:50:9:50:12 | sum | | +| functions.ps1:50:9:50:12 | [Stmt] sum | functions.ps1:46:17:46:18 | __pipeline_iterator | | +| functions.ps1:50:9:50:12 | [Stmt] sum | functions.ps1:50:9:50:12 | sum | | +| functions.ps1:50:9:50:12 | sum | functions.ps1:36:36:52:1 | exit {...} (normal) | | +| global.ps1:1:1:4:1 | {...} | global.ps1:2:5:2:10 | ...=... | | +| global.ps1:1:1:7:1 | enter {...} | global.ps1:1:1:7:1 | {...} | | +| global.ps1:1:1:7:1 | exit {...} (normal) | global.ps1:1:1:7:1 | exit {...} | | +| global.ps1:1:1:7:1 | {...} | global.ps1:1:1:4:1 | {...} | | +| global.ps1:2:5:2:6 | a | global.ps1:2:10:2:10 | 1 | | +| global.ps1:2:5:2:10 | ...=... | global.ps1:2:5:2:6 | a | | +| global.ps1:2:10:2:10 | 1 | global.ps1:3:5:3:10 | ...=... | | +| global.ps1:3:5:3:6 | b | global.ps1:3:10:3:10 | 2 | | +| global.ps1:3:5:3:10 | ...=... | global.ps1:3:5:3:6 | b | | +| global.ps1:3:10:3:10 | 2 | global.ps1:5:1:7:1 | {...} | | +| global.ps1:5:1:7:1 | {...} | global.ps1:6:5:6:16 | ...=... | | +| global.ps1:6:5:6:6 | c | global.ps1:6:10:6:11 | a | | +| global.ps1:6:5:6:16 | ...=... | global.ps1:6:5:6:6 | c | | +| global.ps1:6:10:6:11 | a | global.ps1:6:15:6:16 | b | | +| global.ps1:6:10:6:16 | ...+... | global.ps1:1:1:7:1 | exit {...} (normal) | | +| global.ps1:6:15:6:16 | b | global.ps1:6:10:6:16 | ...+... | | +| loops.ps1:1:1:7:1 | def of Test-While | loops.ps1:9:1:15:1 | def of Test-Break | | +| loops.ps1:1:1:68:1 | {...} | loops.ps1:1:1:7:1 | def of Test-While | | +| loops.ps1:1:1:70:0 | enter {...} | loops.ps1:1:1:70:0 | {...} | | +| loops.ps1:1:1:70:0 | exit {...} (normal) | loops.ps1:1:1:70:0 | exit {...} | | +| loops.ps1:1:1:70:0 | {...} | loops.ps1:1:1:68:1 | {...} | | +| loops.ps1:1:21:7:1 | enter {...} | loops.ps1:1:21:7:1 | {...} | | +| loops.ps1:1:21:7:1 | exit {...} (normal) | loops.ps1:1:21:7:1 | exit {...} | | +| loops.ps1:1:21:7:1 | {...} | loops.ps1:2:5:6:5 | {...} | | +| loops.ps1:2:5:2:6 | a | loops.ps1:2:10:2:10 | 0 | | +| loops.ps1:2:5:2:10 | ...=... | loops.ps1:2:5:2:6 | a | | +| loops.ps1:2:5:6:5 | {...} | loops.ps1:2:5:2:10 | ...=... | | +| loops.ps1:2:10:2:10 | 0 | loops.ps1:4:5:6:5 | while(...) {...} | | +| loops.ps1:4:5:6:5 | while(...) {...} | loops.ps1:4:11:4:12 | a | | +| loops.ps1:4:11:4:12 | a | loops.ps1:4:18:4:19 | 10 | | +| loops.ps1:4:11:4:19 | ... -le ... | loops.ps1:1:21:7:1 | exit {...} (normal) | false | +| loops.ps1:4:11:4:19 | ... -le ... | loops.ps1:4:22:6:5 | {...} | true | +| loops.ps1:4:18:4:19 | 10 | loops.ps1:4:11:4:19 | ... -le ... | | +| loops.ps1:4:22:6:5 | {...} | loops.ps1:5:9:5:19 | ...=... | | +| loops.ps1:5:9:5:10 | a | loops.ps1:5:14:5:15 | a | | +| loops.ps1:5:9:5:19 | ...=... | loops.ps1:5:9:5:10 | a | | +| loops.ps1:5:14:5:15 | a | loops.ps1:5:19:5:19 | 1 | | +| loops.ps1:5:14:5:19 | ...+... | loops.ps1:4:11:4:12 | a | | +| loops.ps1:5:19:5:19 | 1 | loops.ps1:5:14:5:19 | ...+... | | +| loops.ps1:9:1:15:1 | def of Test-Break | loops.ps1:17:1:23:1 | def of Test-Continue | | +| loops.ps1:9:21:15:1 | enter {...} | loops.ps1:9:21:15:1 | {...} | | +| loops.ps1:9:21:15:1 | exit {...} (normal) | loops.ps1:9:21:15:1 | exit {...} | | +| loops.ps1:9:21:15:1 | {...} | loops.ps1:10:5:14:5 | {...} | | +| loops.ps1:10:5:10:6 | a | loops.ps1:10:10:10:10 | 0 | | +| loops.ps1:10:5:10:10 | ...=... | loops.ps1:10:5:10:6 | a | | +| loops.ps1:10:5:14:5 | {...} | loops.ps1:10:5:10:10 | ...=... | | +| loops.ps1:10:10:10:10 | 0 | loops.ps1:11:5:14:5 | while(...) {...} | | +| loops.ps1:11:5:14:5 | while(...) {...} | loops.ps1:11:11:11:12 | a | | +| loops.ps1:11:11:11:12 | a | loops.ps1:11:18:11:19 | 10 | | +| loops.ps1:11:11:11:19 | ... -le ... | loops.ps1:9:21:15:1 | exit {...} (normal) | false | +| loops.ps1:11:11:11:19 | ... -le ... | loops.ps1:11:22:14:5 | {...} | true | +| loops.ps1:11:18:11:19 | 10 | loops.ps1:11:11:11:19 | ... -le ... | | +| loops.ps1:11:22:14:5 | {...} | loops.ps1:12:9:12:13 | break | | +| loops.ps1:12:9:12:13 | break | loops.ps1:9:21:15:1 | exit {...} (normal) | break | +| loops.ps1:17:1:23:1 | def of Test-Continue | loops.ps1:25:1:31:1 | def of Test-DoWhile | | +| loops.ps1:17:24:23:1 | enter {...} | loops.ps1:17:24:23:1 | {...} | | +| loops.ps1:17:24:23:1 | exit {...} (normal) | loops.ps1:17:24:23:1 | exit {...} | | +| loops.ps1:17:24:23:1 | {...} | loops.ps1:18:5:22:5 | {...} | | +| loops.ps1:18:5:18:6 | a | loops.ps1:18:10:18:10 | 0 | | +| loops.ps1:18:5:18:10 | ...=... | loops.ps1:18:5:18:6 | a | | +| loops.ps1:18:5:22:5 | {...} | loops.ps1:18:5:18:10 | ...=... | | +| loops.ps1:18:10:18:10 | 0 | loops.ps1:19:5:22:5 | while(...) {...} | | +| loops.ps1:19:5:22:5 | while(...) {...} | loops.ps1:19:11:19:12 | a | | +| loops.ps1:19:11:19:12 | a | loops.ps1:19:18:19:19 | 10 | | +| loops.ps1:19:11:19:19 | ... -le ... | loops.ps1:17:24:23:1 | exit {...} (normal) | false | +| loops.ps1:19:11:19:19 | ... -le ... | loops.ps1:19:22:22:5 | {...} | true | +| loops.ps1:19:18:19:19 | 10 | loops.ps1:19:11:19:19 | ... -le ... | | +| loops.ps1:19:22:22:5 | {...} | loops.ps1:20:9:20:16 | continue | | +| loops.ps1:20:9:20:16 | continue | loops.ps1:19:11:19:12 | a | continue | +| loops.ps1:25:1:31:1 | def of Test-DoWhile | loops.ps1:33:1:39:1 | def of Test-DoUntil | | +| loops.ps1:25:23:31:1 | enter {...} | loops.ps1:25:23:31:1 | {...} | | +| loops.ps1:25:23:31:1 | exit {...} (normal) | loops.ps1:25:23:31:1 | exit {...} | | +| loops.ps1:25:23:31:1 | {...} | loops.ps1:26:5:30:23 | {...} | | +| loops.ps1:26:5:26:6 | a | loops.ps1:26:10:26:10 | 0 | | +| loops.ps1:26:5:26:10 | ...=... | loops.ps1:26:5:26:6 | a | | +| loops.ps1:26:5:30:23 | {...} | loops.ps1:26:5:26:10 | ...=... | | +| loops.ps1:26:10:26:10 | 0 | loops.ps1:28:5:30:23 | do...while... | | +| loops.ps1:28:5:30:23 | do...while... | loops.ps1:28:8:30:5 | {...} | | +| loops.ps1:28:8:30:5 | {...} | loops.ps1:29:9:29:19 | ...=... | | +| loops.ps1:29:9:29:10 | a | loops.ps1:29:14:29:15 | a | | +| loops.ps1:29:9:29:19 | ...=... | loops.ps1:29:9:29:10 | a | | +| loops.ps1:29:14:29:15 | a | loops.ps1:29:19:29:19 | 1 | | +| loops.ps1:29:14:29:19 | ...+... | loops.ps1:30:14:30:15 | a | | +| loops.ps1:29:19:29:19 | 1 | loops.ps1:29:14:29:19 | ...+... | | +| loops.ps1:30:14:30:15 | a | loops.ps1:30:21:30:22 | 10 | | +| loops.ps1:30:14:30:22 | ... -le ... | loops.ps1:25:23:31:1 | exit {...} (normal) | false | +| loops.ps1:30:14:30:22 | ... -le ... | loops.ps1:28:8:30:5 | {...} | true | +| loops.ps1:30:21:30:22 | 10 | loops.ps1:30:14:30:22 | ... -le ... | | +| loops.ps1:33:1:39:1 | def of Test-DoUntil | loops.ps1:41:1:47:1 | def of Test-For | | +| loops.ps1:33:23:39:1 | enter {...} | loops.ps1:33:23:39:1 | {...} | | +| loops.ps1:33:23:39:1 | exit {...} (normal) | loops.ps1:33:23:39:1 | exit {...} | | +| loops.ps1:33:23:39:1 | {...} | loops.ps1:34:5:38:23 | {...} | | +| loops.ps1:34:5:34:6 | a | loops.ps1:34:10:34:10 | 0 | | +| loops.ps1:34:5:34:10 | ...=... | loops.ps1:34:5:34:6 | a | | +| loops.ps1:34:5:38:23 | {...} | loops.ps1:34:5:34:10 | ...=... | | +| loops.ps1:34:10:34:10 | 0 | loops.ps1:36:5:38:23 | do...until... | | +| loops.ps1:36:5:38:23 | do...until... | loops.ps1:36:8:38:5 | {...} | | +| loops.ps1:36:8:38:5 | {...} | loops.ps1:37:9:37:19 | ...=... | | +| loops.ps1:37:9:37:10 | a | loops.ps1:37:14:37:15 | a | | +| loops.ps1:37:9:37:19 | ...=... | loops.ps1:37:9:37:10 | a | | +| loops.ps1:37:14:37:15 | a | loops.ps1:37:19:37:19 | 1 | | +| loops.ps1:37:14:37:19 | ...+... | loops.ps1:38:14:38:15 | a | | +| loops.ps1:37:19:37:19 | 1 | loops.ps1:37:14:37:19 | ...+... | | +| loops.ps1:38:14:38:15 | a | loops.ps1:38:21:38:22 | 10 | | +| loops.ps1:38:14:38:22 | ... -ge ... | loops.ps1:33:23:39:1 | exit {...} (normal) | true | +| loops.ps1:38:14:38:22 | ... -ge ... | loops.ps1:36:8:38:5 | {...} | false | +| loops.ps1:38:21:38:22 | 10 | loops.ps1:38:14:38:22 | ... -ge ... | | +| loops.ps1:41:1:47:1 | def of Test-For | loops.ps1:49:1:56:1 | def of Test-ForEach | | +| loops.ps1:41:19:47:1 | enter {...} | loops.ps1:41:19:47:1 | {...} | | +| loops.ps1:41:19:47:1 | exit {...} (normal) | loops.ps1:41:19:47:1 | exit {...} | | +| loops.ps1:41:19:47:1 | {...} | loops.ps1:42:5:46:5 | {...} | | +| loops.ps1:42:5:42:6 | a | loops.ps1:42:10:42:10 | 0 | | +| loops.ps1:42:5:42:10 | ...=... | loops.ps1:42:5:42:6 | a | | +| loops.ps1:42:5:46:5 | {...} | loops.ps1:42:5:42:10 | ...=... | | +| loops.ps1:42:10:42:10 | 0 | loops.ps1:44:5:46:5 | for(...;...;...) | | +| loops.ps1:44:5:46:5 | for(...;...;...) | loops.ps1:44:10:44:15 | ...=... | | +| loops.ps1:44:10:44:11 | i | loops.ps1:44:15:44:15 | 0 | | +| loops.ps1:44:10:44:15 | ...=... | loops.ps1:44:10:44:11 | i | | +| loops.ps1:44:15:44:15 | 0 | loops.ps1:44:18:44:19 | i | | +| loops.ps1:44:18:44:19 | i | loops.ps1:44:25:44:26 | 10 | | +| loops.ps1:44:18:44:26 | ... -le ... | loops.ps1:41:19:47:1 | exit {...} (normal) | false | +| loops.ps1:44:18:44:26 | ... -le ... | loops.ps1:44:42:46:5 | {...} | true | +| loops.ps1:44:25:44:26 | 10 | loops.ps1:44:18:44:26 | ... -le ... | | +| loops.ps1:44:29:44:30 | i | loops.ps1:44:34:44:35 | i | | +| loops.ps1:44:29:44:39 | ...=... | loops.ps1:44:29:44:30 | i | | +| loops.ps1:44:34:44:35 | i | loops.ps1:44:39:44:39 | 1 | | +| loops.ps1:44:34:44:39 | ...+... | loops.ps1:44:18:44:19 | i | | +| loops.ps1:44:39:44:39 | 1 | loops.ps1:44:34:44:39 | ...+... | | +| loops.ps1:44:42:46:5 | {...} | loops.ps1:45:9:45:19 | ...=... | | +| loops.ps1:45:9:45:10 | a | loops.ps1:45:14:45:15 | a | | +| loops.ps1:45:9:45:19 | ...=... | loops.ps1:45:9:45:10 | a | | +| loops.ps1:45:14:45:15 | a | loops.ps1:45:19:45:19 | 1 | | +| loops.ps1:45:14:45:19 | ...+... | loops.ps1:44:18:44:19 | i | | +| loops.ps1:45:14:45:19 | ...+... | loops.ps1:44:29:44:39 | ...=... | | +| loops.ps1:45:19:45:19 | 1 | loops.ps1:45:14:45:19 | ...+... | | +| loops.ps1:49:1:56:1 | def of Test-ForEach | loops.ps1:58:1:68:1 | def of Test-For-Ever | | +| loops.ps1:49:23:56:1 | enter {...} | loops.ps1:49:23:56:1 | {...} | | +| loops.ps1:49:23:56:1 | exit {...} (normal) | loops.ps1:49:23:56:1 | exit {...} | | +| loops.ps1:49:23:56:1 | {...} | loops.ps1:50:5:55:5 | {...} | | +| loops.ps1:50:5:50:16 | letterArray | loops.ps1:50:20:50:22 | a | | +| loops.ps1:50:5:50:34 | ...=... | loops.ps1:50:5:50:16 | letterArray | | +| loops.ps1:50:5:55:5 | {...} | loops.ps1:50:5:50:34 | ...=... | | +| loops.ps1:50:20:50:22 | a | loops.ps1:50:24:50:26 | b | | +| loops.ps1:50:20:50:34 | ...,... | loops.ps1:51:5:51:10 | ...=... | | +| loops.ps1:50:24:50:26 | b | loops.ps1:50:28:50:30 | c | | +| loops.ps1:50:28:50:30 | c | loops.ps1:50:32:50:34 | d | | +| loops.ps1:50:32:50:34 | d | loops.ps1:50:20:50:34 | ...,... | | +| loops.ps1:51:5:51:6 | a | loops.ps1:51:10:51:10 | 0 | | +| loops.ps1:51:5:51:10 | ...=... | loops.ps1:51:5:51:6 | a | | +| loops.ps1:51:10:51:10 | 0 | loops.ps1:52:25:52:36 | letterArray | | +| loops.ps1:52:5:55:5 | forach(... in ...) | loops.ps1:49:23:56:1 | exit {...} (normal) | empty | +| loops.ps1:52:25:52:36 | letterArray | loops.ps1:52:5:55:5 | forach(... in ...) | | +| loops.ps1:58:1:68:1 | def of Test-For-Ever | loops.ps1:1:1:70:0 | exit {...} (normal) | | +| loops.ps1:58:24:68:1 | enter {...} | loops.ps1:58:24:68:1 | {...} | | +| loops.ps1:58:24:68:1 | exit {...} (normal) | loops.ps1:58:24:68:1 | exit {...} | | +| loops.ps1:58:24:68:1 | {...} | loops.ps1:59:5:67:5 | {...} | | +| loops.ps1:59:5:59:6 | a | loops.ps1:59:10:59:10 | 0 | | +| loops.ps1:59:5:59:10 | ...=... | loops.ps1:59:5:59:6 | a | | +| loops.ps1:59:5:67:5 | {...} | loops.ps1:59:5:59:10 | ...=... | | +| loops.ps1:59:10:59:10 | 0 | loops.ps1:61:5:67:5 | for(...;...;...) | | +| loops.ps1:61:5:67:5 | for(...;...;...) | loops.ps1:62:5:67:5 | {...} | | +| loops.ps1:62:5:67:5 | {...} | loops.ps1:63:9:66:9 | [Stmt] if (...) {...} | | +| loops.ps1:63:9:66:9 | [Stmt] if (...) {...} | loops.ps1:63:12:63:13 | a | | +| loops.ps1:63:9:66:9 | if (...) {...} | loops.ps1:62:5:67:5 | {...} | | +| loops.ps1:63:12:63:13 | a | loops.ps1:63:19:63:20 | 10 | | +| loops.ps1:63:12:63:20 | ... -le ... | loops.ps1:63:9:66:9 | if (...) {...} | false | +| loops.ps1:63:12:63:20 | ... -le ... | loops.ps1:64:9:66:9 | {...} | true | +| loops.ps1:63:19:63:20 | 10 | loops.ps1:63:12:63:20 | ... -le ... | | +| loops.ps1:64:9:66:9 | {...} | loops.ps1:65:13:65:17 | break | | +| loops.ps1:65:13:65:17 | break | loops.ps1:58:24:68:1 | exit {...} (normal) | break | +| try.ps1:1:1:8:1 | def of test-try-catch | try.ps1:10:1:19:1 | def of test-try-with-throw-catch | | +| try.ps1:1:1:194:1 | enter {...} | try.ps1:1:1:194:1 | {...} | | +| try.ps1:1:1:194:1 | exit {...} (normal) | try.ps1:1:1:194:1 | exit {...} | | +| try.ps1:1:1:194:1 | {...} | try.ps1:1:1:8:1 | def of test-try-catch | | +| try.ps1:1:1:194:1 | {...} | try.ps1:1:1:194:1 | {...} | | +| try.ps1:1:25:8:1 | enter {...} | try.ps1:1:25:8:1 | {...} | | +| try.ps1:1:25:8:1 | exit {...} (normal) | try.ps1:1:25:8:1 | exit {...} | | +| try.ps1:1:25:8:1 | {...} | try.ps1:2:5:7:12 | {...} | | +| try.ps1:2:5:6:5 | try {...} | try.ps1:2:9:4:5 | {...} | | +| try.ps1:2:5:7:12 | {...} | try.ps1:2:5:6:5 | try {...} | | +| try.ps1:2:9:4:5 | {...} | try.ps1:3:9:3:29 | [Stmt] Call to Write-Output | | +| try.ps1:3:9:3:20 | Write-Output | try.ps1:3:22:3:29 | Hello! | | +| try.ps1:3:9:3:29 | Call to Write-Output | try.ps1:7:5:7:12 | return ... | | +| try.ps1:3:9:3:29 | [Stmt] Call to Write-Output | try.ps1:3:9:3:20 | Write-Output | | +| try.ps1:3:22:3:29 | Hello! | try.ps1:3:9:3:29 | Call to Write-Output | | +| try.ps1:7:5:7:12 | return ... | try.ps1:7:12:7:12 | 1 | | +| try.ps1:7:12:7:12 | 1 | try.ps1:1:25:8:1 | exit {...} (normal) | | +| try.ps1:10:1:19:1 | def of test-try-with-throw-catch | try.ps1:21:1:30:1 | def of test-try-with-throw-catch-with-throw | | +| try.ps1:10:40:19:1 | b | try.ps1:11:5:18:12 | {...} | | +| try.ps1:10:40:19:1 | enter {...} | try.ps1:10:40:19:1 | {...} | | +| try.ps1:10:40:19:1 | exit {...} (normal) | try.ps1:10:40:19:1 | exit {...} | | +| try.ps1:10:40:19:1 | {...} | try.ps1:10:40:19:1 | b | | +| try.ps1:11:5:17:5 | try {...} | try.ps1:11:9:15:5 | {...} | | +| try.ps1:11:5:18:12 | {...} | try.ps1:11:5:17:5 | try {...} | | +| try.ps1:11:9:15:5 | {...} | try.ps1:12:9:14:9 | [Stmt] if (...) {...} | | +| try.ps1:12:9:14:9 | [Stmt] if (...) {...} | try.ps1:12:12:12:13 | b | | +| try.ps1:12:9:14:9 | if (...) {...} | try.ps1:18:5:18:12 | return ... | | +| try.ps1:12:12:12:13 | b | try.ps1:12:9:14:9 | if (...) {...} | false | +| try.ps1:12:12:12:13 | b | try.ps1:12:16:14:9 | {...} | true | +| try.ps1:12:16:14:9 | {...} | try.ps1:13:13:13:20 | throw ... | | +| try.ps1:13:13:13:20 | throw ... | try.ps1:13:19:13:20 | 42 | | +| try.ps1:13:19:13:20 | 42 | try.ps1:12:9:14:9 | if (...) {...} | | +| try.ps1:18:5:18:12 | return ... | try.ps1:18:12:18:12 | 1 | | +| try.ps1:18:12:18:12 | 1 | try.ps1:10:40:19:1 | exit {...} (normal) | | +| try.ps1:21:1:30:1 | def of test-try-with-throw-catch-with-throw | try.ps1:32:1:41:1 | def of test-try-with-throw-catch-with-rethrow | | +| try.ps1:21:51:30:1 | b | try.ps1:22:5:29:12 | {...} | | +| try.ps1:21:51:30:1 | enter {...} | try.ps1:21:51:30:1 | {...} | | +| try.ps1:21:51:30:1 | exit {...} (normal) | try.ps1:21:51:30:1 | exit {...} | | +| try.ps1:21:51:30:1 | {...} | try.ps1:21:51:30:1 | b | | +| try.ps1:22:5:28:5 | try {...} | try.ps1:22:9:26:5 | {...} | | +| try.ps1:22:5:29:12 | {...} | try.ps1:22:5:28:5 | try {...} | | +| try.ps1:22:9:26:5 | {...} | try.ps1:23:9:25:9 | [Stmt] if (...) {...} | | +| try.ps1:23:9:25:9 | [Stmt] if (...) {...} | try.ps1:23:12:23:13 | b | | +| try.ps1:23:9:25:9 | if (...) {...} | try.ps1:29:5:29:12 | return ... | | +| try.ps1:23:12:23:13 | b | try.ps1:23:9:25:9 | if (...) {...} | false | +| try.ps1:23:12:23:13 | b | try.ps1:23:16:25:9 | {...} | true | +| try.ps1:23:16:25:9 | {...} | try.ps1:24:13:24:20 | throw ... | | +| try.ps1:24:13:24:20 | throw ... | try.ps1:24:19:24:20 | 42 | | +| try.ps1:24:19:24:20 | 42 | try.ps1:23:9:25:9 | if (...) {...} | | +| try.ps1:29:5:29:12 | return ... | try.ps1:29:12:29:12 | 1 | | +| try.ps1:29:12:29:12 | 1 | try.ps1:21:51:30:1 | exit {...} (normal) | | +| try.ps1:32:1:41:1 | def of test-try-with-throw-catch-with-rethrow | try.ps1:43:1:50:1 | def of test-try-catch-specific-1 | | +| try.ps1:32:53:41:1 | b | try.ps1:33:5:40:12 | {...} | | +| try.ps1:32:53:41:1 | enter {...} | try.ps1:32:53:41:1 | {...} | | +| try.ps1:32:53:41:1 | exit {...} (normal) | try.ps1:32:53:41:1 | exit {...} | | +| try.ps1:32:53:41:1 | {...} | try.ps1:32:53:41:1 | b | | +| try.ps1:33:5:39:5 | try {...} | try.ps1:33:9:37:5 | {...} | | +| try.ps1:33:5:40:12 | {...} | try.ps1:33:5:39:5 | try {...} | | +| try.ps1:33:9:37:5 | {...} | try.ps1:34:9:36:9 | [Stmt] if (...) {...} | | +| try.ps1:34:9:36:9 | [Stmt] if (...) {...} | try.ps1:34:12:34:13 | b | | +| try.ps1:34:9:36:9 | if (...) {...} | try.ps1:40:5:40:12 | return ... | | +| try.ps1:34:12:34:13 | b | try.ps1:34:9:36:9 | if (...) {...} | false | +| try.ps1:34:12:34:13 | b | try.ps1:34:16:36:9 | {...} | true | +| try.ps1:34:16:36:9 | {...} | try.ps1:35:13:35:20 | throw ... | | +| try.ps1:35:13:35:20 | throw ... | try.ps1:35:19:35:20 | 42 | | +| try.ps1:35:19:35:20 | 42 | try.ps1:34:9:36:9 | if (...) {...} | | +| try.ps1:40:5:40:12 | return ... | try.ps1:40:12:40:12 | 1 | | +| try.ps1:40:12:40:12 | 1 | try.ps1:32:53:41:1 | exit {...} (normal) | | +| try.ps1:43:1:50:1 | def of test-try-catch-specific-1 | try.ps1:52:1:59:1 | def of test-try-catch-specific-1 | | +| try.ps1:43:36:50:1 | enter {...} | try.ps1:43:36:50:1 | {...} | | +| try.ps1:43:36:50:1 | exit {...} (normal) | try.ps1:43:36:50:1 | exit {...} | | +| try.ps1:43:36:50:1 | {...} | try.ps1:44:5:49:12 | {...} | | +| try.ps1:44:5:48:5 | try {...} | try.ps1:44:9:46:5 | {...} | | +| try.ps1:44:5:49:12 | {...} | try.ps1:44:5:48:5 | try {...} | | +| try.ps1:44:9:46:5 | {...} | try.ps1:45:9:45:29 | [Stmt] Call to Write-Output | | +| try.ps1:45:9:45:20 | Write-Output | try.ps1:45:22:45:29 | Hello! | | +| try.ps1:45:9:45:29 | Call to Write-Output | try.ps1:49:5:49:12 | return ... | | +| try.ps1:45:9:45:29 | [Stmt] Call to Write-Output | try.ps1:45:9:45:20 | Write-Output | | +| try.ps1:45:22:45:29 | Hello! | try.ps1:45:9:45:29 | Call to Write-Output | | +| try.ps1:49:5:49:12 | return ... | try.ps1:49:12:49:12 | 1 | | +| try.ps1:49:12:49:12 | 1 | try.ps1:43:36:50:1 | exit {...} (normal) | | +| try.ps1:52:1:59:1 | def of test-try-catch-specific-1 | try.ps1:61:1:70:1 | def of test-try-two-catch-specific-1 | | +| try.ps1:52:36:59:1 | enter {...} | try.ps1:52:36:59:1 | {...} | | +| try.ps1:52:36:59:1 | exit {...} (normal) | try.ps1:52:36:59:1 | exit {...} | | +| try.ps1:52:36:59:1 | {...} | try.ps1:53:5:58:12 | {...} | | +| try.ps1:53:5:57:5 | try {...} | try.ps1:53:9:55:5 | {...} | | +| try.ps1:53:5:58:12 | {...} | try.ps1:53:5:57:5 | try {...} | | +| try.ps1:53:9:55:5 | {...} | try.ps1:54:9:54:29 | [Stmt] Call to Write-Output | | +| try.ps1:54:9:54:20 | Write-Output | try.ps1:54:22:54:29 | Hello! | | +| try.ps1:54:9:54:29 | Call to Write-Output | try.ps1:58:5:58:12 | return ... | | +| try.ps1:54:9:54:29 | [Stmt] Call to Write-Output | try.ps1:54:9:54:20 | Write-Output | | +| try.ps1:54:22:54:29 | Hello! | try.ps1:54:9:54:29 | Call to Write-Output | | +| try.ps1:58:5:58:12 | return ... | try.ps1:58:12:58:12 | 1 | | +| try.ps1:58:12:58:12 | 1 | try.ps1:52:36:59:1 | exit {...} (normal) | | +| try.ps1:61:1:70:1 | def of test-try-two-catch-specific-1 | try.ps1:72:1:79:1 | def of test-try-catch-specific-2 | | +| try.ps1:61:40:70:1 | enter {...} | try.ps1:61:40:70:1 | {...} | | +| try.ps1:61:40:70:1 | exit {...} (normal) | try.ps1:61:40:70:1 | exit {...} | | +| try.ps1:61:40:70:1 | {...} | try.ps1:62:5:69:12 | {...} | | +| try.ps1:62:5:68:5 | try {...} | try.ps1:62:9:64:5 | {...} | | +| try.ps1:62:5:69:12 | {...} | try.ps1:62:5:68:5 | try {...} | | +| try.ps1:62:9:64:5 | {...} | try.ps1:63:9:63:29 | [Stmt] Call to Write-Output | | +| try.ps1:63:9:63:20 | Write-Output | try.ps1:63:22:63:29 | Hello! | | +| try.ps1:63:9:63:29 | Call to Write-Output | try.ps1:69:5:69:12 | return ... | | +| try.ps1:63:9:63:29 | [Stmt] Call to Write-Output | try.ps1:63:9:63:20 | Write-Output | | +| try.ps1:63:22:63:29 | Hello! | try.ps1:63:9:63:29 | Call to Write-Output | | +| try.ps1:69:5:69:12 | return ... | try.ps1:69:12:69:12 | 2 | | +| try.ps1:69:12:69:12 | 2 | try.ps1:61:40:70:1 | exit {...} (normal) | | +| try.ps1:72:1:79:1 | def of test-try-catch-specific-2 | try.ps1:81:1:90:1 | def of test-try-two-catch-specific-2 | | +| try.ps1:72:36:79:1 | enter {...} | try.ps1:72:36:79:1 | {...} | | +| try.ps1:72:36:79:1 | exit {...} (normal) | try.ps1:72:36:79:1 | exit {...} | | +| try.ps1:72:36:79:1 | {...} | try.ps1:73:5:78:12 | {...} | | +| try.ps1:73:5:77:5 | try {...} | try.ps1:73:9:75:5 | {...} | | +| try.ps1:73:5:78:12 | {...} | try.ps1:73:5:77:5 | try {...} | | +| try.ps1:73:9:75:5 | {...} | try.ps1:74:9:74:29 | [Stmt] Call to Write-Output | | +| try.ps1:74:9:74:20 | Write-Output | try.ps1:74:22:74:29 | Hello! | | +| try.ps1:74:9:74:29 | Call to Write-Output | try.ps1:78:5:78:12 | return ... | | +| try.ps1:74:9:74:29 | [Stmt] Call to Write-Output | try.ps1:74:9:74:20 | Write-Output | | +| try.ps1:74:22:74:29 | Hello! | try.ps1:74:9:74:29 | Call to Write-Output | | +| try.ps1:78:5:78:12 | return ... | try.ps1:78:12:78:12 | 1 | | +| try.ps1:78:12:78:12 | 1 | try.ps1:72:36:79:1 | exit {...} (normal) | | +| try.ps1:81:1:90:1 | def of test-try-two-catch-specific-2 | try.ps1:92:1:103:1 | def of test-try-three-catch-specific-2 | | +| try.ps1:81:40:90:1 | enter {...} | try.ps1:81:40:90:1 | {...} | | +| try.ps1:81:40:90:1 | exit {...} (normal) | try.ps1:81:40:90:1 | exit {...} | | +| try.ps1:81:40:90:1 | {...} | try.ps1:82:5:89:12 | {...} | | +| try.ps1:82:5:88:5 | try {...} | try.ps1:82:9:84:5 | {...} | | +| try.ps1:82:5:89:12 | {...} | try.ps1:82:5:88:5 | try {...} | | +| try.ps1:82:9:84:5 | {...} | try.ps1:83:9:83:29 | [Stmt] Call to Write-Output | | +| try.ps1:83:9:83:20 | Write-Output | try.ps1:83:22:83:29 | Hello! | | +| try.ps1:83:9:83:29 | Call to Write-Output | try.ps1:89:5:89:12 | return ... | | +| try.ps1:83:9:83:29 | [Stmt] Call to Write-Output | try.ps1:83:9:83:20 | Write-Output | | +| try.ps1:83:22:83:29 | Hello! | try.ps1:83:9:83:29 | Call to Write-Output | | +| try.ps1:89:5:89:12 | return ... | try.ps1:89:12:89:12 | 2 | | +| try.ps1:89:12:89:12 | 2 | try.ps1:81:40:90:1 | exit {...} (normal) | | +| try.ps1:92:1:103:1 | def of test-try-three-catch-specific-2 | try.ps1:105:1:114:1 | def of test-try-catch-finally | | +| try.ps1:92:42:103:1 | enter {...} | try.ps1:92:42:103:1 | {...} | | +| try.ps1:92:42:103:1 | exit {...} (normal) | try.ps1:92:42:103:1 | exit {...} | | +| try.ps1:92:42:103:1 | {...} | try.ps1:93:5:102:12 | {...} | | +| try.ps1:93:5:101:5 | try {...} | try.ps1:93:9:95:5 | {...} | | +| try.ps1:93:5:102:12 | {...} | try.ps1:93:5:101:5 | try {...} | | +| try.ps1:93:9:95:5 | {...} | try.ps1:94:9:94:29 | [Stmt] Call to Write-Output | | +| try.ps1:94:9:94:20 | Write-Output | try.ps1:94:22:94:29 | Hello! | | +| try.ps1:94:9:94:29 | Call to Write-Output | try.ps1:102:5:102:12 | return ... | | +| try.ps1:94:9:94:29 | [Stmt] Call to Write-Output | try.ps1:94:9:94:20 | Write-Output | | +| try.ps1:94:22:94:29 | Hello! | try.ps1:94:9:94:29 | Call to Write-Output | | +| try.ps1:102:5:102:12 | return ... | try.ps1:102:12:102:12 | 3 | | +| try.ps1:102:12:102:12 | 3 | try.ps1:92:42:103:1 | exit {...} (normal) | | +| try.ps1:105:1:114:1 | def of test-try-catch-finally | try.ps1:116:1:123:1 | def of test-try-finally | | +| try.ps1:105:33:114:1 | enter {...} | try.ps1:105:33:114:1 | {...} | | +| try.ps1:105:33:114:1 | exit {...} (normal) | try.ps1:105:33:114:1 | exit {...} | | +| try.ps1:105:33:114:1 | {...} | try.ps1:106:5:113:12 | {...} | | +| try.ps1:106:5:112:5 | try {...} | try.ps1:106:9:108:5 | {...} | | +| try.ps1:106:5:113:12 | {...} | try.ps1:106:5:112:5 | try {...} | | +| try.ps1:106:9:108:5 | {...} | try.ps1:107:9:107:29 | [Stmt] Call to Write-Output | | +| try.ps1:107:9:107:20 | Write-Output | try.ps1:107:22:107:29 | Hello! | | +| try.ps1:107:9:107:29 | Call to Write-Output | try.ps1:110:15:112:5 | {...} | | +| try.ps1:107:9:107:29 | [Stmt] Call to Write-Output | try.ps1:107:9:107:20 | Write-Output | | +| try.ps1:107:22:107:29 | Hello! | try.ps1:107:9:107:29 | Call to Write-Output | | +| try.ps1:110:15:112:5 | {...} | try.ps1:111:9:111:31 | [Stmt] Call to Write-Output | | +| try.ps1:111:9:111:20 | Write-Output | try.ps1:111:22:111:31 | Finally! | | +| try.ps1:111:9:111:31 | Call to Write-Output | try.ps1:113:5:113:12 | return ... | | +| try.ps1:111:9:111:31 | [Stmt] Call to Write-Output | try.ps1:111:9:111:20 | Write-Output | | +| try.ps1:111:22:111:31 | Finally! | try.ps1:111:9:111:31 | Call to Write-Output | | +| try.ps1:113:5:113:12 | return ... | try.ps1:113:12:113:12 | 1 | | +| try.ps1:113:12:113:12 | 1 | try.ps1:105:33:114:1 | exit {...} (normal) | | +| try.ps1:116:1:123:1 | def of test-try-finally | try.ps1:125:1:134:1 | def of test-try-finally-catch-specific-1 | | +| try.ps1:116:27:123:1 | enter {...} | try.ps1:116:27:123:1 | {...} | | +| try.ps1:116:27:123:1 | exit {...} (normal) | try.ps1:116:27:123:1 | exit {...} | | +| try.ps1:116:27:123:1 | {...} | try.ps1:117:5:122:12 | {...} | | +| try.ps1:117:5:121:5 | try {...} | try.ps1:117:9:119:5 | {...} | | +| try.ps1:117:5:122:12 | {...} | try.ps1:117:5:121:5 | try {...} | | +| try.ps1:117:9:119:5 | {...} | try.ps1:118:9:118:29 | [Stmt] Call to Write-Output | | +| try.ps1:118:9:118:20 | Write-Output | try.ps1:118:22:118:29 | Hello! | | +| try.ps1:118:9:118:29 | Call to Write-Output | try.ps1:119:15:121:5 | {...} | | +| try.ps1:118:9:118:29 | [Stmt] Call to Write-Output | try.ps1:118:9:118:20 | Write-Output | | +| try.ps1:118:22:118:29 | Hello! | try.ps1:118:9:118:29 | Call to Write-Output | | +| try.ps1:119:15:121:5 | {...} | try.ps1:120:9:120:31 | [Stmt] Call to Write-Output | | +| try.ps1:120:9:120:20 | Write-Output | try.ps1:120:22:120:31 | Finally! | | +| try.ps1:120:9:120:31 | Call to Write-Output | try.ps1:122:5:122:12 | return ... | | +| try.ps1:120:9:120:31 | [Stmt] Call to Write-Output | try.ps1:120:9:120:20 | Write-Output | | +| try.ps1:120:22:120:31 | Finally! | try.ps1:120:9:120:31 | Call to Write-Output | | +| try.ps1:122:5:122:12 | return ... | try.ps1:122:12:122:12 | 1 | | +| try.ps1:122:12:122:12 | 1 | try.ps1:116:27:123:1 | exit {...} (normal) | | +| try.ps1:125:1:134:1 | def of test-try-finally-catch-specific-1 | try.ps1:136:1:147:1 | def of test-nested-try-inner-finally | | +| try.ps1:125:44:134:1 | enter {...} | try.ps1:125:44:134:1 | {...} | | +| try.ps1:125:44:134:1 | exit {...} (normal) | try.ps1:125:44:134:1 | exit {...} | | +| try.ps1:125:44:134:1 | {...} | try.ps1:126:5:133:12 | {...} | | +| try.ps1:126:5:132:5 | try {...} | try.ps1:126:9:128:5 | {...} | | +| try.ps1:126:5:133:12 | {...} | try.ps1:126:5:132:5 | try {...} | | +| try.ps1:126:9:128:5 | {...} | try.ps1:127:9:127:29 | [Stmt] Call to Write-Output | | +| try.ps1:127:9:127:20 | Write-Output | try.ps1:127:22:127:29 | Hello! | | +| try.ps1:127:9:127:29 | Call to Write-Output | try.ps1:130:15:132:5 | {...} | | +| try.ps1:127:9:127:29 | [Stmt] Call to Write-Output | try.ps1:127:9:127:20 | Write-Output | | +| try.ps1:127:22:127:29 | Hello! | try.ps1:127:9:127:29 | Call to Write-Output | | +| try.ps1:130:15:132:5 | {...} | try.ps1:131:9:131:31 | [Stmt] Call to Write-Output | | +| try.ps1:131:9:131:20 | Write-Output | try.ps1:131:22:131:31 | Finally! | | +| try.ps1:131:9:131:31 | Call to Write-Output | try.ps1:133:5:133:12 | return ... | | +| try.ps1:131:9:131:31 | [Stmt] Call to Write-Output | try.ps1:131:9:131:20 | Write-Output | | +| try.ps1:131:22:131:31 | Finally! | try.ps1:131:9:131:31 | Call to Write-Output | | +| try.ps1:133:5:133:12 | return ... | try.ps1:133:12:133:12 | 1 | | +| try.ps1:133:12:133:12 | 1 | try.ps1:125:44:134:1 | exit {...} (normal) | | +| try.ps1:136:1:147:1 | def of test-nested-try-inner-finally | try.ps1:149:1:162:1 | def of test-nested-try-inner-finally | | +| try.ps1:136:40:147:1 | enter {...} | try.ps1:136:40:147:1 | {...} | | +| try.ps1:136:40:147:1 | exit {...} (normal) | try.ps1:136:40:147:1 | exit {...} | | +| try.ps1:136:40:147:1 | {...} | try.ps1:137:5:146:12 | {...} | | +| try.ps1:137:5:145:5 | try {...} | try.ps1:137:9:143:5 | {...} | | +| try.ps1:137:5:146:12 | {...} | try.ps1:137:5:145:5 | try {...} | | +| try.ps1:137:9:143:5 | {...} | try.ps1:138:9:142:9 | try {...} | | +| try.ps1:138:9:142:9 | try {...} | try.ps1:138:13:140:9 | {...} | | +| try.ps1:138:13:140:9 | {...} | try.ps1:139:13:139:33 | [Stmt] Call to Write-Output | | +| try.ps1:139:13:139:24 | Write-Output | try.ps1:139:26:139:33 | Hello! | | +| try.ps1:139:13:139:33 | Call to Write-Output | try.ps1:146:5:146:12 | return ... | | +| try.ps1:139:13:139:33 | [Stmt] Call to Write-Output | try.ps1:139:13:139:24 | Write-Output | | +| try.ps1:139:26:139:33 | Hello! | try.ps1:139:13:139:33 | Call to Write-Output | | +| try.ps1:146:5:146:12 | return ... | try.ps1:146:12:146:12 | 1 | | +| try.ps1:146:12:146:12 | 1 | try.ps1:136:40:147:1 | exit {...} (normal) | | +| try.ps1:149:1:162:1 | def of test-nested-try-inner-finally | try.ps1:164:1:177:1 | def of test-nested-try-outer-finally | | +| try.ps1:149:40:162:1 | enter {...} | try.ps1:149:40:162:1 | {...} | | +| try.ps1:149:40:162:1 | exit {...} (normal) | try.ps1:149:40:162:1 | exit {...} | | +| try.ps1:149:40:162:1 | {...} | try.ps1:150:5:161:12 | {...} | | +| try.ps1:150:5:160:5 | try {...} | try.ps1:150:9:158:5 | {...} | | +| try.ps1:150:5:161:12 | {...} | try.ps1:150:5:160:5 | try {...} | | +| try.ps1:150:9:158:5 | {...} | try.ps1:151:9:157:9 | try {...} | | +| try.ps1:151:9:157:9 | try {...} | try.ps1:151:13:153:9 | {...} | | +| try.ps1:151:13:153:9 | {...} | try.ps1:152:13:152:33 | [Stmt] Call to Write-Output | | +| try.ps1:152:13:152:24 | Write-Output | try.ps1:152:26:152:33 | Hello! | | +| try.ps1:152:13:152:33 | Call to Write-Output | try.ps1:155:19:157:9 | {...} | | +| try.ps1:152:13:152:33 | [Stmt] Call to Write-Output | try.ps1:152:13:152:24 | Write-Output | | +| try.ps1:152:26:152:33 | Hello! | try.ps1:152:13:152:33 | Call to Write-Output | | +| try.ps1:155:19:157:9 | {...} | try.ps1:156:13:156:35 | [Stmt] Call to Write-Output | | +| try.ps1:156:13:156:24 | Write-Output | try.ps1:156:26:156:35 | Finally! | | +| try.ps1:156:13:156:35 | Call to Write-Output | try.ps1:161:5:161:12 | return ... | | +| try.ps1:156:13:156:35 | [Stmt] Call to Write-Output | try.ps1:156:13:156:24 | Write-Output | | +| try.ps1:156:26:156:35 | Finally! | try.ps1:156:13:156:35 | Call to Write-Output | | +| try.ps1:161:5:161:12 | return ... | try.ps1:161:12:161:12 | 1 | | +| try.ps1:161:12:161:12 | 1 | try.ps1:149:40:162:1 | exit {...} (normal) | | +| try.ps1:164:1:177:1 | def of test-nested-try-outer-finally | try.ps1:179:1:194:1 | def of test-nested-try-inner-outer-finally | | +| try.ps1:164:40:177:1 | enter {...} | try.ps1:164:40:177:1 | {...} | | +| try.ps1:164:40:177:1 | exit {...} (normal) | try.ps1:164:40:177:1 | exit {...} | | +| try.ps1:164:40:177:1 | {...} | try.ps1:165:5:176:12 | {...} | | +| try.ps1:165:5:175:5 | try {...} | try.ps1:165:9:171:5 | {...} | | +| try.ps1:165:5:176:12 | {...} | try.ps1:165:5:175:5 | try {...} | | +| try.ps1:165:9:171:5 | {...} | try.ps1:166:9:170:9 | try {...} | | +| try.ps1:166:9:170:9 | try {...} | try.ps1:166:13:168:9 | {...} | | +| try.ps1:166:13:168:9 | {...} | try.ps1:167:13:167:33 | [Stmt] Call to Write-Output | | +| try.ps1:167:13:167:24 | Write-Output | try.ps1:167:26:167:33 | Hello! | | +| try.ps1:167:13:167:33 | Call to Write-Output | try.ps1:173:15:175:5 | {...} | | +| try.ps1:167:13:167:33 | [Stmt] Call to Write-Output | try.ps1:167:13:167:24 | Write-Output | | +| try.ps1:167:26:167:33 | Hello! | try.ps1:167:13:167:33 | Call to Write-Output | | +| try.ps1:173:15:175:5 | {...} | try.ps1:174:9:174:31 | [Stmt] Call to Write-Output | | +| try.ps1:174:9:174:20 | Write-Output | try.ps1:174:22:174:31 | Finally! | | +| try.ps1:174:9:174:31 | Call to Write-Output | try.ps1:176:5:176:12 | return ... | | +| try.ps1:174:9:174:31 | [Stmt] Call to Write-Output | try.ps1:174:9:174:20 | Write-Output | | +| try.ps1:174:22:174:31 | Finally! | try.ps1:174:9:174:31 | Call to Write-Output | | +| try.ps1:176:5:176:12 | return ... | try.ps1:176:12:176:12 | 1 | | +| try.ps1:176:12:176:12 | 1 | try.ps1:164:40:177:1 | exit {...} (normal) | | +| try.ps1:179:1:194:1 | def of test-nested-try-inner-outer-finally | try.ps1:1:1:194:1 | exit {...} (normal) | | +| try.ps1:179:46:194:1 | enter {...} | try.ps1:179:46:194:1 | {...} | | +| try.ps1:179:46:194:1 | exit {...} (normal) | try.ps1:179:46:194:1 | exit {...} | | +| try.ps1:179:46:194:1 | {...} | try.ps1:180:5:193:12 | {...} | | +| try.ps1:180:5:192:5 | try {...} | try.ps1:180:9:188:5 | {...} | | +| try.ps1:180:5:193:12 | {...} | try.ps1:180:5:192:5 | try {...} | | +| try.ps1:180:9:188:5 | {...} | try.ps1:181:9:187:9 | try {...} | | +| try.ps1:181:9:187:9 | try {...} | try.ps1:181:13:183:9 | {...} | | +| try.ps1:181:13:183:9 | {...} | try.ps1:182:13:182:33 | [Stmt] Call to Write-Output | | +| try.ps1:182:13:182:24 | Write-Output | try.ps1:182:26:182:33 | Hello! | | +| try.ps1:182:13:182:33 | Call to Write-Output | try.ps1:185:19:187:9 | {...} | | +| try.ps1:182:13:182:33 | [Stmt] Call to Write-Output | try.ps1:182:13:182:24 | Write-Output | | +| try.ps1:182:26:182:33 | Hello! | try.ps1:182:13:182:33 | Call to Write-Output | | +| try.ps1:185:19:187:9 | {...} | try.ps1:186:13:186:35 | [Stmt] Call to Write-Output | | +| try.ps1:186:13:186:24 | Write-Output | try.ps1:186:26:186:35 | Finally! | | +| try.ps1:186:13:186:35 | Call to Write-Output | try.ps1:190:15:192:5 | {...} | | +| try.ps1:186:13:186:35 | [Stmt] Call to Write-Output | try.ps1:186:13:186:24 | Write-Output | | +| try.ps1:186:26:186:35 | Finally! | try.ps1:186:13:186:35 | Call to Write-Output | | +| try.ps1:190:15:192:5 | {...} | try.ps1:191:9:191:31 | [Stmt] Call to Write-Output | | +| try.ps1:191:9:191:20 | Write-Output | try.ps1:191:22:191:31 | Finally! | | +| try.ps1:191:9:191:31 | Call to Write-Output | try.ps1:193:5:193:12 | return ... | | +| try.ps1:191:9:191:31 | [Stmt] Call to Write-Output | try.ps1:191:9:191:20 | Write-Output | | +| try.ps1:191:22:191:31 | Finally! | try.ps1:191:9:191:31 | Call to Write-Output | | +| try.ps1:193:5:193:12 | return ... | try.ps1:193:12:193:12 | 1 | | +| try.ps1:193:12:193:12 | 1 | try.ps1:179:46:194:1 | exit {...} (normal) | | diff --git a/powershell/ql/test/library-tests/controlflow/graph/consistency.expected b/powershell/ql/test/library-tests/controlflow/graph/consistency.expected new file mode 100644 index 000000000000..68e5304a2904 --- /dev/null +++ b/powershell/ql/test/library-tests/controlflow/graph/consistency.expected @@ -0,0 +1,44 @@ +nonUniqueSetRepresentation +breakInvariant2 +breakInvariant3 +breakInvariant4 +breakInvariant5 +multipleSuccessors +| functions.ps1:8:5:8:23 | [Stmt] ...+... | successor | functions.ps1:8:5:8:12 | number1 | +| functions.ps1:8:5:8:23 | [Stmt] ...+... | successor | functions.ps1:46:17:46:18 | __pipeline_iterator | +| functions.ps1:8:5:8:23 | [Stmt] __pipeline_iterator | successor | functions.ps1:8:5:8:12 | number1 | +| functions.ps1:8:5:8:23 | [Stmt] __pipeline_iterator | successor | functions.ps1:46:17:46:18 | __pipeline_iterator | +| functions.ps1:16:24:16:24 | 0 | successor | functions.ps1:13:28:20:1 | name2 | +| functions.ps1:16:24:16:24 | 0 | successor | functions.ps1:17:24:17:29 | name1 | +| functions.ps1:17:24:17:33 | ...+... | successor | functions.ps1:13:28:20:1 | [synth] pipeline | +| functions.ps1:17:24:17:33 | ...+... | successor | functions.ps1:13:28:20:1 | name0 | +| functions.ps1:19:5:19:18 | [Stmt] ...+... | successor | functions.ps1:19:13:19:18 | name2 | +| functions.ps1:19:5:19:18 | [Stmt] ...+... | successor | functions.ps1:46:17:46:18 | __pipeline_iterator | +| functions.ps1:19:5:19:18 | [Stmt] __pipeline_iterator | successor | functions.ps1:19:13:19:18 | name2 | +| functions.ps1:19:5:19:18 | [Stmt] __pipeline_iterator | successor | functions.ps1:46:17:46:18 | __pipeline_iterator | +| functions.ps1:33:5:33:8 | [Stmt] __pipeline_iterator | successor | functions.ps1:33:5:33:8 | sum | +| functions.ps1:33:5:33:8 | [Stmt] __pipeline_iterator | successor | functions.ps1:46:17:46:18 | __pipeline_iterator | +| functions.ps1:33:5:33:8 | [Stmt] sum | successor | functions.ps1:33:5:33:8 | sum | +| functions.ps1:33:5:33:8 | [Stmt] sum | successor | functions.ps1:46:17:46:18 | __pipeline_iterator | +| functions.ps1:46:9:46:12 | sum | successor | functions.ps1:44:5:47:5 | {...} | +| functions.ps1:46:9:46:12 | sum | successor | functions.ps1:48:5:51:5 | {...} | +| functions.ps1:50:9:50:12 | [Stmt] __pipeline_iterator | successor | functions.ps1:46:17:46:18 | __pipeline_iterator | +| functions.ps1:50:9:50:12 | [Stmt] __pipeline_iterator | successor | functions.ps1:50:9:50:12 | sum | +| functions.ps1:50:9:50:12 | [Stmt] sum | successor | functions.ps1:46:17:46:18 | __pipeline_iterator | +| functions.ps1:50:9:50:12 | [Stmt] sum | successor | functions.ps1:50:9:50:12 | sum | +| loops.ps1:45:14:45:19 | ...+... | successor | loops.ps1:44:18:44:19 | i | +| loops.ps1:45:14:45:19 | ...+... | successor | loops.ps1:44:29:44:39 | ...=... | +simpleAndNormalSuccessors +deadEnd +nonUniqueSplitKind +nonUniqueListOrder +multipleToString +| functions.ps1:8:5:8:23 | [Stmt] ...+... | [Stmt] ...+...,[Stmt] __pipeline_iterator | +| functions.ps1:8:5:8:23 | [Stmt] __pipeline_iterator | [Stmt] ...+...,[Stmt] __pipeline_iterator | +| functions.ps1:19:5:19:18 | [Stmt] ...+... | [Stmt] ...+...,[Stmt] __pipeline_iterator | +| functions.ps1:19:5:19:18 | [Stmt] __pipeline_iterator | [Stmt] ...+...,[Stmt] __pipeline_iterator | +| functions.ps1:33:5:33:8 | [Stmt] __pipeline_iterator | [Stmt] __pipeline_iterator,[Stmt] sum | +| functions.ps1:33:5:33:8 | [Stmt] sum | [Stmt] __pipeline_iterator,[Stmt] sum | +| functions.ps1:50:9:50:12 | [Stmt] __pipeline_iterator | [Stmt] __pipeline_iterator,[Stmt] sum | +| functions.ps1:50:9:50:12 | [Stmt] sum | [Stmt] __pipeline_iterator,[Stmt] sum | +scopeNoFirst diff --git a/powershell/ql/test/library-tests/controlflow/graph/consistency.ql b/powershell/ql/test/library-tests/controlflow/graph/consistency.ql new file mode 100644 index 000000000000..f7ab51cc4941 --- /dev/null +++ b/powershell/ql/test/library-tests/controlflow/graph/consistency.ql @@ -0,0 +1 @@ +import semmle.code.powershell.controlflow.internal.ControlFlowGraphImpl::Consistency \ No newline at end of file diff --git a/powershell/ql/test/library-tests/dataflow/fields/test.expected b/powershell/ql/test/library-tests/dataflow/fields/test.expected index 40cc3128e6a9..8916976e2a57 100644 --- a/powershell/ql/test/library-tests/dataflow/fields/test.expected +++ b/powershell/ql/test/library-tests/dataflow/fields/test.expected @@ -1,214 +1,139 @@ models edges -| test.ps1:1:1:1:3 | [post] a [f] | test.ps1:2:6:2:8 | a [f] | provenance | | -| test.ps1:1:8:1:18 | call to Source | test.ps1:1:1:1:3 | [post] a [f] | provenance | | -| test.ps1:2:6:2:8 | a [f] | test.ps1:2:6:2:10 | f | provenance | | -| test.ps1:8:1:8:6 | [post] arr1 [element 3] | test.ps1:9:6:9:11 | arr1 [element 3] | provenance | | -| test.ps1:8:1:8:6 | [post] arr1 [element 3] | test.ps1:9:6:9:11 | arr1 [element 3] | provenance | | -| test.ps1:8:12:8:22 | call to Source | test.ps1:8:1:8:6 | [post] arr1 [element 3] | provenance | | -| test.ps1:8:12:8:22 | call to Source | test.ps1:8:1:8:6 | [post] arr1 [element 3] | provenance | | -| test.ps1:9:6:9:11 | arr1 [element 3] | test.ps1:9:6:9:14 | ...[...] | provenance | | -| test.ps1:9:6:9:11 | arr1 [element 3] | test.ps1:9:6:9:14 | ...[...] | provenance | | -| test.ps1:12:1:12:6 | [post] arr2 [element] | test.ps1:13:6:13:11 | arr2 [element] | provenance | | -| test.ps1:12:19:12:29 | call to Source | test.ps1:12:1:12:6 | [post] arr2 [element] | provenance | | -| test.ps1:13:6:13:11 | arr2 [element] | test.ps1:13:6:13:14 | ...[...] | provenance | | -| test.ps1:15:1:15:6 | [post] arr3 [element 3] | test.ps1:16:6:16:11 | arr3 [element 3] | provenance | | -| test.ps1:15:1:15:6 | [post] arr3 [element 3] | test.ps1:16:6:16:11 | arr3 [element 3] | provenance | | -| test.ps1:15:12:15:22 | call to Source | test.ps1:15:1:15:6 | [post] arr3 [element 3] | provenance | | -| test.ps1:15:12:15:22 | call to Source | test.ps1:15:1:15:6 | [post] arr3 [element 3] | provenance | | -| test.ps1:16:6:16:11 | arr3 [element 3] | test.ps1:16:6:16:21 | ...[...] | provenance | | -| test.ps1:16:6:16:11 | arr3 [element 3] | test.ps1:16:6:16:21 | ...[...] | provenance | | -| test.ps1:18:1:18:6 | [post] arr4 [element] | test.ps1:19:6:19:11 | arr4 [element] | provenance | | -| test.ps1:18:20:18:30 | call to Source | test.ps1:18:1:18:6 | [post] arr4 [element] | provenance | | -| test.ps1:19:6:19:11 | arr4 [element] | test.ps1:19:6:19:22 | ...[...] | provenance | | -| test.ps1:21:1:21:6 | [post] arr5 [element, element 1] | test.ps1:22:6:22:11 | arr5 [element, element 1] | provenance | | -| test.ps1:21:1:21:6 | [post] arr5 [element, element 1] | test.ps1:22:6:22:11 | arr5 [element, element 1] | provenance | | -| test.ps1:21:1:21:17 | [post] ...[...] [element 1] | test.ps1:21:1:21:6 | [post] arr5 [element, element 1] | provenance | | -| test.ps1:21:1:21:17 | [post] ...[...] [element 1] | test.ps1:21:1:21:6 | [post] arr5 [element, element 1] | provenance | | -| test.ps1:21:23:21:33 | call to Source | test.ps1:21:1:21:17 | [post] ...[...] [element 1] | provenance | | -| test.ps1:21:23:21:33 | call to Source | test.ps1:21:1:21:17 | [post] ...[...] [element 1] | provenance | | -| test.ps1:22:6:22:11 | arr5 [element, element 1] | test.ps1:22:6:22:22 | ...[...] [element 1] | provenance | | -| test.ps1:22:6:22:11 | arr5 [element, element 1] | test.ps1:22:6:22:22 | ...[...] [element 1] | provenance | | -| test.ps1:22:6:22:22 | ...[...] [element 1] | test.ps1:22:6:22:25 | ...[...] | provenance | | -| test.ps1:22:6:22:22 | ...[...] [element 1] | test.ps1:22:6:22:25 | ...[...] | provenance | | -| test.ps1:25:1:25:6 | [post] arr6 [element 1, element] | test.ps1:26:6:26:11 | arr6 [element 1, element] | provenance | | -| test.ps1:25:1:25:6 | [post] arr6 [element 1, element] | test.ps1:26:6:26:11 | arr6 [element 1, element] | provenance | | -| test.ps1:25:1:25:9 | [post] ...[...] [element] | test.ps1:25:1:25:6 | [post] arr6 [element 1, element] | provenance | | -| test.ps1:25:1:25:9 | [post] ...[...] [element] | test.ps1:25:1:25:6 | [post] arr6 [element 1, element] | provenance | | -| test.ps1:25:23:25:33 | call to Source | test.ps1:25:1:25:9 | [post] ...[...] [element] | provenance | | -| test.ps1:26:6:26:11 | arr6 [element 1, element] | test.ps1:26:6:26:14 | ...[...] [element] | provenance | | -| test.ps1:26:6:26:11 | arr6 [element 1, element] | test.ps1:26:6:26:14 | ...[...] [element] | provenance | | -| test.ps1:26:6:26:14 | ...[...] [element] | test.ps1:26:6:26:25 | ...[...] | provenance | | -| test.ps1:29:1:29:6 | [post] arr7 [element, element] | test.ps1:30:6:30:11 | arr7 [element, element] | provenance | | -| test.ps1:29:1:29:6 | [post] arr7 [element, element] | test.ps1:31:6:31:11 | arr7 [element, element] | provenance | | -| test.ps1:29:1:29:17 | [post] ...[...] [element] | test.ps1:29:1:29:6 | [post] arr7 [element, element] | provenance | | -| test.ps1:29:31:29:41 | call to Source | test.ps1:29:1:29:17 | [post] ...[...] [element] | provenance | | -| test.ps1:30:6:30:11 | arr7 [element, element] | test.ps1:30:6:30:14 | ...[...] [element] | provenance | | -| test.ps1:30:6:30:14 | ...[...] [element] | test.ps1:30:6:30:17 | ...[...] | provenance | | -| test.ps1:31:6:31:11 | arr7 [element, element] | test.ps1:31:6:31:22 | ...[...] [element] | provenance | | -| test.ps1:31:6:31:22 | ...[...] [element] | test.ps1:31:6:31:33 | ...[...] | provenance | | -| test.ps1:33:6:33:17 | call to Source | test.ps1:35:15:35:17 | x | provenance | | -| test.ps1:35:9:35:17 | ...,... [element 2] | test.ps1:38:6:38:11 | arr8 [element 2] | provenance | | -| test.ps1:35:9:35:17 | ...,... [element 2] | test.ps1:39:6:39:11 | arr8 [element 2] | provenance | | -| test.ps1:35:15:35:17 | x | test.ps1:35:9:35:17 | ...,... [element 2] | provenance | | -| test.ps1:38:6:38:11 | arr8 [element 2] | test.ps1:38:6:38:14 | ...[...] | provenance | | -| test.ps1:39:6:39:11 | arr8 [element 2] | test.ps1:39:6:39:21 | ...[...] | provenance | | -| test.ps1:41:6:41:17 | call to Source | test.ps1:43:17:43:19 | y | provenance | | -| test.ps1:43:11:43:19 | ...,... [element 2] | test.ps1:46:6:46:11 | arr9 [element 2] | provenance | | -| test.ps1:43:11:43:19 | ...,... [element 2] | test.ps1:47:6:47:11 | arr9 [element 2] | provenance | | -| test.ps1:43:17:43:19 | y | test.ps1:43:11:43:19 | ...,... [element 2] | provenance | | -| test.ps1:46:6:46:11 | arr9 [element 2] | test.ps1:46:6:46:14 | ...[...] | provenance | | -| test.ps1:47:6:47:11 | arr9 [element 2] | test.ps1:47:6:47:21 | ...[...] | provenance | | -| test.ps1:52:22:54:6 | this [field] | test.ps1:53:14:53:19 | this [field] | provenance | | -| test.ps1:53:14:53:19 | this [field] | test.ps1:53:14:53:25 | field | provenance | | -| test.ps1:59:1:59:9 | [post] myClass [field] | test.ps1:61:1:61:9 | myClass [field] | provenance | | -| test.ps1:59:18:59:29 | call to Source | test.ps1:59:1:59:9 | [post] myClass [field] | provenance | | -| test.ps1:61:1:61:9 | myClass [field] | test.ps1:52:22:54:6 | this [field] | provenance | | -| test.ps1:64:10:64:21 | call to Source | test.ps1:67:5:67:7 | x | provenance | | -| test.ps1:65:10:65:21 | call to Source | test.ps1:68:5:68:7 | y | provenance | | -| test.ps1:66:10:66:21 | call to Source | test.ps1:68:9:68:11 | z | provenance | | -| test.ps1:67:5:67:7 | x | test.ps1:71:6:71:13 | call to produce [element] | provenance | | -| test.ps1:68:5:68:7 | y | test.ps1:68:5:68:11 | ...,... [element 0] | provenance | | -| test.ps1:68:5:68:11 | ...,... [element 0] | test.ps1:71:6:71:13 | call to produce [element] | provenance | | -| test.ps1:68:5:68:11 | ...,... [element 1] | test.ps1:71:6:71:13 | call to produce [element] | provenance | | -| test.ps1:68:9:68:11 | z | test.ps1:68:5:68:11 | ...,... [element 1] | provenance | | -| test.ps1:71:6:71:13 | call to produce [element] | test.ps1:72:6:72:8 | x [element] | provenance | | -| test.ps1:71:6:71:13 | call to produce [element] | test.ps1:73:6:73:8 | x [element] | provenance | | -| test.ps1:71:6:71:13 | call to produce [element] | test.ps1:74:6:74:8 | x [element] | provenance | | -| test.ps1:72:6:72:8 | x [element] | test.ps1:72:6:72:11 | ...[...] | provenance | | -| test.ps1:73:6:73:8 | x [element] | test.ps1:73:6:73:11 | ...[...] | provenance | | -| test.ps1:74:6:74:8 | x [element] | test.ps1:74:6:74:11 | ...[...] | provenance | | -| test.ps1:76:9:79:2 | ${...} [element a] | test.ps1:81:6:81:11 | hash [element a] | provenance | | -| test.ps1:76:9:79:2 | ${...} [element a] | test.ps1:85:6:85:11 | hash [element a] | provenance | | -| test.ps1:77:7:77:18 | call to Source | test.ps1:76:9:79:2 | ${...} [element a] | provenance | | -| test.ps1:81:6:81:11 | hash [element a] | test.ps1:81:6:81:16 | ...[...] | provenance | | -| test.ps1:85:6:85:11 | hash [element a] | test.ps1:85:6:85:16 | ...[...] | provenance | | -| test.ps1:86:1:86:6 | [post] hash [b] | test.ps1:87:6:87:11 | hash [b] | provenance | | -| test.ps1:86:11:86:22 | call to Source | test.ps1:86:1:86:6 | [post] hash [b] | provenance | | -| test.ps1:87:6:87:11 | hash [b] | test.ps1:87:6:87:13 | b | provenance | | +| test.ps1:3:1:3:2 | [post] a [f] | test.ps1:4:6:4:7 | a [f] | provenance | | +| test.ps1:3:8:3:17 | Call to Source | test.ps1:3:1:3:2 | [post] a [f] | provenance | | +| test.ps1:4:6:4:7 | a [f] | test.ps1:4:6:4:9 | f | provenance | | +| test.ps1:10:1:10:5 | [post] arr1 [element 3] | test.ps1:11:6:11:10 | arr1 [element 3] | provenance | | +| test.ps1:10:12:10:21 | Call to Source | test.ps1:10:1:10:5 | [post] arr1 [element 3] | provenance | | +| test.ps1:11:6:11:10 | arr1 [element 3] | test.ps1:11:6:11:13 | ...[...] | provenance | | +| test.ps1:14:1:14:5 | [post] arr2 [element] | test.ps1:15:6:15:10 | arr2 [element] | provenance | | +| test.ps1:14:19:14:28 | Call to Source | test.ps1:14:1:14:5 | [post] arr2 [element] | provenance | | +| test.ps1:15:6:15:10 | arr2 [element] | test.ps1:15:6:15:13 | ...[...] | provenance | | +| test.ps1:17:1:17:5 | [post] arr3 [element 3] | test.ps1:18:6:18:10 | arr3 [element 3] | provenance | | +| test.ps1:17:12:17:21 | Call to Source | test.ps1:17:1:17:5 | [post] arr3 [element 3] | provenance | | +| test.ps1:18:6:18:10 | arr3 [element 3] | test.ps1:18:6:18:20 | ...[...] | provenance | | +| test.ps1:20:1:20:5 | [post] arr4 [element] | test.ps1:21:6:21:10 | arr4 [element] | provenance | | +| test.ps1:20:20:20:29 | Call to Source | test.ps1:20:1:20:5 | [post] arr4 [element] | provenance | | +| test.ps1:21:6:21:10 | arr4 [element] | test.ps1:21:6:21:21 | ...[...] | provenance | | +| test.ps1:23:1:23:5 | [post] arr5 [element, element 1] | test.ps1:24:6:24:10 | arr5 [element, element 1] | provenance | | +| test.ps1:23:1:23:16 | [post] ...[...] [element 1] | test.ps1:23:1:23:5 | [post] arr5 [element, element 1] | provenance | | +| test.ps1:23:23:23:32 | Call to Source | test.ps1:23:1:23:16 | [post] ...[...] [element 1] | provenance | | +| test.ps1:24:6:24:10 | arr5 [element, element 1] | test.ps1:24:6:24:21 | ...[...] [element 1] | provenance | | +| test.ps1:24:6:24:21 | ...[...] [element 1] | test.ps1:24:6:24:24 | ...[...] | provenance | | +| test.ps1:27:1:27:5 | [post] arr6 [element 1, element] | test.ps1:28:6:28:10 | arr6 [element 1, element] | provenance | | +| test.ps1:27:1:27:8 | [post] ...[...] [element] | test.ps1:27:1:27:5 | [post] arr6 [element 1, element] | provenance | | +| test.ps1:27:23:27:32 | Call to Source | test.ps1:27:1:27:8 | [post] ...[...] [element] | provenance | | +| test.ps1:28:6:28:10 | arr6 [element 1, element] | test.ps1:28:6:28:13 | ...[...] [element] | provenance | | +| test.ps1:28:6:28:13 | ...[...] [element] | test.ps1:28:6:28:24 | ...[...] | provenance | | +| test.ps1:31:1:31:5 | [post] arr7 [element, element] | test.ps1:32:6:32:10 | arr7 [element, element] | provenance | | +| test.ps1:31:1:31:5 | [post] arr7 [element, element] | test.ps1:33:6:33:10 | arr7 [element, element] | provenance | | +| test.ps1:31:1:31:16 | [post] ...[...] [element] | test.ps1:31:1:31:5 | [post] arr7 [element, element] | provenance | | +| test.ps1:31:31:31:40 | Call to Source | test.ps1:31:1:31:16 | [post] ...[...] [element] | provenance | | +| test.ps1:32:6:32:10 | arr7 [element, element] | test.ps1:32:6:32:13 | ...[...] [element] | provenance | | +| test.ps1:32:6:32:13 | ...[...] [element] | test.ps1:32:6:32:16 | ...[...] | provenance | | +| test.ps1:33:6:33:10 | arr7 [element, element] | test.ps1:33:6:33:21 | ...[...] [element] | provenance | | +| test.ps1:33:6:33:21 | ...[...] [element] | test.ps1:33:6:33:32 | ...[...] | provenance | | +| test.ps1:35:6:35:16 | Call to Source | test.ps1:37:15:37:16 | x | provenance | | +| test.ps1:37:9:37:16 | ...,... [element 2] | test.ps1:40:6:40:10 | arr8 [element 2] | provenance | | +| test.ps1:37:9:37:16 | ...,... [element 2] | test.ps1:41:6:41:10 | arr8 [element 2] | provenance | | +| test.ps1:37:15:37:16 | x | test.ps1:37:9:37:16 | ...,... [element 2] | provenance | | +| test.ps1:40:6:40:10 | arr8 [element 2] | test.ps1:40:6:40:13 | ...[...] | provenance | | +| test.ps1:41:6:41:10 | arr8 [element 2] | test.ps1:41:6:41:20 | ...[...] | provenance | | +| test.ps1:43:6:43:16 | Call to Source | test.ps1:45:17:45:18 | y | provenance | | +| test.ps1:45:11:45:18 | ...,... [element 2] | test.ps1:48:6:48:10 | arr9 [element 2] | provenance | | +| test.ps1:45:11:45:18 | ...,... [element 2] | test.ps1:49:6:49:10 | arr9 [element 2] | provenance | | +| test.ps1:45:17:45:18 | y | test.ps1:45:11:45:18 | ...,... [element 2] | provenance | | +| test.ps1:48:6:48:10 | arr9 [element 2] | test.ps1:48:6:48:13 | ...[...] | provenance | | +| test.ps1:49:6:49:10 | arr9 [element 2] | test.ps1:49:6:49:20 | ...[...] | provenance | | +| test.ps1:88:1:88:5 | [post] hash [b] | test.ps1:89:6:89:10 | hash [b] | provenance | | +| test.ps1:88:11:88:21 | Call to Source | test.ps1:88:1:88:5 | [post] hash [b] | provenance | | +| test.ps1:89:6:89:10 | hash [b] | test.ps1:89:6:89:12 | b | provenance | | nodes -| test.ps1:1:1:1:3 | [post] a [f] | semmle.label | [post] a [f] | -| test.ps1:1:8:1:18 | call to Source | semmle.label | call to Source | -| test.ps1:2:6:2:8 | a [f] | semmle.label | a [f] | -| test.ps1:2:6:2:10 | f | semmle.label | f | -| test.ps1:8:1:8:6 | [post] arr1 [element 3] | semmle.label | [post] arr1 [element 3] | -| test.ps1:8:1:8:6 | [post] arr1 [element 3] | semmle.label | [post] arr1 [element 3] | -| test.ps1:8:12:8:22 | call to Source | semmle.label | call to Source | -| test.ps1:9:6:9:11 | arr1 [element 3] | semmle.label | arr1 [element 3] | -| test.ps1:9:6:9:11 | arr1 [element 3] | semmle.label | arr1 [element 3] | -| test.ps1:9:6:9:14 | ...[...] | semmle.label | ...[...] | -| test.ps1:12:1:12:6 | [post] arr2 [element] | semmle.label | [post] arr2 [element] | -| test.ps1:12:19:12:29 | call to Source | semmle.label | call to Source | -| test.ps1:13:6:13:11 | arr2 [element] | semmle.label | arr2 [element] | -| test.ps1:13:6:13:14 | ...[...] | semmle.label | ...[...] | -| test.ps1:15:1:15:6 | [post] arr3 [element 3] | semmle.label | [post] arr3 [element 3] | -| test.ps1:15:1:15:6 | [post] arr3 [element 3] | semmle.label | [post] arr3 [element 3] | -| test.ps1:15:12:15:22 | call to Source | semmle.label | call to Source | -| test.ps1:16:6:16:11 | arr3 [element 3] | semmle.label | arr3 [element 3] | -| test.ps1:16:6:16:11 | arr3 [element 3] | semmle.label | arr3 [element 3] | -| test.ps1:16:6:16:21 | ...[...] | semmle.label | ...[...] | -| test.ps1:18:1:18:6 | [post] arr4 [element] | semmle.label | [post] arr4 [element] | -| test.ps1:18:20:18:30 | call to Source | semmle.label | call to Source | -| test.ps1:19:6:19:11 | arr4 [element] | semmle.label | arr4 [element] | -| test.ps1:19:6:19:22 | ...[...] | semmle.label | ...[...] | -| test.ps1:21:1:21:6 | [post] arr5 [element, element 1] | semmle.label | [post] arr5 [element, element 1] | -| test.ps1:21:1:21:6 | [post] arr5 [element, element 1] | semmle.label | [post] arr5 [element, element 1] | -| test.ps1:21:1:21:17 | [post] ...[...] [element 1] | semmle.label | [post] ...[...] [element 1] | -| test.ps1:21:1:21:17 | [post] ...[...] [element 1] | semmle.label | [post] ...[...] [element 1] | -| test.ps1:21:23:21:33 | call to Source | semmle.label | call to Source | -| test.ps1:22:6:22:11 | arr5 [element, element 1] | semmle.label | arr5 [element, element 1] | -| test.ps1:22:6:22:11 | arr5 [element, element 1] | semmle.label | arr5 [element, element 1] | -| test.ps1:22:6:22:22 | ...[...] [element 1] | semmle.label | ...[...] [element 1] | -| test.ps1:22:6:22:22 | ...[...] [element 1] | semmle.label | ...[...] [element 1] | -| test.ps1:22:6:22:25 | ...[...] | semmle.label | ...[...] | -| test.ps1:25:1:25:6 | [post] arr6 [element 1, element] | semmle.label | [post] arr6 [element 1, element] | -| test.ps1:25:1:25:6 | [post] arr6 [element 1, element] | semmle.label | [post] arr6 [element 1, element] | -| test.ps1:25:1:25:9 | [post] ...[...] [element] | semmle.label | [post] ...[...] [element] | -| test.ps1:25:23:25:33 | call to Source | semmle.label | call to Source | -| test.ps1:26:6:26:11 | arr6 [element 1, element] | semmle.label | arr6 [element 1, element] | -| test.ps1:26:6:26:11 | arr6 [element 1, element] | semmle.label | arr6 [element 1, element] | -| test.ps1:26:6:26:14 | ...[...] [element] | semmle.label | ...[...] [element] | -| test.ps1:26:6:26:25 | ...[...] | semmle.label | ...[...] | -| test.ps1:29:1:29:6 | [post] arr7 [element, element] | semmle.label | [post] arr7 [element, element] | -| test.ps1:29:1:29:17 | [post] ...[...] [element] | semmle.label | [post] ...[...] [element] | -| test.ps1:29:31:29:41 | call to Source | semmle.label | call to Source | -| test.ps1:30:6:30:11 | arr7 [element, element] | semmle.label | arr7 [element, element] | -| test.ps1:30:6:30:14 | ...[...] [element] | semmle.label | ...[...] [element] | -| test.ps1:30:6:30:17 | ...[...] | semmle.label | ...[...] | -| test.ps1:31:6:31:11 | arr7 [element, element] | semmle.label | arr7 [element, element] | -| test.ps1:31:6:31:22 | ...[...] [element] | semmle.label | ...[...] [element] | -| test.ps1:31:6:31:33 | ...[...] | semmle.label | ...[...] | -| test.ps1:33:6:33:17 | call to Source | semmle.label | call to Source | -| test.ps1:35:9:35:17 | ...,... [element 2] | semmle.label | ...,... [element 2] | -| test.ps1:35:15:35:17 | x | semmle.label | x | -| test.ps1:38:6:38:11 | arr8 [element 2] | semmle.label | arr8 [element 2] | -| test.ps1:38:6:38:14 | ...[...] | semmle.label | ...[...] | -| test.ps1:39:6:39:11 | arr8 [element 2] | semmle.label | arr8 [element 2] | -| test.ps1:39:6:39:21 | ...[...] | semmle.label | ...[...] | -| test.ps1:41:6:41:17 | call to Source | semmle.label | call to Source | -| test.ps1:43:11:43:19 | ...,... [element 2] | semmle.label | ...,... [element 2] | -| test.ps1:43:17:43:19 | y | semmle.label | y | -| test.ps1:46:6:46:11 | arr9 [element 2] | semmle.label | arr9 [element 2] | -| test.ps1:46:6:46:14 | ...[...] | semmle.label | ...[...] | -| test.ps1:47:6:47:11 | arr9 [element 2] | semmle.label | arr9 [element 2] | -| test.ps1:47:6:47:21 | ...[...] | semmle.label | ...[...] | -| test.ps1:52:22:54:6 | this [field] | semmle.label | this [field] | -| test.ps1:53:14:53:19 | this [field] | semmle.label | this [field] | -| test.ps1:53:14:53:25 | field | semmle.label | field | -| test.ps1:59:1:59:9 | [post] myClass [field] | semmle.label | [post] myClass [field] | -| test.ps1:59:18:59:29 | call to Source | semmle.label | call to Source | -| test.ps1:61:1:61:9 | myClass [field] | semmle.label | myClass [field] | -| test.ps1:64:10:64:21 | call to Source | semmle.label | call to Source | -| test.ps1:65:10:65:21 | call to Source | semmle.label | call to Source | -| test.ps1:66:10:66:21 | call to Source | semmle.label | call to Source | -| test.ps1:67:5:67:7 | x | semmle.label | x | -| test.ps1:68:5:68:7 | y | semmle.label | y | -| test.ps1:68:5:68:11 | ...,... [element 0] | semmle.label | ...,... [element 0] | -| test.ps1:68:5:68:11 | ...,... [element 1] | semmle.label | ...,... [element 1] | -| test.ps1:68:9:68:11 | z | semmle.label | z | -| test.ps1:71:6:71:13 | call to produce [element] | semmle.label | call to produce [element] | -| test.ps1:72:6:72:8 | x [element] | semmle.label | x [element] | -| test.ps1:72:6:72:11 | ...[...] | semmle.label | ...[...] | -| test.ps1:73:6:73:8 | x [element] | semmle.label | x [element] | -| test.ps1:73:6:73:11 | ...[...] | semmle.label | ...[...] | -| test.ps1:74:6:74:8 | x [element] | semmle.label | x [element] | -| test.ps1:74:6:74:11 | ...[...] | semmle.label | ...[...] | -| test.ps1:76:9:79:2 | ${...} [element a] | semmle.label | ${...} [element a] | -| test.ps1:77:7:77:18 | call to Source | semmle.label | call to Source | -| test.ps1:81:6:81:11 | hash [element a] | semmle.label | hash [element a] | -| test.ps1:81:6:81:16 | ...[...] | semmle.label | ...[...] | -| test.ps1:85:6:85:11 | hash [element a] | semmle.label | hash [element a] | -| test.ps1:85:6:85:16 | ...[...] | semmle.label | ...[...] | -| test.ps1:86:1:86:6 | [post] hash [b] | semmle.label | [post] hash [b] | -| test.ps1:86:11:86:22 | call to Source | semmle.label | call to Source | -| test.ps1:87:6:87:11 | hash [b] | semmle.label | hash [b] | -| test.ps1:87:6:87:13 | b | semmle.label | b | +| test.ps1:3:1:3:2 | [post] a [f] | semmle.label | [post] a [f] | +| test.ps1:3:8:3:17 | Call to Source | semmle.label | Call to Source | +| test.ps1:4:6:4:7 | a [f] | semmle.label | a [f] | +| test.ps1:4:6:4:9 | f | semmle.label | f | +| test.ps1:10:1:10:5 | [post] arr1 [element 3] | semmle.label | [post] arr1 [element 3] | +| test.ps1:10:12:10:21 | Call to Source | semmle.label | Call to Source | +| test.ps1:11:6:11:10 | arr1 [element 3] | semmle.label | arr1 [element 3] | +| test.ps1:11:6:11:13 | ...[...] | semmle.label | ...[...] | +| test.ps1:14:1:14:5 | [post] arr2 [element] | semmle.label | [post] arr2 [element] | +| test.ps1:14:19:14:28 | Call to Source | semmle.label | Call to Source | +| test.ps1:15:6:15:10 | arr2 [element] | semmle.label | arr2 [element] | +| test.ps1:15:6:15:13 | ...[...] | semmle.label | ...[...] | +| test.ps1:17:1:17:5 | [post] arr3 [element 3] | semmle.label | [post] arr3 [element 3] | +| test.ps1:17:12:17:21 | Call to Source | semmle.label | Call to Source | +| test.ps1:18:6:18:10 | arr3 [element 3] | semmle.label | arr3 [element 3] | +| test.ps1:18:6:18:20 | ...[...] | semmle.label | ...[...] | +| test.ps1:20:1:20:5 | [post] arr4 [element] | semmle.label | [post] arr4 [element] | +| test.ps1:20:20:20:29 | Call to Source | semmle.label | Call to Source | +| test.ps1:21:6:21:10 | arr4 [element] | semmle.label | arr4 [element] | +| test.ps1:21:6:21:21 | ...[...] | semmle.label | ...[...] | +| test.ps1:23:1:23:5 | [post] arr5 [element, element 1] | semmle.label | [post] arr5 [element, element 1] | +| test.ps1:23:1:23:16 | [post] ...[...] [element 1] | semmle.label | [post] ...[...] [element 1] | +| test.ps1:23:23:23:32 | Call to Source | semmle.label | Call to Source | +| test.ps1:24:6:24:10 | arr5 [element, element 1] | semmle.label | arr5 [element, element 1] | +| test.ps1:24:6:24:21 | ...[...] [element 1] | semmle.label | ...[...] [element 1] | +| test.ps1:24:6:24:24 | ...[...] | semmle.label | ...[...] | +| test.ps1:27:1:27:5 | [post] arr6 [element 1, element] | semmle.label | [post] arr6 [element 1, element] | +| test.ps1:27:1:27:8 | [post] ...[...] [element] | semmle.label | [post] ...[...] [element] | +| test.ps1:27:23:27:32 | Call to Source | semmle.label | Call to Source | +| test.ps1:28:6:28:10 | arr6 [element 1, element] | semmle.label | arr6 [element 1, element] | +| test.ps1:28:6:28:13 | ...[...] [element] | semmle.label | ...[...] [element] | +| test.ps1:28:6:28:24 | ...[...] | semmle.label | ...[...] | +| test.ps1:31:1:31:5 | [post] arr7 [element, element] | semmle.label | [post] arr7 [element, element] | +| test.ps1:31:1:31:16 | [post] ...[...] [element] | semmle.label | [post] ...[...] [element] | +| test.ps1:31:31:31:40 | Call to Source | semmle.label | Call to Source | +| test.ps1:32:6:32:10 | arr7 [element, element] | semmle.label | arr7 [element, element] | +| test.ps1:32:6:32:13 | ...[...] [element] | semmle.label | ...[...] [element] | +| test.ps1:32:6:32:16 | ...[...] | semmle.label | ...[...] | +| test.ps1:33:6:33:10 | arr7 [element, element] | semmle.label | arr7 [element, element] | +| test.ps1:33:6:33:21 | ...[...] [element] | semmle.label | ...[...] [element] | +| test.ps1:33:6:33:32 | ...[...] | semmle.label | ...[...] | +| test.ps1:35:6:35:16 | Call to Source | semmle.label | Call to Source | +| test.ps1:37:9:37:16 | ...,... [element 2] | semmle.label | ...,... [element 2] | +| test.ps1:37:15:37:16 | x | semmle.label | x | +| test.ps1:40:6:40:10 | arr8 [element 2] | semmle.label | arr8 [element 2] | +| test.ps1:40:6:40:13 | ...[...] | semmle.label | ...[...] | +| test.ps1:41:6:41:10 | arr8 [element 2] | semmle.label | arr8 [element 2] | +| test.ps1:41:6:41:20 | ...[...] | semmle.label | ...[...] | +| test.ps1:43:6:43:16 | Call to Source | semmle.label | Call to Source | +| test.ps1:45:11:45:18 | ...,... [element 2] | semmle.label | ...,... [element 2] | +| test.ps1:45:17:45:18 | y | semmle.label | y | +| test.ps1:48:6:48:10 | arr9 [element 2] | semmle.label | arr9 [element 2] | +| test.ps1:48:6:48:13 | ...[...] | semmle.label | ...[...] | +| test.ps1:49:6:49:10 | arr9 [element 2] | semmle.label | arr9 [element 2] | +| test.ps1:49:6:49:20 | ...[...] | semmle.label | ...[...] | +| test.ps1:88:1:88:5 | [post] hash [b] | semmle.label | [post] hash [b] | +| test.ps1:88:11:88:21 | Call to Source | semmle.label | Call to Source | +| test.ps1:89:6:89:10 | hash [b] | semmle.label | hash [b] | +| test.ps1:89:6:89:12 | b | semmle.label | b | subpaths testFailures +| test.ps1:55:26:55:44 | # $ hasValueFlow=12 | Missing result: hasValueFlow=12 | +| test.ps1:74:12:74:62 | # $ hasValueFlow=13 hasValueFlow=14 hasValueFlow=15 | Missing result: hasValueFlow=13 | +| test.ps1:74:12:74:62 | # $ hasValueFlow=13 hasValueFlow=14 hasValueFlow=15 | Missing result: hasValueFlow=14 | +| test.ps1:74:12:74:62 | # $ hasValueFlow=13 hasValueFlow=14 hasValueFlow=15 | Missing result: hasValueFlow=15 | +| test.ps1:75:12:75:62 | # $ hasValueFlow=13 hasValueFlow=14 hasValueFlow=15 | Missing result: hasValueFlow=13 | +| test.ps1:75:12:75:62 | # $ hasValueFlow=13 hasValueFlow=14 hasValueFlow=15 | Missing result: hasValueFlow=14 | +| test.ps1:75:12:75:62 | # $ hasValueFlow=13 hasValueFlow=14 hasValueFlow=15 | Missing result: hasValueFlow=15 | +| test.ps1:76:12:76:62 | # $ hasValueFlow=13 hasValueFlow=14 hasValueFlow=15 | Missing result: hasValueFlow=13 | +| test.ps1:76:12:76:62 | # $ hasValueFlow=13 hasValueFlow=14 hasValueFlow=15 | Missing result: hasValueFlow=14 | +| test.ps1:76:12:76:62 | # $ hasValueFlow=13 hasValueFlow=14 hasValueFlow=15 | Missing result: hasValueFlow=15 | +| test.ps1:83:17:83:35 | # $ hasValueFlow=16 | Missing result: hasValueFlow=16 | +| test.ps1:87:17:87:45 | # $ SPURIOUS: hasValueFlow=16 | Fixed spurious result: hasValueFlow=16 | #select -| test.ps1:2:6:2:10 | f | test.ps1:1:8:1:18 | call to Source | test.ps1:2:6:2:10 | f | $@ | test.ps1:1:8:1:18 | call to Source | call to Source | -| test.ps1:9:6:9:14 | ...[...] | test.ps1:8:12:8:22 | call to Source | test.ps1:9:6:9:14 | ...[...] | $@ | test.ps1:8:12:8:22 | call to Source | call to Source | -| test.ps1:13:6:13:14 | ...[...] | test.ps1:12:19:12:29 | call to Source | test.ps1:13:6:13:14 | ...[...] | $@ | test.ps1:12:19:12:29 | call to Source | call to Source | -| test.ps1:16:6:16:21 | ...[...] | test.ps1:15:12:15:22 | call to Source | test.ps1:16:6:16:21 | ...[...] | $@ | test.ps1:15:12:15:22 | call to Source | call to Source | -| test.ps1:19:6:19:22 | ...[...] | test.ps1:18:20:18:30 | call to Source | test.ps1:19:6:19:22 | ...[...] | $@ | test.ps1:18:20:18:30 | call to Source | call to Source | -| test.ps1:22:6:22:25 | ...[...] | test.ps1:21:23:21:33 | call to Source | test.ps1:22:6:22:25 | ...[...] | $@ | test.ps1:21:23:21:33 | call to Source | call to Source | -| test.ps1:26:6:26:25 | ...[...] | test.ps1:25:23:25:33 | call to Source | test.ps1:26:6:26:25 | ...[...] | $@ | test.ps1:25:23:25:33 | call to Source | call to Source | -| test.ps1:30:6:30:17 | ...[...] | test.ps1:29:31:29:41 | call to Source | test.ps1:30:6:30:17 | ...[...] | $@ | test.ps1:29:31:29:41 | call to Source | call to Source | -| test.ps1:31:6:31:33 | ...[...] | test.ps1:29:31:29:41 | call to Source | test.ps1:31:6:31:33 | ...[...] | $@ | test.ps1:29:31:29:41 | call to Source | call to Source | -| test.ps1:38:6:38:14 | ...[...] | test.ps1:33:6:33:17 | call to Source | test.ps1:38:6:38:14 | ...[...] | $@ | test.ps1:33:6:33:17 | call to Source | call to Source | -| test.ps1:39:6:39:21 | ...[...] | test.ps1:33:6:33:17 | call to Source | test.ps1:39:6:39:21 | ...[...] | $@ | test.ps1:33:6:33:17 | call to Source | call to Source | -| test.ps1:46:6:46:14 | ...[...] | test.ps1:41:6:41:17 | call to Source | test.ps1:46:6:46:14 | ...[...] | $@ | test.ps1:41:6:41:17 | call to Source | call to Source | -| test.ps1:47:6:47:21 | ...[...] | test.ps1:41:6:41:17 | call to Source | test.ps1:47:6:47:21 | ...[...] | $@ | test.ps1:41:6:41:17 | call to Source | call to Source | -| test.ps1:53:14:53:25 | field | test.ps1:59:18:59:29 | call to Source | test.ps1:53:14:53:25 | field | $@ | test.ps1:59:18:59:29 | call to Source | call to Source | -| test.ps1:72:6:72:11 | ...[...] | test.ps1:64:10:64:21 | call to Source | test.ps1:72:6:72:11 | ...[...] | $@ | test.ps1:64:10:64:21 | call to Source | call to Source | -| test.ps1:72:6:72:11 | ...[...] | test.ps1:65:10:65:21 | call to Source | test.ps1:72:6:72:11 | ...[...] | $@ | test.ps1:65:10:65:21 | call to Source | call to Source | -| test.ps1:72:6:72:11 | ...[...] | test.ps1:66:10:66:21 | call to Source | test.ps1:72:6:72:11 | ...[...] | $@ | test.ps1:66:10:66:21 | call to Source | call to Source | -| test.ps1:73:6:73:11 | ...[...] | test.ps1:64:10:64:21 | call to Source | test.ps1:73:6:73:11 | ...[...] | $@ | test.ps1:64:10:64:21 | call to Source | call to Source | -| test.ps1:73:6:73:11 | ...[...] | test.ps1:65:10:65:21 | call to Source | test.ps1:73:6:73:11 | ...[...] | $@ | test.ps1:65:10:65:21 | call to Source | call to Source | -| test.ps1:73:6:73:11 | ...[...] | test.ps1:66:10:66:21 | call to Source | test.ps1:73:6:73:11 | ...[...] | $@ | test.ps1:66:10:66:21 | call to Source | call to Source | -| test.ps1:74:6:74:11 | ...[...] | test.ps1:64:10:64:21 | call to Source | test.ps1:74:6:74:11 | ...[...] | $@ | test.ps1:64:10:64:21 | call to Source | call to Source | -| test.ps1:74:6:74:11 | ...[...] | test.ps1:65:10:65:21 | call to Source | test.ps1:74:6:74:11 | ...[...] | $@ | test.ps1:65:10:65:21 | call to Source | call to Source | -| test.ps1:74:6:74:11 | ...[...] | test.ps1:66:10:66:21 | call to Source | test.ps1:74:6:74:11 | ...[...] | $@ | test.ps1:66:10:66:21 | call to Source | call to Source | -| test.ps1:81:6:81:16 | ...[...] | test.ps1:77:7:77:18 | call to Source | test.ps1:81:6:81:16 | ...[...] | $@ | test.ps1:77:7:77:18 | call to Source | call to Source | -| test.ps1:85:6:85:16 | ...[...] | test.ps1:77:7:77:18 | call to Source | test.ps1:85:6:85:16 | ...[...] | $@ | test.ps1:77:7:77:18 | call to Source | call to Source | -| test.ps1:87:6:87:13 | b | test.ps1:86:11:86:22 | call to Source | test.ps1:87:6:87:13 | b | $@ | test.ps1:86:11:86:22 | call to Source | call to Source | +| test.ps1:4:6:4:9 | f | test.ps1:3:8:3:17 | Call to Source | test.ps1:4:6:4:9 | f | $@ | test.ps1:3:8:3:17 | Call to Source | Call to Source | +| test.ps1:11:6:11:13 | ...[...] | test.ps1:10:12:10:21 | Call to Source | test.ps1:11:6:11:13 | ...[...] | $@ | test.ps1:10:12:10:21 | Call to Source | Call to Source | +| test.ps1:15:6:15:13 | ...[...] | test.ps1:14:19:14:28 | Call to Source | test.ps1:15:6:15:13 | ...[...] | $@ | test.ps1:14:19:14:28 | Call to Source | Call to Source | +| test.ps1:18:6:18:20 | ...[...] | test.ps1:17:12:17:21 | Call to Source | test.ps1:18:6:18:20 | ...[...] | $@ | test.ps1:17:12:17:21 | Call to Source | Call to Source | +| test.ps1:21:6:21:21 | ...[...] | test.ps1:20:20:20:29 | Call to Source | test.ps1:21:6:21:21 | ...[...] | $@ | test.ps1:20:20:20:29 | Call to Source | Call to Source | +| test.ps1:24:6:24:24 | ...[...] | test.ps1:23:23:23:32 | Call to Source | test.ps1:24:6:24:24 | ...[...] | $@ | test.ps1:23:23:23:32 | Call to Source | Call to Source | +| test.ps1:28:6:28:24 | ...[...] | test.ps1:27:23:27:32 | Call to Source | test.ps1:28:6:28:24 | ...[...] | $@ | test.ps1:27:23:27:32 | Call to Source | Call to Source | +| test.ps1:32:6:32:16 | ...[...] | test.ps1:31:31:31:40 | Call to Source | test.ps1:32:6:32:16 | ...[...] | $@ | test.ps1:31:31:31:40 | Call to Source | Call to Source | +| test.ps1:33:6:33:32 | ...[...] | test.ps1:31:31:31:40 | Call to Source | test.ps1:33:6:33:32 | ...[...] | $@ | test.ps1:31:31:31:40 | Call to Source | Call to Source | +| test.ps1:40:6:40:13 | ...[...] | test.ps1:35:6:35:16 | Call to Source | test.ps1:40:6:40:13 | ...[...] | $@ | test.ps1:35:6:35:16 | Call to Source | Call to Source | +| test.ps1:41:6:41:20 | ...[...] | test.ps1:35:6:35:16 | Call to Source | test.ps1:41:6:41:20 | ...[...] | $@ | test.ps1:35:6:35:16 | Call to Source | Call to Source | +| test.ps1:48:6:48:13 | ...[...] | test.ps1:43:6:43:16 | Call to Source | test.ps1:48:6:48:13 | ...[...] | $@ | test.ps1:43:6:43:16 | Call to Source | Call to Source | +| test.ps1:49:6:49:20 | ...[...] | test.ps1:43:6:43:16 | Call to Source | test.ps1:49:6:49:20 | ...[...] | $@ | test.ps1:43:6:43:16 | Call to Source | Call to Source | +| test.ps1:89:6:89:12 | b | test.ps1:88:11:88:21 | Call to Source | test.ps1:89:6:89:12 | b | $@ | test.ps1:88:11:88:21 | Call to Source | Call to Source | diff --git a/powershell/ql/test/library-tests/dataflow/fields/test.ps1 b/powershell/ql/test/library-tests/dataflow/fields/test.ps1 index a73c4fb79f38..fcd375c0516b 100644 --- a/powershell/ql/test/library-tests/dataflow/fields/test.ps1 +++ b/powershell/ql/test/library-tests/dataflow/fields/test.ps1 @@ -1,3 +1,5 @@ +param($a, $arr1, $arr2, $arr3, $arr4, $arr5, $arr6, $arr7, $arr8, $arr9, $unknown, $unknown1, $unknown2, $unknown3, $unknown4, $unknown5, $unknown6, $unknown7, $unknown8) + $a.f = Source "1" Sink $a.f # $ hasValueFlow=1 diff --git a/powershell/ql/test/library-tests/dataflow/local/flow.expected b/powershell/ql/test/library-tests/dataflow/local/flow.expected index 96670d797bb4..080873884dfe 100644 --- a/powershell/ql/test/library-tests/dataflow/local/flow.expected +++ b/powershell/ql/test/library-tests/dataflow/local/flow.expected @@ -1,56 +1,51 @@ -| test.ps1:1:1:1:4 | a1 | test.ps1:2:6:2:9 | a1 | -| test.ps1:1:7:1:13 | call to Source | test.ps1:1:1:1:4 | a1 | -| test.ps1:1:7:1:13 | call to Source | test.ps1:1:1:1:13 | ...=... | -| test.ps1:2:1:2:9 | call to Sink | test.ps1:2:1:2:9 | pre-return value for call to Sink | -| test.ps1:2:1:2:9 | call to Sink | test.ps1:2:1:2:9 | pre-return value for call to Sink | -| test.ps1:2:1:2:9 | implicit unwrapping of call to Sink | test.ps1:1:1:21:28 | return value for test.ps1 | -| test.ps1:2:1:2:9 | pre-return value for call to Sink | test.ps1:2:1:2:9 | implicit unwrapping of call to Sink | -| test.ps1:4:1:4:3 | b | test.ps1:5:4:5:6 | b | -| test.ps1:4:6:4:13 | call to GetBool | test.ps1:4:1:4:3 | b | -| test.ps1:4:6:4:13 | call to GetBool | test.ps1:4:1:4:13 | ...=... | -| test.ps1:5:4:5:6 | b | test.ps1:10:14:10:16 | b | -| test.ps1:6:5:6:8 | a2 | test.ps1:8:6:8:9 | a2 | -| test.ps1:6:11:6:17 | call to Source | test.ps1:6:5:6:8 | a2 | -| test.ps1:6:11:6:17 | call to Source | test.ps1:6:5:6:17 | ...=... | -| test.ps1:8:1:8:9 | call to Sink | test.ps1:8:1:8:9 | pre-return value for call to Sink | -| test.ps1:8:1:8:9 | call to Sink | test.ps1:8:1:8:9 | pre-return value for call to Sink | -| test.ps1:8:1:8:9 | implicit unwrapping of call to Sink | test.ps1:1:1:21:28 | return value for test.ps1 | -| test.ps1:8:1:8:9 | pre-return value for call to Sink | test.ps1:8:1:8:9 | implicit unwrapping of call to Sink | -| test.ps1:10:1:10:3 | c | test.ps1:11:6:11:8 | c | -| test.ps1:10:6:10:16 | [...]... | test.ps1:10:1:10:3 | c | -| test.ps1:10:6:10:16 | [...]... | test.ps1:10:1:10:16 | ...=... | -| test.ps1:10:6:10:16 | [...]... | test.ps1:10:6:10:16 | [...]... | -| test.ps1:10:14:10:16 | b | test.ps1:10:6:10:16 | [...]... | -| test.ps1:11:1:11:8 | call to Sink | test.ps1:11:1:11:8 | pre-return value for call to Sink | -| test.ps1:11:1:11:8 | call to Sink | test.ps1:11:1:11:8 | pre-return value for call to Sink | -| test.ps1:11:1:11:8 | implicit unwrapping of call to Sink | test.ps1:1:1:21:28 | return value for test.ps1 | -| test.ps1:11:1:11:8 | pre-return value for call to Sink | test.ps1:11:1:11:8 | implicit unwrapping of call to Sink | -| test.ps1:11:6:11:8 | [post] c | test.ps1:13:7:13:9 | c | -| test.ps1:11:6:11:8 | c | test.ps1:13:7:13:9 | c | -| test.ps1:13:1:13:3 | d | test.ps1:14:6:14:8 | d | -| test.ps1:13:6:13:10 | (...) | test.ps1:13:1:13:3 | d | -| test.ps1:13:6:13:10 | (...) | test.ps1:13:1:13:10 | ...=... | -| test.ps1:13:6:13:10 | (...) | test.ps1:13:6:13:10 | (...) | -| test.ps1:13:7:13:9 | c | test.ps1:13:6:13:10 | (...) | -| test.ps1:13:7:13:9 | c | test.ps1:13:7:13:9 | c | -| test.ps1:14:1:14:8 | call to Sink | test.ps1:14:1:14:8 | pre-return value for call to Sink | -| test.ps1:14:1:14:8 | call to Sink | test.ps1:14:1:14:8 | pre-return value for call to Sink | -| test.ps1:14:1:14:8 | implicit unwrapping of call to Sink | test.ps1:1:1:21:28 | return value for test.ps1 | -| test.ps1:14:1:14:8 | pre-return value for call to Sink | test.ps1:14:1:14:8 | implicit unwrapping of call to Sink | -| test.ps1:14:6:14:8 | [post] d | test.ps1:16:6:16:8 | d | -| test.ps1:14:6:14:8 | d | test.ps1:16:6:16:8 | d | -| test.ps1:16:1:16:3 | e | test.ps1:17:6:17:8 | e | -| test.ps1:16:6:16:12 | ...+... | test.ps1:16:1:16:3 | e | -| test.ps1:16:6:16:12 | ...+... | test.ps1:16:1:16:12 | ...=... | -| test.ps1:16:6:16:12 | ...+... | test.ps1:16:6:16:12 | ...+... | -| test.ps1:17:1:17:8 | call to Sink | test.ps1:17:1:17:8 | pre-return value for call to Sink | -| test.ps1:17:1:17:8 | call to Sink | test.ps1:17:1:17:8 | pre-return value for call to Sink | -| test.ps1:17:1:17:8 | implicit unwrapping of call to Sink | test.ps1:1:1:21:28 | return value for test.ps1 | -| test.ps1:17:1:17:8 | pre-return value for call to Sink | test.ps1:17:1:17:8 | implicit unwrapping of call to Sink | -| test.ps1:19:1:19:3 | f | test.ps1:21:25:21:27 | f | -| test.ps1:19:6:19:12 | call to Source | test.ps1:19:1:19:3 | f | -| test.ps1:19:6:19:12 | call to Source | test.ps1:19:1:19:12 | ...=... | -| test.ps1:21:1:21:28 | call to Sink | test.ps1:21:1:21:28 | pre-return value for call to Sink | -| test.ps1:21:1:21:28 | call to Sink | test.ps1:21:1:21:28 | pre-return value for call to Sink | -| test.ps1:21:1:21:28 | implicit unwrapping of call to Sink | test.ps1:1:1:21:28 | return value for test.ps1 | -| test.ps1:21:1:21:28 | pre-return value for call to Sink | test.ps1:21:1:21:28 | implicit unwrapping of call to Sink | +| test.ps1:1:1:1:3 | a1 | test.ps1:2:6:2:8 | a1 | +| test.ps1:1:7:1:12 | Call to Source | test.ps1:1:1:1:3 | a1 | +| test.ps1:2:1:2:8 | Call to Sink | test.ps1:2:1:2:8 | pre-return value for Call to Sink | +| test.ps1:2:1:2:8 | Call to Sink | test.ps1:2:1:2:8 | pre-return value for Call to Sink | +| test.ps1:2:1:2:8 | implicit unwrapping of Call to Sink | test.ps1:1:1:21:27 | return value for {...} | +| test.ps1:2:1:2:8 | pre-return value for Call to Sink | test.ps1:2:1:2:8 | implicit unwrapping of Call to Sink | +| test.ps1:4:1:4:2 | b | test.ps1:5:4:5:5 | b | +| test.ps1:4:6:4:12 | Call to GetBool | test.ps1:4:1:4:2 | b | +| test.ps1:5:1:7:1 | if (...) {...} | test.ps1:5:1:7:1 | pre-return value for if (...) {...} | +| test.ps1:5:1:7:1 | if (...) {...} | test.ps1:5:1:7:1 | pre-return value for if (...) {...} | +| test.ps1:5:1:7:1 | implicit unwrapping of if (...) {...} | test.ps1:1:1:21:27 | return value for {...} | +| test.ps1:5:1:7:1 | phi | test.ps1:8:6:8:8 | a2 | +| test.ps1:5:1:7:1 | pre-return value for if (...) {...} | test.ps1:5:1:7:1 | implicit unwrapping of if (...) {...} | +| test.ps1:5:4:5:5 | b | test.ps1:10:14:10:15 | b | +| test.ps1:6:5:6:7 | a2 | test.ps1:6:11:6:16 | [input] phi | +| test.ps1:6:11:6:16 | Call to Source | test.ps1:6:5:6:7 | a2 | +| test.ps1:6:11:6:16 | [input] phi | test.ps1:5:1:7:1 | phi | +| test.ps1:8:1:8:8 | Call to Sink | test.ps1:8:1:8:8 | pre-return value for Call to Sink | +| test.ps1:8:1:8:8 | Call to Sink | test.ps1:8:1:8:8 | pre-return value for Call to Sink | +| test.ps1:8:1:8:8 | implicit unwrapping of Call to Sink | test.ps1:1:1:21:27 | return value for {...} | +| test.ps1:8:1:8:8 | pre-return value for Call to Sink | test.ps1:8:1:8:8 | implicit unwrapping of Call to Sink | +| test.ps1:10:1:10:2 | c | test.ps1:11:6:11:7 | c | +| test.ps1:10:6:10:15 | [...]... | test.ps1:10:1:10:2 | c | +| test.ps1:10:14:10:15 | b | test.ps1:10:6:10:15 | [...]... | +| test.ps1:11:1:11:7 | Call to Sink | test.ps1:11:1:11:7 | pre-return value for Call to Sink | +| test.ps1:11:1:11:7 | Call to Sink | test.ps1:11:1:11:7 | pre-return value for Call to Sink | +| test.ps1:11:1:11:7 | implicit unwrapping of Call to Sink | test.ps1:1:1:21:27 | return value for {...} | +| test.ps1:11:1:11:7 | pre-return value for Call to Sink | test.ps1:11:1:11:7 | implicit unwrapping of Call to Sink | +| test.ps1:11:6:11:7 | [post] c | test.ps1:13:7:13:8 | c | +| test.ps1:11:6:11:7 | c | test.ps1:13:7:13:8 | c | +| test.ps1:13:1:13:2 | d | test.ps1:14:6:14:7 | d | +| test.ps1:13:6:13:9 | (...) | test.ps1:13:1:13:2 | d | +| test.ps1:13:7:13:8 | c | test.ps1:13:6:13:9 | (...) | +| test.ps1:14:1:14:7 | Call to Sink | test.ps1:14:1:14:7 | pre-return value for Call to Sink | +| test.ps1:14:1:14:7 | Call to Sink | test.ps1:14:1:14:7 | pre-return value for Call to Sink | +| test.ps1:14:1:14:7 | implicit unwrapping of Call to Sink | test.ps1:1:1:21:27 | return value for {...} | +| test.ps1:14:1:14:7 | pre-return value for Call to Sink | test.ps1:14:1:14:7 | implicit unwrapping of Call to Sink | +| test.ps1:14:6:14:7 | [post] d | test.ps1:16:6:16:7 | d | +| test.ps1:14:6:14:7 | d | test.ps1:16:6:16:7 | d | +| test.ps1:16:1:16:2 | e | test.ps1:17:6:17:7 | e | +| test.ps1:16:6:16:11 | ...+... | test.ps1:16:1:16:2 | e | +| test.ps1:17:1:17:7 | Call to Sink | test.ps1:17:1:17:7 | pre-return value for Call to Sink | +| test.ps1:17:1:17:7 | Call to Sink | test.ps1:17:1:17:7 | pre-return value for Call to Sink | +| test.ps1:17:1:17:7 | implicit unwrapping of Call to Sink | test.ps1:1:1:21:27 | return value for {...} | +| test.ps1:17:1:17:7 | pre-return value for Call to Sink | test.ps1:17:1:17:7 | implicit unwrapping of Call to Sink | +| test.ps1:19:1:19:2 | f | test.ps1:21:25:21:26 | f | +| test.ps1:19:6:19:11 | Call to Source | test.ps1:19:1:19:2 | f | +| test.ps1:21:1:21:27 | Call to Sink | test.ps1:21:1:21:27 | pre-return value for Call to Sink | +| test.ps1:21:1:21:27 | Call to Sink | test.ps1:21:1:21:27 | pre-return value for Call to Sink | +| test.ps1:21:1:21:27 | implicit unwrapping of Call to Sink | test.ps1:1:1:21:27 | return value for {...} | +| test.ps1:21:1:21:27 | pre-return value for Call to Sink | test.ps1:21:1:21:27 | implicit unwrapping of Call to Sink | diff --git a/powershell/ql/test/library-tests/dataflow/local/taint.expected b/powershell/ql/test/library-tests/dataflow/local/taint.expected index 923c723a31f8..5a68287270e1 100644 --- a/powershell/ql/test/library-tests/dataflow/local/taint.expected +++ b/powershell/ql/test/library-tests/dataflow/local/taint.expected @@ -1,65 +1,61 @@ -| test.ps1:1:1:1:4 | a1 | test.ps1:2:6:2:9 | a1 | -| test.ps1:1:7:1:13 | call to Source | test.ps1:1:1:1:4 | a1 | -| test.ps1:1:7:1:13 | call to Source | test.ps1:1:1:1:13 | ...=... | -| test.ps1:2:1:2:9 | call to Sink | test.ps1:2:1:2:9 | pre-return value for call to Sink | -| test.ps1:2:1:2:9 | call to Sink | test.ps1:2:1:2:9 | pre-return value for call to Sink | -| test.ps1:2:1:2:9 | implicit unwrapping of call to Sink | test.ps1:1:1:21:28 | return value for test.ps1 | -| test.ps1:2:1:2:9 | pre-return value for call to Sink | test.ps1:2:1:2:9 | implicit unwrapping of call to Sink | -| test.ps1:2:1:2:9 | pre-return value for call to Sink | test.ps1:2:1:2:9 | implicit unwrapping of call to Sink | -| test.ps1:4:1:4:3 | b | test.ps1:5:4:5:6 | b | -| test.ps1:4:6:4:13 | call to GetBool | test.ps1:4:1:4:3 | b | -| test.ps1:4:6:4:13 | call to GetBool | test.ps1:4:1:4:13 | ...=... | -| test.ps1:5:4:5:6 | b | test.ps1:10:14:10:16 | b | -| test.ps1:6:5:6:8 | a2 | test.ps1:8:6:8:9 | a2 | -| test.ps1:6:11:6:17 | call to Source | test.ps1:6:5:6:8 | a2 | -| test.ps1:6:11:6:17 | call to Source | test.ps1:6:5:6:17 | ...=... | -| test.ps1:8:1:8:9 | call to Sink | test.ps1:8:1:8:9 | pre-return value for call to Sink | -| test.ps1:8:1:8:9 | call to Sink | test.ps1:8:1:8:9 | pre-return value for call to Sink | -| test.ps1:8:1:8:9 | implicit unwrapping of call to Sink | test.ps1:1:1:21:28 | return value for test.ps1 | -| test.ps1:8:1:8:9 | pre-return value for call to Sink | test.ps1:8:1:8:9 | implicit unwrapping of call to Sink | -| test.ps1:8:1:8:9 | pre-return value for call to Sink | test.ps1:8:1:8:9 | implicit unwrapping of call to Sink | -| test.ps1:10:1:10:3 | c | test.ps1:11:6:11:8 | c | -| test.ps1:10:6:10:16 | [...]... | test.ps1:10:1:10:3 | c | -| test.ps1:10:6:10:16 | [...]... | test.ps1:10:1:10:16 | ...=... | -| test.ps1:10:6:10:16 | [...]... | test.ps1:10:6:10:16 | [...]... | -| test.ps1:10:14:10:16 | b | test.ps1:10:6:10:16 | [...]... | -| test.ps1:11:1:11:8 | call to Sink | test.ps1:11:1:11:8 | pre-return value for call to Sink | -| test.ps1:11:1:11:8 | call to Sink | test.ps1:11:1:11:8 | pre-return value for call to Sink | -| test.ps1:11:1:11:8 | implicit unwrapping of call to Sink | test.ps1:1:1:21:28 | return value for test.ps1 | -| test.ps1:11:1:11:8 | pre-return value for call to Sink | test.ps1:11:1:11:8 | implicit unwrapping of call to Sink | -| test.ps1:11:1:11:8 | pre-return value for call to Sink | test.ps1:11:1:11:8 | implicit unwrapping of call to Sink | -| test.ps1:11:6:11:8 | [post] c | test.ps1:13:7:13:9 | c | -| test.ps1:11:6:11:8 | c | test.ps1:13:7:13:9 | c | -| test.ps1:13:1:13:3 | d | test.ps1:14:6:14:8 | d | -| test.ps1:13:6:13:10 | (...) | test.ps1:13:1:13:3 | d | -| test.ps1:13:6:13:10 | (...) | test.ps1:13:1:13:10 | ...=... | -| test.ps1:13:6:13:10 | (...) | test.ps1:13:6:13:10 | (...) | -| test.ps1:13:7:13:9 | c | test.ps1:13:6:13:10 | (...) | -| test.ps1:13:7:13:9 | c | test.ps1:13:7:13:9 | c | -| test.ps1:14:1:14:8 | call to Sink | test.ps1:14:1:14:8 | pre-return value for call to Sink | -| test.ps1:14:1:14:8 | call to Sink | test.ps1:14:1:14:8 | pre-return value for call to Sink | -| test.ps1:14:1:14:8 | implicit unwrapping of call to Sink | test.ps1:1:1:21:28 | return value for test.ps1 | -| test.ps1:14:1:14:8 | pre-return value for call to Sink | test.ps1:14:1:14:8 | implicit unwrapping of call to Sink | -| test.ps1:14:1:14:8 | pre-return value for call to Sink | test.ps1:14:1:14:8 | implicit unwrapping of call to Sink | -| test.ps1:14:6:14:8 | [post] d | test.ps1:16:6:16:8 | d | -| test.ps1:14:6:14:8 | d | test.ps1:16:6:16:8 | d | -| test.ps1:16:1:16:3 | e | test.ps1:17:6:17:8 | e | -| test.ps1:16:6:16:8 | d | test.ps1:16:6:16:12 | ...+... | -| test.ps1:16:6:16:12 | ...+... | test.ps1:16:1:16:3 | e | -| test.ps1:16:6:16:12 | ...+... | test.ps1:16:1:16:12 | ...=... | -| test.ps1:16:6:16:12 | ...+... | test.ps1:16:6:16:12 | ...+... | -| test.ps1:16:11:16:12 | 1 | test.ps1:16:6:16:12 | ...+... | -| test.ps1:17:1:17:8 | call to Sink | test.ps1:17:1:17:8 | pre-return value for call to Sink | -| test.ps1:17:1:17:8 | call to Sink | test.ps1:17:1:17:8 | pre-return value for call to Sink | -| test.ps1:17:1:17:8 | implicit unwrapping of call to Sink | test.ps1:1:1:21:28 | return value for test.ps1 | -| test.ps1:17:1:17:8 | pre-return value for call to Sink | test.ps1:17:1:17:8 | implicit unwrapping of call to Sink | -| test.ps1:17:1:17:8 | pre-return value for call to Sink | test.ps1:17:1:17:8 | implicit unwrapping of call to Sink | -| test.ps1:19:1:19:3 | f | test.ps1:21:25:21:27 | f | -| test.ps1:19:6:19:12 | call to Source | test.ps1:19:1:19:3 | f | -| test.ps1:19:6:19:12 | call to Source | test.ps1:19:1:19:12 | ...=... | -| test.ps1:21:1:21:28 | call to Sink | test.ps1:21:1:21:28 | pre-return value for call to Sink | -| test.ps1:21:1:21:28 | call to Sink | test.ps1:21:1:21:28 | pre-return value for call to Sink | -| test.ps1:21:1:21:28 | implicit unwrapping of call to Sink | test.ps1:1:1:21:28 | return value for test.ps1 | -| test.ps1:21:1:21:28 | pre-return value for call to Sink | test.ps1:21:1:21:28 | implicit unwrapping of call to Sink | -| test.ps1:21:1:21:28 | pre-return value for call to Sink | test.ps1:21:1:21:28 | implicit unwrapping of call to Sink | -| test.ps1:21:25:21:27 | f | test.ps1:21:6:21:28 | here is a string: $f | +| test.ps1:1:1:1:3 | a1 | test.ps1:2:6:2:8 | a1 | +| test.ps1:1:7:1:12 | Call to Source | test.ps1:1:1:1:3 | a1 | +| test.ps1:2:1:2:8 | Call to Sink | test.ps1:2:1:2:8 | pre-return value for Call to Sink | +| test.ps1:2:1:2:8 | Call to Sink | test.ps1:2:1:2:8 | pre-return value for Call to Sink | +| test.ps1:2:1:2:8 | implicit unwrapping of Call to Sink | test.ps1:1:1:21:27 | return value for {...} | +| test.ps1:2:1:2:8 | pre-return value for Call to Sink | test.ps1:2:1:2:8 | implicit unwrapping of Call to Sink | +| test.ps1:2:1:2:8 | pre-return value for Call to Sink | test.ps1:2:1:2:8 | implicit unwrapping of Call to Sink | +| test.ps1:4:1:4:2 | b | test.ps1:5:4:5:5 | b | +| test.ps1:4:6:4:12 | Call to GetBool | test.ps1:4:1:4:2 | b | +| test.ps1:5:1:7:1 | if (...) {...} | test.ps1:5:1:7:1 | pre-return value for if (...) {...} | +| test.ps1:5:1:7:1 | if (...) {...} | test.ps1:5:1:7:1 | pre-return value for if (...) {...} | +| test.ps1:5:1:7:1 | implicit unwrapping of if (...) {...} | test.ps1:1:1:21:27 | return value for {...} | +| test.ps1:5:1:7:1 | phi | test.ps1:8:6:8:8 | a2 | +| test.ps1:5:1:7:1 | pre-return value for if (...) {...} | test.ps1:5:1:7:1 | implicit unwrapping of if (...) {...} | +| test.ps1:5:1:7:1 | pre-return value for if (...) {...} | test.ps1:5:1:7:1 | implicit unwrapping of if (...) {...} | +| test.ps1:5:4:5:5 | b | test.ps1:10:14:10:15 | b | +| test.ps1:6:5:6:7 | a2 | test.ps1:6:11:6:16 | [input] phi | +| test.ps1:6:11:6:16 | Call to Source | test.ps1:6:5:6:7 | a2 | +| test.ps1:6:11:6:16 | [input] phi | test.ps1:5:1:7:1 | phi | +| test.ps1:8:1:8:8 | Call to Sink | test.ps1:8:1:8:8 | pre-return value for Call to Sink | +| test.ps1:8:1:8:8 | Call to Sink | test.ps1:8:1:8:8 | pre-return value for Call to Sink | +| test.ps1:8:1:8:8 | implicit unwrapping of Call to Sink | test.ps1:1:1:21:27 | return value for {...} | +| test.ps1:8:1:8:8 | pre-return value for Call to Sink | test.ps1:8:1:8:8 | implicit unwrapping of Call to Sink | +| test.ps1:8:1:8:8 | pre-return value for Call to Sink | test.ps1:8:1:8:8 | implicit unwrapping of Call to Sink | +| test.ps1:10:1:10:2 | c | test.ps1:11:6:11:7 | c | +| test.ps1:10:6:10:15 | [...]... | test.ps1:10:1:10:2 | c | +| test.ps1:10:14:10:15 | b | test.ps1:10:6:10:15 | [...]... | +| test.ps1:11:1:11:7 | Call to Sink | test.ps1:11:1:11:7 | pre-return value for Call to Sink | +| test.ps1:11:1:11:7 | Call to Sink | test.ps1:11:1:11:7 | pre-return value for Call to Sink | +| test.ps1:11:1:11:7 | implicit unwrapping of Call to Sink | test.ps1:1:1:21:27 | return value for {...} | +| test.ps1:11:1:11:7 | pre-return value for Call to Sink | test.ps1:11:1:11:7 | implicit unwrapping of Call to Sink | +| test.ps1:11:1:11:7 | pre-return value for Call to Sink | test.ps1:11:1:11:7 | implicit unwrapping of Call to Sink | +| test.ps1:11:6:11:7 | [post] c | test.ps1:13:7:13:8 | c | +| test.ps1:11:6:11:7 | c | test.ps1:13:7:13:8 | c | +| test.ps1:13:1:13:2 | d | test.ps1:14:6:14:7 | d | +| test.ps1:13:6:13:9 | (...) | test.ps1:13:1:13:2 | d | +| test.ps1:13:7:13:8 | c | test.ps1:13:6:13:9 | (...) | +| test.ps1:14:1:14:7 | Call to Sink | test.ps1:14:1:14:7 | pre-return value for Call to Sink | +| test.ps1:14:1:14:7 | Call to Sink | test.ps1:14:1:14:7 | pre-return value for Call to Sink | +| test.ps1:14:1:14:7 | implicit unwrapping of Call to Sink | test.ps1:1:1:21:27 | return value for {...} | +| test.ps1:14:1:14:7 | pre-return value for Call to Sink | test.ps1:14:1:14:7 | implicit unwrapping of Call to Sink | +| test.ps1:14:1:14:7 | pre-return value for Call to Sink | test.ps1:14:1:14:7 | implicit unwrapping of Call to Sink | +| test.ps1:14:6:14:7 | [post] d | test.ps1:16:6:16:7 | d | +| test.ps1:14:6:14:7 | d | test.ps1:16:6:16:7 | d | +| test.ps1:16:1:16:2 | e | test.ps1:17:6:17:7 | e | +| test.ps1:16:6:16:7 | d | test.ps1:16:6:16:11 | ...+... | +| test.ps1:16:6:16:11 | ...+... | test.ps1:16:1:16:2 | e | +| test.ps1:16:11:16:11 | 1 | test.ps1:16:6:16:11 | ...+... | +| test.ps1:17:1:17:7 | Call to Sink | test.ps1:17:1:17:7 | pre-return value for Call to Sink | +| test.ps1:17:1:17:7 | Call to Sink | test.ps1:17:1:17:7 | pre-return value for Call to Sink | +| test.ps1:17:1:17:7 | implicit unwrapping of Call to Sink | test.ps1:1:1:21:27 | return value for {...} | +| test.ps1:17:1:17:7 | pre-return value for Call to Sink | test.ps1:17:1:17:7 | implicit unwrapping of Call to Sink | +| test.ps1:17:1:17:7 | pre-return value for Call to Sink | test.ps1:17:1:17:7 | implicit unwrapping of Call to Sink | +| test.ps1:19:1:19:2 | f | test.ps1:21:25:21:26 | f | +| test.ps1:19:6:19:11 | Call to Source | test.ps1:19:1:19:2 | f | +| test.ps1:21:1:21:27 | Call to Sink | test.ps1:21:1:21:27 | pre-return value for Call to Sink | +| test.ps1:21:1:21:27 | Call to Sink | test.ps1:21:1:21:27 | pre-return value for Call to Sink | +| test.ps1:21:1:21:27 | implicit unwrapping of Call to Sink | test.ps1:1:1:21:27 | return value for {...} | +| test.ps1:21:1:21:27 | pre-return value for Call to Sink | test.ps1:21:1:21:27 | implicit unwrapping of Call to Sink | +| test.ps1:21:1:21:27 | pre-return value for Call to Sink | test.ps1:21:1:21:27 | implicit unwrapping of Call to Sink | +| test.ps1:21:25:21:26 | f | test.ps1:21:6:21:27 | here is a string: $f | diff --git a/powershell/ql/test/library-tests/dataflow/params/test.expected b/powershell/ql/test/library-tests/dataflow/params/test.expected index 2387ed8cbcf0..d9110ac4f4a6 100644 --- a/powershell/ql/test/library-tests/dataflow/params/test.expected +++ b/powershell/ql/test/library-tests/dataflow/params/test.expected @@ -1,243 +1,243 @@ models edges -| global.ps1:1:7:1:23 | Source1 | global.ps1:3:6:3:14 | Source1 | provenance | | -| global.ps1:1:25:1:41 | Source2 | global.ps1:4:6:4:14 | Source2 | provenance | | -| global.ps1:1:43:1:59 | Source3 | global.ps1:5:6:5:14 | Source3 | provenance | | -| global.ps1:1:61:1:77 | Source4 | global.ps1:6:6:6:14 | Source4 | provenance | | -| test.ps1:1:14:1:16 | a | test.ps1:2:10:2:12 | a | provenance | | -| test.ps1:5:6:5:16 | call to Source | test.ps1:6:5:6:7 | x | provenance | | -| test.ps1:6:5:6:7 | x | test.ps1:1:14:1:16 | a | provenance | | -| test.ps1:8:20:8:22 | x | test.ps1:9:10:9:12 | x | provenance | | -| test.ps1:8:24:8:26 | y | test.ps1:10:10:10:12 | y | provenance | | -| test.ps1:8:28:8:30 | z | test.ps1:11:10:11:12 | z | provenance | | -| test.ps1:14:10:14:20 | call to Source | test.ps1:18:11:18:17 | first | provenance | | -| test.ps1:14:10:14:20 | call to Source | test.ps1:19:22:19:28 | first | provenance | | -| test.ps1:14:10:14:20 | call to Source | test.ps1:20:14:20:20 | first | provenance | | -| test.ps1:14:10:14:20 | call to Source | test.ps1:21:11:21:17 | first | provenance | | -| test.ps1:14:10:14:20 | call to Source | test.ps1:22:22:22:28 | first | provenance | | -| test.ps1:14:10:14:20 | call to Source | test.ps1:23:22:23:28 | first | provenance | | -| test.ps1:14:10:14:20 | call to Source | test.ps1:24:14:24:20 | first | provenance | | -| test.ps1:14:10:14:20 | call to Source | test.ps1:25:11:25:17 | first | provenance | | -| test.ps1:14:10:14:20 | call to Source | test.ps1:26:22:26:28 | first | provenance | | -| test.ps1:14:10:14:20 | call to Source | test.ps1:27:22:27:28 | first | provenance | | -| test.ps1:14:10:14:20 | call to Source | test.ps1:28:14:28:20 | first | provenance | | -| test.ps1:14:10:14:20 | call to Source | test.ps1:29:11:29:17 | first | provenance | | -| test.ps1:14:10:14:20 | call to Source | test.ps1:30:32:30:38 | first | provenance | | -| test.ps1:14:10:14:20 | call to Source | test.ps1:31:32:31:38 | first | provenance | | -| test.ps1:14:10:14:20 | call to Source | test.ps1:32:14:32:20 | first | provenance | | -| test.ps1:14:10:14:20 | call to Source | test.ps1:33:11:33:17 | first | provenance | | -| test.ps1:14:10:14:20 | call to Source | test.ps1:34:32:34:38 | first | provenance | | -| test.ps1:14:10:14:20 | call to Source | test.ps1:35:32:35:38 | first | provenance | | -| test.ps1:14:10:14:20 | call to Source | test.ps1:36:32:36:38 | first | provenance | | -| test.ps1:14:10:14:20 | call to Source | test.ps1:37:24:37:30 | first | provenance | | -| test.ps1:14:10:14:20 | call to Source | test.ps1:38:21:38:27 | first | provenance | | -| test.ps1:14:10:14:20 | call to Source | test.ps1:39:32:39:38 | first | provenance | | -| test.ps1:15:11:15:21 | call to Source | test.ps1:18:18:18:25 | second | provenance | | -| test.ps1:15:11:15:21 | call to Source | test.ps1:19:11:19:18 | second | provenance | | -| test.ps1:15:11:15:21 | call to Source | test.ps1:20:21:20:28 | second | provenance | | -| test.ps1:15:11:15:21 | call to Source | test.ps1:21:21:21:28 | second | provenance | | -| test.ps1:15:11:15:21 | call to Source | test.ps1:22:14:22:21 | second | provenance | | -| test.ps1:15:11:15:21 | call to Source | test.ps1:23:11:23:18 | second | provenance | | -| test.ps1:15:11:15:21 | call to Source | test.ps1:24:21:24:28 | second | provenance | | -| test.ps1:15:11:15:21 | call to Source | test.ps1:25:21:25:28 | second | provenance | | -| test.ps1:15:11:15:21 | call to Source | test.ps1:26:14:26:21 | second | provenance | | -| test.ps1:15:11:15:21 | call to Source | test.ps1:27:11:27:18 | second | provenance | | -| test.ps1:15:11:15:21 | call to Source | test.ps1:28:31:28:38 | second | provenance | | -| test.ps1:15:11:15:21 | call to Source | test.ps1:29:21:29:28 | second | provenance | | -| test.ps1:15:11:15:21 | call to Source | test.ps1:30:14:30:21 | second | provenance | | -| test.ps1:15:11:15:21 | call to Source | test.ps1:31:11:31:18 | second | provenance | | -| test.ps1:15:11:15:21 | call to Source | test.ps1:32:31:32:38 | second | provenance | | -| test.ps1:15:11:15:21 | call to Source | test.ps1:33:31:33:38 | second | provenance | | -| test.ps1:15:11:15:21 | call to Source | test.ps1:34:14:34:21 | second | provenance | | -| test.ps1:15:11:15:21 | call to Source | test.ps1:35:24:35:31 | second | provenance | | -| test.ps1:15:11:15:21 | call to Source | test.ps1:36:21:36:28 | second | provenance | | -| test.ps1:15:11:15:21 | call to Source | test.ps1:37:31:37:38 | second | provenance | | -| test.ps1:15:11:15:21 | call to Source | test.ps1:38:31:38:38 | second | provenance | | -| test.ps1:15:11:15:21 | call to Source | test.ps1:39:24:39:31 | second | provenance | | -| test.ps1:16:10:16:20 | call to Source | test.ps1:18:26:18:32 | third | provenance | | -| test.ps1:16:10:16:20 | call to Source | test.ps1:19:29:19:35 | third | provenance | | -| test.ps1:16:10:16:20 | call to Source | test.ps1:20:29:20:35 | third | provenance | | -| test.ps1:16:10:16:20 | call to Source | test.ps1:21:29:21:35 | third | provenance | | -| test.ps1:16:10:16:20 | call to Source | test.ps1:22:29:22:35 | third | provenance | | -| test.ps1:16:10:16:20 | call to Source | test.ps1:23:32:23:38 | third | provenance | | -| test.ps1:16:10:16:20 | call to Source | test.ps1:24:32:24:38 | third | provenance | | -| test.ps1:16:10:16:20 | call to Source | test.ps1:25:32:25:38 | third | provenance | | -| test.ps1:16:10:16:20 | call to Source | test.ps1:26:32:26:38 | third | provenance | | -| test.ps1:16:10:16:20 | call to Source | test.ps1:27:32:27:38 | third | provenance | | -| test.ps1:16:10:16:20 | call to Source | test.ps1:28:24:28:30 | third | provenance | | -| test.ps1:16:10:16:20 | call to Source | test.ps1:29:32:29:38 | third | provenance | | -| test.ps1:16:10:16:20 | call to Source | test.ps1:30:25:30:31 | third | provenance | | -| test.ps1:16:10:16:20 | call to Source | test.ps1:31:22:31:28 | third | provenance | | -| test.ps1:16:10:16:20 | call to Source | test.ps1:32:24:32:30 | third | provenance | | -| test.ps1:16:10:16:20 | call to Source | test.ps1:33:21:33:27 | third | provenance | | -| test.ps1:16:10:16:20 | call to Source | test.ps1:34:25:34:31 | third | provenance | | -| test.ps1:16:10:16:20 | call to Source | test.ps1:35:14:35:20 | third | provenance | | -| test.ps1:16:10:16:20 | call to Source | test.ps1:36:14:36:20 | third | provenance | | -| test.ps1:16:10:16:20 | call to Source | test.ps1:37:14:37:20 | third | provenance | | -| test.ps1:16:10:16:20 | call to Source | test.ps1:38:14:38:20 | third | provenance | | -| test.ps1:16:10:16:20 | call to Source | test.ps1:39:14:39:20 | third | provenance | | -| test.ps1:18:11:18:17 | first | test.ps1:8:20:8:22 | x | provenance | | -| test.ps1:18:18:18:25 | second | test.ps1:8:24:8:26 | y | provenance | | -| test.ps1:18:26:18:32 | third | test.ps1:8:28:8:30 | z | provenance | | -| test.ps1:19:11:19:18 | second | test.ps1:8:24:8:26 | y | provenance | | -| test.ps1:19:22:19:28 | first | test.ps1:8:20:8:22 | x | provenance | | -| test.ps1:19:29:19:35 | third | test.ps1:8:28:8:30 | z | provenance | | -| test.ps1:20:14:20:20 | first | test.ps1:8:20:8:22 | x | provenance | | -| test.ps1:20:21:20:28 | second | test.ps1:8:24:8:26 | y | provenance | | -| test.ps1:20:29:20:35 | third | test.ps1:8:28:8:30 | z | provenance | | -| test.ps1:21:11:21:17 | first | test.ps1:8:20:8:22 | x | provenance | | -| test.ps1:21:21:21:28 | second | test.ps1:8:24:8:26 | y | provenance | | -| test.ps1:21:29:21:35 | third | test.ps1:8:28:8:30 | z | provenance | | -| test.ps1:22:14:22:21 | second | test.ps1:8:24:8:26 | y | provenance | | -| test.ps1:22:22:22:28 | first | test.ps1:8:20:8:22 | x | provenance | | -| test.ps1:22:29:22:35 | third | test.ps1:8:28:8:30 | z | provenance | | -| test.ps1:23:11:23:18 | second | test.ps1:8:24:8:26 | y | provenance | | -| test.ps1:23:22:23:28 | first | test.ps1:8:20:8:22 | x | provenance | | -| test.ps1:23:32:23:38 | third | test.ps1:8:28:8:30 | z | provenance | | -| test.ps1:24:14:24:20 | first | test.ps1:8:20:8:22 | x | provenance | | -| test.ps1:24:21:24:28 | second | test.ps1:8:24:8:26 | y | provenance | | -| test.ps1:24:32:24:38 | third | test.ps1:8:28:8:30 | z | provenance | | -| test.ps1:25:11:25:17 | first | test.ps1:8:20:8:22 | x | provenance | | -| test.ps1:25:21:25:28 | second | test.ps1:8:24:8:26 | y | provenance | | -| test.ps1:25:32:25:38 | third | test.ps1:8:28:8:30 | z | provenance | | -| test.ps1:26:14:26:21 | second | test.ps1:8:24:8:26 | y | provenance | | -| test.ps1:26:22:26:28 | first | test.ps1:8:20:8:22 | x | provenance | | -| test.ps1:26:32:26:38 | third | test.ps1:8:28:8:30 | z | provenance | | -| test.ps1:27:11:27:18 | second | test.ps1:8:24:8:26 | y | provenance | | -| test.ps1:27:22:27:28 | first | test.ps1:8:20:8:22 | x | provenance | | -| test.ps1:27:32:27:38 | third | test.ps1:8:28:8:30 | z | provenance | | -| test.ps1:28:14:28:20 | first | test.ps1:8:20:8:22 | x | provenance | | -| test.ps1:28:24:28:30 | third | test.ps1:8:28:8:30 | z | provenance | | -| test.ps1:28:31:28:38 | second | test.ps1:8:24:8:26 | y | provenance | | -| test.ps1:29:11:29:17 | first | test.ps1:8:20:8:22 | x | provenance | | -| test.ps1:29:21:29:28 | second | test.ps1:8:24:8:26 | y | provenance | | -| test.ps1:29:32:29:38 | third | test.ps1:8:28:8:30 | z | provenance | | -| test.ps1:30:14:30:21 | second | test.ps1:8:24:8:26 | y | provenance | | -| test.ps1:30:25:30:31 | third | test.ps1:8:28:8:30 | z | provenance | | -| test.ps1:30:32:30:38 | first | test.ps1:8:20:8:22 | x | provenance | | -| test.ps1:31:11:31:18 | second | test.ps1:8:24:8:26 | y | provenance | | -| test.ps1:31:22:31:28 | third | test.ps1:8:28:8:30 | z | provenance | | -| test.ps1:31:32:31:38 | first | test.ps1:8:20:8:22 | x | provenance | | -| test.ps1:32:14:32:20 | first | test.ps1:8:20:8:22 | x | provenance | | -| test.ps1:32:24:32:30 | third | test.ps1:8:28:8:30 | z | provenance | | -| test.ps1:32:31:32:38 | second | test.ps1:8:24:8:26 | y | provenance | | -| test.ps1:33:11:33:17 | first | test.ps1:8:20:8:22 | x | provenance | | -| test.ps1:33:21:33:27 | third | test.ps1:8:28:8:30 | z | provenance | | -| test.ps1:33:31:33:38 | second | test.ps1:8:24:8:26 | y | provenance | | -| test.ps1:34:14:34:21 | second | test.ps1:8:24:8:26 | y | provenance | | -| test.ps1:34:25:34:31 | third | test.ps1:8:28:8:30 | z | provenance | | -| test.ps1:34:32:34:38 | first | test.ps1:8:20:8:22 | x | provenance | | -| test.ps1:35:14:35:20 | third | test.ps1:8:28:8:30 | z | provenance | | -| test.ps1:35:24:35:31 | second | test.ps1:8:24:8:26 | y | provenance | | -| test.ps1:35:32:35:38 | first | test.ps1:8:20:8:22 | x | provenance | | -| test.ps1:36:14:36:20 | third | test.ps1:8:28:8:30 | z | provenance | | -| test.ps1:36:21:36:28 | second | test.ps1:8:24:8:26 | y | provenance | | -| test.ps1:36:32:36:38 | first | test.ps1:8:20:8:22 | x | provenance | | -| test.ps1:37:14:37:20 | third | test.ps1:8:28:8:30 | z | provenance | | -| test.ps1:37:24:37:30 | first | test.ps1:8:20:8:22 | x | provenance | | -| test.ps1:37:31:37:38 | second | test.ps1:8:24:8:26 | y | provenance | | -| test.ps1:38:14:38:20 | third | test.ps1:8:28:8:30 | z | provenance | | -| test.ps1:38:21:38:27 | first | test.ps1:8:20:8:22 | x | provenance | | -| test.ps1:38:31:38:38 | second | test.ps1:8:24:8:26 | y | provenance | | -| test.ps1:39:14:39:20 | third | test.ps1:8:28:8:30 | z | provenance | | -| test.ps1:39:24:39:31 | second | test.ps1:8:24:8:26 | y | provenance | | -| test.ps1:39:32:39:38 | first | test.ps1:8:20:8:22 | x | provenance | | +| global.ps1:1:1:6:32 | Source1 | global.ps1:3:6:3:13 | Source1 | provenance | | +| global.ps1:1:1:6:32 | Source2 | global.ps1:4:6:4:13 | Source2 | provenance | | +| global.ps1:1:1:6:32 | Source3 | global.ps1:5:6:5:13 | Source3 | provenance | | +| global.ps1:1:1:6:32 | Source4 | global.ps1:6:6:6:13 | Source4 | provenance | | +| test.ps1:1:18:3:1 | a | test.ps1:2:10:2:11 | a | provenance | | +| test.ps1:5:6:5:15 | Call to Source | test.ps1:6:5:6:6 | x | provenance | | +| test.ps1:6:5:6:6 | x | test.ps1:1:18:3:1 | a | provenance | | +| test.ps1:8:32:12:1 | x | test.ps1:9:10:9:11 | x | provenance | | +| test.ps1:8:32:12:1 | y | test.ps1:10:10:10:11 | y | provenance | | +| test.ps1:8:32:12:1 | z | test.ps1:11:10:11:11 | z | provenance | | +| test.ps1:14:10:14:19 | Call to Source | test.ps1:18:11:18:16 | first | provenance | | +| test.ps1:14:10:14:19 | Call to Source | test.ps1:19:22:19:27 | first | provenance | | +| test.ps1:14:10:14:19 | Call to Source | test.ps1:20:14:20:19 | first | provenance | | +| test.ps1:14:10:14:19 | Call to Source | test.ps1:21:11:21:16 | first | provenance | | +| test.ps1:14:10:14:19 | Call to Source | test.ps1:22:22:22:27 | first | provenance | | +| test.ps1:14:10:14:19 | Call to Source | test.ps1:23:22:23:27 | first | provenance | | +| test.ps1:14:10:14:19 | Call to Source | test.ps1:24:14:24:19 | first | provenance | | +| test.ps1:14:10:14:19 | Call to Source | test.ps1:25:11:25:16 | first | provenance | | +| test.ps1:14:10:14:19 | Call to Source | test.ps1:26:22:26:27 | first | provenance | | +| test.ps1:14:10:14:19 | Call to Source | test.ps1:27:22:27:27 | first | provenance | | +| test.ps1:14:10:14:19 | Call to Source | test.ps1:28:14:28:19 | first | provenance | | +| test.ps1:14:10:14:19 | Call to Source | test.ps1:29:11:29:16 | first | provenance | | +| test.ps1:14:10:14:19 | Call to Source | test.ps1:30:32:30:37 | first | provenance | | +| test.ps1:14:10:14:19 | Call to Source | test.ps1:31:32:31:37 | first | provenance | | +| test.ps1:14:10:14:19 | Call to Source | test.ps1:32:14:32:19 | first | provenance | | +| test.ps1:14:10:14:19 | Call to Source | test.ps1:33:11:33:16 | first | provenance | | +| test.ps1:14:10:14:19 | Call to Source | test.ps1:34:32:34:37 | first | provenance | | +| test.ps1:14:10:14:19 | Call to Source | test.ps1:35:32:35:37 | first | provenance | | +| test.ps1:14:10:14:19 | Call to Source | test.ps1:36:32:36:37 | first | provenance | | +| test.ps1:14:10:14:19 | Call to Source | test.ps1:37:24:37:29 | first | provenance | | +| test.ps1:14:10:14:19 | Call to Source | test.ps1:38:21:38:26 | first | provenance | | +| test.ps1:14:10:14:19 | Call to Source | test.ps1:39:32:39:37 | first | provenance | | +| test.ps1:15:11:15:20 | Call to Source | test.ps1:18:18:18:24 | second | provenance | | +| test.ps1:15:11:15:20 | Call to Source | test.ps1:19:11:19:17 | second | provenance | | +| test.ps1:15:11:15:20 | Call to Source | test.ps1:20:21:20:27 | second | provenance | | +| test.ps1:15:11:15:20 | Call to Source | test.ps1:21:21:21:27 | second | provenance | | +| test.ps1:15:11:15:20 | Call to Source | test.ps1:22:14:22:20 | second | provenance | | +| test.ps1:15:11:15:20 | Call to Source | test.ps1:23:11:23:17 | second | provenance | | +| test.ps1:15:11:15:20 | Call to Source | test.ps1:24:21:24:27 | second | provenance | | +| test.ps1:15:11:15:20 | Call to Source | test.ps1:25:21:25:27 | second | provenance | | +| test.ps1:15:11:15:20 | Call to Source | test.ps1:26:14:26:20 | second | provenance | | +| test.ps1:15:11:15:20 | Call to Source | test.ps1:27:11:27:17 | second | provenance | | +| test.ps1:15:11:15:20 | Call to Source | test.ps1:28:31:28:37 | second | provenance | | +| test.ps1:15:11:15:20 | Call to Source | test.ps1:29:21:29:27 | second | provenance | | +| test.ps1:15:11:15:20 | Call to Source | test.ps1:30:14:30:20 | second | provenance | | +| test.ps1:15:11:15:20 | Call to Source | test.ps1:31:11:31:17 | second | provenance | | +| test.ps1:15:11:15:20 | Call to Source | test.ps1:32:31:32:37 | second | provenance | | +| test.ps1:15:11:15:20 | Call to Source | test.ps1:33:31:33:37 | second | provenance | | +| test.ps1:15:11:15:20 | Call to Source | test.ps1:34:14:34:20 | second | provenance | | +| test.ps1:15:11:15:20 | Call to Source | test.ps1:35:24:35:30 | second | provenance | | +| test.ps1:15:11:15:20 | Call to Source | test.ps1:36:21:36:27 | second | provenance | | +| test.ps1:15:11:15:20 | Call to Source | test.ps1:37:31:37:37 | second | provenance | | +| test.ps1:15:11:15:20 | Call to Source | test.ps1:38:31:38:37 | second | provenance | | +| test.ps1:15:11:15:20 | Call to Source | test.ps1:39:24:39:30 | second | provenance | | +| test.ps1:16:10:16:19 | Call to Source | test.ps1:18:26:18:31 | third | provenance | | +| test.ps1:16:10:16:19 | Call to Source | test.ps1:19:29:19:34 | third | provenance | | +| test.ps1:16:10:16:19 | Call to Source | test.ps1:20:29:20:34 | third | provenance | | +| test.ps1:16:10:16:19 | Call to Source | test.ps1:21:29:21:34 | third | provenance | | +| test.ps1:16:10:16:19 | Call to Source | test.ps1:22:29:22:34 | third | provenance | | +| test.ps1:16:10:16:19 | Call to Source | test.ps1:23:32:23:37 | third | provenance | | +| test.ps1:16:10:16:19 | Call to Source | test.ps1:24:32:24:37 | third | provenance | | +| test.ps1:16:10:16:19 | Call to Source | test.ps1:25:32:25:37 | third | provenance | | +| test.ps1:16:10:16:19 | Call to Source | test.ps1:26:32:26:37 | third | provenance | | +| test.ps1:16:10:16:19 | Call to Source | test.ps1:27:32:27:37 | third | provenance | | +| test.ps1:16:10:16:19 | Call to Source | test.ps1:28:24:28:29 | third | provenance | | +| test.ps1:16:10:16:19 | Call to Source | test.ps1:29:32:29:37 | third | provenance | | +| test.ps1:16:10:16:19 | Call to Source | test.ps1:30:25:30:30 | third | provenance | | +| test.ps1:16:10:16:19 | Call to Source | test.ps1:31:22:31:27 | third | provenance | | +| test.ps1:16:10:16:19 | Call to Source | test.ps1:32:24:32:29 | third | provenance | | +| test.ps1:16:10:16:19 | Call to Source | test.ps1:33:21:33:26 | third | provenance | | +| test.ps1:16:10:16:19 | Call to Source | test.ps1:34:25:34:30 | third | provenance | | +| test.ps1:16:10:16:19 | Call to Source | test.ps1:35:14:35:19 | third | provenance | | +| test.ps1:16:10:16:19 | Call to Source | test.ps1:36:14:36:19 | third | provenance | | +| test.ps1:16:10:16:19 | Call to Source | test.ps1:37:14:37:19 | third | provenance | | +| test.ps1:16:10:16:19 | Call to Source | test.ps1:38:14:38:19 | third | provenance | | +| test.ps1:16:10:16:19 | Call to Source | test.ps1:39:14:39:19 | third | provenance | | +| test.ps1:18:11:18:16 | first | test.ps1:8:32:12:1 | x | provenance | | +| test.ps1:18:18:18:24 | second | test.ps1:8:32:12:1 | y | provenance | | +| test.ps1:18:26:18:31 | third | test.ps1:8:32:12:1 | z | provenance | | +| test.ps1:19:11:19:17 | second | test.ps1:8:32:12:1 | y | provenance | | +| test.ps1:19:22:19:27 | first | test.ps1:8:32:12:1 | x | provenance | | +| test.ps1:19:29:19:34 | third | test.ps1:8:32:12:1 | z | provenance | | +| test.ps1:20:14:20:19 | first | test.ps1:8:32:12:1 | x | provenance | | +| test.ps1:20:21:20:27 | second | test.ps1:8:32:12:1 | y | provenance | | +| test.ps1:20:29:20:34 | third | test.ps1:8:32:12:1 | z | provenance | | +| test.ps1:21:11:21:16 | first | test.ps1:8:32:12:1 | x | provenance | | +| test.ps1:21:21:21:27 | second | test.ps1:8:32:12:1 | y | provenance | | +| test.ps1:21:29:21:34 | third | test.ps1:8:32:12:1 | z | provenance | | +| test.ps1:22:14:22:20 | second | test.ps1:8:32:12:1 | y | provenance | | +| test.ps1:22:22:22:27 | first | test.ps1:8:32:12:1 | x | provenance | | +| test.ps1:22:29:22:34 | third | test.ps1:8:32:12:1 | z | provenance | | +| test.ps1:23:11:23:17 | second | test.ps1:8:32:12:1 | y | provenance | | +| test.ps1:23:22:23:27 | first | test.ps1:8:32:12:1 | x | provenance | | +| test.ps1:23:32:23:37 | third | test.ps1:8:32:12:1 | z | provenance | | +| test.ps1:24:14:24:19 | first | test.ps1:8:32:12:1 | x | provenance | | +| test.ps1:24:21:24:27 | second | test.ps1:8:32:12:1 | y | provenance | | +| test.ps1:24:32:24:37 | third | test.ps1:8:32:12:1 | z | provenance | | +| test.ps1:25:11:25:16 | first | test.ps1:8:32:12:1 | x | provenance | | +| test.ps1:25:21:25:27 | second | test.ps1:8:32:12:1 | y | provenance | | +| test.ps1:25:32:25:37 | third | test.ps1:8:32:12:1 | z | provenance | | +| test.ps1:26:14:26:20 | second | test.ps1:8:32:12:1 | y | provenance | | +| test.ps1:26:22:26:27 | first | test.ps1:8:32:12:1 | x | provenance | | +| test.ps1:26:32:26:37 | third | test.ps1:8:32:12:1 | z | provenance | | +| test.ps1:27:11:27:17 | second | test.ps1:8:32:12:1 | y | provenance | | +| test.ps1:27:22:27:27 | first | test.ps1:8:32:12:1 | x | provenance | | +| test.ps1:27:32:27:37 | third | test.ps1:8:32:12:1 | z | provenance | | +| test.ps1:28:14:28:19 | first | test.ps1:8:32:12:1 | x | provenance | | +| test.ps1:28:24:28:29 | third | test.ps1:8:32:12:1 | z | provenance | | +| test.ps1:28:31:28:37 | second | test.ps1:8:32:12:1 | y | provenance | | +| test.ps1:29:11:29:16 | first | test.ps1:8:32:12:1 | x | provenance | | +| test.ps1:29:21:29:27 | second | test.ps1:8:32:12:1 | y | provenance | | +| test.ps1:29:32:29:37 | third | test.ps1:8:32:12:1 | z | provenance | | +| test.ps1:30:14:30:20 | second | test.ps1:8:32:12:1 | y | provenance | | +| test.ps1:30:25:30:30 | third | test.ps1:8:32:12:1 | z | provenance | | +| test.ps1:30:32:30:37 | first | test.ps1:8:32:12:1 | x | provenance | | +| test.ps1:31:11:31:17 | second | test.ps1:8:32:12:1 | y | provenance | | +| test.ps1:31:22:31:27 | third | test.ps1:8:32:12:1 | z | provenance | | +| test.ps1:31:32:31:37 | first | test.ps1:8:32:12:1 | x | provenance | | +| test.ps1:32:14:32:19 | first | test.ps1:8:32:12:1 | x | provenance | | +| test.ps1:32:24:32:29 | third | test.ps1:8:32:12:1 | z | provenance | | +| test.ps1:32:31:32:37 | second | test.ps1:8:32:12:1 | y | provenance | | +| test.ps1:33:11:33:16 | first | test.ps1:8:32:12:1 | x | provenance | | +| test.ps1:33:21:33:26 | third | test.ps1:8:32:12:1 | z | provenance | | +| test.ps1:33:31:33:37 | second | test.ps1:8:32:12:1 | y | provenance | | +| test.ps1:34:14:34:20 | second | test.ps1:8:32:12:1 | y | provenance | | +| test.ps1:34:25:34:30 | third | test.ps1:8:32:12:1 | z | provenance | | +| test.ps1:34:32:34:37 | first | test.ps1:8:32:12:1 | x | provenance | | +| test.ps1:35:14:35:19 | third | test.ps1:8:32:12:1 | z | provenance | | +| test.ps1:35:24:35:30 | second | test.ps1:8:32:12:1 | y | provenance | | +| test.ps1:35:32:35:37 | first | test.ps1:8:32:12:1 | x | provenance | | +| test.ps1:36:14:36:19 | third | test.ps1:8:32:12:1 | z | provenance | | +| test.ps1:36:21:36:27 | second | test.ps1:8:32:12:1 | y | provenance | | +| test.ps1:36:32:36:37 | first | test.ps1:8:32:12:1 | x | provenance | | +| test.ps1:37:14:37:19 | third | test.ps1:8:32:12:1 | z | provenance | | +| test.ps1:37:24:37:29 | first | test.ps1:8:32:12:1 | x | provenance | | +| test.ps1:37:31:37:37 | second | test.ps1:8:32:12:1 | y | provenance | | +| test.ps1:38:14:38:19 | third | test.ps1:8:32:12:1 | z | provenance | | +| test.ps1:38:21:38:26 | first | test.ps1:8:32:12:1 | x | provenance | | +| test.ps1:38:31:38:37 | second | test.ps1:8:32:12:1 | y | provenance | | +| test.ps1:39:14:39:19 | third | test.ps1:8:32:12:1 | z | provenance | | +| test.ps1:39:24:39:30 | second | test.ps1:8:32:12:1 | y | provenance | | +| test.ps1:39:32:39:37 | first | test.ps1:8:32:12:1 | x | provenance | | nodes -| global.ps1:1:7:1:23 | Source1 | semmle.label | Source1 | -| global.ps1:1:25:1:41 | Source2 | semmle.label | Source2 | -| global.ps1:1:43:1:59 | Source3 | semmle.label | Source3 | -| global.ps1:1:61:1:77 | Source4 | semmle.label | Source4 | -| global.ps1:3:6:3:14 | Source1 | semmle.label | Source1 | -| global.ps1:4:6:4:14 | Source2 | semmle.label | Source2 | -| global.ps1:5:6:5:14 | Source3 | semmle.label | Source3 | -| global.ps1:6:6:6:14 | Source4 | semmle.label | Source4 | -| test.ps1:1:14:1:16 | a | semmle.label | a | -| test.ps1:2:10:2:12 | a | semmle.label | a | -| test.ps1:5:6:5:16 | call to Source | semmle.label | call to Source | -| test.ps1:6:5:6:7 | x | semmle.label | x | -| test.ps1:8:20:8:22 | x | semmle.label | x | -| test.ps1:8:24:8:26 | y | semmle.label | y | -| test.ps1:8:28:8:30 | z | semmle.label | z | -| test.ps1:9:10:9:12 | x | semmle.label | x | -| test.ps1:10:10:10:12 | y | semmle.label | y | -| test.ps1:11:10:11:12 | z | semmle.label | z | -| test.ps1:14:10:14:20 | call to Source | semmle.label | call to Source | -| test.ps1:15:11:15:21 | call to Source | semmle.label | call to Source | -| test.ps1:16:10:16:20 | call to Source | semmle.label | call to Source | -| test.ps1:18:11:18:17 | first | semmle.label | first | -| test.ps1:18:18:18:25 | second | semmle.label | second | -| test.ps1:18:26:18:32 | third | semmle.label | third | -| test.ps1:19:11:19:18 | second | semmle.label | second | -| test.ps1:19:22:19:28 | first | semmle.label | first | -| test.ps1:19:29:19:35 | third | semmle.label | third | -| test.ps1:20:14:20:20 | first | semmle.label | first | -| test.ps1:20:21:20:28 | second | semmle.label | second | -| test.ps1:20:29:20:35 | third | semmle.label | third | -| test.ps1:21:11:21:17 | first | semmle.label | first | -| test.ps1:21:21:21:28 | second | semmle.label | second | -| test.ps1:21:29:21:35 | third | semmle.label | third | -| test.ps1:22:14:22:21 | second | semmle.label | second | -| test.ps1:22:22:22:28 | first | semmle.label | first | -| test.ps1:22:29:22:35 | third | semmle.label | third | -| test.ps1:23:11:23:18 | second | semmle.label | second | -| test.ps1:23:22:23:28 | first | semmle.label | first | -| test.ps1:23:32:23:38 | third | semmle.label | third | -| test.ps1:24:14:24:20 | first | semmle.label | first | -| test.ps1:24:21:24:28 | second | semmle.label | second | -| test.ps1:24:32:24:38 | third | semmle.label | third | -| test.ps1:25:11:25:17 | first | semmle.label | first | -| test.ps1:25:21:25:28 | second | semmle.label | second | -| test.ps1:25:32:25:38 | third | semmle.label | third | -| test.ps1:26:14:26:21 | second | semmle.label | second | -| test.ps1:26:22:26:28 | first | semmle.label | first | -| test.ps1:26:32:26:38 | third | semmle.label | third | -| test.ps1:27:11:27:18 | second | semmle.label | second | -| test.ps1:27:22:27:28 | first | semmle.label | first | -| test.ps1:27:32:27:38 | third | semmle.label | third | -| test.ps1:28:14:28:20 | first | semmle.label | first | -| test.ps1:28:24:28:30 | third | semmle.label | third | -| test.ps1:28:31:28:38 | second | semmle.label | second | -| test.ps1:29:11:29:17 | first | semmle.label | first | -| test.ps1:29:21:29:28 | second | semmle.label | second | -| test.ps1:29:32:29:38 | third | semmle.label | third | -| test.ps1:30:14:30:21 | second | semmle.label | second | -| test.ps1:30:25:30:31 | third | semmle.label | third | -| test.ps1:30:32:30:38 | first | semmle.label | first | -| test.ps1:31:11:31:18 | second | semmle.label | second | -| test.ps1:31:22:31:28 | third | semmle.label | third | -| test.ps1:31:32:31:38 | first | semmle.label | first | -| test.ps1:32:14:32:20 | first | semmle.label | first | -| test.ps1:32:24:32:30 | third | semmle.label | third | -| test.ps1:32:31:32:38 | second | semmle.label | second | -| test.ps1:33:11:33:17 | first | semmle.label | first | -| test.ps1:33:21:33:27 | third | semmle.label | third | -| test.ps1:33:31:33:38 | second | semmle.label | second | -| test.ps1:34:14:34:21 | second | semmle.label | second | -| test.ps1:34:25:34:31 | third | semmle.label | third | -| test.ps1:34:32:34:38 | first | semmle.label | first | -| test.ps1:35:14:35:20 | third | semmle.label | third | -| test.ps1:35:24:35:31 | second | semmle.label | second | -| test.ps1:35:32:35:38 | first | semmle.label | first | -| test.ps1:36:14:36:20 | third | semmle.label | third | -| test.ps1:36:21:36:28 | second | semmle.label | second | -| test.ps1:36:32:36:38 | first | semmle.label | first | -| test.ps1:37:14:37:20 | third | semmle.label | third | -| test.ps1:37:24:37:30 | first | semmle.label | first | -| test.ps1:37:31:37:38 | second | semmle.label | second | -| test.ps1:38:14:38:20 | third | semmle.label | third | -| test.ps1:38:21:38:27 | first | semmle.label | first | -| test.ps1:38:31:38:38 | second | semmle.label | second | -| test.ps1:39:14:39:20 | third | semmle.label | third | -| test.ps1:39:24:39:31 | second | semmle.label | second | -| test.ps1:39:32:39:38 | first | semmle.label | first | +| global.ps1:1:1:6:32 | Source1 | semmle.label | Source1 | +| global.ps1:1:1:6:32 | Source2 | semmle.label | Source2 | +| global.ps1:1:1:6:32 | Source3 | semmle.label | Source3 | +| global.ps1:1:1:6:32 | Source4 | semmle.label | Source4 | +| global.ps1:3:6:3:13 | Source1 | semmle.label | Source1 | +| global.ps1:4:6:4:13 | Source2 | semmle.label | Source2 | +| global.ps1:5:6:5:13 | Source3 | semmle.label | Source3 | +| global.ps1:6:6:6:13 | Source4 | semmle.label | Source4 | +| test.ps1:1:18:3:1 | a | semmle.label | a | +| test.ps1:2:10:2:11 | a | semmle.label | a | +| test.ps1:5:6:5:15 | Call to Source | semmle.label | Call to Source | +| test.ps1:6:5:6:6 | x | semmle.label | x | +| test.ps1:8:32:12:1 | x | semmle.label | x | +| test.ps1:8:32:12:1 | y | semmle.label | y | +| test.ps1:8:32:12:1 | z | semmle.label | z | +| test.ps1:9:10:9:11 | x | semmle.label | x | +| test.ps1:10:10:10:11 | y | semmle.label | y | +| test.ps1:11:10:11:11 | z | semmle.label | z | +| test.ps1:14:10:14:19 | Call to Source | semmle.label | Call to Source | +| test.ps1:15:11:15:20 | Call to Source | semmle.label | Call to Source | +| test.ps1:16:10:16:19 | Call to Source | semmle.label | Call to Source | +| test.ps1:18:11:18:16 | first | semmle.label | first | +| test.ps1:18:18:18:24 | second | semmle.label | second | +| test.ps1:18:26:18:31 | third | semmle.label | third | +| test.ps1:19:11:19:17 | second | semmle.label | second | +| test.ps1:19:22:19:27 | first | semmle.label | first | +| test.ps1:19:29:19:34 | third | semmle.label | third | +| test.ps1:20:14:20:19 | first | semmle.label | first | +| test.ps1:20:21:20:27 | second | semmle.label | second | +| test.ps1:20:29:20:34 | third | semmle.label | third | +| test.ps1:21:11:21:16 | first | semmle.label | first | +| test.ps1:21:21:21:27 | second | semmle.label | second | +| test.ps1:21:29:21:34 | third | semmle.label | third | +| test.ps1:22:14:22:20 | second | semmle.label | second | +| test.ps1:22:22:22:27 | first | semmle.label | first | +| test.ps1:22:29:22:34 | third | semmle.label | third | +| test.ps1:23:11:23:17 | second | semmle.label | second | +| test.ps1:23:22:23:27 | first | semmle.label | first | +| test.ps1:23:32:23:37 | third | semmle.label | third | +| test.ps1:24:14:24:19 | first | semmle.label | first | +| test.ps1:24:21:24:27 | second | semmle.label | second | +| test.ps1:24:32:24:37 | third | semmle.label | third | +| test.ps1:25:11:25:16 | first | semmle.label | first | +| test.ps1:25:21:25:27 | second | semmle.label | second | +| test.ps1:25:32:25:37 | third | semmle.label | third | +| test.ps1:26:14:26:20 | second | semmle.label | second | +| test.ps1:26:22:26:27 | first | semmle.label | first | +| test.ps1:26:32:26:37 | third | semmle.label | third | +| test.ps1:27:11:27:17 | second | semmle.label | second | +| test.ps1:27:22:27:27 | first | semmle.label | first | +| test.ps1:27:32:27:37 | third | semmle.label | third | +| test.ps1:28:14:28:19 | first | semmle.label | first | +| test.ps1:28:24:28:29 | third | semmle.label | third | +| test.ps1:28:31:28:37 | second | semmle.label | second | +| test.ps1:29:11:29:16 | first | semmle.label | first | +| test.ps1:29:21:29:27 | second | semmle.label | second | +| test.ps1:29:32:29:37 | third | semmle.label | third | +| test.ps1:30:14:30:20 | second | semmle.label | second | +| test.ps1:30:25:30:30 | third | semmle.label | third | +| test.ps1:30:32:30:37 | first | semmle.label | first | +| test.ps1:31:11:31:17 | second | semmle.label | second | +| test.ps1:31:22:31:27 | third | semmle.label | third | +| test.ps1:31:32:31:37 | first | semmle.label | first | +| test.ps1:32:14:32:19 | first | semmle.label | first | +| test.ps1:32:24:32:29 | third | semmle.label | third | +| test.ps1:32:31:32:37 | second | semmle.label | second | +| test.ps1:33:11:33:16 | first | semmle.label | first | +| test.ps1:33:21:33:26 | third | semmle.label | third | +| test.ps1:33:31:33:37 | second | semmle.label | second | +| test.ps1:34:14:34:20 | second | semmle.label | second | +| test.ps1:34:25:34:30 | third | semmle.label | third | +| test.ps1:34:32:34:37 | first | semmle.label | first | +| test.ps1:35:14:35:19 | third | semmle.label | third | +| test.ps1:35:24:35:30 | second | semmle.label | second | +| test.ps1:35:32:35:37 | first | semmle.label | first | +| test.ps1:36:14:36:19 | third | semmle.label | third | +| test.ps1:36:21:36:27 | second | semmle.label | second | +| test.ps1:36:32:36:37 | first | semmle.label | first | +| test.ps1:37:14:37:19 | third | semmle.label | third | +| test.ps1:37:24:37:29 | first | semmle.label | first | +| test.ps1:37:31:37:37 | second | semmle.label | second | +| test.ps1:38:14:38:19 | third | semmle.label | third | +| test.ps1:38:21:38:26 | first | semmle.label | first | +| test.ps1:38:31:38:37 | second | semmle.label | second | +| test.ps1:39:14:39:19 | third | semmle.label | third | +| test.ps1:39:24:39:30 | second | semmle.label | second | +| test.ps1:39:32:39:37 | first | semmle.label | first | subpaths testFailures #select -| global.ps1:3:6:3:14 | Source1 | global.ps1:1:7:1:23 | Source1 | global.ps1:3:6:3:14 | Source1 | $@ | global.ps1:1:7:1:23 | Source1 | Source1 | -| global.ps1:4:6:4:14 | Source2 | global.ps1:1:25:1:41 | Source2 | global.ps1:4:6:4:14 | Source2 | $@ | global.ps1:1:25:1:41 | Source2 | Source2 | -| global.ps1:5:6:5:14 | Source3 | global.ps1:1:43:1:59 | Source3 | global.ps1:5:6:5:14 | Source3 | $@ | global.ps1:1:43:1:59 | Source3 | Source3 | -| global.ps1:6:6:6:14 | Source4 | global.ps1:1:61:1:77 | Source4 | global.ps1:6:6:6:14 | Source4 | $@ | global.ps1:1:61:1:77 | Source4 | Source4 | -| test.ps1:2:10:2:12 | a | test.ps1:5:6:5:16 | call to Source | test.ps1:2:10:2:12 | a | $@ | test.ps1:5:6:5:16 | call to Source | call to Source | -| test.ps1:9:10:9:12 | x | test.ps1:14:10:14:20 | call to Source | test.ps1:9:10:9:12 | x | $@ | test.ps1:14:10:14:20 | call to Source | call to Source | -| test.ps1:10:10:10:12 | y | test.ps1:15:11:15:21 | call to Source | test.ps1:10:10:10:12 | y | $@ | test.ps1:15:11:15:21 | call to Source | call to Source | -| test.ps1:11:10:11:12 | z | test.ps1:16:10:16:20 | call to Source | test.ps1:11:10:11:12 | z | $@ | test.ps1:16:10:16:20 | call to Source | call to Source | +| global.ps1:3:6:3:13 | Source1 | global.ps1:1:1:6:32 | Source1 | global.ps1:3:6:3:13 | Source1 | $@ | global.ps1:1:1:6:32 | Source1 | Source1 | +| global.ps1:4:6:4:13 | Source2 | global.ps1:1:1:6:32 | Source2 | global.ps1:4:6:4:13 | Source2 | $@ | global.ps1:1:1:6:32 | Source2 | Source2 | +| global.ps1:5:6:5:13 | Source3 | global.ps1:1:1:6:32 | Source3 | global.ps1:5:6:5:13 | Source3 | $@ | global.ps1:1:1:6:32 | Source3 | Source3 | +| global.ps1:6:6:6:13 | Source4 | global.ps1:1:1:6:32 | Source4 | global.ps1:6:6:6:13 | Source4 | $@ | global.ps1:1:1:6:32 | Source4 | Source4 | +| test.ps1:2:10:2:11 | a | test.ps1:5:6:5:15 | Call to Source | test.ps1:2:10:2:11 | a | $@ | test.ps1:5:6:5:15 | Call to Source | Call to Source | +| test.ps1:9:10:9:11 | x | test.ps1:14:10:14:19 | Call to Source | test.ps1:9:10:9:11 | x | $@ | test.ps1:14:10:14:19 | Call to Source | Call to Source | +| test.ps1:10:10:10:11 | y | test.ps1:15:11:15:20 | Call to Source | test.ps1:10:10:10:11 | y | $@ | test.ps1:15:11:15:20 | Call to Source | Call to Source | +| test.ps1:11:10:11:11 | z | test.ps1:16:10:16:19 | Call to Source | test.ps1:11:10:11:11 | z | $@ | test.ps1:16:10:16:19 | Call to Source | Call to Source | diff --git a/powershell/ql/test/library-tests/dataflow/pipeline/test.expected b/powershell/ql/test/library-tests/dataflow/pipeline/test.expected index 12b6de837cb2..bbea92282028 100644 --- a/powershell/ql/test/library-tests/dataflow/pipeline/test.expected +++ b/powershell/ql/test/library-tests/dataflow/pipeline/test.expected @@ -1,127 +1,17 @@ models edges -| test.ps1:2:10:2:20 | call to Source | test.ps1:5:5:5:7 | x | provenance | | -| test.ps1:3:10:3:20 | call to Source | test.ps1:6:5:6:7 | y | provenance | | -| test.ps1:4:10:4:20 | call to Source | test.ps1:6:9:6:11 | z | provenance | | -| test.ps1:5:5:5:7 | x | test.ps1:17:1:17:8 | call to produce [element] | provenance | | -| test.ps1:6:5:6:7 | y | test.ps1:6:5:6:11 | ...,... [element 0] | provenance | | -| test.ps1:6:5:6:11 | ...,... [element 0] | test.ps1:17:1:17:8 | call to produce [element] | provenance | | -| test.ps1:6:5:6:11 | ...,... [element 1] | test.ps1:17:1:17:8 | call to produce [element] | provenance | | -| test.ps1:6:9:6:11 | z | test.ps1:6:5:6:11 | ...,... [element 1] | provenance | | -| test.ps1:10:11:10:44 | x [element 0] | test.ps1:13:14:13:16 | x | provenance | | -| test.ps1:10:11:10:44 | x [element 1] | test.ps1:13:14:13:16 | x | provenance | | -| test.ps1:10:11:10:44 | x [element] | test.ps1:13:14:13:16 | x | provenance | | -| test.ps1:17:1:17:8 | call to produce [element] | test.ps1:10:11:10:44 | x [element] | provenance | | -| test.ps1:19:6:19:16 | call to Source | test.ps1:21:1:21:3 | x | provenance | | -| test.ps1:20:6:20:16 | call to Source | test.ps1:21:5:21:7 | y | provenance | | -| test.ps1:21:1:21:3 | x | test.ps1:21:1:21:7 | ...,... [element 0] | provenance | | -| test.ps1:21:1:21:7 | ...,... [element 0] | test.ps1:10:11:10:44 | x [element 0] | provenance | | -| test.ps1:21:1:21:7 | ...,... [element 0] | test.ps1:21:1:21:7 | ...,... [element 0] | provenance | | -| test.ps1:21:1:21:7 | ...,... [element 1] | test.ps1:10:11:10:44 | x [element 1] | provenance | | -| test.ps1:21:1:21:7 | ...,... [element 1] | test.ps1:21:1:21:7 | ...,... [element 1] | provenance | | -| test.ps1:21:5:21:7 | y | test.ps1:21:1:21:7 | ...,... [element 1] | provenance | | -| test.ps1:25:14:25:16 | _ [element 0] | test.ps1:25:14:25:16 | _ | provenance | | -| test.ps1:25:14:25:16 | _ [element 1] | test.ps1:25:14:25:16 | _ | provenance | | -| test.ps1:29:6:29:16 | call to Source | test.ps1:31:1:31:3 | x | provenance | | -| test.ps1:30:6:30:16 | call to Source | test.ps1:31:5:31:7 | y | provenance | | -| test.ps1:31:1:31:3 | x | test.ps1:31:1:31:7 | ...,... [element 0] | provenance | | -| test.ps1:31:1:31:7 | ...,... [element 0] | test.ps1:25:14:25:16 | _ [element 0] | provenance | | -| test.ps1:31:1:31:7 | ...,... [element 0] | test.ps1:31:1:31:7 | ...,... [element 0] | provenance | | -| test.ps1:31:1:31:7 | ...,... [element 1] | test.ps1:25:14:25:16 | _ [element 1] | provenance | | -| test.ps1:31:1:31:7 | ...,... [element 1] | test.ps1:31:1:31:7 | ...,... [element 1] | provenance | | -| test.ps1:31:5:31:7 | y | test.ps1:31:1:31:7 | ...,... [element 1] | provenance | | -| test.ps1:34:11:34:58 | x [element x] | test.ps1:36:10:36:12 | x | provenance | | -| test.ps1:39:6:39:16 | call to Source | test.ps1:40:23:40:25 | x | provenance | | -| test.ps1:40:1:40:26 | [...]... [element x] | test.ps1:34:11:34:58 | x [element x] | provenance | | -| test.ps1:40:17:40:26 | ${...} [element x] | test.ps1:40:1:40:26 | [...]... [element x] | provenance | | -| test.ps1:40:23:40:25 | x | test.ps1:40:17:40:26 | ${...} [element x] | provenance | | -| test.ps1:43:11:43:58 | x [element 0, element x] | test.ps1:46:14:46:16 | x | provenance | | -| test.ps1:43:11:43:58 | x [element 1, element x] | test.ps1:46:14:46:16 | x | provenance | | -| test.ps1:43:11:43:58 | x [element 2, element x] | test.ps1:46:14:46:16 | x | provenance | | -| test.ps1:50:1:50:34 | [...]... [element x] | test.ps1:50:1:50:106 | ...,... [element 0, element x] | provenance | | -| test.ps1:50:1:50:106 | ...,... [element 0, element x] | test.ps1:43:11:43:58 | x [element 0, element x] | provenance | | -| test.ps1:50:1:50:106 | ...,... [element 0, element x] | test.ps1:50:1:50:106 | ...,... [element 0, element x] | provenance | | -| test.ps1:50:1:50:106 | ...,... [element 1, element x] | test.ps1:43:11:43:58 | x [element 1, element x] | provenance | | -| test.ps1:50:1:50:106 | ...,... [element 1, element x] | test.ps1:50:1:50:106 | ...,... [element 1, element x] | provenance | | -| test.ps1:50:1:50:106 | ...,... [element 2, element x] | test.ps1:43:11:43:58 | x [element 2, element x] | provenance | | -| test.ps1:50:1:50:106 | ...,... [element 2, element x] | test.ps1:50:1:50:106 | ...,... [element 2, element x] | provenance | | -| test.ps1:50:17:50:34 | ${...} [element x] | test.ps1:50:1:50:34 | [...]... [element x] | provenance | | -| test.ps1:50:23:50:33 | call to Source | test.ps1:50:17:50:34 | ${...} [element x] | provenance | | -| test.ps1:50:36:50:70 | [...]... [element x] | test.ps1:50:1:50:106 | ...,... [element 1, element x] | provenance | | -| test.ps1:50:52:50:70 | ${...} [element x] | test.ps1:50:36:50:70 | [...]... [element x] | provenance | | -| test.ps1:50:58:50:69 | call to Source | test.ps1:50:52:50:70 | ${...} [element x] | provenance | | -| test.ps1:50:72:50:106 | [...]... [element x] | test.ps1:50:1:50:106 | ...,... [element 2, element x] | provenance | | -| test.ps1:50:88:50:106 | ${...} [element x] | test.ps1:50:72:50:106 | [...]... [element x] | provenance | | -| test.ps1:50:94:50:105 | call to Source | test.ps1:50:88:50:106 | ${...} [element x] | provenance | | nodes -| test.ps1:2:10:2:20 | call to Source | semmle.label | call to Source | -| test.ps1:3:10:3:20 | call to Source | semmle.label | call to Source | -| test.ps1:4:10:4:20 | call to Source | semmle.label | call to Source | -| test.ps1:5:5:5:7 | x | semmle.label | x | -| test.ps1:6:5:6:7 | y | semmle.label | y | -| test.ps1:6:5:6:11 | ...,... [element 0] | semmle.label | ...,... [element 0] | -| test.ps1:6:5:6:11 | ...,... [element 1] | semmle.label | ...,... [element 1] | -| test.ps1:6:9:6:11 | z | semmle.label | z | -| test.ps1:10:11:10:44 | x [element 0] | semmle.label | x [element 0] | -| test.ps1:10:11:10:44 | x [element 1] | semmle.label | x [element 1] | -| test.ps1:10:11:10:44 | x [element] | semmle.label | x [element] | -| test.ps1:13:14:13:16 | x | semmle.label | x | -| test.ps1:17:1:17:8 | call to produce [element] | semmle.label | call to produce [element] | -| test.ps1:19:6:19:16 | call to Source | semmle.label | call to Source | -| test.ps1:20:6:20:16 | call to Source | semmle.label | call to Source | -| test.ps1:21:1:21:3 | x | semmle.label | x | -| test.ps1:21:1:21:7 | ...,... [element 0] | semmle.label | ...,... [element 0] | -| test.ps1:21:1:21:7 | ...,... [element 0] | semmle.label | ...,... [element 0] | -| test.ps1:21:1:21:7 | ...,... [element 1] | semmle.label | ...,... [element 1] | -| test.ps1:21:1:21:7 | ...,... [element 1] | semmle.label | ...,... [element 1] | -| test.ps1:21:5:21:7 | y | semmle.label | y | -| test.ps1:25:14:25:16 | _ | semmle.label | _ | -| test.ps1:25:14:25:16 | _ [element 0] | semmle.label | _ [element 0] | -| test.ps1:25:14:25:16 | _ [element 1] | semmle.label | _ [element 1] | -| test.ps1:29:6:29:16 | call to Source | semmle.label | call to Source | -| test.ps1:30:6:30:16 | call to Source | semmle.label | call to Source | -| test.ps1:31:1:31:3 | x | semmle.label | x | -| test.ps1:31:1:31:7 | ...,... [element 0] | semmle.label | ...,... [element 0] | -| test.ps1:31:1:31:7 | ...,... [element 0] | semmle.label | ...,... [element 0] | -| test.ps1:31:1:31:7 | ...,... [element 1] | semmle.label | ...,... [element 1] | -| test.ps1:31:1:31:7 | ...,... [element 1] | semmle.label | ...,... [element 1] | -| test.ps1:31:5:31:7 | y | semmle.label | y | -| test.ps1:34:11:34:58 | x [element x] | semmle.label | x [element x] | -| test.ps1:36:10:36:12 | x | semmle.label | x | -| test.ps1:39:6:39:16 | call to Source | semmle.label | call to Source | -| test.ps1:40:1:40:26 | [...]... [element x] | semmle.label | [...]... [element x] | -| test.ps1:40:17:40:26 | ${...} [element x] | semmle.label | ${...} [element x] | -| test.ps1:40:23:40:25 | x | semmle.label | x | -| test.ps1:43:11:43:58 | x [element 0, element x] | semmle.label | x [element 0, element x] | -| test.ps1:43:11:43:58 | x [element 1, element x] | semmle.label | x [element 1, element x] | -| test.ps1:43:11:43:58 | x [element 2, element x] | semmle.label | x [element 2, element x] | -| test.ps1:46:14:46:16 | x | semmle.label | x | -| test.ps1:50:1:50:34 | [...]... [element x] | semmle.label | [...]... [element x] | -| test.ps1:50:1:50:106 | ...,... [element 0, element x] | semmle.label | ...,... [element 0, element x] | -| test.ps1:50:1:50:106 | ...,... [element 0, element x] | semmle.label | ...,... [element 0, element x] | -| test.ps1:50:1:50:106 | ...,... [element 1, element x] | semmle.label | ...,... [element 1, element x] | -| test.ps1:50:1:50:106 | ...,... [element 1, element x] | semmle.label | ...,... [element 1, element x] | -| test.ps1:50:1:50:106 | ...,... [element 2, element x] | semmle.label | ...,... [element 2, element x] | -| test.ps1:50:1:50:106 | ...,... [element 2, element x] | semmle.label | ...,... [element 2, element x] | -| test.ps1:50:17:50:34 | ${...} [element x] | semmle.label | ${...} [element x] | -| test.ps1:50:23:50:33 | call to Source | semmle.label | call to Source | -| test.ps1:50:36:50:70 | [...]... [element x] | semmle.label | [...]... [element x] | -| test.ps1:50:52:50:70 | ${...} [element x] | semmle.label | ${...} [element x] | -| test.ps1:50:58:50:69 | call to Source | semmle.label | call to Source | -| test.ps1:50:72:50:106 | [...]... [element x] | semmle.label | [...]... [element x] | -| test.ps1:50:88:50:106 | ${...} [element x] | semmle.label | ${...} [element x] | -| test.ps1:50:94:50:105 | call to Source | semmle.label | call to Source | subpaths testFailures +| test.ps1:13:17:13:94 | # $ hasValueFlow=1 hasValueFlow=2 hasValueFlow=3 hasValueFlow=4 hasValueFlow=5 | Missing result: hasValueFlow=1 | +| test.ps1:13:17:13:94 | # $ hasValueFlow=1 hasValueFlow=2 hasValueFlow=3 hasValueFlow=4 hasValueFlow=5 | Missing result: hasValueFlow=2 | +| test.ps1:13:17:13:94 | # $ hasValueFlow=1 hasValueFlow=2 hasValueFlow=3 hasValueFlow=4 hasValueFlow=5 | Missing result: hasValueFlow=3 | +| test.ps1:13:17:13:94 | # $ hasValueFlow=1 hasValueFlow=2 hasValueFlow=3 hasValueFlow=4 hasValueFlow=5 | Missing result: hasValueFlow=4 | +| test.ps1:13:17:13:94 | # $ hasValueFlow=1 hasValueFlow=2 hasValueFlow=3 hasValueFlow=4 hasValueFlow=5 | Missing result: hasValueFlow=5 | +| test.ps1:25:17:25:49 | # $ hasValueFlow=6 hasValueFlow=7 | Missing result: hasValueFlow=6 | +| test.ps1:25:17:25:49 | # $ hasValueFlow=6 hasValueFlow=7 | Missing result: hasValueFlow=7 | +| test.ps1:36:13:36:30 | # $ hasValueFlow=8 | Missing result: hasValueFlow=8 | +| test.ps1:46:17:46:66 | # $ hasValueFlow=9 hasValueFlow=10 hasValueFlow=11 | Missing result: hasValueFlow=9 | +| test.ps1:46:17:46:66 | # $ hasValueFlow=9 hasValueFlow=10 hasValueFlow=11 | Missing result: hasValueFlow=10 | +| test.ps1:46:17:46:66 | # $ hasValueFlow=9 hasValueFlow=10 hasValueFlow=11 | Missing result: hasValueFlow=11 | #select -| test.ps1:13:14:13:16 | x | test.ps1:2:10:2:20 | call to Source | test.ps1:13:14:13:16 | x | $@ | test.ps1:2:10:2:20 | call to Source | call to Source | -| test.ps1:13:14:13:16 | x | test.ps1:3:10:3:20 | call to Source | test.ps1:13:14:13:16 | x | $@ | test.ps1:3:10:3:20 | call to Source | call to Source | -| test.ps1:13:14:13:16 | x | test.ps1:4:10:4:20 | call to Source | test.ps1:13:14:13:16 | x | $@ | test.ps1:4:10:4:20 | call to Source | call to Source | -| test.ps1:13:14:13:16 | x | test.ps1:19:6:19:16 | call to Source | test.ps1:13:14:13:16 | x | $@ | test.ps1:19:6:19:16 | call to Source | call to Source | -| test.ps1:13:14:13:16 | x | test.ps1:20:6:20:16 | call to Source | test.ps1:13:14:13:16 | x | $@ | test.ps1:20:6:20:16 | call to Source | call to Source | -| test.ps1:25:14:25:16 | _ | test.ps1:29:6:29:16 | call to Source | test.ps1:25:14:25:16 | _ | $@ | test.ps1:29:6:29:16 | call to Source | call to Source | -| test.ps1:25:14:25:16 | _ | test.ps1:30:6:30:16 | call to Source | test.ps1:25:14:25:16 | _ | $@ | test.ps1:30:6:30:16 | call to Source | call to Source | -| test.ps1:36:10:36:12 | x | test.ps1:39:6:39:16 | call to Source | test.ps1:36:10:36:12 | x | $@ | test.ps1:39:6:39:16 | call to Source | call to Source | -| test.ps1:46:14:46:16 | x | test.ps1:50:23:50:33 | call to Source | test.ps1:46:14:46:16 | x | $@ | test.ps1:50:23:50:33 | call to Source | call to Source | -| test.ps1:46:14:46:16 | x | test.ps1:50:58:50:69 | call to Source | test.ps1:46:14:46:16 | x | $@ | test.ps1:50:58:50:69 | call to Source | call to Source | -| test.ps1:46:14:46:16 | x | test.ps1:50:94:50:105 | call to Source | test.ps1:46:14:46:16 | x | $@ | test.ps1:50:94:50:105 | call to Source | call to Source | diff --git a/powershell/ql/test/library-tests/dataflow/returns/test.expected b/powershell/ql/test/library-tests/dataflow/returns/test.expected index 3fe33326ac75..ae3eefed04d1 100644 --- a/powershell/ql/test/library-tests/dataflow/returns/test.expected +++ b/powershell/ql/test/library-tests/dataflow/returns/test.expected @@ -1,69 +1,47 @@ models edges -| test.ps1:2:5:2:15 | call to Source | test.ps1:5:6:5:20 | call to callSourceOnce | provenance | | -| test.ps1:5:6:5:20 | call to callSourceOnce | test.ps1:6:6:6:8 | x | provenance | | -| test.ps1:9:5:9:15 | call to Source | test.ps1:13:6:13:21 | call to callSourceTwice [element] | provenance | | -| test.ps1:10:5:10:15 | call to Source | test.ps1:13:6:13:21 | call to callSourceTwice [element] | provenance | | -| test.ps1:13:6:13:21 | call to callSourceTwice [element] | test.ps1:15:6:15:8 | x [element] | provenance | | -| test.ps1:13:6:13:21 | call to callSourceTwice [element] | test.ps1:16:6:16:8 | x [element] | provenance | | -| test.ps1:15:6:15:8 | x [element] | test.ps1:15:6:15:11 | ...[...] | provenance | | -| test.ps1:16:6:16:8 | x [element] | test.ps1:16:6:16:11 | ...[...] | provenance | | -| test.ps1:19:12:19:22 | call to Source | test.ps1:22:6:22:19 | call to returnSource1 | provenance | | -| test.ps1:22:6:22:19 | call to returnSource1 | test.ps1:23:6:23:8 | x | provenance | | -| test.ps1:26:10:26:20 | call to Source | test.ps1:27:5:27:7 | x | provenance | | -| test.ps1:27:5:27:7 | x | test.ps1:32:6:32:19 | call to returnSource2 [element] | provenance | | -| test.ps1:28:10:28:20 | call to Source | test.ps1:29:12:29:14 | y | provenance | | -| test.ps1:29:12:29:14 | y | test.ps1:32:6:32:19 | call to returnSource2 [element] | provenance | | -| test.ps1:32:6:32:19 | call to returnSource2 [element] | test.ps1:33:6:33:8 | x [element] | provenance | | -| test.ps1:32:6:32:19 | call to returnSource2 [element] | test.ps1:34:6:34:8 | x [element] | provenance | | -| test.ps1:33:6:33:8 | x [element] | test.ps1:33:6:33:11 | ...[...] | provenance | | -| test.ps1:34:6:34:8 | x [element] | test.ps1:34:6:34:11 | ...[...] | provenance | | -| test.ps1:38:9:38:19 | call to Source | test.ps1:42:6:42:22 | call to callSourceInLoop [element] | provenance | | -| test.ps1:42:6:42:22 | call to callSourceInLoop [element] | test.ps1:43:6:43:8 | x [element] | provenance | | -| test.ps1:42:6:42:22 | call to callSourceInLoop [element] | test.ps1:44:6:44:8 | x [element] | provenance | | -| test.ps1:43:6:43:8 | x [element] | test.ps1:43:6:43:11 | ...[...] | provenance | | -| test.ps1:44:6:44:8 | x [element] | test.ps1:44:6:44:11 | ...[...] | provenance | | +| test.ps1:2:5:2:14 | Call to Source | test.ps1:5:6:5:19 | Call to callSourceOnce | provenance | | +| test.ps1:5:6:5:19 | Call to callSourceOnce | test.ps1:6:6:6:7 | x | provenance | | +| test.ps1:9:5:9:14 | Call to Source | test.ps1:13:6:13:20 | Call to callSourceTwice [element] | provenance | | +| test.ps1:10:5:10:14 | Call to Source | test.ps1:13:6:13:20 | Call to callSourceTwice [element] | provenance | | +| test.ps1:13:6:13:20 | Call to callSourceTwice [element] | test.ps1:15:6:15:7 | x [element] | provenance | | +| test.ps1:13:6:13:20 | Call to callSourceTwice [element] | test.ps1:16:6:16:7 | x [element] | provenance | | +| test.ps1:15:6:15:7 | x [element] | test.ps1:15:6:15:10 | ...[...] | provenance | | +| test.ps1:16:6:16:7 | x [element] | test.ps1:16:6:16:10 | ...[...] | provenance | | +| test.ps1:38:9:38:18 | Call to Source | test.ps1:42:6:42:21 | Call to callSourceInLoop [element] | provenance | | +| test.ps1:42:6:42:21 | Call to callSourceInLoop [element] | test.ps1:43:6:43:7 | x [element] | provenance | | +| test.ps1:42:6:42:21 | Call to callSourceInLoop [element] | test.ps1:44:6:44:7 | x [element] | provenance | | +| test.ps1:43:6:43:7 | x [element] | test.ps1:43:6:43:10 | ...[...] | provenance | | +| test.ps1:44:6:44:7 | x [element] | test.ps1:44:6:44:10 | ...[...] | provenance | | nodes -| test.ps1:2:5:2:15 | call to Source | semmle.label | call to Source | -| test.ps1:5:6:5:20 | call to callSourceOnce | semmle.label | call to callSourceOnce | -| test.ps1:6:6:6:8 | x | semmle.label | x | -| test.ps1:9:5:9:15 | call to Source | semmle.label | call to Source | -| test.ps1:10:5:10:15 | call to Source | semmle.label | call to Source | -| test.ps1:13:6:13:21 | call to callSourceTwice [element] | semmle.label | call to callSourceTwice [element] | -| test.ps1:15:6:15:8 | x [element] | semmle.label | x [element] | -| test.ps1:15:6:15:11 | ...[...] | semmle.label | ...[...] | -| test.ps1:16:6:16:8 | x [element] | semmle.label | x [element] | -| test.ps1:16:6:16:11 | ...[...] | semmle.label | ...[...] | -| test.ps1:19:12:19:22 | call to Source | semmle.label | call to Source | -| test.ps1:22:6:22:19 | call to returnSource1 | semmle.label | call to returnSource1 | -| test.ps1:23:6:23:8 | x | semmle.label | x | -| test.ps1:26:10:26:20 | call to Source | semmle.label | call to Source | -| test.ps1:27:5:27:7 | x | semmle.label | x | -| test.ps1:28:10:28:20 | call to Source | semmle.label | call to Source | -| test.ps1:29:12:29:14 | y | semmle.label | y | -| test.ps1:32:6:32:19 | call to returnSource2 [element] | semmle.label | call to returnSource2 [element] | -| test.ps1:33:6:33:8 | x [element] | semmle.label | x [element] | -| test.ps1:33:6:33:11 | ...[...] | semmle.label | ...[...] | -| test.ps1:34:6:34:8 | x [element] | semmle.label | x [element] | -| test.ps1:34:6:34:11 | ...[...] | semmle.label | ...[...] | -| test.ps1:38:9:38:19 | call to Source | semmle.label | call to Source | -| test.ps1:42:6:42:22 | call to callSourceInLoop [element] | semmle.label | call to callSourceInLoop [element] | -| test.ps1:43:6:43:8 | x [element] | semmle.label | x [element] | -| test.ps1:43:6:43:11 | ...[...] | semmle.label | ...[...] | -| test.ps1:44:6:44:8 | x [element] | semmle.label | x [element] | -| test.ps1:44:6:44:11 | ...[...] | semmle.label | ...[...] | +| test.ps1:2:5:2:14 | Call to Source | semmle.label | Call to Source | +| test.ps1:5:6:5:19 | Call to callSourceOnce | semmle.label | Call to callSourceOnce | +| test.ps1:6:6:6:7 | x | semmle.label | x | +| test.ps1:9:5:9:14 | Call to Source | semmle.label | Call to Source | +| test.ps1:10:5:10:14 | Call to Source | semmle.label | Call to Source | +| test.ps1:13:6:13:20 | Call to callSourceTwice [element] | semmle.label | Call to callSourceTwice [element] | +| test.ps1:15:6:15:7 | x [element] | semmle.label | x [element] | +| test.ps1:15:6:15:10 | ...[...] | semmle.label | ...[...] | +| test.ps1:16:6:16:7 | x [element] | semmle.label | x [element] | +| test.ps1:16:6:16:10 | ...[...] | semmle.label | ...[...] | +| test.ps1:38:9:38:18 | Call to Source | semmle.label | Call to Source | +| test.ps1:42:6:42:21 | Call to callSourceInLoop [element] | semmle.label | Call to callSourceInLoop [element] | +| test.ps1:43:6:43:7 | x [element] | semmle.label | x [element] | +| test.ps1:43:6:43:10 | ...[...] | semmle.label | ...[...] | +| test.ps1:44:6:44:7 | x [element] | semmle.label | x [element] | +| test.ps1:44:6:44:10 | ...[...] | semmle.label | ...[...] | subpaths testFailures +| test.ps1:23:9:23:26 | # $ hasValueFlow=4 | Missing result: hasValueFlow=4 | +| test.ps1:33:12:33:54 | # $ hasValueFlow=5 SPURIOUS: hasValueFlow=6 | Fixed spurious result: hasValueFlow=6 | +| test.ps1:33:12:33:54 | # $ hasValueFlow=5 SPURIOUS: hasValueFlow=6 | Missing result: hasValueFlow=5 | +| test.ps1:34:12:34:54 | # $ hasValueFlow=6 SPURIOUS: hasValueFlow=5 | Fixed spurious result: hasValueFlow=5 | +| test.ps1:34:12:34:54 | # $ hasValueFlow=6 SPURIOUS: hasValueFlow=5 | Missing result: hasValueFlow=6 | #select -| test.ps1:6:6:6:8 | x | test.ps1:2:5:2:15 | call to Source | test.ps1:6:6:6:8 | x | $@ | test.ps1:2:5:2:15 | call to Source | call to Source | -| test.ps1:15:6:15:11 | ...[...] | test.ps1:9:5:9:15 | call to Source | test.ps1:15:6:15:11 | ...[...] | $@ | test.ps1:9:5:9:15 | call to Source | call to Source | -| test.ps1:15:6:15:11 | ...[...] | test.ps1:10:5:10:15 | call to Source | test.ps1:15:6:15:11 | ...[...] | $@ | test.ps1:10:5:10:15 | call to Source | call to Source | -| test.ps1:16:6:16:11 | ...[...] | test.ps1:9:5:9:15 | call to Source | test.ps1:16:6:16:11 | ...[...] | $@ | test.ps1:9:5:9:15 | call to Source | call to Source | -| test.ps1:16:6:16:11 | ...[...] | test.ps1:10:5:10:15 | call to Source | test.ps1:16:6:16:11 | ...[...] | $@ | test.ps1:10:5:10:15 | call to Source | call to Source | -| test.ps1:23:6:23:8 | x | test.ps1:19:12:19:22 | call to Source | test.ps1:23:6:23:8 | x | $@ | test.ps1:19:12:19:22 | call to Source | call to Source | -| test.ps1:33:6:33:11 | ...[...] | test.ps1:26:10:26:20 | call to Source | test.ps1:33:6:33:11 | ...[...] | $@ | test.ps1:26:10:26:20 | call to Source | call to Source | -| test.ps1:33:6:33:11 | ...[...] | test.ps1:28:10:28:20 | call to Source | test.ps1:33:6:33:11 | ...[...] | $@ | test.ps1:28:10:28:20 | call to Source | call to Source | -| test.ps1:34:6:34:11 | ...[...] | test.ps1:26:10:26:20 | call to Source | test.ps1:34:6:34:11 | ...[...] | $@ | test.ps1:26:10:26:20 | call to Source | call to Source | -| test.ps1:34:6:34:11 | ...[...] | test.ps1:28:10:28:20 | call to Source | test.ps1:34:6:34:11 | ...[...] | $@ | test.ps1:28:10:28:20 | call to Source | call to Source | -| test.ps1:43:6:43:11 | ...[...] | test.ps1:38:9:38:19 | call to Source | test.ps1:43:6:43:11 | ...[...] | $@ | test.ps1:38:9:38:19 | call to Source | call to Source | -| test.ps1:44:6:44:11 | ...[...] | test.ps1:38:9:38:19 | call to Source | test.ps1:44:6:44:11 | ...[...] | $@ | test.ps1:38:9:38:19 | call to Source | call to Source | +| test.ps1:6:6:6:7 | x | test.ps1:2:5:2:14 | Call to Source | test.ps1:6:6:6:7 | x | $@ | test.ps1:2:5:2:14 | Call to Source | Call to Source | +| test.ps1:15:6:15:10 | ...[...] | test.ps1:9:5:9:14 | Call to Source | test.ps1:15:6:15:10 | ...[...] | $@ | test.ps1:9:5:9:14 | Call to Source | Call to Source | +| test.ps1:15:6:15:10 | ...[...] | test.ps1:10:5:10:14 | Call to Source | test.ps1:15:6:15:10 | ...[...] | $@ | test.ps1:10:5:10:14 | Call to Source | Call to Source | +| test.ps1:16:6:16:10 | ...[...] | test.ps1:9:5:9:14 | Call to Source | test.ps1:16:6:16:10 | ...[...] | $@ | test.ps1:9:5:9:14 | Call to Source | Call to Source | +| test.ps1:16:6:16:10 | ...[...] | test.ps1:10:5:10:14 | Call to Source | test.ps1:16:6:16:10 | ...[...] | $@ | test.ps1:10:5:10:14 | Call to Source | Call to Source | +| test.ps1:43:6:43:10 | ...[...] | test.ps1:38:9:38:18 | Call to Source | test.ps1:43:6:43:10 | ...[...] | $@ | test.ps1:38:9:38:18 | Call to Source | Call to Source | +| test.ps1:44:6:44:10 | ...[...] | test.ps1:38:9:38:18 | Call to Source | test.ps1:44:6:44:10 | ...[...] | $@ | test.ps1:38:9:38:18 | Call to Source | Call to Source | diff --git a/powershell/ql/test/library-tests/dataflow/typetracking/test.expected b/powershell/ql/test/library-tests/dataflow/typetracking/test.expected index 8ec8033d086e..8748ef879ad2 100644 --- a/powershell/ql/test/library-tests/dataflow/typetracking/test.expected +++ b/powershell/ql/test/library-tests/dataflow/typetracking/test.expected @@ -1,2 +1,2 @@ -testFailures -failures +| test.ps1:15:20:15:36 | # $ type=PSObject | Missing result: type=PSObject | +| test.ps1:19:25:19:41 | # $ type=PSObject | Missing result: type=PSObject | diff --git a/powershell/ql/test/library-tests/ssa/ssa.expected b/powershell/ql/test/library-tests/ssa/ssa.expected index 3dc5c8e4c07f..1cfa0788bbc6 100644 --- a/powershell/ql/test/library-tests/ssa/ssa.expected +++ b/powershell/ql/test/library-tests/ssa/ssa.expected @@ -1,7 +1,6 @@ -| explicit.ps1:1:1:8:2 | glob_a | explicit.ps1:2:11:2:18 | glob_a | -| explicit.ps1:5:5:5:7 | a | explicit.ps1:5:5:5:7 | a | -| explicit.ps1:6:5:6:7 | b | explicit.ps1:6:5:6:7 | b | -| parameters.ps1:1:25:1:33 | n1 | parameters.ps1:1:25:1:33 | n1 | -| parameters.ps1:1:35:1:43 | n2 | parameters.ps1:1:35:1:43 | n2 | -| parameters.ps1:7:9:7:16 | a | parameters.ps1:7:9:7:16 | a | -| parameters.ps1:8:9:8:16 | b | parameters.ps1:8:9:8:16 | b | +| explicit.ps1:5:5:5:6 | a | explicit.ps1:5:5:5:6 | a | +| explicit.ps1:6:5:6:6 | b | explicit.ps1:6:5:6:6 | b | +| parameters.ps1:1:45:3:1 | n1 | parameters.ps1:1:45:3:1 | n1 | +| parameters.ps1:1:45:3:1 | n2 | parameters.ps1:1:45:3:1 | n2 | +| parameters.ps1:5:22:11:1 | a | parameters.ps1:5:22:11:1 | a | +| parameters.ps1:5:22:11:1 | b | parameters.ps1:5:22:11:1 | b | diff --git a/powershell/ql/test/query-tests/security/cwe-078/CommandInjection/CommandInjection.expected b/powershell/ql/test/query-tests/security/cwe-078/CommandInjection/CommandInjection.expected index 53e66a64f682..e217064d1dfc 100644 --- a/powershell/ql/test/query-tests/security/cwe-078/CommandInjection/CommandInjection.expected +++ b/powershell/ql/test/query-tests/security/cwe-078/CommandInjection/CommandInjection.expected @@ -1,12 +1,4 @@ edges -| test.ps1:1:8:1:10 | x | test.ps1:3:28:3:48 | Get-Process -Id $x | provenance | | -| test.ps1:5:10:5:21 | Env:MY_VAR | test.ps1:7:3:7:20 | $code --enabled | provenance | | nodes -| test.ps1:1:8:1:10 | x | semmle.label | x | -| test.ps1:3:28:3:48 | Get-Process -Id $x | semmle.label | Get-Process -Id $x | -| test.ps1:5:10:5:21 | Env:MY_VAR | semmle.label | Env:MY_VAR | -| test.ps1:7:3:7:20 | $code --enabled | semmle.label | $code --enabled | subpaths #select -| test.ps1:3:28:3:48 | Get-Process -Id $x | test.ps1:1:8:1:10 | x | test.ps1:3:28:3:48 | Get-Process -Id $x | This command depends on a $@. | test.ps1:1:8:1:10 | x | user-provided value | -| test.ps1:7:3:7:20 | $code --enabled | test.ps1:5:10:5:21 | Env:MY_VAR | test.ps1:7:3:7:20 | $code --enabled | This command depends on a $@. | test.ps1:5:10:5:21 | Env:MY_VAR | user-provided value | diff --git a/powershell/ql/test/query-tests/security/cwe-078/DoNotUseInvokeExpression/DoNotUseInvokeExpression.expected b/powershell/ql/test/query-tests/security/cwe-078/DoNotUseInvokeExpression/DoNotUseInvokeExpression.expected index 3b7235e641f0..738c250420e5 100644 --- a/powershell/ql/test/query-tests/security/cwe-078/DoNotUseInvokeExpression/DoNotUseInvokeExpression.expected +++ b/powershell/ql/test/query-tests/security/cwe-078/DoNotUseInvokeExpression/DoNotUseInvokeExpression.expected @@ -1 +1 @@ -| test.ps1:2:1:2:27 | call to Invoke-Expression | Do not use Invoke-Expression. It is a command injection risk. | +| test.ps1:2:1:2:26 | Call to Invoke-Expression | Do not use Invoke-Expression. It is a command injection risk. |