From a207c8008bd76e291e477c11e2a520d2c28a87e4 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 26 Mar 2025 18:04:34 +0000 Subject: [PATCH] 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 00000000000..d89c502823a --- /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 00000000000..1fe24b69d17 --- /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 00000000000..99ff19ccf4b --- /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 00000000000..5bfb2383a69 --- /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 00000000000..10c1183bec0 --- /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 00000000000..6c4bf907c0a --- /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 00000000000..8987fd203e6 --- /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 00000000000..f8eb16d2768 --- /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 00000000000..7592f4dfc95 --- /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 00000000000..8c26d639421 --- /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 00000000000..2c388b865fe --- /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 00000000000..ee66cefc579 --- /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 00000000000..1f5419d8f1f --- /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 00000000000..8da1c5e2fb2 --- /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 00000000000..7186de94065 --- /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 00000000000..b6ba3abb738 --- /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 00000000000..ffeccacd5eb --- /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 00000000000..7c9343ee785 --- /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 00000000000..5a9865830bd --- /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 00000000000..e270595a12c --- /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 00000000000..8d9461b3c4d --- /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 00000000000..3f276a64388 --- /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 00000000000..0140a92c863 --- /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 00000000000..0bc04174092 --- /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 00000000000..c8caa6e6cb7 --- /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 00000000000..ef40c546091 --- /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 00000000000..52909c5830f --- /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 00000000000..e6e1d9c010c --- /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 00000000000..1f8d0d97720 --- /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 00000000000..451922ad7e5 --- /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 00000000000..299735945cf --- /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 00000000000..86b08a5e412 --- /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 00000000000..930b918c472 --- /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 00000000000..5fbadd59626 --- /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 00000000000..c398aeb9ec9 --- /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 00000000000..980c2e84894 --- /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 00000000000..e136f274b21 --- /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 00000000000..6b303fb36be --- /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 00000000000..bae96f4aa51 --- /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 00000000000..200c1b13a80 --- /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 00000000000..35754f5740a --- /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 00000000000..9b98e364480 --- /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 00000000000..a2fa623f395 --- /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 00000000000..058d15922df --- /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 00000000000..574d5598578 --- /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 00000000000..2889b1c7d8d --- /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 00000000000..9c0c2d29ba0 --- /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 00000000000..26f4996f52c --- /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 00000000000..02758e5a786 --- /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 00000000000..491dbada6bb --- /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 00000000000..9a512d62690 --- /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 00000000000..324dec4d27e --- /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 00000000000..f11e621e74d --- /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 00000000000..0ebae92854a --- /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 00000000000..32669d0141e --- /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 00000000000..5e767329b16 --- /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 00000000000..c8d24d6f8ba --- /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 00000000000..9c1e793a4e5 --- /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 00000000000..f7e08c9b41e --- /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 00000000000..b7830927ed9 --- /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 00000000000..537161ac311 --- /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 00000000000..e4303171df3 --- /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 00000000000..a007dec2ffe --- /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 00000000000..6c8488e1a1a --- /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 00000000000..4b923136aa3 --- /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 00000000000..288daed9b0e --- /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 00000000000..569de5e4229 --- /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 00000000000..881f86e94f2 --- /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 00000000000..8fc5b4b238d --- /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 00000000000..dabbc2e2e73 --- /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 00000000000..e24ed143cdf --- /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 00000000000..b2caafdc304 --- /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 00000000000..bb8a30b6bd3 --- /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 00000000000..9b6e49e6ddb --- /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 00000000000..58f357a8efe --- /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 00000000000..a179d361291 --- /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 00000000000..d03605161a0 --- /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 00000000000..149aacbf040 --- /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 00000000000..bd386eb461f --- /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 00000000000..c5552aaf173 --- /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 00000000000..50fbc41bbac --- /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 00000000000..74370a61b19 --- /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 00000000000..527b17c0668 --- /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 00000000000..46614401daa --- /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 00000000000..00bc726699c --- /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 00000000000..92ced49b423 --- /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() + } +}