diff --git a/.github/instructions/library.instructions.md b/.github/instructions/library.instructions.md index 3192098..00383c0 100644 --- a/.github/instructions/library.instructions.md +++ b/.github/instructions/library.instructions.md @@ -249,6 +249,8 @@ Predicates such as `toString`, `getAPrimaryQlClass`, and `getAPrimaryQlModule` s ## Testing +- Follow: [Testing custom queries](https://docs.github.com/en/code-security/codeql-cli/using-the-advanced-functionality-of-the-codeql-cli/testing-custom-queries) best practices + All tests should be stored in the `ql/tests/library-tests/` directory. AST, CFG, and Dataflow tests should be stored in the `ql/tests/library-tests/ast`, `ql/tests/library-tests/cfg`, and `ql/tests/library-tests/dataflow` directories respectively. diff --git a/.github/instructions/queries.instructions.md b/.github/instructions/queries.instructions.md index 3ba404f..133b848 100644 --- a/.github/instructions/queries.instructions.md +++ b/.github/instructions/queries.instructions.md @@ -111,6 +111,8 @@ The documentation should include: ## Testing Query +- Follow: [Testing custom queries](https://docs.github.com/en/code-security/codeql-cli/using-the-advanced-functionality-of-the-codeql-cli/testing-custom-queries) best practices + After generating the query, run the CodeQL test command to ensure the query passes all tests. Use the `codeql-test` command to run the tests on the query file. diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml new file mode 100644 index 0000000..93fcd05 --- /dev/null +++ b/.github/workflows/copilot-setup-steps.yml @@ -0,0 +1,62 @@ +--- +name: "Copilot Setup Steps" + +# Automatically run the setup steps when they are changed to allow for +# easy validation, and manual testing through the repository's Actions tab +on: + workflow_dispatch: {} + push: + paths: + - .github/workflows/copilot-setup-steps.yml + pull_request: + paths: + - .github/workflows/copilot-setup-steps.yml + +# Set the GH_TOKEN environment variable globally +# This appears to not work in a copilot-setup-steps +env: + GH_TOKEN: ${{ github.token }} + +jobs: + # The job MUST be called `copilot-setup-steps` or it will not be picked up + # by Copilot. + copilot-setup-steps: + runs-on: ubuntu-latest + + # Set the permissions to the lowest permissions possible needed for your + # steps. Copilot will be given its own token for its operations. + permissions: + # If you want to clone the repository as part of your setup steps, for + # example to install dependencies, you'll need the `contents: read` + # permission. If you don't clone the repository in your setup steps, + # Copilot will do this for you automatically after the steps complete. + contents: read + + # You can define any steps you want, and they will run before the agent + # starts. If you do not check out your code, Copilot will do this for you. + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + submodules: true + + - name: Install GitHub CLI CodeQL extension + env: + GH_TOKEN: ${{ github.token }} + run: | + # Install GitHub CLI (should already be available in ubuntu-latest) + gh --version + + # Install CodeQL CLI extension + gh extension install github/gh-codeql + + # Set CodeQL to latest version + gh codeql set-version latest + + # Verify the extension is installed and working + gh codeql version + + #install packs + (cd ./ql/src/ && gh codeql pack install) + (cd ./ql/lib/ && gh codeql pack install) + (cd ./ql/test/ && gh codeql pack install) diff --git a/ql/lib/codeql/bicep/AST.qll b/ql/lib/codeql/bicep/AST.qll index 5798087..36009a9 100644 --- a/ql/lib/codeql/bicep/AST.qll +++ b/ql/lib/codeql/bicep/AST.qll @@ -9,3 +9,4 @@ import ast.Misc import ast.Idents import ast.Variables import ast.Resources +import ast.Types diff --git a/ql/lib/codeql/bicep/ast/Calls.qll b/ql/lib/codeql/bicep/ast/Calls.qll index 6b889a5..41e4d2c 100644 --- a/ql/lib/codeql/bicep/ast/Calls.qll +++ b/ql/lib/codeql/bicep/ast/Calls.qll @@ -3,6 +3,7 @@ private import Expr private import Stmts private import Idents private import Misc +private import Types private import internal.Calls private import internal.CallExpression private import internal.LambdaExpression diff --git a/ql/lib/codeql/bicep/ast/Conditionals.qll b/ql/lib/codeql/bicep/ast/Conditionals.qll index 2e89e27..90ea2b4 100644 --- a/ql/lib/codeql/bicep/ast/Conditionals.qll +++ b/ql/lib/codeql/bicep/ast/Conditionals.qll @@ -5,6 +5,7 @@ private import Expr private import Stmts private import internal.Conditionals +private import internal.IfStatement class Conditionals extends Stmts instanceof ConditionalsImpl { @@ -24,4 +25,34 @@ private import internal.Conditionals * this branch is selected in a switch/match statement. */ StmtSequence getBranch() { result = ConditionalsImpl.super.getBranch() } +} + + +/** + * An if statement in the AST. + * + * Represents a conditional statement in Bicep that executes certain code + * only when a specific condition is true. If statements enable conditional + * resource creation or property setting based on input parameters or other factors. + */ +class IfStatement extends Stmts instanceof IfStatementImpl { + /** + * Gets the condition of the if statement. + * + * This is the expression that is evaluated to determine whether + * the body of the if statement should be executed. + * + * @return The condition expression + */ + Expr getCondition() { result = IfStatementImpl.super.getCondition() } + + /** + * Gets the body of the if statement. + * + * This is the expression or block that will be executed if the + * condition evaluates to true. + * + * @return The body expression + */ + Expr getBody() { result = IfStatementImpl.super.getBody() } } \ No newline at end of file diff --git a/ql/lib/codeql/bicep/ast/Idents.qll b/ql/lib/codeql/bicep/ast/Idents.qll index 028da75..b0332a8 100644 --- a/ql/lib/codeql/bicep/ast/Idents.qll +++ b/ql/lib/codeql/bicep/ast/Idents.qll @@ -3,6 +3,7 @@ private import Expr private import internal.Idents private import internal.Identifier private import internal.PropertyIdentifier +private import internal.CompatibleIdentifier /** * The base class for all identifiers in the AST. @@ -42,6 +43,15 @@ class Identifier extends Idents instanceof IdentifierImpl { * Represents the name part of a property in an object literal. For example, * in the property `name: 'example'`, `name` is represented by a PropertyIdentifier. * Property identifiers are used as keys in object literals. + * + * In Bicep, property identifiers appear in object literals and resource declarations: + * + * ```bicep + * var myObject = { + * name: 'value', // 'name' is a PropertyIdentifier + * type: 'string' // 'type' is a PropertyIdentifier + * } + * ``` */ class PropertyIdentifier extends Idents instanceof PropertyIdentifierImpl { /** @@ -51,3 +61,26 @@ class PropertyIdentifier extends Idents instanceof PropertyIdentifierImpl { */ override string getName() { result = PropertyIdentifierImpl.super.getName() } } + +/** + * A compatible identifier in the AST. + * + * Represents an identifier that is compatible with certain naming conventions. + * Compatible identifiers are often used when a standard identifier is needed + * in contexts that have specific compatibility requirements. + */ +class CompatibleIdentifier extends Idents instanceof CompatibleIdentifierImpl { + /** + * Gets the name of this compatible identifier as a string. + * + * @return The name of this compatible identifier + */ + override string getName() { result = CompatibleIdentifierImpl.super.getName() } + + /** + * Gets the underlying identifier. + * + * @return The underlying identifier + */ + Identifier getIdentifier() { result = CompatibleIdentifierImpl.super.getIdentifier() } +} diff --git a/ql/lib/codeql/bicep/ast/Misc.qll b/ql/lib/codeql/bicep/ast/Misc.qll index 79568c7..4cda2bf 100644 --- a/ql/lib/codeql/bicep/ast/Misc.qll +++ b/ql/lib/codeql/bicep/ast/Misc.qll @@ -1,41 +1,19 @@ private import AstNodes private import internal.Array -private import internal.ArrayType private import internal.Boolean -private import internal.CompatibleIdentifier private import internal.Decorator private import internal.Decorators private import internal.DiagnosticComment private import internal.EscapeSequence private import internal.ForLoopParameters -private import internal.Identifier private import internal.ImportFunctionality private import internal.LoopEnumerator private import internal.LoopVariable private import internal.MetadataDeclaration private import internal.ModuleDeclaration -private import internal.NegatedType private import internal.ObjectProperty -private import internal.ParameterizedType -private import internal.ParenthesizedType -private import internal.PrimitiveType -private import internal.PropertyIdentifier private import internal.TargetScopeAssignment private import internal.TestBlock -private import internal.Type -private import internal.TypeArguments -private import internal.TypeDeclaration -private import internal.UnionType - -/** - * A ArrayType unknown AST node. - */ -class ArrayType extends AstNode instanceof ArrayTypeImpl { } - -/** - * A CompatibleIdentifier unknown AST node. - */ -class CompatibleIdentifier extends AstNode instanceof CompatibleIdentifierImpl { } /** * A Decorator unknown AST node. @@ -87,26 +65,6 @@ class MetadataDeclaration extends AstNode instanceof MetadataDeclarationImpl { } */ class ModuleDeclaration extends AstNode instanceof ModuleDeclarationImpl { } -/** - * A NegatedType unknown AST node. - */ -class NegatedType extends AstNode instanceof NegatedTypeImpl { } - -/** - * A ParameterizedType unknown AST node. - */ -class ParameterizedType extends AstNode instanceof ParameterizedTypeImpl { } - -/** - * A ParenthesizedType unknown AST node. - */ -class ParenthesizedType extends AstNode instanceof ParenthesizedTypeImpl { } - -/** - * A PrimitiveType unknown AST node. - */ -class PrimitiveType extends AstNode instanceof PrimitiveTypeImpl { } - /** * A TargetScopeAssignment unknown AST node. */ @@ -116,38 +74,3 @@ class TargetScopeAssignment extends AstNode instanceof TargetScopeAssignmentImpl * A TestBlock unknown AST node. */ class TestBlock extends AstNode instanceof TestBlockImpl { } - -/** - * A type node in the AST. - * - * This class represents all type annotations in Bicep, including primitive types - * (like string, int, bool), complex types (like arrays, objects), and user-defined - * types. Types are used in parameter declarations, variable declarations, function - * return types, and other contexts to specify the kind of values that are expected. - */ -class Type extends AstNode instanceof TypeImpl { - /** - * Gets the name of this type as a string. - * - * For primitive types, this will be the name of the type (e.g., "string", "int"). - * For complex types, this will be a representation of the type structure. - * - * @return The type name or representation as a string - */ - string getType() { result = TypeImpl.super.getType() } -} - -/** - * A TypeArguments unknown AST node. - */ -class TypeArguments extends AstNode instanceof TypeArgumentsImpl { } - -/** - * A TypeDeclaration unknown AST node. - */ -class TypeDeclaration extends AstNode instanceof TypeDeclarationImpl { } - -/** - * A UnionType unknown AST node. - */ -class UnionType extends AstNode instanceof UnionTypeImpl { } diff --git a/ql/lib/codeql/bicep/ast/Stmts.qll b/ql/lib/codeql/bicep/ast/Stmts.qll index abb526a..35c21e9 100644 --- a/ql/lib/codeql/bicep/ast/Stmts.qll +++ b/ql/lib/codeql/bicep/ast/Stmts.qll @@ -7,6 +7,7 @@ private import Idents private import Expr private import Calls private import Misc +private import Types private import internal.AstNodes private import internal.TreeSitter private import internal.Stmts @@ -52,6 +53,8 @@ class Stmts extends AstNode instanceof StmtsImpl { * @return A control-flow entry node for this statement */ AstNode getAControlFlowEntryNode() { result = CfgImpl::getAControlFlowEntryNode(this) } + + Expr getExpr() { result = StmtsImpl.super.getExpr() } } /** @@ -102,45 +105,8 @@ class StmtSequence extends AstNode instanceof StmtSequenceImpl { * and raises an error if the condition is false. Assert statements are * useful for validating assumptions and ensuring inputs meet expected criteria. */ -final class AssertStatementStmt extends Stmts instanceof AssertStatementImpl { } - -/** - * A for statement in the AST. - * - * Represents a for loop in Bicep, which iterates over a collection of items. - * For loops are commonly used for creating multiple instances of resources - * or for processing arrays of configuration data. - */ -final class ForStatementStmt extends Stmts instanceof ForStatementImpl { } - -/** - * An if statement in the AST. - * - * Represents a conditional statement in Bicep that executes certain code - * only when a specific condition is true. If statements enable conditional - * resource creation or property setting based on input parameters or other factors. - */ -class IfStatement extends Stmts instanceof IfStatementImpl { - /** - * Gets the condition of the if statement. - * - * This is the expression that is evaluated to determine whether - * the body of the if statement should be executed. - * - * @return The condition expression - */ - Expr getCondition() { result = IfStatementImpl.super.getCondition() } +class AssertStatement extends Stmts instanceof AssertStatementImpl { } - /** - * Gets the body of the if statement. - * - * This is the expression or block that will be executed if the - * condition evaluates to true. - * - * @return The body expression - */ - Expr getBody() { result = IfStatementImpl.super.getBody() } -} /** * An import statement in the AST. @@ -149,7 +115,7 @@ class IfStatement extends Stmts instanceof IfStatementImpl { * namespaces, or resources into the current scope. Import statements enable * code reuse and modularization of Bicep templates. */ -final class ImportStatementStmt extends Stmts instanceof ImportStatementImpl { } +class ImportStatement extends Stmts instanceof ImportStatementImpl { } /** * An infrastructure node in the AST. @@ -322,7 +288,7 @@ class Parameters extends Expr instanceof ParametersImpl { * Import-with statements allow importing external modules with specific settings * or transformations applied to the imported items. */ -final class ImportWithStatementStmt extends Stmts instanceof ImportWithStatementImpl { } +class ImportWithStatement extends Stmts instanceof ImportWithStatementImpl { } /** * A using statement in the AST. @@ -331,4 +297,4 @@ final class ImportWithStatementStmt extends Stmts instanceof ImportWithStatement * an imported module or namespace. Using statements help improve readability * by allowing shorter references to external resources. */ -final class UsingStatementStmt extends Stmts instanceof UsingStatementImpl { } +class UsingStatement extends Stmts instanceof UsingStatementImpl { } diff --git a/ql/lib/codeql/bicep/ast/Types.qll b/ql/lib/codeql/bicep/ast/Types.qll new file mode 100644 index 0000000..d32ded7 --- /dev/null +++ b/ql/lib/codeql/bicep/ast/Types.qll @@ -0,0 +1,171 @@ +private import Expr +private import AstNodes +private import internal.Types +private import internal.Type +private import internal.ArrayType +private import internal.NegatedType +private import internal.ParameterizedType +private import internal.ParenthesizedType +private import internal.PrimitiveType +private import internal.TypeArguments +private import internal.TypeDeclaration +private import internal.UnionType + +/** + * The Super Type + */ +class Types extends Expr instanceof TypesImpl { + string getValue() { result = super.getValue() } +} + +/** + * A type node in the AST. + * + * This class represents all type annotations in Bicep, including primitive types + * (like string, int, bool), complex types (like arrays, objects), and user-defined + * types. Types are used in parameter declarations, variable declarations, function + * return types, and other contexts to specify the kind of values that are expected. + */ +class Type extends Types instanceof TypeImpl { + /** + * Gets the name of this type as a string. + * + * For primitive types, this will be the name of the type (e.g., "string", "int"). + * For complex types, this will be a representation of the type structure. + * + * @return The type name or representation as a string + */ + string getType() { result = TypeImpl.super.getType() } +} + +/** + * An array type node in the AST. + * + * This class represents array type annotations in Bicep (e.g., `string[]`). + * Array types are used to specify that a value should be an array of elements + * of the specified element type. + * + * Example: + * ```bicep + * param names string[] // Array of strings + * ``` + */ +class ArrayType extends Types instanceof ArrayTypeImpl { + /** + * Gets the element type of this array type. + * + * For example, in `string[]`, this returns the `string` type. + * + * @return The element type of the array + */ + Type getElementType() { + result = ArrayTypeImpl.super.getElementType() + } +} + +/** + * A negated type node in the AST. + * + * This class represents negated type annotations in Bicep (e.g., `!string`). + * Negated types are used to specify that a value should not be of the specified type. + * + * Example: + * ```bicep + * param value !string // Any type except string + * ``` + */ +class NegatedType extends Types instanceof NegatedTypeImpl { + /** + * Gets the negated type. + * + * For example, in `!string`, this returns the `string` type. + * + * @return The negated type + */ + Type getNegatedType() { + result = NegatedTypeImpl.super.getNegatedType() + } +} + +/** + * A parameterized type node in the AST. + * + * This class represents parameterized type annotations in Bicep. + * Parameterized types are generic types with type parameters. + * + * Example: + * ```bicep + * param values array // Array of strings + * ``` + */ +class ParameterizedType extends Types instanceof ParameterizedTypeImpl { } + +/** + * A parenthesized type node in the AST. + * + * This class represents parenthesized type annotations in Bicep (e.g., `(string|int)`). + * Parenthesized types are used to group types for clarity or precedence. + * + * Example: + * ```bicep + * param value (string|int) // Either string or int + * ``` + */ +class ParenthesizedType extends Types instanceof ParenthesizedTypeImpl { } + +/** + * A primitive type node in the AST. + * + * This class represents primitive type annotations in Bicep (e.g., `string`, `int`, `bool`). + * Primitive types are the basic built-in types in the language. + * + * Example: + * ```bicep + * param name string // String type + * param count int // Integer type + * param enabled bool // Boolean type + * ``` + */ +class PrimitiveType extends Types instanceof PrimitiveTypeImpl { } + +/** + * A type arguments node in the AST. + * + * This class represents type arguments in parameterized types. + * Type arguments specify the concrete types to use for generic type parameters. + * + * Example: + * ```bicep + * param values array // is the type argument + * ``` + */ +class TypeArguments extends Types instanceof TypeArgumentsImpl { } + +/** + * A type declaration node in the AST. + * + * This class represents type declarations in Bicep. + * Type declarations define new named types that can be used in the program. + * + * Example: + * ```bicep + * type Person = { + * name: string + * age: int + * } + * ``` + */ +class TypeDeclaration extends Types instanceof TypeDeclarationImpl { } + +/** + * A union type node in the AST. + * + * This class represents union type annotations in Bicep (e.g., `string|int`). + * Union types are used to specify that a value can be of multiple possible types. + * + * Example: + * ```bicep + * param value string|int // Either string or int + * ``` + */ +class UnionType extends Types instanceof UnionTypeImpl { } diff --git a/ql/lib/codeql/bicep/ast/Variables.qll b/ql/lib/codeql/bicep/ast/Variables.qll index a4da736..f066c52 100644 --- a/ql/lib/codeql/bicep/ast/Variables.qll +++ b/ql/lib/codeql/bicep/ast/Variables.qll @@ -7,6 +7,7 @@ private import AstNodes private import Calls private import Idents private import Stmts +private import Types private import internal.Variables private import codeql.bicep.controlflow.BasicBlocks as BasicBlocks private import codeql.bicep.controlflow.ControlFlowGraph diff --git a/ql/lib/codeql/bicep/ast/internal/ArrayType.qll b/ql/lib/codeql/bicep/ast/internal/ArrayType.qll index e1c922f..32dc12a 100644 --- a/ql/lib/codeql/bicep/ast/internal/ArrayType.qll +++ b/ql/lib/codeql/bicep/ast/internal/ArrayType.qll @@ -6,19 +6,24 @@ private import AstNodes private import TreeSitter private import codeql.bicep.ast.AstNodes +private import Type +private import Types /** * A ArrayType AST Node. */ -class ArrayTypeImpl extends TArrayType, AstNode { +class ArrayTypeImpl extends TArrayType, TypesImpl { private BICEP::ArrayType ast; override string getAPrimaryQlClass() { result = "ArrayType" } ArrayTypeImpl() { this = TArrayType(ast) } - + override string toString() { result = ast.toString() } + + override string getValue() { result = ast.toString() } - - + TypeImpl getElementType() { + toTreeSitter(result) = ast.getChild() + } } \ No newline at end of file diff --git a/ql/lib/codeql/bicep/ast/internal/AstNodes.qll b/ql/lib/codeql/bicep/ast/internal/AstNodes.qll index 99dff6b..5c820c5 100644 --- a/ql/lib/codeql/bicep/ast/internal/AstNodes.qll +++ b/ql/lib/codeql/bicep/ast/internal/AstNodes.qll @@ -77,7 +77,7 @@ class TLiterals = /** * A identifier in a SQL program */ -class TIdents = TIdentifier or TPropertyIdentifier; +class TIdents = TIdentifier or TPropertyIdentifier or TCompatibleIdentifier; /** * A statement in a Bicep program @@ -95,7 +95,7 @@ class TScopes = TInfrastructure; * A expersion value in a Bicep program */ class TExpr = - TLiterals or TConditionals or TCall or TCallable or TIdents or TObject or TObjectProperty or + TLiterals or TConditionals or TCall or TCallable or TIdents or TTypes or TObject or TObjectProperty or TAssignmentExpression or TArguments or TBinaryExpression or TCallExpression or TLambdaExpression or TMemberExpression or TParenthesizedExpression or TParameter or TParameters or TResourceExpression or TSubscriptExpression or TTernaryExpression or @@ -115,7 +115,12 @@ class TCallable = TUserDefinedFunction or TLambdaExpression; class TLoops = TForStatement; -class TTypes = TType or TTypeArguments; +/** + * Type expressions in a Bicep program + */ +class TTypes = TType or TTypeArguments or TArrayType or TNegatedType or + TParameterizedType or TParenthesizedType or TPrimitiveType or + TTypeDeclaration or TUnionType or TNullableType; cached BICEP::AstNode toTreeSitter(TAstNode n) { diff --git a/ql/lib/codeql/bicep/ast/internal/CompatibleIdentifier.qll b/ql/lib/codeql/bicep/ast/internal/CompatibleIdentifier.qll index 4560fff..d1b438e 100644 --- a/ql/lib/codeql/bicep/ast/internal/CompatibleIdentifier.qll +++ b/ql/lib/codeql/bicep/ast/internal/CompatibleIdentifier.qll @@ -1,16 +1,16 @@ /** * Internal implementation for CompatibleIdentifier - * - * WARNING: this file is generated, do not edit manually */ private import AstNodes private import TreeSitter private import codeql.bicep.ast.AstNodes +private import Idents +private import Identifier /** * A CompatibleIdentifier AST Node. */ -class CompatibleIdentifierImpl extends TCompatibleIdentifier, AstNode { +class CompatibleIdentifierImpl extends IdentsImpl, TCompatibleIdentifier { private BICEP::CompatibleIdentifier ast; override string getAPrimaryQlClass() { result = "CompatibleIdentifier" } @@ -18,7 +18,15 @@ class CompatibleIdentifierImpl extends TCompatibleIdentifier, AstNode { CompatibleIdentifierImpl() { this = TCompatibleIdentifier(ast) } override string toString() { result = ast.toString() } - - - + + /** + * Gets the underlying identifier. + */ + IdentifierImpl getIdentifier() { + toTreeSitter(result) = ast.getChild() + } + + override string getName() { + result = this.getIdentifier().getName() + } } \ No newline at end of file diff --git a/ql/lib/codeql/bicep/ast/internal/NegatedType.qll b/ql/lib/codeql/bicep/ast/internal/NegatedType.qll index c4971a3..92dd6f9 100644 --- a/ql/lib/codeql/bicep/ast/internal/NegatedType.qll +++ b/ql/lib/codeql/bicep/ast/internal/NegatedType.qll @@ -6,11 +6,13 @@ private import AstNodes private import TreeSitter private import codeql.bicep.ast.AstNodes +private import Type +private import Types /** * A NegatedType AST Node. */ -class NegatedTypeImpl extends TNegatedType, AstNode { +class NegatedTypeImpl extends TNegatedType, TypesImpl { private BICEP::NegatedType ast; override string getAPrimaryQlClass() { result = "NegatedType" } @@ -18,7 +20,10 @@ class NegatedTypeImpl extends TNegatedType, AstNode { NegatedTypeImpl() { this = TNegatedType(ast) } override string toString() { result = ast.toString() } + + override string getValue() { result = ast.toString() } - - + TypeImpl getNegatedType() { + toTreeSitter(result) = ast.getChild() + } } \ No newline at end of file diff --git a/ql/lib/codeql/bicep/ast/internal/ParameterizedType.qll b/ql/lib/codeql/bicep/ast/internal/ParameterizedType.qll index f6e04f0..da88f91 100644 --- a/ql/lib/codeql/bicep/ast/internal/ParameterizedType.qll +++ b/ql/lib/codeql/bicep/ast/internal/ParameterizedType.qll @@ -6,11 +6,12 @@ private import AstNodes private import TreeSitter private import codeql.bicep.ast.AstNodes +private import Types /** * A ParameterizedType AST Node. */ -class ParameterizedTypeImpl extends TParameterizedType, AstNode { +class ParameterizedTypeImpl extends TParameterizedType, TypesImpl { private BICEP::ParameterizedType ast; override string getAPrimaryQlClass() { result = "ParameterizedType" } @@ -18,6 +19,8 @@ class ParameterizedTypeImpl extends TParameterizedType, AstNode { ParameterizedTypeImpl() { this = TParameterizedType(ast) } override string toString() { result = ast.toString() } + + override string getValue() { result = ast.toString() } diff --git a/ql/lib/codeql/bicep/ast/internal/ParenthesizedType.qll b/ql/lib/codeql/bicep/ast/internal/ParenthesizedType.qll index 7a49160..2b6c2c3 100644 --- a/ql/lib/codeql/bicep/ast/internal/ParenthesizedType.qll +++ b/ql/lib/codeql/bicep/ast/internal/ParenthesizedType.qll @@ -6,11 +6,12 @@ private import AstNodes private import TreeSitter private import codeql.bicep.ast.AstNodes +private import Types /** * A ParenthesizedType AST Node. */ -class ParenthesizedTypeImpl extends TParenthesizedType, AstNode { +class ParenthesizedTypeImpl extends TParenthesizedType, TypesImpl { private BICEP::ParenthesizedType ast; override string getAPrimaryQlClass() { result = "ParenthesizedType" } @@ -18,6 +19,8 @@ class ParenthesizedTypeImpl extends TParenthesizedType, AstNode { ParenthesizedTypeImpl() { this = TParenthesizedType(ast) } override string toString() { result = ast.toString() } + + override string getValue() { result = ast.toString() } diff --git a/ql/lib/codeql/bicep/ast/internal/PrimitiveType.qll b/ql/lib/codeql/bicep/ast/internal/PrimitiveType.qll index b630753..5957a22 100644 --- a/ql/lib/codeql/bicep/ast/internal/PrimitiveType.qll +++ b/ql/lib/codeql/bicep/ast/internal/PrimitiveType.qll @@ -6,11 +6,12 @@ private import AstNodes private import TreeSitter private import codeql.bicep.ast.AstNodes +private import Types /** * A PrimitiveType AST Node. */ -class PrimitiveTypeImpl extends TPrimitiveType, AstNode { +class PrimitiveTypeImpl extends TPrimitiveType, TypesImpl { private BICEP::PrimitiveType ast; override string getAPrimaryQlClass() { result = "PrimitiveType" } @@ -18,6 +19,8 @@ class PrimitiveTypeImpl extends TPrimitiveType, AstNode { PrimitiveTypeImpl() { this = TPrimitiveType(ast) } override string toString() { result = ast.toString() } + + override string getValue() { result = ast.toString() } diff --git a/ql/lib/codeql/bicep/ast/internal/PropertyIdentifier.qll b/ql/lib/codeql/bicep/ast/internal/PropertyIdentifier.qll index 22706cf..dc95743 100644 --- a/ql/lib/codeql/bicep/ast/internal/PropertyIdentifier.qll +++ b/ql/lib/codeql/bicep/ast/internal/PropertyIdentifier.qll @@ -1,7 +1,5 @@ /** * Internal implementation for PropertyIdentifier - * - * WARNING: this file is generated, do not edit manually */ private import AstNodes @@ -11,8 +9,11 @@ private import Idents /** * A PropertyIdentifier AST Node. + * + * Represents the name part of a property in an object literal. PropertyIdentifier + * is a Token subtype in TreeSitter, which provides the getValue() method. */ -class PropertyIdentifierImpl extends TPropertyIdentifier, IdentsImpl { +class PropertyIdentifierImpl extends IdentsImpl, TPropertyIdentifier { private BICEP::PropertyIdentifier ast; override string getAPrimaryQlClass() { result = "PropertyIdentifier" } @@ -21,5 +22,10 @@ class PropertyIdentifierImpl extends TPropertyIdentifier, IdentsImpl { override string toString() { result = ast.toString() } + /** + * Gets the name of this property identifier as a string. + * + * @return The name of this property identifier + */ override string getName() { result = ast.getValue() } } diff --git a/ql/lib/codeql/bicep/ast/internal/Stmts.qll b/ql/lib/codeql/bicep/ast/internal/Stmts.qll index 88b2135..7890399 100644 --- a/ql/lib/codeql/bicep/ast/internal/Stmts.qll +++ b/ql/lib/codeql/bicep/ast/internal/Stmts.qll @@ -8,6 +8,8 @@ private import Expr */ class StmtsImpl extends AstNode, TStmts { override string getAPrimaryQlClass() { result = "Stmts" } + + ExprImpl getExpr() { none() } } class StmtSequenceImpl extends AstNode, TStmtSeq { diff --git a/ql/lib/codeql/bicep/ast/internal/Type.qll b/ql/lib/codeql/bicep/ast/internal/Type.qll index 95de8a0..df7c817 100644 --- a/ql/lib/codeql/bicep/ast/internal/Type.qll +++ b/ql/lib/codeql/bicep/ast/internal/Type.qll @@ -6,11 +6,12 @@ private import AstNodes private import TreeSitter private import codeql.bicep.ast.AstNodes +private import Types /** * A Type AST Node. */ -class TypeImpl extends TType, AstNode { +class TypeImpl extends TType, TypesImpl { private BICEP::Type ast; override string getAPrimaryQlClass() { result = "Type" } @@ -18,6 +19,8 @@ class TypeImpl extends TType, AstNode { TypeImpl() { this = TType(ast) } override string toString() { result = ast.toString() } + + override string getValue() { result = ast.toString() } string getType() { result = ast.getChild().toString() diff --git a/ql/lib/codeql/bicep/ast/internal/TypeArguments.qll b/ql/lib/codeql/bicep/ast/internal/TypeArguments.qll index b83f0a0..ac65ee3 100644 --- a/ql/lib/codeql/bicep/ast/internal/TypeArguments.qll +++ b/ql/lib/codeql/bicep/ast/internal/TypeArguments.qll @@ -6,11 +6,12 @@ private import AstNodes private import TreeSitter private import codeql.bicep.ast.AstNodes +private import Types /** * A TypeArguments AST Node. */ -class TypeArgumentsImpl extends TTypeArguments, AstNode { +class TypeArgumentsImpl extends TTypeArguments, TypesImpl { private BICEP::TypeArguments ast; override string getAPrimaryQlClass() { result = "TypeArguments" } @@ -18,6 +19,8 @@ class TypeArgumentsImpl extends TTypeArguments, AstNode { TypeArgumentsImpl() { this = TTypeArguments(ast) } override string toString() { result = ast.toString() } + + override string getValue() { result = ast.toString() } diff --git a/ql/lib/codeql/bicep/ast/internal/TypeDeclaration.qll b/ql/lib/codeql/bicep/ast/internal/TypeDeclaration.qll index fcaf7ef..bb5efcd 100644 --- a/ql/lib/codeql/bicep/ast/internal/TypeDeclaration.qll +++ b/ql/lib/codeql/bicep/ast/internal/TypeDeclaration.qll @@ -6,11 +6,12 @@ private import AstNodes private import TreeSitter private import codeql.bicep.ast.AstNodes +private import Types /** * A TypeDeclaration AST Node. */ -class TypeDeclarationImpl extends TTypeDeclaration, AstNode { +class TypeDeclarationImpl extends TTypeDeclaration, TypesImpl { private BICEP::TypeDeclaration ast; override string getAPrimaryQlClass() { result = "TypeDeclaration" } @@ -18,6 +19,8 @@ class TypeDeclarationImpl extends TTypeDeclaration, AstNode { TypeDeclarationImpl() { this = TTypeDeclaration(ast) } override string toString() { result = ast.toString() } + + override string getValue() { result = ast.toString() } diff --git a/ql/lib/codeql/bicep/ast/internal/Types.qll b/ql/lib/codeql/bicep/ast/internal/Types.qll new file mode 100644 index 0000000..c14c8ac --- /dev/null +++ b/ql/lib/codeql/bicep/ast/internal/Types.qll @@ -0,0 +1,8 @@ +private import AstNodes +private import codeql.bicep.ast.AstNodes +private import TreeSitter +private import Expr + +class TypesImpl extends ExprImpl, TTypes { + abstract string getValue(); +} \ No newline at end of file diff --git a/ql/lib/codeql/bicep/ast/internal/UnionType.qll b/ql/lib/codeql/bicep/ast/internal/UnionType.qll index e177daf..682c9a0 100644 --- a/ql/lib/codeql/bicep/ast/internal/UnionType.qll +++ b/ql/lib/codeql/bicep/ast/internal/UnionType.qll @@ -6,11 +6,12 @@ private import AstNodes private import TreeSitter private import codeql.bicep.ast.AstNodes +private import Types /** * A UnionType AST Node. */ -class UnionTypeImpl extends TUnionType, AstNode { +class UnionTypeImpl extends TUnionType, TypesImpl { private BICEP::UnionType ast; override string getAPrimaryQlClass() { result = "UnionType" } @@ -18,6 +19,8 @@ class UnionTypeImpl extends TUnionType, AstNode { UnionTypeImpl() { this = TUnionType(ast) } override string toString() { result = ast.toString() } + + override string getValue() { result = ast.toString() } diff --git a/ql/lib/codeql/bicep/ast/internal/Variables.qll b/ql/lib/codeql/bicep/ast/internal/Variables.qll index f94a6c6..4c88839 100644 --- a/ql/lib/codeql/bicep/ast/internal/Variables.qll +++ b/ql/lib/codeql/bicep/ast/internal/Variables.qll @@ -5,6 +5,7 @@ private import codeql.bicep.AST private import codeql.bicep.CFG private import codeql.Locations private import Expr +private import Types /** * A scope in a Bicep program. @@ -89,7 +90,7 @@ class VariableImpl extends MkVariable { * * @return The type of the variable, if available */ - Type getType() { + TypesImpl getType() { result = this.getParameter().getType() or result = this.getOutput().getType() diff --git a/ql/lib/codeql/bicep/controlflow/CfgNodes.qll b/ql/lib/codeql/bicep/controlflow/CfgNodes.qll index 8d078db..596492e 100644 --- a/ql/lib/codeql/bicep/controlflow/CfgNodes.qll +++ b/ql/lib/codeql/bicep/controlflow/CfgNodes.qll @@ -445,18 +445,18 @@ module StmtNodes { class AssertStatementCfgNode extends StmtsCfgNode { override string getAPrimaryQlClass() { result = "AssertStatementCfgNode" } - override AssertStatementStmt s; + override AssertStatement s; - override AssertStatementStmt getStmt() { result = super.getStmt() } + override AssertStatement getStmt() { result = super.getStmt() } } /** A control-flow node that wraps a ForStatement AST node. */ class ForStatementCfgNode extends StmtsCfgNode { override string getAPrimaryQlClass() { result = "ForStatementCfgNode" } - override ForStatementStmt s; + override ForStatement s; - override ForStatementStmt getStmt() { result = super.getStmt() } + override ForStatement getStmt() { result = super.getStmt() } } /** A mapping from a child of an IfStatement to the statement. */ @@ -489,9 +489,9 @@ module StmtNodes { class ImportStatementCfgNode extends StmtsCfgNode { override string getAPrimaryQlClass() { result = "ImportStatementCfgNode" } - override ImportStatementStmt s; + override ImportStatement s; - override ImportStatementStmt getStmt() { result = super.getStmt() } + override ImportStatement getStmt() { result = super.getStmt() } } /** A control-flow node that wraps an Infrastructure AST node. */ @@ -559,18 +559,18 @@ module StmtNodes { class ImportWithStatementCfgNode extends StmtsCfgNode { override string getAPrimaryQlClass() { result = "ImportWithStatementCfgNode" } - override ImportWithStatementStmt s; + override ImportWithStatement s; - override ImportWithStatementStmt getStmt() { result = super.getStmt() } + override ImportWithStatement getStmt() { result = super.getStmt() } } /** A control-flow node that wraps a UsingStatement AST node. */ class UsingStatementCfgNode extends StmtsCfgNode { override string getAPrimaryQlClass() { result = "UsingStatementCfgNode" } - override UsingStatementStmt s; + override UsingStatement s; - override UsingStatementStmt getStmt() { result = super.getStmt() } + override UsingStatement getStmt() { result = super.getStmt() } } /** A control-flow node that wraps a UserDefinedFunction AST node. */ diff --git a/ql/lib/codeql/bicep/controlflow/internal/ControlFlowGraphImpl.qll b/ql/lib/codeql/bicep/controlflow/internal/ControlFlowGraphImpl.qll index d2dcde6..390c159 100644 --- a/ql/lib/codeql/bicep/controlflow/internal/ControlFlowGraphImpl.qll +++ b/ql/lib/codeql/bicep/controlflow/internal/ControlFlowGraphImpl.qll @@ -247,14 +247,14 @@ module Trees { /** * A tree for AssertStatement in a Bicep program. */ - private class AssertStatementTree extends StandardPostOrderTree instanceof AssertStatementStmt { + private class AssertStatementTree extends StandardPostOrderTree instanceof AssertStatement { override AstNode getChildNode(int i) { i = 0 and result = super.getAChild() } } /** * A tree for ForStatement in a Bicep program. */ - private class ForStatementTree extends StandardPostOrderTree instanceof ForStatementStmt { + private class ForStatementTree extends StandardPostOrderTree instanceof ForStatement { override AstNode getChildNode(int i) { i = 0 and result = super.getAChild() } } @@ -282,21 +282,21 @@ module Trees { /** * A tree for ImportStatement in a Bicep program. */ - private class ImportStatementTree extends StandardPostOrderTree instanceof ImportStatementStmt { + private class ImportStatementTree extends StandardPostOrderTree instanceof ImportStatement { override AstNode getChildNode(int i) { i = 0 and result = super.getAChild() } } /** * A tree for ImportWithStatement in a Bicep program. */ - private class ImportWithStatementTree extends StandardPostOrderTree instanceof ImportWithStatementStmt { + private class ImportWithStatementTree extends StandardPostOrderTree instanceof ImportWithStatement { override AstNode getChildNode(int i) { i = 0 and result = super.getAChild() } } /** * A tree for UsingStatement in a Bicep program. */ - private class UsingStatementTree extends StandardPostOrderTree instanceof UsingStatementStmt { + private class UsingStatementTree extends StandardPostOrderTree instanceof UsingStatement { override AstNode getChildNode(int i) { i = 0 and result = super.getAChild() } } diff --git a/ql/test/library-tests/cfg/basic/Cfg.expected b/ql/test/library-tests/cfg/basic/Cfg.expected index 2c2124c..2b48fec 100644 --- a/ql/test/library-tests/cfg/basic/Cfg.expected +++ b/ql/test/library-tests/cfg/basic/Cfg.expected @@ -3,6 +3,7 @@ | sample.bicep:1:1:103:1 | Infrastructure | sample.bicep:1:1:103:1 | exit Infrastructure (normal) | | | sample.bicep:1:1:103:1 | enter Infrastructure | sample.bicep:1:1:1:48 | ParameterDeclaration | | | sample.bicep:1:1:103:1 | enter Infrastructure | sample.bicep:1:7:1:14 | location | | +| sample.bicep:1:1:103:1 | enter Infrastructure | sample.bicep:1:16:1:21 | string | | | sample.bicep:1:1:103:1 | enter Infrastructure | sample.bicep:1:25:1:37 | resourceGroup | | | sample.bicep:1:1:103:1 | enter Infrastructure | sample.bicep:1:38:1:39 | Arguments | | | sample.bicep:1:1:103:1 | enter Infrastructure | sample.bicep:1:41:1:48 | location | | @@ -11,6 +12,8 @@ | sample.bicep:1:7:1:14 | location | sample.bicep:1:25:1:37 | resourceGroup | | | sample.bicep:1:7:1:14 | location | sample.bicep:1:38:1:39 | Arguments | | | sample.bicep:1:7:1:14 | location | sample.bicep:1:41:1:48 | location | | +| sample.bicep:1:16:1:21 | Type | sample.bicep:1:1:1:48 | ParameterDeclaration | | +| sample.bicep:1:16:1:21 | string | sample.bicep:1:16:1:21 | Type | | | sample.bicep:1:25:1:37 | resourceGroup | sample.bicep:1:25:1:39 | CallExpression | | | sample.bicep:1:25:1:39 | CallExpression | sample.bicep:1:25:1:48 | MemberExpression | | | sample.bicep:1:25:1:48 | MemberExpression | sample.bicep:1:1:1:48 | ParameterDeclaration | |