mirror of
https://github.com/github/codeql.git
synced 2026-05-25 00:27:09 +02:00
Merge pull request #85 from microsoft/powershell-cfg-for-function-bodies-and-loops
PS: Control-flow for function bodies and loops
This commit is contained in:
@@ -22,6 +22,7 @@ import semmle.code.powershell.ScriptBlock
|
||||
import semmle.code.powershell.StringLiteral
|
||||
import semmle.code.powershell.AssignmentStatement
|
||||
import semmle.code.powershell.BinaryExpression
|
||||
import semmle.code.powershell.UnaryExpression
|
||||
import semmle.code.powershell.ScriptBlockExpr
|
||||
import semmle.code.powershell.TernaryExpression
|
||||
import semmle.code.powershell.UsingExpression
|
||||
@@ -47,7 +48,7 @@ import semmle.code.powershell.UsingStmt
|
||||
import semmle.code.powershell.Type
|
||||
import semmle.code.powershell.Member
|
||||
import semmle.code.powershell.PropertyMember
|
||||
import semmle.code.powershell.FunctionMember
|
||||
import semmle.code.powershell.Function
|
||||
import semmle.code.powershell.TryStmt
|
||||
import semmle.code.powershell.IfStmt
|
||||
import semmle.code.powershell.ExitStmt
|
||||
@@ -65,6 +66,5 @@ import semmle.code.powershell.ParenExpression
|
||||
import semmle.code.powershell.Chainable
|
||||
import semmle.code.powershell.Pipeline
|
||||
import semmle.code.powershell.StringConstantExpression
|
||||
import semmle.code.powershell.FunctionDefinition
|
||||
import semmle.code.powershell.InvokeMemberExpression
|
||||
import semmle.code.powershell.CommentEntity
|
||||
|
||||
@@ -7,5 +7,5 @@ class ArrayLiteral extends @array_literal, Expr {
|
||||
|
||||
Expr getAnElement() { array_literal_element(this, _, result) }
|
||||
|
||||
override string toString() { result = "ArrayLiteral at: " + this.getLocation().toString() }
|
||||
override string toString() { result = "...,..." }
|
||||
}
|
||||
|
||||
@@ -1,15 +1,255 @@
|
||||
import powershell
|
||||
|
||||
class BinaryExpr extends @binary_expression, Expr {
|
||||
override string toString() {
|
||||
result = "...+..." // TODO
|
||||
}
|
||||
|
||||
override SourceLocation getLocation() { binary_expression_location(this, result) }
|
||||
|
||||
private int getKind() { binary_expression(this, result, _, _) }
|
||||
int getKind() { binary_expression(this, result, _, _) }
|
||||
|
||||
Expr getLeft() { binary_expression(this, _, result, _) }
|
||||
|
||||
Expr getRight() { binary_expression(this, _, _, result) }
|
||||
}
|
||||
|
||||
abstract private class AbstractArithmeticExpr extends BinaryExpr { }
|
||||
|
||||
final class ArithmeticExpr = AbstractArithmeticExpr;
|
||||
|
||||
class AddExpr extends AbstractArithmeticExpr {
|
||||
AddExpr() { this.getKind() = 40 }
|
||||
|
||||
final override string toString() { result = "...+..." }
|
||||
}
|
||||
|
||||
class SubExpr extends AbstractArithmeticExpr {
|
||||
SubExpr() { this.getKind() = 41 }
|
||||
|
||||
final override string toString() { result = "...-..." }
|
||||
}
|
||||
|
||||
class MulExpr extends AbstractArithmeticExpr {
|
||||
MulExpr() { this.getKind() = 37 }
|
||||
|
||||
final override string toString() { result = "...*..." }
|
||||
}
|
||||
|
||||
class DivExpr extends AbstractArithmeticExpr {
|
||||
DivExpr() { this.getKind() = 38 }
|
||||
|
||||
final override string toString() { result = ".../..." }
|
||||
}
|
||||
|
||||
class RemExpr extends AbstractArithmeticExpr {
|
||||
RemExpr() { this.getKind() = 39 }
|
||||
|
||||
final override string toString() { result = "...%..." }
|
||||
}
|
||||
|
||||
abstract private class AbstractBitwiseExpr extends BinaryExpr { }
|
||||
|
||||
final class BitwiseExpr = AbstractBitwiseExpr;
|
||||
|
||||
class BitwiseAndExpr extends AbstractBitwiseExpr {
|
||||
BitwiseAndExpr() { this.getKind() = 56 }
|
||||
|
||||
final override string toString() { result = "...&..." }
|
||||
}
|
||||
|
||||
class BitwiseOrExpr extends AbstractBitwiseExpr {
|
||||
BitwiseOrExpr() { this.getKind() = 57 }
|
||||
|
||||
final override string toString() { result = "...|..." }
|
||||
}
|
||||
|
||||
class BitwiseXorExpr extends AbstractBitwiseExpr {
|
||||
BitwiseXorExpr() { this.getKind() = 58 }
|
||||
|
||||
final override string toString() { result = "...^..." }
|
||||
}
|
||||
|
||||
class ShiftLeftExpr extends AbstractBitwiseExpr {
|
||||
ShiftLeftExpr() { this.getKind() = 97 }
|
||||
|
||||
final override string toString() { result = "...<<..." }
|
||||
}
|
||||
|
||||
class ShiftRightExpr extends AbstractBitwiseExpr {
|
||||
ShiftRightExpr() { this.getKind() = 98 }
|
||||
|
||||
final override string toString() { result = "...>>..." }
|
||||
}
|
||||
|
||||
abstract private class AbstractComparisonExpr extends BinaryExpr { }
|
||||
|
||||
final class ComparisonExpr = AbstractComparisonExpr;
|
||||
|
||||
abstract private class AbstractCaseInsensitiveComparisonExpr extends AbstractComparisonExpr { }
|
||||
|
||||
final class CaseInsensitiveComparisonExpr = AbstractCaseInsensitiveComparisonExpr;
|
||||
|
||||
class EqExpr extends AbstractCaseInsensitiveComparisonExpr {
|
||||
EqExpr() { this.getKind() = 60 }
|
||||
|
||||
final override string toString() { result = "... -eq ..." }
|
||||
}
|
||||
|
||||
class NeExpr extends AbstractCaseInsensitiveComparisonExpr {
|
||||
NeExpr() { this.getKind() = 61 }
|
||||
|
||||
final override string toString() { result = "... -ne ..." }
|
||||
}
|
||||
|
||||
abstract private class AbstractRelationalExpr extends AbstractComparisonExpr { }
|
||||
|
||||
final class RelationalExpr = AbstractRelationalExpr;
|
||||
|
||||
abstract private class AbstractCaseInsensitiveRelationalExpr extends AbstractRelationalExpr { }
|
||||
|
||||
class GeExpr extends AbstractCaseInsensitiveRelationalExpr {
|
||||
GeExpr() { this.getKind() = 62 }
|
||||
|
||||
final override string toString() { result = "... -ge ..." }
|
||||
}
|
||||
|
||||
class GtExpr extends AbstractCaseInsensitiveRelationalExpr {
|
||||
GtExpr() { this.getKind() = 63 }
|
||||
|
||||
final override string toString() { result = "... -gt ..." }
|
||||
}
|
||||
|
||||
class LtExpr extends AbstractCaseInsensitiveRelationalExpr {
|
||||
LtExpr() { this.getKind() = 64 }
|
||||
|
||||
final override string toString() { result = "... -lt ..." }
|
||||
}
|
||||
|
||||
class LeExpr extends AbstractCaseInsensitiveRelationalExpr {
|
||||
LeExpr() { this.getKind() = 65 }
|
||||
|
||||
final override string toString() { result = "... -le ..." }
|
||||
}
|
||||
|
||||
class LikeExpr extends AbstractCaseInsensitiveComparisonExpr {
|
||||
LikeExpr() { this.getKind() = 66 }
|
||||
|
||||
final override string toString() { result = "... -like ..." }
|
||||
}
|
||||
|
||||
class NotLikeExpr extends AbstractCaseInsensitiveComparisonExpr {
|
||||
NotLikeExpr() { this.getKind() = 67 }
|
||||
|
||||
final override string toString() { result = "... -notlike ..." }
|
||||
}
|
||||
|
||||
class MatchExpr extends AbstractCaseInsensitiveComparisonExpr {
|
||||
MatchExpr() { this.getKind() = 68 }
|
||||
|
||||
final override string toString() { result = "... -match ..." }
|
||||
}
|
||||
|
||||
class NotMatchExpr extends AbstractCaseInsensitiveComparisonExpr {
|
||||
NotMatchExpr() { this.getKind() = 69 }
|
||||
|
||||
final override string toString() { result = "... -notmatch ..." }
|
||||
}
|
||||
|
||||
class ReplaceExpr extends AbstractCaseInsensitiveComparisonExpr {
|
||||
ReplaceExpr() { this.getKind() = 70 }
|
||||
|
||||
final override string toString() { result = "... -replace ..." }
|
||||
}
|
||||
|
||||
abstract class AbstractTypeExpr extends BinaryExpr { }
|
||||
|
||||
final class TypeExpr = AbstractTypeExpr;
|
||||
|
||||
abstract class AbstractTypeComparisonExpr extends AbstractTypeExpr { }
|
||||
|
||||
final class TypeComparisonExpr = AbstractTypeComparisonExpr;
|
||||
|
||||
class IsExpr extends AbstractTypeComparisonExpr {
|
||||
IsExpr() { this.getKind() = 92 }
|
||||
|
||||
final override string toString() { result = "... -is ..." }
|
||||
}
|
||||
|
||||
class IsNotExpr extends AbstractTypeComparisonExpr {
|
||||
IsNotExpr() { this.getKind() = 93 }
|
||||
|
||||
final override string toString() { result = "... -isnot ..." }
|
||||
}
|
||||
|
||||
class AsExpr extends AbstractTypeExpr {
|
||||
AsExpr() { this.getKind() = 94 }
|
||||
|
||||
final override string toString() { result = "... -as ..." }
|
||||
}
|
||||
|
||||
abstract private class AbstractContainmentExpr extends BinaryExpr { }
|
||||
|
||||
final class ContainmentExpr = AbstractContainmentExpr;
|
||||
|
||||
abstract private class AbstractCaseInsensitiveContainmentExpr extends AbstractContainmentExpr { }
|
||||
|
||||
final class CaseInsensitiveContainmentExpr = AbstractCaseInsensitiveContainmentExpr;
|
||||
|
||||
class ContainsExpr extends AbstractCaseInsensitiveContainmentExpr {
|
||||
ContainsExpr() { this.getKind() = 71 }
|
||||
|
||||
final override string toString() { result = "... -contains ..." }
|
||||
}
|
||||
|
||||
class NotContainsExpr extends AbstractCaseInsensitiveContainmentExpr {
|
||||
NotContainsExpr() { this.getKind() = 72 }
|
||||
|
||||
final override string toString() { result = "... -notcontains ..." }
|
||||
}
|
||||
|
||||
class InExpr extends AbstractCaseInsensitiveContainmentExpr {
|
||||
InExpr() { this.getKind() = 73 }
|
||||
|
||||
final override string toString() { result = "... -in ..." }
|
||||
}
|
||||
|
||||
class NotInExpr extends AbstractCaseInsensitiveContainmentExpr {
|
||||
NotInExpr() { this.getKind() = 74 }
|
||||
|
||||
final override string toString() { result = "... -notin ..." }
|
||||
}
|
||||
|
||||
abstract private class AbstractLogicalBinaryExpr extends BinaryExpr { }
|
||||
|
||||
final class LogicalBinaryExpr = AbstractLogicalBinaryExpr;
|
||||
|
||||
class LogicalAndExpr extends AbstractLogicalBinaryExpr {
|
||||
LogicalAndExpr() { this.getKind() = 53 }
|
||||
|
||||
final override string toString() { result = "... -and ..." }
|
||||
}
|
||||
|
||||
class LogicalOrExpr extends AbstractLogicalBinaryExpr {
|
||||
LogicalOrExpr() { this.getKind() = 54 }
|
||||
|
||||
final override string toString() { result = "... -or ..." }
|
||||
}
|
||||
|
||||
class LogicalXorExpr extends AbstractLogicalBinaryExpr {
|
||||
LogicalXorExpr() { this.getKind() = 55 }
|
||||
|
||||
final override string toString() { result = "... -xor ..." }
|
||||
}
|
||||
|
||||
abstract private class AbstractStringExpr extends BinaryExpr { }
|
||||
|
||||
final class StringExpr = AbstractStringExpr;
|
||||
|
||||
class JoinExpr extends AbstractStringExpr {
|
||||
JoinExpr() { this.getKind() = 59 }
|
||||
|
||||
final override string toString() { result = "... -join ..." }
|
||||
}
|
||||
|
||||
class SplitExpr extends AbstractStringExpr {
|
||||
SplitExpr() { this.getKind() = 75 }
|
||||
|
||||
final override string toString() { result = "... -split ..." }
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import powershell
|
||||
|
||||
class BreakStmt extends GotoStmt, Stmt {
|
||||
class BreakStmt extends GotoStmt, @break_statement {
|
||||
override SourceLocation getLocation() { break_statement_location(this, result) }
|
||||
|
||||
override string toString() { result = "continue" }
|
||||
override string toString() { result = "break" }
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import powershell
|
||||
|
||||
class ContinueStmt extends GotoStmt, Stmt {
|
||||
class ContinueStmt extends GotoStmt, @continue_statement {
|
||||
override SourceLocation getLocation() { continue_statement_location(this, result) }
|
||||
|
||||
override string toString() { result = "continue" }
|
||||
|
||||
@@ -7,5 +7,5 @@ class DoUntilStmt extends @do_until_statement, LoopStmt {
|
||||
|
||||
PipelineBase getCondition() { do_until_statement_condition(this, result) } // TODO: Change @ast to @pipeline_base in dbscheme
|
||||
|
||||
StmtBlock getBody() { do_until_statement(this, result) } // TODO: Change @ast to @stmt_block in dbscheme
|
||||
final override StmtBlock getBody() { do_until_statement(this, result) } // TODO: Change @ast to @stmt_block in dbscheme
|
||||
}
|
||||
|
||||
@@ -7,5 +7,5 @@ class DoWhileStmt extends @do_while_statement, LoopStmt {
|
||||
|
||||
PipelineBase getCondition() { do_while_statement_condition(this, result) } // TODO: Change @ast to @pipeline_base in dbscheme
|
||||
|
||||
StmtBlock getBody() { do_while_statement(this, result) } // TODO: Change @ast to @stmt_block in dbscheme
|
||||
final override StmtBlock getBody() { do_while_statement(this, result) } // TODO: Change @ast to @stmt_block in dbscheme
|
||||
}
|
||||
|
||||
@@ -5,12 +5,11 @@ class ForEachStmt extends @foreach_statement, LoopStmt {
|
||||
|
||||
override string toString() { result = "forach(... in ...)" }
|
||||
|
||||
StmtBlock getBody() { foreach_statement(this, _, _, result, _) } // TODO: Change @ast to @stmt_block in dbscheme
|
||||
final override StmtBlock getBody() { foreach_statement(this, _, _, result, _) } // TODO: Change @ast to @stmt_block in dbscheme
|
||||
|
||||
VarAccess getVariable() { foreach_statement(this, result, _, _, _) } // TODO: Change @ast to @variable_expression in dbscheme
|
||||
|
||||
/** ..., if any. */
|
||||
PipelineBase getCondition() { foreach_statement(this, _, result, _, _) } // TODO: Change @ast to @pipeline_base in dbscheme
|
||||
PipelineBase getIterableExpr() { foreach_statement(this, _, result, _, _) } // TODO: Change @ast to @pipeline_base in dbscheme
|
||||
|
||||
predicate isParallel() { foreach_statement(this, _, _, _, 1) }
|
||||
}
|
||||
|
||||
@@ -11,5 +11,5 @@ class ForStmt extends @for_statement, LoopStmt {
|
||||
|
||||
PipelineBase getIterator() { for_statement_iterator(this, result) } // TODO: Change @ast to @pipeline_base in dbscheme
|
||||
|
||||
StmtBlock getBody() { for_statement(this, result) } // TODO: Change @ast to @stmt_block in dbscheme
|
||||
final override StmtBlock getBody() { for_statement(this, result) } // TODO: Change @ast to @stmt_block in dbscheme
|
||||
}
|
||||
|
||||
69
powershell/ql/lib/semmle/code/powershell/Function.qll
Normal file
69
powershell/ql/lib/semmle/code/powershell/Function.qll
Normal file
@@ -0,0 +1,69 @@
|
||||
import powershell
|
||||
|
||||
abstract private class AbstractFunction extends Ast {
|
||||
abstract string getName();
|
||||
|
||||
abstract ScriptBlock getBody();
|
||||
|
||||
abstract Parameter getFunctionParameter(int i);
|
||||
|
||||
final Parameter getAFunctionParameter() { result = this.getFunctionParameter(_) }
|
||||
|
||||
final int getNumberOfFunctionParameters() { result = count(this.getAFunctionParameter()) }
|
||||
|
||||
final int getNumberOfParameters() { result = count(this.getAParameter()) }
|
||||
|
||||
final Parameter getParameter(int i) {
|
||||
result = this.getFunctionParameter(i)
|
||||
or
|
||||
result = this.getBody().getParamBlock().getParameter(i)
|
||||
}
|
||||
|
||||
final Parameter getAParameter() { result = this.getParameter(_) }
|
||||
}
|
||||
|
||||
class NonMemberFunction extends @function_definition, Stmt, AbstractFunction {
|
||||
override string toString() { result = this.getName() }
|
||||
|
||||
override SourceLocation getLocation() { function_definition_location(this, result) }
|
||||
|
||||
override string getName() { function_definition(this, _, result, _, _) }
|
||||
|
||||
override ScriptBlock getBody() { function_definition(this, result, _, _, _) }
|
||||
|
||||
predicate isFilter() { function_definition(this, _, _, true, _) }
|
||||
|
||||
predicate isWorkflow() { function_definition(this, _, _, _, true) }
|
||||
|
||||
override Parameter getFunctionParameter(int i) { function_definition_parameter(this, i, result) }
|
||||
}
|
||||
|
||||
class MemberFunction extends @function_member, Member, AbstractFunction {
|
||||
override string getName() { function_member(this, _, _, _, _, _, _, result, _) }
|
||||
|
||||
override SourceLocation getLocation() { function_member_location(this, result) }
|
||||
|
||||
override string toString() { result = this.getName() }
|
||||
|
||||
override ScriptBlock getBody() { function_member(this, result, _, _, _, _, _, _, _) }
|
||||
|
||||
override predicate isHidden() { function_member(this, _, _, true, _, _, _, _, _) }
|
||||
|
||||
override predicate isPrivate() { function_member(this, _, _, _, true, _, _, _, _) }
|
||||
|
||||
override predicate isPublic() { function_member(this, _, _, _, _, true, _, _, _) }
|
||||
|
||||
override predicate isStatic() { function_member(this, _, _, _, _, _, true, _, _) }
|
||||
|
||||
predicate isConstructor() { function_member(this, _, true, _, _, _, _, _, _) }
|
||||
|
||||
override Parameter getFunctionParameter(int i) { function_member_parameter(this, i, result) }
|
||||
|
||||
TypeConstraint getTypeConstraint() { function_member_return_type(this, result) }
|
||||
}
|
||||
|
||||
class Constructor extends MemberFunction {
|
||||
Constructor() { this.isConstructor() }
|
||||
}
|
||||
|
||||
final class Function = AbstractFunction;
|
||||
@@ -1,19 +0,0 @@
|
||||
import powershell
|
||||
|
||||
class Function extends @function_definition, Stmt {
|
||||
override string toString() { result = "FunctionDefinition at: " + this.getLocation().toString() }
|
||||
|
||||
override SourceLocation getLocation() { function_definition_location(this, result) }
|
||||
|
||||
string getName() { function_definition(this, _, result, _, _) }
|
||||
|
||||
ScriptBlock getBody() { function_definition(this, result, _, _, _) }
|
||||
|
||||
predicate isFilter() { function_definition(this, _, _, true, _) }
|
||||
|
||||
predicate isWorkflow() { function_definition(this, _, _, _, true) }
|
||||
|
||||
Parameter getParameter(int i) { function_definition_parameter(this, i, result) }
|
||||
|
||||
Parameter getAParameter() { result = this.getParameter(_) }
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
import powershell
|
||||
|
||||
class FunctionMember extends @function_member, Member {
|
||||
override string getName() { function_member(this, _, _, _, _, _, _, result, _) }
|
||||
|
||||
override SourceLocation getLocation() { function_member_location(this, result) }
|
||||
|
||||
override string toString() { result = this.getName() }
|
||||
|
||||
ScriptBlock getBody() { function_member(this, result, _, _, _, _, _, _, _) }
|
||||
|
||||
override predicate isHidden() { function_member(this, _, _, true, _, _, _, _, _) }
|
||||
|
||||
override predicate isPrivate() { function_member(this, _, _, _, true, _, _, _, _) }
|
||||
|
||||
override predicate isPublic() { function_member(this, _, _, _, _, true, _, _, _) }
|
||||
|
||||
override predicate isStatic() { function_member(this, _, _, _, _, _, true, _, _) }
|
||||
|
||||
predicate isConstructor() { function_member(this, _, true, _, _, _, _, _, _) }
|
||||
|
||||
Parameter getParameter(int i) { function_member_parameter(this, i, result) }
|
||||
|
||||
Parameter getAParameter() { result = this.getParameter(_) }
|
||||
|
||||
TypeConstraint getTypeConstraint() { function_member_return_type(this, result) }
|
||||
}
|
||||
|
||||
class Constructor extends FunctionMember {
|
||||
Constructor() { this.isConstructor() }
|
||||
}
|
||||
@@ -9,6 +9,8 @@ class IfStmt extends @if_statement, Stmt {
|
||||
|
||||
PipelineBase getCondition(int i) { if_statement_clause(this, i, result, _) } // TODO: Change @ast to @pipeline_base in dbscheme
|
||||
|
||||
PipelineBase getACondition() { result = this.getCondition(_) }
|
||||
|
||||
StmtBlock getThen(int i) { if_statement_clause(this, i, _, result) } // TODO: Change @ast to @statement_block in dbscheme
|
||||
|
||||
/** ..., if any. */
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import powershell
|
||||
|
||||
class LoopStmt extends @loop_statement, LabeledStmt { }
|
||||
class LoopStmt extends @loop_statement, LabeledStmt {
|
||||
StmtBlock getBody() { none() }
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import powershell
|
||||
|
||||
class ParamBlock extends @param_block, Ast {
|
||||
override string toString() { result = "ParamBlock" }
|
||||
override string toString() { result = "param(...)" }
|
||||
|
||||
override SourceLocation getLocation() { param_block_location(this, result) }
|
||||
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
import powershell
|
||||
|
||||
class Pipeline extends @pipeline, Chainable {
|
||||
override string toString() { result = "...|..." }
|
||||
override string toString() {
|
||||
if this.getNumberOfComponents() = 1
|
||||
then result = this.getComponent(0).toString()
|
||||
else result = "...|..."
|
||||
}
|
||||
|
||||
override SourceLocation getLocation() { pipeline_location(this, result) }
|
||||
|
||||
int getNumComponents() { pipeline(this, result) }
|
||||
int getNumberOfComponents() { result = count(this.getAComponent()) }
|
||||
|
||||
CmdBase getComponent(int i) { pipeline_component(this, i, result) }
|
||||
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
import powershell
|
||||
|
||||
class ScriptBlock extends @script_block, Ast {
|
||||
override string toString() { result = this.getLocation().getFile().getBaseName() }
|
||||
predicate isTopLevel() { not exists(this.getParent()) }
|
||||
|
||||
override string toString() {
|
||||
if this.isTopLevel()
|
||||
then result = this.getLocation().getFile().getBaseName()
|
||||
else result = "{...}"
|
||||
}
|
||||
|
||||
override SourceLocation getLocation() { script_block_location(this, result) }
|
||||
|
||||
|
||||
@@ -3,17 +3,17 @@ import powershell
|
||||
class StmtBlock extends @statement_block, Ast {
|
||||
override SourceLocation getLocation() { statement_block_location(this, result) }
|
||||
|
||||
int getNumStatements() { statement_block(this, result, _) }
|
||||
int getNumberOfStmts() { statement_block(this, result, _) }
|
||||
|
||||
int getNumTraps() { statement_block(this, _, result) }
|
||||
|
||||
Stmt getStatement(int index) { statement_block_statement(this, index, result) }
|
||||
Stmt getStmt(int index) { statement_block_statement(this, index, result) }
|
||||
|
||||
Stmt getAStatement() { result = this.getStatement(_) }
|
||||
Stmt getAStmt() { result = this.getStmt(_) }
|
||||
|
||||
TrapStmt getTrapStatement(int index) { statement_block_trap(this, index, result) }
|
||||
TrapStmt getTrapStmt(int index) { statement_block_trap(this, index, result) }
|
||||
|
||||
TrapStmt getATrapStatement() { result = this.getTrapStatement(_) }
|
||||
TrapStmt getATrapStmt() { result = this.getTrapStmt(_) }
|
||||
|
||||
override string toString() { result = "StatementBlock at: " + this.getLocation().toString() }
|
||||
override string toString() { result = "{...}" }
|
||||
}
|
||||
|
||||
@@ -10,4 +10,14 @@ class ConditionalExpr extends @ternary_expression, Expr {
|
||||
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(_) }
|
||||
}
|
||||
|
||||
15
powershell/ql/lib/semmle/code/powershell/UnaryExpression.qll
Normal file
15
powershell/ql/lib/semmle/code/powershell/UnaryExpression.qll
Normal file
@@ -0,0 +1,15 @@
|
||||
import powershell
|
||||
|
||||
class UnaryExpr extends @unary_expression, Expr {
|
||||
override SourceLocation getLocation() { unary_expression_location(this, result) }
|
||||
|
||||
int getKind() { unary_expression(this, _, result, _) }
|
||||
|
||||
Expr getOperand() { unary_expression(this, result, _, _) }
|
||||
}
|
||||
|
||||
class NotExpr extends UnaryExpr {
|
||||
NotExpr() { this.getKind() = 36 }
|
||||
|
||||
final override string toString() { result = "!..." }
|
||||
}
|
||||
@@ -7,5 +7,5 @@ class WhileStmt extends @while_statement, LoopStmt {
|
||||
|
||||
PipelineBase getCondition() { while_statement_condition(this, result) } // TODO: Change @ast to @pipeline_base in dbscheme
|
||||
|
||||
StmtBlock getBody() { while_statement(this, result) } // TODO: Change @ast to @stmt_block in dbscheme
|
||||
final override StmtBlock getBody() { while_statement(this, result) } // TODO: Change @ast to @stmt_block in dbscheme
|
||||
}
|
||||
|
||||
@@ -90,6 +90,10 @@ module SuccessorTypes {
|
||||
final override string toString() { result = "break" }
|
||||
}
|
||||
|
||||
class ContinueSuccessor extends SuccessorType, CfgImpl::TContinueSuccessor {
|
||||
final override string toString() { result = "continue" }
|
||||
}
|
||||
|
||||
class RaiseSuccessor extends SuccessorType, CfgImpl::TRaiseSuccessor {
|
||||
final override string toString() { result = "raise" }
|
||||
}
|
||||
|
||||
@@ -15,11 +15,18 @@ private newtype TCompletion =
|
||||
TBooleanCompletion(boolean b) { b in [false, true] } or
|
||||
TReturnCompletion() or
|
||||
TBreakCompletion() or
|
||||
TContinueCompletion() or
|
||||
TRaiseCompletion() or
|
||||
TExitCompletion()
|
||||
|
||||
pragma[noinline]
|
||||
private predicate completionIsValidForStmt(Ast n, Completion c) { none() }
|
||||
private predicate completionIsValidForStmt(Ast n, Completion c) {
|
||||
n instanceof BreakStmt and
|
||||
c instanceof BreakCompletion
|
||||
or
|
||||
n instanceof ContinueStmt and
|
||||
c instanceof ContinueCompletion
|
||||
}
|
||||
|
||||
/** A completion of a statement or an expression. */
|
||||
abstract class Completion extends TCompletion {
|
||||
@@ -49,19 +56,10 @@ abstract class Completion extends TCompletion {
|
||||
* Holds if this completion will continue a loop when it is the completion
|
||||
* of a loop body.
|
||||
*/
|
||||
predicate continuesLoop() { this instanceof NormalCompletion }
|
||||
|
||||
/**
|
||||
* Gets the inner completion. This is either the inner completion,
|
||||
* when the completion is nested, or the completion itself.
|
||||
*/
|
||||
Completion getInnerCompletion() { result = this }
|
||||
|
||||
/**
|
||||
* Gets the outer completion. This is either the outer completion,
|
||||
* when the completion is nested, or the completion itself.
|
||||
*/
|
||||
Completion getOuterCompletion() { result = this }
|
||||
predicate continuesLoop() {
|
||||
this instanceof NormalCompletion or
|
||||
this instanceof ContinueCompletion
|
||||
}
|
||||
|
||||
/** Gets a successor type that matches this completion. */
|
||||
abstract SuccessorType getAMatchingSuccessorType();
|
||||
@@ -85,7 +83,50 @@ private predicate mustHaveBooleanCompletion(Ast n) { inBooleanContext(n) }
|
||||
* Holds if `n` is used in a Boolean context. That is, the value
|
||||
* that `n` evaluates to determines a true/false branch successor.
|
||||
*/
|
||||
private predicate inBooleanContext(Ast n) { none() }
|
||||
private predicate inBooleanContext(Ast n) {
|
||||
n = any(IfStmt ifStmt).getACondition()
|
||||
or
|
||||
n = any(WhileStmt whileStmt).getCondition()
|
||||
or
|
||||
n = any(DoWhileStmt doWhileStmt).getCondition()
|
||||
or
|
||||
n = any(ForStmt forStmt).getCondition()
|
||||
or
|
||||
n = any(DoUntilStmt doUntilStmt).getCondition()
|
||||
or
|
||||
exists(ConditionalExpr cond |
|
||||
n = cond.getCondition()
|
||||
or
|
||||
inBooleanContext(cond) and
|
||||
n = cond.getABranch()
|
||||
)
|
||||
or
|
||||
exists(LogicalAndExpr parent |
|
||||
n = parent.getLeft()
|
||||
or
|
||||
inBooleanContext(parent) and
|
||||
n = parent.getRight()
|
||||
)
|
||||
or
|
||||
exists(LogicalOrExpr parent |
|
||||
n = parent.getLeft()
|
||||
or
|
||||
inBooleanContext(parent) and
|
||||
n = parent.getRight()
|
||||
)
|
||||
or
|
||||
n = any(NotExpr parent | inBooleanContext(parent)).getOperand()
|
||||
or
|
||||
exists(Pipeline pipeline |
|
||||
inBooleanContext(pipeline) and
|
||||
n = pipeline.getComponent(pipeline.getNumberOfComponents() - 1)
|
||||
)
|
||||
or
|
||||
exists(CmdExpr cmdExpr |
|
||||
inBooleanContext(cmdExpr) and
|
||||
n = cmdExpr.getExpr()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A completion that represents normal evaluation of a statement or an
|
||||
@@ -159,6 +200,16 @@ class BreakCompletion extends Completion, TBreakCompletion {
|
||||
override string toString() { result = "break" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A completion that represents evaluation of a statement or an
|
||||
* expression resulting in a continuation of a loop.
|
||||
*/
|
||||
class ContinueCompletion extends Completion, TContinueCompletion {
|
||||
override ContinueSuccessor getAMatchingSuccessorType() { any() }
|
||||
|
||||
override string toString() { result = "continue" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A completion that represents evaluation of a statement or an
|
||||
* expression resulting in a thrown exception.
|
||||
|
||||
@@ -75,8 +75,29 @@ predicate succExit(CfgScope scope, Ast last, Completion c) { scope.exit(last, c)
|
||||
|
||||
/** Defines the CFG by dispatch on the various AST types. */
|
||||
module Trees {
|
||||
class ScriptBlockTree extends PreOrderTree instanceof ScriptBlock {
|
||||
final override predicate last(AstNode last, Completion c) {
|
||||
class NonDefaultParameterTree extends LeafTree instanceof Parameter {
|
||||
NonDefaultParameterTree() { not exists(super.getDefaultValue()) }
|
||||
}
|
||||
|
||||
class DefaultParameterTree extends StandardPostOrderTree instanceof Parameter {
|
||||
DefaultParameterTree() { exists(super.getDefaultValue()) }
|
||||
|
||||
override AstNode getChildNode(int i) {
|
||||
i = 0 and
|
||||
result = super.getDefaultValue()
|
||||
}
|
||||
|
||||
final override predicate propagatesAbnormal(AstNode child) { child = super.getDefaultValue() }
|
||||
}
|
||||
|
||||
class ParameterBlockTree extends StandardPostOrderTree instanceof ParamBlock {
|
||||
override AstNode getChildNode(int i) { result = super.getParameter(i) }
|
||||
}
|
||||
|
||||
abstract class ScriptBlockTree extends ControlFlowTree instanceof ScriptBlock {
|
||||
abstract predicate succEntry(AstNode n, Completion c);
|
||||
|
||||
override predicate last(AstNode last, Completion c) {
|
||||
last(super.getEndBlock(), last, c)
|
||||
or
|
||||
not exists(super.getEndBlock()) and
|
||||
@@ -89,16 +110,36 @@ module Trees {
|
||||
not exists(super.getEndBlock()) and
|
||||
not exists(super.getProcessBlock()) and
|
||||
not exists(super.getBeginBlock()) and
|
||||
last = this and
|
||||
completionIsSimple(c)
|
||||
last(super.getParamBlock(), last, c)
|
||||
or
|
||||
not exists(super.getEndBlock()) and
|
||||
not exists(super.getProcessBlock()) and
|
||||
not exists(super.getBeginBlock()) and
|
||||
not exists(super.getParamBlock()) and
|
||||
// No blocks at all. We end where we started
|
||||
this.succEntry(last, c)
|
||||
}
|
||||
|
||||
final override predicate propagatesAbnormal(AstNode child) {
|
||||
child = [super.getBeginBlock(), super.getProcessBlock(), super.getEndBlock()]
|
||||
}
|
||||
|
||||
final override predicate succ(AstNode pred, AstNode succ, Completion c) {
|
||||
pred = this and
|
||||
override predicate succ(AstNode pred, AstNode succ, Completion c) {
|
||||
this.succEntry(pred, c) and
|
||||
(
|
||||
first(super.getParamBlock(), succ)
|
||||
or
|
||||
not exists(super.getParamBlock()) and
|
||||
first(super.getBeginBlock(), succ)
|
||||
or
|
||||
not exists(super.getParamBlock()) and
|
||||
not exists(super.getBeginBlock()) and
|
||||
first(super.getProcessBlock(), succ)
|
||||
or
|
||||
not exists(super.getParamBlock()) and
|
||||
not exists(super.getBeginBlock()) and
|
||||
not exists(super.getProcessBlock()) and
|
||||
first(super.getEndBlock(), succ)
|
||||
)
|
||||
or
|
||||
last(super.getParamBlock(), pred, c) and
|
||||
completionIsNormal(c) and
|
||||
(
|
||||
first(super.getBeginBlock(), succ)
|
||||
or
|
||||
@@ -108,24 +149,19 @@ module Trees {
|
||||
not exists(super.getBeginBlock()) and
|
||||
not exists(super.getProcessBlock()) and
|
||||
first(super.getEndBlock(), succ)
|
||||
) and
|
||||
completionIsSimple(c)
|
||||
)
|
||||
or
|
||||
last(super.getBeginBlock(), pred, c) and
|
||||
c instanceof NormalCompletion and
|
||||
completionIsNormal(c) and
|
||||
(
|
||||
first(super.getProcessBlock(), succ)
|
||||
or
|
||||
not exists(super.getProcessBlock()) and
|
||||
first(super.getEndBlock(), succ)
|
||||
or
|
||||
not exists(super.getProcessBlock()) and
|
||||
not exists(super.getEndBlock()) and
|
||||
succ = this
|
||||
)
|
||||
or
|
||||
last(super.getProcessBlock(), pred, c) and
|
||||
c instanceof NormalCompletion and
|
||||
completionIsNormal(c) and
|
||||
(
|
||||
// If we process multiple items we will loop back to the process block
|
||||
first(super.getProcessBlock(), succ)
|
||||
@@ -134,6 +170,57 @@ module Trees {
|
||||
first(super.getEndBlock(), succ)
|
||||
)
|
||||
}
|
||||
|
||||
final override predicate propagatesAbnormal(AstNode child) {
|
||||
child = super.getParamBlock() or
|
||||
child = super.getBeginBlock() or
|
||||
child = super.getProcessBlock() or
|
||||
child = super.getEndBlock()
|
||||
}
|
||||
}
|
||||
|
||||
class FunctionScriptBlockTree extends PreOrderTree, ScriptBlockTree {
|
||||
Function func;
|
||||
|
||||
FunctionScriptBlockTree() { func.getBody() = this }
|
||||
|
||||
AstNode getParameter(int i) { result = func.getFunctionParameter(i) }
|
||||
|
||||
int getNumberOfParameters() { result = func.getNumberOfFunctionParameters() }
|
||||
|
||||
override predicate succ(AstNode pred, AstNode succ, Completion c) {
|
||||
// Step to the first parameter
|
||||
pred = this and
|
||||
first(this.getParameter(0), succ) and
|
||||
completionIsSimple(c)
|
||||
or
|
||||
// Step to the next parameter
|
||||
exists(int i |
|
||||
last(this.getParameter(i), pred, c) and
|
||||
completionIsNormal(c) and
|
||||
first(this.getParameter(i + 1), succ)
|
||||
)
|
||||
or
|
||||
// Body steps
|
||||
super.succ(pred, succ, c)
|
||||
}
|
||||
|
||||
final override predicate succEntry(AstNode n, Completion c) {
|
||||
// If there are no paramters we enter the body directly
|
||||
not exists(this.getParameter(0)) and
|
||||
n = this and
|
||||
completionIsSimple(c)
|
||||
or
|
||||
// Once we are done with the last parameter we enter the body
|
||||
last(this.getParameter(this.getNumberOfParameters() - 1), n, c) and
|
||||
completionIsNormal(c)
|
||||
}
|
||||
}
|
||||
|
||||
class TopLevelScriptBlockTree extends PreOrderTree, ScriptBlockTree {
|
||||
TopLevelScriptBlockTree() { this.(ScriptBlock).isTopLevel() }
|
||||
|
||||
final override predicate succEntry(Ast n, Completion c) { n = this and completionIsSimple(c) }
|
||||
}
|
||||
|
||||
class NamedBlockTree extends StandardPostOrderTree instanceof NamedBlock {
|
||||
@@ -149,6 +236,192 @@ module Trees {
|
||||
}
|
||||
}
|
||||
|
||||
abstract class LoopStmtTree extends ControlFlowTree instanceof LoopStmt {
|
||||
final AstNode getBody() { result = super.getBody() }
|
||||
|
||||
override predicate last(AstNode last, Completion c) {
|
||||
// Exit the loop body when we encounter a break
|
||||
last(this.getBody(), last, c) and
|
||||
c instanceof BreakCompletion
|
||||
or
|
||||
// Body exits abnormally
|
||||
last(this.getBody(), last, c) and
|
||||
not c instanceof BreakCompletion and
|
||||
not c.continuesLoop()
|
||||
}
|
||||
}
|
||||
|
||||
abstract class ConditionalLoopStmtTree extends PreOrderTree, LoopStmtTree {
|
||||
abstract AstNode getCondition();
|
||||
|
||||
abstract predicate entersLoopWhenConditionIs(boolean value);
|
||||
|
||||
final override predicate propagatesAbnormal(AstNode child) { child = this.getCondition() }
|
||||
|
||||
override predicate last(AstNode last, Completion c) {
|
||||
// Exit the loop body when the condition is false
|
||||
last(this.getCondition(), last, c) and
|
||||
this.entersLoopWhenConditionIs(c.(BooleanCompletion).getValue().booleanNot())
|
||||
or
|
||||
super.last(last, c)
|
||||
}
|
||||
|
||||
override predicate succ(AstNode pred, AstNode succ, Completion c) {
|
||||
// Condition -> body
|
||||
last(this.getCondition(), pred, c) and
|
||||
this.entersLoopWhenConditionIs(c.(BooleanCompletion).getValue()) and
|
||||
first(this.getBody(), succ)
|
||||
or
|
||||
// Body -> condition
|
||||
last(this.getBody(), pred, c) and
|
||||
c.continuesLoop() and
|
||||
first(this.getCondition(), succ)
|
||||
}
|
||||
}
|
||||
|
||||
class WhileStmtTree extends ConditionalLoopStmtTree instanceof WhileStmt {
|
||||
override predicate entersLoopWhenConditionIs(boolean value) { value = true }
|
||||
|
||||
override AstNode getCondition() { result = WhileStmt.super.getCondition() }
|
||||
|
||||
final override predicate succ(AstNode pred, AstNode succ, Completion c) {
|
||||
// Start with the condition
|
||||
this = pred and
|
||||
first(this.getCondition(), succ) and
|
||||
completionIsSimple(c)
|
||||
or
|
||||
super.succ(pred, succ, c)
|
||||
}
|
||||
}
|
||||
|
||||
abstract class DoBasedLoopStmtTree extends ConditionalLoopStmtTree {
|
||||
final override predicate succ(AstNode pred, AstNode succ, Completion c) {
|
||||
// Start with the body
|
||||
this = pred and
|
||||
first(this.getBody(), succ) and
|
||||
completionIsSimple(c)
|
||||
or
|
||||
super.succ(pred, succ, c)
|
||||
}
|
||||
}
|
||||
|
||||
class DoWhileStmtTree extends DoBasedLoopStmtTree instanceof DoWhileStmt {
|
||||
override AstNode getCondition() { result = DoWhileStmt.super.getCondition() }
|
||||
|
||||
override predicate entersLoopWhenConditionIs(boolean value) { value = true }
|
||||
}
|
||||
|
||||
class DoUntilStmtTree extends DoBasedLoopStmtTree instanceof DoUntilStmt {
|
||||
override AstNode getCondition() { result = DoUntilStmt.super.getCondition() }
|
||||
|
||||
override predicate entersLoopWhenConditionIs(boolean value) { value = false }
|
||||
}
|
||||
|
||||
class ForStmtTree extends PreOrderTree, LoopStmtTree instanceof ForStmt {
|
||||
final override predicate propagatesAbnormal(AstNode child) {
|
||||
child = [super.getInitializer(), super.getIterator()]
|
||||
}
|
||||
|
||||
override predicate last(AstNode last, Completion c) {
|
||||
// Condition returns false
|
||||
last(super.getCondition(), last, c) and
|
||||
c instanceof FalseCompletion
|
||||
or
|
||||
super.last(last, c)
|
||||
}
|
||||
|
||||
final override predicate succ(AstNode pred, AstNode succ, Completion c) {
|
||||
// Start with initialization
|
||||
this = pred and
|
||||
first(super.getInitializer(), succ) and
|
||||
completionIsSimple(c)
|
||||
or
|
||||
// Initialization -> condition
|
||||
last(super.getInitializer(), pred, c) and
|
||||
completionIsNormal(c) and
|
||||
first(super.getCondition(), succ)
|
||||
or
|
||||
// Condition -> body
|
||||
last(super.getCondition(), pred, c) and
|
||||
c instanceof TrueCompletion and
|
||||
first(this.getBody(), succ)
|
||||
or
|
||||
// Body -> iterator
|
||||
last(this.getBody(), pred, c) and
|
||||
completionIsNormal(c) and
|
||||
first(super.getIterator(), succ)
|
||||
}
|
||||
}
|
||||
|
||||
class ForEachStmtTree extends LoopStmtTree instanceof ForEachStmt {
|
||||
final override predicate propagatesAbnormal(AstNode child) { child = super.getIterableExpr() }
|
||||
|
||||
final override predicate first(AstNode first) {
|
||||
// Unlike most other statements, `foreach` statements are not modeled in
|
||||
// pre-order, because we use the `foreach` node itself to represent the
|
||||
// emptiness test that determines whether to execute the loop body
|
||||
first(super.getIterableExpr(), first)
|
||||
}
|
||||
|
||||
final override predicate last(AstNode last, Completion c) {
|
||||
// Emptiness test exits with no more elements
|
||||
last = this and
|
||||
completionIsSimple(c)
|
||||
or
|
||||
super.last(last, c)
|
||||
}
|
||||
|
||||
final override predicate succ(AstNode pred, AstNode succ, Completion c) {
|
||||
// Emptiness test
|
||||
last(super.getIterableExpr(), pred, c) and
|
||||
completionIsNormal(c) and
|
||||
succ = this
|
||||
or
|
||||
// Emptiness test to variable declaration
|
||||
pred = this and
|
||||
first(super.getVariable(), succ) and
|
||||
completionIsSimple(c)
|
||||
or
|
||||
// Variable declaration to body
|
||||
last(super.getVariable(), succ, c) and
|
||||
completionIsNormal(c) and
|
||||
first(this.getBody(), succ)
|
||||
or
|
||||
// Body to emptiness test
|
||||
last(this.getBody(), pred, c) and
|
||||
c.continuesLoop() and
|
||||
succ = this
|
||||
}
|
||||
}
|
||||
|
||||
class StmtBlockTree extends PreOrderTree instanceof StmtBlock {
|
||||
final override predicate propagatesAbnormal(AstNode child) { child = super.getAStmt() }
|
||||
|
||||
final override predicate last(AstNode last, Completion c) {
|
||||
last(super.getStmt(super.getNumberOfStmts() - 1), last, c)
|
||||
or
|
||||
not exists(super.getAStmt()) and
|
||||
last = this and
|
||||
completionIsSimple(c)
|
||||
}
|
||||
|
||||
final override predicate succ(AstNode pred, AstNode succ, Completion c) {
|
||||
this = pred and
|
||||
first(super.getStmt(0), succ) and
|
||||
completionIsSimple(c)
|
||||
or
|
||||
exists(int i |
|
||||
last(super.getStmt(i), pred, c) and
|
||||
completionIsNormal(c) and
|
||||
first(super.getStmt(i + 1), succ)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class GotoStmtTree extends LeafTree instanceof GotoStmt { }
|
||||
|
||||
class FunctionStmtTree extends LeafTree instanceof Function { }
|
||||
|
||||
class VarAccessTree extends LeafTree instanceof VarAccess { }
|
||||
|
||||
class BinaryExprTree extends StandardPostOrderTree instanceof BinaryExpr {
|
||||
@@ -159,11 +432,23 @@ module Trees {
|
||||
}
|
||||
}
|
||||
|
||||
class UnaryExprTree extends StandardPostOrderTree instanceof UnaryExpr {
|
||||
override AstNode getChildNode(int i) { i = 0 and result = super.getOperand() }
|
||||
}
|
||||
|
||||
class ArrayLiteralTree extends StandardPostOrderTree instanceof ArrayLiteral {
|
||||
override AstNode getChildNode(int i) { result = super.getElement(i) }
|
||||
}
|
||||
|
||||
class ConstExprTree extends LeafTree instanceof ConstExpr { }
|
||||
|
||||
class CmdExprTree extends StandardPreOrderTree instanceof CmdExpr {
|
||||
override AstNode getChildNode(int i) { i = 0 and result = super.getExpr() }
|
||||
}
|
||||
|
||||
class PipelineTree extends StandardPreOrderTree instanceof Pipeline {
|
||||
override AstNode getChildNode(int i) { result = super.getComponent(i) }
|
||||
}
|
||||
}
|
||||
|
||||
private import Scope
|
||||
@@ -188,6 +473,7 @@ private module Cached {
|
||||
TBooleanSuccessor(boolean b) { b in [false, true] } or
|
||||
TReturnSuccessor() or
|
||||
TBreakSuccessor() or
|
||||
TContinueSuccessor() or
|
||||
TRaiseSuccessor() or
|
||||
TExitSuccessor()
|
||||
}
|
||||
|
||||
@@ -1,3 +1,260 @@
|
||||
functions.ps1:
|
||||
# 1| Add-Numbers-Arguments
|
||||
#-----| -> foo
|
||||
|
||||
# 1| {...}
|
||||
#-----| -> exit functions.ps1 (normal)
|
||||
|
||||
# 1| enter functions.ps1
|
||||
#-----| -> functions.ps1
|
||||
|
||||
# 1| exit functions.ps1
|
||||
|
||||
# 1| exit functions.ps1 (normal)
|
||||
#-----| -> exit functions.ps1
|
||||
|
||||
# 1| functions.ps1
|
||||
#-----| -> Add-Numbers-Arguments
|
||||
|
||||
# 1| enter {...}
|
||||
#-----| -> {...}
|
||||
|
||||
# 1| exit {...}
|
||||
|
||||
# 1| exit {...} (normal)
|
||||
#-----| -> exit {...}
|
||||
|
||||
# 1| {...}
|
||||
#-----| -> number1
|
||||
|
||||
# 3| param(...)
|
||||
#-----| -> ...+...
|
||||
|
||||
# 3| {...}
|
||||
#-----| -> exit {...} (normal)
|
||||
|
||||
# 4| number1
|
||||
#-----| -> number2
|
||||
|
||||
# 5| number2
|
||||
#-----| -> param(...)
|
||||
|
||||
# 8| number1
|
||||
#-----| -> number2
|
||||
|
||||
# 8| ...+...
|
||||
#-----| -> number1
|
||||
|
||||
# 8| ...+...
|
||||
#-----| -> {...}
|
||||
|
||||
# 8| ...+...
|
||||
#-----| -> ...+...
|
||||
|
||||
# 8| number2
|
||||
#-----| -> ...+...
|
||||
|
||||
# 11| foo
|
||||
#-----| -> Default-Arguments
|
||||
|
||||
# 11| enter {...}
|
||||
#-----| -> {...}
|
||||
|
||||
# 11| exit {...}
|
||||
|
||||
# 11| exit {...} (normal)
|
||||
#-----| -> exit {...}
|
||||
|
||||
# 11| {...}
|
||||
#-----| -> a
|
||||
|
||||
# 11| param(...)
|
||||
#-----| -> {...}
|
||||
|
||||
# 11| {...}
|
||||
#-----| -> exit {...} (normal)
|
||||
|
||||
# 11| a
|
||||
#-----| -> param(...)
|
||||
|
||||
# 13| Default-Arguments
|
||||
#-----| -> Add-Numbers-From-Array
|
||||
|
||||
# 13| enter {...}
|
||||
#-----| -> {...}
|
||||
|
||||
# 13| exit {...}
|
||||
|
||||
# 13| exit {...} (normal)
|
||||
#-----| -> exit {...}
|
||||
|
||||
# 13| {...}
|
||||
#-----| -> name0
|
||||
|
||||
# 14| param(...)
|
||||
#-----| -> ...+...
|
||||
|
||||
# 14| {...}
|
||||
#-----| -> exit {...} (normal)
|
||||
|
||||
# 15| name0
|
||||
#-----| -> 0
|
||||
|
||||
# 16| name1
|
||||
#-----| -> name1
|
||||
|
||||
# 16| 0
|
||||
#-----| -> name1
|
||||
|
||||
# 17| name2
|
||||
#-----| -> param(...)
|
||||
|
||||
# 17| name1
|
||||
#-----| -> 1
|
||||
|
||||
# 17| ...+...
|
||||
#-----| -> name2
|
||||
|
||||
# 17| 1
|
||||
#-----| -> ...+...
|
||||
|
||||
# 19| name
|
||||
#-----| -> name2
|
||||
|
||||
# 19| ...+...
|
||||
#-----| -> name
|
||||
|
||||
# 19| ...+...
|
||||
#-----| -> {...}
|
||||
|
||||
# 19| ...+...
|
||||
#-----| -> ...+...
|
||||
|
||||
# 19| name2
|
||||
#-----| -> ...+...
|
||||
|
||||
# 22| Add-Numbers-From-Array
|
||||
#-----| -> Add-Numbers-From-Pipeline
|
||||
|
||||
# 22| enter {...}
|
||||
#-----| -> {...}
|
||||
|
||||
# 22| exit {...}
|
||||
|
||||
# 22| exit {...} (normal)
|
||||
#-----| -> exit {...}
|
||||
|
||||
# 22| {...}
|
||||
#-----| -> numbers
|
||||
|
||||
# 24| param(...)
|
||||
#-----| -> sum
|
||||
|
||||
# 24| {...}
|
||||
#-----| -> exit {...} (normal)
|
||||
|
||||
# 25| numbers
|
||||
#-----| -> param(...)
|
||||
|
||||
# 28| sum
|
||||
#-----| -> 0
|
||||
|
||||
# 28| ...=...
|
||||
#-----| -> numbers
|
||||
|
||||
# 28| 0
|
||||
#-----| -> ...=...
|
||||
|
||||
# 28| 0
|
||||
#-----| -> 0
|
||||
|
||||
# 29| forach(... in ...)
|
||||
#-----| -> number
|
||||
#-----| -> sum
|
||||
|
||||
# 29| number
|
||||
|
||||
# 29| numbers
|
||||
#-----| -> numbers
|
||||
|
||||
# 29| numbers
|
||||
#-----| -> forach(... in ...)
|
||||
|
||||
# 29| numbers
|
||||
#-----| -> numbers
|
||||
|
||||
# 33| sum
|
||||
#-----| -> sum
|
||||
|
||||
# 33| sum
|
||||
#-----| -> {...}
|
||||
|
||||
# 33| sum
|
||||
#-----| -> sum
|
||||
|
||||
# 36| Add-Numbers-From-Pipeline
|
||||
#-----| -> {...}
|
||||
|
||||
# 36| enter {...}
|
||||
#-----| -> {...}
|
||||
|
||||
# 36| exit {...}
|
||||
|
||||
# 36| exit {...} (normal)
|
||||
#-----| -> exit {...}
|
||||
|
||||
# 36| {...}
|
||||
#-----| -> numbers
|
||||
|
||||
# 38| param(...)
|
||||
#-----| -> sum
|
||||
|
||||
# 39| numbers
|
||||
#-----| -> param(...)
|
||||
|
||||
# 41| {...}
|
||||
#-----| -> sum
|
||||
|
||||
# 42| sum
|
||||
#-----| -> 0
|
||||
|
||||
# 42| ...=...
|
||||
#-----| -> {...}
|
||||
|
||||
# 42| 0
|
||||
#-----| -> ...=...
|
||||
|
||||
# 42| 0
|
||||
#-----| -> 0
|
||||
|
||||
# 44| {...}
|
||||
#-----| -> sum
|
||||
#-----| -> sum
|
||||
|
||||
# 46| sum
|
||||
#-----| -> _
|
||||
|
||||
# 46| ...=...
|
||||
#-----| -> {...}
|
||||
|
||||
# 46| _
|
||||
#-----| -> ...=...
|
||||
|
||||
# 46| _
|
||||
#-----| -> _
|
||||
|
||||
# 48| {...}
|
||||
#-----| -> exit {...} (normal)
|
||||
|
||||
# 50| sum
|
||||
#-----| -> sum
|
||||
|
||||
# 50| sum
|
||||
#-----| -> {...}
|
||||
|
||||
# 50| sum
|
||||
#-----| -> sum
|
||||
|
||||
global.ps1:
|
||||
# 1| {...}
|
||||
#-----| -> c
|
||||
@@ -57,3 +314,445 @@ global.ps1:
|
||||
|
||||
# 6| b
|
||||
#-----| -> ...+...
|
||||
|
||||
loops.ps1:
|
||||
# 1| Test-While
|
||||
#-----| -> Test-Break
|
||||
|
||||
# 1| enter loops.ps1
|
||||
#-----| -> loops.ps1
|
||||
|
||||
# 1| exit loops.ps1
|
||||
|
||||
# 1| exit loops.ps1 (normal)
|
||||
#-----| -> exit loops.ps1
|
||||
|
||||
# 1| loops.ps1
|
||||
#-----| -> Test-While
|
||||
|
||||
# 1| {...}
|
||||
#-----| -> exit loops.ps1 (normal)
|
||||
|
||||
# 1| enter {...}
|
||||
#-----| -> {...}
|
||||
|
||||
# 1| exit {...}
|
||||
|
||||
# 1| exit {...} (normal)
|
||||
#-----| -> exit {...}
|
||||
|
||||
# 1| {...}
|
||||
#-----| -> a
|
||||
|
||||
# 2| a
|
||||
#-----| -> 0
|
||||
|
||||
# 2| ...=...
|
||||
#-----| -> while(...) {...}
|
||||
|
||||
# 2| {...}
|
||||
#-----| -> exit {...} (normal)
|
||||
|
||||
# 2| 0
|
||||
#-----| -> ...=...
|
||||
|
||||
# 2| 0
|
||||
#-----| -> 0
|
||||
|
||||
# 4| while(...) {...}
|
||||
#-----| -> ... -le ...
|
||||
|
||||
# 4| a
|
||||
#-----| -> 10
|
||||
|
||||
# 4| ... -le ...
|
||||
#-----| -> a
|
||||
|
||||
# 4| ... -le ...
|
||||
#-----| false -> {...}
|
||||
#-----| true -> {...}
|
||||
|
||||
# 4| ... -le ...
|
||||
#-----| -> ... -le ...
|
||||
|
||||
# 4| 10
|
||||
#-----| -> ... -le ...
|
||||
|
||||
# 4| {...}
|
||||
#-----| -> a
|
||||
|
||||
# 5| a
|
||||
#-----| -> ...+...
|
||||
|
||||
# 5| ...=...
|
||||
#-----| -> ... -le ...
|
||||
|
||||
# 5| a
|
||||
#-----| -> 1
|
||||
|
||||
# 5| ...+...
|
||||
#-----| -> ...=...
|
||||
|
||||
# 5| ...+...
|
||||
#-----| -> a
|
||||
|
||||
# 5| 1
|
||||
#-----| -> ...+...
|
||||
|
||||
# 9| Test-Break
|
||||
#-----| -> Test-Continue
|
||||
|
||||
# 9| enter {...}
|
||||
#-----| -> {...}
|
||||
|
||||
# 9| exit {...}
|
||||
|
||||
# 9| exit {...} (normal)
|
||||
#-----| -> exit {...}
|
||||
|
||||
# 9| {...}
|
||||
#-----| -> a
|
||||
|
||||
# 10| a
|
||||
#-----| -> 0
|
||||
|
||||
# 10| ...=...
|
||||
#-----| -> while(...) {...}
|
||||
|
||||
# 10| {...}
|
||||
#-----| -> exit {...} (normal)
|
||||
|
||||
# 10| 0
|
||||
#-----| -> ...=...
|
||||
|
||||
# 10| 0
|
||||
#-----| -> 0
|
||||
|
||||
# 11| while(...) {...}
|
||||
#-----| -> ... -le ...
|
||||
|
||||
# 11| a
|
||||
#-----| -> 10
|
||||
|
||||
# 11| ... -le ...
|
||||
#-----| -> a
|
||||
|
||||
# 11| ... -le ...
|
||||
#-----| false -> {...}
|
||||
#-----| true -> {...}
|
||||
|
||||
# 11| ... -le ...
|
||||
#-----| -> ... -le ...
|
||||
|
||||
# 11| 10
|
||||
#-----| -> ... -le ...
|
||||
|
||||
# 11| {...}
|
||||
#-----| -> break
|
||||
|
||||
# 12| break
|
||||
#-----| break -> exit {...} (normal)
|
||||
|
||||
# 17| Test-Continue
|
||||
#-----| -> Test-DoWhile
|
||||
|
||||
# 17| enter {...}
|
||||
#-----| -> {...}
|
||||
|
||||
# 17| exit {...}
|
||||
|
||||
# 17| exit {...} (normal)
|
||||
#-----| -> exit {...}
|
||||
|
||||
# 17| {...}
|
||||
#-----| -> a
|
||||
|
||||
# 18| a
|
||||
#-----| -> 0
|
||||
|
||||
# 18| ...=...
|
||||
#-----| -> while(...) {...}
|
||||
|
||||
# 18| {...}
|
||||
#-----| -> exit {...} (normal)
|
||||
|
||||
# 18| 0
|
||||
#-----| -> ...=...
|
||||
|
||||
# 18| 0
|
||||
#-----| -> 0
|
||||
|
||||
# 19| while(...) {...}
|
||||
#-----| -> ... -le ...
|
||||
|
||||
# 19| a
|
||||
#-----| -> 10
|
||||
|
||||
# 19| ... -le ...
|
||||
#-----| -> a
|
||||
|
||||
# 19| ... -le ...
|
||||
#-----| false -> {...}
|
||||
#-----| true -> {...}
|
||||
|
||||
# 19| ... -le ...
|
||||
#-----| -> ... -le ...
|
||||
|
||||
# 19| 10
|
||||
#-----| -> ... -le ...
|
||||
|
||||
# 19| {...}
|
||||
#-----| -> continue
|
||||
|
||||
# 20| continue
|
||||
#-----| continue -> ... -le ...
|
||||
|
||||
# 25| Test-DoWhile
|
||||
#-----| -> Test-DoUntil
|
||||
|
||||
# 25| enter {...}
|
||||
#-----| -> {...}
|
||||
|
||||
# 25| exit {...}
|
||||
|
||||
# 25| exit {...} (normal)
|
||||
#-----| -> exit {...}
|
||||
|
||||
# 25| {...}
|
||||
#-----| -> a
|
||||
|
||||
# 26| a
|
||||
#-----| -> 0
|
||||
|
||||
# 26| ...=...
|
||||
#-----| -> DoWhile
|
||||
|
||||
# 26| {...}
|
||||
#-----| -> exit {...} (normal)
|
||||
|
||||
# 26| 0
|
||||
#-----| -> ...=...
|
||||
|
||||
# 26| 0
|
||||
#-----| -> 0
|
||||
|
||||
# 28| DoWhile
|
||||
#-----| -> {...}
|
||||
|
||||
# 28| {...}
|
||||
#-----| -> a
|
||||
|
||||
# 29| a
|
||||
#-----| -> ...+...
|
||||
|
||||
# 29| ...=...
|
||||
#-----| -> ... -le ...
|
||||
|
||||
# 29| a
|
||||
#-----| -> 1
|
||||
|
||||
# 29| ...+...
|
||||
#-----| -> ...=...
|
||||
|
||||
# 29| ...+...
|
||||
#-----| -> a
|
||||
|
||||
# 29| 1
|
||||
#-----| -> ...+...
|
||||
|
||||
# 30| a
|
||||
#-----| -> 10
|
||||
|
||||
# 30| ... -le ...
|
||||
#-----| -> a
|
||||
|
||||
# 30| ... -le ...
|
||||
#-----| false -> {...}
|
||||
#-----| true -> {...}
|
||||
|
||||
# 30| ... -le ...
|
||||
#-----| -> ... -le ...
|
||||
|
||||
# 30| 10
|
||||
#-----| -> ... -le ...
|
||||
|
||||
# 33| Test-DoUntil
|
||||
#-----| -> Tet-For
|
||||
|
||||
# 33| enter {...}
|
||||
#-----| -> {...}
|
||||
|
||||
# 33| exit {...}
|
||||
|
||||
# 33| exit {...} (normal)
|
||||
#-----| -> exit {...}
|
||||
|
||||
# 33| {...}
|
||||
#-----| -> a
|
||||
|
||||
# 34| a
|
||||
#-----| -> 0
|
||||
|
||||
# 34| ...=...
|
||||
#-----| -> DoUntil
|
||||
|
||||
# 34| {...}
|
||||
#-----| -> exit {...} (normal)
|
||||
|
||||
# 34| 0
|
||||
#-----| -> ...=...
|
||||
|
||||
# 34| 0
|
||||
#-----| -> 0
|
||||
|
||||
# 36| DoUntil
|
||||
#-----| -> {...}
|
||||
|
||||
# 36| {...}
|
||||
#-----| -> a
|
||||
|
||||
# 37| a
|
||||
#-----| -> ...+...
|
||||
|
||||
# 37| ...=...
|
||||
#-----| -> ... -ge ...
|
||||
|
||||
# 37| a
|
||||
#-----| -> 1
|
||||
|
||||
# 37| ...+...
|
||||
#-----| -> ...=...
|
||||
|
||||
# 37| ...+...
|
||||
#-----| -> a
|
||||
|
||||
# 37| 1
|
||||
#-----| -> ...+...
|
||||
|
||||
# 38| a
|
||||
#-----| -> 10
|
||||
|
||||
# 38| ... -ge ...
|
||||
#-----| -> a
|
||||
|
||||
# 38| ... -ge ...
|
||||
#-----| true -> {...}
|
||||
#-----| false -> {...}
|
||||
|
||||
# 38| ... -ge ...
|
||||
#-----| -> ... -ge ...
|
||||
|
||||
# 38| 10
|
||||
#-----| -> ... -ge ...
|
||||
|
||||
# 41| Tet-For
|
||||
#-----| -> Test-ForEach
|
||||
|
||||
# 41| enter {...}
|
||||
#-----| -> {...}
|
||||
|
||||
# 41| exit {...}
|
||||
|
||||
# 41| exit {...} (normal)
|
||||
#-----| -> exit {...}
|
||||
|
||||
# 41| {...}
|
||||
#-----| -> a
|
||||
|
||||
# 42| a
|
||||
#-----| -> 0
|
||||
|
||||
# 42| ...=...
|
||||
#-----| -> for(...;...;...)
|
||||
|
||||
# 42| {...}
|
||||
#-----| -> exit {...} (normal)
|
||||
|
||||
# 42| 0
|
||||
#-----| -> ...=...
|
||||
|
||||
# 42| 0
|
||||
#-----| -> 0
|
||||
|
||||
# 44| for(...;...;...)
|
||||
#-----| -> i
|
||||
|
||||
# 44| i
|
||||
#-----| -> 0
|
||||
|
||||
# 44| ...=...
|
||||
#-----| -> ... -le ...
|
||||
|
||||
# 44| 0
|
||||
#-----| -> ...=...
|
||||
|
||||
# 44| 0
|
||||
#-----| -> 0
|
||||
|
||||
# 44| i
|
||||
#-----| -> 10
|
||||
|
||||
# 44| ... -le ...
|
||||
#-----| -> i
|
||||
|
||||
# 44| ... -le ...
|
||||
#-----| false -> {...}
|
||||
#-----| true -> {...}
|
||||
|
||||
# 44| ... -le ...
|
||||
#-----| -> ... -le ...
|
||||
|
||||
# 44| 10
|
||||
#-----| -> ... -le ...
|
||||
|
||||
# 44| i
|
||||
#-----| -> ...+...
|
||||
|
||||
# 44| ...=...
|
||||
|
||||
# 44| i
|
||||
#-----| -> 1
|
||||
|
||||
# 44| ...+...
|
||||
#-----| -> ...=...
|
||||
|
||||
# 44| ...+...
|
||||
#-----| -> i
|
||||
|
||||
# 44| 1
|
||||
#-----| -> ...+...
|
||||
|
||||
# 44| {...}
|
||||
#-----| -> a
|
||||
|
||||
# 45| a
|
||||
#-----| -> ...+...
|
||||
|
||||
# 45| ...=...
|
||||
#-----| -> i
|
||||
|
||||
# 45| a
|
||||
#-----| -> 1
|
||||
|
||||
# 45| ...+...
|
||||
#-----| -> ...=...
|
||||
|
||||
# 45| ...+...
|
||||
#-----| -> a
|
||||
|
||||
# 45| 1
|
||||
#-----| -> ...+...
|
||||
|
||||
# 49| Test-ForEach
|
||||
#-----| -> {...}
|
||||
|
||||
# 49| enter {...}
|
||||
#-----| -> {...}
|
||||
|
||||
# 49| {...}
|
||||
#-----| -> letterArray
|
||||
|
||||
# 50| letterArray
|
||||
#-----| -> ...,...
|
||||
|
||||
# 50| ...,...
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
Function Add-Numbers-Arguments {
|
||||
# We take in two numbers
|
||||
param(
|
||||
[int] $number1,
|
||||
[int] $number2
|
||||
)
|
||||
# We add them together
|
||||
$number1 + $number2
|
||||
}
|
||||
|
||||
function foo() { param($a) }
|
||||
|
||||
Function Default-Arguments {
|
||||
param(
|
||||
[int] $name0,
|
||||
[int] $name1 = 0,
|
||||
[int] $name2 = $name1 + 1
|
||||
)
|
||||
$name + $name2
|
||||
}
|
||||
|
||||
Function Add-Numbers-From-Array {
|
||||
# We take in a list of numbers
|
||||
param(
|
||||
[int[]] $numbers
|
||||
)
|
||||
|
||||
$sum = 0
|
||||
foreach ($number in $numbers) {
|
||||
# We add each number to the sum
|
||||
$sum += $number
|
||||
}
|
||||
$sum
|
||||
}
|
||||
|
||||
Function Add-Numbers-From-Pipeline {
|
||||
# We take in a list of numbers
|
||||
param(
|
||||
[int[]] $numbers
|
||||
)
|
||||
Begin {
|
||||
$sum = 0
|
||||
}
|
||||
Process {
|
||||
# We add each number to the sum
|
||||
$sum += $_
|
||||
}
|
||||
End {
|
||||
# We return the sum
|
||||
$sum
|
||||
}
|
||||
}
|
||||
|
||||
56
powershell/ql/test/library-tests/controlflow/graph/loops.ps1
Normal file
56
powershell/ql/test/library-tests/controlflow/graph/loops.ps1
Normal file
@@ -0,0 +1,56 @@
|
||||
function Test-While {
|
||||
$a = 0
|
||||
|
||||
while($a -le 10) {
|
||||
$a = $a + 1
|
||||
}
|
||||
}
|
||||
|
||||
function Test-Break {
|
||||
$a = 0
|
||||
while($a -le 10) {
|
||||
break
|
||||
$a = $a + 1
|
||||
}
|
||||
}
|
||||
|
||||
function Test-Continue {
|
||||
$a = 0
|
||||
while($a -le 10) {
|
||||
continue
|
||||
$a = $a + 1
|
||||
}
|
||||
}
|
||||
|
||||
function Test-DoWhile {
|
||||
$a = 0
|
||||
|
||||
do {
|
||||
$a = $a + 1
|
||||
} while ($a -le 10)
|
||||
}
|
||||
|
||||
function Test-DoUntil {
|
||||
$a = 0
|
||||
|
||||
do {
|
||||
$a = $a + 1
|
||||
} until ($a -ge 10)
|
||||
}
|
||||
|
||||
function Tet-For {
|
||||
$a = 0
|
||||
|
||||
for ($i = 0; $i -le 10; $i = $i + 1) {
|
||||
$a = $a + 1
|
||||
}
|
||||
}
|
||||
|
||||
function Test-ForEach {
|
||||
$letterArray = 'a','b','c','d'
|
||||
$a = 0
|
||||
foreach ($letter in $letterArray)
|
||||
{
|
||||
$a = $a + 1
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user