From 44e4e3eb5463f67928f4449f1726597da6f632cd Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Tue, 25 Mar 2025 16:59:28 +0000 Subject: [PATCH 01/26] PS: Extract more powershell files and fix off-by-one error in locations. --- powershell/codeql-extractor.yml | 3 ++- .../Semmle.Extraction.PowerShell.Standalone/Options.cs | 2 +- powershell/extractor/Semmle.Extraction/Tuples.cs | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) 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); } } } From d79eb013c81e3a45112e1f39425421ef84af9b2e Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 26 Mar 2025 18:00:10 +0000 Subject: [PATCH 02/26] PS: Delete the old AST. --- .../code/powershell/ArrayExpression.qll | 26 - .../semmle/code/powershell/ArrayLiteral.qll | 11 - .../code/powershell/AssignmentStatement.qll | 13 - .../ql/lib/semmle/code/powershell/Ast.qll | 14 - .../lib/semmle/code/powershell/Attribute.qll | 25 - .../semmle/code/powershell/AttributeBase.qll | 3 - .../powershell/BaseConstantExpression.qll | 13 - .../code/powershell/BinaryExpression.qll | 319 ---- .../lib/semmle/code/powershell/BreakStmt.qll | 7 - .../ql/lib/semmle/code/powershell/Call.qll | 79 - .../semmle/code/powershell/CatchClause.qll | 39 - .../lib/semmle/code/powershell/Chainable.qll | 3 - .../ql/lib/semmle/code/powershell/Command.qll | 114 -- .../semmle/code/powershell/CommandBase.qll | 3 - .../semmle/code/powershell/CommandElement.qll | 3 - .../code/powershell/CommandExpression.qll | 15 - .../code/powershell/CommandParameter.qll | 23 - .../semmle/code/powershell/CommentEntity.qll | 17 - .../semmle/code/powershell/Configuration.qll | 15 - .../code/powershell/ConstantExpression.qll | 127 -- .../semmle/code/powershell/ContinueStmt.qll | 7 - .../semmle/code/powershell/ConvertExpr.qll | 13 - .../lib/semmle/code/powershell/DataStmt.qll | 15 - .../semmle/code/powershell/DoUntilStmt.qll | 11 - .../semmle/code/powershell/DoWhileStmt.qll | 11 - .../semmle/code/powershell/DynamicStmt.qll | 11 - .../lib/semmle/code/powershell/ErrorExpr.qll | 7 - .../lib/semmle/code/powershell/ErrorStmt.qll | 7 - .../lib/semmle/code/powershell/ExitStmt.qll | 12 - .../powershell/ExpandableStringExpression.qll | 15 - .../lib/semmle/code/powershell/Expression.qll | 11 - .../ql/lib/semmle/code/powershell/File.qll | 224 --- .../code/powershell/FileRedirection.qll | 7 - .../semmle/code/powershell/ForEachStmt.qll | 23 - .../ql/lib/semmle/code/powershell/ForStmt.qll | 15 - .../lib/semmle/code/powershell/Function.qll | 127 -- .../lib/semmle/code/powershell/GotoStmt.qll | 8 - .../lib/semmle/code/powershell/HashTable.qll | 21 - .../ql/lib/semmle/code/powershell/IfStmt.qll | 24 - .../lib/semmle/code/powershell/IndexExpr.qll | 30 - .../powershell/InvokeMemberExpression.qll | 49 - .../semmle/code/powershell/LabeledStmt.qll | 5 - .../lib/semmle/code/powershell/Location.qll | 52 - .../lib/semmle/code/powershell/LoopStmt.qll | 5 - .../ql/lib/semmle/code/powershell/Member.qll | 17 - .../lib/semmle/code/powershell/MemberExpr.qll | 28 - .../code/powershell/MemberExpressionBase.qll | 5 - .../code/powershell/MergingRedirection.qll | 7 - .../semmle/code/powershell/ModuleManifest.qll | 44 - .../code/powershell/ModuleSpecification.qll | 17 - .../powershell/NamedAttributeArgument.qll | 21 - .../lib/semmle/code/powershell/NamedBlock.qll | 19 - .../semmle/code/powershell/ObjectCreation.qll | 55 - .../lib/semmle/code/powershell/ParamBlock.qll | 21 - .../code/powershell/ParenExpression.qll | 9 - .../lib/semmle/code/powershell/Pipeline.qll | 17 - .../semmle/code/powershell/PipelineBase.qll | 3 - .../semmle/code/powershell/PipelineChain.qll | 11 - .../semmle/code/powershell/PropertyMember.qll | 17 - .../semmle/code/powershell/Redirection.qll | 3 - .../lib/semmle/code/powershell/ReturnStmt.qll | 13 - .../semmle/code/powershell/ScriptBlock.qll | 111 -- .../code/powershell/ScriptBlockExpr.qll | 9 - .../semmle/code/powershell/SourceLocation.qll | 25 - .../lib/semmle/code/powershell/SplitExpr.qll | 28 - .../lib/semmle/code/powershell/Statement.qll | 3 - .../semmle/code/powershell/StatementBlock.qll | 32 - .../powershell/StringConstantExpression.qll | 10 - .../semmle/code/powershell/StringLiteral.qll | 16 - .../semmle/code/powershell/SubExpression.qll | 10 - .../lib/semmle/code/powershell/SwitchStmt.qll | 25 - .../code/powershell/TernaryExpression.qll | 23 - .../lib/semmle/code/powershell/ThrowStmt.qll | 13 - .../lib/semmle/code/powershell/TokenKind.qll | 1345 ----------------- .../semmle/code/powershell/TrapStatement.qll | 7 - .../ql/lib/semmle/code/powershell/TryStmt.qll | 18 - .../ql/lib/semmle/code/powershell/Type.qll | 31 - .../semmle/code/powershell/TypeConstraint.qll | 13 - .../semmle/code/powershell/TypeExpression.qll | 14 - .../code/powershell/UnaryExpression.qll | 73 - .../code/powershell/UsingExpression.qll | 7 - .../lib/semmle/code/powershell/UsingStmt.qll | 21 - .../lib/semmle/code/powershell/Variable.qll | 406 ----- .../code/powershell/VariableExpression.qll | 59 - .../lib/semmle/code/powershell/WhileStmt.qll | 11 - .../powershell/controlflow/internal/Scope.qll | 20 - .../code/powershell/internal/Internal.qll | 13 - .../code/powershell/internal/Operation.qll | 31 - .../code/powershell/internal/Parameter.qll | 28 - 89 files changed, 4288 deletions(-) delete mode 100644 powershell/ql/lib/semmle/code/powershell/ArrayExpression.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/ArrayLiteral.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/AssignmentStatement.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/Ast.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/Attribute.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/AttributeBase.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/BaseConstantExpression.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/BinaryExpression.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/BreakStmt.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/Call.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/CatchClause.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/Chainable.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/Command.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/CommandBase.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/CommandElement.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/CommandExpression.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/CommandParameter.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/CommentEntity.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/Configuration.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/ConstantExpression.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/ContinueStmt.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/ConvertExpr.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/DataStmt.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/DoUntilStmt.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/DoWhileStmt.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/DynamicStmt.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/ErrorExpr.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/ErrorStmt.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/ExitStmt.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/ExpandableStringExpression.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/Expression.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/File.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/FileRedirection.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/ForEachStmt.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/ForStmt.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/Function.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/GotoStmt.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/HashTable.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/IfStmt.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/IndexExpr.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/InvokeMemberExpression.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/LabeledStmt.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/Location.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/LoopStmt.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/Member.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/MemberExpr.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/MemberExpressionBase.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/MergingRedirection.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/ModuleManifest.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/ModuleSpecification.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/NamedAttributeArgument.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/NamedBlock.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/ObjectCreation.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/ParamBlock.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/ParenExpression.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/Pipeline.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/PipelineBase.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/PipelineChain.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/PropertyMember.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/Redirection.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/ReturnStmt.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/ScriptBlock.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/ScriptBlockExpr.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/SourceLocation.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/SplitExpr.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/Statement.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/StatementBlock.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/StringConstantExpression.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/StringLiteral.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/SubExpression.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/SwitchStmt.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/TernaryExpression.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/ThrowStmt.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/TokenKind.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/TrapStatement.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/TryStmt.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/Type.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/TypeConstraint.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/TypeExpression.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/UnaryExpression.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/UsingExpression.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/UsingStmt.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/Variable.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/VariableExpression.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/WhileStmt.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/controlflow/internal/Scope.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/internal/Internal.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/internal/Operation.qll delete mode 100644 powershell/ql/lib/semmle/code/powershell/internal/Parameter.qll 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/ArrayLiteral.qll b/powershell/ql/lib/semmle/code/powershell/ArrayLiteral.qll deleted file mode 100644 index 447d26b45e36..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/ArrayLiteral.qll +++ /dev/null @@ -1,11 +0,0 @@ -import powershell - -class ArrayLiteral extends @array_literal, Expr { - override SourceLocation getLocation() { array_literal_location(this, result) } - - Expr getElement(int index) { array_literal_element(this, index, result) } - - Expr getAnElement() { array_literal_element(this, _, result) } - - override string toString() { result = "...,..." } -} diff --git a/powershell/ql/lib/semmle/code/powershell/AssignmentStatement.qll b/powershell/ql/lib/semmle/code/powershell/AssignmentStatement.qll deleted file mode 100644 index 10bfaed20661..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/AssignmentStatement.qll +++ /dev/null @@ -1,13 +0,0 @@ -import powershell - -class AssignStmt extends @assignment_statement, PipelineBase { - override SourceLocation getLocation() { assignment_statement_location(this, result) } - - int getKind() { assignment_statement(this, result, _, _) } - - Expr getLeftHandSide() { assignment_statement(this, _, result, _) } - - Stmt getRightHandSide() { assignment_statement(this, _, _, result) } - - 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/Attribute.qll b/powershell/ql/lib/semmle/code/powershell/Attribute.qll deleted file mode 100644 index 72a061c09f2a..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/Attribute.qll +++ /dev/null @@ -1,25 +0,0 @@ -import powershell - -class Attribute extends @attribute, AttributeBase { - override string toString() { result = this.getName() } - - override SourceLocation getLocation() { attribute_location(this, result) } - - string getName() { attribute(this, result, _, _) } - - int getNumNamedArguments() { attribute(this, _, result, _) } - - int getNumPositionalArguments() { attribute(this, _, _, result) } - - NamedAttributeArgument getNamedArgument(int i) { attribute_named_argument(this, i, result) } - - NamedAttributeArgument getANamedArgument() { result = this.getNamedArgument(_) } - - int getNumberOfArguments() { result = count(this.getAPositionalArgument()) } - - Expr getPositionalArgument(int i) { attribute_positional_argument(this, i, result) } - - Expr getAPositionalArgument() { result = this.getPositionalArgument(_) } - - int getNumberOfPositionalArguments() { result = count(this.getAPositionalArgument()) } -} diff --git a/powershell/ql/lib/semmle/code/powershell/AttributeBase.qll b/powershell/ql/lib/semmle/code/powershell/AttributeBase.qll deleted file mode 100644 index a0a5a36cdb10..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/AttributeBase.qll +++ /dev/null @@ -1,3 +0,0 @@ -import powershell - -class AttributeBase extends @attribute_base, Ast { } diff --git a/powershell/ql/lib/semmle/code/powershell/BaseConstantExpression.qll b/powershell/ql/lib/semmle/code/powershell/BaseConstantExpression.qll deleted file mode 100644 index c495e5da1859..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/BaseConstantExpression.qll +++ /dev/null @@ -1,13 +0,0 @@ -import powershell - -/** The base class for constant expressions. */ -class BaseConstExpr extends @base_constant_expression, Expr { - /** Gets the type of this constant expression. */ - string getType() { none() } - - /** 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/BinaryExpression.qll b/powershell/ql/lib/semmle/code/powershell/BinaryExpression.qll deleted file mode 100644 index 7e7d4011b7f9..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/BinaryExpression.qll +++ /dev/null @@ -1,319 +0,0 @@ -import powershell - -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() - } - - /** 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 { } - -final class ArithmeticExpr = AbstractArithmeticExpr; - -class AddExpr extends AbstractArithmeticExpr { - AddExpr() { this.getKind() = 40 } - - final override string toString() { result = "...+..." } -} - -class SubExpr extends AbstractArithmeticExpr { - SubExpr() { this.getKind() = 41 } - - final override string toString() { result = "...-..." } -} - -class MulExpr extends AbstractArithmeticExpr { - MulExpr() { this.getKind() = 37 } - - final override string toString() { result = "...*..." } -} - -class DivExpr extends AbstractArithmeticExpr { - DivExpr() { this.getKind() = 38 } - - final override string toString() { result = ".../..." } -} - -class RemExpr extends AbstractArithmeticExpr { - RemExpr() { this.getKind() = 39 } - - final override string toString() { result = "...%..." } -} - -abstract private class AbstractBitwiseExpr extends BinaryExpr { } - -final class BitwiseExpr = AbstractBitwiseExpr; - -class BitwiseAndExpr extends AbstractBitwiseExpr { - BitwiseAndExpr() { this.getKind() = 56 } - - final override string toString() { result = "...&..." } -} - -class BitwiseOrExpr extends AbstractBitwiseExpr { - BitwiseOrExpr() { this.getKind() = 57 } - - final override string toString() { result = "...|..." } -} - -class BitwiseXorExpr extends AbstractBitwiseExpr { - BitwiseXorExpr() { this.getKind() = 58 } - - final override string toString() { result = "...^..." } -} - -class ShiftLeftExpr extends AbstractBitwiseExpr { - ShiftLeftExpr() { this.getKind() = 97 } - - final override string toString() { result = "...<<..." } -} - -class ShiftRightExpr extends AbstractBitwiseExpr { - ShiftRightExpr() { this.getKind() = 98 } - - final override string toString() { result = "...>>..." } -} - -abstract private class AbstractComparisonExpr extends BinaryExpr { } - -final class ComparisonExpr = AbstractComparisonExpr; - -abstract private class AbstractCaseInsensitiveComparisonExpr extends AbstractComparisonExpr { } - -final class CaseInsensitiveComparisonExpr = AbstractCaseInsensitiveComparisonExpr; - -abstract private class AbstractCaseSensitiveComparisonExpr extends AbstractComparisonExpr { } - -final class CaseSensitiveComparisonExpr = AbstractCaseSensitiveComparisonExpr; - -class EqExpr extends AbstractCaseInsensitiveComparisonExpr { - EqExpr() { this.getKind() = 60 } - - final override string toString() { result = "... -eq ..." } -} - -class NeExpr extends AbstractCaseInsensitiveComparisonExpr { - NeExpr() { this.getKind() = 61 } - - final override string toString() { result = "... -ne ..." } -} - -class CEqExpr extends AbstractCaseSensitiveComparisonExpr { - CEqExpr() { this.getKind() = 76 } - - final override string toString() { result = "... -ceq ..." } -} - -class CNeExpr extends AbstractCaseSensitiveComparisonExpr { - CNeExpr() { this.getKind() = 77 } - - final override string toString() { result = "... -cne ..." } -} - -abstract private class AbstractRelationalExpr extends AbstractComparisonExpr { } - -final class RelationalExpr = AbstractRelationalExpr; - -abstract private class AbstractCaseInsensitiveRelationalExpr extends AbstractRelationalExpr { } - -final class CaseInsensitiveRelationalExpr = AbstractCaseInsensitiveRelationalExpr; - -abstract private class AbstractCaseSensitiveRelationalExpr extends AbstractRelationalExpr { } - -final class CaseSensitiveRelationalExpr = AbstractCaseSensitiveRelationalExpr; - -class GeExpr extends AbstractCaseInsensitiveRelationalExpr { - GeExpr() { this.getKind() = 62 } - - final override string toString() { result = "... -ge ..." } -} - -class GtExpr extends AbstractCaseInsensitiveRelationalExpr { - GtExpr() { this.getKind() = 63 } - - final override string toString() { result = "... -gt ..." } -} - -class LtExpr extends AbstractCaseInsensitiveRelationalExpr { - LtExpr() { this.getKind() = 64 } - - final override string toString() { result = "... -lt ..." } -} - -class LeExpr extends AbstractCaseInsensitiveRelationalExpr { - LeExpr() { this.getKind() = 65 } - - final override string toString() { result = "... -le ..." } -} - -class CGeExpr extends AbstractCaseSensitiveRelationalExpr { - CGeExpr() { this.getKind() = 78 } - - final override string toString() { result = "... -cge ..." } -} - -class CGtExpr extends AbstractCaseSensitiveRelationalExpr { - CGtExpr() { this.getKind() = 79 } - - final override string toString() { result = "... -cgt ..." } -} - -class CLtExpr extends AbstractCaseSensitiveRelationalExpr { - CLtExpr() { this.getKind() = 80 } - - final override string toString() { result = "... -clt ..." } -} - -class CLeExpr extends AbstractCaseSensitiveRelationalExpr { - CLeExpr() { this.getKind() = 81 } - - final override string toString() { result = "... -cle ..." } -} - -class LikeExpr extends AbstractCaseInsensitiveComparisonExpr { - LikeExpr() { this.getKind() = 66 } - - final override string toString() { result = "... -like ..." } -} - -class NotLikeExpr extends AbstractCaseInsensitiveComparisonExpr { - NotLikeExpr() { this.getKind() = 67 } - - final override string toString() { result = "... -notlike ..." } -} - -class MatchExpr extends AbstractCaseInsensitiveComparisonExpr { - MatchExpr() { this.getKind() = 68 } - - final override string toString() { result = "... -match ..." } -} - -class NotMatchExpr extends AbstractCaseInsensitiveComparisonExpr { - NotMatchExpr() { this.getKind() = 69 } - - final override string toString() { result = "... -notmatch ..." } -} - -class ReplaceExpr extends AbstractCaseInsensitiveComparisonExpr { - ReplaceExpr() { this.getKind() = 70 } - - final override string toString() { result = "... -replace ..." } -} - -abstract class AbstractTypeExpr extends BinaryExpr { } - -final class TypeExpr = AbstractTypeExpr; - -abstract class AbstractTypeComparisonExpr extends AbstractTypeExpr { } - -final class TypeComparisonExpr = AbstractTypeComparisonExpr; - -class IsExpr extends AbstractTypeComparisonExpr { - IsExpr() { this.getKind() = 92 } - - final override string toString() { result = "... -is ..." } -} - -class IsNotExpr extends AbstractTypeComparisonExpr { - IsNotExpr() { this.getKind() = 93 } - - final override string toString() { result = "... -isnot ..." } -} - -class AsExpr extends AbstractTypeExpr { - AsExpr() { this.getKind() = 94 } - - final override string toString() { result = "... -as ..." } -} - -abstract private class AbstractContainmentExpr extends BinaryExpr { } - -final class ContainmentExpr = AbstractContainmentExpr; - -abstract private class AbstractCaseInsensitiveContainmentExpr extends AbstractContainmentExpr { } - -final class CaseInsensitiveContainmentExpr = AbstractCaseInsensitiveContainmentExpr; - -class ContainsExpr extends AbstractCaseInsensitiveContainmentExpr { - ContainsExpr() { this.getKind() = 71 } - - final override string toString() { result = "... -contains ..." } -} - -class NotContainsExpr extends AbstractCaseInsensitiveContainmentExpr { - NotContainsExpr() { this.getKind() = 72 } - - final override string toString() { result = "... -notcontains ..." } -} - -class InExpr extends AbstractCaseInsensitiveContainmentExpr { - InExpr() { this.getKind() = 73 } - - final override string toString() { result = "... -in ..." } -} - -class NotInExpr extends AbstractCaseInsensitiveContainmentExpr { - NotInExpr() { this.getKind() = 74 } - - final override string toString() { result = "... -notin ..." } -} - -abstract private class AbstractLogicalBinaryExpr extends BinaryExpr { } - -final class LogicalBinaryExpr = AbstractLogicalBinaryExpr; - -class LogicalAndExpr extends AbstractLogicalBinaryExpr { - LogicalAndExpr() { this.getKind() = 53 } - - final override string toString() { result = "... -and ..." } -} - -class LogicalOrExpr extends AbstractLogicalBinaryExpr { - LogicalOrExpr() { this.getKind() = 54 } - - final override string toString() { result = "... -or ..." } -} - -class LogicalXorExpr extends AbstractLogicalBinaryExpr { - LogicalXorExpr() { this.getKind() = 55 } - - final override string toString() { result = "... -xor ..." } -} - -class JoinExpr extends BinaryExpr { - JoinExpr() { this.getKind() = 59 } - - final override string toString() { result = "... -join ..." } -} - -class SequenceExpr extends BinaryExpr { - SequenceExpr() { this.getKind() = 33 } - - final override string toString() { result = "[..]" } -} - -class FormatExpr extends BinaryExpr { - FormatExpr() { this.getKind() = 50 } - - final override string toString() { result = "... -f ..." } -} diff --git a/powershell/ql/lib/semmle/code/powershell/BreakStmt.qll b/powershell/ql/lib/semmle/code/powershell/BreakStmt.qll deleted file mode 100644 index abd74f3e682f..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/BreakStmt.qll +++ /dev/null @@ -1,7 +0,0 @@ -import powershell - -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/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/Chainable.qll b/powershell/ql/lib/semmle/code/powershell/Chainable.qll deleted file mode 100644 index 273ccc48113a..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/Chainable.qll +++ /dev/null @@ -1,3 +0,0 @@ -import powershell - -class Chainable extends @chainable, PipelineBase { } 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/CommandBase.qll b/powershell/ql/lib/semmle/code/powershell/CommandBase.qll deleted file mode 100644 index 2ca1342a826f..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/CommandBase.qll +++ /dev/null @@ -1,3 +0,0 @@ -import powershell - -class CmdBase extends @command_base, Chainable { } diff --git a/powershell/ql/lib/semmle/code/powershell/CommandElement.qll b/powershell/ql/lib/semmle/code/powershell/CommandElement.qll deleted file mode 100644 index 6dbdffa72503..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/CommandElement.qll +++ /dev/null @@ -1,3 +0,0 @@ -import powershell - -class CmdElement extends @command_element, Ast { } diff --git a/powershell/ql/lib/semmle/code/powershell/CommandExpression.qll b/powershell/ql/lib/semmle/code/powershell/CommandExpression.qll deleted file mode 100644 index b8e4bdf29860..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/CommandExpression.qll +++ /dev/null @@ -1,15 +0,0 @@ -import powershell - -class CmdExpr extends @command_expression, CmdBase { - override SourceLocation getLocation() { command_expression_location(this, result) } - - Expr getExpr() { command_expression(this, result, _) } - - 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/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/CommentEntity.qll b/powershell/ql/lib/semmle/code/powershell/CommentEntity.qll deleted file mode 100644 index d234eb0f3c78..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/CommentEntity.qll +++ /dev/null @@ -1,17 +0,0 @@ -import powershell - -class Comment extends @comment_entity { - Location getLocation() { comment_entity_location(this, result) } - - StringLiteral getCommentContents() { comment_entity(this, result) } - - string toString() { result = this.getCommentContents().toString() } -} - -class SingleLineComment extends Comment { - SingleLineComment() { this.getCommentContents().getNumContinuations() = 1 } -} - -class MultiLineComment extends Comment { - MultiLineComment() { this.getCommentContents().getNumContinuations() > 1 } -} diff --git a/powershell/ql/lib/semmle/code/powershell/Configuration.qll b/powershell/ql/lib/semmle/code/powershell/Configuration.qll deleted file mode 100644 index acc265924a20..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/Configuration.qll +++ /dev/null @@ -1,15 +0,0 @@ -import powershell - -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, _, _) } - - predicate isMeta() { configuration_definition(this, _, 1, _) } - - predicate isResource() { configuration_definition(this, _, 0, _) } -} diff --git a/powershell/ql/lib/semmle/code/powershell/ConstantExpression.qll b/powershell/ql/lib/semmle/code/powershell/ConstantExpression.qll deleted file mode 100644 index 9c9e8b7f2002..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/ConstantExpression.qll +++ /dev/null @@ -1,127 +0,0 @@ -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 newtype TConstantValue = - TConstInteger(int value) { - exists(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) - } or - TConstString(string value) { exists(StringLiteral sl | sl.getValue() = value) } or - TConstBoolean(boolean value) { - exists(VarAccess va | - value = true and - va.getUserPath() = "true" - or - value = false and - va.getUserPath() = "false" - ) - } or - TNull() - -/** A constant value. */ -class ConstantValue extends TConstantValue { - /** Gets a string representation of this value. */ - final string toString() { result = this.getValue() } - - /** Gets the value of this consant. */ - string getValue() { none() } - - /** Gets the integer value of this constant, if any. */ - int asInt() { none() } - - /** Gets the floating point value of this constant, if any. */ - float asDouble() { none() } - - /** Gets the string value of this constant, if any. */ - string asString() { none() } - - /** Gets the boolean value of this constant, if any. */ - boolean asBoolean() { none() } - - /** Holds if this constant represents the null value. */ - predicate isNull() { none() } - - /** Gets a (unique) serialized version of this value. */ - string serialize() { none() } - - /** Gets an exprssion that has this value. */ - Expr getAnExpr() { none() } -} - -/** A constant integer value */ -class ConstInteger extends ConstantValue, TConstInteger { - final override int asInt() { this = TConstInteger(result) } - - final override string getValue() { result = this.asInt().toString() } - - final override string serialize() { result = this.getValue() } - - final override ConstExpr getAnExpr() { result.getValue().getValue() = this.getValue() } -} - -/** A constant floating point value. */ -class ConstDouble extends ConstantValue, TConstDouble { - final override float asDouble() { this = TConstDouble(result) } - - final override string getValue() { result = this.asDouble().toString() } - - final override string serialize() { - exists(string res | res = this.asDouble().toString() | - if exists(res.indexOf(".")) then result = res else result = res + ".0" - ) - } - - final override ConstExpr getAnExpr() { result.getValue().getValue() = this.getValue() } -} - -/** A constant string value. */ -class ConstString extends ConstantValue, TConstString { - final override string asString() { this = TConstString(result) } - - final override string getValue() { result = this.asString() } - - final override string serialize() { - result = "\"" + this.asString().replaceAll("\"", "\\\"") + "\"" - } - - final override BaseConstExpr getAnExpr() { result.getValue().getValue() = this.getValue() } -} - -/** A constant boolean value. */ -class ConstBoolean extends ConstantValue, TConstBoolean { - final override boolean asBoolean() { this = TConstBoolean(result) } - - final override string getValue() { result = this.asBoolean().toString() } - - 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" - } -} - -/** The constant null value. */ -class NullConst extends ConstantValue, TNull { - final override predicate isNull() { any() } - - final override string getValue() { result = "null" } - - final override string serialize() { result = this.getValue() } - - final override VarAccess getAnExpr() { result.getUserPath() = "null" } -} diff --git a/powershell/ql/lib/semmle/code/powershell/ContinueStmt.qll b/powershell/ql/lib/semmle/code/powershell/ContinueStmt.qll deleted file mode 100644 index 98fe1ba3fcbb..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/ContinueStmt.qll +++ /dev/null @@ -1,7 +0,0 @@ -import powershell - -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/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/DataStmt.qll b/powershell/ql/lib/semmle/code/powershell/DataStmt.qll deleted file mode 100644 index 205cdfbd862f..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/DataStmt.qll +++ /dev/null @@ -1,15 +0,0 @@ -import powershell - -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) } - - Expr getACmdAllowed() { result = this.getCmdAllowed(_) } - - StmtBlock getBody() { data_statement(this, result) } -} diff --git a/powershell/ql/lib/semmle/code/powershell/DoUntilStmt.qll b/powershell/ql/lib/semmle/code/powershell/DoUntilStmt.qll deleted file mode 100644 index a226931ec2ba..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/DoUntilStmt.qll +++ /dev/null @@ -1,11 +0,0 @@ -import powershell - -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) } -} diff --git a/powershell/ql/lib/semmle/code/powershell/DoWhileStmt.qll b/powershell/ql/lib/semmle/code/powershell/DoWhileStmt.qll deleted file mode 100644 index 8d29567d01de..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/DoWhileStmt.qll +++ /dev/null @@ -1,11 +0,0 @@ -import powershell - -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) } -} 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/ErrorExpr.qll b/powershell/ql/lib/semmle/code/powershell/ErrorExpr.qll deleted file mode 100644 index 2816f4390b36..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/ErrorExpr.qll +++ /dev/null @@ -1,7 +0,0 @@ -import powershell - -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/ErrorStmt.qll deleted file mode 100644 index 13be222c9c11..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/ErrorStmt.qll +++ /dev/null @@ -1,7 +0,0 @@ -import powershell - -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/ExitStmt.qll deleted file mode 100644 index 421bc453011f..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/ExitStmt.qll +++ /dev/null @@ -1,12 +0,0 @@ -import powershell - -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()) } -} diff --git a/powershell/ql/lib/semmle/code/powershell/ExpandableStringExpression.qll b/powershell/ql/lib/semmle/code/powershell/ExpandableStringExpression.qll deleted file mode 100644 index fa3a8a77ba25..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/ExpandableStringExpression.qll +++ /dev/null @@ -1,15 +0,0 @@ -import powershell - -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()) } - - Expr getExpr(int i) { expandable_string_expression_nested_expression(this, i, result) } - - Expr getAnExpr() { result = this.getExpr(_) } -} 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/File.qll b/powershell/ql/lib/semmle/code/powershell/File.qll deleted file mode 100644 index 5fbadd59626d..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/File.qll +++ /dev/null @@ -1,224 +0,0 @@ -/** - * Provides classes representing filesystem files and folders. - * Based on csharp/ql/lib/semmle/code/csharp/File.qll - */ - -/** A file or folder. */ -class Container extends @container { - /** - * Gets the absolute, canonical path of this container, using forward slashes - * as path separator. - * - * The path starts with a _root prefix_ followed by zero or more _path - * segments_ separated by forward slashes. - * - * The root prefix is of one of the following forms: - * - * 1. A single forward slash `/` (Unix-style) - * 2. An upper-case drive letter followed by a colon and a forward slash, - * such as `C:/` (Windows-style) - * 3. Two forward slashes, a computer name, and then another forward slash, - * such as `//FileServer/` (UNC-style) - * - * Path segments are never empty (that is, absolute paths never contain two - * contiguous slashes, except as part of a UNC-style root prefix). Also, path - * segments never contain forward slashes, and no path segment is of the - * form `.` (one dot) or `..` (two dots). - * - * Note that an absolute path never ends with a forward slash, except if it is - * a bare root prefix, that is, the path has no path segments. A container - * whose absolute path has no segments is always a `Folder`, not a `File`. - */ - string getAbsolutePath() { none() } - - /** - * Gets a URL representing the location of this container. - * - * For more information see [Providing URLs](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/#providing-urls). - */ - string getURL() { none() } - - /** - * Gets the relative path of this file or folder from the root folder of the - * analyzed source location. The relative path of the root folder itself is - * the empty string. - * - * This has no result if the container is outside the source root, that is, - * if the root folder is not a reflexive, transitive parent of this container. - */ - string getRelativePath() { - exists(string absPath, string pref | - absPath = this.getAbsolutePath() and sourceLocationPrefix(pref) - | - absPath = pref and result = "" - or - absPath = pref.regexpReplaceAll("/$", "") + "/" + result and - not result.matches("/%") - ) - } - - /** - * Gets the base name of this container including extension, that is, the last - * segment of its absolute path, or the empty string if it has no segments. - * - * Here are some examples of absolute paths and the corresponding base names - * (surrounded with quotes to avoid ambiguity): - * - * - * - * - * - * - * - * - * - *
Absolute pathBase name
"/tmp/tst.sql""tst.sql"
"C:/Program Files (x86)""Program Files (x86)"
"/"""
"C:/"""
"D:/"""
"//FileServer/"""
- */ - string getBaseName() { - result = this.getAbsolutePath().regexpCapture(".*/(([^/]*?)(?:\\.([^.]*))?)", 1) - } - - /** - * Gets the extension of this container, that is, the suffix of its base name - * after the last dot character, if any. - * - * In particular, - * - * - if the name does not include a dot, there is no extension, so this - * predicate has no result; - * - if the name ends in a dot, the extension is the empty string; - * - if the name contains multiple dots, the extension follows the last dot. - * - * Here are some examples of absolute paths and the corresponding extensions - * (surrounded with quotes to avoid ambiguity): - * - * - * - * - * - * - * - * - *
Absolute pathExtension
"/tmp/tst.cs""cs"
"/tmp/.classpath""classpath"
"/bin/bash"not defined
"/tmp/tst2."""
"/tmp/x.tar.gz""gz"
- */ - string getExtension() { - result = this.getAbsolutePath().regexpCapture(".*/([^/]*?)(\\.([^.]*))?", 3) - } - - /** - * Gets the stem of this container, that is, the prefix of its base name up to - * (but not including) the last dot character if there is one, or the entire - * base name if there is not. - * - * Here are some examples of absolute paths and the corresponding stems - * (surrounded with quotes to avoid ambiguity): - * - * - * - * - * - * - * - * - *
Absolute pathStem
"/tmp/tst.cs""tst"
"/tmp/.classpath"""
"/bin/bash""bash"
"/tmp/tst2.""tst2"
"/tmp/x.tar.gz""x.tar"
- */ - string getStem() { - result = this.getAbsolutePath().regexpCapture(".*/([^/]*?)(?:\\.([^.]*))?", 1) - } - - /** Gets the parent container of this file or folder, if any. */ - Container getParentContainer() { containerparent(result, this) } - - /** Gets a file or sub-folder in this container. */ - Container getAChildContainer() { this = result.getParentContainer() } - - /** Gets a file in this container. */ - File getAFile() { result = this.getAChildContainer() } - - /** Gets the file in this container that has the given `baseName`, if any. */ - File getFile(string baseName) { - result = this.getAFile() and - result.getBaseName() = baseName - } - - /** Gets a sub-folder in this container. */ - Folder getAFolder() { result = this.getAChildContainer() } - - /** Gets the sub-folder in this container that has the given `baseName`, if any. */ - Folder getFolder(string baseName) { - result = this.getAFolder() and - result.getBaseName() = baseName - } - - /** Gets the file or sub-folder in this container that has the given `name`, if any. */ - Container getChildContainer(string name) { - result = this.getAChildContainer() and - result.getBaseName() = name - } - - /** Gets the file in this container that has the given `stem` and `extension`, if any. */ - File getFile(string stem, string extension) { - result = this.getAChildContainer() and - result.getStem() = stem and - result.getExtension() = extension - } - - /** Gets a sub-folder contained in this container. */ - Folder getASubFolder() { result = this.getAChildContainer() } - - /** - * Gets a textual representation of the path of this container. - * - * This is the absolute path of the container. - */ - string toString() { result = this.getAbsolutePath() } -} - -/** A folder. */ -class Folder extends Container, @folder { - override string getAbsolutePath() { folders(this, result) } - - override string getURL() { result = "folder://" + this.getAbsolutePath() } -} - -/** A file. */ -class File extends Container, @file { - override string getAbsolutePath() { files(this, result) } - - /** Gets the number of lines in this file. */ - int getNumberOfLines() { numlines(this, result, _, _) } - - /** Gets the number of lines containing code in this file. */ - int getNumberOfLinesOfCode() { numlines(this, _, result, _) } - - /** Gets the number of lines containing comments in this file. */ - int getNumberOfLinesOfComments() { numlines(this, _, _, result) } - - override string getURL() { result = "file://" + this.getAbsolutePath() + ":0:0:0:0" } - - /** Holds if this file is a QL test stub file. */ - pragma[noinline] - private predicate isStub() { - // this.extractedQlTest() and - this.getAbsolutePath().matches("%resources/stubs/%") - } - - /** Holds if this file contains source code. */ - predicate fromSource() { - this.getExtension() = "cs" and - not this.isStub() - } - - /** Holds if this file is a library. */ - predicate fromLibrary() { - not this.getBaseName() = "" and - not this.fromSource() - } -} - -/** - * A source file. - */ -class SourceFile extends File { - SourceFile() { this.fromSource() } -} diff --git a/powershell/ql/lib/semmle/code/powershell/FileRedirection.qll b/powershell/ql/lib/semmle/code/powershell/FileRedirection.qll deleted file mode 100644 index 68dca062551f..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/FileRedirection.qll +++ /dev/null @@ -1,7 +0,0 @@ -import powershell - -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/ForEachStmt.qll deleted file mode 100644 index 4cbcc87038f7..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/ForEachStmt.qll +++ /dev/null @@ -1,23 +0,0 @@ -import powershell - -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) } -} diff --git a/powershell/ql/lib/semmle/code/powershell/ForStmt.qll b/powershell/ql/lib/semmle/code/powershell/ForStmt.qll deleted file mode 100644 index 104d3e3e2272..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/ForStmt.qll +++ /dev/null @@ -1,15 +0,0 @@ -import powershell - -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) } - - PipelineBase getIterator() { for_statement_iterator(this, result) } - - final override StmtBlock getBody() { for_statement(this, result) } -} 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/GotoStmt.qll b/powershell/ql/lib/semmle/code/powershell/GotoStmt.qll deleted file mode 100644 index 64cc20bf8002..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/GotoStmt.qll +++ /dev/null @@ -1,8 +0,0 @@ -import powershell - -/** A `break` or `continue` statement. */ -class GotoStmt extends @labelled_statement, Stmt { - - /** ..., if any. */ - Expr getLabel() { statement_label(this, result) } -} 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/IfStmt.qll b/powershell/ql/lib/semmle/code/powershell/IfStmt.qll deleted file mode 100644 index 21ce4d68fc8b..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/IfStmt.qll +++ /dev/null @@ -1,24 +0,0 @@ -import powershell - -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(_) } - - StmtBlock getThen(int i) { if_statement_clause(this, i, _, result) } - - int getNumberOfConditions() { result = count(this.getACondition()) } - - StmtBlock getAThen() { result = this.getThen(_) } - - /** ..., if any. */ - StmtBlock getElse() { if_statement_else(this, result) } - - predicate hasElse() { exists(this.getElse()) } -} 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/LabeledStmt.qll b/powershell/ql/lib/semmle/code/powershell/LabeledStmt.qll deleted file mode 100644 index fff4e1712ccb..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/LabeledStmt.qll +++ /dev/null @@ -1,5 +0,0 @@ -import powershell - -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/Location.qll deleted file mode 100644 index c08dcb83af11..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/Location.qll +++ /dev/null @@ -1,52 +0,0 @@ -/** - * Provides the `Location` class to give a location for each - * program element. - * - * A `SourceLocation` provides a section of text in a source file - * containing the program element. - * - * Based on csharp/ql/lib/semmle/code/csharp/Location.qll - */ - -import File - -/** - * A location of a program element. - */ -class Location extends @location { - /** Gets the file of the location. */ - File getFile() { none() } - - /** - * Holds if this element is at the specified location. - * The location spans column `startcolumn` of line `startline` to - * column `endcolumn` of line `endline` in file `filepath`. - * For more information, see - * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/). - */ - predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - none() - } - - /** Gets a textual representation of this location. */ - string toString() { none() } - - /** Gets the 1-based line number (inclusive) where this location starts. */ - int getStartLine() { this.hasLocationInfo(_, result, _, _, _) } - - /** Gets the 1-based line number (inclusive) where this location ends. */ - int getEndLine() { this.hasLocationInfo(_, _, _, result, _) } - - /** Gets the 1-based column number (inclusive) where this location starts. */ - int getStartColumn() { this.hasLocationInfo(_, _, result, _, _) } - - /** Gets the 1-based column number (inclusive) where this location ends. */ - int getEndColumn() { this.hasLocationInfo(_, _, _, _, result) } -} - -/** An empty location. */ -class EmptyLocation extends Location { - EmptyLocation() { this.hasLocationInfo("", 0, 0, 0, 0) } -} diff --git a/powershell/ql/lib/semmle/code/powershell/LoopStmt.qll b/powershell/ql/lib/semmle/code/powershell/LoopStmt.qll deleted file mode 100644 index edd9417a4951..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/LoopStmt.qll +++ /dev/null @@ -1,5 +0,0 @@ -import powershell - -class LoopStmt extends @loop_statement, LabeledStmt { - StmtBlock getBody() { none() } -} 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/MemberExpr.qll b/powershell/ql/lib/semmle/code/powershell/MemberExpr.qll deleted file mode 100644 index 1d6d143c053e..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/MemberExpr.qll +++ /dev/null @@ -1,28 +0,0 @@ -import powershell - -class MemberExpr extends @member_expression, MemberExprBase { - final override Location getLocation() { member_expression_location(this, result) } - - Expr getQualifier() { member_expression(this, result, _, _, _) } - - CmdElement getMember() { member_expression(this, _, result, _, _) } - - /** Gets the name of the member being looked up, if any. */ - string getMemberName() { result = this.getMember().(StringConstExpr).getValue().getValue() } - - predicate isNullConditional() { member_expression(this, _, _, true, _) } - - override predicate isStatic() { member_expression(this, _, _, _, true) } - - final override string toString() { result = this.getMember().toString() } -} - -/** A `MemberExpr` that is being written to. */ -class MemberExprWriteAccess extends MemberExpr { - MemberExprWriteAccess() { this = any(AssignStmt assign).getLeftHandSide() } -} - -/** 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/MemberExpressionBase.qll b/powershell/ql/lib/semmle/code/powershell/MemberExpressionBase.qll deleted file mode 100644 index 81db24f00196..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/MemberExpressionBase.qll +++ /dev/null @@ -1,5 +0,0 @@ -import powershell - -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/MergingRedirection.qll deleted file mode 100644 index b227fc3c585f..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/MergingRedirection.qll +++ /dev/null @@ -1,7 +0,0 @@ -import powershell - -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/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/ModuleSpecification.qll b/powershell/ql/lib/semmle/code/powershell/ModuleSpecification.qll deleted file mode 100644 index 5e2a3d3d3918..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/ModuleSpecification.qll +++ /dev/null @@ -1,17 +0,0 @@ -import powershell - -class ModuleSpecification extends @module_specification { - string toString() { result = this.getName() } - - string getName() { module_specification(this, result, _, _, _, _) } - - string getGuid() { module_specification(this, _, result, _, _, _) } - - string getMaxVersion() { module_specification(this, _, _, result, _, _) } - - string getRequiredVersion() { module_specification(this, _, _, _, result, _) } - - string getVersion() { module_specification(this, _, _, _, _, result) } - - Location getLocation() { result instanceof EmptyLocation } -} diff --git a/powershell/ql/lib/semmle/code/powershell/NamedAttributeArgument.qll b/powershell/ql/lib/semmle/code/powershell/NamedAttributeArgument.qll deleted file mode 100644 index 1d05343b87ea..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/NamedAttributeArgument.qll +++ /dev/null @@ -1,21 +0,0 @@ -import powershell - -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, _) } - - predicate hasName(string s) { this.getName() = s } - - Expr getValue() { named_attribute_argument(this, _, result) } -} - -class ValueFromPipelineAttribute extends NamedAttributeArgument { - ValueFromPipelineAttribute() { this.getName() = "ValueFromPipeline" } -} - -class ValueFromPipelineByPropertyName extends NamedAttributeArgument { - ValueFromPipelineByPropertyName() { this.getName() = "ValueFromPipelineByPropertyName" } -} diff --git a/powershell/ql/lib/semmle/code/powershell/NamedBlock.qll b/powershell/ql/lib/semmle/code/powershell/NamedBlock.qll deleted file mode 100644 index 5bf4de25cb38..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/NamedBlock.qll +++ /dev/null @@ -1,19 +0,0 @@ -import powershell - -class NamedBlock extends @named_block, Ast { - override string toString() { result = "{...}" } - - override SourceLocation getLocation() { named_block_location(this, result) } - - int getNumStatements() { named_block(this, result, _) } - - int getNumTraps() { named_block(this, _, result) } - - Stmt getStmt(int i) { named_block_statement(this, i, result) } - - Stmt getAStmt() { result = this.getStmt(_) } - - TrapStmt getTrap(int i) { named_block_trap(this, i, result) } - - TrapStmt getATrap() { result = this.getTrap(_) } -} 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/ParenExpression.qll b/powershell/ql/lib/semmle/code/powershell/ParenExpression.qll deleted file mode 100644 index 6a71d2681307..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/ParenExpression.qll +++ /dev/null @@ -1,9 +0,0 @@ -import powershell - -class ParenExpr extends @paren_expression, Expr { - PipelineBase getBase() { paren_expression(this, result) } - - override SourceLocation getLocation() { paren_expression_location(this, result) } - - override string toString() { result = "(...)" } -} diff --git a/powershell/ql/lib/semmle/code/powershell/Pipeline.qll b/powershell/ql/lib/semmle/code/powershell/Pipeline.qll deleted file mode 100644 index f630a117e547..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/Pipeline.qll +++ /dev/null @@ -1,17 +0,0 @@ -import powershell - -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()) } - - CmdBase getComponent(int i) { pipeline_component(this, i, result) } - - CmdBase getAComponent() { result = this.getComponent(_) } -} diff --git a/powershell/ql/lib/semmle/code/powershell/PipelineBase.qll b/powershell/ql/lib/semmle/code/powershell/PipelineBase.qll deleted file mode 100644 index bb2d8cab85e4..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/PipelineBase.qll +++ /dev/null @@ -1,3 +0,0 @@ -import powershell - -class PipelineBase extends @pipeline_base, Stmt { } diff --git a/powershell/ql/lib/semmle/code/powershell/PipelineChain.qll b/powershell/ql/lib/semmle/code/powershell/PipelineChain.qll deleted file mode 100644 index ee5dd56cec0a..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/PipelineChain.qll +++ /dev/null @@ -1,11 +0,0 @@ -import powershell - -class PipelineChain extends @pipeline_chain, Chainable { - final override SourceLocation getLocation() { pipeline_chain_location(this, result) } - - predicate isBackground() { pipeline_chain(this, true, _, _, _) } - - Chainable getLeft() { pipeline_chain(this, _, _, result, _) } - - Pipeline getRight() { pipeline_chain(this, _, _, _, result) } -} diff --git a/powershell/ql/lib/semmle/code/powershell/PropertyMember.qll b/powershell/ql/lib/semmle/code/powershell/PropertyMember.qll deleted file mode 100644 index e9144dc78e45..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/PropertyMember.qll +++ /dev/null @@ -1,17 +0,0 @@ -import powershell - -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, _, _, _, _) } - - override predicate isPublic() { property_member(this, _, _, true, _, _, _) } - - override predicate isStatic() { property_member(this, _, _, _, true, _, _) } -} 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/ReturnStmt.qll b/powershell/ql/lib/semmle/code/powershell/ReturnStmt.qll deleted file mode 100644 index aa8ad6732514..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/ReturnStmt.qll +++ /dev/null @@ -1,13 +0,0 @@ -import powershell - -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()) } -} diff --git a/powershell/ql/lib/semmle/code/powershell/ScriptBlock.qll b/powershell/ql/lib/semmle/code/powershell/ScriptBlock.qll deleted file mode 100644 index 4e6c77352234..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/ScriptBlock.qll +++ /dev/null @@ -1,111 +0,0 @@ -import powershell -private import semmle.code.powershell.controlflow.internal.Scope - -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, _, _, _, _) } - - int getNumRequiredModules() { script_block(this, _, result, _, _, _) } - - int getNumRequiredAssemblies() { script_block(this, _, _, result, _, _) } - - int getNumRequiredPsEditions() { script_block(this, _, _, _, result, _) } - - int getNumRequiredPsSnapIns() { script_block(this, _, _, _, _, result) } - - Stmt getUsing(int i) { script_block_using(this, i, result) } - - Stmt getAUsing() { result = this.getUsing(_) } - - ParamBlock getParamBlock() { script_block_param_block(this, result) } - - NamedBlock getBeginBlock() { script_block_begin_block(this, result) } - - NamedBlock getCleanBlock() { script_block_clean_block(this, result) } - - NamedBlock getDynamicParamBlock() { script_block_dynamic_param_block(this, result) } - - NamedBlock getEndBlock() { script_block_end_block(this, result) } - - NamedBlock getProcessBlock() { script_block_process_block(this, result) } - - string getRequiredApplicationId() { script_block_required_application_id(this, result) } - - boolean getRequiresElevation() { script_block_requires_elevation(this, result) } - - string getRequiredPsVersion() { script_block_required_ps_version(this, result) } - - ModuleSpecification getModuleSpecification(int i) { - script_block_required_module(this, i, result) - } - - 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) - ) - 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() - } -} - -class TopLevelScriptBlock extends ScriptBlock { - TopLevelScriptBlock() { this.isTopLevel() } -} diff --git a/powershell/ql/lib/semmle/code/powershell/ScriptBlockExpr.qll b/powershell/ql/lib/semmle/code/powershell/ScriptBlockExpr.qll deleted file mode 100644 index 78dd5abbc2e6..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/ScriptBlockExpr.qll +++ /dev/null @@ -1,9 +0,0 @@ -import powershell - -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) } -} diff --git a/powershell/ql/lib/semmle/code/powershell/SourceLocation.qll b/powershell/ql/lib/semmle/code/powershell/SourceLocation.qll deleted file mode 100644 index 8c70f06f7bc1..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/SourceLocation.qll +++ /dev/null @@ -1,25 +0,0 @@ -import powershell - -/** - * A location in source code, comprising of a source file and a segment of text - * within the file. - */ -class SourceLocation extends Location, @location_default { - override File getFile() { locations_default(this, result, _, _, _, _) } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - exists(File f | locations_default(this, f, startline, startcolumn, endline, endcolumn) | - filepath = f.getAbsolutePath() - ) - } - - override string toString() { - exists(string filepath, int startline, int startcolumn, int endline, int endcolumn | - this.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - | - result = filepath + ":" + startline + ":" + startcolumn + ":" + endline + ":" + endcolumn - ) - } -} 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/Statement.qll b/powershell/ql/lib/semmle/code/powershell/Statement.qll deleted file mode 100644 index 19bed527915a..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/Statement.qll +++ /dev/null @@ -1,3 +0,0 @@ -import powershell - -class Stmt extends @statement, Ast { } diff --git a/powershell/ql/lib/semmle/code/powershell/StatementBlock.qll b/powershell/ql/lib/semmle/code/powershell/StatementBlock.qll deleted file mode 100644 index c0dd9939079c..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/StatementBlock.qll +++ /dev/null @@ -1,32 +0,0 @@ -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 } -} - -class StmtBlock extends @statement_block, Ast { - override SourceLocation getLocation() { statement_block_location(this, result) } - - int getNumberOfStmts() { statement_block(this, result, _) } - - int getNumTraps() { statement_block(this, _, result) } - - Stmt getStmt(int index) { statement_block_statement(this, index, result) } - - Stmt getAStmt() { result = this.getStmt(_) } - - TrapStmt getTrapStmt(int index) { statement_block_trap(this, index, result) } - - TrapStmt getATrapStmt() { result = this.getTrapStmt(_) } - - override string toString() { result = "{...}" } - - /** Gets an element that may escape this `StmtBlock`. */ - Ast getAnElement() { - result = this.(AstEscape::Element).getAnEscapingElement() - } -} diff --git a/powershell/ql/lib/semmle/code/powershell/StringConstantExpression.qll b/powershell/ql/lib/semmle/code/powershell/StringConstantExpression.qll deleted file mode 100644 index d640817f99b3..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/StringConstantExpression.qll +++ /dev/null @@ -1,10 +0,0 @@ -import powershell - -/** A string constant. */ -class StringConstExpr extends @string_constant_expression, BaseConstExpr { - override StringLiteral getValue() { string_constant_expression(this, result) } - - override string getType() { result = "String" } - - override SourceLocation getLocation() { string_constant_expression_location(this, result) } -} diff --git a/powershell/ql/lib/semmle/code/powershell/StringLiteral.qll b/powershell/ql/lib/semmle/code/powershell/StringLiteral.qll deleted file mode 100644 index a7f85ece8e42..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/StringLiteral.qll +++ /dev/null @@ -1,16 +0,0 @@ -import powershell - -class StringLiteral extends @string_literal { - int getNumContinuations() { result = strictcount(int i | exists(this.getContinuation(i))) } - - string getContinuation(int index) { string_literal_line(this, index, result) } - - /** Get the full string literal with all its parts concatenated */ - string toString() { result = this.getValue() } - - string getValue() { - result = concat(int i | i = [0 .. this.getNumContinuations()] | this.getContinuation(i), "\n") - } - - SourceLocation getLocation() { string_literal_location(this, result) } -} diff --git a/powershell/ql/lib/semmle/code/powershell/SubExpression.qll b/powershell/ql/lib/semmle/code/powershell/SubExpression.qll deleted file mode 100644 index df39df46a48a..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/SubExpression.qll +++ /dev/null @@ -1,10 +0,0 @@ -import powershell - -// TODO: Should we remove this from the dbscheme? -class ExpandableSubExpr extends @sub_expression, Expr { - final override Location getLocation() { sub_expression_location(this, result) } - - StmtBlock getExpr() { sub_expression(this, result) } - - final override string toString() { result = "$(...)" } -} diff --git a/powershell/ql/lib/semmle/code/powershell/SwitchStmt.qll b/powershell/ql/lib/semmle/code/powershell/SwitchStmt.qll deleted file mode 100644 index 8dca8f0b91c2..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/SwitchStmt.qll +++ /dev/null @@ -1,25 +0,0 @@ -import powershell - -class SwitchStmt extends LabeledStmt, @switch_statement { - final override Location getLocation() { switch_statement_location(this, result) } - - PipelineBase getCondition() { switch_statement(this, result, _) } - - StmtBlock getDefault() { switch_statement_default(this, result) } - - StmtBlock getCase(int i, Expr e) { switch_statement_clauses(this, i, e, result) } - - StmtBlock getCase(int i) { result = this.getCase(i, _) } - - StmtBlock getACase() { result = this.getCase(_) } - - StmtBlock getCaseForExpr(Expr e) { result = this.getCase(_, e) } - - Expr getPattern(int i) { exists(this.getCase(i, result)) } - - Expr getAPattern() { result = this.getPattern(_) } - - int getNumberOfCases() { result = count(this.getACase()) } - - final override string toString() { result = "switch(...) {...}" } -} diff --git a/powershell/ql/lib/semmle/code/powershell/TernaryExpression.qll b/powershell/ql/lib/semmle/code/powershell/TernaryExpression.qll deleted file mode 100644 index 19af31478fcf..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/TernaryExpression.qll +++ /dev/null @@ -1,23 +0,0 @@ -import powershell - -class ConditionalExpr extends @ternary_expression, Expr { - override string toString() { result = "...?...:..." } - - override SourceLocation getLocation() { ternary_expression_location(this, result) } - - Expr getCondition() { ternary_expression(this, result, _, _) } - - Expr getIfFalse() { ternary_expression(this, _, result, _) } - - Expr getIfTrue() { ternary_expression(this, _, _, result) } - - 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/ThrowStmt.qll b/powershell/ql/lib/semmle/code/powershell/ThrowStmt.qll deleted file mode 100644 index af8ccaab5f5b..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/ThrowStmt.qll +++ /dev/null @@ -1,13 +0,0 @@ -import powershell - -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()) } -} diff --git a/powershell/ql/lib/semmle/code/powershell/TokenKind.qll b/powershell/ql/lib/semmle/code/powershell/TokenKind.qll deleted file mode 100644 index a179d3612917..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/TokenKind.qll +++ /dev/null @@ -1,1345 +0,0 @@ -class TokenKind extends @token_kind { - string toString() { none() } - - string getDescription() { none() } - - int getValue() { none() } -} - -class Ampersand extends @ampersand, TokenKind { - override int getValue() { result = 28 } - - override string getDescription() { result = "The invocation operator '&'." } - - override string toString() { result = "Ampersand" } -} - -class And extends @and, TokenKind { - override int getValue() { result = 53 } - - override string getDescription() { result = "The logical and operator '-and'." } - - override string toString() { result = "And" } -} - -class AndAnd extends @andAnd, TokenKind { - override int getValue() { result = 26 } - - override string getDescription() { result = "The (unimplemented) operator '&&'." } - - override string toString() { result = "AndAnd" } -} - -class As extends @as, TokenKind { - override int getValue() { result = 94 } - - override string getDescription() { result = "The type conversion operator '-as'." } - - override string toString() { result = "As" } -} - -class Assembly extends @assembly, TokenKind { - override int getValue() { result = 165 } - - override string getDescription() { result = "The 'assembly' keyword" } - - override string toString() { result = "Assembly" } -} - -class AtCurly extends @atCurly, TokenKind { - override int getValue() { result = 23 } - - override string getDescription() { result = "The opening token of a hash expression '@{'." } - - override string toString() { result = "AtCurly" } -} - -class AtParen extends @atParen, TokenKind { - override int getValue() { result = 22 } - - override string getDescription() { result = "The opening token of an array expression '@('." } - - override string toString() { result = "AtParen" } -} - -class Band extends @band, TokenKind { - override int getValue() { result = 56 } - - override string getDescription() { result = "The bitwise and operator '-band'." } - - override string toString() { result = "Band" } -} - -class Base extends @base, TokenKind { - override int getValue() { result = 168 } - - override string getDescription() { result = "The 'base' keyword" } - - override string toString() { result = "Base" } -} - -class Begin extends @begin, TokenKind { - override int getValue() { result = 119 } - - override string getDescription() { result = "The 'begin' keyword." } - - override string toString() { result = "Begin" } -} - -class Bnot extends @bnot, TokenKind { - override int getValue() { result = 52 } - - override string getDescription() { result = "The bitwise not operator '-bnot'." } - - override string toString() { result = "Bnot" } -} - -class Bor extends @bor, TokenKind { - override int getValue() { result = 57 } - - override string getDescription() { result = "The bitwise or operator '-bor'." } - - override string toString() { result = "Bor" } -} - -class Break extends @break, TokenKind { - override int getValue() { result = 120 } - - override string getDescription() { result = "The 'break' keyword." } - - override string toString() { result = "Break" } -} - -class Bxor extends @bxor, TokenKind { - override int getValue() { result = 58 } - - override string getDescription() { result = "The bitwise exclusive or operator '-xor'." } - - override string toString() { result = "Bxor" } -} - -class Catch extends @catch, TokenKind { - override int getValue() { result = 121 } - - override string getDescription() { result = "The 'catch' keyword." } - - override string toString() { result = "Catch" } -} - -class Ccontains extends @ccontains, TokenKind { - override int getValue() { result = 87 } - - override string getDescription() { result = "The case sensitive contains operator '-ccontains'." } - - override string toString() { result = "Ccontains" } -} - -class Ceq extends @ceq, TokenKind { - override int getValue() { result = 76 } - - override string getDescription() { result = "The case sensitive equal operator '-ceq'." } - - override string toString() { result = "Ceq" } -} - -class Cge extends @cge, TokenKind { - override int getValue() { result = 78 } - - override string getDescription() { - result = "The case sensitive greater than or equal operator '-cge'." - } - - override string toString() { result = "Cge" } -} - -class Cgt extends @cgt, TokenKind { - override int getValue() { result = 79 } - - override string getDescription() { result = "The case sensitive greater than operator '-cgt'." } - - override string toString() { result = "Cgt" } -} - -class Cin extends @cin, TokenKind { - override int getValue() { result = 89 } - - override string getDescription() { result = "The case sensitive in operator '-cin'." } - - override string toString() { result = "Cin" } -} - -class Class extends @class, TokenKind { - override int getValue() { result = 122 } - - override string getDescription() { result = "The 'class' keyword." } - - override string toString() { result = "Class" } -} - -class Cle extends @cle, TokenKind { - override int getValue() { result = 81 } - - override string getDescription() { - result = "The case sensitive less than or equal operator '-cle'." - } - - override string toString() { result = "Cle" } -} - -class Clean extends @clean, TokenKind { - override int getValue() { result = 170 } - - override string getDescription() { result = "The 'clean' keyword." } - - override string toString() { result = "Clean" } -} - -class Clike extends @clike, TokenKind { - override int getValue() { result = 82 } - - override string getDescription() { result = "The case sensitive like operator '-clike'." } - - override string toString() { result = "Clike" } -} - -class Clt extends @clt, TokenKind { - override int getValue() { result = 80 } - - override string getDescription() { result = "The case sensitive less than operator '-clt'." } - - override string toString() { result = "Clt" } -} - -class Cmatch extends @cmatch, TokenKind { - override int getValue() { result = 84 } - - override string getDescription() { result = "The case sensitive match operator '-cmatch'." } - - override string toString() { result = "Cmatch" } -} - -class Cne extends @cne, TokenKind { - override int getValue() { result = 77 } - - override string getDescription() { result = "The case sensitive not equal operator '-cne'." } - - override string toString() { result = "Cne" } -} - -class Cnotcontains extends @cnotcontains, TokenKind { - override int getValue() { result = 88 } - - override string getDescription() { - result = "The case sensitive not contains operator '-cnotcontains'." - } - - override string toString() { result = "Cnotcontains" } -} - -class Cnotin extends @cnotin, TokenKind { - override int getValue() { result = 90 } - - override string getDescription() { result = "The case sensitive not in operator '-notin'." } - - override string toString() { result = "Cnotin" } -} - -class Cnotlike extends @cnotlike, TokenKind { - override int getValue() { result = 83 } - - override string getDescription() { result = "The case sensitive notlike operator '-cnotlike'." } - - override string toString() { result = "Cnotlike" } -} - -class Cnotmatch extends @cnotmatch, TokenKind { - override int getValue() { result = 85 } - - override string getDescription() { - result = "The case sensitive not match operator '-cnotmatch'." - } - - override string toString() { result = "Cnotmatch" } -} - -class Colon extends @colon, TokenKind { - override int getValue() { result = 99 } - - override string getDescription() { - result = - "The PS class base class and implemented interfaces operator ':'. Also used in base class ctor calls." - } - - override string toString() { result = "Colon" } -} - -class ColonColon extends @colonColon, TokenKind { - override int getValue() { result = 34 } - - override string getDescription() { result = "The static member access operator '::'." } - - override string toString() { result = "ColonColon" } -} - -class Comma extends @comma, TokenKind { - override int getValue() { result = 30 } - - override string getDescription() { result = "The unary or binary array operator ','." } - - override string toString() { result = "Comma" } -} - -class CommandToken extends @command_token, TokenKind { - override int getValue() { result = 166 } - - override string getDescription() { result = "The 'command' keyword" } - - override string toString() { result = "Command" } -} - -class Comment extends @comment, TokenKind { - override int getValue() { result = 10 } - - override string getDescription() { result = "A single line comment, or a delimited comment." } - - override string toString() { result = "Comment" } -} - -class Configuration extends @configuration, TokenKind { - override int getValue() { result = 155 } - - override string getDescription() { result = "The 'configuration' keyword" } - - override string toString() { result = "Configuration" } -} - -class Continue extends @continue, TokenKind { - override int getValue() { result = 123 } - - override string getDescription() { result = "The 'continue' keyword." } - - override string toString() { result = "Continue" } -} - -class Creplace extends @creplace, TokenKind { - override int getValue() { result = 86 } - - override string getDescription() { result = "The case sensitive replace operator '-creplace'." } - - override string toString() { result = "Creplace" } -} - -class Csplit extends @csplit, TokenKind { - override int getValue() { result = 91 } - - override string getDescription() { result = "The case sensitive split operator '-csplit'." } - - override string toString() { result = "Csplit" } -} - -class Data extends @data, TokenKind { - override int getValue() { result = 124 } - - override string getDescription() { result = "The 'data' keyword." } - - override string toString() { result = "Data" } -} - -class Default extends @default, TokenKind { - override int getValue() { result = 169 } - - override string getDescription() { result = "The 'default' keyword" } - - override string toString() { result = "Default" } -} - -class Define extends @define, TokenKind { - override int getValue() { result = 125 } - - override string getDescription() { result = "The (unimplemented) 'define' keyword." } - - override string toString() { result = "Define" } -} - -class Divide extends @divide, TokenKind { - override int getValue() { result = 38 } - - override string getDescription() { result = "The division operator '/'." } - - override string toString() { result = "Divide" } -} - -class DivideEquals extends @divideEquals, TokenKind { - override int getValue() { result = 46 } - - override string getDescription() { result = "The division assignment operator '/='." } - - override string toString() { result = "DivideEquals" } -} - -class Do extends @do, TokenKind { - override int getValue() { result = 126 } - - override string getDescription() { result = "The 'do' keyword." } - - override string toString() { result = "Do" } -} - -class DollarParen extends @dollarParen, TokenKind { - override int getValue() { result = 24 } - - override string getDescription() { result = "The opening token of a sub-expression '$('." } - - override string toString() { result = "DollarParen" } -} - -class Dot extends @dot, TokenKind { - override int getValue() { result = 35 } - - override string getDescription() { - result = "The instance member access or dot source invocation operator '.'." - } - - override string toString() { result = "Dot" } -} - -class DotDot extends @dotDot, TokenKind { - override int getValue() { result = 33 } - - override string getDescription() { result = "The range operator '..'." } - - override string toString() { result = "DotDot" } -} - -class DynamicKeyword extends @dynamicKeyword, TokenKind { - override int getValue() { result = 156 } - - override string getDescription() { result = "The token kind for dynamic keywords" } - - override string toString() { result = "DynamicKeyword" } -} - -class Dynamicparam extends @dynamicparam, TokenKind { - override int getValue() { result = 127 } - - override string getDescription() { result = "The 'dynamicparam' keyword." } - - override string toString() { result = "Dynamicparam" } -} - -class Else extends @else, TokenKind { - override int getValue() { result = 128 } - - override string getDescription() { result = "The 'else' keyword." } - - override string toString() { result = "Else" } -} - -class ElseIf extends @elseIf, TokenKind { - override int getValue() { result = 129 } - - override string getDescription() { result = "The 'elseif' keyword." } - - override string toString() { result = "ElseIf" } -} - -class End extends @end, TokenKind { - override int getValue() { result = 130 } - - override string getDescription() { result = "The 'end' keyword." } - - override string toString() { result = "End" } -} - -class EndOfInput extends @endOfInput, TokenKind { - override int getValue() { result = 11 } - - override string getDescription() { result = "Marks the end of the input script or file." } - - override string toString() { result = "EndOfInput" } -} - -class Enum extends @enum, TokenKind { - override int getValue() { result = 161 } - - override string getDescription() { result = "The 'enum' keyword" } - - override string toString() { result = "Enum" } -} - -class Equals extends @equals, TokenKind { - override int getValue() { result = 42 } - - override string getDescription() { result = "The assignment operator '='." } - - override string toString() { result = "Equals" } -} - -class Exclaim extends @exclaim, TokenKind { - override int getValue() { result = 36 } - - override string getDescription() { result = "The logical not operator '!'." } - - override string toString() { result = "Exclaim" } -} - -class Exit extends @exit, TokenKind { - override int getValue() { result = 131 } - - override string getDescription() { result = "The 'exit' keyword." } - - override string toString() { result = "Exit" } -} - -class Filter extends @filter, TokenKind { - override int getValue() { result = 132 } - - override string getDescription() { result = "The 'filter' keyword." } - - override string toString() { result = "Filter" } -} - -class Finally extends @finally, TokenKind { - override int getValue() { result = 133 } - - override string getDescription() { result = "The 'finally' keyword." } - - override string toString() { result = "Finally" } -} - -class For extends @for, TokenKind { - override int getValue() { result = 134 } - - override string getDescription() { result = "The 'for' keyword." } - - override string toString() { result = "For" } -} - -class Foreach extends @foreach, TokenKind { - override int getValue() { result = 135 } - - override string getDescription() { result = "The 'foreach' keyword." } - - override string toString() { result = "Foreach" } -} - -class Format extends @format, TokenKind { - override int getValue() { result = 50 } - - override string getDescription() { result = "The string format operator '-f'." } - - override string toString() { result = "Format" } -} - -class From extends @from, TokenKind { - override int getValue() { result = 136 } - - override string getDescription() { result = "The (unimplemented) 'from' keyword." } - - override string toString() { result = "From" } -} - -class Function extends @function, TokenKind { - override int getValue() { result = 137 } - - override string getDescription() { result = "The 'function' keyword." } - - override string toString() { result = "Function" } -} - -class Generic extends @generic, TokenKind { - override int getValue() { result = 7 } - - override string getDescription() { - result = - "A token that is only valid as a command name, command argument, function name, or configuration name. It may contain characters not allowed in identifiers. Tokens with this kind are always instances of StringLiteralToken or StringExpandableToken if the token contains variable references or subexpressions." - } - - override string toString() { result = "Generic" } -} - -class HereStringExpandable extends @hereStringExpandable, TokenKind { - override int getValue() { result = 15 } - - override string getDescription() { - result = - "A double quoted here string literal. Tokens with this kind are always instances of StringExpandableToken. even if there are no nested tokens to expand." - } - - override string toString() { result = "HereStringExpandable" } -} - -class HereStringLiteral extends @hereStringLiteral, TokenKind { - override int getValue() { result = 14 } - - override string getDescription() { - result = - "A single quoted here string literal. Tokens with this kind are always instances of StringLiteralToken." - } - - override string toString() { result = "HereStringLiteral" } -} - -class Hidden extends @hidden, TokenKind { - override int getValue() { result = 167 } - - override string getDescription() { result = "The 'hidden' keyword" } - - override string toString() { result = "Hidden" } -} - -class Icontains extends @icontains, TokenKind { - override int getValue() { result = 71 } - - override string getDescription() { - result = "The case insensitive contains operator '-icontains' or '-contains'." - } - - override string toString() { result = "Icontains" } -} - -class Identifier extends @identifier, TokenKind { - override int getValue() { result = 6 } - - override string getDescription() { - result = - "A simple identifier, always begins with a letter or '', and is followed by letters, numbers, or ''." - } - - override string toString() { result = "Identifier" } -} - -class Ieq extends @ieq, TokenKind { - override int getValue() { result = 60 } - - override string getDescription() { - result = "The case insensitive equal operator '-ieq' or '-eq'." - } - - override string toString() { result = "Ieq" } -} - -class If extends @if, TokenKind { - override int getValue() { result = 138 } - - override string getDescription() { result = "The 'if' keyword." } - - override string toString() { result = "If" } -} - -class Ige extends @ige, TokenKind { - override int getValue() { result = 62 } - - override string getDescription() { - result = "The case insensitive greater than or equal operator '-ige' or '-ge'." - } - - override string toString() { result = "Ige" } -} - -class Igt extends @igt, TokenKind { - override int getValue() { result = 63 } - - override string getDescription() { - result = "The case insensitive greater than operator '-igt' or '-gt'." - } - - override string toString() { result = "Igt" } -} - -class Iin extends @iin, TokenKind { - override int getValue() { result = 73 } - - override string getDescription() { result = "The case insensitive in operator '-iin' or '-in'." } - - override string toString() { result = "Iin" } -} - -class Ile extends @ile, TokenKind { - override int getValue() { result = 65 } - - override string getDescription() { - result = "The case insensitive less than or equal operator '-ile' or '-le'." - } - - override string toString() { result = "Ile" } -} - -class Ilike extends @ilike, TokenKind { - override int getValue() { result = 66 } - - override string getDescription() { - result = "The case insensitive like operator '-ilike' or '-like'." - } - - override string toString() { result = "Ilike" } -} - -class Ilt extends @ilt, TokenKind { - override int getValue() { result = 64 } - - override string getDescription() { - result = "The case insensitive less than operator '-ilt' or '-lt'." - } - - override string toString() { result = "Ilt" } -} - -class Imatch extends @imatch, TokenKind { - override int getValue() { result = 68 } - - override string getDescription() { - result = "The case insensitive match operator '-imatch' or '-match'." - } - - override string toString() { result = "Imatch" } -} - -class In extends @in, TokenKind { - override int getValue() { result = 139 } - - override string getDescription() { result = "The 'in' keyword." } - - override string toString() { result = "In" } -} - -class Ine extends @ine, TokenKind { - override int getValue() { result = 61 } - - override string getDescription() { - result = "The case insensitive not equal operator '-ine' or '-ne'." - } - - override string toString() { result = "Ine" } -} - -class InlineScript extends @inlineScript, TokenKind { - override int getValue() { result = 154 } - - override string getDescription() { result = "The 'InlineScript' keyword" } - - override string toString() { result = "InlineScript" } -} - -class Inotcontains extends @inotcontains, TokenKind { - override int getValue() { result = 72 } - - override string getDescription() { - result = "The case insensitive notcontains operator '-inotcontains' or '-notcontains'." - } - - override string toString() { result = "Inotcontains" } -} - -class Inotin extends @inotin, TokenKind { - override int getValue() { result = 74 } - - override string getDescription() { - result = "The case insensitive notin operator '-inotin' or '-notin'" - } - - override string toString() { result = "Inotin" } -} - -class Inotlike extends @inotlike, TokenKind { - override int getValue() { result = 67 } - - override string getDescription() { - result = "The case insensitive not like operator '-inotlike' or '-notlike'." - } - - override string toString() { result = "Inotlike" } -} - -class Inotmatch extends @inotmatch, TokenKind { - override int getValue() { result = 69 } - - override string getDescription() { - result = "The case insensitive not match operator '-inotmatch' or '-notmatch'." - } - - override string toString() { result = "Inotmatch" } -} - -class Interface extends @interface, TokenKind { - override int getValue() { result = 160 } - - override string getDescription() { result = "The 'interface' keyword" } - - override string toString() { result = "Interface" } -} - -class Ireplace extends @ireplace, TokenKind { - override int getValue() { result = 70 } - - override string getDescription() { - result = "The case insensitive replace operator '-ireplace' or '-replace'." - } - - override string toString() { result = "Ireplace" } -} - -class Is extends @is, TokenKind { - override int getValue() { result = 92 } - - override string getDescription() { result = "The type test operator '-is'." } - - override string toString() { result = "Is" } -} - -class IsNot extends @isNot, TokenKind { - override int getValue() { result = 93 } - - override string getDescription() { result = "The type test operator '-isnot'." } - - override string toString() { result = "IsNot" } -} - -class Isplit extends @isplit, TokenKind { - override int getValue() { result = 75 } - - override string getDescription() { - result = "The case insensitive split operator '-isplit' or '-split'." - } - - override string toString() { result = "Isplit" } -} - -class Join extends @join, TokenKind { - override int getValue() { result = 59 } - - override string getDescription() { result = "The join operator '-join'." } - - override string toString() { result = "Join" } -} - -class Label extends @label, TokenKind { - override int getValue() { result = 5 } - - override string getDescription() { - result = - "A label token - always begins with ':', followed by the label name. Tokens with this kind are always instances of LabelToken." - } - - override string toString() { result = "Label" } -} - -class LBracket extends @lBracket, TokenKind { - override int getValue() { result = 20 } - - override string getDescription() { result = "The opening square brace token '['." } - - override string toString() { result = "LBracket" } -} - -class LCurly extends @lCurly, TokenKind { - override int getValue() { result = 18 } - - override string getDescription() { result = "The opening curly brace token '{'." } - - override string toString() { result = "LCurly" } -} - -class LineContinuation extends @lineContinuation, TokenKind { - override int getValue() { result = 9 } - - override string getDescription() { - result = "A line continuation (backtick followed by newline)." - } - - override string toString() { result = "LineContinuation" } -} - -class LParen extends @lParen, TokenKind { - override int getValue() { result = 16 } - - override string getDescription() { result = "The opening parenthesis token '('." } - - override string toString() { result = "LParen" } -} - -class Minus extends @minus, TokenKind { - override int getValue() { result = 41 } - - override string getDescription() { result = "The substraction operator '-'." } - - override string toString() { result = "Minus" } -} - -class MinusEquals extends @minusEquals, TokenKind { - override int getValue() { result = 44 } - - override string getDescription() { result = "The subtraction assignment operator '-='." } - - override string toString() { result = "MinusEquals" } -} - -class MinusMinus extends @minusMinus, TokenKind { - override int getValue() { result = 31 } - - override string getDescription() { result = "The pre-decrement operator '--'." } - - override string toString() { result = "MinusMinus" } -} - -class Module extends @module, TokenKind { - override int getValue() { result = 163 } - - override string getDescription() { result = "The 'module' keyword" } - - override string toString() { result = "Module" } -} - -class Multiply extends @multiply, TokenKind { - override int getValue() { result = 37 } - - override string getDescription() { result = "The multiplication operator '*'." } - - override string toString() { result = "Multiply" } -} - -class MultiplyEquals extends @multiplyEquals, TokenKind { - override int getValue() { result = 45 } - - override string getDescription() { result = "The multiplication assignment operator '*='." } - - override string toString() { result = "MultiplyEquals" } -} - -class Namespace extends @namespace, TokenKind { - override int getValue() { result = 162 } - - override string getDescription() { result = "The 'namespace' keyword" } - - override string toString() { result = "Namespace" } -} - -class NewLine extends @newLine, TokenKind { - override int getValue() { result = 8 } - - override string getDescription() { result = "A newline (one of '\n', '\r', or '\r\n')." } - - override string toString() { result = "NewLine" } -} - -class Not extends @not, TokenKind { - override int getValue() { result = 51 } - - override string getDescription() { result = "The logical not operator '-not'." } - - override string toString() { result = "Not" } -} - -class Number extends @number, TokenKind { - override int getValue() { result = 4 } - - override string getDescription() { - result = - "Any numerical literal token. Tokens with this kind are always instances of NumberToken." - } - - override string toString() { result = "Number" } -} - -class Or extends @or, TokenKind { - override int getValue() { result = 54 } - - override string getDescription() { result = "The logical or operator '-or'." } - - override string toString() { result = "Or" } -} - -class OrOr extends @orOr, TokenKind { - override int getValue() { result = 27 } - - override string getDescription() { result = "The (unimplemented) operator '||'." } - - override string toString() { result = "OrOr" } -} - -class Parallel extends @parallel, TokenKind { - override int getValue() { result = 152 } - - override string getDescription() { result = "The 'parallel' keyword." } - - override string toString() { result = "Parallel" } -} - -class Param extends @param, TokenKind { - override int getValue() { result = 140 } - - override string getDescription() { result = "The 'param' keyword." } - - override string toString() { result = "Param" } -} - -class ParameterToken extends @parameter_token, TokenKind { - override int getValue() { result = 3 } - - override string getDescription() { - result = - "A parameter to a command, always begins with a dash ('-'), followed by the parameter name. Tokens with this kind are always instances of ParameterToken." - } - - override string toString() { result = "Parameter" } -} - -class Pipe extends @pipe, TokenKind { - override int getValue() { result = 29 } - - override string getDescription() { result = "The pipe operator '|'." } - - override string toString() { result = "Pipe" } -} - -class Plus extends @plus, TokenKind { - override int getValue() { result = 40 } - - override string getDescription() { result = "The addition operator '+'." } - - override string toString() { result = "Plus" } -} - -class PlusEquals extends @plusEquals, TokenKind { - override int getValue() { result = 43 } - - override string getDescription() { result = "The addition assignment operator '+='." } - - override string toString() { result = "PlusEquals" } -} - -class PlusPlus extends @plusPlus, TokenKind { - override int getValue() { result = 32 } - - override string getDescription() { result = "The pre-increment operator '++'." } - - override string toString() { result = "PlusPlus" } -} - -class PostfixMinusMinus extends @postfixMinusMinus, TokenKind { - override int getValue() { result = 96 } - - override string getDescription() { result = "The post-decrement operator '--'." } - - override string toString() { result = "PostfixMinusMinus" } -} - -class PostfixPlusPlus extends @postfixPlusPlus, TokenKind { - override int getValue() { result = 95 } - - override string getDescription() { result = "The post-increment operator '++'." } - - override string toString() { result = "PostfixPlusPlus" } -} - -class Private extends @private, TokenKind { - override int getValue() { result = 158 } - - override string getDescription() { result = "The 'private' keyword" } - - override string toString() { result = "Private" } -} - -class Process extends @process, TokenKind { - override int getValue() { result = 141 } - - override string getDescription() { result = "The 'process' keyword." } - - override string toString() { result = "Process" } -} - -class Public extends @public, TokenKind { - override int getValue() { result = 157 } - - override string getDescription() { result = "The 'public' keyword" } - - override string toString() { result = "Public" } -} - -class QuestionDot extends @questionDot, TokenKind { - override int getValue() { result = 103 } - - override string getDescription() { result = "The null conditional member access operator '?.'." } - - override string toString() { result = "QuestionDot" } -} - -class QuestionLBracket extends @questionLBracket, TokenKind { - override int getValue() { result = 104 } - - override string getDescription() { result = "The null conditional index access operator '?[]'." } - - override string toString() { result = "QuestionLBracket" } -} - -class QuestionMark extends @questionMark, TokenKind { - override int getValue() { result = 100 } - - override string getDescription() { result = "The ternary operator '?'." } - - override string toString() { result = "QuestionMark" } -} - -class QuestionQuestion extends @questionQuestion, TokenKind { - override int getValue() { result = 102 } - - override string getDescription() { result = "The null coalesce operator '??'." } - - override string toString() { result = "QuestionQuestion" } -} - -class QuestionQuestionEquals extends @questionQuestionEquals, TokenKind { - override int getValue() { result = 101 } - - override string getDescription() { result = "The null conditional assignment operator '??='." } - - override string toString() { result = "QuestionQuestionEquals" } -} - -class RBracket extends @rBracket, TokenKind { - override int getValue() { result = 21 } - - override string getDescription() { result = "The closing square brace token ']'." } - - override string toString() { result = "RBracket" } -} - -class RCurly extends @rCurly, TokenKind { - override int getValue() { result = 19 } - - override string getDescription() { result = "The closing curly brace token '}'." } - - override string toString() { result = "RCurly" } -} - -class RedirectInStd extends @redirectInStd, TokenKind { - override int getValue() { result = 49 } - - override string getDescription() { - result = "The (unimplemented) stdin redirection operator '<'." - } - - override string toString() { result = "RedirectInStd" } -} - -class RedirectionToken extends @redirection_token, TokenKind { - override int getValue() { result = 48 } - - override string getDescription() { result = "A redirection operator such as '2>&1' or '>>'." } - - override string toString() { result = "Redirection" } -} - -class Rem extends @rem, TokenKind { - override int getValue() { result = 39 } - - override string getDescription() { result = "The modulo division (remainder) operator '%'." } - - override string toString() { result = "Rem" } -} - -class RemainderEquals extends @remainderEquals, TokenKind { - override int getValue() { result = 47 } - - override string getDescription() { - result = "The modulo division (remainder) assignment operator '%='." - } - - override string toString() { result = "RemainderEquals" } -} - -class Return extends @return, TokenKind { - override int getValue() { result = 142 } - - override string getDescription() { result = "The 'return' keyword." } - - override string toString() { result = "Return" } -} - -class RParen extends @rParen, TokenKind { - override int getValue() { result = 17 } - - override string getDescription() { result = "The closing parenthesis token ')'." } - - override string toString() { result = "RParen" } -} - -class Semi extends @semi, TokenKind { - override int getValue() { result = 25 } - - override string getDescription() { result = "The statement terminator ';'." } - - override string toString() { result = "Semi" } -} - -class Sequence extends @sequence, TokenKind { - override int getValue() { result = 153 } - - override string getDescription() { result = "The 'sequence' keyword." } - - override string toString() { result = "Sequence" } -} - -class Shl extends @shl, TokenKind { - override int getValue() { result = 97 } - - override string getDescription() { result = "The shift left operator." } - - override string toString() { result = "Shl" } -} - -class Shr extends @shr, TokenKind { - override int getValue() { result = 98 } - - override string getDescription() { result = "The shift right operator." } - - override string toString() { result = "Shr" } -} - -class SplattedVariable extends @splattedVariable, TokenKind { - override int getValue() { result = 2 } - - override string getDescription() { - result = - "A splatted variable token, always begins with '@' and followed by the variable name. Tokens with this kind are always instances of VariableToken." - } - - override string toString() { result = "SplattedVariable" } -} - -class Static extends @static, TokenKind { - override int getValue() { result = 159 } - - override string getDescription() { result = "The 'static' keyword" } - - override string toString() { result = "Static" } -} - -class StringExpandable extends @stringExpandable, TokenKind { - override int getValue() { result = 13 } - - override string getDescription() { - result = - "A double quoted string literal. Tokens with this kind are always instances of StringExpandableToken even if there are no nested tokens to expand." - } - - override string toString() { result = "StringExpandable" } -} - -class StringLiteralToken extends @stringLiteral_token, TokenKind { - override int getValue() { result = 12 } - - override string getDescription() { - result = - "A single quoted string literal. Tokens with this kind are always instances of StringLiteralToken." - } - - override string toString() { result = "StringLiteral" } -} - -class Switch extends @switch, TokenKind { - override int getValue() { result = 143 } - - override string getDescription() { result = "The 'switch' keyword." } - - override string toString() { result = "Switch" } -} - -class Throw extends @throw, TokenKind { - override int getValue() { result = 144 } - - override string getDescription() { result = "The 'throw' keyword." } - - override string toString() { result = "Throw" } -} - -class Trap extends @trap, TokenKind { - override int getValue() { result = 145 } - - override string getDescription() { result = "The 'trap' keyword." } - - override string toString() { result = "Trap" } -} - -class Try extends @try, TokenKind { - override int getValue() { result = 146 } - - override string getDescription() { result = "The 'try' keyword." } - - override string toString() { result = "Try" } -} - -class Type extends @type, TokenKind { - override int getValue() { result = 164 } - - override string getDescription() { result = "The 'type' keyword" } - - override string toString() { result = "Type" } -} - -class Unknown extends @unknown, TokenKind { - override int getValue() { result = 0 } - - override string getDescription() { result = "An unknown token, signifies an error condition." } - - override string toString() { result = "Unknown" } -} - -class Until extends @until, TokenKind { - override int getValue() { result = 147 } - - override string getDescription() { result = "The 'until' keyword." } - - override string toString() { result = "Until" } -} - -class Using extends @using, TokenKind { - override int getValue() { result = 148 } - - override string getDescription() { result = "The (unimplemented) 'using' keyword." } - - override string toString() { result = "Using" } -} - -class Var extends @var, TokenKind { - override int getValue() { result = 149 } - - override string getDescription() { result = "The (unimplemented) 'var' keyword." } - - override string toString() { result = "Var" } -} - -class Variable extends @variable, TokenKind { - override int getValue() { result = 1 } - - override string getDescription() { - result = - "A variable token, always begins with '$' and followed by the variable name, possibly enclose in curly braces. Tokens with this kind are always instances of VariableToken." - } - - override string toString() { result = "Variable" } -} - -class While extends @while, TokenKind { - override int getValue() { result = 150 } - - override string getDescription() { result = "The 'while' keyword." } - - override string toString() { result = "While" } -} - -class Workflow extends @workflow, TokenKind { - override int getValue() { result = 151 } - - override string getDescription() { result = "The 'workflow' keyword." } - - override string toString() { result = "Workflow" } -} - -class Xor extends @xor, TokenKind { - override int getValue() { result = 55 } - - override string getDescription() { result = "The logical exclusive or operator '-xor'." } - - override string toString() { result = "Xor" } -} 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/TryStmt.qll b/powershell/ql/lib/semmle/code/powershell/TryStmt.qll deleted file mode 100644 index 300c59712e6b..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/TryStmt.qll +++ /dev/null @@ -1,18 +0,0 @@ -import powershell - -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(_) } - - /** ..., if any. */ - StmtBlock getFinally() { try_statement_finally(this, result) } - - StmtBlock getBody() { try_statement(this, result) } - - predicate hasFinally() { exists(this.getFinally()) } -} diff --git a/powershell/ql/lib/semmle/code/powershell/Type.qll b/powershell/ql/lib/semmle/code/powershell/Type.qll deleted file mode 100644 index d67aea74ad15..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/Type.qll +++ /dev/null @@ -1,31 +0,0 @@ -import powershell - -class Type 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) } - - 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() - } - - 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() } -} diff --git a/powershell/ql/lib/semmle/code/powershell/TypeConstraint.qll b/powershell/ql/lib/semmle/code/powershell/TypeConstraint.qll deleted file mode 100644 index 970afcb5b70c..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/TypeConstraint.qll +++ /dev/null @@ -1,13 +0,0 @@ -import powershell - -class TypeConstraint extends @type_constraint, AttributeBase { - override SourceLocation getLocation() { type_constraint_location(this, result) } - - /** Gets the assembly name. */ - string getName() { type_constraint(this, result, _) } - - /** 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/TypeExpression.qll deleted file mode 100644 index 9817a5ca07a7..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/TypeExpression.qll +++ /dev/null @@ -1,14 +0,0 @@ -import powershell - -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() } -} diff --git a/powershell/ql/lib/semmle/code/powershell/UnaryExpression.qll b/powershell/ql/lib/semmle/code/powershell/UnaryExpression.qll deleted file mode 100644 index 6a42360d7dcf..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/UnaryExpression.qll +++ /dev/null @@ -1,73 +0,0 @@ -import powershell - -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, _, _) } -} - -class NotExpr extends UnaryExpr { - NotExpr() { this.getKind() = [36, 51] } - - predicate isExclamationMark() { this.getKind() = 36 } - - predicate isNot() { this.getKind() = 51 } - - final override string toString() { - this.isExclamationMark() and result = "!..." - or - this.isNot() and result = "-not ..." - } -} - -abstract private class AbstractUnaryArithmeticExpr extends UnaryExpr { } - -final class UnaryArithmeticExpr = AbstractUnaryArithmeticExpr; - -abstract private class AbstractPostfixExpr extends AbstractUnaryArithmeticExpr, UnaryExpr { } - -abstract private class AbstractPrefixExpr extends AbstractUnaryArithmeticExpr, UnaryExpr { } - -abstract private class AbstractIncrExpr extends AbstractUnaryArithmeticExpr, UnaryExpr { } - -abstract private class AbstractDecrExpr extends AbstractUnaryArithmeticExpr, UnaryExpr { } - -final class PostfixExpr = AbstractPostfixExpr; - -final class PrefixExpr = AbstractPrefixExpr; - -final class IncrExpr = AbstractIncrExpr; - -final class DecrExpr = AbstractDecrExpr; - -class PostfixIncrExpr extends AbstractPostfixExpr, AbstractIncrExpr { - PostfixIncrExpr() { this.getKind() = 95 } - - final override string toString() { result = "...++" } -} - -class PostfixDecrExpr extends AbstractPostfixExpr, AbstractIncrExpr { - PostfixDecrExpr() { this.getKind() = 96 } - - final override string toString() { result = "...--" } -} - -class PrefixDecrExpr extends AbstractPostfixExpr, AbstractIncrExpr { - PrefixDecrExpr() { this.getKind() = 31 } - - final override string toString() { result = "--..." } -} - -class PrefixIncrExpr extends AbstractPostfixExpr, AbstractIncrExpr { - PrefixIncrExpr() { this.getKind() = 32 } - - final override string toString() { result = "++..." } -} - -class NegateExpr extends AbstractUnaryArithmeticExpr { - NegateExpr() { this.getKind() = 41 } - - final override string toString() { result = "-..." } -} 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/UsingStmt.qll b/powershell/ql/lib/semmle/code/powershell/UsingStmt.qll deleted file mode 100644 index 2278409c0a55..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/UsingStmt.qll +++ /dev/null @@ -1,21 +0,0 @@ -import powershell - -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 - result = const.getValue().getValue() - ) - } - - string getAlias() { - exists(StringConstExpr const | - using_statement_alias(this, const) and // TODO: Change dbscheme - result = const.getValue().getValue() - ) - } -} 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/VariableExpression.qll b/powershell/ql/lib/semmle/code/powershell/VariableExpression.qll deleted file mode 100644 index b07774a29246..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/VariableExpression.qll +++ /dev/null @@ -1,59 +0,0 @@ -import powershell -private import internal.ExplicitWrite::Private - -private predicate isParameterName(@variable_expression ve) { parameter(_, ve, _, _) } - -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, _, _, _, _, _, _, _, _, _, _) } - - string getDriveName() { variable_expression(this, _, result, _, _, _, _, _, _, _, _, _) } - - boolean isConstant() { variable_expression(this, _, _, result, _, _, _, _, _, _, _, _) } - - boolean isGlobal() { variable_expression(this, _, _, _, result, _, _, _, _, _, _, _) } - - boolean isLocal() { variable_expression(this, _, _, _, _, result, _, _, _, _, _, _) } - - boolean isPrivate() { variable_expression(this, _, _, _, _, _, result, _, _, _, _, _) } - - boolean isScript() { variable_expression(this, _, _, _, _, _, _, result, _, _, _, _) } - - boolean isUnqualified() { variable_expression(this, _, _, _, _, _, _, _, result, _, _, _) } - - boolean isUnscoped() { variable_expression(this, _, _, _, _, _, _, _, _, result, _, _) } - - 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 VarWriteAccess extends VarAccess { - VarWriteAccess() { isExplicitWrite(this, _) or isImplicitVariableWriteAccess(this) } - - predicate isExplicit(AssignStmt assign) { isExplicitWrite(this, assign) } - - predicate isImplicit() { isImplicitVariableWriteAccess(this) } -} - -/** 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() } -} diff --git a/powershell/ql/lib/semmle/code/powershell/WhileStmt.qll b/powershell/ql/lib/semmle/code/powershell/WhileStmt.qll deleted file mode 100644 index 9f244d3ed78a..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/WhileStmt.qll +++ /dev/null @@ -1,11 +0,0 @@ -import powershell - -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) } -} diff --git a/powershell/ql/lib/semmle/code/powershell/controlflow/internal/Scope.qll b/powershell/ql/lib/semmle/code/powershell/controlflow/internal/Scope.qll deleted file mode 100644 index 49d182548fdd..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/controlflow/internal/Scope.qll +++ /dev/null @@ -1,20 +0,0 @@ -private import powershell -private import ControlFlowGraphImpl - -/** 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) - ) -} - -/** - * A variable scope. This is either a top-level (file), a module, a class, - * or a callable. - */ -class Scope extends Ast, ScriptBlock { - /** Gets the outer scope, if any. */ - Scope getOuterScope() { result = scopeOf(this) } -} 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 { } From 665202195c53e0f99f7e30315598407cd80d596c Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 26 Mar 2025 18:03:31 +0000 Subject: [PATCH 03/26] PS: Add user-facing AST classes. --- powershell/ql/lib/powershell.qll | 86 +---- .../ql/lib/semmle/code/powershell/ast/Ast.qll | 1 + .../ast/internal/ArrayExpression.qll | 37 ++ .../powershell/ast/internal/ArrayLiteral.qll | 25 ++ .../ast/internal/AssignmentStatement.qll | 33 ++ .../code/powershell/ast/internal/Ast.qll | 37 ++ .../powershell/ast/internal/AstImport.qll | 5 + .../powershell/ast/internal/Attribute.qll | 58 ++++ .../powershell/ast/internal/AttributeBase.qll | 3 + .../ast/internal/AttributedExpr.qll | 32 ++ .../ast/internal/AttributedExprBase.qll | 7 + .../ast/internal/AutomaticVariable.qll | 11 + .../ast/internal/BinaryExpression.qll | 328 ++++++++++++++++++ .../powershell/ast/internal/BoolLiteral.qll | 9 + .../powershell/ast/internal/BreakStmt.qll | 5 + .../code/powershell/ast/internal/CallExpr.qll | 54 +++ .../powershell/ast/internal/CatchClause.qll | 62 ++++ .../powershell/ast/internal/ChildIndex.qll | 267 ++++++++++++++ .../code/powershell/ast/internal/Command.qll | 147 ++++++++ .../powershell/ast/internal/CommentEntity.qll | 2 + .../powershell/ast/internal/Configuration.qll | 31 ++ .../code/powershell/ast/internal/Constant.qll | 122 +++++++ .../ast/internal/ConstantExpression.qll | 7 + .../powershell/ast/internal/ContinueStmt.qll | 5 + .../powershell/ast/internal/ConvertExpr.qll | 42 +++ .../code/powershell/ast/internal/DataStmt.qll | 37 ++ .../powershell/ast/internal/DoUntilStmt.qll | 31 ++ .../powershell/ast/internal/DoWhileStmt.qll | 33 ++ .../powershell/ast/internal/DynamicStmt.qll | 45 +++ .../powershell/ast/internal/EnvVariable.qll | 11 + .../powershell/ast/internal/ErrorExpr.qll | 5 + .../powershell/ast/internal/ErrorStmt.qll | 5 + .../code/powershell/ast/internal/ExitStmt.qll | 22 ++ .../internal/ExpandableStringExpression.qll | 31 ++ .../code/powershell/ast/internal/Expr.qll | 22 ++ .../code/powershell/ast/internal/ExprStmt.qll | 16 + .../code/powershell/ast/internal/File.qll | 1 + .../ast/internal/FileRedirection.qll | 7 + .../powershell/ast/internal/ForEachStmt.qll | 43 +++ .../code/powershell/ast/internal/ForStmt.qll | 58 ++++ .../code/powershell/ast/internal/Function.qll | 15 + .../powershell/ast/internal/FunctionBase.qll | 23 ++ .../ast/internal/FunctionDefinition.qll | 15 + .../code/powershell/ast/internal/GotoStmt.qll | 18 + .../powershell/ast/internal/HashTable.qll | 51 +++ .../code/powershell/ast/internal/If.qll | 57 +++ .../powershell/ast/internal/IndexExpr.qll | 51 +++ .../code/powershell/ast/internal/Internal.qll | 96 +++++ .../ast/internal/InvokeMemberExpression.qll | 74 ++++ .../code/powershell/ast/internal/Literal.qll | 3 + .../code/powershell/ast/internal/Location.qll | 1 + .../code/powershell/ast/internal/LoopStmt.qll | 5 + .../code/powershell/ast/internal/Member.qll | 41 +++ .../powershell/ast/internal/MemberExpr.qll | 58 ++++ .../ast/internal/MergingRedirection.qll | 7 + .../code/powershell/ast/internal/Method.qll | 35 ++ .../ast/internal/ModuleSpecification.qll | 1 + .../ast/internal/NamedAttributeArgument.qll | 24 ++ .../powershell/ast/internal/NamedBlock.qll | 56 +++ .../powershell/ast/internal/NullLiteral.qll | 7 + .../ast/internal/ObjectCreation.qll | 42 +++ .../powershell/ast/internal/Operation.qll | 19 + .../powershell/ast/internal/Parameter.qll | 56 +++ .../powershell/ast/internal/ParenExpr.qll | 21 ++ .../code/powershell/ast/internal/Pipeline.qll | 31 ++ .../powershell/ast/internal/PipelineChain.qll | 31 ++ .../ast/internal/PropertyMember.qll | 7 + .../powershell/ast/internal/Redirection.qll | 18 + .../powershell/ast/internal/ReturnStmt.qll | 25 ++ .../code/powershell/ast/internal/Scopes.qll | 23 ++ .../powershell/ast/internal/ScriptBlock.qll | 122 +++++++ .../ast/internal/ScriptBlockExpr.qll | 20 ++ .../ast/internal/SourceLocation.qll | 1 + .../powershell/ast/internal/Statement.qll | 3 + .../ast/internal/StatementBlock.qll | 42 +++ .../code/powershell/ast/internal/Stmt.qll | 3 + .../ast/internal/StringConstantExpression.qll | 7 + .../powershell/ast/internal/SubExpression.qll | 20 ++ .../powershell/ast/internal/SwitchStmt.qll | 65 ++++ .../ast/internal/TernaryExpression.qll | 55 +++ .../code/powershell/ast/internal/ThisExpr.qll | 6 + .../powershell/ast/internal/ThrowStmt.qll | 24 ++ .../powershell/ast/internal/TrapStatement.qll | 33 ++ .../code/powershell/ast/internal/TryStmt.qll | 52 +++ .../code/powershell/ast/internal/Type.qll | 38 ++ .../ast/internal/TypeConstraint.qll | 7 + .../ast/internal/TypeDefinitionStmt.qll | 50 +++ .../ast/internal/TypeExpression.qll | 32 ++ .../ast/internal/UnaryExpression.qll | 85 +++++ .../ast/internal/UsingExpression.qll | 21 ++ .../powershell/ast/internal/UsingStmt.qll | 9 + .../code/powershell/ast/internal/Variable.qll | 181 ++++++++++ .../powershell/ast/internal/WhileStmt.qll | 33 ++ 93 files changed, 3518 insertions(+), 85 deletions(-) create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/Ast.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/ArrayExpression.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/ArrayLiteral.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/AssignmentStatement.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Ast.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/AstImport.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Attribute.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/AttributeBase.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/AttributedExpr.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/AttributedExprBase.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/AutomaticVariable.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/BinaryExpression.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/BoolLiteral.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/BreakStmt.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/CallExpr.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/CatchClause.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/ChildIndex.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Command.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/CommentEntity.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Configuration.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Constant.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/ConstantExpression.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/ContinueStmt.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/ConvertExpr.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/DataStmt.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/DoUntilStmt.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/DoWhileStmt.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/DynamicStmt.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/EnvVariable.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/ErrorExpr.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/ErrorStmt.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/ExitStmt.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/ExpandableStringExpression.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Expr.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/ExprStmt.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/File.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/FileRedirection.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/ForEachStmt.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/ForStmt.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Function.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/FunctionBase.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/FunctionDefinition.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/GotoStmt.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/HashTable.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/If.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/IndexExpr.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Internal.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/InvokeMemberExpression.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Literal.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Location.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/LoopStmt.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Member.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/MemberExpr.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/MergingRedirection.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Method.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/ModuleSpecification.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/NamedAttributeArgument.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/NamedBlock.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/NullLiteral.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/ObjectCreation.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Operation.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Parameter.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/ParenExpr.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Pipeline.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/PipelineChain.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/PropertyMember.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Redirection.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/ReturnStmt.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Scopes.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/ScriptBlock.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/ScriptBlockExpr.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/SourceLocation.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Statement.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/StatementBlock.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Stmt.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/StringConstantExpression.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/SubExpression.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/SwitchStmt.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/TernaryExpression.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/ThisExpr.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/ThrowStmt.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/TrapStatement.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/TryStmt.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Type.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/TypeConstraint.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/TypeDefinitionStmt.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/TypeExpression.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/UnaryExpression.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/UsingExpression.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/UsingStmt.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Variable.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/WhileStmt.qll 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/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/ast/internal/BinaryExpression.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/BinaryExpression.qll new file mode 100644 index 000000000000..f40eba8a30a2 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/BinaryExpression.qll @@ -0,0 +1,328 @@ +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()) + ) + } + + 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()) + ) + } + + Expr getAnOperand() { result = this.getLeft() or result = this.getRight() } + + final override Ast getChild(ChildIndex i) { + result = super.getChild(i) + or + i = binaryExprLeft() and + result = this.getLeft() + or + i = binaryExprRight() and + result = this.getRight() + } +} + +abstract private class AbstractArithmeticExpr extends BinaryExpr { } + +final class ArithmeticExpr = AbstractArithmeticExpr; + +class AddExpr extends AbstractArithmeticExpr { + AddExpr() { this.getKind() = 40 } + + final override string toString() { result = "...+..." } +} + +class SubExpr extends AbstractArithmeticExpr { + SubExpr() { this.getKind() = 41 } + + final override string toString() { result = "...-..." } +} + +class MulExpr extends AbstractArithmeticExpr { + MulExpr() { this.getKind() = 37 } + + final override string toString() { result = "...*..." } +} + +class DivExpr extends AbstractArithmeticExpr { + DivExpr() { this.getKind() = 38 } + + final override string toString() { result = ".../..." } +} + +class RemExpr extends AbstractArithmeticExpr { + RemExpr() { this.getKind() = 39 } + + final override string toString() { result = "...%..." } +} + +abstract private class AbstractBitwiseExpr extends BinaryExpr { } + +final class BitwiseExpr = AbstractBitwiseExpr; + +class BitwiseAndExpr extends AbstractBitwiseExpr { + BitwiseAndExpr() { this.getKind() = 56 } + + final override string toString() { result = "...&..." } +} + +class BitwiseOrExpr extends AbstractBitwiseExpr { + BitwiseOrExpr() { this.getKind() = 57 } + + final override string toString() { result = "...|..." } +} + +class BitwiseXorExpr extends AbstractBitwiseExpr { + BitwiseXorExpr() { this.getKind() = 58 } + + final override string toString() { result = "...^..." } +} + +class ShiftLeftExpr extends AbstractBitwiseExpr { + ShiftLeftExpr() { this.getKind() = 97 } + + final override string toString() { result = "...<<..." } +} + +class ShiftRightExpr extends AbstractBitwiseExpr { + ShiftRightExpr() { this.getKind() = 98 } + + final override string toString() { result = "...>>..." } +} + +abstract private class AbstractComparisonExpr extends BinaryExpr { } + +final class ComparisonExpr = AbstractComparisonExpr; + +abstract private class AbstractCaseInsensitiveComparisonExpr extends AbstractComparisonExpr { } + +final class CaseInsensitiveComparisonExpr = AbstractCaseInsensitiveComparisonExpr; + +abstract private class AbstractCaseSensitiveComparisonExpr extends AbstractComparisonExpr { } + +final class CaseSensitiveComparisonExpr = AbstractCaseSensitiveComparisonExpr; + +class EqExpr extends AbstractCaseInsensitiveComparisonExpr { + EqExpr() { this.getKind() = 60 } + + final override string toString() { result = "... -eq ..." } +} + +class NeExpr extends AbstractCaseInsensitiveComparisonExpr { + NeExpr() { this.getKind() = 61 } + + final override string toString() { result = "... -ne ..." } +} + +class CEqExpr extends AbstractCaseSensitiveComparisonExpr { + CEqExpr() { this.getKind() = 76 } + + final override string toString() { result = "... -ceq ..." } +} + +class CNeExpr extends AbstractCaseSensitiveComparisonExpr { + CNeExpr() { this.getKind() = 77 } + + final override string toString() { result = "... -cne ..." } +} + +abstract private class AbstractRelationalExpr extends AbstractComparisonExpr { } + +final class RelationalExpr = AbstractRelationalExpr; + +abstract private class AbstractCaseInsensitiveRelationalExpr extends AbstractRelationalExpr { } + +final class CaseInsensitiveRelationalExpr = AbstractCaseInsensitiveRelationalExpr; + +abstract private class AbstractCaseSensitiveRelationalExpr extends AbstractRelationalExpr { } + +final class CaseSensitiveRelationalExpr = AbstractCaseSensitiveRelationalExpr; + +class GeExpr extends AbstractCaseInsensitiveRelationalExpr { + GeExpr() { this.getKind() = 62 } + + final override string toString() { result = "... -ge ..." } +} + +class GtExpr extends AbstractCaseInsensitiveRelationalExpr { + GtExpr() { this.getKind() = 63 } + + final override string toString() { result = "... -gt ..." } +} + +class LtExpr extends AbstractCaseInsensitiveRelationalExpr { + LtExpr() { this.getKind() = 64 } + + final override string toString() { result = "... -lt ..." } +} + +class LeExpr extends AbstractCaseInsensitiveRelationalExpr { + LeExpr() { this.getKind() = 65 } + + final override string toString() { result = "... -le ..." } +} + +class CGeExpr extends AbstractCaseSensitiveRelationalExpr { + CGeExpr() { this.getKind() = 78 } + + final override string toString() { result = "... -cge ..." } +} + +class CGtExpr extends AbstractCaseSensitiveRelationalExpr { + CGtExpr() { this.getKind() = 79 } + + final override string toString() { result = "... -cgt ..." } +} + +class CLtExpr extends AbstractCaseSensitiveRelationalExpr { + CLtExpr() { this.getKind() = 80 } + + final override string toString() { result = "... -clt ..." } +} + +class CLeExpr extends AbstractCaseSensitiveRelationalExpr { + CLeExpr() { this.getKind() = 81 } + + final override string toString() { result = "... -cle ..." } +} + +class LikeExpr extends AbstractCaseInsensitiveComparisonExpr { + LikeExpr() { this.getKind() = 66 } + + final override string toString() { result = "... -like ..." } +} + +class NotLikeExpr extends AbstractCaseInsensitiveComparisonExpr { + NotLikeExpr() { this.getKind() = 67 } + + final override string toString() { result = "... -notlike ..." } +} + +class MatchExpr extends AbstractCaseInsensitiveComparisonExpr { + MatchExpr() { this.getKind() = 68 } + + final override string toString() { result = "... -match ..." } +} + +class NotMatchExpr extends AbstractCaseInsensitiveComparisonExpr { + NotMatchExpr() { this.getKind() = 69 } + + final override string toString() { result = "... -notmatch ..." } +} + +class ReplaceExpr extends AbstractCaseInsensitiveComparisonExpr { + ReplaceExpr() { this.getKind() = 70 } + + final override string toString() { result = "... -replace ..." } +} + +abstract class AbstractTypeExpr extends BinaryExpr { } + +final class TypeExpr = AbstractTypeExpr; + +abstract class AbstractTypeComparisonExpr extends AbstractTypeExpr { } + +final class TypeComparisonExpr = AbstractTypeComparisonExpr; + +class IsExpr extends AbstractTypeComparisonExpr { + IsExpr() { this.getKind() = 92 } + + final override string toString() { result = "... -is ..." } +} + +class IsNotExpr extends AbstractTypeComparisonExpr { + IsNotExpr() { this.getKind() = 93 } + + final override string toString() { result = "... -isnot ..." } +} + +class AsExpr extends AbstractTypeExpr { + AsExpr() { this.getKind() = 94 } + + final override string toString() { result = "... -as ..." } +} + +abstract private class AbstractContainmentExpr extends BinaryExpr { } + +final class ContainmentExpr = AbstractContainmentExpr; + +abstract private class AbstractCaseInsensitiveContainmentExpr extends AbstractContainmentExpr { } + +final class CaseInsensitiveContainmentExpr = AbstractCaseInsensitiveContainmentExpr; + +class ContainsExpr extends AbstractCaseInsensitiveContainmentExpr { + ContainsExpr() { this.getKind() = 71 } + + final override string toString() { result = "... -contains ..." } +} + +class NotContainsExpr extends AbstractCaseInsensitiveContainmentExpr { + NotContainsExpr() { this.getKind() = 72 } + + final override string toString() { result = "... -notcontains ..." } +} + +class InExpr extends AbstractCaseInsensitiveContainmentExpr { + InExpr() { this.getKind() = 73 } + + final override string toString() { result = "... -in ..." } +} + +class NotInExpr extends AbstractCaseInsensitiveContainmentExpr { + NotInExpr() { this.getKind() = 74 } + + final override string toString() { result = "... -notin ..." } +} + +abstract private class AbstractLogicalBinaryExpr extends BinaryExpr { } + +final class LogicalBinaryExpr = AbstractLogicalBinaryExpr; + +class LogicalAndExpr extends AbstractLogicalBinaryExpr { + LogicalAndExpr() { this.getKind() = 53 } + + final override string toString() { result = "... -and ..." } +} + +class LogicalOrExpr extends AbstractLogicalBinaryExpr { + LogicalOrExpr() { this.getKind() = 54 } + + final override string toString() { result = "... -or ..." } +} + +class LogicalXorExpr extends AbstractLogicalBinaryExpr { + LogicalXorExpr() { this.getKind() = 55 } + + final override string toString() { result = "... -xor ..." } +} + +class JoinExpr extends BinaryExpr { + JoinExpr() { this.getKind() = 59 } + + final override string toString() { result = "... -join ..." } +} + +class SequenceExpr extends BinaryExpr { + SequenceExpr() { this.getKind() = 33 } + + final override string toString() { result = "[..]" } +} + +class FormatExpr extends BinaryExpr { + FormatExpr() { this.getKind() = 50 } + + final override string toString() { result = "... -f ..." } +} 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..74ba575ae711 --- /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 + 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/ast/internal/Constant.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Constant.qll new file mode 100644 index 000000000000..f39a9bdfff7a --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Constant.qll @@ -0,0 +1,122 @@ +private import AstImport + +private newtype TConstantValue = + TConstInteger(int 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(Raw::ConstExpr ce | + ce.getType() = "Double" and ce.getValue().getValue().toFloat() = double + ) + } or + TConstString(string value) { exists(Raw::StringLiteral sl | sl.getValue() = value) } or + TConstBoolean(boolean value) { + exists(Raw::VarAccess va | + value = true and + va.getUserPath() = "true" + or + value = false and + va.getUserPath() = "false" + ) + } or + TNull() + +/** A constant value. */ +class ConstantValue extends TConstantValue { + /** Gets a string representation of this value. */ + final string toString() { result = this.getValue() } + + /** Gets the value of this consant. */ + string getValue() { none() } + + /** Gets the integer value of this constant, if any. */ + int asInt() { none() } + + /** Gets the floating point value of this constant, if any. */ + float asDouble() { none() } + + /** Gets the string value of this constant, if any. */ + string asString() { none() } + + /** Gets the boolean value of this constant, if any. */ + boolean asBoolean() { none() } + + /** Holds if this constant represents the null value. */ + predicate isNull() { none() } + + /** Gets a (unique) serialized version of this value. */ + string serialize() { none() } + + /** Gets an exprssion that has this value. */ + Expr getAnExpr() { none() } +} + +/** A constant integer value */ +class ConstInteger extends ConstantValue, TConstInteger { + final override int asInt() { this = TConstInteger(result) } + + final override string getValue() { result = this.asInt().toString() } + + final override string serialize() { result = this.getValue() } + + final override ConstExpr getAnExpr() { + result.getValueString() = this.getValue() + } +} + +/** A constant floating point value. */ +class ConstDouble extends ConstantValue, TConstDouble { + final override float asDouble() { this = TConstDouble(result) } + + final override string getValue() { result = this.asDouble().toString() } + + final override string serialize() { + exists(string res | res = this.asDouble().toString() | + if exists(res.indexOf(".")) then result = res else result = res + ".0" + ) + } + + final override ConstExpr getAnExpr() { + exists(Raw::ConstExpr ce | + ce.getValue().getValue() = this.getValue() and + result = fromRaw(ce) + ) + } +} + +/** A constant string value. */ +class ConstString extends ConstantValue, TConstString { + final override string asString() { this = TConstString(result) } + + final override string getValue() { result = this.asString() } + + final override string serialize() { + result = "\"" + this.asString().replaceAll("\"", "\\\"") + "\"" + } + + final override StringConstExpr getAnExpr() { result.getValueString() = this.getValue() } +} + +/** A constant boolean value. */ +class ConstBoolean extends ConstantValue, TConstBoolean { + final override boolean asBoolean() { this = TConstBoolean(result) } + + final override string getValue() { result = this.asBoolean().toString() } + + final override string serialize() { result = this.getValue() } + + final override BoolLiteral getAnExpr() { result.getBoolValue() = this.asBoolean() } +} + +/** The constant null value. */ +class NullConst extends ConstantValue, TNull { + final override predicate isNull() { any() } + + final override string getValue() { result = "null" } + + final override string serialize() { result = this.getValue() } + + 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..0cd1938a077a --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/ObjectCreation.qll @@ -0,0 +1,42 @@ +import powershell + +abstract private class AbstractObjectCreation extends CallExpr { + /** 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 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 CmdCall { + DotNetObjectCreation() { this.getName() = "New-Object" } + + final override string getConstructedTypeName() { + // Either it's the named argument `TypeName` + result = CmdCall.super.getNamedArgument("TypeName").(StringConstExpr).getValueString() + or + // Or it's the first positional argument if that's the named argument + not CmdCall.super.hasNamedArgument("TypeName") and + exists(StringConstExpr arg | arg = CmdCall.super.getPositionalArgument(0) | + result = arg.getValueString() and + not arg = 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/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/ast/internal/Scopes.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Scopes.qll new file mode 100644 index 000000000000..52212cf5ea22 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Scopes.qll @@ -0,0 +1,23 @@ +private import AstImport + +/** 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) + ) +} + +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/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/ast/internal/UnaryExpression.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/UnaryExpression.qll new file mode 100644 index 000000000000..860dddfc65b3 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/UnaryExpression.qll @@ -0,0 +1,85 @@ +private import AstImport + +class UnaryExpr extends Expr, TUnaryExpr { + final override Ast getChild(ChildIndex i) { + result = super.getChild(i) + or + i = unaryExprOp() and result = this.getOperand() + } + + /** INTERNAL: Do not use. */ + int getKind() { result = getRawAst(this).(Raw::UnaryExpr).getKind() } + + 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 { + NotExpr() { this.getKind() = [36, 51] } + + predicate isExclamationMark() { this.getKind() = 36 } + + predicate isNot() { this.getKind() = 51 } + + final override string toString() { + this.isExclamationMark() and result = "!..." + or + this.isNot() and result = "-not ..." + } +} + +abstract private class AbstractUnaryArithmeticExpr extends UnaryExpr { } + +final class UnaryArithmeticExpr = AbstractUnaryArithmeticExpr; + +abstract private class AbstractPostfixExpr extends AbstractUnaryArithmeticExpr, UnaryExpr { } + +abstract private class AbstractPrefixExpr extends AbstractUnaryArithmeticExpr, UnaryExpr { } + +abstract private class AbstractIncrExpr extends AbstractUnaryArithmeticExpr, UnaryExpr { } + +abstract private class AbstractDecrExpr extends AbstractUnaryArithmeticExpr, UnaryExpr { } + +final class PostfixExpr = AbstractPostfixExpr; + +final class PrefixExpr = AbstractPrefixExpr; + +final class IncrExpr = AbstractIncrExpr; + +final class DecrExpr = AbstractDecrExpr; + +class PostfixIncrExpr extends AbstractPostfixExpr, AbstractIncrExpr { + PostfixIncrExpr() { this.getKind() = 95 } + + final override string toString() { result = "...++" } +} + +class PostfixDecrExpr extends AbstractPostfixExpr, AbstractIncrExpr { + PostfixDecrExpr() { this.getKind() = 96 } + + final override string toString() { result = "...--" } +} + +class PrefixDecrExpr extends AbstractPostfixExpr, AbstractIncrExpr { + PrefixDecrExpr() { this.getKind() = 31 } + + final override string toString() { result = "--..." } +} + +class PrefixIncrExpr extends AbstractPostfixExpr, AbstractIncrExpr { + PrefixIncrExpr() { this.getKind() = 32 } + + final override string toString() { result = "++..." } +} + +class NegateExpr extends AbstractUnaryArithmeticExpr { + NegateExpr() { this.getKind() = 41 } + + final override string toString() { result = "-..." } +} 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() + } +} From a207c8008bd76e291e477c11e2a520d2c28a87e4 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 26 Mar 2025 18:04:34 +0000 Subject: [PATCH 04/26] PS: Add 'raw' AST classes coming directly from the extractor. --- .../ast/internal/Raw/ArrayExpression.qll | 11 + .../ast/internal/Raw/ArrayLiteral.qll | 16 + .../ast/internal/Raw/AssignmentStatement.qll | 19 + .../code/powershell/ast/internal/Raw/Ast.qll | 17 + .../powershell/ast/internal/Raw/Attribute.qll | 33 + .../ast/internal/Raw/AttributeBase.qll | 3 + .../ast/internal/Raw/AttributedExpr.qll | 17 + .../ast/internal/Raw/AttributedExprBase.qll | 7 + .../internal/Raw/BaseConstantExpression.qll | 10 + .../ast/internal/Raw/BinaryExpression.qll | 35 + .../powershell/ast/internal/Raw/BreakStmt.qll | 5 + .../ast/internal/Raw/CatchClause.qll | 25 + .../powershell/ast/internal/Raw/Chainable.qll | 3 + .../ast/internal/Raw/ChildIndex.qll | 101 ++ .../powershell/ast/internal/Raw/Command.qll | 105 ++ .../ast/internal/Raw/CommandBase.qll | 3 + .../ast/internal/Raw/CommandElement.qll | 3 + .../ast/internal/Raw/CommandExpression.qll | 18 + .../ast/internal/Raw/CommandParameter.qll | 13 + .../ast/internal/Raw/CommentEntity.qll | 17 + .../ast/internal/Raw/Configuration.qll | 21 + .../ast/internal/Raw/ConstantExpression.qll | 9 + .../ast/internal/Raw/ContinueStmt.qll | 5 + .../ast/internal/Raw/ConvertExpr.qll | 22 + .../powershell/ast/internal/Raw/DataStmt.qll | 23 + .../ast/internal/Raw/DoUntilStmt.qll | 17 + .../ast/internal/Raw/DoWhileStmt.qll | 17 + .../ast/internal/Raw/DynamicStmt.qll | 27 + .../powershell/ast/internal/Raw/ErrorExpr.qll | 5 + .../powershell/ast/internal/Raw/ErrorStmt.qll | 5 + .../powershell/ast/internal/Raw/ExitStmt.qll | 14 + .../Raw/ExpandableStringExpression.qll | 20 + .../ast/internal/Raw/Expression.qll | 8 + .../code/powershell/ast/internal/Raw/File.qll | 224 +++ .../ast/internal/Raw/FileRedirection.qll | 5 + .../ast/internal/Raw/ForEachStmt.qll | 21 + .../powershell/ast/internal/Raw/ForStmt.qll | 27 + .../powershell/ast/internal/Raw/Function.qll | 22 + .../powershell/ast/internal/Raw/GotoStmt.qll | 9 + .../powershell/ast/internal/Raw/HashTable.qll | 23 + .../powershell/ast/internal/Raw/IfStmt.qll | 33 + .../powershell/ast/internal/Raw/IndexExpr.qll | 18 + .../internal/Raw/InvokeMemberExpression.qll | 32 + .../ast/internal/Raw/LabeledStmt.qll | 5 + .../powershell/ast/internal/Raw/Location.qll | 60 + .../powershell/ast/internal/Raw/LoopStmt.qll | 5 + .../powershell/ast/internal/Raw/Member.qll | 62 + .../ast/internal/Raw/MemberExpr.qll | 33 + .../ast/internal/Raw/MemberExpressionBase.qll | 5 + .../ast/internal/Raw/MergingRedirection.qll | 5 + .../ast/internal/Raw/ModuleSpecification.qll | 17 + .../internal/Raw/NamedAttributeArgument.qll | 23 + .../ast/internal/Raw/NamedBlock.qll | 36 + .../ast/internal/Raw/ParamBlock.qll | 36 + .../powershell/ast/internal/Raw/Parameter.qll | 60 + .../ast/internal/Raw/ParenExpression.qll | 9 + .../powershell/ast/internal/Raw/Pipeline.qll | 18 + .../ast/internal/Raw/PipelineBase.qll | 3 + .../ast/internal/Raw/PipelineChain.qll | 17 + .../ast/internal/Raw/PropertyMember.qll | 19 + .../code/powershell/ast/internal/Raw/Raw.qll | 84 + .../ast/internal/Raw/Redirection.qll | 10 + .../ast/internal/Raw/ReturnStmt.qll | 11 + .../powershell/ast/internal/Raw/Scope.qll | 59 + .../ast/internal/Raw/ScriptBlock.qll | 74 + .../ast/internal/Raw/ScriptBlockExpr.qll | 9 + .../ast/internal/Raw/SourceLocation.qll | 25 + .../powershell/ast/internal/Raw/Statement.qll | 3 + .../ast/internal/Raw/StatementBlock.qll | 27 + .../internal/Raw/StringConstantExpression.qll | 10 + .../ast/internal/Raw/StringLiteral.qll | 16 + .../ast/internal/Raw/SubExpression.qll | 12 + .../ast/internal/Raw/SwitchStmt.qll | 39 + .../ast/internal/Raw/TernaryExpression.qll | 33 + .../powershell/ast/internal/Raw/ThrowStmt.qll | 11 + .../powershell/ast/internal/Raw/TokenKind.qll | 1345 +++++++++++++++++ .../ast/internal/Raw/TrapStatement.qll | 17 + .../powershell/ast/internal/Raw/TryStmt.qll | 29 + .../code/powershell/ast/internal/Raw/Type.qll | 32 + .../ast/internal/Raw/TypeConstraint.qll | 11 + .../ast/internal/Raw/TypeExpression.qll | 10 + .../ast/internal/Raw/UnaryExpression.qll | 11 + .../ast/internal/Raw/UsingExpression.qll | 12 + .../powershell/ast/internal/Raw/UsingStmt.qll | 19 + .../ast/internal/Raw/VariableExpression.qll | 48 + .../powershell/ast/internal/Raw/WhileStmt.qll | 15 + 86 files changed, 3453 insertions(+) create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ArrayExpression.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ArrayLiteral.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/AssignmentStatement.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Ast.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Attribute.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/AttributeBase.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/AttributedExpr.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/AttributedExprBase.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/BaseConstantExpression.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/BinaryExpression.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/BreakStmt.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/CatchClause.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Chainable.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ChildIndex.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Command.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/CommandBase.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/CommandElement.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/CommandExpression.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/CommandParameter.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/CommentEntity.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Configuration.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ConstantExpression.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ContinueStmt.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ConvertExpr.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/DataStmt.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/DoUntilStmt.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/DoWhileStmt.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/DynamicStmt.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ErrorExpr.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ErrorStmt.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ExitStmt.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ExpandableStringExpression.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Expression.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/File.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/FileRedirection.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ForEachStmt.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ForStmt.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Function.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/GotoStmt.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/HashTable.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/IfStmt.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/IndexExpr.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/InvokeMemberExpression.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/LabeledStmt.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Location.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/LoopStmt.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Member.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/MemberExpr.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/MemberExpressionBase.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/MergingRedirection.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ModuleSpecification.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/NamedAttributeArgument.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/NamedBlock.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ParamBlock.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Parameter.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ParenExpression.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Pipeline.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/PipelineBase.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/PipelineChain.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/PropertyMember.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Raw.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Redirection.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ReturnStmt.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Scope.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ScriptBlock.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ScriptBlockExpr.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/SourceLocation.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Statement.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/StatementBlock.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/StringConstantExpression.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/StringLiteral.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/SubExpression.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/SwitchStmt.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/TernaryExpression.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ThrowStmt.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/TokenKind.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/TrapStatement.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/TryStmt.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Type.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/TypeConstraint.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/TypeExpression.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/UnaryExpression.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/UsingExpression.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/UsingStmt.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/VariableExpression.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/WhileStmt.qll 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/ast/internal/Raw/ArrayLiteral.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ArrayLiteral.qll new file mode 100644 index 000000000000..1fe24b69d17c --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ArrayLiteral.qll @@ -0,0 +1,16 @@ +private import Raw + +class ArrayLiteral extends @array_literal, Expr { + override SourceLocation getLocation() { array_literal_location(this, result) } + + Expr getElement(int index) { array_literal_element(this, index, result) } + + Expr getAnElement() { array_literal_element(this, _, 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/ast/internal/Raw/AssignmentStatement.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/AssignmentStatement.qll new file mode 100644 index 000000000000..99ff19ccf4bc --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/AssignmentStatement.qll @@ -0,0 +1,19 @@ +private import Raw + +class AssignStmt extends @assignment_statement, PipelineBase { + override SourceLocation getLocation() { assignment_statement_location(this, result) } + + int getKind() { assignment_statement(this, result, _, _) } + + Expr getLeftHandSide() { assignment_statement(this, _, result, _) } + + Stmt getRightHandSide() { assignment_statement(this, _, _, 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/ast/internal/Raw/Attribute.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Attribute.qll new file mode 100644 index 000000000000..10c1183bec0a --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Attribute.qll @@ -0,0 +1,33 @@ +private import Raw + +class Attribute extends @attribute, AttributeBase { + override SourceLocation getLocation() { attribute_location(this, result) } + + string getName() { attribute(this, result, _, _) } + + int getNumNamedArguments() { attribute(this, _, result, _) } + + int getNumPositionalArguments() { attribute(this, _, _, result) } + + 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()) } + + Expr getPositionalArgument(int i) { attribute_positional_argument(this, i, result) } + + Expr getAPositionalArgument() { result = this.getPositionalArgument(_) } + + int getNumberOfPositionalArguments() { result = count(this.getAPositionalArgument()) } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/AttributeBase.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/AttributeBase.qll new file mode 100644 index 000000000000..6c4bf907c0a1 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/AttributeBase.qll @@ -0,0 +1,3 @@ +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/ast/internal/Raw/BaseConstantExpression.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/BaseConstantExpression.qll new file mode 100644 index 000000000000..7592f4dfc956 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/BaseConstantExpression.qll @@ -0,0 +1,10 @@ +private import Raw + +/** The base class for constant expressions. */ +class BaseConstExpr extends @base_constant_expression, Expr { + /** Gets the type of this constant expression. */ + string getType() { none() } + + /** Gets a string literal of this constant expression. */ + StringLiteral getValue() { none() } +} 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/ast/internal/Raw/BreakStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/BreakStmt.qll new file mode 100644 index 000000000000..2c388b865fe8 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/BreakStmt.qll @@ -0,0 +1,5 @@ +import Raw + +class BreakStmt extends GotoStmt, @break_statement { + override SourceLocation getLocation() { break_statement_location(this, result) } +} 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/ast/internal/Raw/Chainable.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Chainable.qll new file mode 100644 index 000000000000..1f5419d8f1f4 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Chainable.qll @@ -0,0 +1,3 @@ +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/ast/internal/Raw/CommandBase.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/CommandBase.qll new file mode 100644 index 000000000000..b6ba3abb738a --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/CommandBase.qll @@ -0,0 +1,3 @@ +private import Raw + +class CmdBase extends @command_base, Chainable { } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/CommandElement.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/CommandElement.qll new file mode 100644 index 000000000000..ffeccacd5ebf --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/CommandElement.qll @@ -0,0 +1,3 @@ +private import Raw + +class CmdElement extends @command_element, Ast { } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/CommandExpression.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/CommandExpression.qll new file mode 100644 index 000000000000..7c9343ee7854 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/CommandExpression.qll @@ -0,0 +1,18 @@ +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(_) } +} 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/ast/internal/Raw/CommentEntity.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/CommentEntity.qll new file mode 100644 index 000000000000..e270595a12c4 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/CommentEntity.qll @@ -0,0 +1,17 @@ +private import Raw + +class Comment extends @comment_entity { + Location getLocation() { comment_entity_location(this, result) } + + StringLiteral getCommentContents() { comment_entity(this, result) } + + string toString() { result = this.getCommentContents().toString() } +} + +class SingleLineComment extends Comment { + SingleLineComment() { this.getCommentContents().getNumContinuations() = 1 } +} + +class MultiLineComment extends Comment { + MultiLineComment() { this.getCommentContents().getNumContinuations() > 1 } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Configuration.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Configuration.qll new file mode 100644 index 000000000000..8d9461b3c4de --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Configuration.qll @@ -0,0 +1,21 @@ +private import Raw + +class Configuration extends @configuration_definition, Stmt { + override SourceLocation getLocation() { configuration_definition_location(this, result) } + + 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/ast/internal/Raw/ContinueStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ContinueStmt.qll new file mode 100644 index 000000000000..0140a92c8639 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ContinueStmt.qll @@ -0,0 +1,5 @@ +private import Raw + +class ContinueStmt extends GotoStmt, @continue_statement { + override SourceLocation getLocation() { continue_statement_location(this, result) } +} 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/ast/internal/Raw/DataStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/DataStmt.qll new file mode 100644 index 000000000000..c8caa6e6cb7c --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/DataStmt.qll @@ -0,0 +1,23 @@ +private import Raw + +class DataStmt extends @data_statement, Stmt { + override SourceLocation getLocation() { data_statement_location(this, result) } + + string getVariableName() { data_statement_variable(this, result) } + + Expr getCmdAllowed(int i) { data_statement_commands_allowed(this, i, result) } + + 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/ast/internal/Raw/DoUntilStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/DoUntilStmt.qll new file mode 100644 index 000000000000..ef40c5460911 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/DoUntilStmt.qll @@ -0,0 +1,17 @@ +private import Raw + +class DoUntilStmt extends @do_until_statement, LoopStmt { + override SourceLocation getLocation() { do_until_statement_location(this, result) } + + 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/ast/internal/Raw/DoWhileStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/DoWhileStmt.qll new file mode 100644 index 000000000000..52909c5830fe --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/DoWhileStmt.qll @@ -0,0 +1,17 @@ +private import Raw + +class DoWhileStmt extends @do_while_statement, LoopStmt { + override SourceLocation getLocation() { do_while_statement_location(this, result) } + + 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/ast/internal/Raw/ErrorExpr.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ErrorExpr.qll new file mode 100644 index 000000000000..1f8d0d97720f --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ErrorExpr.qll @@ -0,0 +1,5 @@ +private import Raw + +class ErrorExpr extends @error_expression, Expr { + final override SourceLocation getLocation() { error_expression_location(this, result) } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ErrorStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ErrorStmt.qll new file mode 100644 index 000000000000..451922ad7e5c --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ErrorStmt.qll @@ -0,0 +1,5 @@ +private import Raw + +class ErrorStmt extends @error_statement, PipelineBase { + final override SourceLocation getLocation() { error_statement_location(this, result) } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ExitStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ExitStmt.qll new file mode 100644 index 000000000000..299735945cf3 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ExitStmt.qll @@ -0,0 +1,14 @@ +private import Raw + +class ExitStmt extends @exit_statement, Stmt { + override SourceLocation getLocation() { exit_statement_location(this, result) } + + /** ..., 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/ast/internal/Raw/ExpandableStringExpression.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ExpandableStringExpression.qll new file mode 100644 index 000000000000..86b08a5e4121 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ExpandableStringExpression.qll @@ -0,0 +1,20 @@ +private import Raw + +class ExpandableStringExpr extends @expandable_string_expression, Expr { + override SourceLocation getLocation() { expandable_string_expression_location(this, result) } + + StringLiteral getUnexpandedValue() { expandable_string_expression(this, result, _, _) } + + int getNumExprs() { result = count(this.getAnExpr()) } + + 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/ast/internal/Raw/File.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/File.qll new file mode 100644 index 000000000000..5fbadd59626d --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/File.qll @@ -0,0 +1,224 @@ +/** + * Provides classes representing filesystem files and folders. + * Based on csharp/ql/lib/semmle/code/csharp/File.qll + */ + +/** A file or folder. */ +class Container extends @container { + /** + * Gets the absolute, canonical path of this container, using forward slashes + * as path separator. + * + * The path starts with a _root prefix_ followed by zero or more _path + * segments_ separated by forward slashes. + * + * The root prefix is of one of the following forms: + * + * 1. A single forward slash `/` (Unix-style) + * 2. An upper-case drive letter followed by a colon and a forward slash, + * such as `C:/` (Windows-style) + * 3. Two forward slashes, a computer name, and then another forward slash, + * such as `//FileServer/` (UNC-style) + * + * Path segments are never empty (that is, absolute paths never contain two + * contiguous slashes, except as part of a UNC-style root prefix). Also, path + * segments never contain forward slashes, and no path segment is of the + * form `.` (one dot) or `..` (two dots). + * + * Note that an absolute path never ends with a forward slash, except if it is + * a bare root prefix, that is, the path has no path segments. A container + * whose absolute path has no segments is always a `Folder`, not a `File`. + */ + string getAbsolutePath() { none() } + + /** + * Gets a URL representing the location of this container. + * + * For more information see [Providing URLs](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/#providing-urls). + */ + string getURL() { none() } + + /** + * Gets the relative path of this file or folder from the root folder of the + * analyzed source location. The relative path of the root folder itself is + * the empty string. + * + * This has no result if the container is outside the source root, that is, + * if the root folder is not a reflexive, transitive parent of this container. + */ + string getRelativePath() { + exists(string absPath, string pref | + absPath = this.getAbsolutePath() and sourceLocationPrefix(pref) + | + absPath = pref and result = "" + or + absPath = pref.regexpReplaceAll("/$", "") + "/" + result and + not result.matches("/%") + ) + } + + /** + * Gets the base name of this container including extension, that is, the last + * segment of its absolute path, or the empty string if it has no segments. + * + * Here are some examples of absolute paths and the corresponding base names + * (surrounded with quotes to avoid ambiguity): + * + * + * + * + * + * + * + * + * + *
Absolute pathBase name
"/tmp/tst.sql""tst.sql"
"C:/Program Files (x86)""Program Files (x86)"
"/"""
"C:/"""
"D:/"""
"//FileServer/"""
+ */ + string getBaseName() { + result = this.getAbsolutePath().regexpCapture(".*/(([^/]*?)(?:\\.([^.]*))?)", 1) + } + + /** + * Gets the extension of this container, that is, the suffix of its base name + * after the last dot character, if any. + * + * In particular, + * + * - if the name does not include a dot, there is no extension, so this + * predicate has no result; + * - if the name ends in a dot, the extension is the empty string; + * - if the name contains multiple dots, the extension follows the last dot. + * + * Here are some examples of absolute paths and the corresponding extensions + * (surrounded with quotes to avoid ambiguity): + * + * + * + * + * + * + * + * + *
Absolute pathExtension
"/tmp/tst.cs""cs"
"/tmp/.classpath""classpath"
"/bin/bash"not defined
"/tmp/tst2."""
"/tmp/x.tar.gz""gz"
+ */ + string getExtension() { + result = this.getAbsolutePath().regexpCapture(".*/([^/]*?)(\\.([^.]*))?", 3) + } + + /** + * Gets the stem of this container, that is, the prefix of its base name up to + * (but not including) the last dot character if there is one, or the entire + * base name if there is not. + * + * Here are some examples of absolute paths and the corresponding stems + * (surrounded with quotes to avoid ambiguity): + * + * + * + * + * + * + * + * + *
Absolute pathStem
"/tmp/tst.cs""tst"
"/tmp/.classpath"""
"/bin/bash""bash"
"/tmp/tst2.""tst2"
"/tmp/x.tar.gz""x.tar"
+ */ + string getStem() { + result = this.getAbsolutePath().regexpCapture(".*/([^/]*?)(?:\\.([^.]*))?", 1) + } + + /** Gets the parent container of this file or folder, if any. */ + Container getParentContainer() { containerparent(result, this) } + + /** Gets a file or sub-folder in this container. */ + Container getAChildContainer() { this = result.getParentContainer() } + + /** Gets a file in this container. */ + File getAFile() { result = this.getAChildContainer() } + + /** Gets the file in this container that has the given `baseName`, if any. */ + File getFile(string baseName) { + result = this.getAFile() and + result.getBaseName() = baseName + } + + /** Gets a sub-folder in this container. */ + Folder getAFolder() { result = this.getAChildContainer() } + + /** Gets the sub-folder in this container that has the given `baseName`, if any. */ + Folder getFolder(string baseName) { + result = this.getAFolder() and + result.getBaseName() = baseName + } + + /** Gets the file or sub-folder in this container that has the given `name`, if any. */ + Container getChildContainer(string name) { + result = this.getAChildContainer() and + result.getBaseName() = name + } + + /** Gets the file in this container that has the given `stem` and `extension`, if any. */ + File getFile(string stem, string extension) { + result = this.getAChildContainer() and + result.getStem() = stem and + result.getExtension() = extension + } + + /** Gets a sub-folder contained in this container. */ + Folder getASubFolder() { result = this.getAChildContainer() } + + /** + * Gets a textual representation of the path of this container. + * + * This is the absolute path of the container. + */ + string toString() { result = this.getAbsolutePath() } +} + +/** A folder. */ +class Folder extends Container, @folder { + override string getAbsolutePath() { folders(this, result) } + + override string getURL() { result = "folder://" + this.getAbsolutePath() } +} + +/** A file. */ +class File extends Container, @file { + override string getAbsolutePath() { files(this, result) } + + /** Gets the number of lines in this file. */ + int getNumberOfLines() { numlines(this, result, _, _) } + + /** Gets the number of lines containing code in this file. */ + int getNumberOfLinesOfCode() { numlines(this, _, result, _) } + + /** Gets the number of lines containing comments in this file. */ + int getNumberOfLinesOfComments() { numlines(this, _, _, result) } + + override string getURL() { result = "file://" + this.getAbsolutePath() + ":0:0:0:0" } + + /** Holds if this file is a QL test stub file. */ + pragma[noinline] + private predicate isStub() { + // this.extractedQlTest() and + this.getAbsolutePath().matches("%resources/stubs/%") + } + + /** Holds if this file contains source code. */ + predicate fromSource() { + this.getExtension() = "cs" and + not this.isStub() + } + + /** Holds if this file is a library. */ + predicate fromLibrary() { + not this.getBaseName() = "" and + not this.fromSource() + } +} + +/** + * A source file. + */ +class SourceFile extends File { + SourceFile() { this.fromSource() } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/FileRedirection.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/FileRedirection.qll new file mode 100644 index 000000000000..c398aeb9ec9a --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/FileRedirection.qll @@ -0,0 +1,5 @@ +private import Raw + +class FileRedirection extends @file_redirection, Redirection { + override Location getLocation() { file_redirection_location(this, result) } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ForEachStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ForEachStmt.qll new file mode 100644 index 000000000000..980c2e848949 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ForEachStmt.qll @@ -0,0 +1,21 @@ +private import Raw + +class ForEachStmt extends @foreach_statement, LoopStmt { + override SourceLocation getLocation() { foreach_statement_location(this, result) } + + final override StmtBlock getBody() { foreach_statement(this, _, _, result, _) } + + VarAccess getVarAccess() { foreach_statement(this, result, _, _, _) } + + 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/ast/internal/Raw/ForStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ForStmt.qll new file mode 100644 index 000000000000..e136f274b214 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ForStmt.qll @@ -0,0 +1,27 @@ +private import Raw + +class ForStmt extends @for_statement, LoopStmt { + override SourceLocation getLocation() { for_statement_location(this, result) } + + PipelineBase getInitializer() { for_statement_initializer(this, result) } + + PipelineBase getCondition() { for_statement_condition(this, result) } + + 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/ast/internal/Raw/GotoStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/GotoStmt.qll new file mode 100644 index 000000000000..bae96f4aa51f --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/GotoStmt.qll @@ -0,0 +1,9 @@ +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/ast/internal/Raw/IfStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/IfStmt.qll new file mode 100644 index 000000000000..35754f5740a1 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/IfStmt.qll @@ -0,0 +1,33 @@ +private import Raw + +class IfStmt extends @if_statement, Stmt { + override SourceLocation getLocation() { if_statement_location(this, result) } + + PipelineBase getCondition(int i) { if_statement_clause(this, i, result, _) } + + PipelineBase getACondition() { result = this.getCondition(_) } + + StmtBlock getThen(int i) { if_statement_clause(this, i, _, result) } + + int getNumberOfConditions() { result = count(this.getACondition()) } + + StmtBlock getAThen() { result = this.getThen(_) } + + /** ..., if any. */ + 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/ast/internal/Raw/LabeledStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/LabeledStmt.qll new file mode 100644 index 000000000000..058d15922dfe --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/LabeledStmt.qll @@ -0,0 +1,5 @@ +private import Raw + +class LabeledStmt extends @labeled_statement, Stmt { + string getLabel() { label(this, result) } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Location.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Location.qll new file mode 100644 index 000000000000..574d5598578f --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Location.qll @@ -0,0 +1,60 @@ +/** + * Provides the `Location` class to give a location for each + * program element. + * + * A `SourceLocation` provides a section of text in a source file + * containing the program element. + * + * Based on csharp/ql/lib/semmle/code/csharp/Location.qll + */ + +import File + +/** + * A location of a program element. + */ +class Location extends @location { + /** Gets the file of the location. */ + File getFile() { none() } + + /** + * Holds if this element is at the specified location. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `filepath`. + * For more information, see + * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/). + */ + predicate hasLocationInfo( + string filepath, int startline, int startcolumn, int endline, int endcolumn + ) { + none() + } + + /** Gets a textual representation of this location. */ + string toString() { none() } + + /** Gets the 1-based line number (inclusive) where this location starts. */ + int getStartLine() { this.hasLocationInfo(_, result, _, _, _) } + + /** Gets the 1-based line number (inclusive) where this location ends. */ + int getEndLine() { this.hasLocationInfo(_, _, _, result, _) } + + /** Gets the 1-based column number (inclusive) where this location starts. */ + int getStartColumn() { this.hasLocationInfo(_, _, result, _, _) } + + /** 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. */ +class EmptyLocation extends Location { + EmptyLocation() { this.hasLocationInfo("", 0, 0, 0, 0) } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/LoopStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/LoopStmt.qll new file mode 100644 index 000000000000..2889b1c7d8d7 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/LoopStmt.qll @@ -0,0 +1,5 @@ +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/ast/internal/Raw/MemberExpr.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/MemberExpr.qll new file mode 100644 index 000000000000..26f4996f52ca --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/MemberExpr.qll @@ -0,0 +1,33 @@ +private import Raw + +class MemberExpr extends @member_expression, MemberExprBase { + final override Location getLocation() { member_expression_location(this, result) } + + Expr getQualifier() { member_expression(this, result, _, _, _) } + + CmdElement getMember() { member_expression(this, _, result, _, _) } + + /** Gets the name of the member being looked up, if any. */ + string getMemberName() { result = this.getMember().(StringConstExpr).getValue().getValue() } + + predicate isNullConditional() { member_expression(this, _, _, true, _) } + + override predicate isStatic() { member_expression(this, _, _, _, true) } + + 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. */ +class MemberExprWriteAccess extends MemberExpr { + MemberExprWriteAccess() { this = any(AssignStmt assign).getLeftHandSide() } +} + +/** 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/Raw/MemberExpressionBase.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/MemberExpressionBase.qll new file mode 100644 index 000000000000..02758e5a7867 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/MemberExpressionBase.qll @@ -0,0 +1,5 @@ +private import Raw + +class MemberExprBase extends @member_expression_base, Expr { + predicate isStatic() { none() } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/MergingRedirection.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/MergingRedirection.qll new file mode 100644 index 000000000000..491dbada6bb0 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/MergingRedirection.qll @@ -0,0 +1,5 @@ +private import Raw + +class MergingRedirection extends @merging_redirection, Redirection { + override Location getLocation() { merging_redirection_location(this, result) } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ModuleSpecification.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ModuleSpecification.qll new file mode 100644 index 000000000000..9a512d62690c --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ModuleSpecification.qll @@ -0,0 +1,17 @@ +private import Raw + +class ModuleSpecification extends @module_specification { + string toString() { result = this.getName() } + + string getName() { module_specification(this, result, _, _, _, _) } + + string getGuid() { module_specification(this, _, result, _, _, _) } + + string getMaxVersion() { module_specification(this, _, _, result, _, _) } + + string getRequiredVersion() { module_specification(this, _, _, _, result, _) } + + string getVersion() { module_specification(this, _, _, _, _, result) } + + Location getLocation() { result instanceof EmptyLocation } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/NamedAttributeArgument.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/NamedAttributeArgument.qll new file mode 100644 index 000000000000..324dec4d27e7 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/NamedAttributeArgument.qll @@ -0,0 +1,23 @@ +private import Raw + +class NamedAttributeArgument extends @named_attribute_argument, Ast { + final override SourceLocation getLocation() { named_attribute_argument_location(this, result) } + + string getName() { named_attribute_argument(this, result, _) } + + 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 { + ValueFromPipelineAttribute() { this.getName() = "ValueFromPipeline" } +} + +class ValueFromPipelineByPropertyName extends NamedAttributeArgument { + ValueFromPipelineByPropertyName() { this.getName() = "ValueFromPipelineByPropertyName" } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/NamedBlock.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/NamedBlock.qll new file mode 100644 index 000000000000..f11e621e74d0 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/NamedBlock.qll @@ -0,0 +1,36 @@ +private import Raw + +class NamedBlock extends @named_block, Ast { + override SourceLocation getLocation() { named_block_location(this, result) } + + int getNumStatements() { named_block(this, result, _) } + + int getNumTraps() { named_block(this, _, result) } + + Stmt getStmt(int i) { named_block_statement(this, i, result) } + + Stmt getAStmt() { result = this.getStmt(_) } + + 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/ast/internal/Raw/ParenExpression.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ParenExpression.qll new file mode 100644 index 000000000000..5e767329b165 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ParenExpression.qll @@ -0,0 +1,9 @@ +private import Raw + +class ParenExpr extends @paren_expression, Expr { + PipelineBase getBase() { paren_expression(this, result) } + + override SourceLocation getLocation() { paren_expression_location(this, result) } + + final override Ast getChild(ChildIndex i) { i = ParenExprExpr() and result = this.getBase() } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Pipeline.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Pipeline.qll new file mode 100644 index 000000000000..c8d24d6f8ba6 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Pipeline.qll @@ -0,0 +1,18 @@ +private import Raw + +class Pipeline extends @pipeline, Chainable { + override SourceLocation getLocation() { pipeline_location(this, result) } + + int getNumberOfComponents() { result = count(this.getAComponent()) } + + 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/ast/internal/Raw/PipelineBase.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/PipelineBase.qll new file mode 100644 index 000000000000..9c1e793a4e5c --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/PipelineBase.qll @@ -0,0 +1,3 @@ +private import Raw + +class PipelineBase extends @pipeline_base, Stmt { } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/PipelineChain.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/PipelineChain.qll new file mode 100644 index 000000000000..f7e08c9b41e5 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/PipelineChain.qll @@ -0,0 +1,17 @@ +private import Raw + +class PipelineChain extends @pipeline_chain, Chainable { + final override SourceLocation getLocation() { pipeline_chain_location(this, result) } + + predicate isBackground() { pipeline_chain(this, true, _, _, _) } + + 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/ast/internal/Raw/PropertyMember.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/PropertyMember.qll new file mode 100644 index 000000000000..b7830927ed9a --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/PropertyMember.qll @@ -0,0 +1,19 @@ +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 predicate isHidden() { property_member(this, true, _, _, _, _, _) } + + override predicate isPrivate() { property_member(this, _, true, _, _, _, _) } + + 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/ast/internal/Raw/ReturnStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ReturnStmt.qll new file mode 100644 index 000000000000..a007dec2ffec --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ReturnStmt.qll @@ -0,0 +1,11 @@ +private import Raw + +class ReturnStmt extends @return_statement, Stmt { + override SourceLocation getLocation() { return_statement_location(this, result) } + + 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/ast/internal/Raw/ScriptBlock.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ScriptBlock.qll new file mode 100644 index 000000000000..4b923136aa38 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ScriptBlock.qll @@ -0,0 +1,74 @@ +private import Raw + +class ScriptBlock extends @script_block, Ast { + predicate isTopLevel() { not exists(this.getParent()) } + + override Location getLocation() { script_block_location(this, result) } + + int getNumUsings() { script_block(this, result, _, _, _, _) } + + int getNumRequiredModules() { script_block(this, _, result, _, _, _) } + + int getNumRequiredAssemblies() { script_block(this, _, _, result, _, _) } + + int getNumRequiredPsEditions() { script_block(this, _, _, _, result, _) } + + int getNumRequiredPsSnapIns() { script_block(this, _, _, _, _, result) } + + Stmt getUsing(int i) { script_block_using(this, i, result) } + + Stmt getAUsing() { result = this.getUsing(_) } + + ParamBlock getParamBlock() { script_block_param_block(this, result) } + + NamedBlock getBeginBlock() { script_block_begin_block(this, result) } + + NamedBlock getCleanBlock() { script_block_clean_block(this, result) } + + NamedBlock getDynamicParamBlock() { script_block_dynamic_param_block(this, result) } + + NamedBlock getEndBlock() { script_block_end_block(this, result) } + + NamedBlock getProcessBlock() { script_block_process_block(this, result) } + + string getRequiredApplicationId() { script_block_required_application_id(this, result) } + + boolean getRequiresElevation() { script_block_requires_elevation(this, result) } + + string getRequiredPsVersion() { script_block_required_ps_version(this, result) } + + ModuleSpecification getModuleSpecification(int i) { + script_block_required_module(this, i, result) + } + + ModuleSpecification getAModuleSpecification() { result = this.getModuleSpecification(_) } + + final override Ast getChild(ChildIndex i) { + exists(int index | + i = ScriptBlockUsing(index) and + result = this.getUsing(index) + ) + or + 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() + } +} + +class TopLevelScriptBlock extends ScriptBlock { + TopLevelScriptBlock() { this.isTopLevel() } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ScriptBlockExpr.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ScriptBlockExpr.qll new file mode 100644 index 000000000000..288daed9b0ee --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ScriptBlockExpr.qll @@ -0,0 +1,9 @@ +private import Raw + +class ScriptBlockExpr extends @script_block_expression, Expr { + override SourceLocation getLocation() { script_block_expression_location(this, 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/ast/internal/Raw/SourceLocation.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/SourceLocation.qll new file mode 100644 index 000000000000..569de5e4229e --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/SourceLocation.qll @@ -0,0 +1,25 @@ +private import Raw + +/** + * A location in source code, comprising of a source file and a segment of text + * within the file. + */ +class SourceLocation extends Location, @location_default { + override File getFile() { locations_default(this, result, _, _, _, _) } + + override predicate hasLocationInfo( + string filepath, int startline, int startcolumn, int endline, int endcolumn + ) { + exists(File f | locations_default(this, f, startline, startcolumn, endline, endcolumn) | + filepath = f.getAbsolutePath() + ) + } + + override string toString() { + exists(string filepath, int startline, int startcolumn, int endline, int endcolumn | + this.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) + | + result = filepath + ":" + startline + ":" + startcolumn + ":" + endline + ":" + endcolumn + ) + } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Statement.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Statement.qll new file mode 100644 index 000000000000..881f86e94f26 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Statement.qll @@ -0,0 +1,3 @@ +private import Raw + +class Stmt extends @statement, Ast { } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/StatementBlock.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/StatementBlock.qll new file mode 100644 index 000000000000..8fc5b4b238d6 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/StatementBlock.qll @@ -0,0 +1,27 @@ +private import Raw + +class StmtBlock extends @statement_block, Ast { + override SourceLocation getLocation() { statement_block_location(this, result) } + + int getNumberOfStmts() { statement_block(this, result, _) } + + int getNumTraps() { statement_block(this, _, result) } + + Stmt getStmt(int index) { statement_block_statement(this, index, result) } + + Stmt getAStmt() { result = this.getStmt(_) } + + TrapStmt getTrapStmt(int index) { statement_block_trap(this, index, result) } + + TrapStmt getATrapStmt() { result = this.getTrapStmt(_) } + + 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/ast/internal/Raw/StringConstantExpression.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/StringConstantExpression.qll new file mode 100644 index 000000000000..dabbc2e2e73f --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/StringConstantExpression.qll @@ -0,0 +1,10 @@ +private import Raw + +/** A string constant. */ +class StringConstExpr extends @string_constant_expression, BaseConstExpr { + override StringLiteral getValue() { string_constant_expression(this, result) } + + override string getType() { result = "String" } + + override SourceLocation getLocation() { string_constant_expression_location(this, result) } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/StringLiteral.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/StringLiteral.qll new file mode 100644 index 000000000000..e24ed143cdf1 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/StringLiteral.qll @@ -0,0 +1,16 @@ +private import Raw + +class StringLiteral extends @string_literal { + int getNumContinuations() { result = strictcount(int i | exists(this.getContinuation(i))) } + + string getContinuation(int index) { string_literal_line(this, index, result) } + + /** Get the full string literal with all its parts concatenated */ + string toString() { result = this.getValue() } + + string getValue() { + result = concat(int i | i = [0 .. this.getNumContinuations()] | this.getContinuation(i), "\n") + } + + SourceLocation getLocation() { string_literal_location(this, result) } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/SubExpression.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/SubExpression.qll new file mode 100644 index 000000000000..b2caafdc304d --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/SubExpression.qll @@ -0,0 +1,12 @@ +private import Raw + +// TODO: Should we remove this from the dbscheme? +class ExpandableSubExpr extends @sub_expression, Expr { + final override Location getLocation() { sub_expression_location(this, result) } + + StmtBlock getExpr() { sub_expression(this, result) } + + final override Ast getChild(ChildIndex i) { + i = ExpandableSubExprExpr() and result = this.getExpr() + } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/SwitchStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/SwitchStmt.qll new file mode 100644 index 000000000000..bb8a30b6bd34 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/SwitchStmt.qll @@ -0,0 +1,39 @@ +private import Raw + +class SwitchStmt extends LabeledStmt, @switch_statement { + final override Location getLocation() { switch_statement_location(this, result) } + + PipelineBase getCondition() { switch_statement(this, result, _) } + + StmtBlock getDefault() { switch_statement_default(this, result) } + + StmtBlock getCase(int i, Expr e) { switch_statement_clauses(this, i, e, result) } + + StmtBlock getCase(int i) { result = this.getCase(i, _) } + + StmtBlock getACase() { result = this.getCase(_) } + + StmtBlock getCaseForExpr(Expr e) { result = this.getCase(_, e) } + + Expr getPattern(int i) { exists(this.getCase(i, result)) } + + Expr getAPattern() { result = this.getPattern(_) } + + int getNumberOfCases() { result = count(this.getACase()) } + + 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/ast/internal/Raw/TernaryExpression.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/TernaryExpression.qll new file mode 100644 index 000000000000..9b6e49e6ddb5 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/TernaryExpression.qll @@ -0,0 +1,33 @@ +private import Raw + +class ConditionalExpr extends @ternary_expression, Expr { + + override SourceLocation getLocation() { ternary_expression_location(this, result) } + + Expr getCondition() { ternary_expression(this, result, _, _) } + + Expr getIfFalse() { ternary_expression(this, _, result, _) } + + Expr getIfTrue() { ternary_expression(this, _, _, result) } + + Expr getBranch(boolean value) { + value = true and + result = this.getIfTrue() + or + value = false and + result = this.getIfFalse() + } + + 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/ast/internal/Raw/ThrowStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ThrowStmt.qll new file mode 100644 index 000000000000..58f357a8efeb --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ThrowStmt.qll @@ -0,0 +1,11 @@ +private import Raw + +class ThrowStmt extends @throw_statement, Stmt { + override SourceLocation getLocation() { throw_statement_location(this, result) } + + 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/ast/internal/Raw/TokenKind.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/TokenKind.qll new file mode 100644 index 000000000000..a179d3612917 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/TokenKind.qll @@ -0,0 +1,1345 @@ +class TokenKind extends @token_kind { + string toString() { none() } + + string getDescription() { none() } + + int getValue() { none() } +} + +class Ampersand extends @ampersand, TokenKind { + override int getValue() { result = 28 } + + override string getDescription() { result = "The invocation operator '&'." } + + override string toString() { result = "Ampersand" } +} + +class And extends @and, TokenKind { + override int getValue() { result = 53 } + + override string getDescription() { result = "The logical and operator '-and'." } + + override string toString() { result = "And" } +} + +class AndAnd extends @andAnd, TokenKind { + override int getValue() { result = 26 } + + override string getDescription() { result = "The (unimplemented) operator '&&'." } + + override string toString() { result = "AndAnd" } +} + +class As extends @as, TokenKind { + override int getValue() { result = 94 } + + override string getDescription() { result = "The type conversion operator '-as'." } + + override string toString() { result = "As" } +} + +class Assembly extends @assembly, TokenKind { + override int getValue() { result = 165 } + + override string getDescription() { result = "The 'assembly' keyword" } + + override string toString() { result = "Assembly" } +} + +class AtCurly extends @atCurly, TokenKind { + override int getValue() { result = 23 } + + override string getDescription() { result = "The opening token of a hash expression '@{'." } + + override string toString() { result = "AtCurly" } +} + +class AtParen extends @atParen, TokenKind { + override int getValue() { result = 22 } + + override string getDescription() { result = "The opening token of an array expression '@('." } + + override string toString() { result = "AtParen" } +} + +class Band extends @band, TokenKind { + override int getValue() { result = 56 } + + override string getDescription() { result = "The bitwise and operator '-band'." } + + override string toString() { result = "Band" } +} + +class Base extends @base, TokenKind { + override int getValue() { result = 168 } + + override string getDescription() { result = "The 'base' keyword" } + + override string toString() { result = "Base" } +} + +class Begin extends @begin, TokenKind { + override int getValue() { result = 119 } + + override string getDescription() { result = "The 'begin' keyword." } + + override string toString() { result = "Begin" } +} + +class Bnot extends @bnot, TokenKind { + override int getValue() { result = 52 } + + override string getDescription() { result = "The bitwise not operator '-bnot'." } + + override string toString() { result = "Bnot" } +} + +class Bor extends @bor, TokenKind { + override int getValue() { result = 57 } + + override string getDescription() { result = "The bitwise or operator '-bor'." } + + override string toString() { result = "Bor" } +} + +class Break extends @break, TokenKind { + override int getValue() { result = 120 } + + override string getDescription() { result = "The 'break' keyword." } + + override string toString() { result = "Break" } +} + +class Bxor extends @bxor, TokenKind { + override int getValue() { result = 58 } + + override string getDescription() { result = "The bitwise exclusive or operator '-xor'." } + + override string toString() { result = "Bxor" } +} + +class Catch extends @catch, TokenKind { + override int getValue() { result = 121 } + + override string getDescription() { result = "The 'catch' keyword." } + + override string toString() { result = "Catch" } +} + +class Ccontains extends @ccontains, TokenKind { + override int getValue() { result = 87 } + + override string getDescription() { result = "The case sensitive contains operator '-ccontains'." } + + override string toString() { result = "Ccontains" } +} + +class Ceq extends @ceq, TokenKind { + override int getValue() { result = 76 } + + override string getDescription() { result = "The case sensitive equal operator '-ceq'." } + + override string toString() { result = "Ceq" } +} + +class Cge extends @cge, TokenKind { + override int getValue() { result = 78 } + + override string getDescription() { + result = "The case sensitive greater than or equal operator '-cge'." + } + + override string toString() { result = "Cge" } +} + +class Cgt extends @cgt, TokenKind { + override int getValue() { result = 79 } + + override string getDescription() { result = "The case sensitive greater than operator '-cgt'." } + + override string toString() { result = "Cgt" } +} + +class Cin extends @cin, TokenKind { + override int getValue() { result = 89 } + + override string getDescription() { result = "The case sensitive in operator '-cin'." } + + override string toString() { result = "Cin" } +} + +class Class extends @class, TokenKind { + override int getValue() { result = 122 } + + override string getDescription() { result = "The 'class' keyword." } + + override string toString() { result = "Class" } +} + +class Cle extends @cle, TokenKind { + override int getValue() { result = 81 } + + override string getDescription() { + result = "The case sensitive less than or equal operator '-cle'." + } + + override string toString() { result = "Cle" } +} + +class Clean extends @clean, TokenKind { + override int getValue() { result = 170 } + + override string getDescription() { result = "The 'clean' keyword." } + + override string toString() { result = "Clean" } +} + +class Clike extends @clike, TokenKind { + override int getValue() { result = 82 } + + override string getDescription() { result = "The case sensitive like operator '-clike'." } + + override string toString() { result = "Clike" } +} + +class Clt extends @clt, TokenKind { + override int getValue() { result = 80 } + + override string getDescription() { result = "The case sensitive less than operator '-clt'." } + + override string toString() { result = "Clt" } +} + +class Cmatch extends @cmatch, TokenKind { + override int getValue() { result = 84 } + + override string getDescription() { result = "The case sensitive match operator '-cmatch'." } + + override string toString() { result = "Cmatch" } +} + +class Cne extends @cne, TokenKind { + override int getValue() { result = 77 } + + override string getDescription() { result = "The case sensitive not equal operator '-cne'." } + + override string toString() { result = "Cne" } +} + +class Cnotcontains extends @cnotcontains, TokenKind { + override int getValue() { result = 88 } + + override string getDescription() { + result = "The case sensitive not contains operator '-cnotcontains'." + } + + override string toString() { result = "Cnotcontains" } +} + +class Cnotin extends @cnotin, TokenKind { + override int getValue() { result = 90 } + + override string getDescription() { result = "The case sensitive not in operator '-notin'." } + + override string toString() { result = "Cnotin" } +} + +class Cnotlike extends @cnotlike, TokenKind { + override int getValue() { result = 83 } + + override string getDescription() { result = "The case sensitive notlike operator '-cnotlike'." } + + override string toString() { result = "Cnotlike" } +} + +class Cnotmatch extends @cnotmatch, TokenKind { + override int getValue() { result = 85 } + + override string getDescription() { + result = "The case sensitive not match operator '-cnotmatch'." + } + + override string toString() { result = "Cnotmatch" } +} + +class Colon extends @colon, TokenKind { + override int getValue() { result = 99 } + + override string getDescription() { + result = + "The PS class base class and implemented interfaces operator ':'. Also used in base class ctor calls." + } + + override string toString() { result = "Colon" } +} + +class ColonColon extends @colonColon, TokenKind { + override int getValue() { result = 34 } + + override string getDescription() { result = "The static member access operator '::'." } + + override string toString() { result = "ColonColon" } +} + +class Comma extends @comma, TokenKind { + override int getValue() { result = 30 } + + override string getDescription() { result = "The unary or binary array operator ','." } + + override string toString() { result = "Comma" } +} + +class CommandToken extends @command_token, TokenKind { + override int getValue() { result = 166 } + + override string getDescription() { result = "The 'command' keyword" } + + override string toString() { result = "Command" } +} + +class Comment extends @comment, TokenKind { + override int getValue() { result = 10 } + + override string getDescription() { result = "A single line comment, or a delimited comment." } + + override string toString() { result = "Comment" } +} + +class Configuration extends @configuration, TokenKind { + override int getValue() { result = 155 } + + override string getDescription() { result = "The 'configuration' keyword" } + + override string toString() { result = "Configuration" } +} + +class Continue extends @continue, TokenKind { + override int getValue() { result = 123 } + + override string getDescription() { result = "The 'continue' keyword." } + + override string toString() { result = "Continue" } +} + +class Creplace extends @creplace, TokenKind { + override int getValue() { result = 86 } + + override string getDescription() { result = "The case sensitive replace operator '-creplace'." } + + override string toString() { result = "Creplace" } +} + +class Csplit extends @csplit, TokenKind { + override int getValue() { result = 91 } + + override string getDescription() { result = "The case sensitive split operator '-csplit'." } + + override string toString() { result = "Csplit" } +} + +class Data extends @data, TokenKind { + override int getValue() { result = 124 } + + override string getDescription() { result = "The 'data' keyword." } + + override string toString() { result = "Data" } +} + +class Default extends @default, TokenKind { + override int getValue() { result = 169 } + + override string getDescription() { result = "The 'default' keyword" } + + override string toString() { result = "Default" } +} + +class Define extends @define, TokenKind { + override int getValue() { result = 125 } + + override string getDescription() { result = "The (unimplemented) 'define' keyword." } + + override string toString() { result = "Define" } +} + +class Divide extends @divide, TokenKind { + override int getValue() { result = 38 } + + override string getDescription() { result = "The division operator '/'." } + + override string toString() { result = "Divide" } +} + +class DivideEquals extends @divideEquals, TokenKind { + override int getValue() { result = 46 } + + override string getDescription() { result = "The division assignment operator '/='." } + + override string toString() { result = "DivideEquals" } +} + +class Do extends @do, TokenKind { + override int getValue() { result = 126 } + + override string getDescription() { result = "The 'do' keyword." } + + override string toString() { result = "Do" } +} + +class DollarParen extends @dollarParen, TokenKind { + override int getValue() { result = 24 } + + override string getDescription() { result = "The opening token of a sub-expression '$('." } + + override string toString() { result = "DollarParen" } +} + +class Dot extends @dot, TokenKind { + override int getValue() { result = 35 } + + override string getDescription() { + result = "The instance member access or dot source invocation operator '.'." + } + + override string toString() { result = "Dot" } +} + +class DotDot extends @dotDot, TokenKind { + override int getValue() { result = 33 } + + override string getDescription() { result = "The range operator '..'." } + + override string toString() { result = "DotDot" } +} + +class DynamicKeyword extends @dynamicKeyword, TokenKind { + override int getValue() { result = 156 } + + override string getDescription() { result = "The token kind for dynamic keywords" } + + override string toString() { result = "DynamicKeyword" } +} + +class Dynamicparam extends @dynamicparam, TokenKind { + override int getValue() { result = 127 } + + override string getDescription() { result = "The 'dynamicparam' keyword." } + + override string toString() { result = "Dynamicparam" } +} + +class Else extends @else, TokenKind { + override int getValue() { result = 128 } + + override string getDescription() { result = "The 'else' keyword." } + + override string toString() { result = "Else" } +} + +class ElseIf extends @elseIf, TokenKind { + override int getValue() { result = 129 } + + override string getDescription() { result = "The 'elseif' keyword." } + + override string toString() { result = "ElseIf" } +} + +class End extends @end, TokenKind { + override int getValue() { result = 130 } + + override string getDescription() { result = "The 'end' keyword." } + + override string toString() { result = "End" } +} + +class EndOfInput extends @endOfInput, TokenKind { + override int getValue() { result = 11 } + + override string getDescription() { result = "Marks the end of the input script or file." } + + override string toString() { result = "EndOfInput" } +} + +class Enum extends @enum, TokenKind { + override int getValue() { result = 161 } + + override string getDescription() { result = "The 'enum' keyword" } + + override string toString() { result = "Enum" } +} + +class Equals extends @equals, TokenKind { + override int getValue() { result = 42 } + + override string getDescription() { result = "The assignment operator '='." } + + override string toString() { result = "Equals" } +} + +class Exclaim extends @exclaim, TokenKind { + override int getValue() { result = 36 } + + override string getDescription() { result = "The logical not operator '!'." } + + override string toString() { result = "Exclaim" } +} + +class Exit extends @exit, TokenKind { + override int getValue() { result = 131 } + + override string getDescription() { result = "The 'exit' keyword." } + + override string toString() { result = "Exit" } +} + +class Filter extends @filter, TokenKind { + override int getValue() { result = 132 } + + override string getDescription() { result = "The 'filter' keyword." } + + override string toString() { result = "Filter" } +} + +class Finally extends @finally, TokenKind { + override int getValue() { result = 133 } + + override string getDescription() { result = "The 'finally' keyword." } + + override string toString() { result = "Finally" } +} + +class For extends @for, TokenKind { + override int getValue() { result = 134 } + + override string getDescription() { result = "The 'for' keyword." } + + override string toString() { result = "For" } +} + +class Foreach extends @foreach, TokenKind { + override int getValue() { result = 135 } + + override string getDescription() { result = "The 'foreach' keyword." } + + override string toString() { result = "Foreach" } +} + +class Format extends @format, TokenKind { + override int getValue() { result = 50 } + + override string getDescription() { result = "The string format operator '-f'." } + + override string toString() { result = "Format" } +} + +class From extends @from, TokenKind { + override int getValue() { result = 136 } + + override string getDescription() { result = "The (unimplemented) 'from' keyword." } + + override string toString() { result = "From" } +} + +class Function extends @function, TokenKind { + override int getValue() { result = 137 } + + override string getDescription() { result = "The 'function' keyword." } + + override string toString() { result = "Function" } +} + +class Generic extends @generic, TokenKind { + override int getValue() { result = 7 } + + override string getDescription() { + result = + "A token that is only valid as a command name, command argument, function name, or configuration name. It may contain characters not allowed in identifiers. Tokens with this kind are always instances of StringLiteralToken or StringExpandableToken if the token contains variable references or subexpressions." + } + + override string toString() { result = "Generic" } +} + +class HereStringExpandable extends @hereStringExpandable, TokenKind { + override int getValue() { result = 15 } + + override string getDescription() { + result = + "A double quoted here string literal. Tokens with this kind are always instances of StringExpandableToken. even if there are no nested tokens to expand." + } + + override string toString() { result = "HereStringExpandable" } +} + +class HereStringLiteral extends @hereStringLiteral, TokenKind { + override int getValue() { result = 14 } + + override string getDescription() { + result = + "A single quoted here string literal. Tokens with this kind are always instances of StringLiteralToken." + } + + override string toString() { result = "HereStringLiteral" } +} + +class Hidden extends @hidden, TokenKind { + override int getValue() { result = 167 } + + override string getDescription() { result = "The 'hidden' keyword" } + + override string toString() { result = "Hidden" } +} + +class Icontains extends @icontains, TokenKind { + override int getValue() { result = 71 } + + override string getDescription() { + result = "The case insensitive contains operator '-icontains' or '-contains'." + } + + override string toString() { result = "Icontains" } +} + +class Identifier extends @identifier, TokenKind { + override int getValue() { result = 6 } + + override string getDescription() { + result = + "A simple identifier, always begins with a letter or '', and is followed by letters, numbers, or ''." + } + + override string toString() { result = "Identifier" } +} + +class Ieq extends @ieq, TokenKind { + override int getValue() { result = 60 } + + override string getDescription() { + result = "The case insensitive equal operator '-ieq' or '-eq'." + } + + override string toString() { result = "Ieq" } +} + +class If extends @if, TokenKind { + override int getValue() { result = 138 } + + override string getDescription() { result = "The 'if' keyword." } + + override string toString() { result = "If" } +} + +class Ige extends @ige, TokenKind { + override int getValue() { result = 62 } + + override string getDescription() { + result = "The case insensitive greater than or equal operator '-ige' or '-ge'." + } + + override string toString() { result = "Ige" } +} + +class Igt extends @igt, TokenKind { + override int getValue() { result = 63 } + + override string getDescription() { + result = "The case insensitive greater than operator '-igt' or '-gt'." + } + + override string toString() { result = "Igt" } +} + +class Iin extends @iin, TokenKind { + override int getValue() { result = 73 } + + override string getDescription() { result = "The case insensitive in operator '-iin' or '-in'." } + + override string toString() { result = "Iin" } +} + +class Ile extends @ile, TokenKind { + override int getValue() { result = 65 } + + override string getDescription() { + result = "The case insensitive less than or equal operator '-ile' or '-le'." + } + + override string toString() { result = "Ile" } +} + +class Ilike extends @ilike, TokenKind { + override int getValue() { result = 66 } + + override string getDescription() { + result = "The case insensitive like operator '-ilike' or '-like'." + } + + override string toString() { result = "Ilike" } +} + +class Ilt extends @ilt, TokenKind { + override int getValue() { result = 64 } + + override string getDescription() { + result = "The case insensitive less than operator '-ilt' or '-lt'." + } + + override string toString() { result = "Ilt" } +} + +class Imatch extends @imatch, TokenKind { + override int getValue() { result = 68 } + + override string getDescription() { + result = "The case insensitive match operator '-imatch' or '-match'." + } + + override string toString() { result = "Imatch" } +} + +class In extends @in, TokenKind { + override int getValue() { result = 139 } + + override string getDescription() { result = "The 'in' keyword." } + + override string toString() { result = "In" } +} + +class Ine extends @ine, TokenKind { + override int getValue() { result = 61 } + + override string getDescription() { + result = "The case insensitive not equal operator '-ine' or '-ne'." + } + + override string toString() { result = "Ine" } +} + +class InlineScript extends @inlineScript, TokenKind { + override int getValue() { result = 154 } + + override string getDescription() { result = "The 'InlineScript' keyword" } + + override string toString() { result = "InlineScript" } +} + +class Inotcontains extends @inotcontains, TokenKind { + override int getValue() { result = 72 } + + override string getDescription() { + result = "The case insensitive notcontains operator '-inotcontains' or '-notcontains'." + } + + override string toString() { result = "Inotcontains" } +} + +class Inotin extends @inotin, TokenKind { + override int getValue() { result = 74 } + + override string getDescription() { + result = "The case insensitive notin operator '-inotin' or '-notin'" + } + + override string toString() { result = "Inotin" } +} + +class Inotlike extends @inotlike, TokenKind { + override int getValue() { result = 67 } + + override string getDescription() { + result = "The case insensitive not like operator '-inotlike' or '-notlike'." + } + + override string toString() { result = "Inotlike" } +} + +class Inotmatch extends @inotmatch, TokenKind { + override int getValue() { result = 69 } + + override string getDescription() { + result = "The case insensitive not match operator '-inotmatch' or '-notmatch'." + } + + override string toString() { result = "Inotmatch" } +} + +class Interface extends @interface, TokenKind { + override int getValue() { result = 160 } + + override string getDescription() { result = "The 'interface' keyword" } + + override string toString() { result = "Interface" } +} + +class Ireplace extends @ireplace, TokenKind { + override int getValue() { result = 70 } + + override string getDescription() { + result = "The case insensitive replace operator '-ireplace' or '-replace'." + } + + override string toString() { result = "Ireplace" } +} + +class Is extends @is, TokenKind { + override int getValue() { result = 92 } + + override string getDescription() { result = "The type test operator '-is'." } + + override string toString() { result = "Is" } +} + +class IsNot extends @isNot, TokenKind { + override int getValue() { result = 93 } + + override string getDescription() { result = "The type test operator '-isnot'." } + + override string toString() { result = "IsNot" } +} + +class Isplit extends @isplit, TokenKind { + override int getValue() { result = 75 } + + override string getDescription() { + result = "The case insensitive split operator '-isplit' or '-split'." + } + + override string toString() { result = "Isplit" } +} + +class Join extends @join, TokenKind { + override int getValue() { result = 59 } + + override string getDescription() { result = "The join operator '-join'." } + + override string toString() { result = "Join" } +} + +class Label extends @label, TokenKind { + override int getValue() { result = 5 } + + override string getDescription() { + result = + "A label token - always begins with ':', followed by the label name. Tokens with this kind are always instances of LabelToken." + } + + override string toString() { result = "Label" } +} + +class LBracket extends @lBracket, TokenKind { + override int getValue() { result = 20 } + + override string getDescription() { result = "The opening square brace token '['." } + + override string toString() { result = "LBracket" } +} + +class LCurly extends @lCurly, TokenKind { + override int getValue() { result = 18 } + + override string getDescription() { result = "The opening curly brace token '{'." } + + override string toString() { result = "LCurly" } +} + +class LineContinuation extends @lineContinuation, TokenKind { + override int getValue() { result = 9 } + + override string getDescription() { + result = "A line continuation (backtick followed by newline)." + } + + override string toString() { result = "LineContinuation" } +} + +class LParen extends @lParen, TokenKind { + override int getValue() { result = 16 } + + override string getDescription() { result = "The opening parenthesis token '('." } + + override string toString() { result = "LParen" } +} + +class Minus extends @minus, TokenKind { + override int getValue() { result = 41 } + + override string getDescription() { result = "The substraction operator '-'." } + + override string toString() { result = "Minus" } +} + +class MinusEquals extends @minusEquals, TokenKind { + override int getValue() { result = 44 } + + override string getDescription() { result = "The subtraction assignment operator '-='." } + + override string toString() { result = "MinusEquals" } +} + +class MinusMinus extends @minusMinus, TokenKind { + override int getValue() { result = 31 } + + override string getDescription() { result = "The pre-decrement operator '--'." } + + override string toString() { result = "MinusMinus" } +} + +class Module extends @module, TokenKind { + override int getValue() { result = 163 } + + override string getDescription() { result = "The 'module' keyword" } + + override string toString() { result = "Module" } +} + +class Multiply extends @multiply, TokenKind { + override int getValue() { result = 37 } + + override string getDescription() { result = "The multiplication operator '*'." } + + override string toString() { result = "Multiply" } +} + +class MultiplyEquals extends @multiplyEquals, TokenKind { + override int getValue() { result = 45 } + + override string getDescription() { result = "The multiplication assignment operator '*='." } + + override string toString() { result = "MultiplyEquals" } +} + +class Namespace extends @namespace, TokenKind { + override int getValue() { result = 162 } + + override string getDescription() { result = "The 'namespace' keyword" } + + override string toString() { result = "Namespace" } +} + +class NewLine extends @newLine, TokenKind { + override int getValue() { result = 8 } + + override string getDescription() { result = "A newline (one of '\n', '\r', or '\r\n')." } + + override string toString() { result = "NewLine" } +} + +class Not extends @not, TokenKind { + override int getValue() { result = 51 } + + override string getDescription() { result = "The logical not operator '-not'." } + + override string toString() { result = "Not" } +} + +class Number extends @number, TokenKind { + override int getValue() { result = 4 } + + override string getDescription() { + result = + "Any numerical literal token. Tokens with this kind are always instances of NumberToken." + } + + override string toString() { result = "Number" } +} + +class Or extends @or, TokenKind { + override int getValue() { result = 54 } + + override string getDescription() { result = "The logical or operator '-or'." } + + override string toString() { result = "Or" } +} + +class OrOr extends @orOr, TokenKind { + override int getValue() { result = 27 } + + override string getDescription() { result = "The (unimplemented) operator '||'." } + + override string toString() { result = "OrOr" } +} + +class Parallel extends @parallel, TokenKind { + override int getValue() { result = 152 } + + override string getDescription() { result = "The 'parallel' keyword." } + + override string toString() { result = "Parallel" } +} + +class Param extends @param, TokenKind { + override int getValue() { result = 140 } + + override string getDescription() { result = "The 'param' keyword." } + + override string toString() { result = "Param" } +} + +class ParameterToken extends @parameter_token, TokenKind { + override int getValue() { result = 3 } + + override string getDescription() { + result = + "A parameter to a command, always begins with a dash ('-'), followed by the parameter name. Tokens with this kind are always instances of ParameterToken." + } + + override string toString() { result = "Parameter" } +} + +class Pipe extends @pipe, TokenKind { + override int getValue() { result = 29 } + + override string getDescription() { result = "The pipe operator '|'." } + + override string toString() { result = "Pipe" } +} + +class Plus extends @plus, TokenKind { + override int getValue() { result = 40 } + + override string getDescription() { result = "The addition operator '+'." } + + override string toString() { result = "Plus" } +} + +class PlusEquals extends @plusEquals, TokenKind { + override int getValue() { result = 43 } + + override string getDescription() { result = "The addition assignment operator '+='." } + + override string toString() { result = "PlusEquals" } +} + +class PlusPlus extends @plusPlus, TokenKind { + override int getValue() { result = 32 } + + override string getDescription() { result = "The pre-increment operator '++'." } + + override string toString() { result = "PlusPlus" } +} + +class PostfixMinusMinus extends @postfixMinusMinus, TokenKind { + override int getValue() { result = 96 } + + override string getDescription() { result = "The post-decrement operator '--'." } + + override string toString() { result = "PostfixMinusMinus" } +} + +class PostfixPlusPlus extends @postfixPlusPlus, TokenKind { + override int getValue() { result = 95 } + + override string getDescription() { result = "The post-increment operator '++'." } + + override string toString() { result = "PostfixPlusPlus" } +} + +class Private extends @private, TokenKind { + override int getValue() { result = 158 } + + override string getDescription() { result = "The 'private' keyword" } + + override string toString() { result = "Private" } +} + +class Process extends @process, TokenKind { + override int getValue() { result = 141 } + + override string getDescription() { result = "The 'process' keyword." } + + override string toString() { result = "Process" } +} + +class Public extends @public, TokenKind { + override int getValue() { result = 157 } + + override string getDescription() { result = "The 'public' keyword" } + + override string toString() { result = "Public" } +} + +class QuestionDot extends @questionDot, TokenKind { + override int getValue() { result = 103 } + + override string getDescription() { result = "The null conditional member access operator '?.'." } + + override string toString() { result = "QuestionDot" } +} + +class QuestionLBracket extends @questionLBracket, TokenKind { + override int getValue() { result = 104 } + + override string getDescription() { result = "The null conditional index access operator '?[]'." } + + override string toString() { result = "QuestionLBracket" } +} + +class QuestionMark extends @questionMark, TokenKind { + override int getValue() { result = 100 } + + override string getDescription() { result = "The ternary operator '?'." } + + override string toString() { result = "QuestionMark" } +} + +class QuestionQuestion extends @questionQuestion, TokenKind { + override int getValue() { result = 102 } + + override string getDescription() { result = "The null coalesce operator '??'." } + + override string toString() { result = "QuestionQuestion" } +} + +class QuestionQuestionEquals extends @questionQuestionEquals, TokenKind { + override int getValue() { result = 101 } + + override string getDescription() { result = "The null conditional assignment operator '??='." } + + override string toString() { result = "QuestionQuestionEquals" } +} + +class RBracket extends @rBracket, TokenKind { + override int getValue() { result = 21 } + + override string getDescription() { result = "The closing square brace token ']'." } + + override string toString() { result = "RBracket" } +} + +class RCurly extends @rCurly, TokenKind { + override int getValue() { result = 19 } + + override string getDescription() { result = "The closing curly brace token '}'." } + + override string toString() { result = "RCurly" } +} + +class RedirectInStd extends @redirectInStd, TokenKind { + override int getValue() { result = 49 } + + override string getDescription() { + result = "The (unimplemented) stdin redirection operator '<'." + } + + override string toString() { result = "RedirectInStd" } +} + +class RedirectionToken extends @redirection_token, TokenKind { + override int getValue() { result = 48 } + + override string getDescription() { result = "A redirection operator such as '2>&1' or '>>'." } + + override string toString() { result = "Redirection" } +} + +class Rem extends @rem, TokenKind { + override int getValue() { result = 39 } + + override string getDescription() { result = "The modulo division (remainder) operator '%'." } + + override string toString() { result = "Rem" } +} + +class RemainderEquals extends @remainderEquals, TokenKind { + override int getValue() { result = 47 } + + override string getDescription() { + result = "The modulo division (remainder) assignment operator '%='." + } + + override string toString() { result = "RemainderEquals" } +} + +class Return extends @return, TokenKind { + override int getValue() { result = 142 } + + override string getDescription() { result = "The 'return' keyword." } + + override string toString() { result = "Return" } +} + +class RParen extends @rParen, TokenKind { + override int getValue() { result = 17 } + + override string getDescription() { result = "The closing parenthesis token ')'." } + + override string toString() { result = "RParen" } +} + +class Semi extends @semi, TokenKind { + override int getValue() { result = 25 } + + override string getDescription() { result = "The statement terminator ';'." } + + override string toString() { result = "Semi" } +} + +class Sequence extends @sequence, TokenKind { + override int getValue() { result = 153 } + + override string getDescription() { result = "The 'sequence' keyword." } + + override string toString() { result = "Sequence" } +} + +class Shl extends @shl, TokenKind { + override int getValue() { result = 97 } + + override string getDescription() { result = "The shift left operator." } + + override string toString() { result = "Shl" } +} + +class Shr extends @shr, TokenKind { + override int getValue() { result = 98 } + + override string getDescription() { result = "The shift right operator." } + + override string toString() { result = "Shr" } +} + +class SplattedVariable extends @splattedVariable, TokenKind { + override int getValue() { result = 2 } + + override string getDescription() { + result = + "A splatted variable token, always begins with '@' and followed by the variable name. Tokens with this kind are always instances of VariableToken." + } + + override string toString() { result = "SplattedVariable" } +} + +class Static extends @static, TokenKind { + override int getValue() { result = 159 } + + override string getDescription() { result = "The 'static' keyword" } + + override string toString() { result = "Static" } +} + +class StringExpandable extends @stringExpandable, TokenKind { + override int getValue() { result = 13 } + + override string getDescription() { + result = + "A double quoted string literal. Tokens with this kind are always instances of StringExpandableToken even if there are no nested tokens to expand." + } + + override string toString() { result = "StringExpandable" } +} + +class StringLiteralToken extends @stringLiteral_token, TokenKind { + override int getValue() { result = 12 } + + override string getDescription() { + result = + "A single quoted string literal. Tokens with this kind are always instances of StringLiteralToken." + } + + override string toString() { result = "StringLiteral" } +} + +class Switch extends @switch, TokenKind { + override int getValue() { result = 143 } + + override string getDescription() { result = "The 'switch' keyword." } + + override string toString() { result = "Switch" } +} + +class Throw extends @throw, TokenKind { + override int getValue() { result = 144 } + + override string getDescription() { result = "The 'throw' keyword." } + + override string toString() { result = "Throw" } +} + +class Trap extends @trap, TokenKind { + override int getValue() { result = 145 } + + override string getDescription() { result = "The 'trap' keyword." } + + override string toString() { result = "Trap" } +} + +class Try extends @try, TokenKind { + override int getValue() { result = 146 } + + override string getDescription() { result = "The 'try' keyword." } + + override string toString() { result = "Try" } +} + +class Type extends @type, TokenKind { + override int getValue() { result = 164 } + + override string getDescription() { result = "The 'type' keyword" } + + override string toString() { result = "Type" } +} + +class Unknown extends @unknown, TokenKind { + override int getValue() { result = 0 } + + override string getDescription() { result = "An unknown token, signifies an error condition." } + + override string toString() { result = "Unknown" } +} + +class Until extends @until, TokenKind { + override int getValue() { result = 147 } + + override string getDescription() { result = "The 'until' keyword." } + + override string toString() { result = "Until" } +} + +class Using extends @using, TokenKind { + override int getValue() { result = 148 } + + override string getDescription() { result = "The (unimplemented) 'using' keyword." } + + override string toString() { result = "Using" } +} + +class Var extends @var, TokenKind { + override int getValue() { result = 149 } + + override string getDescription() { result = "The (unimplemented) 'var' keyword." } + + override string toString() { result = "Var" } +} + +class Variable extends @variable, TokenKind { + override int getValue() { result = 1 } + + override string getDescription() { + result = + "A variable token, always begins with '$' and followed by the variable name, possibly enclose in curly braces. Tokens with this kind are always instances of VariableToken." + } + + override string toString() { result = "Variable" } +} + +class While extends @while, TokenKind { + override int getValue() { result = 150 } + + override string getDescription() { result = "The 'while' keyword." } + + override string toString() { result = "While" } +} + +class Workflow extends @workflow, TokenKind { + override int getValue() { result = 151 } + + override string getDescription() { result = "The 'workflow' keyword." } + + override string toString() { result = "Workflow" } +} + +class Xor extends @xor, TokenKind { + override int getValue() { result = 55 } + + override string getDescription() { result = "The logical exclusive or operator '-xor'." } + + override string toString() { result = "Xor" } +} 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/ast/internal/Raw/TryStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/TryStmt.qll new file mode 100644 index 000000000000..149aacbf040b --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/TryStmt.qll @@ -0,0 +1,29 @@ +private import Raw + +class TryStmt extends @try_statement, Stmt { + override SourceLocation getLocation() { try_statement_location(this, result) } + + CatchClause getCatchClause(int i) { try_statement_catch_clause(this, i, result) } + + CatchClause getACatchClause() { result = this.getCatchClause(_) } + + /** ..., if any. */ + StmtBlock getFinally() { try_statement_finally(this, result) } + + 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/ast/internal/Raw/Type.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Type.qll new file mode 100644 index 000000000000..bd386eb461ff --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Type.qll @@ -0,0 +1,32 @@ +private import Raw + +class TypeStmt extends @type_definition, Stmt { + override SourceLocation getLocation() { type_definition_location(this, result) } + + string getName() { type_definition(this, result, _, _, _, _) } + + Member getMember(int i) { type_definition_members(this, i, result) } + + Member getAMember() { result = this.getMember(_) } + + Method getMethod(string name) { + result = this.getAMember() and + result.getName() = name + } + + TypeConstraint getBaseType(int i) { type_definition_base_type(this, i, result) } + + TypeConstraint getABaseType() { result = this.getBaseType(_) } + + 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/ast/internal/Raw/TypeConstraint.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/TypeConstraint.qll new file mode 100644 index 000000000000..c5552aaf1731 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/TypeConstraint.qll @@ -0,0 +1,11 @@ +private import Raw + +class TypeConstraint extends @type_constraint, AttributeBase { + override SourceLocation getLocation() { type_constraint_location(this, result) } + + /** Gets the assembly name. */ + string getName() { type_constraint(this, result, _) } + + /** Gets the full name of this type constraint including namespaces. */ + string getFullName() { type_constraint(this, _, result) } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/TypeExpression.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/TypeExpression.qll new file mode 100644 index 000000000000..50fbc41bbac3 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/TypeExpression.qll @@ -0,0 +1,10 @@ +private import Raw + +class TypeNameExpr extends @type_expression, Expr { + string getName() { type_expression(this, result, _) } + + override SourceLocation getLocation() { type_expression_location(this, result) } + + /** Gets the type referred to by this `TypeNameExpr`. */ + 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/ast/internal/Raw/UsingStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/UsingStmt.qll new file mode 100644 index 000000000000..46614401daa9 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/UsingStmt.qll @@ -0,0 +1,19 @@ +private import Raw + +class UsingStmt extends @using_statement, Stmt { + override SourceLocation getLocation() { using_statement_location(this, result) } + + string getName() { + exists(StringConstExpr const | + using_statement_name(this, const) and // TODO: Change dbscheme + result = const.getValue().getValue() + ) + } + + string getAlias() { + exists(StringConstExpr const | + using_statement_alias(this, const) and // TODO: Change dbscheme + result = const.getValue().getValue() + ) + } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/VariableExpression.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/VariableExpression.qll new file mode 100644 index 000000000000..00bc726699c5 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/VariableExpression.qll @@ -0,0 +1,48 @@ +private import Raw + +class VarAccess extends @variable_expression, Expr { + override SourceLocation getLocation() { variable_expression_location(this, result) } + + string getUserPath() { variable_expression(this, result, _, _, _, _, _, _, _, _, _, _) } + + string getDriveName() { variable_expression(this, _, result, _, _, _, _, _, _, _, _, _) } + + boolean isConstant() { variable_expression(this, _, _, result, _, _, _, _, _, _, _, _) } + + boolean isGlobal() { variable_expression(this, _, _, _, result, _, _, _, _, _, _, _) } + + boolean isLocal() { variable_expression(this, _, _, _, _, result, _, _, _, _, _, _) } + + boolean isPrivate() { variable_expression(this, _, _, _, _, _, result, _, _, _, _, _) } + + boolean isScript() { variable_expression(this, _, _, _, _, _, _, result, _, _, _, _) } + + boolean isUnqualified() { variable_expression(this, _, _, _, _, _, _, _, result, _, _, _) } + + boolean isUnscoped() { variable_expression(this, _, _, _, _, _, _, _, _, result, _, _) } + + boolean isVariable() { variable_expression(this, _, _, _, _, _, _, _, _, _, result, _) } + + boolean isDriveQualified() { variable_expression(this, _, _, _, _, _, _, _, _, _, _, result) } +} + +class ThisAccess extends VarAccess { + ThisAccess() { this.getUserPath() = "this" } +} + +predicate isEnvVariableAccess(VarAccess va, string env) { + va.getUserPath().toLowerCase() = "env:" + env +} + +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/ast/internal/Raw/WhileStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/WhileStmt.qll new file mode 100644 index 000000000000..92ced49b4230 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/WhileStmt.qll @@ -0,0 +1,15 @@ +private import Raw + +class WhileStmt extends @while_statement, LoopStmt { + override SourceLocation getLocation() { while_statement_location(this, result) } + + 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() + } +} From b52c6ea4ba972ab41a1f6c8324e9ba25f4ceb4e4 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 26 Mar 2025 18:05:29 +0000 Subject: [PATCH 05/26] PS: Add control-flow node version of all the user-facing ast classes. --- .../code/powershell/controlflow/CfgNodes.qll | 1295 +++++++++++++---- 1 file changed, 980 insertions(+), 315 deletions(-) diff --git a/powershell/ql/lib/semmle/code/powershell/controlflow/CfgNodes.qll b/powershell/ql/lib/semmle/code/powershell/controlflow/CfgNodes.qll index 8c8efcbb42d0..1b162d11a9a4 100644 --- a/powershell/ql/lib/semmle/code/powershell/controlflow/CfgNodes.qll +++ b/powershell/ql/lib/semmle/code/powershell/controlflow/CfgNodes.qll @@ -127,433 +127,841 @@ 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 InvokeMemberChildMapping e; + override ConvertExprChildMapping e; - override InvokeMemberExpr getExpr() { result = super.getExpr() } + override ConvertExpr getExpr() { result = e } - final override ExprCfgNode getQualifier() { e.hasCfgChild(e.getQualifier(), this, result) } + ExprCfgNode getSubExpr() { e.hasCfgChild(e.getExpr(), this, result) } + } - final override ExprCfgNode getArgument(int i) { e.hasCfgChild(e.getArgument(i), this, result) } + class IndexExprChildMapping extends ExprChildMapping, IndexExpr { + override predicate relevantChild(Ast child) { + child = this.getBase() + or + child = this.getIndex() + } + } - final override ExprCfgNode getPositionalArgument(int i) { result = this.getArgument(i) } + class IndexExprCfgNode extends ExprCfgNode { + override string getAPrimaryQlClass() { result = "IndexExprCfgNode" } - final override ExprCfgNode getNamedArgument(string name) { none() } + override IndexExprChildMapping e; - final override ExprCfgNode getAnArgument() { e.hasCfgChild(e.getAnArgument(), this, result) } + override IndexExpr getExpr() { result = e } - final override string getName() { result = e.getName() } + ExprCfgNode getBase() { e.hasCfgChild(e.getBase(), this, result) } - final override ExprCfgNode getCommand() { none() } + ExprCfgNode getIndex() { e.hasCfgChild(e.getIndex(), this, result) } } - /** A control-flow node that wraps an `ConstructorCall` expression. */ - class ConstructorCallCfgNode extends InvokeMemberCfgNode { - ConstructorCallCfgNode() { super.getExpr() instanceof ConstructorCall } + private class IndexExprWriteAccessChildMapping extends IndexExprChildMapping, IndexExprWriteAccess + { + override predicate relevantChild(Ast child) { this.isExplicitWrite(child) } + } + + class IndexExprWriteAccessCfgNode extends IndexExprCfgNode { + override IndexExprWriteAccessChildMapping e; + + override string getAPrimaryQlClass() { result = "IndexExprWriteAccessCfgNode" } + + override IndexExprWriteAccess getExpr() { result = e } - final override ConstructorCall getExpr() { result = super.getExpr() } + final StmtNodes::AssignStmtCfgNode getAssignStmt() { this.isExplicitWrite(result) } - Type getConstructedType() { result = this.getExpr().getConstructedType() } + 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) { none() } + } + + class IndexExprReadAccessCfgNode extends IndexExprCfgNode { + override IndexExprReadAccessChildMapping e; + + override string getAPrimaryQlClass() { result = "IndexExprAccessCfgNode" } - InvokeMemberCfgNode getInvokeMember() { this = result.getQualifier() } + 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 } + + ExprCfgNode getQualifier() { e.hasCfgChild(e.getQualifier(), this, result) } - override TypeNameChildMapping e; + ExprCfgNode getArgument(int i) { e.hasCfgChild(e.getArgument(i), this, result) } - override TypeNameExpr getExpr() { result = super.getExpr() } + ExprCfgNode getAnArgument() { result = this.getArgument(_) } - Type getType() { result = this.getExpr().getType() } + /** Gets the name that is used to select the callee. */ + string getName() { result = e.getName() } + + /** Gets the i'th positional argument to this call. */ + ExprCfgNode getPositionalArgument(int i) { + e.hasCfgChild(e.getPositionalArgument(i), this, result) + } - string getTypeName() { result = this.getExpr().getName() } + /** 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) + } + + ExprCfgNode getCallee() { e.hasCfgChild(e.getCallee(), this, result) } + + 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 ObjectCreationChildMapping e; + + override ObjectCreation getExpr() { result = e } - override ConditionalChildMapping e; + string getConstructedTypeName() { result = this.getExpr().getConstructedTypeName() } - final override ConditionalExpr getExpr() { result = super.getExpr() } + ExprCfgNode getConstructedTypeExpr() { + e.hasCfgChild(this.getExpr().getConstructedTypeExpr(), this, result) + } + } - final ExprCfgNode getCondition() { e.hasCfgChild(e.getCondition(), this, result) } + class CallOperatorChildMapping extends CallExprChildMapping instanceof CallOperator { + override predicate relevantChild(Ast child) { none() } + } - final ExprCfgNode getBranch(boolean value) { e.hasCfgChild(e.getBranch(value), this, result) } + class CallOperatorCfgNode extends CallExprCfgNode { + override string getAPrimaryQlClass() { result = "CallOperatorCfgNode" } - final ExprCfgNode getABranch() { result = this.getBranch(_) } + override CallOperatorChildMapping e; - final ExprCfgNode getIfTrue() { e.hasCfgChild(e.getIfTrue(), this, result) } + override CallOperator getExpr() { result = e } - final ExprCfgNode getIfFalse() { e.hasCfgChild(e.getIfFalse(), this, result) } + 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 MemberChildMapping e; + override MemberExprChildMapping e; - final override MemberExpr getExpr() { result = super.getExpr() } + override MemberExpr getExpr() { result = e } - final ExprCfgNode getQualifier() { e.hasCfgChild(e.getQualifier(), this, result) } + ExprCfgNode getQualifier() { e.hasCfgChild(e.getQualifier(), this, result) } - final string getMemberName() { result = e.getMemberName() } + ExprCfgNode getMemberExpr() { e.hasCfgChild(e.getMemberExpr(), this, result) } + + 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) { this.isExplicitWrite(child) } + } + + class MemberExprWriteAccessCfgNode extends MemberExprCfgNode { + override MemberExprWriteAccessChildMapping e; - StmtNodes::AssignStmtCfgNode getAssignStmt() { result.getLeftHandSide() = this } + override string getAPrimaryQlClass() { result = "MemberExprWriteAccessCfgNode" } + + 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) { none() } } - 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; - ExprCfgNode getElement(int i) { e.hasCfgChild(e.getElement(i), this, result) } + override TypeNameExpr getExpr() { result = e } - ExprCfgNode getAnElement() { e.hasCfgChild(e.getAnElement(), this, result) } + string getName() { result = e.getName() } + + string getNamespace() { result = e.getNamespace() } + + string getPossiblyQualifiedName() { result = e.getPossiblyQualifiedName() } + + 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 StringLiteralExprCfgNode extends ExprCfgNode { + override string getAPrimaryQlClass() { result = "StringLiteralExprCfgNode" } + + override StringLiteralExprChildMapping e; + + override StringConstExpr getExpr() { result = e } + + string getValueString() { result = e.getValueString() } } - class ArrayExprChildMapping extends ExprChildMapping, ArrayExpr { - override predicate relevantChild(Ast n) { n = this.getStmtBlock() or n = this.getAnElement() } + class ExpandableStringExprChildMapping extends ExprChildMapping, ExpandableStringExpr { + override predicate relevantChild(Ast child) { child = this.getAnExpr() } } - class ArrayExprCfgNode extends ExprCfgNode { - override string getAPrimaryQlClass() { result = "ArrayExprCfgNode" } + class ExpandableStringExprCfgNode extends ExprCfgNode { + override string getAPrimaryQlClass() { result = "ExpandableStringExprCfgNode" } - override ArrayExprChildMapping e; + override ExpandableStringExprChildMapping e; - ExprCfgNode getElement(int i) { e.hasCfgChild(e.getElement(i), this, result) } + override ExpandableStringExpr getExpr() { result = e } - ExprCfgNode getAnElement() { result = this.getElement(_) } + 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() } } - class HashTableCfgNode extends ExprCfgNode { - override string getAPrimaryQlClass() { result = "HashMapCfgNode" } + private class VarWriteAccessChildMapping extends ExprChildMapping, VarWriteAccess { + override predicate relevantChild(Ast child) { this.isExplicitWrite(child) } + } - override HashTableChildMapping e; + class VarWriteAccessCfgNode extends VarAccessCfgNode { + override VarWriteAccessChildMapping e; + + override string getAPrimaryQlClass() { result = "VarWriteAccessCfgNode" } + + 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() } + } - StmtCfgNode getAnElement() { result = this.getElement(_) } + 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; + + override HashTableExpr getExpr() { result = e } + + ExprCfgNode getKey(int i) { e.hasCfgChild(e.getKey(i), this, result) } + + ExprCfgNode getAnKey() { result = this.getKey(_) } - 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 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 } + + ExprCfgNode getLeft() { e.hasCfgChild(e.getLeft(), this, result) } + + ExprCfgNode getRight() { e.hasCfgChild(e.getRight(), this, result) } + } - final StmtCfgNode getBase() { e.hasCfgChild(e.getBase(), this, result) } + class ConditionalExprChildMapping extends ExprChildMapping, ConditionalExpr { + override predicate relevantChild(Ast child) { + child = this.getCondition() + or + child = this.getIfTrue() + or + child = this.getIfFalse() + } } - class UnaryExprChildMapping extends ExprChildMapping, UnaryExpr { - override predicate relevantChild(Ast n) { n = this.getOperand() } + class ConditionalExprCfgNode extends ExprCfgNode { + override string getAPrimaryQlClass() { result = "ConditionalExprCfgNode" } + + override ConditionalExprChildMapping e; + + override ConditionalExpr getExpr() { result = e } + + ExprCfgNode getCondition() { e.hasCfgChild(e.getCondition(), this, result) } + + ExprCfgNode getIfTrue() { e.hasCfgChild(e.getIfTrue(), 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 UnaryCfgNode extends ExprCfgNode { - override string getAPrimaryQlClass() { result = "UnaryExprCfgNode" } + class ExpandableSubExprChildMapping extends ExprChildMapping, ExpandableSubExpr { + override predicate relevantChild(Ast child) { child = this.getExpr() } + } - override UnaryExprChildMapping e; + class ExpandableSubExprCfgNode extends ExprCfgNode { + override string getAPrimaryQlClass() { result = "ExpandableSubExprCfgNode" } - override UnaryExpr getExpr() { result = e } + override ExpandableSubExprChildMapping e; - final ExprCfgNode getOperand() { e.hasCfgChild(e.getOperand(), this, result) } + override ExpandableSubExpr getExpr() { result = e } + + ExprCfgNode getSubExpr() { e.hasCfgChild(e.getExpr(), this, result) } } - class BinaryExprChildMapping extends ExprChildMapping, BinaryExpr { - override predicate relevantChild(Ast n) { n = this.getLeft() or n = this.getRight() } + class UsingExprChildMapping extends ExprChildMapping, UsingExpr { + override predicate relevantChild(Ast child) { child = this.getExpr() } } - class BinaryCfgNode extends ExprCfgNode { - override string getAPrimaryQlClass() { result = "BinaryExprCfgNode" } + class UsingExprCfgNode extends ExprCfgNode { + override string getAPrimaryQlClass() { result = "UsingExprCfgNode" } - override BinaryExprChildMapping e; + override UsingExprChildMapping e; - override BinaryExpr getExpr() { result = 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" } + + override NullLiteralChildMapping e; + + override NullLiteral getExpr() { result = e } + } + + class ArgumentCfgNode extends ExprCfgNode { + override Argument e; + + CallExprCfgNode getCall() { result.getAnArgument() = this } - final ExprCfgNode getLeft() { e.hasCfgChild(e.getLeft(), this, result) } + string getName() { result = e.getName() } - final ExprCfgNode getRight() { e.hasCfgChild(e.getRight(), this, result) } + int getPosition() { result = e.getPosition() } } - class OperationChildMapping extends ExprChildMapping instanceof Operation { - override predicate relevantChild(Ast n) { n = super.getAnOperand() } + 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 +971,423 @@ 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) } } +} - class ExpandableStringChildMappinig extends ExprChildMapping, ExpandableStringExpr { - override predicate relevantChild(Ast n) { n = this.getAnExpr() } +module StmtNodes { + private class AssignStmtChildMapping extends NonExprChildMapping, AssignStmt { + override predicate relevantChild(Ast child) { + child = this.getLeftHandSide() + or + child = this.getRightHandSide() + } } - class ExpandableStringCfgNode extends ExprCfgNode { - override string getAPrimaryQlClass() { result = "ExpandableStringCfgNode" } + class AssignStmtCfgNode extends StmtCfgNode { + override string getAPrimaryQlClass() { result = "AssignStmtCfgNode" } + + override AssignStmtChildMapping s; - override ExpandableStringChildMappinig e; + override AssignStmt getStmt() { result = s } - override ExpandableStringExpr getExpr() { result = e } + ExprCfgNode getLeftHandSide() { s.hasCfgChild(s.getLeftHandSide(), this, result) } - ExprCfgNode getExpr(int i) { e.hasCfgChild(e.getExpr(i), this, result) } + ExprCfgNode getRightHandSide() { s.hasCfgChild(s.getRightHandSide(), this, result) } + } - ExprCfgNode getAnExpr() { result = this.getExpr(_) } + class BreakStmtChildMapping extends NonExprChildMapping, BreakStmt { + 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 BreakStmtCfgNode extends StmtCfgNode { + override string getAPrimaryQlClass() { result = "BreakStmtCfgNode" } + + override BreakStmtChildMapping s; + + override BreakStmt getStmt() { result = s } } - /** A control-flow node that wraps a `Cmd` AST expression. */ - class CmdCfgNode extends CmdBaseCfgNode, AbstractCallCfgNode { - override string getAPrimaryQlClass() { result = "CmdCfgNode" } + class ContinueStmtChildMapping extends NonExprChildMapping, ContinueStmt { + override predicate relevantChild(Ast child) { none() } + } - override CmdChildMapping s; + class ContinueStmtCfgNode extends StmtCfgNode { + override string getAPrimaryQlClass() { result = "ContinueStmtCfgNode" } - override Cmd getStmt() { result = super.getStmt() } + override ContinueStmtChildMapping s; - override ExprCfgNode getArgument(int i) { s.hasCfgChild(s.getArgument(i), this, result) } + override ContinueStmt getStmt() { result = s } + } - override ExprCfgNode getPositionalArgument(int i) { - s.hasCfgChild(s.getPositionalArgument(i), this, result) + 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 ExprCfgNode getNamedArgument(string name) { - s.hasCfgChild(s.getNamedArgument(name), this, result) + 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) } + } + + class DoUntilStmtChildMapping extends NonExprChildMapping, DoUntilStmt { + override predicate relevantChild(Ast child) { + child = this.getCondition() or child = this.getBody() } + } - override ExprCfgNode getAnArgument() { s.hasCfgChild(s.getAnArgument(), this, result) } + class DoUntilStmtCfgNode extends StmtCfgNode { + override string getAPrimaryQlClass() { result = "DoUntilStmtCfgNode" } - final override ExprCfgNode getCommand() { s.hasCfgChild(s.getCommand(), this, result) } + override DoUntilStmtChildMapping s; - final override string getName() { result = s.getCommandName() } + override DoUntilStmt getStmt() { result = s } - /** Holds if the command is qualified. */ - predicate isQualified() { s.isQualified() } + ExprCfgNode getCondition() { s.hasCfgChild(s.getCondition(), this, result) } - /** Gets the namespace qualifier of this command, if any. */ - string getNamespaceQualifier() { result = s.getNamespaceQualifier() } + StmtCfgNode getBody() { s.hasCfgChild(s.getBody(), this, result) } } - /** A control-flow node that wraps a call to operator `&` */ - class CallOperatorCfgNode extends CmdCfgNode { - CallOperatorCfgNode() { this.getStmt() instanceof CallOperator } + 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) } } - private class AssignStmtChildMapping extends PipelineBaseChildMapping, AssignStmt { - override predicate relevantChild(Ast n) { - n = this.getLeftHandSide() or n = this.getRightHandSide() + class ErrorStmtChildMapping extends NonExprChildMapping, ErrorStmt { + override predicate relevantChild(Ast child) { none() } + } + + 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() } } - /** A control-flow node that wraps an `AssignStmt` AST expression. */ - class AssignStmtCfgNode extends PipelineBaseCfgNode { - override string getAPrimaryQlClass() { result = "AssignCfgNode" } + class DynamicStmtCfgNode extends StmtCfgNode { + override string getAPrimaryQlClass() { result = "DynamicStmtCfgNode" } - override AssignStmtChildMapping s; + override DynamicStmtChildMapping s; - override AssignStmt getStmt() { result = super.getStmt() } + override DynamicStmt getStmt() { result = s } - /** Gets the LHS of this assignment. */ - final ExprCfgNode getLeftHandSide() { s.hasCfgChild(s.getLeftHandSide(), this, result) } + ExprCfgNode getName() { s.hasCfgChild(s.getName(), this, result) } - /** Gets the RHS of this assignment. */ - final StmtCfgNode getRightHandSide() { s.hasCfgChild(s.getRightHandSide(), this, result) } + ExprCfgNode getScriptBlock() { s.hasCfgChild(s.getScriptBlock(), this, result) } + + ExprCfgNode getHashTableExpr() { s.hasCfgChild(s.getHashTableExpr(), this, result) } } - class CmdExprChildMapping extends CmdBaseChildMapping, CmdExpr { - override predicate relevantChild(Ast n) { n = this.getExpr() } + class ForEachStmtChildMapping extends NonExprChildMapping, ForEachStmt { + override predicate relevantChild(Ast child) { + child = this.getVarAccess() or child = this.getIterableExpr() or child = this.getBody() + } } - /** A control-flow node that wraps a `CmdExpr` expression. */ - class CmdExprCfgNode extends CmdBaseCfgNode { - override string getAPrimaryQlClass() { result = "CmdExprCfgNode" } + class ForEachStmtCfgNode extends StmtCfgNode { + override string getAPrimaryQlClass() { result = "ForEachStmtCfgNode" } + + override ForEachStmtChildMapping s; + + override ForEachStmt getStmt() { result = s } - override CmdExprChildMapping s; + ExprCfgNode getVarAccess() { s.hasCfgChild(s.getVarAccess(), this, result) } - override CmdExpr getStmt() { result = super.getStmt() } + ExprCfgNode getIterableExpr() { s.hasCfgChild(s.getIterableExpr(), this, result) } - final ExprCfgNode getExpr() { s.hasCfgChild(s.getExpr(), this, result) } + StmtCfgNode getBody() { s.hasCfgChild(s.getBody(), this, result) } } - class PipelineBaseChildMapping extends NonExprChildMapping, PipelineBase { - override predicate relevantChild(Ast n) { none() } + 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() + } } - class PipelineBaseCfgNode extends StmtCfgNode { - override string getAPrimaryQlClass() { result = "PipelineBaseCfgNode" } + class ForStmtCfgNode extends StmtCfgNode { + override string getAPrimaryQlClass() { result = "ForStmtCfgNode" } + + override ForStmtChildMapping s; + + override ForStmt getStmt() { result = s } - override PipelineBaseChildMapping s; + AstCfgNode getInitializer() { s.hasCfgChild(s.getInitializer(), this, result) } - override PipelineBase getStmt() { result = super.getStmt() } + ExprCfgNode getCondition() { s.hasCfgChild(s.getCondition(), this, result) } + + AstCfgNode getIterator() { s.hasCfgChild(s.getIterator(), this, result) } + + StmtCfgNode getBody() { s.hasCfgChild(s.getBody(), this, result) } } - class ChainableChildMapping extends PipelineBaseChildMapping, Chainable { - override predicate relevantChild(Ast n) { none() } + class GotoStmtChildMapping extends NonExprChildMapping, GotoStmt { + override predicate relevantChild(Ast child) { child = this.getLabel() } } - class ChainableCfgNode extends PipelineBaseCfgNode { - override string getAPrimaryQlClass() { result = "ChainableCfgNode" } + class GotoStmtCfgNode extends StmtCfgNode { + override string getAPrimaryQlClass() { result = "GotoStmtCfgNode" } + + override GotoStmtChildMapping s; - override ChainableChildMapping s; + override GotoStmt getStmt() { result = s } - override Chainable getStmt() { result = super.getStmt() } + ExprCfgNode getLabel() { s.hasCfgChild(s.getLabel(), this, result) } } - class PipelineChainChildMapping extends ChainableChildMapping, PipelineChain { - override predicate relevantChild(Ast n) { n = this.getLeft() or n = this.getRight() } + class ReturnStmtChildMapping extends NonExprChildMapping, ReturnStmt { + override predicate relevantChild(Ast child) { child = this.getPipeline() } } - class PipelineChainCfgNode extends ChainableCfgNode { - override string getAPrimaryQlClass() { result = "PipelineChainCfgNode" } + class ReturnStmtCfgNode extends StmtCfgNode { + override string getAPrimaryQlClass() { result = "ReturnStmtCfgNode" } + + override ReturnStmtChildMapping s; + + override ReturnStmt getStmt() { result = s } - override PipelineChainChildMapping s; + ExprCfgNode getPipeline() { s.hasCfgChild(s.getPipeline(), this, result) } + } + + class StmtBlockChildMapping extends NonExprChildMapping, StmtBlock { + override predicate relevantChild(Ast child) { child = this.getAStmt() } + } + + class StmtBlockCfgNode extends StmtCfgNode { + override string getAPrimaryQlClass() { result = "StmtBlockCfgNode" } - override PipelineChain getStmt() { result = super.getStmt() } + override StmtBlockChildMapping s; - final ChainableCfgNode getLeft() { s.hasCfgChild(s.getLeft(), this, result) } + override StmtBlock getStmt() { result = s } + + StmtCfgNode getStmt(int i) { s.hasCfgChild(s.getStmt(i), this, result) } + + StmtCfgNode getAStmt() { result = this.getStmt(_) } + } - final ChainableCfgNode getRight() { s.hasCfgChild(s.getRight(), this, result) } + 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 CmdBaseChildMapping extends ChainableChildMapping, CmdBase { } + class SwitchStmtCfgNode extends StmtCfgNode { + override string getAPrimaryQlClass() { result = "SwitchStmtCfgNode" } + + override SwitchStmtChildMapping s; + + override SwitchStmt getStmt() { result = s } + + ExprCfgNode getCondition() { s.hasCfgChild(s.getCondition(), this, result) } - class CmdBaseCfgNode extends ChainableCfgNode { - override string getAPrimaryQlClass() { result = "CmdBaseCfgNode" } + StmtCfgNode getDefault() { s.hasCfgChild(s.getDefault(), this, result) } - override CmdBaseChildMapping s; + StmtCfgNode getCase(int i) { s.hasCfgChild(s.getCase(i), this, result) } - override CmdBase getStmt() { result = super.getStmt() } + StmtCfgNode getACase() { result = this.getCase(_) } + + ExprCfgNode getPattern(int i) { s.hasCfgChild(s.getPattern(i), this, result) } + + ExprCfgNode getAPattern() { result = this.getPattern(_) } } - class PipelineChildMapping extends ChainableChildMapping, Pipeline { - override predicate relevantChild(Ast n) { n = this.getAComponent() } + class ThrowStmtChildMapping extends NonExprChildMapping, ThrowStmt { + override predicate relevantChild(Ast child) { child = this.getPipeline() } } - class PipelineCfgNode extends ChainableCfgNode { - override string getAPrimaryQlClass() { result = "PipelineCfgNode" } + class ThrowStmtCfgNode extends StmtCfgNode { + override string getAPrimaryQlClass() { result = "ThrowStmtCfgNode" } + + override ThrowStmtChildMapping s; + + override ThrowStmt getStmt() { result = s } + + ExprCfgNode getPipeline() { s.hasCfgChild(s.getPipeline(), this, result) } + } + + class TrapStmtChildMapping extends NonExprChildMapping, TrapStmt { + override predicate relevantChild(Ast child) { child = this.getBody() } + } + + 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) } } } From 11c84ccaf4d82e29d42f7ae83bbd7da91d0084cb Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 26 Mar 2025 18:08:32 +0000 Subject: [PATCH 06/26] PS: Add the IPA type representing the AST. --- .../code/powershell/ast/internal/TAst.qll | 242 ++++++++++++++++++ 1 file changed, 242 insertions(+) create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/TAst.qll 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..66fd473bff78 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/TAst.qll @@ -0,0 +1,242 @@ +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)) +} + +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 + 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 + TWhileStmt or TFunctionDefinitionStmt or TExpandableSubExpr or TMethod or TTypeNameExpr or + TAttributedExpr or TUsingExpr or TThisExprReal or TParenExpr ; + + class TAstSynth = + TExprStmtSynth or TFunctionSynth or TBoolLiteral or TNullLiteral or + TEnvVariable or TTypeSynth or TAutomaticVariable; + + 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 + 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 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 = 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 + } + + 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 = TEnvVariable(parent, i) or + result = TTypeSynth(parent, i) or + result = TAutomaticVariable(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 From 0dd756d72d0fdf610e28d92956b98a1d57df46dd Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 26 Mar 2025 18:09:10 +0000 Subject: [PATCH 07/26] PS: Add support for variables. --- .../code/powershell/ast/internal/TAst.qll | 98 +++++++++++++++++-- 1 file changed, 92 insertions(+), 6 deletions(-) diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/TAst.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/TAst.qll index 66fd473bff78..6bc4bf7a8bdb 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/TAst.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/TAst.qll @@ -10,6 +10,70 @@ 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) { @@ -76,6 +140,22 @@ private module Cached { 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 @@ -95,18 +175,18 @@ private module Cached { 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 + 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 ; + TAttributedExpr or TUsingExpr or TThisExprReal or TParenExpr or TVariableReal; class TAstSynth = - TExprStmtSynth or TFunctionSynth or TBoolLiteral or TNullLiteral or - TEnvVariable or TTypeSynth or TAutomaticVariable; + 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 + 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; @@ -138,6 +218,8 @@ private module Cached { 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; @@ -195,6 +277,7 @@ private module Cached { 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 @@ -202,6 +285,7 @@ private module Cached { n = TMethod(result) or n = TAttributedExpr(result) or n = TUsingExpr(result) or + n = TVariableReal(_, _, result) } cached @@ -224,9 +308,11 @@ private module Cached { 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) + result = TAutomaticVariable(parent, i) or + result = TVariableSynth(parent, i) } cached From 31f14ba99a92be25abbdc5df1c3d63bcf55a1dcb Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 26 Mar 2025 18:10:26 +0000 Subject: [PATCH 08/26] PS: Add synthesis framework for cleaning up the AST. --- .../powershell/ast/internal/Synthesis.qll | 115 ++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 powershell/ql/lib/semmle/code/powershell/ast/internal/Synthesis.qll 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..bd738a50dcaf --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Synthesis.qll @@ -0,0 +1,115 @@ +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) } From faa94735bf1fe5b24dd81bd3b55d9c32c64f2808 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 26 Mar 2025 18:11:07 +0000 Subject: [PATCH 09/26] PS: Add an implicit this parameter to all methods. --- .../powershell/ast/internal/Synthesis.qll | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Synthesis.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Synthesis.qll index bd738a50dcaf..c3545cd12737 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/Synthesis.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Synthesis.qll @@ -113,3 +113,28 @@ Ast getResultAst(Raw::Ast 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() + ) + } + } +} From 5bc0a263ec6f6eca390016b092b98b418b3b0b70 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 26 Mar 2025 18:11:37 +0000 Subject: [PATCH 10/26] PS: A call to set-variable is an explicit assignment. --- .../code/powershell/ast/internal/Synthesis.qll | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Synthesis.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Synthesis.qll index c3545cd12737..f7b7e99e1907 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/Synthesis.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Synthesis.qll @@ -138,3 +138,16 @@ private module ThisSynthesis { } } } + +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() + ) + } + } +} From 0b4a7f9436a51ef44497b0838c622a4da51dc414 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 26 Mar 2025 18:12:02 +0000 Subject: [PATCH 11/26] PS: Synthesize a simpler notion of parameters. --- .../powershell/ast/internal/Synthesis.qll | 121 ++++++++++++++++++ 1 file changed, 121 insertions(+) diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Synthesis.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Synthesis.qll index f7b7e99e1907..6a29dc5eee60 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/Synthesis.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Synthesis.qll @@ -151,3 +151,124 @@ private module SetVariableAssignment { } } } + +/** + * 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() + ) + } + } +} From 17661342f81f553a2007c0d63bd08ff51781df13 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 26 Mar 2025 18:12:43 +0000 Subject: [PATCH 12/26] PS: expr-to-stmt conversions. --- .../powershell/ast/internal/Synthesis.qll | 101 ++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Synthesis.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Synthesis.qll index 6a29dc5eee60..b18a1e5dbf7f 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/Synthesis.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Synthesis.qll @@ -272,3 +272,104 @@ private module ParameterSynth { } } } + +/** + * 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() + ) + } + } +} From 8eb5e65ac4d0cf0f823486e6799ec040d18fcf8d Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 26 Mar 2025 18:13:13 +0000 Subject: [PATCH 13/26] PS: Synthesize Function and Type classes instead of relying on the statement that defines them. --- .../powershell/ast/internal/Synthesis.qll | 86 +++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Synthesis.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Synthesis.qll index b18a1e5dbf7f..b585a2b40307 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/Synthesis.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Synthesis.qll @@ -373,3 +373,89 @@ private module ExprToStmtSynth { } } } + +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() + ) + } + } +} From 3bb6021cb2bb1128734f094a13258b2bcc607f7f Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 26 Mar 2025 18:13:41 +0000 Subject: [PATCH 14/26] PS: Remove the CmdExpr AST elements and synthesize StmtExpr instead where needed. --- .../powershell/ast/internal/Synthesis.qll | 69 +++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Synthesis.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Synthesis.qll index b585a2b40307..6dd892816946 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/Synthesis.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Synthesis.qll @@ -459,3 +459,72 @@ private module TypeSynth { } } } + +/** + * 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() + ) + } + } +} From 7adb020977d83781ce2fc82e4b73e2874e3d8b9a Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 26 Mar 2025 18:14:14 +0000 Subject: [PATCH 15/26] PS: Remove arguments that are just names for a named argument. --- .../powershell/ast/internal/Synthesis.qll | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Synthesis.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Synthesis.qll index 6dd892816946..f370336e98ab 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/Synthesis.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Synthesis.qll @@ -528,3 +528,42 @@ private module CmdExprRemoval { } } } + +/** + * 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 + ) + ) + } + } +} From 9f4d1c624dd0d64c3f9a09f55fe6f824063c6174 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 26 Mar 2025 18:14:47 +0000 Subject: [PATCH 16/26] PS: PowerShell doesn't have a notion of true, false, null, etc. In the extracted AST these are just variables with special names. We insert synthesized AST elements that represent these special variables. --- .../powershell/ast/internal/Synthesis.qll | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Synthesis.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Synthesis.qll index f370336e98ab..f3a594401283 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/Synthesis.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Synthesis.qll @@ -567,3 +567,88 @@ private module CmdArguments { } } } + +/** + * 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() + ) + } + } +} From 171f5ca698511e10e484bebcedd21af9e090d975 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 26 Mar 2025 18:15:03 +0000 Subject: [PATCH 17/26] PS: Inside a process block the name of a pipeline parameter actually refers to the individual elements in the pipeline. Add a synthesized variable access that represents this. --- .../powershell/ast/internal/Synthesis.qll | 118 ++++++++++++++++++ 1 file changed, 118 insertions(+) diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Synthesis.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Synthesis.qll index f3a594401283..8aa76fd11a49 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/Synthesis.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Synthesis.qll @@ -652,3 +652,121 @@ private module LiteralSynth { } } } + +/** + * 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() + ) + } + } +} From cc139222063a94f446752e2d70776bb228cf2499 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 26 Mar 2025 18:16:44 +0000 Subject: [PATCH 18/26] PS: Make the experimental query compile again. --- .../ql/src/experimental/CommandInjection.ql | 44 ++++++++++--------- 1 file changed, 24 insertions(+), 20 deletions(-) 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() From 9efc3ec38099a6358a405e0eb8da9b792b841c8e Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Tue, 25 Mar 2025 17:16:57 +0000 Subject: [PATCH 19/26] PS: Make dataflow compile again. --- .../code/powershell/dataflow/FlowSummary.qll | 6 +- .../powershell/dataflow/flowsources/Local.qll | 6 +- .../dataflow/internal/DataFlowDispatch.qll | 31 +- .../dataflow/internal/DataFlowPrivate.qll | 307 +++++++++--------- .../dataflow/internal/DataFlowPublic.qll | 88 ++--- .../code/powershell/internal/AstEscape.qll | 14 +- 6 files changed, 203 insertions(+), 249 deletions(-) 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/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/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() } - } } } From c2e24ea3a494f4cbf13b94cc8911248a39420141 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Tue, 25 Mar 2025 17:11:10 +0000 Subject: [PATCH 20/26] PS: Make CFG construction compile again. --- .../code/powershell/controlflow/CfgNodes.qll | 20 ++- .../controlflow/ControlFlowGraph.qll | 12 +- .../controlflow/internal/Completion.qll | 13 +- .../internal/ControlFlowGraphImpl.qll | 129 ++++++++++-------- .../controlflow/internal/Splitting.qll | 2 + 5 files changed, 105 insertions(+), 71 deletions(-) diff --git a/powershell/ql/lib/semmle/code/powershell/controlflow/CfgNodes.qll b/powershell/ql/lib/semmle/code/powershell/controlflow/CfgNodes.qll index 1b162d11a9a4..809ef64f8724 100644 --- a/powershell/ql/lib/semmle/code/powershell/controlflow/CfgNodes.qll +++ b/powershell/ql/lib/semmle/code/powershell/controlflow/CfgNodes.qll @@ -419,7 +419,10 @@ module ExprNodes { private class IndexExprWriteAccessChildMapping extends IndexExprChildMapping, IndexExprWriteAccess { - override predicate relevantChild(Ast child) { this.isExplicitWrite(child) } + override predicate relevantChild(Ast child) { + super.relevantChild(child) or + this.isExplicitWrite(child) + } } class IndexExprWriteAccessCfgNode extends IndexExprCfgNode { @@ -443,7 +446,7 @@ module ExprNodes { } private class IndexExprReadAccessChildMapping extends IndexExprChildMapping, IndexExprReadAccess { - override predicate relevantChild(Ast child) { none() } + override predicate relevantChild(Ast child) { super.relevantChild(child) } } class IndexExprReadAccessCfgNode extends IndexExprCfgNode { @@ -480,6 +483,8 @@ module ExprNodes { /** 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) @@ -558,7 +563,10 @@ module ExprNodes { private class MemberExprWriteAccessChildMapping extends MemberExprChildMapping, MemberExprWriteAccess { - override predicate relevantChild(Ast child) { this.isExplicitWrite(child) } + override predicate relevantChild(Ast child) { + super.relevantChild(child) or + this.isExplicitWrite(child) + } } class MemberExprWriteAccessCfgNode extends MemberExprCfgNode { @@ -584,7 +592,7 @@ module ExprNodes { private class MemberExprReadAccessChildMapping extends MemberExprChildMapping, MemberExprReadAccess { - override predicate relevantChild(Ast child) { none() } + override predicate relevantChild(Ast child) { super.relevantChild(child) } } class MemberExprReadAccessCfgNode extends MemberExprCfgNode { @@ -1322,9 +1330,7 @@ module StmtNodes { } class ConfigurationChildMapping extends NonExprChildMapping, Configuration { - override predicate relevantChild(Ast child) { - child = this.getName() or child = this.getBody() - } + override predicate relevantChild(Ast child) { child = this.getName() or child = this.getBody() } } class ConfigurationCfgNode extends StmtCfgNode { 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() ) } From 8f9bc1e4b2dc0a79c5aba777deba5fda73478822 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Tue, 25 Mar 2025 17:12:17 +0000 Subject: [PATCH 21/26] PS: Make SSA compile again. --- .../semmle/code/powershell/dataflow/Ssa.qll | 56 ++-- .../powershell/dataflow/internal/SsaImpl.qll | 270 +++++++----------- 2 files changed, 133 insertions(+), 193 deletions(-) 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/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) { From 8092345fee92ba63c37828af59dc2893964de4f5 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Tue, 25 Mar 2025 17:13:03 +0000 Subject: [PATCH 22/26] PS: Make type-tracking and taint-tracking compile again. --- .../powershell/dataflow/internal/TaintTrackingPrivate.qll | 2 +- .../powershell/typetracking/internal/TypeTrackingImpl.qll | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) 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/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 From 7551cce53747575c438eb33b4effed7b4b5c19a7 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Tue, 25 Mar 2025 17:15:18 +0000 Subject: [PATCH 23/26] PS: Make API graphs compile again. There is still some TODOs here, but at least it compiles. --- .../lib/semmle/code/powershell/ApiGraphs.qll | 175 +++++++----------- .../code/powershell/ast/internal/Command.qll | 2 +- .../ast/internal/ObjectCreation.qll | 20 +- .../EngineIntrinsics.qll | 2 +- .../frameworks/data/ModelsAsData.qll | 2 +- .../data/internal/ApiGraphModelsSpecific.qll | 34 +--- 6 files changed, 85 insertions(+), 150 deletions(-) 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/ast/internal/Command.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Command.qll index 74ba575ae711..fb8b93ff9c15 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/Command.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Command.qll @@ -111,7 +111,7 @@ class SplitPath extends CmdCall { not this.hasNamedArgument("path") and result = this.getPositionalArgument(0) or - // TODO: This should not be allowed, but I've seen code doing it + // TODO: This should not be allowed, but I've seen code doing it and somehow it works result = this.getNamedArgument("parent") } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/ObjectCreation.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/ObjectCreation.qll index 0cd1938a077a..5cb392762599 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/ObjectCreation.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/ObjectCreation.qll @@ -3,6 +3,8 @@ import powershell abstract private class AbstractObjectCreation extends CallExpr { /** The name of the type of the object being constructed. */ abstract string getConstructedTypeName(); + + abstract Expr getConstructedTypeExpr(); } /** @@ -11,10 +13,12 @@ abstract private class AbstractObjectCreation extends CallExpr { * [System.IO.FileInfo]::new("C:\\file.txt") * ``` */ -class NewObjectCreation extends AbstractObjectCreation instanceof ConstructorCall { +class NewObjectCreation extends AbstractObjectCreation, ConstructorCall { final override string getConstructedTypeName() { result = ConstructorCall.super.getConstructedTypeName() } + + final override Expr getConstructedTypeExpr() { result = typename } } /** @@ -23,19 +27,21 @@ class NewObjectCreation extends AbstractObjectCreation instanceof ConstructorCal * New-Object -TypeName System.IO.FileInfo -ArgumentList "C:\\file.txt" * ``` */ -class DotNetObjectCreation extends AbstractObjectCreation instanceof CmdCall { +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").(StringConstExpr).getValueString() + 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 - exists(StringConstExpr arg | arg = CmdCall.super.getPositionalArgument(0) | - result = arg.getValueString() and - not arg = CmdCall.super.getNamedArgument(["ArgumentList", "Property"]) - ) + result = CmdCall.super.getPositionalArgument(0) and + result = CmdCall.super.getNamedArgument(["ArgumentList", "Property"]) } } 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`. */ From 655d80ee7b63ab326968db9d5be91ddd619e6080 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 26 Mar 2025 18:55:43 +0000 Subject: [PATCH 24/26] PS: Repair tests and accept test changes in syntax tests. --- .../test/TestUtilities/InlineFlowTestUtil.qll | 6 +- .../library-tests/ast/Arrays/arrays.expected | 42 +- .../test/library-tests/ast/Arrays/arrays.ql | 2 +- .../library-tests/ast/Blocks/blocks.expected | 3 +- .../test/library-tests/ast/Blocks/blocks.ql | 2 +- .../ast/Expressions/expressions.expected | 26 +- .../ast/Expressions/expressions.ql | 4 +- .../library-tests/ast/Loops/loops.expected | 6 +- .../ql/test/library-tests/ast/Loops/loops.ql | 6 +- .../ast/Redirections/redirections.expected | 4 +- .../ast/Statements/statements.expected | 49 +- .../ql/test/library-tests/ast/parent.expected | 773 +++++++++--------- 12 files changed, 462 insertions(+), 461 deletions(-) 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 | {...} | From c840f8670744b27f42bc1287af5543a3a3bfa05c Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 26 Mar 2025 18:56:44 +0000 Subject: [PATCH 25/26] PS: Accept CFG test changes. --- .../controlflow/graph/Cfg.expected | 1571 ++++++++--------- .../controlflow/graph/consistency.expected | 44 + .../controlflow/graph/consistency.ql | 1 + 3 files changed, 804 insertions(+), 812 deletions(-) create mode 100644 powershell/ql/test/library-tests/controlflow/graph/consistency.expected create mode 100644 powershell/ql/test/library-tests/controlflow/graph/consistency.ql 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 From 0fc57789bff2a80d05d9fa1606b70117e9d12342 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 27 Mar 2025 14:45:30 +0000 Subject: [PATCH 26/26] PS: Accept dataflow/taint-tracking/type-tracking regressions. --- .../dataflow/fields/test.expected | 341 +++++-------- .../library-tests/dataflow/fields/test.ps1 | 2 + .../dataflow/local/flow.expected | 107 ++-- .../dataflow/local/taint.expected | 126 +++-- .../dataflow/params/test.expected | 474 +++++++++--------- .../dataflow/pipeline/test.expected | 132 +---- .../dataflow/returns/test.expected | 104 ++-- .../dataflow/typetracking/test.expected | 4 +- .../ql/test/library-tests/ssa/ssa.expected | 13 +- .../CommandInjection.expected | 8 - .../DoNotUseInvokeExpression.expected | 2 +- 11 files changed, 545 insertions(+), 768 deletions(-) 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. |