diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/ArrayExpression.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/ArrayExpression.qll index ae418c4d5117..68d82d96dbd3 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/ArrayExpression.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/ArrayExpression.qll @@ -1,5 +1,19 @@ private import AstImport +/** + * An array expression. For example: + * ``` + * $myArray = @("text", 42, $true) + * ``` + * + * An array expression is an expression of the form `@(...)` where `...` is + * a `StmtBlock` that computes the elements of the array. Often, that + * `StmtBlock` is an `ArrayLiteral`, but that is not necessarily the case. For + * example in: + * ``` + * $squares = @(foreach ($n in 1..5) { $n * $n }) + * ``` + */ class ArrayExpr extends Expr, TArrayExpr { StmtBlock getStmtBlock() { exists(Raw::Ast r | r = getRawAst(this) | diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/ArrayLiteral.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/ArrayLiteral.qll index 21427948b8ec..d9321db86e6b 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/ArrayLiteral.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/ArrayLiteral.qll @@ -1,5 +1,11 @@ private import AstImport +/** + * An array literal. For example: + * ``` + * 1, 2, 3, 4 + * ``` + */ class ArrayLiteral extends Expr, TArrayLiteral { Expr getExpr(int index) { exists(ChildIndex i, Raw::Ast r | i = arrayLiteralExpr(index) and r = getRawAst(this) | diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/AssignmentStatement.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/AssignmentStatement.qll index 6f4cb8d2fbfe..0e988d91cb1e 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/AssignmentStatement.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/AssignmentStatement.qll @@ -1,5 +1,11 @@ private import AstImport +/** + * An assignment statement. For example: + * ``` + * $name = "John" + * ``` + */ class AssignStmt extends Stmt, TAssignStmt { Expr getRightHandSide() { exists(Raw::Ast r | r = getRawAst(this) | diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Ast.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Ast.qll index a8619cb06486..7a2f5089a510 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/Ast.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Ast.qll @@ -1,5 +1,10 @@ private import AstImport +/** + * A PowerShell AST (Abstract Syntax Tree) element. + * + * This is the root of the PowerShell AST class hierarchy. + */ class Ast extends TAst { string toString() { none() } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/AutomaticVariable.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/AutomaticVariable.qll index 0fe155f15667..c89474245047 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/AutomaticVariable.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/AutomaticVariable.qll @@ -1,5 +1,8 @@ private import AstImport +/** + * A PowerShell automatic variable (for example, `$PSVersionTable` or `$MyInvocation`). + */ class AutomaticVariable extends Expr, TAutomaticVariable { final override string toString() { result = this.getLowerCaseName() } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/BinaryExpression.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/BinaryExpression.qll index f40eba8a30a2..1b4bc5eeafd6 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/BinaryExpression.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/BinaryExpression.qll @@ -1,5 +1,13 @@ private import AstImport +/** + * A binary expression. For example: + * ``` + * $sum = $a + $b + * $isEqual = $name -eq "John" + * $isActive = $user.Status -and $user.IsEnabled + * ``` + */ class BinaryExpr extends Expr, TBinaryExpr { /** INTERNAL: Do not use. */ int getKind() { result = getRawAst(this).(Raw::BinaryExpr).getKind() } @@ -39,30 +47,65 @@ abstract private class AbstractArithmeticExpr extends BinaryExpr { } final class ArithmeticExpr = AbstractArithmeticExpr; +/** + * An addition expression. For example: + * ``` + * $sum = $a + $b + * $concatenated = "Hello " + "World" + * ``` + */ class AddExpr extends AbstractArithmeticExpr { AddExpr() { this.getKind() = 40 } final override string toString() { result = "...+..." } } +/** + * A subtraction expression. For example: + * ``` + * $difference = $a - $b + * $remaining = $total - $used + * ``` + */ class SubExpr extends AbstractArithmeticExpr { SubExpr() { this.getKind() = 41 } final override string toString() { result = "...-..." } } +/** + * A multiplication expression. For example: + * ``` + * $product = $a * $b + * $repeated = "Hello" * 3 + * ``` + */ class MulExpr extends AbstractArithmeticExpr { MulExpr() { this.getKind() = 37 } final override string toString() { result = "...*..." } } +/** + * A division expression. For example: + * ``` + * $quotient = $a / $b + * $percentage = $part / $total + * ``` + */ class DivExpr extends AbstractArithmeticExpr { DivExpr() { this.getKind() = 38 } final override string toString() { result = ".../..." } } +/** + * A remainder (modulo) expression. For example: + * ``` + * $remainder = $a % $b + * $isEven = ($number % 2) -eq 0 + * ``` + */ class RemExpr extends AbstractArithmeticExpr { RemExpr() { this.getKind() = 39 } @@ -73,30 +116,65 @@ abstract private class AbstractBitwiseExpr extends BinaryExpr { } final class BitwiseExpr = AbstractBitwiseExpr; +/** + * A bitwise AND expression. For example: + * ``` + * $result = $flags1 -band $flags2 + * $masked = $value -band 0xFF + * ``` + */ class BitwiseAndExpr extends AbstractBitwiseExpr { BitwiseAndExpr() { this.getKind() = 56 } final override string toString() { result = "...&..." } } +/** + * A bitwise OR expression. For example: + * ``` + * $result = $flags1 -bor $flags2 + * $combined = $permissions -bor 0x04 + * ``` + */ class BitwiseOrExpr extends AbstractBitwiseExpr { BitwiseOrExpr() { this.getKind() = 57 } final override string toString() { result = "...|..." } } +/** + * A bitwise XOR expression. For example: + * ``` + * $result = $flags1 -bxor $flags2 + * $toggled = $state -bxor 1 + * ``` + */ class BitwiseXorExpr extends AbstractBitwiseExpr { BitwiseXorExpr() { this.getKind() = 58 } final override string toString() { result = "...^..." } } +/** + * A bitwise left shift expression. For example: + * ``` + * $result = $value -shl 2 + * $multiplied = $number -shl 1 + * ``` + */ class ShiftLeftExpr extends AbstractBitwiseExpr { ShiftLeftExpr() { this.getKind() = 97 } final override string toString() { result = "...<<..." } } +/** + * A bitwise right shift expression. For example: + * ``` + * $result = $value -shr 2 + * $divided = $number -shr 1 + * ``` + */ class ShiftRightExpr extends AbstractBitwiseExpr { ShiftRightExpr() { this.getKind() = 98 } @@ -115,24 +193,52 @@ abstract private class AbstractCaseSensitiveComparisonExpr extends AbstractCompa final class CaseSensitiveComparisonExpr = AbstractCaseSensitiveComparisonExpr; +/** + * A case-insensitive equality expression. For example: + * ``` + * $isEqual = $name -eq "John" + * $isZero = $count -eq 0 + * ``` + */ class EqExpr extends AbstractCaseInsensitiveComparisonExpr { EqExpr() { this.getKind() = 60 } final override string toString() { result = "... -eq ..." } } +/** + * A case-insensitive inequality expression. For example: + * ``` + * $isDifferent = $name -ne "John" + * $isNonZero = $count -ne 0 + * ``` + */ class NeExpr extends AbstractCaseInsensitiveComparisonExpr { NeExpr() { this.getKind() = 61 } final override string toString() { result = "... -ne ..." } } +/** + * A case-sensitive equality expression. For example: + * ``` + * $isEqual = $name -ceq "John" + * $exactMatch = $password -ceq "SecretPass" + * ``` + */ class CEqExpr extends AbstractCaseSensitiveComparisonExpr { CEqExpr() { this.getKind() = 76 } final override string toString() { result = "... -ceq ..." } } +/** + * A case-sensitive inequality expression. For example: + * ``` + * $isDifferent = $name -cne "John" + * $wrongPassword = $password -cne "SecretPass" + * ``` + */ class CNeExpr extends AbstractCaseSensitiveComparisonExpr { CNeExpr() { this.getKind() = 77 } @@ -199,6 +305,13 @@ class CLeExpr extends AbstractCaseSensitiveRelationalExpr { final override string toString() { result = "... -cle ..." } } +/** + * A like pattern matching expression. For example: + * ``` + * $matches = $filename -like "*.txt" + * $isValidEmail = $email -like "*@*.com" + * ``` + */ class LikeExpr extends AbstractCaseInsensitiveComparisonExpr { LikeExpr() { this.getKind() = 66 } @@ -211,6 +324,13 @@ class NotLikeExpr extends AbstractCaseInsensitiveComparisonExpr { final override string toString() { result = "... -notlike ..." } } +/** + * A regex pattern matching expression. For example: + * ``` + * $matches = $text -match "\d{3}-\d{2}-\d{4}" + * $isEmail = $input -match "^[^@]+@[^@]+\.[^@]+$" + * ``` + */ class MatchExpr extends AbstractCaseInsensitiveComparisonExpr { MatchExpr() { this.getKind() = 68 } @@ -223,6 +343,13 @@ class NotMatchExpr extends AbstractCaseInsensitiveComparisonExpr { final override string toString() { result = "... -notmatch ..." } } +/** + * A string replacement expression. For example: + * ``` + * $cleaned = $text -replace "\s+", " " + * $updated = $path -replace "\\", "/" + * ``` + */ class ReplaceExpr extends AbstractCaseInsensitiveComparisonExpr { ReplaceExpr() { this.getKind() = 70 } @@ -237,6 +364,13 @@ abstract class AbstractTypeComparisonExpr extends AbstractTypeExpr { } final class TypeComparisonExpr = AbstractTypeComparisonExpr; +/** + * A type checking expression. For example: + * ``` + * $isString = $value -is [string] + * $isArray = $data -is [array] + * ``` + */ class IsExpr extends AbstractTypeComparisonExpr { IsExpr() { this.getKind() = 92 } @@ -249,6 +383,13 @@ class IsNotExpr extends AbstractTypeComparisonExpr { final override string toString() { result = "... -isnot ..." } } +/** + * A type conversion expression. For example: + * ``` + * $number = $stringValue -as [int] + * $date = $text -as [datetime] + * ``` + */ class AsExpr extends AbstractTypeExpr { AsExpr() { this.getKind() = 94 } @@ -263,6 +404,13 @@ abstract private class AbstractCaseInsensitiveContainmentExpr extends AbstractCo final class CaseInsensitiveContainmentExpr = AbstractCaseInsensitiveContainmentExpr; +/** + * A containment check expression. For example: + * ``` + * $hasItem = $list -contains $item + * $isValidOption = @("Yes", "No", "Maybe") -contains $choice + * ``` + */ class ContainsExpr extends AbstractCaseInsensitiveContainmentExpr { ContainsExpr() { this.getKind() = 71 } @@ -275,6 +423,13 @@ class NotContainsExpr extends AbstractCaseInsensitiveContainmentExpr { final override string toString() { result = "... -notcontains ..." } } +/** + * A membership check expression. For example: + * ``` + * $isValidChoice = $choice -in @("Yes", "No", "Maybe") + * $isWeekend = $dayOfWeek -in @("Saturday", "Sunday") + * ``` + */ class InExpr extends AbstractCaseInsensitiveContainmentExpr { InExpr() { this.getKind() = 73 } @@ -291,24 +446,52 @@ abstract private class AbstractLogicalBinaryExpr extends BinaryExpr { } final class LogicalBinaryExpr = AbstractLogicalBinaryExpr; +/** + * A logical AND expression. For example: + * ``` + * $isValid = $isActive -and $hasPermission + * $canProceed = ($count -gt 0) -and ($status -eq "Ready") + * ``` + */ class LogicalAndExpr extends AbstractLogicalBinaryExpr { LogicalAndExpr() { this.getKind() = 53 } final override string toString() { result = "... -and ..." } } +/** + * A logical OR expression. For example: + * ``` + * $shouldProcess = $isUrgent -or $isHighPriority + * $hasAccess = ($isAdmin -or $isOwner) -and $isActive + * ``` + */ class LogicalOrExpr extends AbstractLogicalBinaryExpr { LogicalOrExpr() { this.getKind() = 54 } final override string toString() { result = "... -or ..." } } +/** + * A logical XOR expression. For example: + * ``` + * $exclusiveChoice = $option1 -xor $option2 + * $toggle = $currentState -xor $true + * ``` + */ class LogicalXorExpr extends AbstractLogicalBinaryExpr { LogicalXorExpr() { this.getKind() = 55 } final override string toString() { result = "... -xor ..." } } +/** + * A string join expression. For example: + * ``` + * $result = $array -join "," + * $path = $pathParts -join "\" + * ``` + */ class JoinExpr extends BinaryExpr { JoinExpr() { this.getKind() = 59 } @@ -321,6 +504,13 @@ class SequenceExpr extends BinaryExpr { final override string toString() { result = "[..]" } } +/** + * A format string expression. For example: + * ``` + * $formatted = "Hello {0}, you have {1} messages" -f $name, $count + * $output = "Value: {0:N2}" -f $number + * ``` + */ class FormatExpr extends BinaryExpr { FormatExpr() { this.getKind() = 50 } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/BoolLiteral.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/BoolLiteral.qll index 36fef4912da7..06bc990103f0 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/BoolLiteral.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/BoolLiteral.qll @@ -1,5 +1,12 @@ private import AstImport +/** + * A boolean literal. For example: + * ``` + * $true + * $false + * ``` + */ class BoolLiteral extends Literal, TBoolLiteral { final override string toString() { result = this.getValue().toString() } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/BreakStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/BreakStmt.qll index f04899c3e81a..d46d2604349d 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/BreakStmt.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/BreakStmt.qll @@ -1,5 +1,11 @@ private import AstImport +/** + * A break statement. For example: + * ``` + * break + * ``` + */ class BreakStmt extends GotoStmt, TBreakStmt { override string toString() { result = "break" } } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/CallExpr.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/CallExpr.qll index b7e756a2a8a0..f5e8c3dc6968 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/CallExpr.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/CallExpr.qll @@ -1,5 +1,13 @@ private import AstImport +/** + * A function or command call expression. For example: + * ``` + * Get-Process + * Write-Host "Hello World" + * $result = $myObj.foo() + * ``` + */ class CallExpr extends Expr, TCallExpr { /** Gets the i'th argument to this call. */ Expr getArgument(int i) { none() } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/CatchClause.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/CatchClause.qll index 3504e0f055ba..8996b82ad001 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/CatchClause.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/CatchClause.qll @@ -1,5 +1,12 @@ private import AstImport +/** + * A catch clause in a try-catch statement. For example: + * ``` + * catch [System.IO.FileNotFoundException] { Write-Host "File not found" } + * catch { Write-Host "General error: $($_.Exception.Message)" } + * ``` + */ class CatchClause extends Ast, TCatchClause { StmtBlock getBody() { exists(Raw::Ast r | r = getRawAst(this) | diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Command.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Command.qll index a2ae0bde31e0..907bcc3b8b2f 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/Command.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Command.qll @@ -1,5 +1,11 @@ private import AstImport +/** + * A call to a command (i.e., a function that is not a method). For example: + * ``` + * Get-Process + * ``` + */ class CmdCall extends CallExpr, TCmd { final override string getLowerCaseName() { result = getRawAst(this).(Raw::Cmd).getLowerCaseName() diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Configuration.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Configuration.qll index 7856efb5d946..ff675110d8c7 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/Configuration.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Configuration.qll @@ -1,5 +1,18 @@ private import AstImport +/** + * A DSC configuration (Desired State Configuration). For example: + * ``` + * Configuration MyConfig { + * Node "MyNode" { + * WindowsFeature MyFeature { + * Name = "Web-Server" + * Ensure = "Present" + * } + * } + * } + * ``` + */ class Configuration extends Stmt, TConfiguration { override string toString() { result = this.getName().toString() } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/ConstantExpression.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/ConstantExpression.qll index d2387c761b72..c20adbefdf99 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/ConstantExpression.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/ConstantExpression.qll @@ -1,5 +1,8 @@ private import AstImport +/** + * A constant expression. For example, the number `42` or the string `"hello"`. + */ class ConstExpr extends Expr, TConstExpr { string getValueString() { result = getRawAst(this).(Raw::ConstExpr).getValue().getValue() } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/ContinueStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/ContinueStmt.qll index 257378bbbb49..3acd91e33efd 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/ContinueStmt.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/ContinueStmt.qll @@ -1,5 +1,11 @@ private import AstImport +/** + * A continue statement. For example: + * ``` + * continue + * ``` + */ class ContinueStmt extends Stmt, TContinueStmt { override string toString() { result = "continue" } } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/ConvertExpr.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/ConvertExpr.qll index e799435c843b..54e404855105 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/ConvertExpr.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/ConvertExpr.qll @@ -1,5 +1,11 @@ private import AstImport +/** + * A type conversion expression. For example: + * ``` + * [int]$stringValue + * ``` + */ class ConvertExpr extends AttributedExprBase, TConvertExpr { override string toString() { result = "[...]..." } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/DataStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/DataStmt.qll index cf32bfb84572..9bee655563bc 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/DataStmt.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/DataStmt.qll @@ -1,5 +1,17 @@ private import AstImport +/** + * A data statement in a PowerShell DSC (Desired State Configuration) script. + * For example: + * ``` + * data Messages { + * @{ + * Welcome = "Hello!" + * Goodbye = "Bye!" + * } + * } + * ``` + */ class DataStmt extends Stmt, TDataStmt { override string toString() { result = "data {...}" } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/DoUntilStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/DoUntilStmt.qll index 415a248a09d3..1e75b4cd8856 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/DoUntilStmt.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/DoUntilStmt.qll @@ -1,5 +1,13 @@ private import AstImport +/** + * A do-until loop statement. For example: + * ``` + * do { + * $input = Read-Host + * } until ($input -eq "exit") + * ``` + */ class DoUntilStmt extends LoopStmt, TDoUntilStmt { override string toString() { result = "do...until..." } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/DoWhileStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/DoWhileStmt.qll index ab7099cefcb7..5668ac44b0c3 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/DoWhileStmt.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/DoWhileStmt.qll @@ -1,5 +1,13 @@ private import AstImport +/** + * A do-while loop statement. For example: + * ``` + * do { + * $input = Read-Host + * } while ($input -ne "exit") + * ``` + */ class DoWhileStmt extends LoopStmt, TDoWhileStmt { override string toString() { result = "do...while..." } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/DynamicStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/DynamicStmt.qll index 34bef60f2da1..0b7d79bdd6a1 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/DynamicStmt.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/DynamicStmt.qll @@ -1,5 +1,27 @@ private import AstImport +/** + * A `dynamicparam` statement. For example this declares a dynamic optional + * parameter named `MyParam`: + * ``` + * dynamicparam + * { + * $parameterAttribute = [System.Management.Automation.ParameterAttribute]@{ + * Mandatory = $false + * } + * + * $attributeCollection = [System.Collections.ObjectModel.Collection[System.Attribute]]::new() + * $attributeCollection.Add($parameterAttribute) + * + * $dynParam1 = [System.Management.Automation.RuntimeDefinedParameter]::new( + * 'MyParam', [int32], $attributeCollection + * ) + * + * $paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new() + * $paramDictionary.Add('MyParam', $dynParam1) + * return $paramDictionary + * } + */ class DynamicStmt extends Stmt, TDynamicStmt { override string toString() { result = "&..." } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/EnvVariable.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/EnvVariable.qll index 3bbd2bf2f485..d1c2e63de57a 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/EnvVariable.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/EnvVariable.qll @@ -1,5 +1,8 @@ private import AstImport +/** + * A PowerShell environment variable (for example, `$env:PATH`). + */ class EnvVariable extends Variable instanceof EnvVariableImpl { string getLowerCaseName() { result = super.getLowerCaseNameImpl() } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/ErrorExpr.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/ErrorExpr.qll index 154b80e8e920..af00e7a3b3cb 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/ErrorExpr.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/ErrorExpr.qll @@ -1,5 +1,8 @@ private import AstImport +/** + * An error expression that occurs when parsing fails. + */ class ErrorExpr extends Expr, TErrorExpr { final override string toString() { result = "error" } } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/ErrorStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/ErrorStmt.qll index 8528cf091154..17ece8dc7d35 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/ErrorStmt.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/ErrorStmt.qll @@ -1,5 +1,8 @@ private import AstImport +/** + * An error statement that occurs when parsing fails. + */ class ErrorStmt extends Stmt, TErrorStmt { final override string toString() { result = "error" } } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/ExitStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/ExitStmt.qll index 07cd97f343cd..7c87d2f6cb06 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/ExitStmt.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/ExitStmt.qll @@ -1,5 +1,8 @@ private import AstImport +/** + * An exit statement. For example `exit` or `exit 1`. + */ class ExitStmt extends Stmt, TExitStmt { Expr getPipeline() { exists(Raw::Ast r | r = getRawAst(this) | diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/ExpandableStringExpression.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/ExpandableStringExpression.qll index 98eb80f2c154..7a7cb3fc6ab6 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/ExpandableStringExpression.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/ExpandableStringExpression.qll @@ -1,5 +1,12 @@ private import AstImport +/** + * An expandable string expression with variable interpolation. For example: + * ``` + * "Hello $name, you have $count messages" + * "Current date: $(Get-Date)" + * ``` + */ class ExpandableStringExpr extends Expr, TExpandableStringExpr { string getUnexpandedValue() { result = getRawAst(this).(Raw::ExpandableStringExpr).getUnexpandedValue().getValue() diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/ExprStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/ExprStmt.qll index 3be667f62b46..c4d197cb0e1e 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/ExprStmt.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/ExprStmt.qll @@ -1,5 +1,16 @@ private import AstImport +/** + * An expression statement. This statement is inserted in the AST when a + * statement is required, but an expression is provided. For example in: + * ``` + * function CallFoo($x) { + * $x.foo() + * } + * ``` + * The body of `CallFoo` is a statement, but `$x.foo()` is an expression. So + * the first element in the body of `CallFoo` is an `ExprStmt`. + */ class ExprStmt extends Stmt, TExprStmt { override string toString() { result = "[Stmt] " + this.getExpr().toString() } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/ForEachStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/ForEachStmt.qll index a1abe00bb80d..e294223f97c6 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/ForEachStmt.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/ForEachStmt.qll @@ -1,5 +1,11 @@ private import AstImport +/** + * A foreach loop statement. For example: + * ``` + * foreach ($item in $collection) { Write-Host $item } + * ``` + */ class ForEachStmt extends LoopStmt, TForEachStmt { override string toString() { result = "forach(... in ...)" } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/ForStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/ForStmt.qll index 81de53fc52ec..e4dd6ae2cb9e 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/ForStmt.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/ForStmt.qll @@ -1,5 +1,13 @@ private import AstImport +/** + * A for loop statement. For example: + * ``` + * for ($i = 0; $i -lt 10; $i++) { + * Write-Host $i + * } + * ``` + */ class ForStmt extends LoopStmt, TForStmt { override string toString() { result = "for(...;...;...)" } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Function.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Function.qll index 42e16d921c6f..db92a8764ff9 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/Function.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Function.qll @@ -1,5 +1,14 @@ private import AstImport +/** + * A non-member function declaration. For example: + * ``` + * function My-Function { + * param($param1, $param2) + * Write-Host "Hello, World!" + * } + * ``` + */ class Function extends FunctionBase, TFunction { final override string getLowerCaseName() { any(Synthesis s).functionName(this, result) } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/FunctionBase.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/FunctionBase.qll index e238e668b648..75dd4636fb2d 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/FunctionBase.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/FunctionBase.qll @@ -1,6 +1,23 @@ private import AstImport private import semmle.code.powershell.controlflow.BasicBlocks +/** + * A non-member function or a method. For example: + * ``` + * function My-Function { + * param($param1, $param2) + * Write-Host "Hello, World!" + * } + * ``` + * or + * ``` + * class MyClass { + * [void] MyMethod($param1) { + * Write-Host "Hello, World!" + * } + * } + * ``` + */ class FunctionBase extends Ast, TFunctionBase { final override string toString() { result = this.getLowerCaseName() } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/FunctionDefinition.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/FunctionDefinition.qll index 9800fb647c6e..b24b86779752 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/FunctionDefinition.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/FunctionDefinition.qll @@ -1,5 +1,14 @@ private import AstImport +/** + * A function definition statement. For example: + * ``` + * function Get-Greeting { + * param($name) + * "Hello, $name!" + * } + * ``` + */ class FunctionDefinitionStmt extends Stmt, TFunctionDefinitionStmt { FunctionBase getFunction() { synthChild(getRawAst(this), funDefFun(), result) } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/GotoStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/GotoStmt.qll index af9c48ed97ca..7f623564a62a 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/GotoStmt.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/GotoStmt.qll @@ -1,5 +1,8 @@ private import AstImport +/** + * A goto statement. A goto statement is either a `break` or a `continue`. + */ class GotoStmt extends Stmt, TGotoStmt { Expr getLabel() { exists(Raw::Ast r | r = getRawAst(this) | diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/HashTable.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/HashTable.qll index ec6b914a9dba..6d5e71cbc6c5 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/HashTable.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/HashTable.qll @@ -1,5 +1,14 @@ private import AstImport +/** + * A hashtable expression. For example: + * ``` + * @{ + * "key1" = $value1; + * "key2" = $value2 + * } + * ``` + */ class HashTableExpr extends Expr, THashTableExpr { final override string toString() { result = "${...}" } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/If.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/If.qll index 4aa44a2359d0..586e53e75679 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/If.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/If.qll @@ -1,5 +1,17 @@ private import AstImport +/** + * An if statement. For example: + * ``` + * if ($a) { + * "First" + * } elseif ($b) { + * "Second" + * } else { + * "Default" + * } + * ``` + */ class If extends Expr, TIf { override string toString() { if this.hasElse() then result = "if (...) {...} else {...}" else result = "if (...) {...}" diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/IndexExpr.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/IndexExpr.qll index 9d52c12485c0..c1ee92845c58 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/IndexExpr.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/IndexExpr.qll @@ -1,5 +1,12 @@ private import AstImport +/** + * An index expression. For example: + * ``` + * $array[0] + * $hashtable["key"] + * ``` + */ class IndexExpr extends Expr, TIndexExpr { override string toString() { result = "...[...]" } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/InvokeMemberExpression.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/InvokeMemberExpression.qll index 9c870d9957a3..a95b08fc5bdc 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/InvokeMemberExpression.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/InvokeMemberExpression.qll @@ -1,5 +1,13 @@ private import AstImport +/** + * A method invocation expression. For example: + * ``` + * $process.Start() + * $string.ToUpper() + * $list.Add($item) + * ``` + */ class InvokeMemberExpr extends CallExpr, TInvokeMemberExpr { final override string getLowerCaseName() { result = getRawAst(this).(Raw::InvokeMemberExpr).getLowerCaseName() diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Literal.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Literal.qll index 9e8ad3d44698..8a1e65711598 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/Literal.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Literal.qll @@ -1,3 +1,6 @@ private import AstImport +/** + * A literal expression. For example, the literal `$null` or `$true`. + */ class Literal extends Expr, TLiteral { } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/LoopStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/LoopStmt.qll index d7ca83ab51a4..2e3014f52a77 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/LoopStmt.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/LoopStmt.qll @@ -1,5 +1,8 @@ private import AstImport +/** + * A statement that loops. For example, `for`, `foreach`, `while`, or `do` statements. + */ class LoopStmt extends Stmt, TLoopStmt { StmtBlock getBody() { none() } } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Member.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Member.qll index 8f38f0e6c86c..c210254631f0 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/Member.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Member.qll @@ -1,5 +1,18 @@ private import AstImport +/** + * A method or property member of a class. For example, in the following code, + * `Get-Name` is a member of the `Person` class, and `Name` is a property member. + * ``` + * class Person { + * [string] $Name + * + * [string] Get-Name() { + * return $this.Name + * } + * } + * ``` + */ class Member extends Ast, TMember { string getLowerCaseName() { result = getRawAst(this).(Raw::Member).getName().toLowerCase() diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/MemberExpr.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/MemberExpr.qll index 0060f891ecbc..dd35b7d03dd4 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/MemberExpr.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/MemberExpr.qll @@ -1,5 +1,11 @@ private import AstImport +/** + * A member access expression. For example: + * ``` + * $object.Property + * ``` + */ class MemberExpr extends Expr, TMemberExpr { Expr getQualifier() { exists(Raw::Ast r | r = getRawAst(this) | diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Method.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Method.qll index 8ce4df97f4d1..e4058dd58d71 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/Method.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Method.qll @@ -1,5 +1,15 @@ private import AstImport +/** + * A method declaration in a class. For example: + * ``` + * class MyClass { + * My-Method($param1, $param2) { + * Write-Host "Hello, World!" + * } + * } + * ``` + */ class Method extends Member, FunctionBase, TMethod { final override string getLowerCaseName() { result = Member.super.getLowerCaseName() } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/NamedAttributeArgument.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/NamedAttributeArgument.qll index 57d8722e8b38..47d5841306ec 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/NamedAttributeArgument.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/NamedAttributeArgument.qll @@ -1,5 +1,10 @@ private import AstImport +/** + * A named argument in an attribute. For example, in + * `[Parameter(Mandatory=$true)]`, `Mandatory=$true` is a named attribute + * argument. + */ class NamedAttributeArgument extends Ast, TNamedAttributeArgument { final override string toString() { result = this.getName() } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/NamedBlock.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/NamedBlock.qll index 6f162c6e1a87..71fea959f970 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/NamedBlock.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/NamedBlock.qll @@ -1,5 +1,22 @@ private import AstImport +/** + * A named block in a script block, function, or method. For example, the + * `process`, `begin`, or `end` block in: + * ``` + * function My-Function { + * begin { + * Write-Host "Starting..." + * } + * process { + * Write-Host "Processing..." + * } + * end { + * Write-Host "Done!" + * } + * } + * ``` + */ class NamedBlock extends Ast, TNamedBlock { override string toString() { result = "{...}" } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/NullLiteral.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/NullLiteral.qll index 5bba004042ca..37777806b38b 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/NullLiteral.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/NullLiteral.qll @@ -1,5 +1,11 @@ private import AstImport +/** + * A null literal. For example: + * ``` + * $null + * ``` + */ class NullLiteral extends Literal, TNullLiteral { final override string toString() { result = this.getValue().toString() } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Operation.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Operation.qll index a2e1e4547e54..661f7aab455c 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/Operation.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Operation.qll @@ -1,5 +1,9 @@ private import AstImport +/** + * An operation expression. For example, a binary operation like `1 + 2` or a + * unary operation like `-1`. + */ class Operation extends Expr, TOperation { Expr getAnOperand() { none() } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Parameter.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Parameter.qll index 1b471bc5a0de..9ed97a36396a 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/Parameter.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Parameter.qll @@ -1,5 +1,14 @@ private import AstImport +/** + * A function or script parameter. For example in a parameter block: + * ``` + * param([string]$Name, [int]$Age = 25) + * ``` + * or as a function parameter: + * function Test([string]$Name, [int]$Age = 25) { ... } + * ``` + */ class Parameter extends Variable instanceof ParameterImpl { string getLowerCaseName() { result = super.getLowerCaseNameImpl() } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/ParenExpr.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/ParenExpr.qll index b4b9c48e4cd4..8758859c01c5 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/ParenExpr.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/ParenExpr.qll @@ -1,5 +1,11 @@ private import AstImport +/** + * A parenthesized expression. For example: + * ``` + * ($a + $b) + * ``` + */ class ParenExpr extends Expr, TParenExpr { override string toString() { result = "(...)" } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Pipeline.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Pipeline.qll index fd4011f41198..25e33590cc58 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/Pipeline.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Pipeline.qll @@ -1,5 +1,11 @@ private import AstImport +/** + * A pipeline expression. For example: + * ``` + * Get-Process | Where-Object { $_.CPU -gt 100 } + * ``` + */ class Pipeline extends Expr, TPipeline { override string toString() { if this.getNumberOfComponents() = 1 diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/PipelineChain.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/PipelineChain.qll index 964d5219ae0d..5c33fb845267 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/PipelineChain.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/PipelineChain.qll @@ -1,5 +1,12 @@ private import AstImport +/** + * A pipeline chain expression. For example: + * ``` + * Get-Process && Write-Host "Success" + * Test-Path $file || Write-Host "File not found" + * ``` + */ class PipelineChain extends Expr, TPipelineChain { predicate isBackground() { getRawAst(this).(Raw::PipelineChain).isBackground() } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/PropertyMember.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/PropertyMember.qll index 247e10dab2dc..8d5dd4c9787c 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/PropertyMember.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/PropertyMember.qll @@ -1,5 +1,13 @@ private import AstImport +/** + * A property member of a class. For example: + * ``` + * class MyClass { + * [string]$MyProperty + * } + * ``` + */ class PropertyMember extends Member, TPropertyMember { final override string getLowerCaseName() { result = getRawAst(this).(Raw::PropertyMember).getName().toLowerCase() } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Redirection.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Redirection.qll index 050c59286e13..8c172bc38010 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/Redirection.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Redirection.qll @@ -1,5 +1,11 @@ private import AstImport +/** + * A redirection expression. For example, `>` in: + * ``` + * Get-Process > processes.txt + * ``` + */ class Redirection extends Ast, TRedirection { Expr getExpr() { exists(Raw::Ast r | r = getRawAst(this) | diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/ReturnStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/ReturnStmt.qll index d54937316547..3f2c1e2b0cc0 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/ReturnStmt.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/ReturnStmt.qll @@ -1,5 +1,8 @@ private import AstImport +/** + * A return statement. For example `return $result` or `return`. + */ class ReturnStmt extends Stmt, TReturnStmt { override string toString() { if this.hasPipeline() then result = "return ..." else result = "return" diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/ScriptBlock.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/ScriptBlock.qll index 899bb8d805a8..dbdd3905b103 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/ScriptBlock.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/ScriptBlock.qll @@ -1,5 +1,8 @@ private import AstImport +/** + * A script block. For example, the body of a function or a script file. + */ class ScriptBlock extends Ast, TScriptBlock { override string toString() { if this.isTopLevel() diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/ScriptBlockExpr.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/ScriptBlockExpr.qll index 1bfc559e66a7..d78dc00bd53b 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/ScriptBlockExpr.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/ScriptBlockExpr.qll @@ -1,5 +1,11 @@ private import AstImport +/** + * A script block expression. For example: + * ``` + * $callback = { Write-Host "Done!" } + * ``` + */ class ScriptBlockExpr extends Expr, TScriptBlockExpr { override string toString() { result = "{...}" } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Statement.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Statement.qll index 802413b3865e..e3da5389c00d 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/Statement.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Statement.qll @@ -1,3 +1,6 @@ private import AstImport +/** + * A statement. This is the base class for all statements. + */ class Stmt extends Ast, TStmt { } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/StatementBlock.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/StatementBlock.qll index 58a0fb1a19aa..e38752338435 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/StatementBlock.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/StatementBlock.qll @@ -1,5 +1,15 @@ private import AstImport +/** + * A sequence of statements, possibly including trap statements. For example: + * ``` + * { + * $a = 1 + * $b = 2 + * $c = 3 + * } + * ``` + */ class StmtBlock extends Stmt, TStmtBlock { pragma[nomagic] Stmt getStmt(int i) { diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Stmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Stmt.qll deleted file mode 100644 index 802413b3865e..000000000000 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/Stmt.qll +++ /dev/null @@ -1,3 +0,0 @@ -private import AstImport - -class Stmt extends Ast, TStmt { } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/StringConstantExpression.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/StringConstantExpression.qll index 95261d31052f..b3e82144646c 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/StringConstantExpression.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/StringConstantExpression.qll @@ -1,5 +1,8 @@ private import AstImport +/** + * A constant string expression. For example, the string `"hello"` or `'world'`. + */ class StringConstExpr extends Expr, TStringConstExpr { string getValueString() { result = getRawAst(this).(Raw::StringConstExpr).getValue().getValue() } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/StringLiteral.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/StringLiteral.qll index 7a25cc89820f..fd4bf1b30f4e 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/StringLiteral.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/StringLiteral.qll @@ -1,5 +1,11 @@ private import AstImport +/** + * A string literal. For example: + * ``` + * "Hello World" + * ``` + */ // TODO: A string literal should ideally be the string constants that are // surrounded by quotes (single or double), but we don't yet extract that // information. So for now we just use the StringConstExpr class, which is diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/SubExpression.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/SubExpression.qll index 2208828595a8..c08a2e8a3343 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/SubExpression.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/SubExpression.qll @@ -1,5 +1,11 @@ private import AstImport +/** + * An expandable sub-expression. For example `$(Get-Date)` in: + * ``` + * "Hello $(Get-Date)" + * ``` + */ class ExpandableSubExpr extends Expr, TExpandableSubExpr { StmtBlock getExpr() { exists(Raw::Ast r | r = getRawAst(this) | diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/SwitchStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/SwitchStmt.qll index ed3ec27ef2fe..5b3cba1feb60 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/SwitchStmt.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/SwitchStmt.qll @@ -1,5 +1,15 @@ private import AstImport +/** + * A switch statement. For example: + * ``` + * switch ($day) { + * "Monday" { "Start of the week" } + * "Friday" { "TGIF!" } + * default { "Regular day" } + * } + * ``` + */ class SwitchStmt extends Stmt, TSwitchStmt { final override string toString() { result = "switch(...) {...}" } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/TAst.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/TAst.qll index cda32d1b2fa8..145c09d88d97 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/TAst.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/TAst.qll @@ -218,7 +218,7 @@ private module Cached { class TVarAccess = TVarAccessReal or TVarAccessSynth; - class TLiteral = TBoolLiteral or TNullLiteral; + class TLiteral = TBoolLiteral or TNullLiteral; // TODO: Numbers and strings? class TGotoStmt = TContinueStmt or TBreakStmt; diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/TernaryExpression.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/TernaryExpression.qll index 022a3675dcd4..6c52f5ef7e31 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/TernaryExpression.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/TernaryExpression.qll @@ -1,5 +1,11 @@ private import AstImport +/** + * A ternary conditional expression. For example: + * ``` + * $result = $condition ? "true" : "false" + * ``` + */ class ConditionalExpr extends Expr, TConditionalExpr { override string toString() { result = "...?...:..." } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/ThisExpr.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/ThisExpr.qll index e93e01f6399c..9e5911a25e07 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/ThisExpr.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/ThisExpr.qll @@ -1,5 +1,12 @@ private import AstImport +/** + * A this expression. For example: + * ``` + * $this.PropertyName + * $this.Method() + * ``` + */ class ThisExpr extends Expr, TThisExpr { final override string toString() { result = "this" } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/ThrowStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/ThrowStmt.qll index 0b8ed0fe7c80..2bef72be845d 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/ThrowStmt.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/ThrowStmt.qll @@ -1,5 +1,13 @@ private import AstImport +/** + * A throw statement. For example: + * ``` + * throw "An error occurred" + * throw [System.ArgumentException]::new("Invalid argument") + * throw + * ``` + */ class ThrowStmt extends Stmt, TThrowStmt { Expr getPipeline() { exists(Raw::Ast r | r = getRawAst(this) | diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/TrapStatement.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/TrapStatement.qll index 498522051253..75a025b242a2 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/TrapStatement.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/TrapStatement.qll @@ -1,5 +1,13 @@ private import AstImport +/** + * A trap statement. For example: + * ``` + * trap { + * Write-Host "An error occurred" + * } + * ``` + */ class TrapStmt extends Stmt, TTrapStmt { StmtBlock getBody() { exists(Raw::Ast r | r = getRawAst(this) | diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/TryStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/TryStmt.qll index 78d6dd8eba69..5f2047063c1b 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/TryStmt.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/TryStmt.qll @@ -1,5 +1,17 @@ private import AstImport +/** + * A try-catch-finally statement. For example: + * ``` + * try { + * Get-Item "nonexistent.txt" + * } catch { + * Write-Host "File not found" + * } finally { + * Write-Host "Cleanup complete" + * } + * ``` + */ class TryStmt extends Stmt, TTryStmt { CatchClause getCatchClause(int i) { exists(ChildIndex index, Raw::Ast r | index = tryStmtCatchClause(i) and r = getRawAst(this) | diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Type.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Type.qll index cc0195adbc49..f2e1e9a7f133 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/Type.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Type.qll @@ -1,5 +1,14 @@ private import AstImport +/** + * A class declaration. For example: + * ``` + * class MyClass { + * [string]$property1 + * [int]$property2 + * } + * ``` + */ class Type extends Ast, TTypeSynth { override string toString() { result = this.getLowerCaseName() } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/TypeConstraint.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/TypeConstraint.qll index 8085a3832aee..e118e087e6fb 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/TypeConstraint.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/TypeConstraint.qll @@ -1,5 +1,11 @@ private import AstImport +/** + * A type constraint on a parameter or variable. For example, the `[string]` in: + * ``` + * param ([string]$name) + * [string]$str = "" + */ class TypeConstraint extends Ast, TTypeConstraint { string getName() { result = getRawAst(this).(Raw::TypeConstraint).getName() } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/TypeDefinitionStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/TypeDefinitionStmt.qll index 88e080266ba5..aedc40ddf205 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/TypeDefinitionStmt.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/TypeDefinitionStmt.qll @@ -1,5 +1,15 @@ private import AstImport +/** + * A type definition statement. For example: + * ``` + * class Person { + * [string]$Name + * [int]$Age + * Person([string]$name) { $this.Name = $name } + * } + * ``` + */ class TypeDefinitionStmt extends Stmt, TTypeDefinitionStmt { string getLowerCaseName() { result = getRawAst(this).(Raw::TypeStmt).getName().toLowerCase() } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/TypeExpression.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/TypeExpression.qll index 2d994035ac3e..7d9e8f772935 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/TypeExpression.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/TypeExpression.qll @@ -1,5 +1,10 @@ private import AstImport +/** + * A type expression. For example, the string `MyNamespace.MyClass` in: + * ``` + * [MyNamespace.MyClass]$obj = [MyNamespace.MyClass]::new() + */ class TypeNameExpr extends Expr, TTypeNameExpr { private predicate parseName(string namespace, string typename) { exists(string fullName | fullName = this.getPossiblyQualifiedName() | diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/UnaryExpression.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/UnaryExpression.qll index 860dddfc65b3..8b939fdb1d79 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/UnaryExpression.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/UnaryExpression.qll @@ -1,5 +1,14 @@ private import AstImport +/** + * A unary expression. For example: + * ``` + * -$number + * !$condition + * -not $isActive + * ++$counter + * ``` + */ class UnaryExpr extends Expr, TUnaryExpr { final override Ast getChild(ChildIndex i) { result = super.getChild(i) @@ -20,6 +29,14 @@ class UnaryExpr extends Expr, TUnaryExpr { } } +/** + * A logical negation expression. For example: + * ``` + * !$condition + * -not $isActive + * -not ($count -eq 0) + * ``` + */ class NotExpr extends UnaryExpr { NotExpr() { this.getKind() = [36, 51] } @@ -54,12 +71,26 @@ final class IncrExpr = AbstractIncrExpr; final class DecrExpr = AbstractDecrExpr; +/** + * A postfix increment expression. For example: + * ``` + * $counter++ + * $index++ + * ``` + */ class PostfixIncrExpr extends AbstractPostfixExpr, AbstractIncrExpr { PostfixIncrExpr() { this.getKind() = 95 } final override string toString() { result = "...++" } } +/** + * A postfix decrement expression. For example: + * ``` + * $counter-- + * $index-- + * ``` + */ class PostfixDecrExpr extends AbstractPostfixExpr, AbstractIncrExpr { PostfixDecrExpr() { this.getKind() = 96 } @@ -72,12 +103,27 @@ class PrefixDecrExpr extends AbstractPostfixExpr, AbstractIncrExpr { final override string toString() { result = "--..." } } +/** + * A prefix increment expression. For example: + * ``` + * ++$counter + * ++$index + * ``` + */ class PrefixIncrExpr extends AbstractPostfixExpr, AbstractIncrExpr { PrefixIncrExpr() { this.getKind() = 32 } final override string toString() { result = "++..." } } +/** + * A numeric negation expression. For example: + * ``` + * -$number + * -42 + * -($a + $b) + * ``` + */ class NegateExpr extends AbstractUnaryArithmeticExpr { NegateExpr() { this.getKind() = 41 } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/UsingExpression.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/UsingExpression.qll index 32848d397dd1..5e4cd411cbe1 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/UsingExpression.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/UsingExpression.qll @@ -1,5 +1,11 @@ private import AstImport +/** + * A using expression. For example: + * ``` + * Invoke-Command -ComputerName $server -ScriptBlock { $using:data } + * ``` + */ class UsingExpr extends Expr, TUsingExpr { override string toString() { result = "$using..." } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/UsingStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/UsingStmt.qll index d649560bcd98..dfff7f55b44d 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/UsingStmt.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/UsingStmt.qll @@ -1,5 +1,13 @@ private import AstImport +/** + * A using statement. For example: + * ``` + * using namespace System.Collections.Generic + * using module MyModule + * using assembly System.Net.Http + * ``` + */ class UsingStmt extends Stmt, TUsingStmt { override string toString() { result = "using ..." } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Variable.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Variable.qll index 41f374373426..57537682fa4d 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/Variable.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Variable.qll @@ -149,6 +149,14 @@ module Private { private import Private module Public { + /** + * A variable. For example: + * ``` + * $name = "John" + * $global:config = @{} + * $script:counter = 0 + * ``` + */ class Variable extends Ast instanceof VariableImpl { final string getLowerCaseName() { result = super.getLowerCaseNameImpl() } @@ -169,6 +177,15 @@ module Public { VarAccess getAnAccess() { result.getVariable() = this } } + /** + * A variable access. For example: + * ``` + * $name + * $global:config + * $script:counter + * $_ + * ``` + */ class VarAccess extends Expr instanceof VarAccessImpl { Variable getVariable() { result = super.getVariableImpl() } @@ -179,10 +196,22 @@ module Public { predicate isImplicitWrite() { implicitAssignment(getRawAst(this)) } } + /** + * A variable access that is written to. For example: + * ``` + * $name = "John" + * ``` + */ class VarWriteAccess extends VarAccess { VarWriteAccess() { this.isExplicitWrite(_) or this.isImplicitWrite() } } + /** + * A variable access that is read from. For example: + * ``` + * Write-Host $name + * ``` + */ class VarReadAccess extends VarAccess { VarReadAccess() { not this instanceof VarWriteAccess } } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/WhileStmt.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/WhileStmt.qll index d8817a6b0371..db1ca10a081c 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/WhileStmt.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/WhileStmt.qll @@ -1,5 +1,11 @@ private import AstImport +/** + * A while loop statement. For example: + * ``` + * while ($count -lt 10) { $count++ } + * ``` + */ class WhileStmt extends LoopStmt, TWhileStmt { override string toString() { result = "while(...) {...}" }