diff --git a/MODULE.bazel b/MODULE.bazel index 8bdc850e327..e6f1ddb893d 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -248,6 +248,7 @@ use_repo( "kotlin-compiler-2.2.20-Beta2", "kotlin-compiler-2.3.0", "kotlin-compiler-2.3.20", + "kotlin-compiler-2.4.0", "kotlin-compiler-embeddable-1.8.0", "kotlin-compiler-embeddable-1.9.0-Beta", "kotlin-compiler-embeddable-1.9.20-Beta", @@ -259,6 +260,7 @@ use_repo( "kotlin-compiler-embeddable-2.2.20-Beta2", "kotlin-compiler-embeddable-2.3.0", "kotlin-compiler-embeddable-2.3.20", + "kotlin-compiler-embeddable-2.4.0", "kotlin-stdlib-1.8.0", "kotlin-stdlib-1.9.0-Beta", "kotlin-stdlib-1.9.20-Beta", @@ -270,6 +272,7 @@ use_repo( "kotlin-stdlib-2.2.20-Beta2", "kotlin-stdlib-2.3.0", "kotlin-stdlib-2.3.20", + "kotlin-stdlib-2.4.0", ) go_sdk = use_extension("@rules_go//go:extensions.bzl", "go_sdk") diff --git a/actions/ql/lib/CHANGELOG.md b/actions/ql/lib/CHANGELOG.md index 2b79e89d6d1..f677e631b4b 100644 --- a/actions/ql/lib/CHANGELOG.md +++ b/actions/ql/lib/CHANGELOG.md @@ -1,3 +1,10 @@ +## 0.4.38 + +### Bug Fixes + +* GitHub Actions queries now better account for permission checks on jobs that call reusable workflows. +* The query `actions/pr-on-self-hosted-runner` was updated to the latest standard runner labels reducing false positive results. + ## 0.4.37 ### Minor Analysis Improvements diff --git a/actions/ql/lib/change-notes/2026-06-12-self_hosted_runners.md b/actions/ql/lib/change-notes/2026-06-12-self_hosted_runners.md deleted file mode 100644 index 8fbf902b6ee..00000000000 --- a/actions/ql/lib/change-notes/2026-06-12-self_hosted_runners.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: fix ---- -* The query `actions/pr-on-self-hosted-runner` was updated to the latest standard runner labels reducing false positive results. \ No newline at end of file diff --git a/actions/ql/lib/change-notes/released/0.4.38.md b/actions/ql/lib/change-notes/released/0.4.38.md new file mode 100644 index 00000000000..5caaaed441b --- /dev/null +++ b/actions/ql/lib/change-notes/released/0.4.38.md @@ -0,0 +1,6 @@ +## 0.4.38 + +### Bug Fixes + +* GitHub Actions queries now better account for permission checks on jobs that call reusable workflows. +* The query `actions/pr-on-self-hosted-runner` was updated to the latest standard runner labels reducing false positive results. diff --git a/actions/ql/lib/codeql-pack.release.yml b/actions/ql/lib/codeql-pack.release.yml index df274514780..5b7b7bb1f33 100644 --- a/actions/ql/lib/codeql-pack.release.yml +++ b/actions/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.4.37 +lastReleaseVersion: 0.4.38 diff --git a/actions/ql/lib/codeql/actions/security/ControlChecks.qll b/actions/ql/lib/codeql/actions/security/ControlChecks.qll index 41f512abbc3..4d3dbc38c65 100644 --- a/actions/ql/lib/codeql/actions/security/ControlChecks.qll +++ b/actions/ql/lib/codeql/actions/security/ControlChecks.qll @@ -42,6 +42,15 @@ string actor_not_attacker_event() { ] } +/** + * Gets the outer caller of `ej`, i.e. the `ExternalJob` that calls the + * reusable workflow containing `ej`. Used with transitive closure to + * walk up nested reusable workflow chains. + */ +private ExternalJob getAnOuterCaller(ExternalJob ej) { + result = ej.getEnclosingWorkflow().(ReusableWorkflow).getACaller() +} + /** An If node that contains an actor, user or label check */ abstract class ControlCheck extends AstNode { ControlCheck() { @@ -53,43 +62,170 @@ abstract class ControlCheck extends AstNode { predicate protects(AstNode node, Event event, string category) { // The check dominates the step it should protect - this.dominates(node) and + this.dominates(node, event) and // The check is effective against the event and category this.protectsCategoryAndEvent(category, event.getName()) and // The check can be triggered by the event - this.getATriggerEvent() = event + this.getATriggerEvent() = event and + // For reusable workflows, there must be no unprotected caller chain for this event. + ( + not node.getEnclosingWorkflow() instanceof ReusableWorkflow + or + this.dominatesSameWorkflow(node, event) + or + not exists(ExternalJob directCaller | + directCaller = node.getEnclosingWorkflow().(ReusableWorkflow).getACaller() and + unprotectedCallerChain(directCaller, event, category) + ) + ) } - predicate dominates(AstNode node) { + /** + * Holds if this control check must execute and pass before `node` can run. + */ + predicate dominates(AstNode node, Event event) { + this.dominatesSameWorkflow(node, event) + or + // When the node is inside a reusable workflow, + // this check dominates via at least one caller chain. + this.dominatesViaCaller(node, event, _) + } + + /** + * Holds if this control check dominates `node` within the same workflow. + */ + predicate dominatesSameWorkflow(AstNode node, Event event) { + this.getATriggerEvent() = event and + ( + // Step-level: the check is an `if:` on the step containing `node`, + // or on the enclosing job, or on a needed job/step. + this instanceof If and + ( + node.getEnclosingStep().getIf() = this or + node.getEnclosingJob().getIf() = this or + node.getEnclosingJob().getANeededJob().(LocalJob).getAStep().getIf() = this or + node.getEnclosingJob().getANeededJob().(LocalJob).getIf() = this + ) + or + // Job-level: the check is an environment on the enclosing job or a needed job. + this instanceof Environment and + ( + node.getEnclosingJob().getEnvironment() = this + or + node.getEnclosingJob().getANeededJob().getEnvironment() = this + ) + or + // Step-level: the check is a Run/UsesStep that precedes `node`'s step + // in the same job, or is a step in a needed job. + ( + this instanceof Run or + this instanceof UsesStep + ) and + ( + this.(Step).getAFollowingStep() = node.getEnclosingStep() + or + node.getEnclosingJob().getANeededJob().(LocalJob).getAStep() = this + ) + ) + } + + /** + * Holds if this control check dominates `node` in a reusable workflow + * via the caller chain starting at `directCaller`. + */ + predicate dominatesViaCaller(AstNode node, Event event, ExternalJob directCaller) { + directCaller = node.getEnclosingWorkflow().(ReusableWorkflow).getACaller() and + directCaller.getATriggerEvent() = event and + exists(ExternalJob caller | + caller = getAnOuterCaller*(directCaller) and + this.dominatesCaller(caller) + ) + } + + /** + * Holds if this control check directly dominates `caller`. + */ + predicate dominatesCaller(ExternalJob caller) { this instanceof If and ( - node.getEnclosingStep().getIf() = this or - node.getEnclosingJob().getIf() = this or - node.getEnclosingJob().getANeededJob().(LocalJob).getAStep().getIf() = this or - node.getEnclosingJob().getANeededJob().(LocalJob).getIf() = this + caller.getIf() = this or + caller.getANeededJob().(LocalJob).getIf() = this or + caller.getANeededJob().(LocalJob).getAStep().getIf() = this ) or this instanceof Environment and ( - node.getEnclosingJob().getEnvironment() = this - or - node.getEnclosingJob().getANeededJob().getEnvironment() = this + caller.getEnvironment() = this or + caller.getANeededJob().getEnvironment() = this ) or - ( - this instanceof Run or - this instanceof UsesStep - ) and - ( - this.(Step).getAFollowingStep() = node.getEnclosingStep() - or - node.getEnclosingJob().getANeededJob().(LocalJob).getAStep() = this.(Step) - ) + (this instanceof Run or this instanceof UsesStep) and + caller.getANeededJob().(LocalJob).getAStep() = this } abstract predicate protectsCategoryAndEvent(string category, string event); } +/** + * Holds if this control check directly protects `caller`. + */ +bindingset[caller, event, category] +private predicate protectedCaller(ExternalJob caller, Event event, string category) { + exists(ControlCheck check | + check.protectsCategoryAndEvent(category, event.getName()) and + check.getATriggerEvent() = event and + check.dominatesCaller(caller) + ) +} + +cached +private newtype TCallerState = + MkCallerState(ExternalJob caller, Event event, string category) { + caller.getATriggerEvent() = event and + category = any_category() + } + +private class CallerState extends TCallerState, MkCallerState { + ExternalJob caller; + Event event; + string category; + + CallerState() { this = MkCallerState(caller, event, category) } + + ExternalJob getCaller() { result = caller } + + Event getEvent() { result = event } + + string getCategory() { result = category } + + /** + * Gets an outer caller state if this caller is not protected. + */ + CallerState getUnprotectedOuterState() { + not protectedCaller(this.getCaller(), this.getEvent(), this.getCategory()) and + result = MkCallerState(getAnOuterCaller(this.getCaller()), this.getEvent(), this.getCategory()) + } + + predicate isUnprotectedOutermost() { + not protectedCaller(this.getCaller(), this.getEvent(), this.getCategory()) and + not exists(getAnOuterCaller(this.getCaller())) + } + + string toString() { result = caller + " / " + event + " / " + category } +} + +/** + * Holds if there is a caller path from `caller` to an outer workflow that has no protection. + */ +bindingset[caller, event, category] +private predicate unprotectedCallerChain(ExternalJob caller, Event event, string category) { + exists(CallerState start, CallerState outermost | + start = MkCallerState(caller, event, category) and + outermost = start.getUnprotectedOuterState*() and + outermost.isUnprotectedOutermost() + ) +} + abstract class AssociationCheck extends ControlCheck { // Checks if the actor is a MEMBER/OWNER the repo // - they are effective against pull requests and workflow_run (since these are triggered by pull_requests) since they can control who is making the PR diff --git a/actions/ql/lib/qlpack.yml b/actions/ql/lib/qlpack.yml index 5d47e3f3d67..33b0c790dd6 100644 --- a/actions/ql/lib/qlpack.yml +++ b/actions/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/actions-all -version: 0.4.38-dev +version: 0.4.39-dev library: true warnOnImplicitThis: true dependencies: diff --git a/actions/ql/src/CHANGELOG.md b/actions/ql/src/CHANGELOG.md index cc99d741c50..d05f3336c09 100644 --- a/actions/ql/src/CHANGELOG.md +++ b/actions/ql/src/CHANGELOG.md @@ -1,3 +1,9 @@ +## 0.6.30 + +### Query Metadata Changes + +* The name, description, and alert message of `actions/untrusted-checkout/medium` have been corrected to describe a non-privileged context. + ## 0.6.29 ### Query Metadata Changes diff --git a/actions/ql/src/Security/CWE-285/ImproperAccessControl.ql b/actions/ql/src/Security/CWE-285/ImproperAccessControl.ql index ba002f16a87..aa16f3ab21b 100644 --- a/actions/ql/src/Security/CWE-285/ImproperAccessControl.ql +++ b/actions/ql/src/Security/CWE-285/ImproperAccessControl.ql @@ -18,7 +18,7 @@ from LocalJob job, LabelCheck check, MutableRefCheckoutStep checkout, Event even where job.isPrivileged() and job.getAStep() = checkout and - check.dominates(checkout) and + check.dominates(checkout, event) and ( job.getATriggerEvent() = event and event.getName() = "pull_request_target" and diff --git a/actions/ql/src/Security/CWE-829/UntrustedCheckoutHigh.ql b/actions/ql/src/Security/CWE-829/UntrustedCheckoutHigh.ql index 9f28706c0d0..56dc65beb5f 100644 --- a/actions/ql/src/Security/CWE-829/UntrustedCheckoutHigh.ql +++ b/actions/ql/src/Security/CWE-829/UntrustedCheckoutHigh.ql @@ -34,8 +34,8 @@ where check instanceof AssociationCheck or check instanceof PermissionCheck ) and - check.dominates(checkout) and - date_check.dominates(checkout) + check.dominates(checkout, event) and + date_check.dominates(checkout, event) ) or // not issue_comment triggered workflows diff --git a/actions/ql/src/change-notes/2026-06-04-untrusted-checkout-medium-metadata.md b/actions/ql/src/change-notes/released/0.6.30.md similarity index 78% rename from actions/ql/src/change-notes/2026-06-04-untrusted-checkout-medium-metadata.md rename to actions/ql/src/change-notes/released/0.6.30.md index cb082fc63a5..91d487c1752 100644 --- a/actions/ql/src/change-notes/2026-06-04-untrusted-checkout-medium-metadata.md +++ b/actions/ql/src/change-notes/released/0.6.30.md @@ -1,4 +1,5 @@ ---- -category: queryMetadata ---- +## 0.6.30 + +### Query Metadata Changes + * The name, description, and alert message of `actions/untrusted-checkout/medium` have been corrected to describe a non-privileged context. diff --git a/actions/ql/src/codeql-pack.release.yml b/actions/ql/src/codeql-pack.release.yml index e785984cacc..14436232c24 100644 --- a/actions/ql/src/codeql-pack.release.yml +++ b/actions/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.6.29 +lastReleaseVersion: 0.6.30 diff --git a/actions/ql/src/qlpack.yml b/actions/ql/src/qlpack.yml index 19187efb071..fb617417c3c 100644 --- a/actions/ql/src/qlpack.yml +++ b/actions/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/actions-queries -version: 0.6.30-dev +version: 0.6.31-dev library: false warnOnImplicitThis: true groups: [actions, queries] diff --git a/actions/ql/test/query-tests/Security/CWE-829/.github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml b/actions/ql/test/query-tests/Security/CWE-829/.github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml new file mode 100644 index 00000000000..39f3ab4e1be --- /dev/null +++ b/actions/ql/test/query-tests/Security/CWE-829/.github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml @@ -0,0 +1,17 @@ +on: + workflow_call: + inputs: + COMMIT_SHA: + type: string + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + with: + ref: ${{ inputs.COMMIT_SHA }} + - run: | + npm install + npm run lint + diff --git a/actions/ql/test/query-tests/Security/CWE-829/.github/workflows/external/TestOrg/TestRepo/.github/workflows/build_nested.yml b/actions/ql/test/query-tests/Security/CWE-829/.github/workflows/external/TestOrg/TestRepo/.github/workflows/build_nested.yml new file mode 100644 index 00000000000..eaaa5616a73 --- /dev/null +++ b/actions/ql/test/query-tests/Security/CWE-829/.github/workflows/external/TestOrg/TestRepo/.github/workflows/build_nested.yml @@ -0,0 +1,13 @@ +on: + workflow_call: + inputs: + COMMIT_SHA: + type: string + +jobs: + build: + uses: TestOrg/TestRepo/.github/workflows/build.yml@main + with: + COMMIT_SHA: ${{ inputs.COMMIT_SHA }} + + diff --git a/actions/ql/test/query-tests/Security/CWE-829/.github/workflows/external/TestOrg/TestRepo/.github/workflows/build_nested_branching.yml b/actions/ql/test/query-tests/Security/CWE-829/.github/workflows/external/TestOrg/TestRepo/.github/workflows/build_nested_branching.yml new file mode 100644 index 00000000000..79e65617673 --- /dev/null +++ b/actions/ql/test/query-tests/Security/CWE-829/.github/workflows/external/TestOrg/TestRepo/.github/workflows/build_nested_branching.yml @@ -0,0 +1,33 @@ +on: + workflow_call: + inputs: + COMMIT_SHA: + type: string + +jobs: + is-collaborator: + runs-on: ubuntu-latest + steps: + - name: Get User Permission + id: checkAccess + uses: actions-cool/check-user-permission@cd622002ff25c2311d2e7fb82107c0d24be83f9b + with: + require: write + username: ${{ github.actor }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Check User Permission + if: steps.checkAccess.outputs.require-result == 'false' + run: | + echo "${{ github.actor }} does not have permissions on this repo." + echo "Current permission level is ${{ steps.checkAccess.outputs.user-permission }}" + exit 1 + build_safe: + needs: is-collaborator + uses: TestOrg/TestRepo/.github/workflows/build_nested.yml@main + with: + COMMIT_SHA: ${{ inputs.COMMIT_SHA }} + build_unsafe: + uses: TestOrg/TestRepo/.github/workflows/build_nested.yml@main + with: + COMMIT_SHA: ${{ inputs.COMMIT_SHA }} diff --git a/actions/ql/test/query-tests/Security/CWE-829/.github/workflows/untrusted_checkout_no_needs.yml b/actions/ql/test/query-tests/Security/CWE-829/.github/workflows/untrusted_checkout_no_needs.yml new file mode 100644 index 00000000000..9cc8567be7d --- /dev/null +++ b/actions/ql/test/query-tests/Security/CWE-829/.github/workflows/untrusted_checkout_no_needs.yml @@ -0,0 +1,31 @@ +on: + pull_request_target: + +jobs: + is-collaborator: + runs-on: ubuntu-latest + steps: + - name: Get User Permission + id: checkAccess + uses: actions-cool/check-user-permission@cd622002ff25c2311d2e7fb82107c0d24be83f9b + with: + require: write + username: ${{ github.actor }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Check User Permission + if: steps.checkAccess.outputs.require-result == 'false' + run: | + echo "${{ github.actor }} does not have permissions on this repo." + echo "Current permission level is ${{ steps.checkAccess.outputs.user-permission }}" + exit 1 + build: + runs-on: ubuntu-latest + #needs: is-collaborator Mistake, doesn't wait for the collaborator - no security check + steps: + - name: Checkout repo + uses: actions/checkout@4 + with: + ref: ${{ github.event.pull_request.head.sha }} # should alert + fetch-depth: 2 + - run: yarn test diff --git a/actions/ql/test/query-tests/Security/CWE-829/.github/workflows/untrusted_checkout_permission_check_reusable.yml b/actions/ql/test/query-tests/Security/CWE-829/.github/workflows/untrusted_checkout_permission_check_reusable.yml new file mode 100644 index 00000000000..005fd8fb9df --- /dev/null +++ b/actions/ql/test/query-tests/Security/CWE-829/.github/workflows/untrusted_checkout_permission_check_reusable.yml @@ -0,0 +1,26 @@ +on: + pull_request_target: + +jobs: + is-collaborator: + runs-on: ubuntu-latest + steps: + - name: Get User Permission + id: checkAccess + uses: actions-cool/check-user-permission@cd622002ff25c2311d2e7fb82107c0d24be83f9b + with: + require: write + username: ${{ github.actor }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Check User Permission + if: steps.checkAccess.outputs.require-result == 'false' + run: | + echo "${{ github.actor }} does not have permissions on this repo." + echo "Current permission level is ${{ steps.checkAccess.outputs.user-permission }}" + exit 1 + build: + needs: is-collaborator + uses: TestOrg/TestRepo/.github/workflows/build.yml@main + with: + COMMIT_SHA: ${{ github.event.pull_request.head.sha }} # shouldn't alert since permission check diff --git a/actions/ql/test/query-tests/Security/CWE-829/.github/workflows/untrusted_checkout_permission_check_reusable2.yml b/actions/ql/test/query-tests/Security/CWE-829/.github/workflows/untrusted_checkout_permission_check_reusable2.yml new file mode 100644 index 00000000000..fa4bbfd9774 --- /dev/null +++ b/actions/ql/test/query-tests/Security/CWE-829/.github/workflows/untrusted_checkout_permission_check_reusable2.yml @@ -0,0 +1,31 @@ +on: + pull_request_target: + +jobs: + is-collaborator: + runs-on: ubuntu-latest + steps: + - name: Get User Permission + id: checkAccess + uses: actions-cool/check-user-permission@cd622002ff25c2311d2e7fb82107c0d24be83f9b + with: + require: write + username: ${{ github.actor }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Check User Permission + if: steps.checkAccess.outputs.require-result == 'false' + run: | + echo "${{ github.actor }} does not have permissions on this repo." + echo "Current permission level is ${{ steps.checkAccess.outputs.user-permission }}" + exit 1 + build_unsafe: + # needs: is-collaborator + uses: TestOrg/TestRepo/.github/workflows/build.yml@main + with: + COMMIT_SHA: ${{ github.event.pull_request.head.sha }} # should alert since no permission check + build_safe: + needs: is-collaborator + uses: TestOrg/TestRepo/.github/workflows/build.yml@main + with: + COMMIT_SHA: ${{ github.event.pull_request.head.sha }} # shouldn't alert since permission check diff --git a/actions/ql/test/query-tests/Security/CWE-829/.github/workflows/untrusted_checkout_permission_check_reusable_branching_nested.yml b/actions/ql/test/query-tests/Security/CWE-829/.github/workflows/untrusted_checkout_permission_check_reusable_branching_nested.yml new file mode 100644 index 00000000000..9b96cb95e00 --- /dev/null +++ b/actions/ql/test/query-tests/Security/CWE-829/.github/workflows/untrusted_checkout_permission_check_reusable_branching_nested.yml @@ -0,0 +1,8 @@ +on: + pull_request_target: + +jobs: + build: + uses: TestOrg/TestRepo/.github/workflows/build_nested_branching.yml@main + with: + COMMIT_SHA: ${{ github.event.pull_request.head.sha }} diff --git a/actions/ql/test/query-tests/Security/CWE-829/.github/workflows/untrusted_checkout_permission_check_reusable_level2.yml b/actions/ql/test/query-tests/Security/CWE-829/.github/workflows/untrusted_checkout_permission_check_reusable_level2.yml new file mode 100644 index 00000000000..04275d981d9 --- /dev/null +++ b/actions/ql/test/query-tests/Security/CWE-829/.github/workflows/untrusted_checkout_permission_check_reusable_level2.yml @@ -0,0 +1,26 @@ +on: + pull_request_target: + +jobs: + is-collaborator: + runs-on: ubuntu-latest + steps: + - name: Get User Permission + id: checkAccess + uses: actions-cool/check-user-permission@cd622002ff25c2311d2e7fb82107c0d24be83f9b + with: + require: write + username: ${{ github.actor }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Check User Permission + if: steps.checkAccess.outputs.require-result == 'false' + run: | + echo "${{ github.actor }} does not have permissions on this repo." + echo "Current permission level is ${{ steps.checkAccess.outputs.user-permission }}" + exit 1 + build: + needs: is-collaborator + uses: TestOrg/TestRepo/.github/workflows/build_nested.yml@main + with: + COMMIT_SHA: ${{ github.event.pull_request.head.sha }} # shouldn't alert since permission check diff --git a/actions/ql/test/query-tests/Security/CWE-829/.github/workflows/untrusted_checkout_permission_check_reusable_no_needs.yml b/actions/ql/test/query-tests/Security/CWE-829/.github/workflows/untrusted_checkout_permission_check_reusable_no_needs.yml new file mode 100644 index 00000000000..0603ca64d0b --- /dev/null +++ b/actions/ql/test/query-tests/Security/CWE-829/.github/workflows/untrusted_checkout_permission_check_reusable_no_needs.yml @@ -0,0 +1,26 @@ +on: + pull_request_target: + +jobs: + is-collaborator: + runs-on: ubuntu-latest + steps: + - name: Get User Permission + id: checkAccess + uses: actions-cool/check-user-permission@cd622002ff25c2311d2e7fb82107c0d24be83f9b + with: + require: write + username: ${{ github.actor }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Check User Permission + if: steps.checkAccess.outputs.require-result == 'false' + run: | + echo "${{ github.actor }} does not have permissions on this repo." + echo "Current permission level is ${{ steps.checkAccess.outputs.user-permission }}" + exit 1 + build: + # needs: is-collaborator + uses: TestOrg/TestRepo/.github/workflows/build_nested.yml@main + with: + COMMIT_SHA: ${{ github.event.pull_request.head.sha }} diff --git a/actions/ql/test/query-tests/Security/CWE-829/.github/workflows/untrusted_checkout_permissions_check.yml b/actions/ql/test/query-tests/Security/CWE-829/.github/workflows/untrusted_checkout_permissions_check.yml new file mode 100644 index 00000000000..c2349895863 --- /dev/null +++ b/actions/ql/test/query-tests/Security/CWE-829/.github/workflows/untrusted_checkout_permissions_check.yml @@ -0,0 +1,41 @@ +on: + pull_request_target: + +jobs: + is-collaborator: + runs-on: ubuntu-latest + steps: + - name: Get User Permission + id: checkAccess + uses: actions-cool/check-user-permission@cd622002ff25c2311d2e7fb82107c0d24be83f9b + with: + require: write + username: ${{ github.actor }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Check User Permission + if: steps.checkAccess.outputs.require-result == 'false' + run: | + echo "${{ github.actor }} does not have permissions on this repo." + echo "Current permission level is ${{ steps.checkAccess.outputs.user-permission }}" + exit 1 + build: + runs-on: ubuntu-latest + needs: is-collaborator + steps: + - name: Checkout repo + uses: actions/checkout@4 + with: + ref: ${{ github.event.pull_request.head.sha }} # shouldn't alert since permission check + fetch-depth: 2 + - run: yarn test + build_unsafe: + runs-on: ubuntu-latest + # needs: is-collaborator + steps: + - name: Checkout repo + uses: actions/checkout@4 + with: + ref: ${{ github.event.pull_request.head.sha }} # should alert since no permission check + fetch-depth: 2 + - run: yarn test \ No newline at end of file diff --git a/actions/ql/test/query-tests/Security/CWE-829/.github/workflows/untrusted_checkout_two_callers_both_protected.yml b/actions/ql/test/query-tests/Security/CWE-829/.github/workflows/untrusted_checkout_two_callers_both_protected.yml new file mode 100644 index 00000000000..6e842fc158e --- /dev/null +++ b/actions/ql/test/query-tests/Security/CWE-829/.github/workflows/untrusted_checkout_two_callers_both_protected.yml @@ -0,0 +1,48 @@ +on: + pull_request_target: + +jobs: + is-collaborator-a: + runs-on: ubuntu-latest + steps: + - name: Get User Permission + id: checkAccess + uses: actions-cool/check-user-permission@cd622002ff25c2311d2e7fb82107c0d24be83f9b + with: + require: write + username: ${{ github.actor }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Check User Permission + if: steps.checkAccess.outputs.require-result == 'false' + run: | + echo "${{ github.actor }} does not have permissions on this repo." + echo "Current permission level is ${{ steps.checkAccess.outputs.user-permission }}" + exit 1 + caller-a: + needs: is-collaborator-a + uses: TestOrg/TestRepo/.github/workflows/build.yml@main + with: + COMMIT_SHA: ${{ github.event.pull_request.head.sha }} + is-collaborator-b: + runs-on: ubuntu-latest + steps: + - name: Get User Permission + id: checkAccess + uses: actions-cool/check-user-permission@cd622002ff25c2311d2e7fb82107c0d24be83f9b + with: + require: write + username: ${{ github.actor }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Check User Permission + if: steps.checkAccess.outputs.require-result == 'false' + run: | + echo "${{ github.actor }} does not have permissions on this repo." + echo "Current permission level is ${{ steps.checkAccess.outputs.user-permission }}" + exit 1 + caller-b: + needs: is-collaborator-b + uses: TestOrg/TestRepo/.github/workflows/build.yml@main + with: + COMMIT_SHA: ${{ github.event.pull_request.head.sha }} diff --git a/actions/ql/test/query-tests/Security/CWE-829/UntrustedCheckoutCritical.expected b/actions/ql/test/query-tests/Security/CWE-829/UntrustedCheckoutCritical.expected index 52fcecfb9ed..b6c349bd64f 100644 --- a/actions/ql/test/query-tests/Security/CWE-829/UntrustedCheckoutCritical.expected +++ b/actions/ql/test/query-tests/Security/CWE-829/UntrustedCheckoutCritical.expected @@ -93,6 +93,8 @@ edges | .github/workflows/dependabot3.yml:15:9:20:6 | Uses Step | .github/workflows/dependabot3.yml:20:9:25:6 | Uses Step | | .github/workflows/dependabot3.yml:20:9:25:6 | Uses Step | .github/workflows/dependabot3.yml:25:9:48:6 | Run Step: set-milestone | | .github/workflows/dependabot3.yml:25:9:48:6 | Run Step: set-milestone | .github/workflows/dependabot3.yml:48:9:52:57 | Run Step | +| .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:11:9:14:6 | Uses Step | .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:14:9:17:7 | Run Step | +| .github/workflows/external/TestOrg/TestRepo/.github/workflows/build_nested_branching.yml:11:9:19:6 | Uses Step: checkAccess | .github/workflows/external/TestOrg/TestRepo/.github/workflows/build_nested_branching.yml:19:9:25:2 | Run Step | | .github/workflows/external/TestOrg/TestRepo/.github/workflows/formal.yml:14:9:19:6 | Uses Step | .github/workflows/external/TestOrg/TestRepo/.github/workflows/formal.yml:19:9:25:6 | Run Step | | .github/workflows/external/TestOrg/TestRepo/.github/workflows/formal.yml:19:9:25:6 | Run Step | .github/workflows/external/TestOrg/TestRepo/.github/workflows/formal.yml:25:9:70:20 | Run Step | | .github/workflows/external/TestOrg/TestRepo/.github/workflows/reusable.yml:23:9:26:6 | Uses Step | .github/workflows/external/TestOrg/TestRepo/.github/workflows/reusable.yml:26:9:29:7 | Run Step | @@ -334,6 +336,17 @@ edges | .github/workflows/untrusted_checkout_6.yml:11:9:14:6 | Uses Step | .github/workflows/untrusted_checkout_6.yml:14:9:17:6 | Uses Step | | .github/workflows/untrusted_checkout_6.yml:14:9:17:6 | Uses Step | .github/workflows/untrusted_checkout_6.yml:17:9:21:6 | Uses Step | | .github/workflows/untrusted_checkout_6.yml:17:9:21:6 | Uses Step | .github/workflows/untrusted_checkout_6.yml:21:9:23:23 | Run Step | +| .github/workflows/untrusted_checkout_no_needs.yml:8:9:16:6 | Uses Step: checkAccess | .github/workflows/untrusted_checkout_no_needs.yml:16:9:22:2 | Run Step | +| .github/workflows/untrusted_checkout_no_needs.yml:26:9:31:6 | Uses Step | .github/workflows/untrusted_checkout_no_needs.yml:31:9:31:23 | Run Step | +| .github/workflows/untrusted_checkout_permission_check_reusable2.yml:8:9:16:6 | Uses Step: checkAccess | .github/workflows/untrusted_checkout_permission_check_reusable2.yml:16:9:22:2 | Run Step | +| .github/workflows/untrusted_checkout_permission_check_reusable.yml:8:9:16:6 | Uses Step: checkAccess | .github/workflows/untrusted_checkout_permission_check_reusable.yml:16:9:22:2 | Run Step | +| .github/workflows/untrusted_checkout_permission_check_reusable_level2.yml:8:9:16:6 | Uses Step: checkAccess | .github/workflows/untrusted_checkout_permission_check_reusable_level2.yml:16:9:22:2 | Run Step | +| .github/workflows/untrusted_checkout_permission_check_reusable_no_needs.yml:8:9:16:6 | Uses Step: checkAccess | .github/workflows/untrusted_checkout_permission_check_reusable_no_needs.yml:16:9:22:2 | Run Step | +| .github/workflows/untrusted_checkout_permissions_check.yml:8:9:16:6 | Uses Step: checkAccess | .github/workflows/untrusted_checkout_permissions_check.yml:16:9:22:2 | Run Step | +| .github/workflows/untrusted_checkout_permissions_check.yml:26:9:31:6 | Uses Step | .github/workflows/untrusted_checkout_permissions_check.yml:31:9:32:2 | Run Step | +| .github/workflows/untrusted_checkout_permissions_check.yml:36:9:41:6 | Uses Step | .github/workflows/untrusted_checkout_permissions_check.yml:41:9:41:22 | Run Step | +| .github/workflows/untrusted_checkout_two_callers_both_protected.yml:8:9:16:6 | Uses Step: checkAccess | .github/workflows/untrusted_checkout_two_callers_both_protected.yml:16:9:22:2 | Run Step | +| .github/workflows/untrusted_checkout_two_callers_both_protected.yml:30:9:38:6 | Uses Step: checkAccess | .github/workflows/untrusted_checkout_two_callers_both_protected.yml:38:9:44:2 | Run Step | | .github/workflows/workflow_run_untrusted_checkout.yml:13:9:16:6 | Uses Step | .github/workflows/workflow_run_untrusted_checkout.yml:16:9:18:31 | Uses Step | | .github/workflows/workflow_run_untrusted_checkout_2.yml:13:9:16:6 | Uses Step | .github/workflows/workflow_run_untrusted_checkout_2.yml:16:9:18:31 | Uses Step | | .github/workflows/workflow_run_untrusted_checkout_3.yml:13:9:16:6 | Uses Step | .github/workflows/workflow_run_untrusted_checkout_3.yml:16:9:18:31 | Uses Step | @@ -344,6 +357,9 @@ edges | .github/workflows/auto_ci.yml:67:9:74:6 | Uses Step | .github/workflows/auto_ci.yml:67:9:74:6 | Uses Step | .github/workflows/auto_ci.yml:79:9:84:6 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/auto_ci.yml:6:3:6:21 | pull_request_target | pull_request_target | | .github/workflows/auto_ci.yml:67:9:74:6 | Uses Step | .github/workflows/auto_ci.yml:67:9:74:6 | Uses Step | .github/workflows/auto_ci.yml:84:9:93:6 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/auto_ci.yml:6:3:6:21 | pull_request_target | pull_request_target | | .github/workflows/dependabot3.yml:15:9:20:6 | Uses Step | .github/workflows/dependabot3.yml:15:9:20:6 | Uses Step | .github/workflows/dependabot3.yml:25:9:48:6 | Run Step: set-milestone | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/dependabot3.yml:3:5:3:23 | pull_request_target | pull_request_target | +| .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:11:9:14:6 | Uses Step | .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:11:9:14:6 | Uses Step | .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:14:9:17:7 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout_permission_check_reusable2.yml:2:3:2:21 | pull_request_target | pull_request_target | +| .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:11:9:14:6 | Uses Step | .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:11:9:14:6 | Uses Step | .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:14:9:17:7 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout_permission_check_reusable_branching_nested.yml:2:3:2:21 | pull_request_target | pull_request_target | +| .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:11:9:14:6 | Uses Step | .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:11:9:14:6 | Uses Step | .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:14:9:17:7 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout_permission_check_reusable_no_needs.yml:2:3:2:21 | pull_request_target | pull_request_target | | .github/workflows/external/TestOrg/TestRepo/.github/workflows/reusable.yml:23:9:26:6 | Uses Step | .github/workflows/external/TestOrg/TestRepo/.github/workflows/reusable.yml:23:9:26:6 | Uses Step | .github/workflows/external/TestOrg/TestRepo/.github/workflows/reusable.yml:26:9:29:7 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/reusable_caller1.yaml:4:3:4:21 | pull_request_target | pull_request_target | | .github/workflows/gitcheckout.yml:10:11:18:8 | Run Step | .github/workflows/gitcheckout.yml:10:11:18:8 | Run Step | .github/workflows/gitcheckout.yml:21:11:23:22 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/gitcheckout.yml:2:3:2:21 | pull_request_target | pull_request_target | | .github/workflows/label_trusted_checkout2.yml:12:7:16:4 | Uses Step | .github/workflows/label_trusted_checkout2.yml:12:7:16:4 | Uses Step | .github/workflows/label_trusted_checkout2.yml:17:7:21:4 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/label_trusted_checkout2.yml:2:3:2:21 | pull_request_target | pull_request_target | @@ -377,3 +393,5 @@ edges | .github/workflows/untrusted_checkout4.yml:29:7:35:4 | Uses Step | .github/workflows/untrusted_checkout4.yml:29:7:35:4 | Uses Step | .github/workflows/untrusted_checkout4.yml:47:7:51:46 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout4.yml:2:3:2:15 | issue_comment | issue_comment | | .github/workflows/untrusted_checkout.yml:8:9:11:6 | Uses Step | .github/workflows/untrusted_checkout.yml:8:9:11:6 | Uses Step | .github/workflows/untrusted_checkout.yml:15:9:18:2 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout.yml:2:3:2:21 | pull_request_target | pull_request_target | | .github/workflows/untrusted_checkout.yml:23:9:26:6 | Uses Step | .github/workflows/untrusted_checkout.yml:23:9:26:6 | Uses Step | .github/workflows/untrusted_checkout.yml:30:9:32:23 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout.yml:2:3:2:21 | pull_request_target | pull_request_target | +| .github/workflows/untrusted_checkout_no_needs.yml:26:9:31:6 | Uses Step | .github/workflows/untrusted_checkout_no_needs.yml:26:9:31:6 | Uses Step | .github/workflows/untrusted_checkout_no_needs.yml:31:9:31:23 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout_no_needs.yml:2:3:2:21 | pull_request_target | pull_request_target | +| .github/workflows/untrusted_checkout_permissions_check.yml:36:9:41:6 | Uses Step | .github/workflows/untrusted_checkout_permissions_check.yml:36:9:41:6 | Uses Step | .github/workflows/untrusted_checkout_permissions_check.yml:41:9:41:22 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout_permissions_check.yml:2:3:2:21 | pull_request_target | pull_request_target | diff --git a/cpp/ql/lib/CHANGELOG.md b/cpp/ql/lib/CHANGELOG.md index 0b3413f9d3c..fd08c4404b0 100644 --- a/cpp/ql/lib/CHANGELOG.md +++ b/cpp/ql/lib/CHANGELOG.md @@ -1,3 +1,20 @@ +## 11.0.0 + +### Breaking Changes + +* Removed the deprecated `overrideReturnsNull` predicate from `Options.qll`. Use `CustomOptions.overrideReturnsNull` instead. +* Removed the deprecated `returnsNull` predicate from `Options.qll`. Use `CustomOptions.returnsNull` instead. +* Removed the deprecated `exits` predicate from `Options.qll`. Use `CustomOptions.exits` instead. +* Removed the deprecated `exprExits` predicate from `Options.qll`. Use `CustomOptions.exprExits` instead. +* Removed the deprecated `alwaysCheckReturnValue` predicate from `Options.qll`. Use `CustomOptions.alwaysCheckReturnValue` instead. +* Removed the deprecated `okToIgnoreReturnValue` predicate from `Options.qll`. Use `CustomOptions.okToIgnoreReturnValue` instead. +* Removed the deprecated `semmle.code.cpp.Member`. Import `semmle.code.cpp.Element` and/or `semmle.code.cpp.Type` directly. +* Removed the deprecated `UnknownDefaultLocation` class. Use `UnknownLocation` instead. +* Removed the deprecated `UnknownExprLocation` class. Use `UnknownLocation` instead. +* Removed the deprecated `UnknownStmtLocation` class. Use `UnknownLocation` instead. +* Removed the deprecated `TemplateParameter` class. Use `TypeTemplateParameter` instead. +* Support for class resolution across link targets has been removed for databases which were created with CodeQL versions before 1.23.0. + ## 10.2.0 ### Deprecated APIs diff --git a/cpp/ql/lib/change-notes/2026-05-27-deprecated-removal.md b/cpp/ql/lib/change-notes/released/11.0.0.md similarity index 97% rename from cpp/ql/lib/change-notes/2026-05-27-deprecated-removal.md rename to cpp/ql/lib/change-notes/released/11.0.0.md index 33ad83230d4..b631baa748b 100644 --- a/cpp/ql/lib/change-notes/2026-05-27-deprecated-removal.md +++ b/cpp/ql/lib/change-notes/released/11.0.0.md @@ -1,6 +1,7 @@ ---- -category: breaking ---- +## 11.0.0 + +### Breaking Changes + * Removed the deprecated `overrideReturnsNull` predicate from `Options.qll`. Use `CustomOptions.overrideReturnsNull` instead. * Removed the deprecated `returnsNull` predicate from `Options.qll`. Use `CustomOptions.returnsNull` instead. * Removed the deprecated `exits` predicate from `Options.qll`. Use `CustomOptions.exits` instead. diff --git a/cpp/ql/lib/codeql-pack.release.yml b/cpp/ql/lib/codeql-pack.release.yml index a230efed2a4..e9866a9ab38 100644 --- a/cpp/ql/lib/codeql-pack.release.yml +++ b/cpp/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 10.2.0 +lastReleaseVersion: 11.0.0 diff --git a/cpp/ql/lib/qlpack.yml b/cpp/ql/lib/qlpack.yml index 6f63423d953..04f66548112 100644 --- a/cpp/ql/lib/qlpack.yml +++ b/cpp/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cpp-all -version: 10.2.1-dev +version: 11.0.1-dev groups: cpp dbscheme: semmlecode.cpp.dbscheme extractor: cpp diff --git a/cpp/ql/lib/semmlecode.cpp.dbscheme.stats b/cpp/ql/lib/semmlecode.cpp.dbscheme.stats index 0b97bb3329b..54cdc7a8508 100644 --- a/cpp/ql/lib/semmlecode.cpp.dbscheme.stats +++ b/cpp/ql/lib/semmlecode.cpp.dbscheme.stats @@ -2,7 +2,7 @@ @compilation - 12550 + 12556 @externalDataElement @@ -10,16 +10,20 @@ @file - 64732 + 64766 @folder - 12298 + 12305 @diagnostic 356 + + @location_default + 46362405 + @trap 1 @@ -28,29 +32,25 @@ @tag 1 - - @location_default - 46452143 - @source_file 1 @pch - 246 + 245 @macro_expansion - 40321986 + 40315722 @other_macro_reference - 300732 + 300696 @normal_function - 2702108 + 2699010 @unknown_function @@ -58,51 +58,51 @@ @constructor - 687816 + 688614 @destructor - 85025 + 84823 @conversion_function - 10212 + 10188 @operator - 643042 + 647163 @user_defined_literal - 984 + 982 @deduction_guide - 5783 + 5769 @fun_decl - 4144339 + 4148376 @var_decl - 9431661 + 9436285 @type_decl - 1610928 + 1639390 @namespace_decl - 408652 + 405513 @using_declaration - 265912 + 265844 @using_directive - 6370 + 6377 @using_enum_declaration @@ -110,279 +110,279 @@ @static_assert - 172696 + 171628 @parameter - 6929135 + 6930613 @membervariable - 1503222 + 1503078 @globalvariable - 662484 + 661280 @localvariable - 724508 + 725852 @enumconstant - 348146 + 348112 @errortype - 123 + 122 @unknowntype - 123 + 122 @void - 123 + 122 @boolean - 123 + 122 @char - 123 + 122 @unsigned_char - 123 + 122 @signed_char - 123 + 122 @short - 123 + 122 @unsigned_short - 123 + 122 @signed_short - 123 + 122 @int - 123 + 122 @unsigned_int - 123 + 122 @signed_int - 123 + 122 @long - 123 + 122 @unsigned_long - 123 + 122 @signed_long - 123 + 122 @long_long - 123 + 122 @unsigned_long_long - 123 + 122 @signed_long_long - 123 + 122 @float - 123 + 122 @double - 123 + 122 @long_double - 123 + 122 @complex_float - 123 + 122 @complex_double - 123 + 122 @complex_long_double - 123 + 122 @imaginary_float - 123 + 122 @imaginary_double - 123 + 122 @imaginary_long_double - 123 + 122 @wchar_t - 123 + 122 @decltype_nullptr - 123 + 122 @int128 - 123 + 122 @unsigned_int128 - 123 + 122 @signed_int128 - 123 + 122 @float128 - 123 + 122 @complex_float128 - 123 + 122 @char16_t - 123 + 122 @char32_t - 123 + 122 @std_float32 - 123 + 122 @float32x - 123 + 122 @std_float64 - 123 + 122 @float64x - 123 + 122 @std_float128 - 123 + 122 @char8_t - 123 + 122 @float16 - 123 + 122 @complex_float16 - 123 + 122 @fp16 - 123 + 122 @std_bfloat16 - 123 + 122 @std_float16 - 123 + 122 @complex_std_float32 - 123 + 122 @complex_float32x - 123 + 122 @complex_std_float64 - 123 + 122 @complex_float64x - 123 + 122 @complex_std_float128 - 123 + 122 @mfp8 - 123 + 122 @scalable_vector_count - 123 + 122 @complex_fp16 - 123 + 122 @complex_std_bfloat16 - 123 + 122 @complex_std_float16 - 123 + 122 @pointer - 450228 + 449159 @type_with_specifiers - 685493 + 686813 @array - 89824 + 89611 @routineptr - 673499 + 674281 @reference - 957919 + 958837 @gnu_vector @@ -390,11 +390,11 @@ @routinereference - 368 + 369 @rvalue_reference - 287560 + 286877 @block @@ -406,11 +406,11 @@ @typeof - 811 + 812 @underlying_type - 615 + 613 @bases @@ -486,27 +486,27 @@ @decltype - 101817 + 101861 @struct - 1036640 + 1039206 @union - 20794 + 20745 @enum - 41618 + 41614 @template_parameter - 862626 + 863096 @alias - 1757492 + 1757610 @unknown_usertype @@ -514,39 +514,39 @@ @class - 321398 + 320881 @template_template_parameter - 6070 + 6073 @proxy_class - 50200 + 50227 @scoped_enum - 11443 + 11416 @template_struct - 210479 + 210581 @template_class - 28916 + 28847 @template_union - 1353 + 1350 @mangledname - 6357829 + 6352070 @type_mention - 5915053 + 5941339 @concept_template @@ -554,15 +554,15 @@ @routinetype - 594974 + 595664 @ptrtomember - 9645 + 9651 @specifier - 7628 + 7610 @gnuattribute @@ -570,11 +570,11 @@ @stdattribute - 347976 + 347764 @declspec - 330496 + 330464 @msattribute @@ -582,15 +582,15 @@ @alignas - 2160 + 2164 @attribute_arg_token - 16429 + 16448 @attribute_arg_constant_expr - 71243 + 71688 @attribute_arg_expr @@ -606,39 +606,39 @@ @attribute_arg_type - 459 + 460 @derivation - 491402 + 492610 @frienddecl - 759702 + 761457 @comment - 11082335 + 11056034 @namespace - 8586 + 8591 @specialnamequalifyingelement - 123 + 122 @namequalifier - 3051489 + 3050545 @value - 13547187 + 13547098 @initialiser - 2245054 + 2289023 @address_of @@ -646,131 +646,131 @@ @indirect - 401821 + 401998 @array_to_pointer - 1954545 + 1954311 @parexpr - 4917201 + 4916613 @arithnegexpr - 586772 + 586702 @unaryplusexpr - 4109 + 4117 @complementexpr - 38199 + 38195 @notexpr - 355910 + 355868 @postincrexpr - 84598 + 84590 @postdecrexpr - 57416 + 57409 @preincrexpr - 96753 + 96742 @predecrexpr - 35835 + 35831 @conditionalexpr - 898245 + 898137 @addexpr - 580786 + 581041 @subexpr - 466989 + 466933 @mulexpr - 445352 + 445548 @divexpr - 52404 + 52399 @remexpr - 15758 + 15776 @paddexpr - 118668 + 118654 @psubexpr - 68038 + 68032 @pdiffexpr - 42943 + 42841 @lshiftexpr - 552247 + 552490 @rshiftexpr - 201394 + 201483 @andexpr - 483517 + 483730 @orexpr - 194025 + 194110 @xorexpr - 73976 + 73969 @eqexpr - 643635 + 643558 @neexpr - 412038 + 411988 @gtexpr - 111194 + 111181 @ltexpr - 139486 + 139469 @geexpr - 81384 + 81322 @leexpr - 292033 + 291998 @assignexpr - 1281668 + 1281515 @assignaddexpr @@ -778,23 +778,23 @@ @assignsubexpr - 15313 + 15312 @assignmulexpr - 11103 + 11109 @assigndivexpr - 6809 + 6808 @assignremexpr - 861 + 859 @assignlshiftexpr - 3704 + 3703 @assignrshiftexpr @@ -806,15 +806,15 @@ @assignorexpr - 19615 + 19612 @assignxorexpr - 29909 + 29905 @assignpaddexpr - 18635 + 18633 @assignpsubexpr @@ -822,27 +822,27 @@ @andlogicalexpr - 346730 + 346689 @orlogicalexpr - 1103987 + 1103855 @commaexpr - 165621 + 165227 @subscriptexpr - 435320 + 435268 @callexpr - 260823 + 261260 @vastartexpr - 4962 + 5007 @vaargexpr @@ -858,51 +858,51 @@ @varaccess - 8258005 + 8257017 @runtime_sizeof - 401643 + 401820 @runtime_alignof - 50293 + 50352 @expr_stmt - 147604 + 147669 @routineexpr - 5708340 + 5708356 @type_operand - 1405954 + 1405785 @offsetofexpr - 148514 + 148579 @typescompexpr - 702229 + 702145 @literal - 8052387 + 8057470 @aggregateliteral - 1397524 + 1397495 @c_style_cast - 6029390 + 6028638 @temp_init - 974928 + 974536 @errorexpr @@ -910,19 +910,19 @@ @reference_to - 1870000 + 1869126 @ref_indirect - 2077162 + 2079573 @vacuous_destructor_call - 7711 + 7720 @assume - 4136 + 4150 @conjugation @@ -974,23 +974,23 @@ @thisaccess - 1553192 + 1549814 @new_expr - 45504 + 45518 @delete_expr - 11299 + 11312 @throw_expr - 23664 + 23607 @condition_decl - 406399 + 406398 @braced_init_list @@ -998,11 +998,11 @@ @type_id - 47141 + 47196 @sizeof_pack - 2337 + 2332 @hasassignexpr @@ -1054,19 +1054,19 @@ @isclassexpr - 2380 + 2374 @isconvtoexpr - 246 + 245 @isemptyexpr - 8736 + 8715 @isenumexpr - 2953 + 2946 @ispodexpr @@ -1086,11 +1086,11 @@ @hastrivialdestructor - 2749 + 2752 @uuidof - 26780 + 26214 @delete_array_expr @@ -1098,7 +1098,7 @@ @new_array_expr - 6630 + 6597 @foldexpr @@ -1106,43 +1106,43 @@ @ctordirectinit - 111048 + 111177 @ctorvirtualinit - 3956 + 3961 @ctorfieldinit - 203396 + 202913 @ctordelegatinginit - 3568 + 3559 @dtordirectdestruct - 38826 + 38871 @dtorvirtualdestruct - 3922 + 3927 @dtorfielddestruct - 39195 + 39241 @static_cast - 347361 + 346536 @reinterpret_cast - 39952 + 39434 @const_cast - 24073 + 24101 @dynamic_cast @@ -1150,19 +1150,19 @@ @lambdaexpr - 18992 + 18970 @param_ref - 163499 + 163542 @noopexpr - 48 + 80 @istriviallyconstructibleexpr - 3691 + 3682 @isdestructibleexpr @@ -1174,15 +1174,15 @@ @istriviallydestructibleexpr - 984 + 982 @istriviallyassignableexpr - 3691 + 3682 @isnothrowassignableexpr - 5044 + 5032 @istrivialexpr @@ -1194,7 +1194,7 @@ @istriviallycopyableexpr - 1353 + 1350 @isliteraltypeexpr @@ -1214,11 +1214,11 @@ @isconstructibleexpr - 3568 + 3559 @isnothrowconstructibleexpr - 20425 + 20377 @hasfinalizerexpr @@ -1254,11 +1254,11 @@ @isfinalexpr - 9254 + 9264 @noexceptexpr - 30165 + 30169 @builtinshufflevector @@ -1266,11 +1266,11 @@ @builtinchooseexpr - 20605 + 20614 @builtinaddressof - 15257 + 15221 @vec_fill @@ -1298,7 +1298,7 @@ @isassignable - 406 + 449 @isaggregate @@ -1310,7 +1310,7 @@ @builtinbitcast - 246 + 245 @builtinshuffle @@ -1526,7 +1526,7 @@ @c11_generic - 29960 + 29973 @requires_expr @@ -1542,7 +1542,7 @@ @concept_id - 90089 + 90068 @isinvocable @@ -1558,59 +1558,59 @@ @lambdacapture - 31856 + 31810 @stmt_expr - 2032444 + 2032201 @stmt_if - 990619 + 990500 @stmt_while - 39664 + 39659 @stmt_goto - 156745 + 156829 @stmt_label - 77471 + 77512 @stmt_return - 1233416 + 1233370 @stmt_block - 1700014 + 1695980 @stmt_end_test_while - 232426 + 232528 @stmt_for - 84423 + 84413 @stmt_switch_case - 830953 + 830952 @stmt_switch - 409307 + 409306 @stmt_asm - 63865 + 63893 @stmt_decl - 769791 + 770162 @stmt_empty @@ -1618,19 +1618,19 @@ @stmt_continue - 28103 + 28099 @stmt_break - 137464 + 137217 @stmt_try_block - 26287 + 26230 @stmt_microsoft_try - 210 + 209 @stmt_set_vla_size @@ -1642,7 +1642,7 @@ @stmt_assigned_goto - 12426 + 12425 @stmt_range_based_for @@ -1650,11 +1650,11 @@ @stmt_handler - 43039 + 42985 @stmt_constexpr_if - 103482 + 103236 @stmt_co_return @@ -1674,43 +1674,43 @@ @ppd_if - 582872 + 581489 @ppd_ifdef - 214451 + 214425 @ppd_ifndef - 160536 + 160411 @ppd_elif - 21755 + 21767 @ppd_else - 231697 + 231147 @ppd_endif - 876831 + 874750 @ppd_plain_include - 316217 + 316386 @ppd_define - 2712444 + 2706007 @ppd_undef - 99052 + 98817 @ppd_pragma - 400640 + 399689 @ppd_include_next @@ -1718,11 +1718,11 @@ @ppd_line - 18775 + 18810 @ppd_error - 123 + 122 @ppd_objc_import @@ -1780,11 +1780,11 @@ compilations - 12550 + 12556 id - 12550 + 12556 cwd @@ -1802,7 +1802,7 @@ 1 2 - 12550 + 12556 @@ -1828,19 +1828,19 @@ compilation_args - 1004756 + 1005291 id - 12550 + 12556 num - 1457 + 1458 arg - 29053 + 29068 @@ -1864,7 +1864,7 @@ 43 44 - 712 + 713 44 @@ -1874,7 +1874,7 @@ 45 51 - 943 + 944 51 @@ -1894,12 +1894,12 @@ 94 96 - 387 + 388 98 99 - 1331 + 1332 100 @@ -1909,22 +1909,22 @@ 103 104 - 1981 + 1982 104 119 - 1058 + 1059 120 138 - 922 + 923 139 140 - 450 + 451 @@ -1945,7 +1945,7 @@ 38 39 - 1488 + 1489 39 @@ -1955,7 +1955,7 @@ 40 42 - 1079 + 1080 42 @@ -1980,27 +1980,27 @@ 67 68 - 1394 + 1395 68 70 - 964 + 965 70 71 - 1394 + 1395 73 79 - 943 + 944 79 89 - 1121 + 1122 89 @@ -2168,17 +2168,17 @@ 1 2 - 13305 + 13312 2 3 - 12592 + 12598 3 103 - 2180 + 2181 104 @@ -2199,12 +2199,12 @@ 1 2 - 19239 + 19249 2 3 - 8660 + 8664 3 @@ -2219,19 +2219,19 @@ compilation_expanded_args - 1004756 + 1005291 id - 12550 + 12556 num - 1457 + 1458 arg - 29053 + 29068 @@ -2255,7 +2255,7 @@ 43 44 - 712 + 713 44 @@ -2265,7 +2265,7 @@ 45 51 - 943 + 944 51 @@ -2285,12 +2285,12 @@ 94 96 - 387 + 388 98 99 - 1331 + 1332 100 @@ -2300,22 +2300,22 @@ 103 104 - 1981 + 1982 104 119 - 1058 + 1059 120 138 - 922 + 923 139 140 - 450 + 451 @@ -2336,7 +2336,7 @@ 38 39 - 1488 + 1489 39 @@ -2346,7 +2346,7 @@ 40 42 - 1079 + 1080 42 @@ -2371,27 +2371,27 @@ 67 68 - 1394 + 1395 68 70 - 964 + 965 70 71 - 1394 + 1395 73 79 - 943 + 944 79 89 - 1121 + 1122 89 @@ -2559,17 +2559,17 @@ 1 2 - 13305 + 13312 2 3 - 12592 + 12598 3 103 - 2180 + 2181 104 @@ -2590,12 +2590,12 @@ 1 2 - 19239 + 19249 2 3 - 8660 + 8664 3 @@ -2658,7 +2658,7 @@ compilation_compiling_files - 15743 + 15741 id @@ -2666,11 +2666,11 @@ num - 4521 + 4520 file - 13673 + 13671 @@ -2858,7 +2858,7 @@ 1 2 - 12311 + 12310 2 @@ -2884,7 +2884,7 @@ 1 2 - 12529 + 12527 2 @@ -2904,7 +2904,7 @@ compilation_time - 62972 + 62966 id @@ -2912,7 +2912,7 @@ num - 4521 + 4520 kind @@ -2920,7 +2920,7 @@ seconds - 17867 + 18682 @@ -2998,55 +2998,55 @@ 12 + + 2 + 3 + 54 + 3 4 - 490 + 544 4 5 - 871 + 762 - 5 - 7 - 163 - - - 8 - 10 + 6 + 9 217 + + 9 + 10 + 108 + 10 11 - 108 + 163 11 - 12 + 13 217 14 - 18 - 163 - - - 18 - 21 + 17 217 - 21 - 53 + 17 + 22 217 - 116 - 117 - 54 + 26 + 121 + 217 @@ -3098,7 +3098,7 @@ 4 5 - 4521 + 4520 @@ -3114,17 +3114,17 @@ 3 4 - 926 + 925 4 5 - 1470 + 1525 5 6 - 217 + 272 6 @@ -3133,28 +3133,23 @@ 7 - 8 - 326 - - - 8 9 - 217 + 381 9 - 13 + 12 381 - 17 - 46 + 13 + 41 381 - 51 - 98 - 108 + 44 + 100 + 163 @@ -3205,13 +3200,13 @@ 108 - 166 - 167 + 189 + 190 54 - 179 - 180 + 198 + 199 54 @@ -3228,22 +3223,22 @@ 1 2 - 11548 + 12854 2 3 - 4249 + 3921 3 - 4 - 1416 + 5 + 1688 - 4 - 45 - 653 + 7 + 42 + 217 @@ -3259,27 +3254,22 @@ 1 2 - 10949 + 11765 2 3 - 3922 + 3867 3 4 - 1307 + 1743 4 - 9 - 1416 - - - 9 67 - 272 + 1307 @@ -3295,12 +3285,12 @@ 1 2 - 16505 + 15850 2 3 - 1361 + 2832 @@ -3576,19 +3566,19 @@ compilation_finished - 12550 + 12556 id - 12550 + 12556 cpu_seconds - 8922 + 9420 elapsed_seconds - 167 + 199 @@ -3602,7 +3592,7 @@ 1 2 - 12550 + 12556 @@ -3618,7 +3608,7 @@ 1 2 - 12550 + 12556 @@ -3634,17 +3624,17 @@ 1 2 - 7161 + 7930 2 3 - 1247 + 996 3 - 31 - 513 + 28 + 493 @@ -3660,12 +3650,12 @@ 1 2 - 8261 + 8843 2 3 - 660 + 576 @@ -3681,12 +3671,12 @@ 1 2 - 41 + 31 2 3 - 10 + 31 4 @@ -3694,48 +3684,53 @@ 10 - 9 - 10 - 20 + 10 + 11 + 31 - 16 - 17 + 12 + 13 10 - 22 - 23 + 14 + 15 10 - 25 - 26 + 18 + 19 10 - 28 - 29 + 32 + 33 10 - 76 - 77 + 51 + 52 10 - 290 - 291 + 159 + 160 10 - 350 - 351 + 260 + 261 10 - 362 - 363 + 286 + 287 + 10 + + + 322 + 323 10 @@ -3752,12 +3747,12 @@ 1 2 - 41 + 31 2 3 - 10 + 31 4 @@ -3765,48 +3760,53 @@ 10 - 9 - 10 - 20 + 10 + 11 + 31 - 16 - 17 + 12 + 13 10 - 22 - 23 + 13 + 14 10 - 25 - 26 + 18 + 19 10 - 27 - 28 + 32 + 33 10 - 71 - 72 + 51 + 52 10 - 168 - 169 + 134 + 135 10 - 255 - 256 + 155 + 156 10 - 302 - 303 + 234 + 235 + 10 + + + 261 + 262 10 @@ -4033,42 +4033,42 @@ sourceLocationPrefix - 123 + 122 prefix - 123 + 122 locations_default - 46452143 + 46362405 id - 46452143 + 46362405 file - 40359 + 40263 beginLine - 7398928 + 7381369 beginColumn - 21656 + 21604 endLine - 7399912 + 7382351 endColumn - 52910 + 52907 @@ -4082,7 +4082,7 @@ 1 2 - 46452143 + 46362405 @@ -4098,7 +4098,7 @@ 1 2 - 46452143 + 46362405 @@ -4114,7 +4114,7 @@ 1 2 - 46452143 + 46362405 @@ -4130,7 +4130,7 @@ 1 2 - 46452143 + 46362405 @@ -4146,7 +4146,7 @@ 1 2 - 46452143 + 46362405 @@ -4162,72 +4162,72 @@ 1 15 - 3076 + 3068 15 41 - 3076 + 3068 42 72 - 3076 + 3068 72 114 - 3199 + 3191 114 142 - 3199 + 3191 143 212 - 3076 + 3068 213 307 - 3076 + 3068 310 - 431 - 3076 + 435 + 3068 437 596 - 3076 + 3068 607 846 - 3076 + 3068 848 1304 - 3076 + 3068 1354 2855 - 3076 + 3068 3114 30788 - 3076 + 3068 57880 57881 - 123 + 122 @@ -4243,67 +4243,67 @@ 1 13 - 3322 + 3314 13 31 - 3322 + 3314 31 47 - 3076 + 3068 47 64 - 3076 + 3068 64 84 - 3076 + 3068 85 115 - 3076 + 3068 116 160 - 3199 + 3191 160 206 - 3076 + 3068 206 291 - 3076 + 3068 298 388 - 3076 + 3068 395 527 - 3076 + 3068 561 1339 - 3076 + 3068 1385 57764 - 2830 + 2823 @@ -4319,67 +4319,67 @@ 1 5 - 3691 + 3682 5 9 - 3076 + 3068 9 15 - 3199 + 3191 15 20 - 3199 + 3191 20 28 - 3199 + 3191 28 36 - 3076 + 3068 36 43 - 3322 + 3314 43 53 - 3199 + 3191 53 62 - 3076 + 3068 62 80 - 3076 + 3068 80 95 - 3199 + 3191 95 111 - 3076 + 3068 112 156 - 1968 + 1964 @@ -4395,67 +4395,67 @@ 1 13 - 3322 + 3314 13 31 - 3322 + 3314 31 46 - 3076 + 3068 46 63 - 3076 + 3068 63 84 - 3076 + 3068 84 114 - 3076 + 3068 118 160 - 3199 + 3191 160 206 - 3076 + 3068 207 291 - 3076 + 3068 300 390 - 3076 + 3068 395 562 - 3076 + 3068 564 1350 - 3076 + 3068 1430 57764 - 2830 + 2823 @@ -4471,67 +4471,67 @@ 1 12 - 3322 + 3314 13 26 - 3445 + 3437 26 34 - 3199 + 3191 34 42 - 3199 + 3191 42 50 - 3076 + 3068 50 61 - 3076 + 3068 61 67 - 3322 + 3314 67 76 - 3445 + 3437 76 88 - 3199 + 3191 89 102 - 3076 + 3068 102 116 - 3322 + 3314 116 132 - 3076 + 3068 132 364 - 1599 + 1595 @@ -4547,32 +4547,32 @@ 1 2 - 4890126 + 4878521 2 3 - 769903 + 768076 3 4 - 536607 + 535333 4 12 - 559370 + 558043 12 - 96 - 554941 + 97 + 555220 - 96 + 97 639 - 87978 + 86173 @@ -4588,27 +4588,27 @@ 1 2 - 4951650 + 4939899 2 3 - 1203151 + 1200296 3 6 - 631107 + 629609 6 56 - 556171 + 554851 56 329 - 56847 + 56712 @@ -4624,27 +4624,27 @@ 1 2 - 5566146 + 5552936 2 3 - 477667 + 476534 3 7 - 570322 + 568968 7 25 - 558263 + 556938 25 94 - 226529 + 225991 @@ -4660,12 +4660,12 @@ 1 2 - 6938241 + 6921775 2 85 - 460687 + 459594 @@ -4681,32 +4681,32 @@ 1 2 - 4957802 + 4946036 2 3 - 732743 + 731004 3 4 - 529347 + 528091 4 12 - 577458 + 576088 12 71 - 555925 + 554483 71 252 - 45650 + 45664 @@ -4722,67 +4722,67 @@ 1 2 - 1722 + 1718 2 6 - 1968 + 1964 6 12 - 1845 + 1841 12 40 - 1722 + 1718 49 128 - 1722 + 1718 129 262 - 1722 + 1718 317 717 - 1722 + 1718 799 1281 - 1722 + 1718 1287 1966 - 1722 + 1718 2038 2400 - 1722 + 1718 2484 3299 - 1722 + 1718 - 3311 + 3340 8093 - 1722 + 1718 11052 121030 - 615 + 613 @@ -4798,67 +4798,67 @@ 1 2 - 1968 + 1964 2 4 - 1722 + 1718 4 7 - 1722 + 1718 7 18 - 1845 + 1841 19 44 - 1722 + 1718 44 61 - 1722 + 1718 66 93 - 1722 + 1718 96 117 - 1722 + 1718 118 151 - 1845 + 1841 152 170 - 1845 + 1841 170 183 - 1722 + 1718 183 244 - 1722 + 1718 259 329 - 369 + 368 @@ -4874,67 +4874,67 @@ 1 2 - 1845 + 1841 2 5 - 1845 + 1841 5 11 - 1722 + 1718 11 36 - 1722 + 1718 36 103 - 1722 + 1718 109 220 - 1722 + 1718 226 548 - 1722 + 1718 640 1059 - 1722 + 1718 1078 1412 - 1722 + 1718 1417 1609 - 1722 + 1718 1625 1811 - 1722 + 1718 1835 3793 - 1722 + 1718 3838 59550 - 738 + 736 @@ -4950,67 +4950,67 @@ 1 2 - 1845 + 1841 2 5 - 1845 + 1841 5 11 - 1722 + 1718 11 36 - 1722 + 1718 36 104 - 1722 + 1718 110 221 - 1722 + 1718 225 550 - 1722 + 1718 638 1058 - 1722 + 1718 1080 1414 - 1722 + 1718 1420 1607 - 1722 + 1718 1624 1809 - 1722 + 1718 1836 3771 - 1722 + 1718 3831 59557 - 738 + 736 @@ -5026,67 +5026,67 @@ 1 2 - 2091 + 2086 2 5 - 1476 + 1473 5 8 - 1599 + 1595 8 13 - 1722 + 1718 13 23 - 1968 + 1964 23 33 - 1722 + 1718 33 44 - 1845 + 1841 45 58 - 1722 + 1718 58 74 - 1845 + 1841 74 87 - 1968 + 1964 87 99 - 1722 + 1718 100 160 - 1722 + 1718 261 299 - 246 + 245 @@ -5102,32 +5102,32 @@ 1 2 - 4887911 + 4876312 2 3 - 773226 + 771391 3 4 - 535868 + 534597 4 12 - 558263 + 556938 12 94 - 555187 + 553746 94 622 - 89455 + 89365 @@ -5143,27 +5143,27 @@ 1 2 - 4948697 + 4936952 2 3 - 1206720 + 1203856 3 6 - 623601 + 622121 6 51 - 556048 + 554728 51 329 - 64845 + 64691 @@ -5179,12 +5179,12 @@ 1 2 - 6955098 + 6938592 2 15 - 444814 + 443758 @@ -5200,27 +5200,27 @@ 1 2 - 5564792 + 5551586 2 3 - 476191 + 475061 3 7 - 574382 + 573019 7 25 - 561093 + 559761 25 89 - 223453 + 222922 @@ -5236,32 +5236,32 @@ 1 2 - 4956325 + 4944563 2 3 - 737911 + 736160 3 4 - 527747 + 526495 4 12 - 579304 + 577929 12 72 - 555679 + 554237 72 252 - 42943 + 42964 @@ -5277,52 +5277,52 @@ 1 2 - 15626 + 15344 2 3 - 5414 + 5646 3 6 - 4060 + 4173 6 16 - 4060 + 4050 16 31 - 4183 + 4173 31 93 - 4060 + 4050 96 660 - 4060 + 4050 - 661 - 2409 - 4060 + 662 + 2411 + 4050 - 2461 - 4698 - 4060 + 2462 + 4702 + 4050 - 4717 + 4720 33780 - 3322 + 3314 @@ -5338,52 +5338,52 @@ 1 2 - 18210 + 17922 2 3 - 5660 + 6014 3 5 - 3691 + 3437 5 8 - 4306 + 4541 8 17 - 4183 + 4173 17 84 - 4060 + 4050 88 160 - 4183 + 4173 160 214 - 4060 + 4050 215 267 - 4060 + 4050 267 329 - 492 + 491 @@ -5399,52 +5399,52 @@ 1 2 - 15873 + 15589 2 3 - 5783 + 6014 3 7 - 4060 + 4173 7 18 - 4429 + 4419 18 - 39 - 4060 + 40 + 4173 - 39 - 155 - 4060 + 41 + 188 + 4050 - 187 - 643 - 4060 + 217 + 747 + 4050 - 746 - 2054 - 4060 + 766 + 2171 + 4050 - 2170 - 2875 - 4060 + 2171 + 2881 + 4050 - 2880 + 2891 30763 - 2460 + 2332 @@ -5460,52 +5460,47 @@ 1 2 - 16857 + 16571 2 3 - 6398 + 6628 3 - 4 - 3199 + 5 + 4787 - 4 - 7 - 4060 + 5 + 9 + 4296 - 7 - 13 - 4183 + 9 + 20 + 4173 - 13 - 28 - 4675 + 20 + 32 + 4296 - 28 - 46 - 4060 + 33 + 57 + 4050 - 46 - 70 - 4060 + 57 + 76 + 4296 - 70 - 83 - 4306 - - - 83 + 76 117 - 1107 + 3805 @@ -5521,52 +5516,52 @@ 1 2 - 15873 + 15589 2 3 - 5783 + 6014 3 7 - 4060 + 4173 7 17 - 4060 + 4050 17 30 - 4060 + 4050 32 - 100 - 4060 + 102 + 4050 104 621 - 4060 + 4050 628 1958 - 4060 + 4050 - 1966 + 1967 2836 - 4060 + 4050 2841 30757 - 2830 + 2823 @@ -5576,15 +5571,15 @@ files - 64732 + 64766 id - 64732 + 64766 name - 64732 + 64766 @@ -5598,7 +5593,7 @@ 1 2 - 64732 + 64766 @@ -5614,7 +5609,7 @@ 1 2 - 64732 + 64766 @@ -5624,15 +5619,15 @@ folders - 12298 + 12305 id - 12298 + 12305 name - 12298 + 12305 @@ -5646,7 +5641,7 @@ 1 2 - 12298 + 12305 @@ -5662,7 +5657,7 @@ 1 2 - 12298 + 12305 @@ -5672,15 +5667,15 @@ containerparent - 77009 + 77050 parent - 12298 + 12305 child - 77009 + 77050 @@ -5694,12 +5689,12 @@ 1 2 - 5986 + 5989 2 3 - 1509 + 1510 3 @@ -5714,7 +5709,7 @@ 6 10 - 964 + 965 10 @@ -5724,7 +5719,7 @@ 16 44 - 922 + 923 44 @@ -5745,7 +5740,7 @@ 1 2 - 77009 + 77050 @@ -5755,23 +5750,23 @@ numlines - 796112 + 794223 element_id - 795005 + 793118 num_lines - 38882 + 38790 num_code - 33591 + 33512 num_comment - 18087 + 18044 @@ -5785,12 +5780,12 @@ 1 2 - 793898 + 792014 2 3 - 1107 + 1104 @@ -5806,12 +5801,12 @@ 1 2 - 793898 + 792014 2 3 - 1107 + 1104 @@ -5827,12 +5822,12 @@ 1 2 - 794759 + 792873 2 3 - 246 + 245 @@ -5848,27 +5843,27 @@ 1 2 - 26332 + 26269 2 3 - 3691 + 3682 3 5 - 3322 + 3314 5 35 - 2953 + 2946 39 1981 - 2583 + 2577 @@ -5884,27 +5879,27 @@ 1 2 - 26824 + 26760 2 3 - 4060 + 4050 3 4 - 2460 + 2455 4 7 - 3445 + 3437 7 12 - 2091 + 2086 @@ -5920,27 +5915,27 @@ 1 2 - 26455 + 26392 2 3 - 4060 + 4050 3 4 - 2337 + 2332 4 6 - 3199 + 3191 6 10 - 2830 + 2823 @@ -5956,32 +5951,32 @@ 1 2 - 21533 + 21482 2 3 - 3568 + 3559 3 4 - 2337 + 2332 4 12 - 2583 + 2577 12 157 - 2583 + 2577 172 2090 - 984 + 982 @@ -5997,32 +5992,32 @@ 1 2 - 21902 + 21850 2 3 - 3568 + 3559 3 4 - 2091 + 2086 4 6 - 1845 + 1841 6 9 - 2707 + 2700 9 13 - 1476 + 1473 @@ -6038,27 +6033,27 @@ 1 2 - 21656 + 21604 2 3 - 4183 + 4173 3 5 - 2830 + 2823 5 8 - 3076 + 3068 8 12 - 1845 + 1841 @@ -6074,32 +6069,32 @@ 1 2 - 11197 + 11170 2 3 - 1968 + 1964 3 4 - 1107 + 1104 4 7 - 1476 + 1473 8 22 - 1476 + 1473 42 3648 - 861 + 859 @@ -6115,32 +6110,32 @@ 1 2 - 11197 + 11170 2 3 - 1968 + 1964 3 4 - 1107 + 1104 4 7 - 1599 + 1595 8 27 - 1476 + 1473 30 48 - 738 + 736 @@ -6156,32 +6151,32 @@ 1 2 - 11197 + 11170 2 3 - 1968 + 1964 3 4 - 1353 + 1350 4 8 - 1476 + 1473 8 31 - 1476 + 1473 35 42 - 615 + 613 @@ -6803,15 +6798,15 @@ extractor_version - 123 + 122 codeql_version - 123 + 122 frontend_version - 123 + 122 @@ -6825,7 +6820,7 @@ 1 2 - 123 + 122 @@ -6841,7 +6836,7 @@ 1 2 - 123 + 122 @@ -7139,7 +7134,7 @@ pch_uses - 4120 + 4118 pch @@ -7147,11 +7142,11 @@ compilation - 4120 + 4118 id - 4120 + 4118 @@ -7180,12 +7175,12 @@ 10 11 - 16 + 8 11 12 - 8 + 16 13 @@ -7271,12 +7266,12 @@ 10 11 - 16 + 8 11 12 - 8 + 16 13 @@ -7347,7 +7342,7 @@ 1 2 - 4120 + 4118 @@ -7363,7 +7358,7 @@ 1 2 - 4120 + 4118 @@ -7379,7 +7374,7 @@ 1 2 - 4120 + 4118 @@ -7395,7 +7390,7 @@ 1 2 - 4120 + 4118 @@ -7405,19 +7400,19 @@ pch_creations - 246 + 245 pch - 246 + 245 compilation - 246 + 245 from - 246 + 245 @@ -7431,7 +7426,7 @@ 1 2 - 246 + 245 @@ -7447,7 +7442,7 @@ 1 2 - 246 + 245 @@ -7463,7 +7458,7 @@ 1 2 - 246 + 245 @@ -7479,7 +7474,7 @@ 1 2 - 246 + 245 @@ -7495,7 +7490,7 @@ 1 2 - 246 + 245 @@ -7511,7 +7506,7 @@ 1 2 - 246 + 245 @@ -7521,11 +7516,11 @@ fileannotations - 4169606 + 4171827 id - 5724 + 5727 kind @@ -7533,11 +7528,11 @@ name - 58284 + 58315 value - 39223 + 39244 @@ -7556,7 +7551,7 @@ 2 3 - 5525 + 5528 @@ -7572,12 +7567,12 @@ 1 86 - 429 + 430 88 206 - 429 + 430 212 @@ -7587,17 +7582,17 @@ 291 359 - 429 + 430 362 401 - 429 + 430 402 479 - 429 + 430 480 @@ -7612,12 +7607,12 @@ 553 628 - 429 + 430 631 753 - 450 + 451 753 @@ -7643,17 +7638,17 @@ 1 98 - 429 + 430 102 244 - 429 + 430 244 351 - 429 + 430 352 @@ -7668,7 +7663,7 @@ 490 628 - 429 + 430 632 @@ -7683,22 +7678,22 @@ 710 939 - 429 + 430 939 1038 - 429 + 430 1066 1853 - 429 + 430 1853 3292 - 429 + 430 3423 @@ -7782,62 +7777,62 @@ 1 2 - 10945 + 10951 2 3 - 4330 + 4332 3 5 - 5022 + 5024 5 7 - 4068 + 4070 7 9 - 4560 + 4563 9 16 - 4298 + 4301 16 19 - 4854 + 4856 19 27 - 4225 + 4227 27 47 - 4801 + 4804 47 128 - 4885 + 4888 128 459 - 4592 + 4594 459 546 - 1698 + 1699 @@ -7853,7 +7848,7 @@ 1 2 - 58284 + 58315 @@ -7869,57 +7864,57 @@ 1 2 - 11501 + 11507 2 3 - 7632 + 7636 3 4 - 4068 + 4070 4 6 - 4036 + 4038 6 8 - 3397 + 3398 8 11 - 4707 + 4710 11 17 - 5357 + 5360 17 23 - 4665 + 4668 23 41 - 4644 + 4647 41 95 - 4435 + 4437 95 1726 - 3837 + 3839 @@ -7935,7 +7930,7 @@ 1 2 - 3334 + 3335 2 @@ -7945,62 +7940,62 @@ 4 5 - 3166 + 3168 5 8 - 2442 + 2444 8 14 - 2946 + 2947 14 17 - 1918 + 1919 17 24 - 3019 + 3021 24 51 - 3512 + 3514 51 58 - 3009 + 3010 58 80 - 2956 + 2958 81 151 - 3061 + 3063 151 334 - 2956 + 2958 334 473 - 2977 + 2979 473 547 - 2296 + 2297 @@ -8016,7 +8011,7 @@ 1 2 - 39212 + 39233 2 @@ -8037,67 +8032,67 @@ 1 2 - 3376 + 3377 2 4 - 1897 + 1898 4 5 - 3030 + 3031 5 8 - 2463 + 2465 8 14 - 3459 + 3461 14 18 - 3428 + 3430 18 28 - 3176 + 3178 28 34 - 3124 + 3126 34 41 - 3176 + 3178 41 66 - 2967 + 2968 66 92 - 3051 + 3052 92 113 - 2967 + 2968 113 145 - 3009 + 3010 145 @@ -8112,15 +8107,15 @@ inmacroexpansion - 150057030 + 150039073 id - 24680985 + 24678024 inv - 3706846 + 3706403 @@ -8134,37 +8129,37 @@ 1 3 - 2210373 + 2210101 3 5 - 1475577 + 1475401 5 6 - 1621028 + 1620834 6 7 - 6585222 + 6584434 7 8 - 8722546 + 8721502 8 9 - 3558495 + 3558069 9 22 - 507741 + 507680 @@ -8180,32 +8175,32 @@ 1 2 - 531923 + 531859 2 3 - 743535 + 743444 3 4 - 481708 + 481650 4 7 - 275415 + 275382 7 8 - 282267 + 282234 8 9 - 330381 + 330341 9 @@ -8215,22 +8210,22 @@ 10 11 - 444831 + 444778 11 337 - 307921 + 307886 339 423 - 281870 + 281836 423 7616 - 23944 + 23941 @@ -8240,15 +8235,15 @@ affectedbymacroexpansion - 48755653 + 48749819 id - 7047601 + 7046758 inv - 3804666 + 3804211 @@ -8262,37 +8257,37 @@ 1 2 - 3848269 + 3847809 2 3 - 766616 + 766524 3 4 - 361989 + 361945 4 5 - 773050 + 772958 5 12 - 535377 + 535313 12 50 - 556493 + 556427 50 9900 - 205803 + 205778 @@ -8308,67 +8303,67 @@ 1 4 - 313374 + 313336 4 7 - 316736 + 316698 7 9 - 301210 + 301174 9 12 - 343078 + 343037 12 13 - 456190 + 456135 13 14 - 226191 + 226164 14 15 - 408204 + 408155 15 16 - 166496 + 166476 16 17 - 377831 + 377786 17 18 - 200718 + 200694 18 20 - 344395 + 344354 20 25 - 285509 + 285475 25 207 - 64728 + 64720 @@ -8378,19 +8373,19 @@ macroinvocations - 40403426 + 40397045 id - 40403426 + 40397045 macro_id - 182761 + 182471 location - 5928563 + 5926523 kind @@ -8408,7 +8403,7 @@ 1 2 - 40403426 + 40397045 @@ -8424,7 +8419,7 @@ 1 2 - 40403426 + 40397045 @@ -8440,7 +8435,7 @@ 1 2 - 40403426 + 40397045 @@ -8456,47 +8451,47 @@ 1 2 - 61174 + 61114 2 3 - 27673 + 27615 3 4 - 18085 + 18083 4 5 - 10023 + 10022 5 7 - 13836 + 13835 7 13 - 14708 + 14597 13 33 - 13727 + 13726 33 - 182 - 13727 + 187 + 13726 - 186 + 190 72214 - 9805 + 9749 @@ -8512,42 +8507,42 @@ 1 2 - 77789 + 77673 2 3 - 30669 + 30666 3 4 - 14381 + 14379 4 5 - 10295 + 10294 5 8 - 14054 + 14053 8 18 - 14217 + 14107 18 90 - 13727 + 13726 90 12207 - 7626 + 7571 @@ -8563,12 +8558,12 @@ 1 2 - 178240 + 177950 2 3 - 4521 + 4520 @@ -8584,17 +8579,17 @@ 1 2 - 5264301 + 5262380 2 4 - 429748 + 429653 4 72214 - 234512 + 234490 @@ -8610,12 +8605,12 @@ 1 2 - 5906392 + 5904354 2 37 - 22171 + 22168 @@ -8631,7 +8626,7 @@ 1 2 - 5928563 + 5926523 @@ -8645,13 +8640,13 @@ 12 - 1495 - 1496 + 1493 + 1494 54 - 740200 - 740201 + 740156 + 740157 54 @@ -8671,8 +8666,8 @@ 54 - 3149 - 3150 + 3144 + 3145 54 @@ -8687,13 +8682,13 @@ 12 - 1077 - 1078 + 1075 + 1076 54 - 107755 - 107756 + 107730 + 107731 54 @@ -8704,15 +8699,15 @@ macroparent - 33697131 + 33692864 id - 33697131 + 33692864 parent_id - 15947558 + 15944993 @@ -8726,7 +8721,7 @@ 1 2 - 33697131 + 33692864 @@ -8742,27 +8737,27 @@ 1 2 - 7818554 + 7816769 2 3 - 1596319 + 1596166 3 4 - 4708934 + 4708483 4 5 - 1297526 + 1297402 5 205 - 526223 + 526172 @@ -8772,15 +8767,15 @@ macrolocationbind - 6005902 + 6005206 id - 4197329 + 4196566 location - 2266082 + 2266167 @@ -8794,22 +8789,22 @@ 1 2 - 3276557 + 3275759 2 3 - 487596 + 487614 3 4 - 8638 + 8639 4 5 - 411558 + 411573 5 @@ -8830,27 +8825,27 @@ 1 2 - 1328930 + 1328980 2 3 - 479769 + 479787 3 4 - 7804 + 7805 4 5 - 425585 + 425601 5 522 - 23991 + 23992 @@ -8860,19 +8855,19 @@ macro_argument_unexpanded - 81891296 + 81936815 invocation - 26088765 + 26104126 argument_index - 691 + 692 text - 340741 + 340922 @@ -8886,22 +8881,22 @@ 1 2 - 9605164 + 9611464 2 3 - 9701025 + 9706317 3 4 - 4966085 + 4968887 4 67 - 1816490 + 1817457 @@ -8917,22 +8912,22 @@ 1 2 - 9786454 + 9792851 2 3 - 9718482 + 9723783 3 4 - 4810534 + 4813253 4 67 - 1773293 + 1774237 @@ -8956,8 +8951,8 @@ 52 - 646904 - 2488278 + 646919 + 2488418 31 @@ -9000,57 +8995,57 @@ 1 2 - 39411 + 39432 2 3 - 61870 + 61882 3 4 - 20854 + 20844 4 5 - 34452 + 34449 5 6 - 38961 + 38992 6 9 - 30531 + 30600 9 15 - 28780 + 28774 15 26 - 25687 + 25711 26 57 - 26935 + 26959 57 517 - 25823 + 25837 518 486640 - 7433 + 7437 @@ -9066,17 +9061,17 @@ 1 2 - 241388 + 241517 2 3 - 89214 + 89261 3 9 - 10138 + 10144 @@ -9086,19 +9081,19 @@ macro_argument_expanded - 81891296 + 81936815 invocation - 26088765 + 26104126 argument_index - 691 + 692 text - 206369 + 206479 @@ -9112,22 +9107,22 @@ 1 2 - 9605164 + 9611464 2 3 - 9701025 + 9706317 3 4 - 4966085 + 4968887 4 67 - 1816490 + 1817457 @@ -9143,22 +9138,22 @@ 1 2 - 12543042 + 12550907 2 3 - 8368235 + 8372817 3 4 - 4194392 + 4196783 4 9 - 983095 + 983618 @@ -9182,8 +9177,8 @@ 52 - 646904 - 2488278 + 646919 + 2488418 31 @@ -9226,57 +9221,57 @@ 1 2 - 21671 + 21683 2 3 - 26662 + 26634 3 4 - 43144 + 43167 4 5 - 15915 + 15924 5 6 - 3239 + 3251 6 7 - 18148 + 18169 7 10 - 18819 + 18830 10 19 - 18190 + 18211 19 51 - 15643 + 15661 51 251 - 15496 + 15494 251 - 1169057 - 9436 + 1169168 + 9451 @@ -9292,17 +9287,17 @@ 1 2 - 104280 + 104336 2 3 - 88259 + 88306 3 66 - 13829 + 13836 @@ -9312,19 +9307,19 @@ functions - 3995453 + 3994932 id - 3995453 + 3994932 name - 1670237 + 1666273 kind - 861 + 859 @@ -9338,7 +9333,7 @@ 1 2 - 3995453 + 3994932 @@ -9354,7 +9349,7 @@ 1 2 - 3995453 + 3994932 @@ -9370,17 +9365,17 @@ 1 2 - 1425128 + 1421746 2 4 - 138796 + 138467 4 3162 - 106312 + 106060 @@ -9396,12 +9391,12 @@ 1 2 - 1667407 + 1663450 2 3 - 2830 + 2823 @@ -9417,37 +9412,37 @@ 8 9 - 123 + 122 47 48 - 123 + 122 83 84 - 123 + 122 691 692 - 123 + 122 4456 4457 - 123 + 122 - 5226 - 5227 - 123 + 5272 + 5273 + 122 - 21960 - 21961 - 123 + 21987 + 21988 + 122 @@ -9463,37 +9458,37 @@ 2 3 - 123 + 122 18 19 - 123 + 122 41 42 - 123 + 122 43 44 - 123 + 122 302 303 - 123 + 122 504 505 - 123 + 122 12687 12688 - 123 + 122 @@ -9503,26 +9498,26 @@ builtin_functions - 30699 + 30715 id - 30699 + 30715 function_entry_point - 1123627 + 1124932 id - 1120308 + 1121608 entry_point - 1123627 + 1124932 @@ -9536,12 +9531,12 @@ 1 2 - 1117525 + 1118822 2 17 - 2782 + 2786 @@ -9557,7 +9552,7 @@ 1 2 - 1123627 + 1124932 @@ -9567,15 +9562,15 @@ function_return_type - 4012556 + 4011995 id - 3995453 + 3994932 return_type - 610312 + 610950 @@ -9589,12 +9584,12 @@ 1 2 - 3978349 + 3977869 2 3 - 17103 + 17062 @@ -9610,27 +9605,27 @@ 1 2 - 305402 + 304800 2 3 - 210533 + 211874 3 5 - 47496 + 47506 5 - 365 - 45773 + 464 + 45910 - 432 - 9957 - 1107 + 475 + 9984 + 859 @@ -9910,11 +9905,11 @@ purefunctions - 131870 + 130740 id - 131870 + 130740 @@ -9943,26 +9938,26 @@ function_prototyped - 3993976 + 3993459 id - 3993976 + 3993459 deduction_guide_for_class - 5783 + 5769 id - 5783 + 5769 class_template - 2214 + 2209 @@ -9976,7 +9971,7 @@ 1 2 - 5783 + 5769 @@ -9992,32 +9987,32 @@ 1 2 - 1107 + 1104 2 3 - 369 + 368 3 4 - 123 + 122 4 5 - 246 + 245 5 6 - 123 + 122 8 9 - 246 + 245 @@ -10027,15 +10022,15 @@ member_function_this_type - 664083 + 662507 id - 664083 + 662507 this_type - 173496 + 173084 @@ -10049,7 +10044,7 @@ 1 2 - 664083 + 662507 @@ -10065,37 +10060,37 @@ 1 2 - 46634 + 46524 2 3 - 36421 + 36335 3 4 - 31992 + 31916 4 5 - 19810 + 19763 5 6 - 12673 + 12643 6 10 - 14396 + 14362 10 65 - 11566 + 11538 @@ -10105,27 +10100,27 @@ fun_decls - 4150246 + 4154268 id - 4144339 + 4148376 function - 3971090 + 3974186 type_id - 602560 + 604076 name - 1668760 + 1664800 location - 2774828 + 2768243 @@ -10139,7 +10134,7 @@ 1 2 - 4144339 + 4148376 @@ -10155,12 +10150,12 @@ 1 2 - 4138433 + 4142483 2 3 - 5906 + 5892 @@ -10176,7 +10171,7 @@ 1 2 - 4144339 + 4148376 @@ -10192,7 +10187,7 @@ 1 2 - 4144339 + 4148376 @@ -10208,12 +10203,12 @@ 1 2 - 3812236 + 3814851 2 5 - 158853 + 159335 @@ -10229,12 +10224,12 @@ 1 2 - 3953002 + 3956142 2 3 - 18087 + 18044 @@ -10250,7 +10245,7 @@ 1 2 - 3971090 + 3974186 @@ -10266,12 +10261,12 @@ 1 2 - 3832416 + 3835842 2 4 - 138673 + 138344 @@ -10287,27 +10282,27 @@ 1 2 - 291128 + 290192 2 3 - 217177 + 219240 3 5 - 47865 + 48365 5 - 365 - 45281 + 506 + 45419 - 463 - 10297 - 1107 + 555 + 10332 + 859 @@ -10323,27 +10318,22 @@ 1 2 - 300972 + 300749 2 3 - 208564 + 210401 3 5 - 47619 + 47628 5 - 1479 - 45281 - - - 9905 - 9906 - 123 + 9941 + 45296 @@ -10359,22 +10349,22 @@ 1 2 - 484558 + 485986 2 3 - 52048 + 52293 3 7 - 49464 + 49347 7 2238 - 16488 + 16449 @@ -10390,22 +10380,22 @@ 1 2 - 448505 + 449159 2 3 - 68414 + 69356 3 6 - 55248 + 55239 6 4756 - 30392 + 30320 @@ -10421,22 +10411,22 @@ 1 2 - 1313155 + 1310039 2 3 - 191460 + 190883 3 11 - 128091 + 127787 11 3169 - 36052 + 36089 @@ -10452,17 +10442,17 @@ 1 2 - 1424636 + 1421255 2 4 - 139289 + 138958 4 3162 - 104835 + 104587 @@ -10478,12 +10468,12 @@ 1 2 - 1580167 + 1576417 2 1596 - 88593 + 88383 @@ -10499,17 +10489,17 @@ 1 2 - 1348593 + 1345392 2 3 - 205488 + 205000 3 1592 - 114679 + 114407 @@ -10525,17 +10515,17 @@ 1 2 - 2387600 + 2376164 2 3 - 247816 + 251770 3 211 - 139412 + 140308 @@ -10551,17 +10541,17 @@ 1 2 - 2406057 + 2395928 2 3 - 229851 + 232497 3 211 - 138919 + 139817 @@ -10577,12 +10567,12 @@ 1 2 - 2662241 + 2655309 2 211 - 112587 + 112934 @@ -10598,12 +10588,12 @@ 1 2 - 2736192 + 2729698 2 8 - 38636 + 38545 @@ -10613,22 +10603,22 @@ fun_def - 1400518 + 1397440 id - 1400518 + 1397440 fun_specialized - 7909 + 7841 id - 7909 + 7841 @@ -10646,15 +10636,15 @@ fun_decl_specifiers - 4221244 + 4214909 id - 1724378 + 1723968 name - 1353 + 1350 @@ -10668,22 +10658,22 @@ 1 2 - 357943 + 360776 2 3 - 258644 + 258030 3 4 - 1085149 + 1082574 4 5 - 22640 + 22586 @@ -10699,57 +10689,57 @@ 15 16 - 123 + 122 19 20 - 123 + 122 222 223 - 123 + 122 261 262 - 123 + 122 561 562 - 123 + 122 826 827 - 123 + 122 1034 1035 - 123 + 122 1093 1094 - 123 + 122 8148 8149 - 123 + 122 11028 11029 - 123 + 122 - 11099 - 11100 - 123 + 11129 + 11130 + 122 @@ -10880,26 +10870,26 @@ fun_decl_empty_throws - 421484 + 433439 fun_decl - 421484 + 433439 fun_decl_noexcept - 139581 + 139743 fun_decl - 139581 + 139743 constant - 139145 + 139307 @@ -10913,7 +10903,7 @@ 1 2 - 139581 + 139743 @@ -10929,12 +10919,12 @@ 1 2 - 138709 + 138870 2 3 - 435 + 436 @@ -10944,26 +10934,26 @@ fun_decl_empty_noexcept - 1147042 + 1156104 fun_decl - 1147042 + 1156104 fun_decl_typedef_type - 2755 + 2760 fun_decl - 2755 + 2760 typedeftype_id - 123 + 124 @@ -10977,7 +10967,7 @@ 1 2 - 2755 + 2760 @@ -10993,57 +10983,57 @@ 1 2 - 39 + 40 2 3 - 11 + 12 3 4 - 11 + 12 5 13 - 7 + 8 16 17 - 11 + 12 17 18 - 3 + 4 21 22 - 7 + 8 25 43 - 7 + 8 46 55 - 7 + 8 89 128 - 7 + 8 158 159 - 3 + 4 @@ -11065,7 +11055,7 @@ constraint - 28696 + 28697 @@ -11204,7 +11194,7 @@ 1 2 - 28696 + 28697 @@ -11214,19 +11204,19 @@ param_decl_bind - 7208821 + 7218351 id - 7208821 + 7218351 index - 7874 + 7856 fun_decl - 3482840 + 3488446 @@ -11240,7 +11230,7 @@ 1 2 - 7208821 + 7218351 @@ -11256,7 +11246,7 @@ 1 2 - 7208821 + 7218351 @@ -11272,32 +11262,32 @@ 2 3 - 3937 + 3928 6 7 - 1968 + 1964 16 20 - 615 + 613 25 147 - 615 + 613 343 - 16206 - 615 + 16310 + 613 - 28305 - 28306 - 123 + 28418 + 28419 + 122 @@ -11313,32 +11303,32 @@ 2 3 - 3937 + 3928 6 7 - 1968 + 1964 16 20 - 615 + 613 25 147 - 615 + 613 343 - 16206 - 615 + 16310 + 613 - 28305 - 28306 - 123 + 28418 + 28419 + 122 @@ -11354,27 +11344,27 @@ 1 2 - 1488866 + 1486438 2 3 - 961980 + 972463 3 4 - 593700 + 592291 4 5 - 286576 + 285895 5 65 - 151716 + 151356 @@ -11390,27 +11380,27 @@ 1 2 - 1488866 + 1486438 2 3 - 961980 + 972463 3 4 - 593700 + 592291 4 5 - 286576 + 285895 5 65 - 151716 + 151356 @@ -11420,27 +11410,27 @@ var_decls - 9438060 + 9442668 id - 9431661 + 9436285 variable - 9094636 + 9098463 type_id - 1436079 + 1440773 name - 840901 + 838906 location - 6190362 + 6175671 @@ -11454,7 +11444,7 @@ 1 2 - 9431661 + 9436285 @@ -11470,12 +11460,12 @@ 1 2 - 9425263 + 9429901 2 3 - 6398 + 6383 @@ -11491,7 +11481,7 @@ 1 2 - 9431661 + 9436285 @@ -11507,7 +11497,7 @@ 1 2 - 9431661 + 9436285 @@ -11523,12 +11513,12 @@ 1 2 - 8774837 + 8778319 2 5 - 319798 + 320144 @@ -11544,12 +11534,12 @@ 1 2 - 9042218 + 9046170 2 3 - 52417 + 52293 @@ -11565,12 +11555,12 @@ 1 2 - 8990662 + 8994735 2 4 - 103974 + 103727 @@ -11586,12 +11576,12 @@ 1 2 - 8853095 + 8857496 2 4 - 241540 + 240967 @@ -11607,27 +11597,27 @@ 1 2 - 839056 + 839151 2 3 - 279685 + 280617 3 5 - 125138 + 127296 5 11 - 111357 + 112934 11 2963 - 80841 + 80772 @@ -11643,27 +11633,27 @@ 1 2 - 859482 + 860388 2 3 - 265042 + 265764 3 5 - 120585 + 122141 5 11 - 110988 + 112566 11 2886 - 79980 + 79913 @@ -11679,22 +11669,22 @@ 1 2 - 1104222 + 1104793 2 3 - 189861 + 191006 3 7 - 113326 + 116371 7 1038 - 28669 + 28601 @@ -11710,27 +11700,27 @@ 1 2 - 971823 + 974304 2 3 - 216070 + 215189 3 - 6 - 131660 + 5 + 104587 - 6 - 98 - 107789 + 5 + 15 + 109865 - 99 + 15 2622 - 8736 + 36826 @@ -11746,32 +11736,32 @@ 1 2 - 458595 + 457507 2 3 - 162052 + 161668 3 4 - 59431 + 59290 4 7 - 64968 + 64814 7 24 - 63492 + 63341 24 27139 - 32361 + 32284 @@ -11787,32 +11777,32 @@ 1 2 - 469546 + 468432 2 3 - 162052 + 161668 3 4 - 55248 + 55116 4 8 - 71367 + 71197 8 44 - 63861 + 63586 44 26704 - 18826 + 18904 @@ -11828,22 +11818,22 @@ 1 2 - 644273 + 642744 2 3 - 111111 + 110847 3 11 - 64230 + 64078 11 3463 - 21287 + 21236 @@ -11859,27 +11849,27 @@ 1 2 - 485911 + 484758 2 3 - 181371 + 180940 3 4 - 51433 + 51311 4 8 - 64107 + 63955 8 22619 - 58078 + 57940 @@ -11895,17 +11885,17 @@ 1 2 - 5693745 + 5670781 2 - 20 - 467947 + 16 + 465117 - 20 + 16 2943 - 28669 + 39772 @@ -11921,12 +11911,12 @@ 1 2 - 5773479 + 5751431 2 2935 - 416882 + 424240 @@ -11942,12 +11932,12 @@ 1 2 - 5895911 + 5874922 2 2555 - 294451 + 300749 @@ -11963,12 +11953,12 @@ 1 2 - 6178180 + 6163519 2 5 - 12181 + 12152 @@ -11978,11 +11968,11 @@ var_def - 3716014 + 3707686 id - 3716014 + 3707686 @@ -12000,15 +11990,15 @@ var_decl_specifiers - 482712 + 481567 id - 482712 + 481567 name - 492 + 491 @@ -12022,7 +12012,7 @@ 1 2 - 482712 + 481567 @@ -12038,22 +12028,22 @@ 16 17 - 123 + 122 77 78 - 123 + 122 653 654 - 123 + 122 3177 3178 - 123 + 122 @@ -12132,19 +12122,19 @@ type_decls - 1610928 + 1639390 id - 1610928 + 1639390 type_id - 1592225 + 1620731 location - 1526272 + 1543273 @@ -12158,7 +12148,7 @@ 1 2 - 1610928 + 1639390 @@ -12174,7 +12164,7 @@ 1 2 - 1610928 + 1639390 @@ -12190,12 +12180,12 @@ 1 2 - 1576106 + 1604650 2 10 - 16119 + 16080 @@ -12211,12 +12201,12 @@ 1 2 - 1576229 + 1604773 2 10 - 15996 + 15958 @@ -12232,12 +12222,12 @@ 1 2 - 1504493 + 1513198 2 64 - 21779 + 30074 @@ -12253,12 +12243,12 @@ 1 2 - 1504616 + 1513321 2 64 - 21656 + 29952 @@ -12268,22 +12258,22 @@ type_def - 1080351 + 1092272 id - 1080351 + 1092272 type_decl_top - 676681 + 676616 type_decl - 676681 + 676616 @@ -12363,23 +12353,23 @@ namespace_decls - 408652 + 405513 id - 408652 + 405513 namespace_id - 1837 + 1768 location - 408652 + 405513 bodylocation - 408652 + 405513 @@ -12393,7 +12383,7 @@ 1 2 - 408652 + 405513 @@ -12409,7 +12399,7 @@ 1 2 - 408652 + 405513 @@ -12425,7 +12415,7 @@ 1 2 - 408652 + 405513 @@ -12441,57 +12431,57 @@ 1 2 - 388 + 363 2 3 - 202 + 185 3 - 6 - 170 + 5 + 129 - 6 - 15 - 153 - - - 15 - 34 + 5 + 12 145 - 35 - 62 - 145 + 12 + 30 + 137 - 63 - 81 - 145 + 30 + 57 + 137 - 86 - 144 - 153 + 57 + 76 + 137 - 153 - 232 - 145 + 77 + 127 + 137 - 263 - 1517 - 145 + 132 + 187 + 137 - 1890 - 12533 - 40 + 189 + 431 + 137 + + + 448 + 12466 + 121 @@ -12507,57 +12497,57 @@ 1 2 - 388 + 363 2 3 - 202 + 185 3 - 6 - 170 + 5 + 129 - 6 - 15 - 153 - - - 15 - 34 + 5 + 12 145 - 35 - 62 - 145 + 12 + 30 + 137 - 63 - 81 - 145 + 30 + 57 + 137 - 86 - 144 - 153 + 57 + 76 + 137 - 153 - 232 - 145 + 77 + 127 + 137 - 263 - 1517 - 145 + 132 + 187 + 137 - 1890 - 12533 - 40 + 189 + 431 + 137 + + + 448 + 12466 + 121 @@ -12573,57 +12563,57 @@ 1 2 - 388 + 363 2 3 - 202 + 185 3 - 6 - 170 + 5 + 129 - 6 - 15 - 153 - - - 15 - 34 + 5 + 12 145 - 35 - 62 - 145 + 12 + 30 + 137 - 63 - 81 - 145 + 30 + 57 + 137 - 86 - 144 - 153 + 57 + 76 + 137 - 153 - 232 - 145 + 77 + 127 + 137 - 263 - 1517 - 145 + 132 + 187 + 137 - 1890 - 12533 - 40 + 189 + 431 + 137 + + + 448 + 12466 + 121 @@ -12639,7 +12629,7 @@ 1 2 - 408652 + 405513 @@ -12655,7 +12645,7 @@ 1 2 - 408652 + 405513 @@ -12671,7 +12661,7 @@ 1 2 - 408652 + 405513 @@ -12687,7 +12677,7 @@ 1 2 - 408652 + 405513 @@ -12703,7 +12693,7 @@ 1 2 - 408652 + 405513 @@ -12719,7 +12709,7 @@ 1 2 - 408652 + 405513 @@ -12729,19 +12719,19 @@ usings - 270032 + 269966 id - 270032 + 269966 element_id - 58567 + 58399 location - 26652 + 26666 kind @@ -12759,7 +12749,7 @@ 1 2 - 270032 + 269966 @@ -12775,7 +12765,7 @@ 1 2 - 270032 + 269966 @@ -12791,7 +12781,7 @@ 1 2 - 270032 + 269966 @@ -12807,17 +12797,17 @@ 1 2 - 50892 + 50730 2 5 - 5347 + 5339 5 134 - 2327 + 2328 @@ -12833,17 +12823,17 @@ 1 2 - 50892 + 50730 2 5 - 5347 + 5339 5 134 - 2327 + 2328 @@ -12859,7 +12849,7 @@ 1 2 - 58567 + 58399 @@ -12875,22 +12865,22 @@ 1 2 - 21021 + 21043 2 4 - 2285 + 2276 4 132 - 1929 + 1930 145 - 366 - 1415 + 364 + 1416 @@ -12906,22 +12896,22 @@ 1 2 - 21021 + 21043 2 4 - 2285 + 2276 4 132 - 1929 + 1930 145 - 366 - 1415 + 364 + 1416 @@ -12937,7 +12927,7 @@ 1 2 - 26652 + 26666 @@ -12956,8 +12946,8 @@ 10 - 25362 - 25363 + 25342 + 25343 10 @@ -12977,8 +12967,8 @@ 10 - 5372 - 5373 + 5353 + 5354 10 @@ -13010,15 +13000,15 @@ using_container - 575839 + 571131 parent - 21734 + 20151 child - 270032 + 269966 @@ -13032,37 +13022,37 @@ 1 2 - 10295 + 8958 2 3 - 1604 + 1584 3 6 - 1845 + 1762 6 7 - 2275 + 2244 7 - 28 - 1656 + 26 + 1521 - 28 + 26 136 - 775 + 797 145 146 - 2600 + 2601 146 @@ -13083,27 +13073,27 @@ 1 2 - 95840 + 96332 2 3 - 119399 + 119536 3 4 - 19952 + 19585 4 5 - 26515 + 26330 5 65 - 8324 + 8182 @@ -13113,27 +13103,27 @@ static_asserts - 172696 + 171628 id - 172696 + 171628 condition - 172696 + 171628 message - 38640 + 38481 location - 22578 + 22434 enclosing - 6808 + 6202 @@ -13147,7 +13137,7 @@ 1 2 - 172696 + 171628 @@ -13163,7 +13153,7 @@ 1 2 - 172696 + 171628 @@ -13179,7 +13169,7 @@ 1 2 - 172696 + 171628 @@ -13195,7 +13185,7 @@ 1 2 - 172696 + 171628 @@ -13211,7 +13201,7 @@ 1 2 - 172696 + 171628 @@ -13227,7 +13217,7 @@ 1 2 - 172696 + 171628 @@ -13243,7 +13233,7 @@ 1 2 - 172696 + 171628 @@ -13259,7 +13249,7 @@ 1 2 - 172696 + 171628 @@ -13275,32 +13265,32 @@ 1 2 - 28407 + 28330 2 3 - 639 + 662 3 4 - 3618 + 3585 4 - 12 - 2080 + 10 + 2043 12 17 - 3124 + 3101 17 513 - 769 + 759 @@ -13316,32 +13306,32 @@ 1 2 - 28407 + 28330 2 3 - 639 + 662 3 4 - 3618 + 3585 4 - 12 - 2080 + 10 + 2043 12 17 - 3124 + 3101 17 513 - 769 + 759 @@ -13357,12 +13347,12 @@ 1 2 - 35807 + 35679 2 33 - 2833 + 2802 @@ -13378,27 +13368,27 @@ 1 2 - 30212 + 30147 2 3 - 348 + 355 3 4 - 3383 + 3351 4 12 - 1902 + 1865 12 43 - 2793 + 2761 @@ -13414,52 +13404,52 @@ 1 2 - 4266 + 4255 2 3 - 3715 + 3690 3 4 - 1740 + 1720 4 5 - 121 + 104 5 6 - 4719 + 4692 6 13 - 429 + 428 14 15 - 2639 + 2632 16 17 - 64 + 48 17 18 - 4379 + 4369 19 52 - 501 + 492 @@ -13475,52 +13465,52 @@ 1 2 - 4266 + 4255 2 3 - 3715 + 3690 3 4 - 1740 + 1720 4 5 - 121 + 104 5 6 - 4719 + 4692 6 13 - 429 + 428 14 15 - 2639 + 2632 16 17 - 64 + 48 17 18 - 4379 + 4369 19 52 - 501 + 492 @@ -13536,17 +13526,17 @@ 1 2 - 6937 + 6832 2 3 - 7650 + 7631 3 4 - 7755 + 7736 4 @@ -13567,37 +13557,37 @@ 1 2 - 5051 + 5055 2 3 - 8071 + 8019 3 4 - 1481 + 1461 4 5 - 4744 + 4716 5 13 - 493 + 476 13 14 - 2639 + 2632 16 43 - 97 + 72 @@ -13613,22 +13603,22 @@ 1 2 - 5707 + 5152 2 3 - 526 + 476 3 - 228 - 526 + 210 + 476 - 229 + 223 11052 - 48 + 96 @@ -13644,22 +13634,22 @@ 1 2 - 5707 + 5152 2 3 - 526 + 476 3 - 228 - 526 + 210 + 476 - 229 + 223 11052 - 48 + 96 @@ -13675,17 +13665,17 @@ 1 2 - 5861 + 5305 2 3 - 518 + 476 3 2936 - 429 + 419 @@ -13701,17 +13691,17 @@ 1 2 - 5845 + 5289 2 3 - 534 + 492 3 1929 - 429 + 419 @@ -13721,23 +13711,23 @@ params - 6969125 + 6970509 id - 6929135 + 6930613 function - 3360408 + 3361394 index - 7874 + 7856 type_id - 1203274 + 1206679 @@ -13751,7 +13741,7 @@ 1 2 - 6929135 + 6930613 @@ -13767,7 +13757,7 @@ 1 2 - 6929135 + 6930613 @@ -13783,12 +13773,12 @@ 1 2 - 6889145 + 6890718 2 3 - 39990 + 39895 @@ -13804,27 +13794,27 @@ 1 2 - 1454044 + 1450593 2 3 - 913499 + 920292 3 4 - 571429 + 570073 4 5 - 277101 + 276443 5 65 - 144333 + 143991 @@ -13840,27 +13830,27 @@ 1 2 - 1454044 + 1450593 2 3 - 913499 + 920292 3 4 - 571429 + 570073 4 5 - 277101 + 276443 5 65 - 144333 + 143991 @@ -13876,22 +13866,22 @@ 1 2 - 1757600 + 1757357 2 3 - 1017228 + 1019846 3 4 - 432386 + 431360 4 11 - 153193 + 152829 @@ -13907,32 +13897,32 @@ 2 3 - 3937 + 3928 6 7 - 1968 + 1964 14 18 - 615 + 613 23 138 - 615 + 613 322 - 15494 - 615 + 15567 + 613 - 27310 - 27311 - 123 + 27383 + 27384 + 122 @@ -13948,32 +13938,32 @@ 2 3 - 3937 + 3928 6 7 - 1968 + 1964 14 18 - 615 + 613 23 138 - 615 + 613 322 - 15494 - 615 + 15567 + 613 - 27310 - 27311 - 123 + 27383 + 27384 + 122 @@ -13989,32 +13979,32 @@ 1 2 - 3937 + 3928 2 3 - 1968 + 1964 4 7 - 615 + 613 9 55 - 615 + 613 116 - 2700 - 615 + 2755 + 613 - 7494 - 7495 - 123 + 7521 + 7522 + 122 @@ -14030,27 +14020,27 @@ 1 2 - 728068 + 728672 2 3 - 236495 + 237039 3 5 - 91669 + 92925 5 13 - 92408 + 93539 13 2574 - 54632 + 54503 @@ -14066,27 +14056,27 @@ 1 2 - 809278 + 810672 2 3 - 175833 + 175784 3 6 - 104958 + 107042 6 27 - 90808 + 90838 27 2562 - 22394 + 22341 @@ -14102,17 +14092,17 @@ 1 2 - 981544 + 981670 2 3 - 164267 + 167683 3 65 - 57462 + 57326 @@ -14122,15 +14112,15 @@ overrides - 159103 + 159700 new - 150336 + 150954 old - 17794 + 17451 @@ -14144,12 +14134,12 @@ 1 2 - 141576 + 142215 2 4 - 8759 + 8738 @@ -14165,32 +14155,32 @@ 1 2 - 9682 + 9392 2 3 - 2404 + 2366 3 4 - 1643 + 1647 4 6 - 1481 + 1437 6 - 17 - 1335 + 16 + 1332 - 17 + 16 230 - 1246 + 1275 @@ -14200,19 +14190,19 @@ membervariables - 1505673 + 1505529 id - 1503222 + 1503078 type_id - 458130 + 458086 name - 644432 + 644370 @@ -14226,7 +14216,7 @@ 1 2 - 1500880 + 1500736 2 @@ -14247,7 +14237,7 @@ 1 2 - 1503222 + 1503078 @@ -14263,22 +14253,22 @@ 1 2 - 339920 + 339887 2 3 - 72614 + 72607 3 10 - 35408 + 35404 10 4445 - 10186 + 10185 @@ -14294,17 +14284,17 @@ 1 2 - 357515 + 357481 2 3 - 64770 + 64763 3 57 - 34373 + 34370 60 @@ -14325,22 +14315,22 @@ 1 2 - 423484 + 423443 2 3 - 122621 + 122610 3 5 - 58124 + 58118 5 664 - 40202 + 40198 @@ -14356,17 +14346,17 @@ 1 2 - 526550 + 526499 2 3 - 73322 + 73315 3 668 - 44560 + 44555 @@ -14376,19 +14366,19 @@ globalvariables - 662484 + 661280 id - 662484 + 661280 type_id - 10212 + 10188 name - 110988 + 110724 @@ -14402,7 +14392,7 @@ 1 2 - 662484 + 661280 @@ -14418,7 +14408,7 @@ 1 2 - 662484 + 661280 @@ -14434,32 +14424,32 @@ 1 2 - 6890 + 6874 2 3 - 369 + 368 3 5 - 738 + 736 5 20 - 861 + 859 20 80 - 861 + 859 152 - 2369 - 492 + 2372 + 491 @@ -14475,32 +14465,32 @@ 1 2 - 7013 + 6997 2 3 - 369 + 368 3 5 - 738 + 736 5 20 - 738 + 736 20 74 - 861 + 859 137 228 - 492 + 491 @@ -14516,22 +14506,22 @@ 1 2 - 92900 + 92679 2 8 - 9351 + 9329 8 139 - 8367 + 8347 181 1156 - 369 + 368 @@ -14547,17 +14537,17 @@ 1 2 - 94130 + 93907 2 3 - 16611 + 16571 3 4 - 246 + 245 @@ -14567,19 +14557,19 @@ localvariables - 724508 + 725852 id - 724508 + 725852 type_id - 53305 + 53389 name - 101431 + 101620 @@ -14593,7 +14583,7 @@ 1 2 - 724508 + 725852 @@ -14609,7 +14599,7 @@ 1 2 - 724508 + 725852 @@ -14625,37 +14615,37 @@ 1 2 - 28819 + 28869 2 3 - 7799 + 7802 3 4 - 4033 + 4041 4 6 - 4057 + 4065 6 12 - 4105 + 4113 12 - 163 - 4001 + 162 + 4005 - 164 + 162 19347 - 487 + 492 @@ -14671,22 +14661,22 @@ 1 2 - 38253 + 38308 2 3 - 6705 + 6718 3 5 - 4469 + 4477 5 3509 - 3878 + 3885 @@ -14702,32 +14692,32 @@ 1 2 - 62415 + 62532 2 3 - 16007 + 16037 3 4 - 6525 + 6538 4 8 - 8139 + 8154 8 137 - 7616 + 7630 137 7546 - 726 + 728 @@ -14743,22 +14733,22 @@ 1 2 - 84417 + 84575 2 3 - 8395 + 8410 3 15 - 7668 + 7682 15 1509 - 950 + 952 @@ -14768,15 +14758,15 @@ autoderivation - 224437 + 223904 var - 224437 + 223904 derivation_type - 615 + 613 @@ -14790,7 +14780,7 @@ 1 2 - 224437 + 223904 @@ -14806,27 +14796,27 @@ 38 39 - 123 + 122 79 80 - 123 + 122 450 451 - 123 + 122 527 528 - 123 + 122 730 731 - 123 + 122 @@ -14836,15 +14826,15 @@ orphaned_variables - 43621 + 43672 var - 43621 + 43672 function - 40402 + 40449 @@ -14858,7 +14848,7 @@ 1 2 - 43621 + 43672 @@ -14874,12 +14864,12 @@ 1 2 - 39564 + 39610 2 47 - 838 + 839 @@ -14889,19 +14879,19 @@ enumconstants - 348146 + 348112 id - 348146 + 348112 parent - 41618 + 41614 index - 13945 + 13944 type_id @@ -14909,11 +14899,11 @@ name - 347764 + 347731 location - 320745 + 320714 @@ -14927,7 +14917,7 @@ 1 2 - 348146 + 348112 @@ -14943,7 +14933,7 @@ 1 2 - 348146 + 348112 @@ -14959,7 +14949,7 @@ 1 2 - 348146 + 348112 @@ -14975,7 +14965,7 @@ 1 2 - 348146 + 348112 @@ -14991,7 +14981,7 @@ 1 2 - 348146 + 348112 @@ -15022,7 +15012,7 @@ 4 5 - 5556 + 5555 5 @@ -15037,12 +15027,12 @@ 7 8 - 1961 + 1960 8 10 - 2996 + 2995 10 @@ -15088,7 +15078,7 @@ 4 5 - 5556 + 5555 5 @@ -15103,12 +15093,12 @@ 7 8 - 1961 + 1960 8 10 - 2996 + 2995 10 @@ -15139,7 +15129,7 @@ 1 2 - 41618 + 41614 @@ -15170,7 +15160,7 @@ 4 5 - 5556 + 5555 5 @@ -15185,12 +15175,12 @@ 7 8 - 1961 + 1960 8 10 - 2996 + 2995 10 @@ -15231,7 +15221,7 @@ 3 4 - 8770 + 8769 4 @@ -15251,12 +15241,12 @@ 7 8 - 1852 + 1851 8 11 - 3813 + 3812 11 @@ -15287,7 +15277,7 @@ 1 2 - 2778 + 2777 2 @@ -15343,7 +15333,7 @@ 1 2 - 2778 + 2777 2 @@ -15399,7 +15389,7 @@ 1 2 - 13945 + 13944 @@ -15415,7 +15405,7 @@ 1 2 - 2778 + 2777 2 @@ -15471,7 +15461,7 @@ 1 2 - 2778 + 2777 2 @@ -15607,7 +15597,7 @@ 1 2 - 347383 + 347350 2 @@ -15628,7 +15618,7 @@ 1 2 - 347383 + 347350 2 @@ -15649,7 +15639,7 @@ 1 2 - 347764 + 347731 @@ -15665,7 +15655,7 @@ 1 2 - 347764 + 347731 @@ -15681,7 +15671,7 @@ 1 2 - 347383 + 347350 2 @@ -15702,12 +15692,12 @@ 1 2 - 319710 + 319679 2 205 - 1035 + 1034 @@ -15723,7 +15713,7 @@ 1 2 - 320745 + 320714 @@ -15739,12 +15729,12 @@ 1 2 - 319710 + 319679 2 205 - 1035 + 1034 @@ -15760,7 +15750,7 @@ 1 2 - 320745 + 320714 @@ -15776,12 +15766,12 @@ 1 2 - 319710 + 319679 2 205 - 1035 + 1034 @@ -15791,31 +15781,31 @@ builtintypes - 7136 + 7119 id - 7136 + 7119 name - 7136 + 7119 kind - 7136 + 7119 size - 861 + 859 sign - 369 + 368 alignment - 615 + 613 @@ -15829,7 +15819,7 @@ 1 2 - 7136 + 7119 @@ -15845,7 +15835,7 @@ 1 2 - 7136 + 7119 @@ -15861,7 +15851,7 @@ 1 2 - 7136 + 7119 @@ -15877,7 +15867,7 @@ 1 2 - 7136 + 7119 @@ -15893,7 +15883,7 @@ 1 2 - 7136 + 7119 @@ -15909,7 +15899,7 @@ 1 2 - 7136 + 7119 @@ -15925,7 +15915,7 @@ 1 2 - 7136 + 7119 @@ -15941,7 +15931,7 @@ 1 2 - 7136 + 7119 @@ -15957,7 +15947,7 @@ 1 2 - 7136 + 7119 @@ -15973,7 +15963,7 @@ 1 2 - 7136 + 7119 @@ -15989,7 +15979,7 @@ 1 2 - 7136 + 7119 @@ -16005,7 +15995,7 @@ 1 2 - 7136 + 7119 @@ -16021,7 +16011,7 @@ 1 2 - 7136 + 7119 @@ -16037,7 +16027,7 @@ 1 2 - 7136 + 7119 @@ -16053,7 +16043,7 @@ 1 2 - 7136 + 7119 @@ -16069,32 +16059,32 @@ 2 3 - 246 + 245 8 9 - 123 + 122 9 10 - 123 + 122 10 11 - 123 + 122 13 14 - 123 + 122 14 15 - 123 + 122 @@ -16110,32 +16100,32 @@ 2 3 - 246 + 245 8 9 - 123 + 122 9 10 - 123 + 122 10 11 - 123 + 122 13 14 - 123 + 122 14 15 - 123 + 122 @@ -16151,32 +16141,32 @@ 2 3 - 246 + 245 8 9 - 123 + 122 9 10 - 123 + 122 10 11 - 123 + 122 13 14 - 123 + 122 14 15 - 123 + 122 @@ -16192,12 +16182,12 @@ 1 2 - 246 + 245 3 4 - 615 + 613 @@ -16213,12 +16203,12 @@ 1 2 - 492 + 491 2 3 - 369 + 368 @@ -16234,17 +16224,17 @@ 6 7 - 123 + 122 12 13 - 123 + 122 40 41 - 123 + 122 @@ -16260,17 +16250,17 @@ 6 7 - 123 + 122 12 13 - 123 + 122 40 41 - 123 + 122 @@ -16286,17 +16276,17 @@ 6 7 - 123 + 122 12 13 - 123 + 122 40 41 - 123 + 122 @@ -16312,12 +16302,12 @@ 5 6 - 246 + 245 7 8 - 123 + 122 @@ -16333,7 +16323,7 @@ 5 6 - 369 + 368 @@ -16349,27 +16339,27 @@ 7 8 - 123 + 122 10 11 - 123 + 122 12 13 - 123 + 122 13 14 - 123 + 122 16 17 - 123 + 122 @@ -16385,27 +16375,27 @@ 7 8 - 123 + 122 10 11 - 123 + 122 12 13 - 123 + 122 13 14 - 123 + 122 16 17 - 123 + 122 @@ -16421,27 +16411,27 @@ 7 8 - 123 + 122 10 11 - 123 + 122 12 13 - 123 + 122 13 14 - 123 + 122 16 17 - 123 + 122 @@ -16457,7 +16447,7 @@ 2 3 - 615 + 613 @@ -16473,7 +16463,7 @@ 3 4 - 615 + 613 @@ -16483,23 +16473,23 @@ derivedtypes - 2998651 + 2997672 id - 2998651 + 2997672 name - 1444200 + 1445315 kind - 738 + 736 type_id - 1926174 + 1925654 @@ -16513,7 +16503,7 @@ 1 2 - 2998651 + 2997672 @@ -16529,7 +16519,7 @@ 1 2 - 2998651 + 2997672 @@ -16545,7 +16535,7 @@ 1 2 - 2998651 + 2997672 @@ -16561,17 +16551,17 @@ 1 2 - 1326444 + 1327838 2 - 22 - 108527 + 23 + 108760 - 22 + 23 4289 - 9228 + 8715 @@ -16587,7 +16577,7 @@ 1 2 - 1444200 + 1445315 @@ -16603,17 +16593,17 @@ 1 2 - 1326567 + 1327961 2 - 22 - 108404 + 23 + 108638 - 22 + 23 4289 - 9228 + 8715 @@ -16629,32 +16619,32 @@ 730 731 - 123 + 122 2337 2338 - 123 + 122 3659 3660 - 123 + 122 4288 4289 - 123 + 122 - 5571 - 5572 - 123 + 5595 + 5596 + 122 - 7785 - 7786 - 123 + 7811 + 7812 + 122 @@ -16670,32 +16660,32 @@ 1 2 - 123 + 122 674 675 - 123 + 122 1614 1615 - 123 + 122 - 2432 - 2433 - 123 + 2443 + 2444 + 122 2672 2673 - 123 + 122 - 4344 - 4345 - 123 + 4370 + 4371 + 122 @@ -16711,32 +16701,32 @@ 213 214 - 123 + 122 2337 2338 - 123 + 122 3655 3656 - 123 + 122 4288 4289 - 123 + 122 - 5506 - 5507 - 123 + 5530 + 5531 + 122 - 7785 - 7786 - 123 + 7811 + 7812 + 122 @@ -16752,22 +16742,22 @@ 1 2 - 1303434 + 1302919 2 3 - 372462 + 372438 3 4 - 121324 + 121650 4 137 - 128953 + 128647 @@ -16783,22 +16773,22 @@ 1 2 - 1304911 + 1304392 2 3 - 372462 + 372438 3 4 - 119847 + 120176 4 137 - 128953 + 128647 @@ -16814,22 +16804,22 @@ 1 2 - 1305280 + 1304760 2 3 - 373077 + 373051 3 4 - 121570 + 121895 4 6 - 126246 + 125946 @@ -16839,19 +16829,19 @@ pointerishsize - 2223333 + 2221248 id - 2223333 + 2221248 size - 246 + 245 alignment - 246 + 245 @@ -16865,7 +16855,7 @@ 1 2 - 2223333 + 2221248 @@ -16881,7 +16871,7 @@ 1 2 - 2223333 + 2221248 @@ -16897,12 +16887,12 @@ 3 4 - 123 + 122 - 18066 - 18067 - 123 + 18092 + 18093 + 122 @@ -16918,7 +16908,7 @@ 1 2 - 246 + 245 @@ -16934,12 +16924,12 @@ 3 4 - 123 + 122 - 18066 - 18067 - 123 + 18092 + 18093 + 122 @@ -16955,7 +16945,7 @@ 1 2 - 246 + 245 @@ -16965,23 +16955,23 @@ arraysizes - 79488 + 79299 id - 79488 + 79299 num_elements - 17595 + 17553 bytesize - 19933 + 19886 alignment - 615 + 613 @@ -16995,7 +16985,7 @@ 1 2 - 79488 + 79299 @@ -17011,7 +17001,7 @@ 1 2 - 79488 + 79299 @@ -17027,7 +17017,7 @@ 1 2 - 79488 + 79299 @@ -17043,37 +17033,37 @@ 1 2 - 246 + 245 2 3 - 10705 + 10679 3 4 - 246 + 245 4 5 - 3445 + 3437 5 9 - 1476 + 1473 9 42 - 1353 + 1350 56 57 - 123 + 122 @@ -17089,22 +17079,22 @@ 1 2 - 11566 + 11538 2 3 - 3937 + 3928 3 5 - 984 + 982 5 11 - 1107 + 1104 @@ -17120,22 +17110,22 @@ 1 2 - 11566 + 11538 2 3 - 3937 + 3928 3 4 - 738 + 736 4 6 - 1353 + 1350 @@ -17151,37 +17141,37 @@ 1 2 - 615 + 613 2 3 - 12550 + 12520 3 4 - 492 + 491 4 5 - 2707 + 2700 5 7 - 1476 + 1473 7 17 - 1599 + 1595 24 45 - 492 + 491 @@ -17197,22 +17187,22 @@ 1 2 - 14396 + 14362 2 3 - 3568 + 3559 3 6 - 1845 + 1841 6 7 - 123 + 122 @@ -17228,22 +17218,22 @@ 1 2 - 14642 + 14607 2 3 - 3322 + 3314 3 5 - 1599 + 1595 5 6 - 369 + 368 @@ -17259,27 +17249,27 @@ 10 11 - 123 + 122 86 87 - 123 + 122 91 92 - 123 + 122 121 122 - 123 + 122 338 339 - 123 + 122 @@ -17295,22 +17285,22 @@ 4 5 - 123 + 122 16 17 - 246 + 245 48 49 - 123 + 122 139 140 - 123 + 122 @@ -17326,27 +17316,27 @@ 4 5 - 123 + 122 19 20 - 123 + 122 20 21 - 123 + 122 48 49 - 123 + 122 140 141 - 123 + 122 @@ -17404,15 +17394,15 @@ typedefbase - 1757492 + 1757610 id - 1757492 + 1757610 type_id - 835030 + 835234 @@ -17426,7 +17416,7 @@ 1 2 - 1757492 + 1757610 @@ -17442,22 +17432,22 @@ 1 2 - 660534 + 660833 2 3 - 80564 + 80512 3 6 - 63746 + 63707 6 4525 - 30185 + 30180 @@ -17467,15 +17457,15 @@ decltypes - 814818 + 814720 id - 27575 + 27572 expr - 814818 + 814720 kind @@ -17501,17 +17491,17 @@ 1 2 - 9741 + 9740 2 3 - 3650 + 3649 4 5 - 3628 + 3627 6 @@ -17557,7 +17547,7 @@ 1 2 - 27575 + 27572 @@ -17573,7 +17563,7 @@ 1 2 - 27575 + 27572 @@ -17589,7 +17579,7 @@ 1 2 - 27575 + 27572 @@ -17605,7 +17595,7 @@ 1 2 - 814818 + 814720 @@ -17621,7 +17611,7 @@ 1 2 - 814818 + 814720 @@ -17637,7 +17627,7 @@ 1 2 - 814818 + 814720 @@ -17653,7 +17643,7 @@ 1 2 - 814818 + 814720 @@ -18231,15 +18221,15 @@ usertypes - 4199005 + 4203790 id - 4199005 + 4203790 name - 949198 + 950343 kind @@ -18257,7 +18247,7 @@ 1 2 - 4199005 + 4203790 @@ -18273,7 +18263,7 @@ 1 2 - 4199005 + 4203790 @@ -18289,22 +18279,22 @@ 1 2 - 680968 + 681205 2 3 - 161107 + 160794 3 8 - 71369 + 72561 8 - 33450 - 35752 + 33452 + 35782 @@ -18320,12 +18310,12 @@ 1 2 - 897382 + 898500 2 10 - 51815 + 51842 @@ -18359,13 +18349,13 @@ 10 - 1656 - 1657 + 1662 + 1663 10 - 1874 - 1875 + 1876 + 1877 10 @@ -18374,28 +18364,28 @@ 10 - 20075 - 20076 + 20074 + 20075 10 - 21602 - 21603 + 21723 + 21724 10 - 82275 - 82276 + 82276 + 82277 10 - 98872 - 98873 + 99064 + 99065 10 - 167625 - 167626 + 167547 + 167548 10 @@ -18460,13 +18450,13 @@ 10 - 12270 - 12271 + 12272 + 12273 10 - 61131 - 61132 + 61190 + 61191 10 @@ -18477,15 +18467,15 @@ usertypesize - 1420243 + 1421775 id - 1420243 + 1421775 size - 1467 + 1468 alignment @@ -18503,7 +18493,7 @@ 1 2 - 1420243 + 1421775 @@ -18519,7 +18509,7 @@ 1 2 - 1420243 + 1421775 @@ -18574,12 +18564,12 @@ 118 - 1735 + 1731 115 - 1839 - 106053 + 1840 + 106128 52 @@ -18645,18 +18635,18 @@ 10 - 2141 - 2142 + 2147 + 2148 10 - 11949 - 11950 + 11942 + 11943 10 - 121248 - 121249 + 121323 + 121324 10 @@ -18713,26 +18703,26 @@ usertype_final - 11320 + 11293 id - 11320 + 11293 usertype_uuid - 47918 + 47615 id - 47918 + 47615 uuid - 47375 + 47074 @@ -18746,7 +18736,7 @@ 1 2 - 47918 + 47615 @@ -18762,12 +18752,12 @@ 1 2 - 46833 + 46533 2 3 - 542 + 541 @@ -18777,11 +18767,11 @@ usertype_alias_kind - 1757492 + 1757610 id - 1757492 + 1757610 alias_kind @@ -18799,7 +18789,7 @@ 1 2 - 1757492 + 1757610 @@ -18813,13 +18803,13 @@ 12 - 36955 - 36956 + 36943 + 36944 10 - 130670 - 130671 + 130604 + 130605 10 @@ -18830,11 +18820,11 @@ nontype_template_parameters - 753499 + 754374 id - 753499 + 754374 @@ -18914,19 +18904,19 @@ mangled_name - 8194180 + 8184676 id - 8194180 + 8184676 mangled_name - 6357829 + 6352070 is_complete - 246 + 245 @@ -18940,7 +18930,7 @@ 1 2 - 8194180 + 8184676 @@ -18956,7 +18946,7 @@ 1 2 - 8194180 + 8184676 @@ -18972,12 +18962,12 @@ 1 2 - 6002593 + 5997431 2 1120 - 355236 + 354638 @@ -18993,7 +18983,7 @@ 1 2 - 6357829 + 6352070 @@ -19009,12 +18999,12 @@ 6 7 - 123 + 122 - 66588 - 66589 - 123 + 66669 + 66670 + 122 @@ -19030,12 +19020,12 @@ 6 7 - 123 + 122 - 51664 - 51665 - 123 + 51740 + 51741 + 122 @@ -19045,59 +19035,59 @@ is_pod_class - 607950 + 608655 id - 607950 + 608655 is_standard_layout_class - 1181968 + 1183332 id - 1181968 + 1183332 is_complete - 1402209 + 1403669 id - 1402209 + 1403669 is_class_template - 230421 + 230554 id - 230421 + 230554 class_instantiation - 1182545 + 1183835 to - 1179556 + 1180845 from - 71725 + 71774 @@ -19111,12 +19101,12 @@ 1 2 - 1177470 + 1178758 2 8 - 2086 + 2087 @@ -19132,47 +19122,47 @@ 1 2 - 20329 + 20340 2 3 - 12770 + 12777 3 4 - 7108 + 7101 4 5 - 4655 + 4657 5 7 - 6175 + 6189 7 10 - 5682 + 5685 10 17 - 5860 + 5864 17 52 - 5399 + 5402 52 4358 - 3743 + 3755 @@ -19182,11 +19172,11 @@ class_template_argument - 2998626 + 3001639 type_id - 1422098 + 1423558 index @@ -19194,7 +19184,7 @@ arg_type - 844162 + 844622 @@ -19208,27 +19198,27 @@ 1 2 - 599073 + 599423 2 3 - 433897 + 434747 3 4 - 263364 + 263557 4 8 - 107667 + 107724 8 113 - 18096 + 18106 @@ -19244,22 +19234,22 @@ 1 2 - 627926 + 628313 2 3 - 448051 + 448888 3 4 - 263427 + 263630 4 113 - 82692 + 82726 @@ -19299,12 +19289,12 @@ 643 - 7143 + 7142 94 11996 - 135625 + 135692 41 @@ -19349,7 +19339,7 @@ 94 - 11128 + 11129 46222 31 @@ -19367,27 +19357,27 @@ 1 2 - 523971 + 524281 2 3 - 174580 + 174662 3 5 - 77680 + 77711 5 44 - 63442 + 63413 44 - 13909 - 4487 + 13910 + 4552 @@ -19403,17 +19393,17 @@ 1 2 - 737082 + 737475 2 3 - 87809 + 87866 3 22 - 19270 + 19281 @@ -19423,19 +19413,19 @@ class_template_argument_value - 508368 + 508958 type_id - 208919 + 209162 index - 301 + 302 arg_value - 508234 + 508824 @@ -19449,17 +19439,17 @@ 1 2 - 159699 + 159884 2 3 - 42682 + 42732 3 8 - 6538 + 6545 @@ -19475,22 +19465,22 @@ 1 2 - 151953 + 152130 2 3 - 39832 + 39878 3 52 - 15892 + 15911 54 154 - 1240 + 1242 @@ -19618,7 +19608,7 @@ 1 2 - 508100 + 508690 2 @@ -19639,7 +19629,7 @@ 1 2 - 508234 + 508824 @@ -19649,15 +19639,15 @@ class_template_generated_from - 61398 + 61420 template - 61398 + 61420 from - 3732 + 3734 @@ -19671,7 +19661,7 @@ 1 2 - 61398 + 61420 @@ -19687,12 +19677,12 @@ 1 2 - 1509 + 1510 2 3 - 471 + 472 3 @@ -19737,15 +19727,15 @@ is_proxy_class_for - 50200 + 50227 id - 50200 + 50227 templ_param_id - 46897 + 46922 @@ -19759,7 +19749,7 @@ 1 2 - 50200 + 50227 @@ -19775,12 +19765,12 @@ 1 2 - 46143 + 46167 2 82 - 754 + 755 @@ -19790,19 +19780,19 @@ type_mentions - 5915053 + 5941339 id - 5915053 + 5941339 type_id - 278092 + 278065 location - 5858726 + 5885018 kind @@ -19820,7 +19810,7 @@ 1 2 - 5915053 + 5941339 @@ -19836,7 +19826,7 @@ 1 2 - 5915053 + 5941339 @@ -19852,7 +19842,7 @@ 1 2 - 5915053 + 5941339 @@ -19868,42 +19858,42 @@ 1 2 - 137493 + 137480 2 3 - 31213 + 31210 3 4 - 11657 + 11656 4 5 - 14980 + 14979 5 7 - 19937 + 19935 7 12 - 21789 + 21787 12 28 - 21027 + 21025 28 8941 - 19992 + 19990 @@ -19919,42 +19909,42 @@ 1 2 - 137493 + 137480 2 3 - 31213 + 31210 3 4 - 11657 + 11656 4 5 - 14980 + 14979 5 7 - 19937 + 19935 7 12 - 21789 + 21787 12 28 - 21027 + 21025 28 8941 - 19992 + 19990 @@ -19970,7 +19960,7 @@ 1 2 - 278092 + 278065 @@ -19986,12 +19976,12 @@ 1 2 - 5813022 + 5839318 2 4 - 45704 + 45699 @@ -20007,12 +19997,12 @@ 1 2 - 5813022 + 5839318 2 4 - 45704 + 45699 @@ -20028,7 +20018,7 @@ 1 2 - 5858726 + 5885018 @@ -20042,8 +20032,8 @@ 12 - 108584 - 108585 + 109077 + 109078 54 @@ -20074,8 +20064,8 @@ 12 - 107550 - 107551 + 108043 + 108044 54 @@ -20086,26 +20076,26 @@ is_function_template - 1312417 + 1311389 id - 1312417 + 1311389 function_instantiation - 958530 + 959643 to - 958530 + 959643 from - 179850 + 180058 @@ -20119,7 +20109,7 @@ 1 2 - 958530 + 959643 @@ -20135,27 +20125,27 @@ 1 2 - 108835 + 108961 2 3 - 42146 + 42195 3 9 - 14216 + 14232 9 104 - 13512 + 13527 119 1532 - 1139 + 1141 @@ -20165,11 +20155,11 @@ function_template_argument - 2445949 + 2464632 function_id - 1430587 + 1448091 index @@ -20177,7 +20167,7 @@ arg_type - 293279 + 293619 @@ -20191,22 +20181,22 @@ 1 2 - 770800 + 787539 2 3 - 406674 + 407146 3 4 - 169154 + 169350 4 15 - 83956 + 84054 @@ -20222,22 +20212,22 @@ 1 2 - 789644 + 806405 2 3 - 404797 + 405266 3 4 - 167008 + 167202 4 9 - 69137 + 69217 @@ -20296,8 +20286,8 @@ 33 - 42667 - 42668 + 43139 + 43140 33 @@ -20375,37 +20365,37 @@ 1 2 - 172004 + 172204 2 3 - 25884 + 25914 3 4 - 19513 + 19536 4 6 - 22430 + 22457 6 11 - 22933 + 22960 11 76 - 23000 + 22960 79 2452 - 7510 + 7586 @@ -20421,17 +20411,17 @@ 1 2 - 252708 + 253002 2 3 - 31651 + 31688 3 15 - 8918 + 8929 @@ -20441,11 +20431,11 @@ function_template_argument_value - 445568 + 453873 function_id - 193664 + 193888 index @@ -20453,7 +20443,7 @@ arg_value - 442919 + 451221 @@ -20467,17 +20457,17 @@ 1 2 - 149003 + 149176 2 3 - 42213 + 42262 3 8 - 2447 + 2450 @@ -20493,22 +20483,22 @@ 1 2 - 142197 + 142362 2 3 - 36110 + 36085 3 54 - 14618 + 14669 54 - 113 - 737 + 166 + 772 @@ -20603,13 +20593,13 @@ 33 - 51 - 52 + 55 + 56 33 - 63 - 64 + 67 + 68 33 @@ -20618,18 +20608,18 @@ 33 - 3294 - 3295 + 3296 + 3297 33 - 3702 - 3703 + 3813 + 3814 33 - 4180 - 4181 + 4291 + 4292 33 @@ -20646,12 +20636,12 @@ 1 2 - 440270 + 448569 2 3 - 2648 + 2651 @@ -20667,7 +20657,7 @@ 1 2 - 442919 + 451221 @@ -20677,15 +20667,15 @@ function_template_generated_from - 863408 + 864410 template - 863408 + 864410 from - 22129 + 22154 @@ -20699,7 +20689,7 @@ 1 2 - 863408 + 864410 @@ -20715,62 +20705,62 @@ 1 2 - 3587 + 3591 2 3 - 1173 + 1174 3 5 - 1676 + 1678 5 8 - 1777 + 1779 8 14 - 1676 + 1678 16 20 - 1575 + 1577 20 23 - 1676 + 1678 23 32 - 1844 + 1846 33 66 - 2045 + 2047 70 79 - 1374 + 1376 83 110 - 1844 + 1846 111 370 - 1877 + 1879 @@ -20780,26 +20770,26 @@ is_variable_template - 57832 + 57694 id - 57832 + 57694 variable_instantiation - 598007 + 596956 to - 598007 + 596956 from - 36175 + 36089 @@ -20813,7 +20803,7 @@ 1 2 - 598007 + 596956 @@ -20829,47 +20819,47 @@ 1 2 - 14396 + 14362 2 3 - 3937 + 3928 3 4 - 2583 + 2455 4 6 - 2707 + 2700 6 8 - 2707 + 2823 8 11 - 3199 + 3191 11 30 - 2830 + 2823 30 94 - 2830 + 2823 103 1155 - 984 + 982 @@ -20879,19 +20869,19 @@ variable_template_argument - 1129692 + 1128116 variable_id - 576474 + 575474 index - 1968 + 1964 arg_type - 464378 + 463276 @@ -20905,22 +20895,22 @@ 1 2 - 189615 + 189165 2 3 - 289652 + 288964 3 4 - 77519 + 77703 4 17 - 19687 + 19640 @@ -20936,22 +20926,22 @@ 1 2 - 207333 + 206841 2 3 - 276855 + 276198 3 4 - 75427 + 75616 4 17 - 16857 + 16817 @@ -20967,42 +20957,42 @@ 27 28 - 861 + 859 33 34 - 369 + 368 40 41 - 123 + 122 72 73 - 123 + 122 160 161 - 123 + 122 - 790 - 791 - 123 + 793 + 794 + 122 - 3144 - 3145 - 123 + 3147 + 3148 + 122 - 4685 - 4686 - 123 + 4688 + 4689 + 122 @@ -21018,42 +21008,42 @@ 1 2 - 861 + 859 2 3 - 369 + 368 5 6 - 123 + 122 35 36 - 123 + 122 63 64 - 123 + 122 362 363 - 123 + 122 1465 1466 - 123 + 122 2164 2165 - 123 + 122 @@ -21069,22 +21059,22 @@ 1 2 - 360650 + 359671 2 3 - 57832 + 57694 3 16 - 35437 + 35476 16 - 224 - 10458 + 227 + 10434 @@ -21100,12 +21090,12 @@ 1 2 - 430909 + 429887 2 7 - 33468 + 33389 @@ -21115,19 +21105,19 @@ variable_template_argument_value - 19810 + 19763 variable_id - 14765 + 14730 index - 492 + 491 arg_value - 19810 + 19763 @@ -21141,12 +21131,12 @@ 1 2 - 13289 + 13257 2 3 - 1476 + 1473 @@ -21162,17 +21152,17 @@ 1 2 - 10458 + 10434 2 3 - 3937 + 3928 4 5 - 369 + 368 @@ -21188,22 +21178,22 @@ 17 18 - 123 + 122 27 28 - 123 + 122 43 44 - 123 + 122 45 46 - 123 + 122 @@ -21219,22 +21209,22 @@ 22 23 - 123 + 122 29 30 - 123 + 122 52 53 - 123 + 122 58 59 - 123 + 122 @@ -21250,7 +21240,7 @@ 1 2 - 19810 + 19763 @@ -21266,7 +21256,7 @@ 1 2 - 19810 + 19763 @@ -21276,15 +21266,15 @@ variable_template_generated_from - 492 + 491 template - 492 + 491 from - 246 + 245 @@ -21298,7 +21288,7 @@ 1 2 - 492 + 491 @@ -21314,7 +21304,7 @@ 2 3 - 246 + 245 @@ -21324,26 +21314,26 @@ is_alias_template - 107393 + 107518 id - 107393 + 107518 alias_instantiation - 459650 + 460184 to - 459650 + 460184 from - 92205 + 92312 @@ -21357,7 +21347,7 @@ 1 2 - 459650 + 460184 @@ -21373,42 +21363,42 @@ 1 2 - 16529 + 16549 2 3 - 16798 + 16817 3 4 - 20016 + 20040 4 5 - 12472 + 12487 5 7 - 6705 + 6713 7 8 - 4794 + 4800 8 10 - 7812 + 7821 10 143 - 6940 + 6948 163 @@ -21423,19 +21413,19 @@ alias_template_argument - 993065 + 994218 type_id - 566977 + 567635 index - 301 + 302 arg_type - 127712 + 127860 @@ -21449,22 +21439,22 @@ 1 2 - 276179 + 276499 2 3 - 182331 + 182542 3 4 - 86907 + 87008 4 10 - 21559 + 21584 @@ -21480,22 +21470,22 @@ 1 2 - 277419 + 277741 2 3 - 181124 + 181334 3 4 - 88349 + 88451 4 10 - 20083 + 20107 @@ -21623,32 +21613,32 @@ 1 2 - 78156 + 78247 2 3 - 20285 + 20308 3 4 - 5431 + 5438 4 6 - 10461 + 10473 6 76 - 10829 + 10842 84 4474 - 2548 + 2551 @@ -21664,17 +21654,17 @@ 1 2 - 108801 + 108928 2 3 - 17301 + 17321 3 9 - 1609 + 1611 @@ -21684,11 +21674,11 @@ alias_template_argument_value - 173177 + 173378 type_id - 160604 + 160790 index @@ -21696,7 +21686,7 @@ arg_value - 173177 + 173378 @@ -21710,12 +21700,12 @@ 1 2 - 159363 + 159548 2 3 - 1240 + 1242 @@ -21731,12 +21721,12 @@ 1 2 - 158693 + 158877 2 42 - 1911 + 1913 @@ -21814,7 +21804,7 @@ 1 2 - 173177 + 173378 @@ -21830,7 +21820,7 @@ 1 2 - 173177 + 173378 @@ -21840,15 +21830,15 @@ alias_template_generated_from - 99816 + 99932 template - 99816 + 99932 from - 1911 + 1913 @@ -21862,7 +21852,7 @@ 1 2 - 99816 + 99932 @@ -21948,15 +21938,15 @@ template_template_instantiation - 6029 + 6014 to - 4675 + 4664 from - 1107 + 1104 @@ -21970,12 +21960,12 @@ 1 2 - 3322 + 3314 2 3 - 1353 + 1350 @@ -21991,22 +21981,22 @@ 1 2 - 738 + 736 2 3 - 123 + 122 14 15 - 123 + 122 27 28 - 123 + 122 @@ -22016,11 +22006,11 @@ template_template_argument - 9603 + 9609 type_id - 6070 + 6073 index @@ -22028,7 +22018,7 @@ arg_type - 9016 + 9021 @@ -22042,7 +22032,7 @@ 1 2 - 4980 + 4982 2 @@ -22073,7 +22063,7 @@ 1 2 - 5001 + 5003 2 @@ -22226,7 +22216,7 @@ 1 2 - 8985 + 8990 3 @@ -22247,7 +22237,7 @@ 1 2 - 8995 + 9000 2 @@ -22262,19 +22252,19 @@ template_template_argument_value - 1107 + 1104 type_id - 123 + 122 index - 123 + 122 arg_value - 1107 + 1104 @@ -22288,7 +22278,7 @@ 1 2 - 123 + 122 @@ -22304,7 +22294,7 @@ 9 10 - 123 + 122 @@ -22320,7 +22310,7 @@ 1 2 - 123 + 122 @@ -22336,7 +22326,7 @@ 9 10 - 123 + 122 @@ -22352,7 +22342,7 @@ 1 2 - 1107 + 1104 @@ -22368,7 +22358,7 @@ 1 2 - 1107 + 1104 @@ -22494,11 +22484,11 @@ concept_instantiation - 90089 + 90068 to - 90089 + 90068 from @@ -22516,7 +22506,7 @@ 1 2 - 90089 + 90068 @@ -22623,11 +22613,11 @@ concept_template_argument - 112671 + 112649 concept_id - 76126 + 76104 index @@ -22649,7 +22639,7 @@ 1 2 - 46317 + 46295 2 @@ -22675,7 +22665,7 @@ 1 2 - 49909 + 49888 2 @@ -22724,8 +22714,8 @@ 21 - 3560 - 3561 + 3559 + 3560 21 @@ -22783,12 +22773,12 @@ 1 2 - 10520 + 10542 2 3 - 2929 + 2908 3 @@ -22985,15 +22975,15 @@ routinetypes - 594974 + 595664 id - 594974 + 595664 return_type - 279398 + 279722 @@ -23007,7 +22997,7 @@ 1 2 - 594974 + 595664 @@ -23023,17 +23013,17 @@ 1 2 - 230412 + 230679 2 3 - 34669 + 34709 3 4677 - 14316 + 14333 @@ -23043,11 +23033,11 @@ routinetypeargs - 1178881 + 1178768 routine - 416130 + 416090 index @@ -23055,7 +23045,7 @@ type_id - 112108 + 112097 @@ -23069,32 +23059,32 @@ 1 2 - 82964 + 82956 2 3 - 126108 + 126096 3 4 - 107913 + 107903 4 5 - 49299 + 49294 5 7 - 33174 + 33171 7 19 - 16669 + 16667 @@ -23110,27 +23100,27 @@ 1 2 - 88956 + 88948 2 3 - 138746 + 138733 3 4 - 114668 + 114657 4 5 - 40746 + 40742 5 10 - 32902 + 32899 10 @@ -23328,47 +23318,47 @@ 1 2 - 33283 + 33280 2 3 - 15579 + 15578 3 4 - 13291 + 13290 4 5 - 9805 + 9804 5 6 - 6373 + 6372 6 8 - 9478 + 9477 8 13 - 9533 + 9532 13 26 - 8661 + 8660 26 926 - 6101 + 6100 @@ -23384,22 +23374,22 @@ 1 2 - 79423 + 79416 2 3 - 17540 + 17539 3 5 - 9478 + 9477 5 17 - 5665 + 5664 @@ -23409,19 +23399,19 @@ ptrtomembers - 9645 + 9651 id - 9645 + 9651 type_id - 7915 + 7920 class_id - 4833 + 4836 @@ -23435,7 +23425,7 @@ 1 2 - 9645 + 9651 @@ -23451,7 +23441,7 @@ 1 2 - 9645 + 9651 @@ -23467,7 +23457,7 @@ 1 2 - 7706 + 7710 2 @@ -23488,7 +23478,7 @@ 1 2 - 7706 + 7710 2 @@ -23509,12 +23499,12 @@ 1 2 - 3879 + 3881 2 3 - 513 + 514 8 @@ -23540,12 +23530,12 @@ 1 2 - 3879 + 3881 2 3 - 513 + 514 8 @@ -23565,15 +23555,15 @@ specifiers - 7628 + 7610 id - 7628 + 7610 str - 7628 + 7610 @@ -23587,7 +23577,7 @@ 1 2 - 7628 + 7610 @@ -23603,7 +23593,7 @@ 1 2 - 7628 + 7610 @@ -23613,11 +23603,11 @@ typespecifiers - 849782 + 853570 type_id - 844676 + 848462 spec_id @@ -23635,12 +23625,12 @@ 1 2 - 839570 + 843353 2 3 - 5106 + 5108 @@ -23669,8 +23659,8 @@ 10 - 533 - 534 + 530 + 531 10 @@ -23684,18 +23674,18 @@ 10 - 4195 - 4196 + 4192 + 4193 10 - 18432 - 18433 + 18435 + 18436 10 - 54893 - 54894 + 55214 + 55215 10 @@ -23706,15 +23696,15 @@ funspecifiers - 9579810 + 9569842 func_id - 3954724 + 3954300 spec_id - 2337 + 2332 @@ -23728,27 +23718,27 @@ 1 2 - 1507569 + 1510375 2 3 - 499939 + 500471 3 4 - 1021657 + 1019724 4 5 - 683402 + 682148 5 8 - 242156 + 241581 @@ -23764,97 +23754,97 @@ 17 18 - 123 + 122 18 19 - 123 + 122 53 54 - 123 + 122 114 115 - 123 + 122 216 217 - 123 + 122 272 273 - 123 + 122 356 357 - 123 + 122 653 654 - 123 + 122 769 770 - 123 + 122 823 824 - 123 + 122 1096 1097 - 123 + 122 1261 1262 - 123 + 122 1670 1671 - 123 + 122 3297 3298 - 123 + 122 - 3348 - 3349 - 123 + 3355 + 3356 + 122 - 6163 - 6164 - 123 + 6170 + 6171 + 122 15130 15131 - 123 + 122 - 19822 - 19823 - 123 + 19895 + 19896 + 122 - 22777 - 22778 - 123 + 22794 + 22795 + 122 @@ -23864,15 +23854,15 @@ varspecifiers - 3216566 + 3209301 var_id - 2461674 + 2456201 spec_id - 1107 + 1104 @@ -23886,17 +23876,17 @@ 1 2 - 1809034 + 1805109 2 3 - 550880 + 549573 3 5 - 101759 + 101518 @@ -23912,47 +23902,47 @@ 97 98 - 123 + 122 240 241 - 123 + 122 1091 1092 - 123 + 122 2238 2239 - 123 + 122 - 2746 - 2747 - 123 + 2749 + 2750 + 122 2812 2813 - 123 + 122 3506 3507 - 123 + 122 4918 4919 - 123 + 122 8493 8494 - 123 + 122 @@ -23962,15 +23952,15 @@ explicit_specifier_exprs - 40728 + 40631 func_id - 40728 + 40631 constant - 40728 + 40631 @@ -23984,7 +23974,7 @@ 1 2 - 40728 + 40631 @@ -24000,7 +23990,7 @@ 1 2 - 40728 + 40631 @@ -24010,27 +24000,27 @@ attributes - 644888 + 643971 id - 644888 + 643971 kind - 369 + 368 name - 2091 + 2086 name_space - 246 + 245 location - 638859 + 637956 @@ -24044,7 +24034,7 @@ 1 2 - 644888 + 643971 @@ -24060,7 +24050,7 @@ 1 2 - 644888 + 643971 @@ -24076,7 +24066,7 @@ 1 2 - 644888 + 643971 @@ -24092,7 +24082,7 @@ 1 2 - 644888 + 643971 @@ -24108,17 +24098,17 @@ 7 8 - 123 + 122 2406 2407 - 123 + 122 - 2828 - 2829 - 123 + 2833 + 2834 + 122 @@ -24134,17 +24124,17 @@ 1 2 - 123 + 122 6 7 - 123 + 122 12 13 - 123 + 122 @@ -24160,12 +24150,12 @@ 1 2 - 246 + 245 2 3 - 123 + 122 @@ -24181,17 +24171,17 @@ 4 5 - 123 + 122 2360 2361 - 123 + 122 - 2828 - 2829 - 123 + 2833 + 2834 + 122 @@ -24207,72 +24197,72 @@ 1 2 - 246 + 245 3 4 - 123 + 122 6 7 - 123 + 122 7 8 - 246 + 245 10 11 - 246 + 245 14 15 - 123 + 122 18 19 - 123 + 122 24 25 - 123 + 122 59 60 - 123 + 122 62 63 - 123 + 122 72 73 - 123 + 122 341 342 - 123 + 122 1977 1978 - 123 + 122 - 2629 - 2630 - 123 + 2634 + 2635 + 122 @@ -24288,12 +24278,12 @@ 1 2 - 1845 + 1841 2 3 - 246 + 245 @@ -24309,7 +24299,7 @@ 1 2 - 2091 + 2086 @@ -24325,77 +24315,77 @@ 1 2 - 246 + 245 3 4 - 123 + 122 4 5 - 123 + 122 6 7 - 123 + 122 7 8 - 123 + 122 10 11 - 246 + 245 14 15 - 123 + 122 18 19 - 123 + 122 24 25 - 123 + 122 59 60 - 123 + 122 62 63 - 123 + 122 72 73 - 123 + 122 336 337 - 123 + 122 1977 1978 - 123 + 122 - 2629 - 2630 - 123 + 2634 + 2635 + 122 @@ -24411,12 +24401,12 @@ 11 12 - 123 + 122 - 5230 - 5231 - 123 + 5235 + 5236 + 122 @@ -24432,12 +24422,12 @@ 1 2 - 123 + 122 3 4 - 123 + 122 @@ -24453,12 +24443,12 @@ 2 3 - 123 + 122 15 16 - 123 + 122 @@ -24474,12 +24464,12 @@ 11 12 - 123 + 122 - 5181 - 5182 - 123 + 5186 + 5187 + 122 @@ -24495,12 +24485,12 @@ 1 2 - 633075 + 632187 2 5 - 5783 + 5769 @@ -24516,7 +24506,7 @@ 1 2 - 638859 + 637956 @@ -24532,12 +24522,12 @@ 1 2 - 633814 + 632923 2 3 - 5044 + 5032 @@ -24553,7 +24543,7 @@ 1 2 - 638859 + 637956 @@ -24563,11 +24553,11 @@ attribute_args - 82133 + 82169 id - 82133 + 82169 kind @@ -24575,7 +24565,7 @@ attribute - 70889 + 70920 index @@ -24583,7 +24573,7 @@ location - 56887 + 56912 @@ -24597,7 +24587,7 @@ 1 2 - 82133 + 82169 @@ -24613,7 +24603,7 @@ 1 2 - 82133 + 82169 @@ -24629,7 +24619,7 @@ 1 2 - 82133 + 82169 @@ -24645,7 +24635,7 @@ 1 2 - 82133 + 82169 @@ -24765,12 +24755,12 @@ 1 2 - 65448 + 65477 2 7 - 5319 + 5322 7 @@ -24791,12 +24781,12 @@ 1 2 - 69380 + 69411 2 3 - 1508 + 1509 @@ -24812,12 +24802,12 @@ 1 2 - 67860 + 67890 2 8 - 3028 + 3029 @@ -24833,12 +24823,12 @@ 1 2 - 68390 + 68420 2 6 - 2498 + 2499 @@ -25018,17 +25008,17 @@ 1 2 - 41291 + 41309 2 3 - 11796 + 11801 3 25 - 3799 + 3801 @@ -25044,12 +25034,12 @@ 1 2 - 47405 + 47426 2 3 - 9482 + 9486 @@ -25065,12 +25055,12 @@ 1 2 - 42638 + 42656 2 3 - 12234 + 12239 3 @@ -25091,7 +25081,7 @@ 1 2 - 56639 + 56664 2 @@ -25106,15 +25096,15 @@ attribute_arg_value - 16429 + 16448 arg - 16429 + 16448 value - 502 + 503 @@ -25128,7 +25118,7 @@ 1 2 - 16429 + 16448 @@ -25199,15 +25189,15 @@ attribute_arg_type - 459 + 460 arg - 459 + 460 type_id - 83 + 84 @@ -25221,7 +25211,7 @@ 1 2 - 459 + 460 @@ -25237,22 +25227,22 @@ 1 2 - 71 + 72 2 3 - 3 + 4 35 36 - 3 + 4 60 61 - 3 + 4 @@ -25262,15 +25252,15 @@ attribute_arg_constant - 71243 + 71688 arg - 71243 + 71688 constant - 71243 + 71688 @@ -25284,7 +25274,7 @@ 1 2 - 71243 + 71688 @@ -25300,7 +25290,7 @@ 1 2 - 71243 + 71688 @@ -25411,15 +25401,15 @@ typeattributes - 94992 + 94766 type_id - 93269 + 93048 spec_id - 31992 + 31916 @@ -25433,12 +25423,12 @@ 1 2 - 91546 + 91329 2 3 - 1722 + 1718 @@ -25454,17 +25444,17 @@ 1 2 - 27562 + 27497 2 9 - 2460 + 2455 11 58 - 1968 + 1964 @@ -25474,15 +25464,15 @@ funcattributes - 830073 + 834364 func_id - 786146 + 788699 spec_id - 608343 + 607513 @@ -25496,12 +25486,12 @@ 1 2 - 746648 + 747454 2 7 - 39498 + 41245 @@ -25517,12 +25507,17 @@ 1 2 - 563923 + 561234 2 + 45 + 45787 + + + 55 213 - 44419 + 491 @@ -25595,7 +25590,7 @@ namespaceattributes - 5901 + 5907 namespace_id @@ -25603,7 +25598,7 @@ spec_id - 5901 + 5907 @@ -25643,7 +25638,7 @@ 1 2 - 5901 + 5907 @@ -25721,15 +25716,15 @@ unspecifiedtype - 7381947 + 7371180 type_id - 7381947 + 7371180 unspecified_type_id - 4143724 + 4135732 @@ -25743,7 +25738,7 @@ 1 2 - 7381947 + 7371180 @@ -25759,22 +25754,22 @@ 1 2 - 2676022 + 2670039 2 3 - 1106067 + 1104793 3 8 - 312292 + 311674 8 - 892 - 49341 + 895 + 49224 @@ -25784,19 +25779,19 @@ member - 4133757 + 4123947 parent - 535991 + 534719 index - 29285 + 29215 child - 4129205 + 4119405 @@ -25810,57 +25805,57 @@ 1 2 - 127722 + 127419 2 3 - 81949 + 81754 3 4 - 31992 + 31916 4 5 - 44296 + 44191 5 6 - 41712 + 41613 6 7 - 33468 + 33389 7 9 - 41712 + 41613 9 13 - 40605 + 40509 13 18 - 40728 + 40631 18 42 - 40236 + 40140 42 239 - 11566 + 11538 @@ -25876,57 +25871,57 @@ 1 2 - 127476 + 127173 2 3 - 82072 + 81877 3 4 - 31746 + 31670 4 5 - 44542 + 44437 5 6 - 41712 + 41613 6 7 - 32361 + 32284 7 9 - 42082 + 41982 9 13 - 40974 + 40877 13 18 - 40851 + 40754 18 42 - 40236 + 40140 42 265 - 11935 + 11907 @@ -25942,57 +25937,57 @@ 1 2 - 6398 + 6383 2 3 - 2583 + 2577 3 8 - 1845 + 1841 9 10 - 2830 + 2823 10 19 - 2214 + 2209 19 26 - 2214 + 2209 26 36 - 2460 + 2455 36 50 - 2214 + 2209 54 141 - 2214 + 2209 150 468 - 2214 + 2209 480 4311 - 2091 + 2086 @@ -26008,57 +26003,57 @@ 1 2 - 5414 + 5401 2 3 - 3568 + 3559 3 9 - 1845 + 1841 9 10 - 2830 + 2823 10 20 - 2214 + 2209 20 27 - 2214 + 2209 27 37 - 2583 + 2577 37 56 - 2337 + 2332 58 155 - 2214 + 2209 164 528 - 2214 + 2209 548 4332 - 1845 + 1841 @@ -26074,7 +26069,7 @@ 1 2 - 4129205 + 4119405 @@ -26090,12 +26085,12 @@ 1 2 - 4124652 + 4114864 2 3 - 4552 + 4541 @@ -26105,15 +26100,15 @@ enclosingfunction - 114597 + 114616 child - 114597 + 114616 parent - 68863 + 68858 @@ -26127,7 +26122,7 @@ 1 2 - 114597 + 114616 @@ -26143,22 +26138,22 @@ 1 2 - 37346 + 37324 2 3 - 24397 + 24410 3 5 - 6039 + 6042 5 45 - 1079 + 1080 @@ -26168,15 +26163,15 @@ derivations - 491402 + 492610 derivation - 491402 + 492610 sub - 470011 + 471194 index @@ -26184,11 +26179,11 @@ super - 238962 + 239877 location - 34836 + 34877 @@ -26202,7 +26197,7 @@ 1 2 - 491402 + 492610 @@ -26218,7 +26213,7 @@ 1 2 - 491402 + 492610 @@ -26234,7 +26229,7 @@ 1 2 - 491402 + 492610 @@ -26250,7 +26245,7 @@ 1 2 - 491402 + 492610 @@ -26266,12 +26261,12 @@ 1 2 - 453749 + 454914 2 9 - 16261 + 16280 @@ -26287,12 +26282,12 @@ 1 2 - 453749 + 454914 2 8 - 16261 + 16280 @@ -26308,12 +26303,12 @@ 1 2 - 453749 + 454914 2 9 - 16261 + 16280 @@ -26329,12 +26324,12 @@ 1 2 - 453749 + 454914 2 8 - 16261 + 16280 @@ -26368,8 +26363,8 @@ 33 - 14018 - 14019 + 14037 + 14038 33 @@ -26399,8 +26394,8 @@ 33 - 14018 - 14019 + 14037 + 14038 33 @@ -26440,8 +26435,8 @@ 33 - 6723 - 6724 + 6742 + 6743 33 @@ -26489,12 +26484,12 @@ 1 2 - 229205 + 230108 2 1758 - 9756 + 9768 @@ -26510,12 +26505,12 @@ 1 2 - 229205 + 230108 2 1758 - 9756 + 9768 @@ -26531,12 +26526,12 @@ 1 2 - 238526 + 239440 2 4 - 435 + 436 @@ -26552,12 +26547,12 @@ 1 2 - 233597 + 234506 2 81 - 5364 + 5370 @@ -26573,27 +26568,27 @@ 1 2 - 25850 + 25847 2 5 - 3185 + 3188 5 - 22 - 2782 + 21 + 2618 - 22 - 371 - 2615 + 21 + 186 + 2618 - 379 + 205 985 - 402 + 604 @@ -26609,27 +26604,27 @@ 1 2 - 25850 + 25847 2 5 - 3185 + 3188 5 - 22 - 2782 + 21 + 2618 - 22 - 371 - 2615 + 21 + 186 + 2618 - 379 + 205 985 - 402 + 604 @@ -26645,7 +26640,7 @@ 1 2 - 34836 + 34877 @@ -26661,22 +26656,22 @@ 1 2 - 28164 + 28163 2 4 - 2548 + 2551 4 24 - 2615 + 2651 24 933 - 1508 + 1510 @@ -26686,11 +26681,11 @@ derspecifiers - 493146 + 494356 der_id - 490966 + 492174 spec_id @@ -26708,12 +26703,12 @@ 1 2 - 488787 + 489992 2 3 - 2179 + 2181 @@ -26742,8 +26737,8 @@ 33 - 13447 - 13448 + 13466 + 13467 33 @@ -26754,15 +26749,15 @@ direct_base_offsets - 464914 + 466092 der_id - 464914 + 466092 offset - 502 + 503 @@ -26776,7 +26771,7 @@ 1 2 - 464914 + 466092 @@ -26825,8 +26820,8 @@ 33 - 13716 - 13717 + 13735 + 13736 33 @@ -26837,11 +26832,11 @@ virtual_base_offsets - 5733 + 5740 sub - 5733 + 5740 super @@ -26863,7 +26858,7 @@ 1 2 - 5733 + 5740 @@ -26879,7 +26874,7 @@ 1 2 - 5733 + 5740 @@ -26937,7 +26932,7 @@ 2 3 - 301 + 302 153 @@ -26963,7 +26958,7 @@ 2 3 - 301 + 302 @@ -26973,23 +26968,23 @@ frienddecls - 759702 + 761457 id - 759702 + 761457 type_id - 53847 + 53910 decl_id - 99782 + 99898 location - 6001 + 6008 @@ -27003,7 +26998,7 @@ 1 2 - 759702 + 761457 @@ -27019,7 +27014,7 @@ 1 2 - 759702 + 761457 @@ -27035,7 +27030,7 @@ 1 2 - 759702 + 761457 @@ -27051,42 +27046,42 @@ 1 2 - 5532 + 5538 2 3 - 24778 + 24806 3 8 - 4794 + 4733 8 17 - 4627 + 4699 17 27 - 4425 + 4430 27 45 - 4258 + 4263 45 81 - 4694 + 4699 102 121 - 737 + 738 @@ -27102,42 +27097,42 @@ 1 2 - 5532 + 5538 2 3 - 24778 + 24806 3 8 - 4794 + 4733 8 17 - 4627 + 4699 17 27 - 4425 + 4430 27 45 - 4258 + 4263 45 81 - 4694 + 4699 102 121 - 737 + 738 @@ -27153,12 +27148,12 @@ 1 2 - 52506 + 52567 2 13 - 1341 + 1342 @@ -27174,32 +27169,32 @@ 1 2 - 66890 + 66968 2 3 - 8046 + 8056 3 9 - 9119 + 9130 9 24 - 7544 + 7552 24 - 134 - 7544 + 136 + 7586 - 135 + 136 191 - 637 + 604 @@ -27215,32 +27210,32 @@ 1 2 - 66890 + 66968 2 3 - 8046 + 8056 3 9 - 9119 + 9130 9 24 - 7544 + 7552 24 - 134 - 7544 + 136 + 7586 - 135 + 136 191 - 637 + 604 @@ -27256,12 +27251,12 @@ 1 2 - 98575 + 98690 2 6 - 1207 + 1208 @@ -27277,12 +27272,12 @@ 1 2 - 5632 + 5639 2 - 22469 - 368 + 22495 + 369 @@ -27298,7 +27293,7 @@ 1 2 - 5867 + 5874 2 @@ -27319,7 +27314,7 @@ 1 2 - 5666 + 5672 2 @@ -27334,19 +27329,19 @@ comments - 11082335 + 11056034 id - 11082335 + 11056034 contents - 4246591 + 4236514 location - 11082335 + 11056034 @@ -27360,7 +27355,7 @@ 1 2 - 11082335 + 11056034 @@ -27376,7 +27371,7 @@ 1 2 - 11082335 + 11056034 @@ -27392,17 +27387,17 @@ 1 2 - 3876344 + 3867144 2 6 - 319183 + 318425 6 34447 - 51064 + 50943 @@ -27418,17 +27413,17 @@ 1 2 - 3876344 + 3867144 2 6 - 319183 + 318425 6 34447 - 51064 + 50943 @@ -27444,7 +27439,7 @@ 1 2 - 11082335 + 11056034 @@ -27460,7 +27455,7 @@ 1 2 - 11082335 + 11056034 @@ -27470,15 +27465,15 @@ commentbinding - 3861332 + 3852168 id - 3305037 + 3297194 element - 3698049 + 3689273 @@ -27492,12 +27487,12 @@ 1 2 - 3244252 + 3236553 2 1706 - 60785 + 60640 @@ -27513,12 +27508,12 @@ 1 2 - 3534766 + 3526377 2 3 - 163283 + 162895 @@ -27528,15 +27523,15 @@ exprconv - 9637003 + 9635850 converted - 9636897 + 9635744 conversion - 9637003 + 9635850 @@ -27550,7 +27545,7 @@ 1 2 - 9636792 + 9635639 2 @@ -27571,7 +27566,7 @@ 1 2 - 9637003 + 9635850 @@ -27581,22 +27576,22 @@ compgenerated - 9885625 + 9880588 id - 9885625 + 9880588 synthetic_destructor_call - 1661392 + 1661391 element - 1237287 + 1237286 i @@ -27604,7 +27599,7 @@ destructor_call - 1661392 + 1661391 @@ -27618,12 +27613,12 @@ 1 2 - 823575 + 823574 2 3 - 406955 + 406954 3 @@ -27644,12 +27639,12 @@ 1 2 - 823575 + 823574 2 3 - 406955 + 406954 3 @@ -27802,7 +27797,7 @@ 1 2 - 1661392 + 1661391 @@ -27818,7 +27813,7 @@ 1 2 - 1661392 + 1661391 @@ -27828,15 +27823,15 @@ namespaces - 8586 + 8591 id - 8586 + 8591 name - 4539 + 4542 @@ -27850,7 +27845,7 @@ 1 2 - 8586 + 8591 @@ -27866,7 +27861,7 @@ 1 2 - 3711 + 3713 2 @@ -27886,26 +27881,26 @@ namespace_inline - 492 + 491 id - 492 + 491 namespacembrs - 2483823 + 2487871 parentid - 3937 + 3928 memberid - 2483823 + 2487871 @@ -27919,67 +27914,67 @@ 1 2 - 492 + 491 2 3 - 246 + 245 3 4 - 492 + 491 4 5 - 615 + 613 7 10 - 246 + 245 10 12 - 246 + 245 12 18 - 246 + 245 19 21 - 246 + 245 23 24 - 246 + 245 25 29 - 246 + 245 70 83 - 246 + 245 169 182 - 246 + 245 - 19440 - 19441 - 123 + 19521 + 19522 + 122 @@ -27995,7 +27990,7 @@ 1 2 - 2483823 + 2487871 @@ -28005,19 +28000,19 @@ exprparents - 19462195 + 19459867 expr_id - 19462195 + 19459867 child_index - 20043 + 20040 parent_id - 12945304 + 12943755 @@ -28031,7 +28026,7 @@ 1 2 - 19462195 + 19459867 @@ -28047,7 +28042,7 @@ 1 2 - 19462195 + 19459867 @@ -28068,7 +28063,7 @@ 2 3 - 1520 + 1519 3 @@ -28078,7 +28073,7 @@ 4 5 - 8980 + 8978 5 @@ -28093,7 +28088,7 @@ 11 53 - 1520 + 1519 56 @@ -28119,7 +28114,7 @@ 2 3 - 1520 + 1519 3 @@ -28129,7 +28124,7 @@ 4 5 - 8980 + 8978 5 @@ -28144,7 +28139,7 @@ 11 53 - 1520 + 1519 56 @@ -28165,17 +28160,17 @@ 1 2 - 7397807 + 7396922 2 3 - 5084757 + 5084149 3 712 - 462739 + 462684 @@ -28191,17 +28186,17 @@ 1 2 - 7397807 + 7396922 2 3 - 5084757 + 5084149 3 712 - 462739 + 462684 @@ -28211,22 +28206,22 @@ expr_isload - 6919045 + 6902994 expr_id - 6919045 + 6902994 conversionkinds - 6052846 + 6052094 expr_id - 6052846 + 6052094 kind @@ -28244,7 +28239,7 @@ 1 2 - 6052846 + 6052094 @@ -28283,13 +28278,13 @@ 1 - 93465 - 93466 + 92949 + 92950 1 - 5833724 - 5833725 + 5833488 + 5833489 1 @@ -28300,11 +28295,11 @@ iscall - 5772727 + 5772743 caller - 5772727 + 5772743 kind @@ -28322,7 +28317,7 @@ 1 2 - 5772727 + 5772743 @@ -28346,8 +28341,8 @@ 21 - 268244 - 268245 + 268245 + 268246 21 @@ -28358,15 +28353,15 @@ numtemplatearguments - 730405 + 729040 expr_id - 730405 + 729040 num - 984 + 982 @@ -28380,7 +28375,7 @@ 1 2 - 730405 + 729040 @@ -28396,42 +28391,42 @@ 1 2 - 123 + 122 6 7 - 123 + 122 27 28 - 123 + 122 39 40 - 123 + 122 68 69 - 123 + 122 404 405 - 123 + 122 - 1998 - 1999 - 123 + 2001 + 2002 + 122 3393 3394 - 123 + 122 @@ -28441,15 +28436,15 @@ specialnamequalifyingelements - 123 + 122 id - 123 + 122 name - 123 + 122 @@ -28463,7 +28458,7 @@ 1 2 - 123 + 122 @@ -28479,7 +28474,7 @@ 1 2 - 123 + 122 @@ -28489,15 +28484,15 @@ namequalifiers - 3051489 + 3050545 id - 3051489 + 3050545 qualifiableelement - 3051489 + 3050545 qualifyingelement @@ -28505,7 +28500,7 @@ location - 558951 + 558950 @@ -28519,7 +28514,7 @@ 1 2 - 3051489 + 3050545 @@ -28535,7 +28530,7 @@ 1 2 - 3051489 + 3050545 @@ -28551,7 +28546,7 @@ 1 2 - 3051489 + 3050545 @@ -28567,7 +28562,7 @@ 1 2 - 3051489 + 3050545 @@ -28583,7 +28578,7 @@ 1 2 - 3051489 + 3050545 @@ -28599,7 +28594,7 @@ 1 2 - 3051489 + 3050545 @@ -28615,27 +28610,27 @@ 1 2 - 37827 + 37913 2 3 - 8275 + 8382 3 5 - 4212 + 4127 5 - 209 + 476 4105 - 234 + 1600 41956 - 235 + 128 @@ -28651,27 +28646,27 @@ 1 2 - 37827 + 37913 2 3 - 8275 + 8382 3 5 - 4212 + 4127 5 - 209 + 476 4105 - 234 + 1600 41956 - 235 + 128 @@ -28718,22 +28713,22 @@ 1 2 - 83268 + 83311 2 6 - 42275 + 42339 6 7 - 396712 + 396669 7 192 - 36694 + 36630 @@ -28749,22 +28744,22 @@ 1 2 - 83268 + 83311 2 6 - 42275 + 42339 6 7 - 396712 + 396669 7 192 - 36694 + 36630 @@ -28790,7 +28785,7 @@ 4 5 - 412921 + 412920 5 @@ -28805,15 +28800,15 @@ varbind - 8258005 + 8257017 expr - 8258005 + 8257017 var - 1050805 + 1050679 @@ -28827,7 +28822,7 @@ 1 2 - 8258005 + 8257017 @@ -28843,52 +28838,52 @@ 1 2 - 171606 + 171585 2 3 - 188777 + 188755 3 4 - 145707 + 145690 4 5 - 116684 + 116670 5 6 - 83185 + 83175 6 7 - 65844 + 65836 7 9 - 80848 + 80838 9 13 - 81608 + 81598 13 27 - 79159 + 79150 27 5137 - 37383 + 37379 @@ -28898,15 +28893,15 @@ funbind - 5787737 + 5787669 expr - 5785278 + 5785316 fun - 274929 + 274909 @@ -28920,12 +28915,12 @@ 1 2 - 5782819 + 5782964 2 3 - 2459 + 2352 @@ -28941,7 +28936,7 @@ 1 2 - 180670 + 180650 2 @@ -28951,17 +28946,17 @@ 3 4 - 16743 + 16764 4 8 - 23308 + 23286 8 37798 - 15994 + 15995 @@ -29097,11 +29092,11 @@ expr_deallocator - 52976 + 53037 expr - 52976 + 53037 func @@ -29123,7 +29118,7 @@ 1 2 - 52976 + 53037 @@ -29139,7 +29134,7 @@ 1 2 - 52976 + 53037 @@ -29244,15 +29239,15 @@ expr_cond_guard - 898245 + 898137 cond - 898245 + 898137 guard - 898245 + 898137 @@ -29266,7 +29261,7 @@ 1 2 - 898245 + 898137 @@ -29282,7 +29277,7 @@ 1 2 - 898245 + 898137 @@ -29292,15 +29287,15 @@ expr_cond_true - 898241 + 898134 cond - 898241 + 898134 true - 898241 + 898134 @@ -29314,7 +29309,7 @@ 1 2 - 898241 + 898134 @@ -29330,7 +29325,7 @@ 1 2 - 898241 + 898134 @@ -29340,15 +29335,15 @@ expr_cond_false - 898245 + 898137 cond - 898245 + 898137 false - 898245 + 898137 @@ -29362,7 +29357,7 @@ 1 2 - 898245 + 898137 @@ -29378,7 +29373,7 @@ 1 2 - 898245 + 898137 @@ -29388,15 +29383,15 @@ values - 13547187 + 13547098 id - 13547187 + 13547098 str - 113976 + 114026 @@ -29410,7 +29405,7 @@ 1 2 - 13547187 + 13547098 @@ -29426,27 +29421,27 @@ 1 2 - 77901 + 77935 2 3 - 15222 + 15228 3 6 - 8837 + 8841 6 52 - 8584 + 8587 52 - 682207 - 3431 + 681857 + 3432 @@ -29456,15 +29451,15 @@ valuetext - 6648929 + 6647904 id - 6648929 + 6647904 text - 1095328 + 1095330 @@ -29478,7 +29473,7 @@ 1 2 - 6648929 + 6647904 @@ -29494,7 +29489,7 @@ 1 2 - 833960 + 833965 2 @@ -29504,12 +29499,12 @@ 3 7 - 86573 + 86571 7 - 593781 - 27887 + 593706 + 27886 @@ -29519,15 +29514,15 @@ valuebind - 13655401 + 13655359 val - 13547187 + 13547098 expr - 13655401 + 13655359 @@ -29541,12 +29536,12 @@ 1 2 - 13456977 + 13456848 2 6 - 90210 + 90250 @@ -29562,7 +29557,7 @@ 1 2 - 13655401 + 13655359 @@ -29572,15 +29567,15 @@ fieldoffsets - 1503222 + 1503078 id - 1503222 + 1503078 byteoffset - 31377 + 31374 bitoffset @@ -29598,7 +29593,7 @@ 1 2 - 1503222 + 1503078 @@ -29614,7 +29609,7 @@ 1 2 - 1503222 + 1503078 @@ -29630,7 +29625,7 @@ 1 2 - 17704 + 17702 2 @@ -29640,7 +29635,7 @@ 3 5 - 2669 + 2668 5 @@ -29676,12 +29671,12 @@ 1 2 - 30342 + 30339 2 9 - 1035 + 1034 @@ -29778,19 +29773,19 @@ bitfield - 29900 + 29829 id - 29900 + 29829 bits - 3445 + 3437 declared_bits - 3445 + 3437 @@ -29804,7 +29799,7 @@ 1 2 - 29900 + 29829 @@ -29820,7 +29815,7 @@ 1 2 - 29900 + 29829 @@ -29836,42 +29831,42 @@ 1 2 - 984 + 982 2 3 - 738 + 736 3 4 - 246 + 245 4 5 - 492 + 491 5 7 - 246 + 245 8 9 - 246 + 245 9 11 - 246 + 245 13 143 - 246 + 245 @@ -29887,7 +29882,7 @@ 1 2 - 3445 + 3437 @@ -29903,42 +29898,42 @@ 1 2 - 984 + 982 2 3 - 738 + 736 3 4 - 246 + 245 4 5 - 492 + 491 5 7 - 246 + 245 8 9 - 246 + 245 9 11 - 246 + 245 13 143 - 246 + 245 @@ -29954,7 +29949,7 @@ 1 2 - 3445 + 3437 @@ -29964,23 +29959,23 @@ initialisers - 2245054 + 2289023 init - 2245054 + 2289023 var - 979258 + 998370 expr - 2245054 + 2289023 location - 515871 + 525173 @@ -29994,7 +29989,7 @@ 1 2 - 2245054 + 2289023 @@ -30010,7 +30005,7 @@ 1 2 - 2245054 + 2289023 @@ -30026,7 +30021,7 @@ 1 2 - 2245054 + 2289023 @@ -30042,17 +30037,17 @@ 1 2 - 869246 + 874745 2 15 - 37296 + 51071 16 25 - 72715 + 72553 @@ -30068,17 +30063,17 @@ 1 2 - 869246 + 874745 2 15 - 37296 + 51071 16 25 - 72715 + 72553 @@ -30094,7 +30089,7 @@ 1 2 - 979250 + 998362 2 @@ -30115,7 +30110,7 @@ 1 2 - 2245054 + 2289023 @@ -30131,7 +30126,7 @@ 1 2 - 2245054 + 2289023 @@ -30147,7 +30142,7 @@ 1 2 - 2245054 + 2289023 @@ -30163,22 +30158,22 @@ 1 2 - 414351 + 414711 2 3 - 33491 + 33393 3 - 13 - 41935 + 6 + 41518 - 13 - 111939 - 26092 + 6 + 113696 + 35549 @@ -30194,17 +30189,17 @@ 1 2 - 443577 + 453031 2 3 - 34398 + 34225 3 - 12248 - 37895 + 12835 + 37916 @@ -30220,22 +30215,22 @@ 1 2 - 414351 + 414711 2 3 - 33491 + 33393 3 - 13 - 41935 + 6 + 41518 - 13 - 111939 - 26092 + 6 + 113696 + 35549 @@ -30245,26 +30240,26 @@ braced_initialisers - 67182 + 67191 init - 67182 + 67191 expr_ancestor - 1667337 + 1667335 exp - 1667337 + 1667335 ancestor - 834481 + 834480 @@ -30278,7 +30273,7 @@ 1 2 - 1667337 + 1667335 @@ -30314,11 +30309,11 @@ exprs - 25220907 + 25217889 id - 25220907 + 25217889 kind @@ -30326,7 +30321,7 @@ location - 10590021 + 10588753 @@ -30340,7 +30335,7 @@ 1 2 - 25220907 + 25217889 @@ -30356,7 +30351,7 @@ 1 2 - 25220907 + 25217889 @@ -30534,22 +30529,22 @@ 1 2 - 8907344 + 8906278 2 3 - 820953 + 820855 3 16 - 797534 + 797438 16 71733 - 64188 + 64181 @@ -30565,17 +30560,17 @@ 1 2 - 9046805 + 9045722 2 3 - 774598 + 774505 3 32 - 768617 + 768525 @@ -30711,15 +30706,15 @@ expr_types - 25220907 + 25217889 id - 25220907 + 25217889 typeid - 214292 + 214267 value_category @@ -30737,7 +30732,7 @@ 1 2 - 25220907 + 25217889 @@ -30753,7 +30748,7 @@ 1 2 - 25220907 + 25217889 @@ -30769,52 +30764,52 @@ 1 2 - 52534 + 52527 2 3 - 35206 + 35201 3 4 - 14513 + 14511 4 5 - 14535 + 14533 5 8 - 17570 + 17567 8 14 - 17394 + 17392 14 24 - 16448 + 16446 24 49 - 16074 + 16072 49 134 - 16184 + 16182 134 441492 - 13831 + 13830 @@ -30830,12 +30825,12 @@ 1 2 - 185991 + 185969 2 3 - 28301 + 28297 @@ -30898,15 +30893,15 @@ new_allocated_type - 45504 + 45518 expr - 45504 + 45518 type_id - 38362 + 26988 @@ -30920,7 +30915,7 @@ 1 2 - 45504 + 45518 @@ -30936,12 +30931,17 @@ 1 2 - 36886 + 11345 2 + 3 + 14266 + + + 3 19 - 1475 + 1376 @@ -30951,15 +30951,15 @@ new_array_allocated_type - 6630 + 6597 expr - 6630 + 6597 type_id - 2833 + 2834 @@ -30973,7 +30973,7 @@ 1 2 - 6630 + 6597 @@ -30989,22 +30989,22 @@ 1 2 - 40 + 48 2 3 - 2501 + 2503 3 - 5 + 7 218 - 6 + 8 15 - 72 + 64 @@ -31014,26 +31014,26 @@ param_ref_to_this - 24973 + 25020 expr - 24973 + 25020 aggregate_field_init - 5717382 + 5717385 aggregate - 1243070 + 1243071 initializer - 5717204 + 5717207 field @@ -31069,7 +31069,7 @@ 3 4 - 77868 + 77869 4 @@ -31120,7 +31120,7 @@ 3 4 - 77868 + 77869 4 @@ -31171,7 +31171,7 @@ 3 4 - 77868 + 77869 4 @@ -31212,7 +31212,7 @@ 1 2 - 1242988 + 1242989 2 @@ -31233,7 +31233,7 @@ 1 2 - 5717204 + 5717207 @@ -31249,7 +31249,7 @@ 1 2 - 5717026 + 5717029 2 @@ -31270,7 +31270,7 @@ 1 2 - 5717204 + 5717207 @@ -31286,7 +31286,7 @@ 1 2 - 5717204 + 5717207 @@ -31504,13 +31504,13 @@ 2 - 554345 - 1223379 + 554346 + 1223380 2 - 1243070 - 1243071 + 1243071 + 1243072 1 @@ -31575,13 +31575,13 @@ 2 - 554345 - 1223379 + 554346 + 1223380 2 - 1243070 - 1243071 + 1243071 + 1243072 1 @@ -31693,8 +31693,8 @@ 1 - 1242672 - 1242673 + 1242673 + 1242674 1 @@ -31714,8 +31714,8 @@ 1 - 5716494 - 5716495 + 5716497 + 5716498 1 @@ -32361,15 +32361,15 @@ condition_decl_bind - 406399 + 406398 expr - 406399 + 406398 decl - 406399 + 406398 @@ -32383,7 +32383,7 @@ 1 2 - 406399 + 406398 @@ -32399,7 +32399,7 @@ 1 2 - 406399 + 406398 @@ -32409,15 +32409,15 @@ typeid_bind - 47141 + 47196 expr - 47141 + 47196 type_id - 15691 + 15709 @@ -32431,7 +32431,7 @@ 1 2 - 47141 + 47196 @@ -32447,12 +32447,12 @@ 1 2 - 2917 + 2920 2 3 - 12372 + 12386 3 @@ -32467,15 +32467,15 @@ uuidof_bind - 26780 + 26214 expr - 26780 + 26214 type_id - 26529 + 26214 @@ -32489,7 +32489,7 @@ 1 2 - 26780 + 26214 @@ -32505,12 +32505,7 @@ 1 2 - 26318 - - - 2 - 4 - 210 + 26214 @@ -32520,15 +32515,15 @@ sizeof_bind - 241971 + 242078 expr - 241971 + 242078 type_id - 11151 + 11156 @@ -32542,7 +32537,7 @@ 1 2 - 241971 + 242078 @@ -32558,12 +32553,12 @@ 1 2 - 3857 + 3859 2 3 - 2751 + 2753 3 @@ -32583,7 +32578,7 @@ 6 7 - 1116 + 1117 7 @@ -32593,7 +32588,7 @@ 42 6061 - 166 + 167 @@ -32651,11 +32646,11 @@ lambdas - 18992 + 18970 expr - 18992 + 18970 default_capture @@ -32681,7 +32676,7 @@ 1 2 - 18992 + 18970 @@ -32697,7 +32692,7 @@ 1 2 - 18992 + 18970 @@ -32713,7 +32708,7 @@ 1 2 - 18992 + 18970 @@ -32732,13 +32727,13 @@ 8 - 719 - 720 + 724 + 725 8 - 1321 - 1322 + 1319 + 1320 8 @@ -32785,13 +32780,13 @@ 12 - 813 - 814 + 812 + 813 8 - 1533 - 1534 + 1537 + 1538 8 @@ -32848,8 +32843,8 @@ 8 - 2312 - 2313 + 2315 + 2316 8 @@ -32897,15 +32892,15 @@ lambda_capture - 31856 + 31810 id - 31856 + 31810 lambda - 15438 + 15424 index @@ -32913,7 +32908,7 @@ field - 31856 + 31810 captured_by_reference @@ -32925,7 +32920,7 @@ location - 17883 + 17888 @@ -32939,7 +32934,7 @@ 1 2 - 31856 + 31810 @@ -32955,7 +32950,7 @@ 1 2 - 31856 + 31810 @@ -32971,7 +32966,7 @@ 1 2 - 31856 + 31810 @@ -32987,7 +32982,7 @@ 1 2 - 31856 + 31810 @@ -33003,7 +32998,7 @@ 1 2 - 31856 + 31810 @@ -33019,7 +33014,7 @@ 1 2 - 31856 + 31810 @@ -33035,27 +33030,27 @@ 1 2 - 8184 + 8156 2 3 - 3529 + 3545 3 4 - 1651 + 1663 4 6 - 1254 + 1251 6 18 - 817 + 807 @@ -33071,27 +33066,27 @@ 1 2 - 8184 + 8156 2 3 - 3529 + 3545 3 4 - 1651 + 1663 4 6 - 1254 + 1251 6 18 - 817 + 807 @@ -33107,27 +33102,27 @@ 1 2 - 8184 + 8156 2 3 - 3529 + 3545 3 4 - 1651 + 1663 4 6 - 1254 + 1251 6 18 - 817 + 807 @@ -33143,12 +33138,12 @@ 1 2 - 14199 + 14189 2 3 - 1238 + 1235 @@ -33164,7 +33159,7 @@ 1 2 - 15316 + 15303 2 @@ -33185,27 +33180,27 @@ 1 2 - 8775 + 8746 2 3 - 3683 + 3698 3 4 - 1384 + 1397 4 7 - 1287 + 1284 7 18 - 307 + 298 @@ -33269,38 +33264,38 @@ 8 - 46 - 47 + 45 + 46 8 - 101 - 102 + 100 + 101 8 - 171 - 172 + 170 + 171 8 - 256 - 257 + 255 + 256 8 - 460 - 461 + 461 + 462 8 - 896 - 897 + 900 + 901 8 - 1907 - 1908 + 1910 + 1911 8 @@ -33365,38 +33360,38 @@ 8 - 46 - 47 + 45 + 46 8 - 101 - 102 + 100 + 101 8 - 171 - 172 + 170 + 171 8 - 256 - 257 + 255 + 256 8 - 460 - 461 + 461 + 462 8 - 896 - 897 + 900 + 901 8 - 1907 - 1908 + 1910 + 1911 8 @@ -33461,38 +33456,38 @@ 8 - 46 - 47 + 45 + 46 8 - 101 - 102 + 100 + 101 8 - 171 - 172 + 170 + 171 8 - 256 - 257 + 255 + 256 8 - 460 - 461 + 461 + 462 8 - 896 - 897 + 900 + 901 8 - 1907 - 1908 + 1910 + 1911 8 @@ -33514,7 +33509,7 @@ 2 3 - 105 + 104 @@ -33530,12 +33525,12 @@ 1 2 - 80 + 88 2 3 - 56 + 48 @@ -33599,38 +33594,38 @@ 8 - 41 - 42 + 40 + 41 8 - 66 - 67 + 65 + 66 8 - 100 - 101 + 99 + 100 8 - 182 - 183 + 181 + 182 8 - 354 - 355 + 355 + 356 8 - 604 - 605 + 609 + 610 8 - 979 - 980 + 983 + 984 8 @@ -33647,7 +33642,7 @@ 1 2 - 31856 + 31810 @@ -33663,7 +33658,7 @@ 1 2 - 31856 + 31810 @@ -33679,7 +33674,7 @@ 1 2 - 31856 + 31810 @@ -33695,7 +33690,7 @@ 1 2 - 31856 + 31810 @@ -33711,7 +33706,7 @@ 1 2 - 31856 + 31810 @@ -33727,7 +33722,7 @@ 1 2 - 31856 + 31810 @@ -33741,13 +33736,13 @@ 12 - 1457 - 1458 + 1450 + 1451 8 - 2478 - 2479 + 2489 + 2490 8 @@ -33762,13 +33757,13 @@ 12 - 819 - 820 + 818 + 819 8 - 1241 - 1242 + 1245 + 1246 8 @@ -33804,13 +33799,13 @@ 12 - 1457 - 1458 + 1450 + 1451 8 - 2478 - 2479 + 2489 + 2490 8 @@ -33841,13 +33836,13 @@ 12 - 573 - 574 + 566 + 567 8 - 1639 - 1640 + 1652 + 1653 8 @@ -33862,13 +33857,13 @@ 12 - 1351 - 1352 + 1344 + 1345 8 - 2584 - 2585 + 2595 + 2596 8 @@ -33883,13 +33878,13 @@ 12 - 955 - 956 + 954 + 955 8 - 967 - 968 + 971 + 972 8 @@ -33904,8 +33899,8 @@ 12 - 7 - 8 + 6 + 7 8 @@ -33925,13 +33920,13 @@ 12 - 1351 - 1352 + 1344 + 1345 8 - 2584 - 2585 + 2595 + 2596 8 @@ -33962,13 +33957,13 @@ 12 - 377 - 378 + 370 + 371 8 - 1832 - 1833 + 1845 + 1846 8 @@ -33985,17 +33980,17 @@ 1 2 - 15640 + 15667 2 6 - 1432 + 1413 6 68 - 809 + 807 @@ -34011,17 +34006,17 @@ 1 2 - 16215 + 16240 2 13 - 1465 + 1445 13 68 - 202 + 201 @@ -34037,12 +34032,12 @@ 1 2 - 17195 + 17201 2 8 - 688 + 686 @@ -34058,17 +34053,17 @@ 1 2 - 15640 + 15667 2 6 - 1432 + 1413 6 68 - 809 + 807 @@ -34084,7 +34079,7 @@ 1 2 - 17859 + 17863 2 @@ -34105,7 +34100,7 @@ 1 2 - 17883 + 17888 @@ -34241,11 +34236,11 @@ stmts - 6347771 + 6310367 id - 6347771 + 6310367 kind @@ -34253,7 +34248,7 @@ location - 2675419 + 2668742 @@ -34267,7 +34262,7 @@ 1 2 - 6347771 + 6310367 @@ -34283,7 +34278,7 @@ 1 2 - 6347771 + 6310367 @@ -34297,8 +34292,8 @@ 12 - 1 - 2 + 2 + 3 8 @@ -34307,13 +34302,13 @@ 8 - 430 - 431 + 495 + 496 8 - 595 - 596 + 596 + 597 8 @@ -34322,18 +34317,18 @@ 8 - 1635 - 1636 + 1637 + 1638 8 - 1818 - 1819 + 1819 + 1820 8 - 2311 - 2312 + 2321 + 2322 8 @@ -34342,58 +34337,58 @@ 8 - 3233 - 3234 + 3234 + 3235 8 - 3809 - 3810 + 3898 + 3899 8 - 5052 - 5053 + 5056 + 5057 8 - 16980 - 16981 + 16991 + 16992 8 - 18543 - 18544 + 18618 + 18619 8 - 22520 - 22521 + 22575 + 22576 8 - 74878 - 74879 + 74923 + 74924 8 - 95087 - 95088 + 95366 + 95367 8 - 119911 - 119912 + 117878 + 117879 8 - 200145 - 200146 + 198406 + 198407 8 - 213249 - 213250 + 213672 + 213673 8 @@ -34408,8 +34403,8 @@ 12 - 1 - 2 + 2 + 3 8 @@ -34418,13 +34413,13 @@ 8 - 111 - 112 + 139 + 140 8 - 436 - 437 + 437 + 438 8 @@ -34433,23 +34428,23 @@ 8 - 1155 - 1156 + 1159 + 1160 8 - 1353 - 1354 + 1354 + 1355 8 - 1388 - 1389 + 1390 + 1391 8 - 1394 - 1395 + 1395 + 1396 8 @@ -34458,53 +34453,53 @@ 8 - 2362 - 2363 + 2370 + 2371 8 - 2509 - 2510 + 2547 + 2548 8 - 7327 - 7328 + 7338 + 7339 8 - 8943 - 8944 + 8940 + 8941 8 - 11676 - 11677 + 11719 + 11720 8 - 37583 - 37584 + 37560 + 37561 8 - 44536 - 44537 + 44652 + 44653 8 - 49045 - 49046 + 48381 + 48382 8 - 86411 - 86412 + 85799 + 85800 8 - 101101 - 101102 + 101302 + 101303 8 @@ -34521,22 +34516,22 @@ 1 2 - 2217489 + 2218981 2 3 - 181609 + 177039 3 - 10 - 201484 + 11 + 202889 - 10 - 1789 - 74836 + 11 + 1816 + 69832 @@ -34552,12 +34547,12 @@ 1 2 - 2592739 + 2592497 2 10 - 82680 + 76244 @@ -34722,15 +34717,15 @@ if_then - 990619 + 990500 if_stmt - 990619 + 990500 then_id - 990619 + 990500 @@ -34744,7 +34739,7 @@ 1 2 - 990619 + 990500 @@ -34760,7 +34755,7 @@ 1 2 - 990619 + 990500 @@ -34866,15 +34861,15 @@ constexpr_if_then - 103482 + 103236 constexpr_if_stmt - 103482 + 103236 then_id - 103482 + 103236 @@ -34888,7 +34883,7 @@ 1 2 - 103482 + 103236 @@ -34904,7 +34899,7 @@ 1 2 - 103482 + 103236 @@ -34914,15 +34909,15 @@ constexpr_if_else - 74197 + 74021 constexpr_if_stmt - 74197 + 74021 else_id - 74197 + 74021 @@ -34936,7 +34931,7 @@ 1 2 - 74197 + 74021 @@ -34952,7 +34947,7 @@ 1 2 - 74197 + 74021 @@ -35058,15 +35053,15 @@ while_body - 39664 + 39659 while_stmt - 39664 + 39659 body_id - 39664 + 39659 @@ -35080,7 +35075,7 @@ 1 2 - 39664 + 39659 @@ -35096,7 +35091,7 @@ 1 2 - 39664 + 39659 @@ -35106,15 +35101,15 @@ do_body - 232426 + 232528 do_stmt - 232426 + 232528 body_id - 232426 + 232528 @@ -35128,7 +35123,7 @@ 1 2 - 232426 + 232528 @@ -35144,7 +35139,7 @@ 1 2 - 232426 + 232528 @@ -35202,11 +35197,11 @@ switch_case - 830953 + 830952 switch_stmt - 409307 + 409306 index @@ -35214,7 +35209,7 @@ case_id - 830953 + 830952 @@ -35422,7 +35417,7 @@ 1 2 - 830953 + 830952 @@ -35438,7 +35433,7 @@ 1 2 - 830953 + 830952 @@ -35448,15 +35443,15 @@ switch_body - 409307 + 409306 switch_stmt - 409307 + 409306 body_id - 409307 + 409306 @@ -35470,7 +35465,7 @@ 1 2 - 409307 + 409306 @@ -35486,7 +35481,7 @@ 1 2 - 409307 + 409306 @@ -35496,15 +35491,15 @@ for_initialization - 73276 + 73267 for_stmt - 73276 + 73267 init_id - 73276 + 73267 @@ -35518,7 +35513,7 @@ 1 2 - 73276 + 73267 @@ -35534,7 +35529,7 @@ 1 2 - 73276 + 73267 @@ -35544,15 +35539,15 @@ for_condition - 76372 + 76363 for_stmt - 76372 + 76363 condition_id - 76372 + 76363 @@ -35566,7 +35561,7 @@ 1 2 - 76372 + 76363 @@ -35582,7 +35577,7 @@ 1 2 - 76372 + 76363 @@ -35592,15 +35587,15 @@ for_update - 73416 + 73407 for_stmt - 73416 + 73407 update_id - 73416 + 73407 @@ -35614,7 +35609,7 @@ 1 2 - 73416 + 73407 @@ -35630,7 +35625,7 @@ 1 2 - 73416 + 73407 @@ -35640,15 +35635,15 @@ for_body - 84423 + 84413 for_stmt - 84423 + 84413 body_id - 84423 + 84413 @@ -35662,7 +35657,7 @@ 1 2 - 84423 + 84413 @@ -35678,7 +35673,7 @@ 1 2 - 84423 + 84413 @@ -35688,19 +35683,19 @@ stmtparents - 5609399 + 5589515 id - 5609399 + 5589515 index - 15721 + 15683 parent - 2373646 + 2355552 @@ -35714,7 +35709,7 @@ 1 2 - 5609399 + 5589515 @@ -35730,7 +35725,7 @@ 1 2 - 5609399 + 5589515 @@ -35746,52 +35741,52 @@ 1 2 - 5165 + 5152 2 3 - 1287 + 1284 3 4 - 283 + 266 4 5 - 1999 + 2010 7 8 - 1311 + 1308 8 12 - 1020 + 1017 12 29 - 1384 + 1380 29 39 - 1181 + 1179 42 78 - 1190 + 1187 78 - 209708 - 898 + 207977 + 896 @@ -35807,52 +35802,52 @@ 1 2 - 5165 + 5152 2 3 - 1287 + 1284 3 4 - 283 + 266 4 5 - 1999 + 2010 7 8 - 1311 + 1308 8 12 - 1020 + 1017 12 29 - 1384 + 1380 29 39 - 1181 + 1179 42 78 - 1190 + 1187 78 - 209708 - 898 + 207977 + 896 @@ -35868,32 +35863,32 @@ 1 2 - 1354678 + 1338178 2 3 - 515604 + 514505 3 4 - 151000 + 150687 4 6 - 155193 + 154814 6 16 - 178258 + 178500 16 1943 - 18911 + 18865 @@ -35909,32 +35904,32 @@ 1 2 - 1354678 + 1338178 2 3 - 515604 + 514505 3 4 - 151000 + 150687 4 6 - 155193 + 154814 6 16 - 178258 + 178500 16 1943 - 18911 + 18865 @@ -35944,22 +35939,22 @@ ishandler - 43039 + 42985 block - 43039 + 42985 stmt_decl_bind - 723395 + 724033 stmt - 712862 + 713534 num @@ -35967,7 +35962,7 @@ decl - 723395 + 724033 @@ -35981,12 +35976,12 @@ 1 2 - 705423 + 706121 2 10 - 7439 + 7413 @@ -36002,12 +35997,12 @@ 1 2 - 705423 + 706121 2 10 - 7439 + 7413 @@ -36056,13 +36051,13 @@ 8 - 919 - 920 + 918 + 919 8 - 88055 - 88056 + 88354 + 88355 8 @@ -36112,13 +36107,13 @@ 8 - 919 - 920 + 918 + 919 8 - 88055 - 88056 + 88354 + 88355 8 @@ -36135,7 +36130,7 @@ 1 2 - 723395 + 724033 @@ -36151,7 +36146,7 @@ 1 2 - 723395 + 724033 @@ -36161,11 +36156,11 @@ stmt_decl_entry_bind - 723395 + 724033 stmt - 712862 + 713534 num @@ -36173,7 +36168,7 @@ decl_entry - 723395 + 724033 @@ -36187,12 +36182,12 @@ 1 2 - 705423 + 706121 2 10 - 7439 + 7413 @@ -36208,12 +36203,12 @@ 1 2 - 705423 + 706121 2 10 - 7439 + 7413 @@ -36262,13 +36257,13 @@ 8 - 919 - 920 + 918 + 919 8 - 88055 - 88056 + 88354 + 88355 8 @@ -36318,13 +36313,13 @@ 8 - 919 - 920 + 918 + 919 8 - 88055 - 88056 + 88354 + 88355 8 @@ -36341,7 +36336,7 @@ 1 2 - 723395 + 724033 @@ -36357,7 +36352,7 @@ 1 2 - 723395 + 724033 @@ -36367,15 +36362,15 @@ blockscope - 1618065 + 1614225 block - 1618065 + 1614225 enclosing - 1404210 + 1400877 @@ -36389,7 +36384,7 @@ 1 2 - 1618065 + 1614225 @@ -36405,17 +36400,17 @@ 1 2 - 1273657 + 1270635 2 4 - 115417 + 115144 4 29 - 15134 + 15098 @@ -36425,19 +36420,19 @@ jumpinfo - 348317 + 348275 id - 348317 + 348275 str - 28948 + 28944 target - 72705 + 72696 @@ -36451,7 +36446,7 @@ 1 2 - 348317 + 348275 @@ -36467,7 +36462,7 @@ 1 2 - 348317 + 348275 @@ -36483,7 +36478,7 @@ 2 3 - 13596 + 13595 3 @@ -36493,7 +36488,7 @@ 4 5 - 2014 + 2013 5 @@ -36529,7 +36524,7 @@ 1 2 - 23190 + 23187 2 @@ -36539,7 +36534,7 @@ 3 3321 - 2131 + 2130 @@ -36560,22 +36555,22 @@ 2 3 - 36210 + 36206 3 4 - 17633 + 17631 4 5 - 7379 + 7378 5 8 - 6418 + 6417 8 @@ -36596,7 +36591,7 @@ 1 2 - 72705 + 72696 @@ -36606,19 +36601,19 @@ preprocdirects - 5334448 + 5321789 id - 5334448 + 5321789 kind - 1353 + 1350 location - 5331372 + 5318720 @@ -36632,7 +36627,7 @@ 1 2 - 5334448 + 5321789 @@ -36648,7 +36643,7 @@ 1 2 - 5334448 + 5321789 @@ -36664,57 +36659,57 @@ 1 2 - 123 + 122 139 140 - 123 + 122 805 806 - 123 + 122 880 881 - 123 + 122 973 974 - 123 + 122 1509 1510 - 123 + 122 1883 1884 - 123 + 122 3256 3257 - 123 + 122 4737 4738 - 123 + 122 7126 7127 - 123 + 122 22044 22045 - 123 + 122 @@ -36730,57 +36725,57 @@ 1 2 - 123 + 122 139 140 - 123 + 122 805 806 - 123 + 122 880 881 - 123 + 122 973 974 - 123 + 122 1509 1510 - 123 + 122 1883 1884 - 123 + 122 3256 3257 - 123 + 122 4737 4738 - 123 + 122 7126 7127 - 123 + 122 22019 22020 - 123 + 122 @@ -36796,12 +36791,12 @@ 1 2 - 5331249 + 5318597 26 27 - 123 + 122 @@ -36817,7 +36812,7 @@ 1 2 - 5331372 + 5318720 @@ -36827,15 +36822,15 @@ preprocpair - 1125632 + 1122961 begin - 876831 + 874750 elseelifend - 1125632 + 1122961 @@ -36849,17 +36844,17 @@ 1 2 - 640704 + 639184 2 3 - 227267 + 226728 3 9 - 8859 + 8838 @@ -36875,7 +36870,7 @@ 1 2 - 1125632 + 1122961 @@ -36885,41 +36880,41 @@ preproctrue - 433247 + 432219 branch - 433247 + 432219 preprocfalse - 281408 + 280740 branch - 281408 + 280740 preproctext - 4292857 + 4282669 id - 4292857 + 4282669 head - 2914733 + 2907815 body - 1660393 + 1656453 @@ -36933,7 +36928,7 @@ 1 2 - 4292857 + 4282669 @@ -36949,7 +36944,7 @@ 1 2 - 4292857 + 4282669 @@ -36965,12 +36960,12 @@ 1 2 - 2718842 + 2712390 2 798 - 195890 + 195425 @@ -36986,12 +36981,12 @@ 1 2 - 2834629 + 2827902 2 5 - 80103 + 79913 @@ -37007,17 +37002,17 @@ 1 2 - 1514214 + 1510620 2 10 - 125507 + 125209 10 13605 - 20671 + 20622 @@ -37033,17 +37028,17 @@ 1 2 - 1518397 + 1514794 2 12 - 125138 + 124841 12 3246 - 16857 + 16817 @@ -37053,15 +37048,15 @@ includes - 316291 + 316459 id - 316291 + 316459 included - 58263 + 58294 @@ -37075,7 +37070,7 @@ 1 2 - 316291 + 316459 @@ -37091,37 +37086,37 @@ 1 2 - 28832 + 28848 2 3 - 9373 + 9378 3 4 - 4917 + 4919 4 6 - 5315 + 5318 6 11 - 4487 + 4489 11 47 - 4372 + 4374 47 793 - 964 + 965 @@ -37227,11 +37222,11 @@ link_parent - 30703622 + 30993807 element - 3901314 + 3938571 link_target @@ -37249,17 +37244,17 @@ 1 2 - 531771 + 537390 2 9 - 26990 + 27022 9 10 - 3342551 + 3374158 @@ -37278,48 +37273,48 @@ 33 - 99949 - 99950 + 100775 + 100776 33 - 100069 - 100070 + 100895 + 100896 33 - 100127 - 100128 + 100953 + 100954 33 - 100148 - 100149 + 100974 + 100975 33 - 100170 - 100171 + 100996 + 100997 33 - 100212 - 100213 + 101038 + 101039 33 - 102215 - 102216 + 103041 + 103042 33 - 105685 - 105686 + 106539 + 106540 33 - 107152 - 107153 + 108099 + 108100 33 diff --git a/cpp/ql/src/CHANGELOG.md b/cpp/ql/src/CHANGELOG.md index e8a2af1383c..9d8877f2181 100644 --- a/cpp/ql/src/CHANGELOG.md +++ b/cpp/ql/src/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.6.5 + +No user-facing changes. + ## 1.6.4 No user-facing changes. diff --git a/cpp/ql/src/change-notes/released/1.6.5.md b/cpp/ql/src/change-notes/released/1.6.5.md new file mode 100644 index 00000000000..44f1ca6de3e --- /dev/null +++ b/cpp/ql/src/change-notes/released/1.6.5.md @@ -0,0 +1,3 @@ +## 1.6.5 + +No user-facing changes. diff --git a/cpp/ql/src/codeql-pack.release.yml b/cpp/ql/src/codeql-pack.release.yml index 1910e09d6a6..03153270557 100644 --- a/cpp/ql/src/codeql-pack.release.yml +++ b/cpp/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.6.4 +lastReleaseVersion: 1.6.5 diff --git a/cpp/ql/src/qlpack.yml b/cpp/ql/src/qlpack.yml index 7f3df37c30a..3b6365f29c6 100644 --- a/cpp/ql/src/qlpack.yml +++ b/cpp/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cpp-queries -version: 1.6.5-dev +version: 1.6.6-dev groups: - cpp - queries diff --git a/csharp/autobuilder/Semmle.Autobuild.CSharp.Tests/BuildScripts.cs b/csharp/autobuilder/Semmle.Autobuild.CSharp.Tests/BuildScripts.cs index a8ce9653916..d0b06753734 100644 --- a/csharp/autobuilder/Semmle.Autobuild.CSharp.Tests/BuildScripts.cs +++ b/csharp/autobuilder/Semmle.Autobuild.CSharp.Tests/BuildScripts.cs @@ -135,7 +135,7 @@ namespace Semmle.Autobuild.CSharp.Tests if (!EnumerateFiles.TryGetValue(dir, out var str)) throw new ArgumentException("Missing EnumerateFiles " + dir); - return str.Split("\n").Select(p => PathCombine(dir, p)); + return str.Split("\n").Select(p => PathJoin(dir, p)); } public IDictionary EnumerateDirectories { get; } = new Dictionary(); @@ -147,7 +147,7 @@ namespace Semmle.Autobuild.CSharp.Tests return string.IsNullOrEmpty(str) ? Enumerable.Empty() - : str.Split("\n").Select(p => PathCombine(dir, p)); + : str.Split("\n").Select(p => PathJoin(dir, p)); } public bool IsWindows { get; set; } @@ -170,7 +170,7 @@ namespace Semmle.Autobuild.CSharp.Tests bool IBuildActions.IsMonoInstalled() => IsMonoInstalled; - public string PathCombine(params string[] parts) + public string PathJoin(params string[] parts) { return string.Join(IsWindows ? '\\' : '/', parts.Where(p => !string.IsNullOrWhiteSpace(p))); } diff --git a/csharp/autobuilder/Semmle.Autobuild.CSharp/DotNetRule.cs b/csharp/autobuilder/Semmle.Autobuild.CSharp/DotNetRule.cs index e07f7592887..47dc60b0022 100644 --- a/csharp/autobuilder/Semmle.Autobuild.CSharp/DotNetRule.cs +++ b/csharp/autobuilder/Semmle.Autobuild.CSharp/DotNetRule.cs @@ -109,7 +109,7 @@ namespace Semmle.Autobuild.CSharp => WithDotNet(builder, ensureDotNetAvailable: false, (_, env) => f(env)); private static string DotNetCommand(IBuildActions actions, string? dotNetPath) => - dotNetPath is not null ? actions.PathCombine(dotNetPath, "dotnet") : "dotnet"; + dotNetPath is not null ? actions.PathJoin(dotNetPath, "dotnet") : "dotnet"; private static CommandBuilder GetCleanCommand(IBuildActions actions, string? dotNetPath, IDictionary? environment) { diff --git a/csharp/autobuilder/Semmle.Autobuild.Cpp.Tests/BuildScripts.cs b/csharp/autobuilder/Semmle.Autobuild.Cpp.Tests/BuildScripts.cs index fd5e4073d6d..661701f2b95 100644 --- a/csharp/autobuilder/Semmle.Autobuild.Cpp.Tests/BuildScripts.cs +++ b/csharp/autobuilder/Semmle.Autobuild.Cpp.Tests/BuildScripts.cs @@ -158,7 +158,7 @@ namespace Semmle.Autobuild.Cpp.Tests bool IBuildActions.IsMonoInstalled() => IsMonoInstalled; - string IBuildActions.PathCombine(params string[] parts) + string IBuildActions.PathJoin(params string[] parts) { return string.Join(IsWindows ? '\\' : '/', parts.Where(p => !string.IsNullOrWhiteSpace(p))); } diff --git a/csharp/autobuilder/Semmle.Autobuild.Shared/Autobuilder.cs b/csharp/autobuilder/Semmle.Autobuild.Shared/Autobuilder.cs index a15235d3502..a26254f7d19 100644 --- a/csharp/autobuilder/Semmle.Autobuild.Shared/Autobuilder.cs +++ b/csharp/autobuilder/Semmle.Autobuild.Shared/Autobuilder.cs @@ -108,7 +108,7 @@ namespace Semmle.Autobuild.Shared /// /// The relative path. /// True iff the path was found. - public bool HasRelativePath(string path) => HasPath(Actions.PathCombine(RootDirectory, path)); + public bool HasRelativePath(string path) => HasPath(Actions.PathJoin(RootDirectory, path)); /// /// List of project/solution files to build. diff --git a/csharp/autobuilder/Semmle.Autobuild.Shared/BuildTools.cs b/csharp/autobuilder/Semmle.Autobuild.Shared/BuildTools.cs index c445fcb805a..83779b2a8d9 100644 --- a/csharp/autobuilder/Semmle.Autobuild.Shared/BuildTools.cs +++ b/csharp/autobuilder/Semmle.Autobuild.Shared/BuildTools.cs @@ -32,7 +32,7 @@ namespace Semmle.Autobuild.Shared yield break; // Attempt to use vswhere to find installations of Visual Studio - var vswhere = actions.PathCombine(programFilesx86, "Microsoft Visual Studio", "Installer", "vswhere.exe"); + var vswhere = actions.PathJoin(programFilesx86, "Microsoft Visual Studio", "Installer", "vswhere.exe"); if (actions.FileExists(vswhere)) { @@ -51,14 +51,14 @@ namespace Semmle.Autobuild.Shared if (majorVersion < 15) { // Visual Studio 2015 and below - yield return new VcVarsBatFile(actions.PathCombine(vsInstallation.InstallationPath, @"VC\vcvarsall.bat"), majorVersion); + yield return new VcVarsBatFile(actions.PathJoin(vsInstallation.InstallationPath, @"VC\vcvarsall.bat"), majorVersion); } else { // Visual Studio 2017 and above - yield return new VcVarsBatFile(actions.PathCombine(vsInstallation.InstallationPath, @"VC\Auxiliary\Build\vcvars32.bat"), majorVersion); - yield return new VcVarsBatFile(actions.PathCombine(vsInstallation.InstallationPath, @"VC\Auxiliary\Build\vcvars64.bat"), majorVersion); - yield return new VcVarsBatFile(actions.PathCombine(vsInstallation.InstallationPath, @"Common7\Tools\VsDevCmd.bat"), majorVersion); + yield return new VcVarsBatFile(actions.PathJoin(vsInstallation.InstallationPath, @"VC\Auxiliary\Build\vcvars32.bat"), majorVersion); + yield return new VcVarsBatFile(actions.PathJoin(vsInstallation.InstallationPath, @"VC\Auxiliary\Build\vcvars64.bat"), majorVersion); + yield return new VcVarsBatFile(actions.PathJoin(vsInstallation.InstallationPath, @"Common7\Tools\VsDevCmd.bat"), majorVersion); } } // else: Skip installation without a version @@ -68,10 +68,10 @@ namespace Semmle.Autobuild.Shared } // vswhere not installed or didn't run correctly - return legacy Visual Studio versions - yield return new VcVarsBatFile(actions.PathCombine(programFilesx86, @"Microsoft Visual Studio 14.0\VC\vcvarsall.bat"), 14); - yield return new VcVarsBatFile(actions.PathCombine(programFilesx86, @"Microsoft Visual Studio 12.0\VC\vcvarsall.bat"), 12); - yield return new VcVarsBatFile(actions.PathCombine(programFilesx86, @"Microsoft Visual Studio 11.0\VC\vcvarsall.bat"), 11); - yield return new VcVarsBatFile(actions.PathCombine(programFilesx86, @"Microsoft Visual Studio 10.0\VC\vcvarsall.bat"), 10); + yield return new VcVarsBatFile(actions.PathJoin(programFilesx86, @"Microsoft Visual Studio 14.0\VC\vcvarsall.bat"), 14); + yield return new VcVarsBatFile(actions.PathJoin(programFilesx86, @"Microsoft Visual Studio 12.0\VC\vcvarsall.bat"), 12); + yield return new VcVarsBatFile(actions.PathJoin(programFilesx86, @"Microsoft Visual Studio 11.0\VC\vcvarsall.bat"), 11); + yield return new VcVarsBatFile(actions.PathJoin(programFilesx86, @"Microsoft Visual Studio 10.0\VC\vcvarsall.bat"), 10); } /// diff --git a/csharp/autobuilder/Semmle.Autobuild.Shared/MsBuildRule.cs b/csharp/autobuilder/Semmle.Autobuild.Shared/MsBuildRule.cs index 748a22fb9d3..62d4f426db5 100644 --- a/csharp/autobuilder/Semmle.Autobuild.Shared/MsBuildRule.cs +++ b/csharp/autobuilder/Semmle.Autobuild.Shared/MsBuildRule.cs @@ -60,7 +60,7 @@ namespace Semmle.Autobuild.Shared // Use `nuget.exe` from source code repo, if present, otherwise first attempt with global // `nuget` command, and if that fails, attempt to download `nuget.exe` from nuget.org var nuget = builder.GetFilename("nuget.exe").Select(t => t.Item1).FirstOrDefault() ?? "nuget"; - var nugetDownloadPath = builder.Actions.PathCombine(FileUtils.GetTemporaryWorkingDirectory(builder.Actions.GetEnvironmentVariable, builder.Options.Language.UpperCaseName, out _), ".nuget", "nuget.exe"); + var nugetDownloadPath = builder.Actions.PathJoin(FileUtils.GetTemporaryWorkingDirectory(builder.Actions.GetEnvironmentVariable, builder.Options.Language.UpperCaseName, out _), ".nuget", "nuget.exe"); var nugetDownloaded = false; var ret = BuildScript.Success; diff --git a/csharp/autobuilder/Semmle.Autobuild.Shared/Project.cs b/csharp/autobuilder/Semmle.Autobuild.Shared/Project.cs index 32c5cdeca28..9c2902f8973 100644 --- a/csharp/autobuilder/Semmle.Autobuild.Shared/Project.cs +++ b/csharp/autobuilder/Semmle.Autobuild.Shared/Project.cs @@ -107,8 +107,9 @@ namespace Semmle.Autobuild.Shared continue; } - var includePath = builder.Actions.PathCombine(include.Value.Split('\\', StringSplitOptions.RemoveEmptyEntries)); - ret.Add(new Project(builder, builder.Actions.PathCombine(DirectoryName, includePath))); + var includePath = builder.Actions.PathJoin(include.Value.Split('\\', StringSplitOptions.RemoveEmptyEntries)); + var path = Path.IsPathRooted(includePath) ? includePath : builder.Actions.PathJoin(DirectoryName, includePath); + ret.Add(new Project(builder, path)); } return ret; }); diff --git a/csharp/autobuilder/Semmle.Autobuild.Shared/Solution.cs b/csharp/autobuilder/Semmle.Autobuild.Shared/Solution.cs index 5cf0c4a8487..5852a3834d4 100644 --- a/csharp/autobuilder/Semmle.Autobuild.Shared/Solution.cs +++ b/csharp/autobuilder/Semmle.Autobuild.Shared/Solution.cs @@ -79,7 +79,7 @@ namespace Semmle.Autobuild.Shared includedProjects = solution.ProjectsInOrder .Where(p => p.ProjectType == SolutionProjectType.KnownToBeMSBuildFormat) - .Select(p => builder.Actions.PathCombine(DirectoryName, builder.Actions.PathCombine(p.RelativePath.Split('\\', StringSplitOptions.RemoveEmptyEntries)))) + .Select(p => builder.Actions.PathJoin(DirectoryName, builder.Actions.PathJoin(p.RelativePath.Split('\\', StringSplitOptions.RemoveEmptyEntries)))) .Select(p => new Project(builder, p)) .ToArray(); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/DependencyContainer.cs b/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/DependencyContainer.cs index b5abefb3a65..e99ab4c74f7 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/DependencyContainer.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/DependencyContainer.cs @@ -50,7 +50,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching return; } - var path = Path.Combine(p, ParseFilePath(d)); + var path = Path.Join(p, ParseFilePath(d)); Paths.Add(path); Packages.Add(GetPackageName(p)); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/DependencyManager.cs b/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/DependencyManager.cs index bc010e318c3..2706d526293 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/DependencyManager.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/DependencyManager.cs @@ -75,7 +75,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching } } - this.diagnosticsWriter = new DiagnosticsStream(Path.Combine( + this.diagnosticsWriter = new DiagnosticsStream(Path.Join( diagDirEnv ?? "", $"dependency-manager-{DateTime.UtcNow:yyyyMMddHHmm}-{Environment.ProcessId}.jsonc")); this.sourceDir = new DirectoryInfo(srcDir); @@ -327,7 +327,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching private void RemoveNugetPackageReference(string packagePrefix, ISet dllLocations) { var packageFolder = nugetPackageRestorer.PackageDirectory.DirInfo.FullName.ToLowerInvariant(); - var packagePathPrefix = Path.Combine(packageFolder, packagePrefix.ToLowerInvariant()); + var packagePathPrefix = Path.Join(packageFolder, packagePrefix.ToLowerInvariant()); var toRemove = dllLocations.Where(s => s.Path.StartsWith(packagePathPrefix, StringComparison.InvariantCultureIgnoreCase)); foreach (var path in toRemove) { diff --git a/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/DotNet.cs b/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/DotNet.cs index 699e06d273c..e93a2933612 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/DotNet.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/DotNet.cs @@ -31,7 +31,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching } } - private DotNet(ILogger logger, string? dotNetPath, TemporaryDirectory tempWorkingDirectory, DependabotProxy? dependabotProxy) : this(new DotNetCliInvoker(logger, Path.Combine(dotNetPath ?? string.Empty, "dotnet"), dependabotProxy), logger, dotNetPath is null, tempWorkingDirectory) { } + private DotNet(ILogger logger, string? dotNetPath, TemporaryDirectory tempWorkingDirectory, DependabotProxy? dependabotProxy) : this(new DotNetCliInvoker(logger, Path.Join(dotNetPath ?? string.Empty, "dotnet"), dependabotProxy), logger, dotNetPath is null, tempWorkingDirectory) { } internal static IDotNet Make(IDotNetCliInvoker dotnetCliInvoker, ILogger logger, bool runDotnetInfo) => new DotNet(dotnetCliInvoker, logger, runDotnetInfo); @@ -73,7 +73,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching var path = ".empty"; if (tempWorkingDirectory != null) { - path = Path.Combine(tempWorkingDirectory.ToString(), "emptyFakeDotnetRoot"); + path = Path.Join(tempWorkingDirectory.ToString(), "emptyFakeDotnetRoot"); Directory.CreateDirectory(path); } @@ -303,7 +303,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching } else { - var dotnetInstallPath = actions.PathCombine(tempWorkingDirectory, ".dotnet", "dotnet-install.sh"); + var dotnetInstallPath = actions.PathJoin(tempWorkingDirectory, ".dotnet", "dotnet-install.sh"); var downloadDotNetInstallSh = BuildScript.DownloadFile( "https://dot.net/v1/dotnet-install.sh", dotnetInstallPath, @@ -339,7 +339,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching }; } - var dotnetInfo = InfoScript(actions, actions.PathCombine(path, "dotnet"), MinimalEnvironment.ToDictionary(), logger); + var dotnetInfo = InfoScript(actions, actions.PathJoin(path, "dotnet"), MinimalEnvironment.ToDictionary(), logger); Func getInstallAndVerify = version => // run `dotnet --info` after install, to check that it executes successfully @@ -384,7 +384,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching /// public static BuildScript WithDotNet(IBuildActions actions, ILogger logger, IEnumerable files, string tempWorkingDirectory, bool shouldCleanUp, bool ensureDotNetAvailable, string? version, Func f) { - var installDir = actions.PathCombine(tempWorkingDirectory, ".dotnet"); + var installDir = actions.PathJoin(tempWorkingDirectory, ".dotnet"); var installScript = DownloadDotNet(actions, logger, files, tempWorkingDirectory, shouldCleanUp, installDir, version, ensureDotNetAvailable); return BuildScript.Bind(installScript, installed => { diff --git a/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/DotNetVersion.cs b/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/DotNetVersion.cs index 31a4ac2292d..8ea710beb38 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/DotNetVersion.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/DotNetVersion.cs @@ -12,7 +12,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching private string FullVersion => version.ToString(); - public string FullPath => Path.Combine(dir, FullVersion); + public string FullPath => Path.Join(dir, FullVersion); /** * The full path to the reference assemblies for this runtime. @@ -33,7 +33,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching { directories[^2] = "packs"; directories[^1] = $"{directories[^1]}.Ref"; - return Path.Combine(string.Join(Path.DirectorySeparatorChar, directories), FullVersion, "ref"); + return Path.Join(string.Join(Path.DirectorySeparatorChar, directories), FullVersion, "ref"); } return null; } diff --git a/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/FeedManager.cs b/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/FeedManager.cs new file mode 100644 index 00000000000..b9b5e16afd8 --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/FeedManager.cs @@ -0,0 +1,413 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.IO; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Security.Cryptography.X509Certificates; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading; +using System.Threading.Tasks; +using Semmle.Util; +using Semmle.Util.Logging; + +namespace Semmle.Extraction.CSharp.DependencyFetching +{ + internal sealed partial class FeedManager : IDisposable + { + internal const string PublicNugetOrgFeed = "https://api.nuget.org/v3/index.json"; + + private readonly ILogger logger; + private readonly IDotNet dotnet; + private readonly FileProvider fileProvider; + private readonly DependabotProxy? dependabotProxy; + private readonly DependencyDirectory emptyPackageDirectory; + + public ImmutableHashSet PrivateRegistryFeeds { get; } + public bool HasPrivateRegistryFeeds { get; } + public bool CheckNugetFeedResponsiveness { get; } = EnvironmentVariables.GetBooleanOptOut(EnvironmentVariableNames.CheckNugetFeedResponsiveness); + + public FeedManager(ILogger logger, IDotNet dotnet, DependabotProxy? dependabotProxy, FileProvider fileProvider) + { + this.logger = logger; + this.dotnet = dotnet; + this.dependabotProxy = dependabotProxy; + this.fileProvider = fileProvider; + PrivateRegistryFeeds = dependabotProxy?.RegistryURLs.ToImmutableHashSet() ?? []; + HasPrivateRegistryFeeds = PrivateRegistryFeeds.Count > 0; + emptyPackageDirectory = new DependencyDirectory("empty", "empty package", logger); + } + + private string? GetDirectoryName(string path) + { + try + { + return new FileInfo(path).Directory?.FullName; + } + catch (Exception exc) + { + logger.LogWarning($"Failed to get directory of '{path}': {exc}"); + } + return null; + } + + private IEnumerable GetFeeds(Func> getNugetFeeds) + { + var results = getNugetFeeds(); + var regex = EnabledNugetFeed(); + foreach (var result in results) + { + var match = regex.Match(result); + if (!match.Success) + { + logger.LogError($"Failed to parse feed from '{result}'"); + continue; + } + + var url = match.Groups[1].Value; + if (!url.StartsWith("https://", StringComparison.InvariantCultureIgnoreCase) && + !url.StartsWith("http://", StringComparison.InvariantCultureIgnoreCase)) + { + logger.LogInfo($"Skipping feed '{url}' as it is not a valid URL."); + continue; + } + + if (!string.IsNullOrWhiteSpace(url)) + { + yield return url; + } + } + } + + private IEnumerable GetFeedsFromFolder(string folderPath) => + GetFeeds(() => dotnet.GetNugetFeedsFromFolder(folderPath)); + + + private IEnumerable GetFeedsFromNugetConfig(string nugetConfigPath) => + GetFeeds(() => dotnet.GetNugetFeeds(nugetConfigPath)); + + private string FeedsToRestoreArgument(IEnumerable feeds) + { + // If there are no feeds, we want to override any default feeds that `dotnet restore` would use by passing a dummy source argument. + if (!feeds.Any()) + { + return $" -s \"{emptyPackageDirectory.DirInfo.FullName}\""; + } + + // Add package sources. If any are present, they override all sources specified in + // the configuration file(s). + var feedArgs = new StringBuilder(); + foreach (var feed in feeds) + { + feedArgs.Append($" -s \"{feed}\""); + } + + return feedArgs.ToString(); + } + + /// + /// Constructs the list of NuGet sources to use for this restore. + /// (1) Use the feeds we get from `dotnet nuget list source` + /// (2) Use private registries, if they are configured + /// + /// Path to project/solution + /// The set of reachable NuGet feeds. + /// A string representing the NuGet sources argument for the restore command. + public string? MakeRestoreSourcesArgument(string path, HashSet reachableFeeds) + { + // Do not construct a set of explicit NuGet sources to use for restore. + if (!CheckNugetFeedResponsiveness && !HasPrivateRegistryFeeds) + { + return null; + } + + // Find the path specific feeds. + var folder = GetDirectoryName(path); + var feedsToConsider = folder is not null ? GetFeedsFromFolder(folder).ToHashSet() : new HashSet(); + + if (HasPrivateRegistryFeeds) + { + feedsToConsider.UnionWith(PrivateRegistryFeeds); + } + + var feedsToUse = CheckNugetFeedResponsiveness + ? feedsToConsider.Where(reachableFeeds.Contains) + : feedsToConsider; + + return FeedsToRestoreArgument(feedsToUse); + } + + private (int initialTimeout, int tryCount) GetFeedRequestSettings(bool isFallback) + { + int timeoutMilliSeconds = isFallback && int.TryParse(Environment.GetEnvironmentVariable(EnvironmentVariableNames.NugetFeedResponsivenessInitialTimeoutForFallback), out timeoutMilliSeconds) + ? timeoutMilliSeconds + : int.TryParse(Environment.GetEnvironmentVariable(EnvironmentVariableNames.NugetFeedResponsivenessInitialTimeout), out timeoutMilliSeconds) + ? timeoutMilliSeconds + : 1000; + logger.LogDebug($"Initial timeout for NuGet feed reachability check is {timeoutMilliSeconds}ms."); + + int tryCount = isFallback && int.TryParse(Environment.GetEnvironmentVariable(EnvironmentVariableNames.NugetFeedResponsivenessRequestCountForFallback), out tryCount) + ? tryCount + : int.TryParse(Environment.GetEnvironmentVariable(EnvironmentVariableNames.NugetFeedResponsivenessRequestCount), out tryCount) + ? tryCount + : 4; + logger.LogDebug($"Number of tries for NuGet feed reachability check is {tryCount}."); + + return (timeoutMilliSeconds, tryCount); + } + + private static async Task ExecuteGetRequest(string address, HttpClient httpClient, CancellationToken cancellationToken) + { + return await httpClient.GetAsync(address, HttpCompletionOption.ResponseHeadersRead, cancellationToken); + } + + private bool IsFeedReachable(string feed, int timeoutMilliSeconds, int tryCount, out bool isTimeout) + { + logger.LogInfo($"Checking if NuGet feed '{feed}' is reachable..."); + + // Configure the HttpClient to be aware of the Dependabot Proxy, if used. + HttpClientHandler httpClientHandler = new(); + if (dependabotProxy != null) + { + httpClientHandler.Proxy = new WebProxy(dependabotProxy.Address); + + if (dependabotProxy.Certificate != null) + { + httpClientHandler.ServerCertificateCustomValidationCallback = (message, cert, chain, _) => + { + if (chain is null || cert is null) + { + var msg = cert is null && chain is null + ? "certificate and chain" + : chain is null + ? "chain" + : "certificate"; + logger.LogWarning($"Dependabot proxy certificate validation failed due to missing {msg}"); + return false; + } + chain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust; + chain.ChainPolicy.CustomTrustStore.Add(dependabotProxy.Certificate); + return chain.Build(cert); + }; + } + } + + using HttpClient client = new(httpClientHandler); + + isTimeout = false; + + for (var i = 0; i < tryCount; i++) + { + using var cts = new CancellationTokenSource(); + cts.CancelAfter(timeoutMilliSeconds); + try + { + logger.LogInfo($"Attempt {i + 1}/{tryCount} to reach NuGet feed '{feed}'."); + using var response = ExecuteGetRequest(feed, client, cts.Token).GetAwaiter().GetResult(); + response.EnsureSuccessStatusCode(); + logger.LogInfo($"Querying NuGet feed '{feed}' succeeded."); + return true; + } + catch (Exception exc) + { + if (exc is TaskCanceledException tce && + tce.CancellationToken == cts.Token && + cts.Token.IsCancellationRequested) + { + logger.LogInfo($"Didn't receive answer from NuGet feed '{feed}' in {timeoutMilliSeconds}ms."); + timeoutMilliSeconds *= 2; + continue; + } + + logger.LogInfo($"Querying NuGet feed '{feed}' failed. The reason for the failure: {exc.Message}"); + return false; + } + } + + logger.LogWarning($"Didn't receive answer from NuGet feed '{feed}'. Tried it {tryCount} times."); + isTimeout = true; + return false; + } + + /// + /// Retrieves a list of excluded NuGet feeds from the corresponding environment variable. + /// + private HashSet GetExcludedFeeds() + { + var excludedFeeds = EnvironmentVariables.GetURLs(EnvironmentVariableNames.ExcludedNugetFeedsFromResponsivenessCheck) + .ToHashSet(); + + if (excludedFeeds.Count > 0) + { + logger.LogInfo($"Excluded NuGet feeds from responsiveness check: {string.Join(", ", excludedFeeds.OrderBy(f => f))}"); + } + + return excludedFeeds; + } + + /// + /// Checks that we can connect to the specified NuGet feeds. + /// + /// The set of package feeds to check. + /// The list of feeds that were reachable. + /// + /// True if there is a timeout when trying to reach the feeds (excluding any feeds that are configured + /// to be excluded from the check) or false otherwise. + /// + public bool CheckSpecifiedFeeds(HashSet feeds, out HashSet reachableFeeds) + { + // Exclude any feeds from the feed check that are configured by the corresponding environment variable. + // These feeds are always assumed to be reachable. + var excludedFeeds = GetExcludedFeeds(); + + HashSet feedsToCheck = feeds.Where(feed => + { + if (excludedFeeds.Contains(feed)) + { + logger.LogInfo($"Not checking reachability of NuGet feed '{feed}' as it is in the list of excluded feeds."); + return false; + } + return true; + }).ToHashSet(); + + reachableFeeds = GetReachableNuGetFeeds(feedsToCheck, isFallback: false, out var isTimeout).ToHashSet(); + + // Always consider feeds excluded for the reachability check as reachable. + reachableFeeds.UnionWith(feeds.Where(feed => excludedFeeds.Contains(feed))); + + return isTimeout; + } + + public bool IsDefaultFeedReachable() + { + if (CheckNugetFeedResponsiveness) + { + var (initialTimeout, tryCount) = GetFeedRequestSettings(isFallback: false); + return IsFeedReachable(PublicNugetOrgFeed, initialTimeout, tryCount, out var _); + } + + return true; + } + + /// + /// Tests which of the feeds given by are reachable. + /// + /// The feeds to check. + /// Whether the feeds are fallback feeds or not. + /// Whether a timeout occurred while checking the feeds. + /// The list of feeds that could be reached. + private List GetReachableNuGetFeeds(HashSet feedsToCheck, bool isFallback, out bool isTimeout) + { + var fallbackStr = isFallback ? "fallback " : ""; + logger.LogInfo($"Checking {fallbackStr}NuGet feed reachability on feeds: {string.Join(", ", feedsToCheck.OrderBy(f => f))}"); + + var (initialTimeout, tryCount) = GetFeedRequestSettings(isFallback); + var timeout = false; + var reachableFeeds = feedsToCheck + .Where(feed => + { + var reachable = IsFeedReachable(feed, initialTimeout, tryCount, out var feedTimeout); + timeout |= feedTimeout; + return reachable; + }) + .ToList(); + + if (reachableFeeds.Count == 0) + { + logger.LogWarning($"No {fallbackStr}NuGet feeds are reachable."); + } + else + { + logger.LogInfo($"Reachable {fallbackStr}NuGet feeds: {string.Join(", ", reachableFeeds.OrderBy(f => f))}"); + } + + isTimeout = timeout; + return reachableFeeds; + } + + public List GetReachableFallbackNugetFeeds(HashSet? feedsFromNugetConfigs) + { + var fallbackFeeds = EnvironmentVariables.GetURLs(EnvironmentVariableNames.FallbackNugetFeeds).ToHashSet(); + if (fallbackFeeds.Count == 0) + { + fallbackFeeds.Add(PublicNugetOrgFeed); + logger.LogInfo($"No fallback NuGet feeds specified. Adding default feed: {PublicNugetOrgFeed}"); + + var shouldAddNugetConfigFeeds = EnvironmentVariables.GetBooleanOptOut(EnvironmentVariableNames.AddNugetConfigFeedsToFallback); + logger.LogInfo($"Adding feeds from nuget.config to fallback restore: {shouldAddNugetConfigFeeds}"); + + if (shouldAddNugetConfigFeeds && feedsFromNugetConfigs?.Count > 0) + { + // There are some feeds in `feedsFromNugetConfigs` that have already been checked for reachability, we could skip those. + // But we might use different responsiveness testing settings when we try them in the fallback logic, so checking them again is safer. + fallbackFeeds.UnionWith(feedsFromNugetConfigs); + logger.LogInfo($"Using NuGet feeds from nuget.config files as fallback feeds: {string.Join(", ", feedsFromNugetConfigs.OrderBy(f => f))}"); + } + } + + return GetReachableNuGetFeeds(fallbackFeeds, isFallback: true, out var _); + } + + public (HashSet explicitFeeds, HashSet allFeeds) GetAllFeeds() + { + var nugetConfigs = fileProvider.NugetConfigs; + + // Find feeds that are explicitly configured in the NuGet configuration files that we found. + var explicitFeeds = nugetConfigs + .SelectMany(GetFeedsFromNugetConfig) + .ToHashSet(); + + if (explicitFeeds.Count > 0) + { + logger.LogInfo($"Found {explicitFeeds.Count} NuGet feeds in nuget.config files: {string.Join(", ", explicitFeeds.OrderBy(f => f))}"); + } + else + { + logger.LogDebug("No NuGet feeds found in nuget.config files."); + } + + // If private package registries are configured for C#, then consider those + // in addition to the ones that are configured in `nuget.config` files. + if (HasPrivateRegistryFeeds) + { + logger.LogInfo($"Found {PrivateRegistryFeeds.Count} private registry feeds configured for C#: {string.Join(", ", PrivateRegistryFeeds.OrderBy(f => f))}"); + explicitFeeds.UnionWith(PrivateRegistryFeeds); + } + + HashSet allFeeds = []; + + // Add all explicitFeeds to the set of all feeds. + allFeeds.UnionWith(explicitFeeds); + + // Obtain the list of feeds from the root source directory. + // If a NuGet file is present it will be respected, otherwise we will just get the machine/environment specific feeds. + var nugetFeedsFromRoot = GetFeedsFromFolder(fileProvider.SourceDir.FullName); + allFeeds.UnionWith(nugetFeedsFromRoot); + + if (nugetConfigs.Count > 0) + { + var nugetConfigFeeds = nugetConfigs + .Select(GetDirectoryName) + .Where(folder => folder != null) + .SelectMany(folder => GetFeedsFromFolder(folder!)) + .ToHashSet(); + + allFeeds.UnionWith(nugetConfigFeeds); + } + + logger.LogInfo($"Found {allFeeds.Count} NuGet feeds (with inherited ones) in nuget.config files: {string.Join(", ", allFeeds.OrderBy(f => f))}"); + + return (explicitFeeds, allFeeds); + } + + [GeneratedRegex(@"^E\s(.*)$", RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.Singleline)] + private static partial Regex EnabledNugetFeed(); + + public void Dispose() + { + emptyPackageDirectory.Dispose(); + } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/NugetExeWrapper.cs b/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/NugetExeWrapper.cs deleted file mode 100644 index e97b0b118c6..00000000000 --- a/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/NugetExeWrapper.cs +++ /dev/null @@ -1,304 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; -using Semmle.Util; - -namespace Semmle.Extraction.CSharp.DependencyFetching -{ - /// - /// Manage the downloading of NuGet packages with nuget.exe. - /// Locates packages in a source tree and downloads all of the - /// referenced assemblies to a temp folder. - /// - internal class NugetExeWrapper : IDisposable - { - private readonly string? nugetExe; - private readonly Semmle.Util.Logging.ILogger logger; - - public int PackageCount => fileProvider.PackagesConfigs.Count; - - private readonly string? backupNugetConfig; - private readonly string? nugetConfigPath; - private readonly FileProvider fileProvider; - - /// - /// The packages directory. - /// This will be in the user-specified or computed Temp location - /// so as to not trample the source tree. - /// - private readonly DependencyDirectory packageDirectory; - - /// - /// Create the package manager for a specified source tree. - /// - public NugetExeWrapper(FileProvider fileProvider, DependencyDirectory packageDirectory, Semmle.Util.Logging.ILogger logger, Func useDefaultFeed) - { - this.fileProvider = fileProvider; - this.packageDirectory = packageDirectory; - this.logger = logger; - - if (fileProvider.PackagesConfigs.Count > 0) - { - logger.LogInfo($"Found packages.config files, trying to use nuget.exe for package restore"); - nugetExe = ResolveNugetExe(); - if (HasNoPackageSource() && useDefaultFeed()) - { - // We only modify or add a top level nuget.config file - nugetConfigPath = Path.Combine(fileProvider.SourceDir.FullName, "nuget.config"); - try - { - if (File.Exists(nugetConfigPath)) - { - var tempFolderPath = FileUtils.GetTemporaryWorkingDirectory(out _); - - do - { - backupNugetConfig = Path.Combine(tempFolderPath, Path.GetRandomFileName()); - } - while (File.Exists(backupNugetConfig)); - File.Copy(nugetConfigPath, backupNugetConfig, true); - } - else - { - File.WriteAllText(nugetConfigPath, - """ - - - - - - """); - } - AddDefaultPackageSource(nugetConfigPath); - } - catch (Exception e) - { - logger.LogError($"Failed to add default package source to {nugetConfigPath}: {e}"); - } - } - } - } - - /// - /// Tries to find the location of `nuget.exe`. It looks for - /// - the environment variable specifying a location, - /// - files in the repository, - /// - tries to resolve nuget from the PATH, or - /// - downloads it if it is not found. - /// - private string ResolveNugetExe() - { - var envVarPath = Environment.GetEnvironmentVariable(EnvironmentVariableNames.NugetExePath); - if (!string.IsNullOrEmpty(envVarPath)) - { - logger.LogInfo($"Using nuget.exe from environment variable: '{envVarPath}'"); - return envVarPath; - } - - try - { - return DownloadNugetExe(fileProvider.SourceDir.FullName); - } - catch (Exception exc) - { - logger.LogInfo($"Download of nuget.exe failed: {exc.Message}"); - } - - var nugetExesInRepo = fileProvider.NugetExes; - if (nugetExesInRepo.Count > 1) - { - logger.LogInfo($"Found multiple nuget.exe files in the repository: {string.Join(", ", nugetExesInRepo.OrderBy(s => s))}"); - } - - if (nugetExesInRepo.Count > 0) - { - var path = nugetExesInRepo.First(); - logger.LogInfo($"Using nuget.exe from path '{path}'"); - return path; - } - - var executableName = Win32.IsWindows() ? "nuget.exe" : "nuget"; - var nugetPath = FileUtils.FindProgramOnPath(executableName); - if (nugetPath is not null) - { - nugetPath = Path.Combine(nugetPath, executableName); - logger.LogInfo($"Using nuget.exe from PATH: {nugetPath}"); - return nugetPath; - } - - throw new Exception("Could not find or download nuget.exe."); - } - - private string DownloadNugetExe(string sourceDir) - { - var directory = Path.Combine(sourceDir, ".nuget"); - var nuget = Path.Combine(directory, "nuget.exe"); - - // Nuget.exe already exists in the .nuget directory. - if (File.Exists(nuget)) - { - logger.LogInfo($"Found nuget.exe at {nuget}"); - return nuget; - } - - Directory.CreateDirectory(directory); - logger.LogInfo("Attempting to download nuget.exe"); - FileUtils.DownloadFile(FileUtils.NugetExeUrl, nuget, logger); - logger.LogInfo($"Downloaded nuget.exe to {nuget}"); - return nuget; - } - - private bool RunWithMono => !Win32.IsWindows() && !string.IsNullOrEmpty(Path.GetExtension(nugetExe)); - - /// - /// Restore all packages in the specified packages.config file. - /// - /// The packages.config file. - private bool TryRestoreNugetPackage(string packagesConfig) - { - logger.LogInfo($"Restoring file \"{packagesConfig}\"..."); - - /* Use nuget.exe to install a package. - * Note that there is a clutch of NuGet assemblies which could be used to - * invoke this directly, which would arguably be nicer. However they are - * really unwieldy and this solution works for now. - */ - - string exe, args; - if (RunWithMono) - { - exe = "mono"; - args = $"\"{nugetExe}\" install -OutputDirectory \"{packageDirectory}\" \"{packagesConfig}\""; - } - else - { - exe = nugetExe!; - args = $"install -OutputDirectory \"{packageDirectory}\" \"{packagesConfig}\""; - } - - var pi = new ProcessStartInfo(exe, args) - { - RedirectStandardOutput = true, - RedirectStandardError = true, - UseShellExecute = false - }; - - var threadId = Environment.CurrentManagedThreadId; - void onOut(string s) => logger.LogDebug(s, threadId); - void onError(string s) => logger.LogError(s, threadId); - var exitCode = pi.ReadOutput(out _, onOut, onError); - if (exitCode != 0) - { - logger.LogError($"Command {pi.FileName} {pi.Arguments} failed with exit code {exitCode}"); - return false; - } - else - { - logger.LogInfo($"Restored file \"{packagesConfig}\""); - return true; - } - } - - /// - /// Download the packages to the temp folder. - /// - public int InstallPackages() - { - return fileProvider.PackagesConfigs.Count(TryRestoreNugetPackage); - } - - private bool HasNoPackageSource() - { - if (Win32.IsWindows()) - { - return false; - } - - try - { - logger.LogInfo("Checking if default package source is available..."); - RunMonoNugetCommand("sources list -ForceEnglishOutput", out var stdout); - if (stdout.All(line => line != "No sources found.")) - { - return false; - } - - return true; - } - catch (Exception e) - { - logger.LogWarning($"Failed to check if default package source is added: {e}"); - return false; - } - } - - private void RunMonoNugetCommand(string command, out IList stdout) - { - string exe, args; - if (RunWithMono) - { - exe = "mono"; - args = $"\"{nugetExe}\" {command}"; - } - else - { - exe = nugetExe!; - args = command; - } - - var pi = new ProcessStartInfo(exe, args) - { - RedirectStandardOutput = true, - RedirectStandardError = true, - UseShellExecute = false - }; - - var threadId = Environment.CurrentManagedThreadId; - void onOut(string s) => logger.LogDebug(s, threadId); - void onError(string s) => logger.LogError(s, threadId); - pi.ReadOutput(out stdout, onOut, onError); - } - - private void AddDefaultPackageSource(string nugetConfig) - { - logger.LogInfo("Adding default package source..."); - RunMonoNugetCommand($"sources add -Name DefaultNugetOrg -Source {NugetPackageRestorer.PublicNugetOrgFeed} -ConfigFile \"{nugetConfig}\"", out _); - } - - public void Dispose() - { - if (nugetConfigPath is null) - { - return; - } - - try - { - if (backupNugetConfig is null) - { - logger.LogInfo("Removing nuget.config file"); - File.Delete(nugetConfigPath); - return; - } - - logger.LogInfo("Reverting nuget.config file content"); - // The content of the original nuget.config file is reverted without changing the file's attributes or casing: - using (var backup = File.OpenRead(backupNugetConfig)) - using (var current = File.OpenWrite(nugetConfigPath)) - { - current.SetLength(0); // Truncate file - backup.CopyTo(current); // Restore original content - } - - logger.LogInfo("Deleting backup nuget.config file"); - File.Delete(backupNugetConfig); - } - catch (Exception exc) - { - logger.LogError($"Failed to restore original nuget.config file: {exc}"); - } - } - } -} diff --git a/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/NugetPackageRestorer.cs b/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/NugetPackageRestorer.cs index e042285af11..eb6ddd4e69b 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/NugetPackageRestorer.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/NugetPackageRestorer.cs @@ -4,9 +4,6 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.IO; using System.Linq; -using System.Net; -using System.Net.Http; -using System.Security.Cryptography.X509Certificates; using System.Text; using System.Text.RegularExpressions; using System.Threading; @@ -19,24 +16,19 @@ namespace Semmle.Extraction.CSharp.DependencyFetching { internal sealed partial class NugetPackageRestorer : IDisposable { - internal const string PublicNugetOrgFeed = "https://api.nuget.org/v3/index.json"; - private readonly FileProvider fileProvider; private readonly FileContent fileContent; private readonly IDotNet dotnet; - private readonly DependabotProxy? dependabotProxy; private readonly IDiagnosticsWriter diagnosticsWriter; private readonly DependencyDirectory legacyPackageDirectory; private readonly DependencyDirectory missingPackageDirectory; - private readonly DependencyDirectory emptyPackageDirectory; private readonly ILogger logger; private readonly ICompilationInfoContainer compilationInfoContainer; - private readonly bool checkNugetFeedResponsiveness = EnvironmentVariables.GetBooleanOptOut(EnvironmentVariableNames.CheckNugetFeedResponsiveness); - private readonly ImmutableHashSet privateRegistryFeeds; - private readonly bool hasPrivateRegistryFeeds; + private readonly FeedManager feedManager; public DependencyDirectory PackageDirectory { get; } + public NugetPackageRestorer( FileProvider fileProvider, FileContent fileContent, @@ -49,9 +41,6 @@ namespace Semmle.Extraction.CSharp.DependencyFetching this.fileProvider = fileProvider; this.fileContent = fileContent; this.dotnet = dotnet; - this.dependabotProxy = dependabotProxy; - this.privateRegistryFeeds = dependabotProxy?.RegistryURLs.ToImmutableHashSet() ?? []; - this.hasPrivateRegistryFeeds = privateRegistryFeeds.Count > 0; this.diagnosticsWriter = diagnosticsWriter; this.logger = logger; this.compilationInfoContainer = compilationInfoContainer; @@ -59,7 +48,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching PackageDirectory = new DependencyDirectory("packages", "package", logger); legacyPackageDirectory = new DependencyDirectory("legacypackages", "legacy package", logger); missingPackageDirectory = new DependencyDirectory("missingpackages", "missing package", logger); - emptyPackageDirectory = new DependencyDirectory("empty", "empty package", logger); + feedManager = new FeedManager(logger, dotnet, dependabotProxy, fileProvider); } public string? TryRestore(string package) @@ -118,20 +107,22 @@ namespace Semmle.Extraction.CSharp.DependencyFetching public HashSet Restore() { var assemblyLookupLocations = new HashSet(); - logger.LogInfo($"Checking NuGet feed responsiveness: {checkNugetFeedResponsiveness}"); - compilationInfoContainer.CompilationInfos.Add(("NuGet feed responsiveness checked", checkNugetFeedResponsiveness ? "1" : "0")); + logger.LogInfo($"Checking NuGet feed responsiveness: {feedManager.CheckNugetFeedResponsiveness}"); + compilationInfoContainer.CompilationInfos.Add(("NuGet feed responsiveness checked", feedManager.CheckNugetFeedResponsiveness ? "1" : "0")); HashSet explicitFeeds = []; HashSet reachableFeeds = []; try { + EmitNugetConfigDiagnostics(); + // Find feeds that are configured in NuGet.config files and divide them into ones that // are explicitly configured for the project or by a private registry, and "all feeds" // (including inherited ones) from other locations on the host outside of the working directory. - (explicitFeeds, var allFeeds) = GetAllFeeds(); + (explicitFeeds, var allFeeds) = feedManager.GetAllFeeds(); - if (checkNugetFeedResponsiveness) + if (feedManager.CheckNugetFeedResponsiveness) { var inheritedFeeds = allFeeds.Except(explicitFeeds).ToHashSet(); @@ -140,7 +131,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching compilationInfoContainer.CompilationInfos.Add(("Inherited NuGet feed count", inheritedFeeds.Count.ToString())); } - var timeout = CheckSpecifiedFeeds(explicitFeeds, out var reachableExplicitFeeds); + var timeout = feedManager.CheckSpecifiedFeeds(explicitFeeds, out var reachableExplicitFeeds); reachableFeeds.UnionWith(reachableExplicitFeeds); var allExplicitReachable = explicitFeeds.Count == reachableExplicitFeeds.Count; @@ -157,17 +148,17 @@ namespace Semmle.Extraction.CSharp.DependencyFetching } // Inherited feeds should only be used, if they are indeed reachable (as they may be environment specific). - CheckSpecifiedFeeds(inheritedFeeds, out var reachableInheritedFeeds); + feedManager.CheckSpecifiedFeeds(inheritedFeeds, out var reachableInheritedFeeds); reachableFeeds.UnionWith(reachableInheritedFeeds); } - using (var nuget = new NugetExeWrapper(fileProvider, legacyPackageDirectory, logger, IsDefaultFeedReachable)) + using (var packagesConfigRestore = PackagesConfigRestoreFactory.Create(fileProvider, legacyPackageDirectory, logger, feedManager.IsDefaultFeedReachable)) { - var count = nuget.InstallPackages(); + var count = packagesConfigRestore.InstallPackages(); - if (nuget.PackageCount > 0) + if (packagesConfigRestore.PackageCount > 0) { - compilationInfoContainer.CompilationInfos.Add(("packages.config files", nuget.PackageCount.ToString())); + compilationInfoContainer.CompilationInfos.Add(("packages.config files", packagesConfigRestore.PackageCount.ToString())); compilationInfoContainer.CompilationInfos.Add(("Successfully restored packages.config files", count.ToString())); } } @@ -209,13 +200,13 @@ namespace Semmle.Extraction.CSharp.DependencyFetching var paths = dependencies .Paths - .Select(d => Path.Combine(PackageDirectory.DirInfo.FullName, d)) + .Select(d => Path.Join(PackageDirectory.DirInfo.FullName, d)) .ToList(); assemblyLookupLocations.UnionWith(paths.Select(p => new AssemblyLookupLocation(p))); var usedPackageNames = GetAllUsedPackageDirNames(dependencies); - var missingPackageLocation = checkNugetFeedResponsiveness + var missingPackageLocation = feedManager.CheckNugetFeedResponsiveness ? DownloadMissingPackagesFromSpecificFeeds(usedPackageNames, explicitFeeds) : DownloadMissingPackages(usedPackageNames); @@ -226,79 +217,6 @@ namespace Semmle.Extraction.CSharp.DependencyFetching return assemblyLookupLocations; } - /// - /// Tests which of the feeds given by are reachable. - /// - /// The feeds to check. - /// Whether the feeds are fallback feeds or not. - /// Whether a timeout occurred while checking the feeds. - /// The list of feeds that could be reached. - private List GetReachableNuGetFeeds(HashSet feedsToCheck, bool isFallback, out bool isTimeout) - { - var fallbackStr = isFallback ? "fallback " : ""; - logger.LogInfo($"Checking {fallbackStr}NuGet feed reachability on feeds: {string.Join(", ", feedsToCheck.OrderBy(f => f))}"); - - var (initialTimeout, tryCount) = GetFeedRequestSettings(isFallback); - var timeout = false; - var reachableFeeds = feedsToCheck - .Where(feed => - { - var reachable = IsFeedReachable(feed, initialTimeout, tryCount, out var feedTimeout); - timeout |= feedTimeout; - return reachable; - }) - .ToList(); - - if (reachableFeeds.Count == 0) - { - logger.LogWarning($"No {fallbackStr}NuGet feeds are reachable."); - } - else - { - logger.LogInfo($"Reachable {fallbackStr}NuGet feeds: {string.Join(", ", reachableFeeds.OrderBy(f => f))}"); - } - - isTimeout = timeout; - return reachableFeeds; - } - - private bool IsDefaultFeedReachable() - { - if (checkNugetFeedResponsiveness) - { - var (initialTimeout, tryCount) = GetFeedRequestSettings(isFallback: false); - return IsFeedReachable(PublicNugetOrgFeed, initialTimeout, tryCount, out var _); - } - - return true; - } - - private List GetReachableFallbackNugetFeeds(HashSet? feedsFromNugetConfigs) - { - var fallbackFeeds = EnvironmentVariables.GetURLs(EnvironmentVariableNames.FallbackNugetFeeds).ToHashSet(); - if (fallbackFeeds.Count == 0) - { - fallbackFeeds.Add(PublicNugetOrgFeed); - logger.LogInfo($"No fallback NuGet feeds specified. Adding default feed: {PublicNugetOrgFeed}"); - - var shouldAddNugetConfigFeeds = EnvironmentVariables.GetBooleanOptOut(EnvironmentVariableNames.AddNugetConfigFeedsToFallback); - logger.LogInfo($"Adding feeds from nuget.config to fallback restore: {shouldAddNugetConfigFeeds}"); - - if (shouldAddNugetConfigFeeds && feedsFromNugetConfigs?.Count > 0) - { - // There are some feeds in `feedsFromNugetConfigs` that have already been checked for reachability, we could skip those. - // But we might use different responsiveness testing settings when we try them in the fallback logic, so checking them again is safer. - fallbackFeeds.UnionWith(feedsFromNugetConfigs); - logger.LogInfo($"Using NuGet feeds from nuget.config files as fallback feeds: {string.Join(", ", feedsFromNugetConfigs.OrderBy(f => f))}"); - } - } - - var reachableFallbackFeeds = GetReachableNuGetFeeds(fallbackFeeds, isFallback: true, out var _); - - compilationInfoContainer.CompilationInfos.Add(("Reachable fallback NuGet feed count", reachableFallbackFeeds.Count.ToString())); - - return reachableFallbackFeeds; - } /// /// Executes `dotnet restore` on all solution files in solutions. @@ -321,7 +239,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching var projects = fileProvider.Solutions.SelectMany(solution => { logger.LogInfo($"Restoring solution {solution}..."); - var nugetSources = MakeRestoreSourcesArgument(solution, reachableFeeds); + var nugetSources = feedManager.MakeRestoreSourcesArgument(solution, reachableFeeds); var res = dotnet.Restore(new(solution, PackageDirectory.DirInfo.FullName, ForceDotnetRefAssemblyFetching: true, NugetSources: nugetSources, TargetWindows: isWindows)); if (res.Success) { @@ -346,57 +264,6 @@ namespace Semmle.Extraction.CSharp.DependencyFetching return projects; } - private string FeedsToRestoreArgument(IEnumerable feeds) - { - // If there are no feeds, we want to override any default feeds that `dotnet restore` would use by passing a dummy source argument. - if (!feeds.Any()) - { - return $" -s \"{emptyPackageDirectory.DirInfo.FullName}\""; - } - - // Add package sources. If any are present, they override all sources specified in - // the configuration file(s). - var feedArgs = new StringBuilder(); - foreach (var feed in feeds) - { - feedArgs.Append($" -s \"{feed}\""); - } - - return feedArgs.ToString(); - } - - /// - /// Constructs the list of NuGet sources to use for this restore. - /// (1) Use the feeds we get from `dotnet nuget list source` - /// (2) Use private registries, if they are configured - /// - /// Path to project/solution - /// The set of reachable NuGet feeds. - /// A string representing the NuGet sources argument for the restore command. - private string? MakeRestoreSourcesArgument(string path, HashSet reachableFeeds) - { - // Do not construct an set of explicit NuGet sources to use for restore. - if (!checkNugetFeedResponsiveness && !hasPrivateRegistryFeeds) - { - return null; - } - - // Find the path specific feeds. - var folder = GetDirectoryName(path); - var feedsToConsider = folder is not null ? GetFeeds(() => dotnet.GetNugetFeedsFromFolder(folder)).ToHashSet() : []; - - if (hasPrivateRegistryFeeds) - { - feedsToConsider.UnionWith(privateRegistryFeeds); - } - - var feedsToUse = checkNugetFeedResponsiveness - ? feedsToConsider.Where(reachableFeeds.Contains) - : feedsToConsider; - - return FeedsToRestoreArgument(feedsToUse); - } - /// /// Executes `dotnet restore` on all projects in projects. /// This is done in parallel for performance reasons. @@ -421,7 +288,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching foreach (var project in projectGroup) { logger.LogInfo($"Restoring project {project}..."); - var nugetSources = MakeRestoreSourcesArgument(project, reachableFeeds); + var nugetSources = feedManager.MakeRestoreSourcesArgument(project, reachableFeeds); var res = dotnet.Restore(new(project, PackageDirectory.DirInfo.FullName, ForceDotnetRefAssemblyFetching: true, NugetSources: nugetSources, TargetWindows: isWindows)); assets.AddDependenciesRange(res.AssetsFilePaths); lock (sync) @@ -450,7 +317,9 @@ namespace Semmle.Extraction.CSharp.DependencyFetching private AssemblyLookupLocation? DownloadMissingPackagesFromSpecificFeeds(IEnumerable usedPackageNames, HashSet? feedsFromNugetConfigs) { - var reachableFallbackFeeds = GetReachableFallbackNugetFeeds(feedsFromNugetConfigs); + var reachableFallbackFeeds = feedManager.GetReachableFallbackNugetFeeds(feedsFromNugetConfigs); + compilationInfoContainer.CompilationInfos.Add(("Reachable fallback NuGet feed count", reachableFallbackFeeds.Count.ToString())); + if (reachableFallbackFeeds.Count > 0) { return DownloadMissingPackages(usedPackageNames, fallbackNugetFeeds: reachableFallbackFeeds); @@ -527,7 +396,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching var sb = new StringBuilder(); fallbackNugetFeeds.ForEach((feed, index) => sb.AppendLine($"")); - var nugetConfigPath = Path.Combine(folderPath, "nuget.config"); + var nugetConfigPath = Path.Join(folderPath, "nuget.config"); logger.LogInfo($"Creating fallback nuget.config file {nugetConfigPath}."); File.WriteAllText(nugetConfigPath, $""" @@ -736,147 +605,6 @@ namespace Semmle.Extraction.CSharp.DependencyFetching } } - private static async Task ExecuteGetRequest(string address, HttpClient httpClient, CancellationToken cancellationToken) - { - return await httpClient.GetAsync(address, HttpCompletionOption.ResponseHeadersRead, cancellationToken); - } - - private bool IsFeedReachable(string feed, int timeoutMilliSeconds, int tryCount, out bool isTimeout) - { - logger.LogInfo($"Checking if NuGet feed '{feed}' is reachable..."); - - // Configure the HttpClient to be aware of the Dependabot Proxy, if used. - HttpClientHandler httpClientHandler = new(); - if (dependabotProxy != null) - { - httpClientHandler.Proxy = new WebProxy(dependabotProxy.Address); - - if (dependabotProxy.Certificate != null) - { - httpClientHandler.ServerCertificateCustomValidationCallback = (message, cert, chain, _) => - { - if (chain is null || cert is null) - { - var msg = cert is null && chain is null - ? "certificate and chain" - : chain is null - ? "chain" - : "certificate"; - logger.LogWarning($"Dependabot proxy certificate validation failed due to missing {msg}"); - return false; - } - chain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust; - chain.ChainPolicy.CustomTrustStore.Add(dependabotProxy.Certificate); - return chain.Build(cert); - }; - } - } - - using HttpClient client = new(httpClientHandler); - - isTimeout = false; - - for (var i = 0; i < tryCount; i++) - { - using var cts = new CancellationTokenSource(); - cts.CancelAfter(timeoutMilliSeconds); - try - { - logger.LogInfo($"Attempt {i + 1}/{tryCount} to reach NuGet feed '{feed}'."); - using var response = ExecuteGetRequest(feed, client, cts.Token).GetAwaiter().GetResult(); - response.EnsureSuccessStatusCode(); - logger.LogInfo($"Querying NuGet feed '{feed}' succeeded."); - return true; - } - catch (Exception exc) - { - if (exc is TaskCanceledException tce && - tce.CancellationToken == cts.Token && - cts.Token.IsCancellationRequested) - { - logger.LogInfo($"Didn't receive answer from NuGet feed '{feed}' in {timeoutMilliSeconds}ms."); - timeoutMilliSeconds *= 2; - continue; - } - - logger.LogInfo($"Querying NuGet feed '{feed}' failed. The reason for the failure: {exc.Message}"); - return false; - } - } - - logger.LogWarning($"Didn't receive answer from NuGet feed '{feed}'. Tried it {tryCount} times."); - isTimeout = true; - return false; - } - - private (int initialTimeout, int tryCount) GetFeedRequestSettings(bool isFallback) - { - int timeoutMilliSeconds = isFallback && int.TryParse(Environment.GetEnvironmentVariable(EnvironmentVariableNames.NugetFeedResponsivenessInitialTimeoutForFallback), out timeoutMilliSeconds) - ? timeoutMilliSeconds - : int.TryParse(Environment.GetEnvironmentVariable(EnvironmentVariableNames.NugetFeedResponsivenessInitialTimeout), out timeoutMilliSeconds) - ? timeoutMilliSeconds - : 1000; - logger.LogDebug($"Initial timeout for NuGet feed reachability check is {timeoutMilliSeconds}ms."); - - int tryCount = isFallback && int.TryParse(Environment.GetEnvironmentVariable(EnvironmentVariableNames.NugetFeedResponsivenessRequestCountForFallback), out tryCount) - ? tryCount - : int.TryParse(Environment.GetEnvironmentVariable(EnvironmentVariableNames.NugetFeedResponsivenessRequestCount), out tryCount) - ? tryCount - : 4; - logger.LogDebug($"Number of tries for NuGet feed reachability check is {tryCount}."); - - return (timeoutMilliSeconds, tryCount); - } - - /// - /// Retrieves a list of excluded NuGet feeds from the corresponding environment variable. - /// - private HashSet GetExcludedFeeds() - { - var excludedFeeds = EnvironmentVariables.GetURLs(EnvironmentVariableNames.ExcludedNugetFeedsFromResponsivenessCheck) - .ToHashSet(); - - if (excludedFeeds.Count > 0) - { - logger.LogInfo($"Excluded NuGet feeds from responsiveness check: {string.Join(", ", excludedFeeds.OrderBy(f => f))}"); - } - - return excludedFeeds; - } - - /// - /// Checks that we can connect to the specified NuGet feeds. - /// - /// The set of package feeds to check. - /// The list of feeds that were reachable. - /// - /// True if there is a timeout when trying to reach the feeds (excluding any feeds that are configured - /// to be excluded from the check) or false otherwise. - /// - private bool CheckSpecifiedFeeds(HashSet feeds, out HashSet reachableFeeds) - { - // Exclude any feeds from the feed check that are configured by the corresponding environment variable. - // These feeds are always assumed to be reachable. - var excludedFeeds = GetExcludedFeeds(); - - HashSet feedsToCheck = feeds.Where(feed => - { - if (excludedFeeds.Contains(feed)) - { - logger.LogInfo($"Not checking reachability of NuGet feed '{feed}' as it is in the list of excluded feeds."); - return false; - } - return true; - }).ToHashSet(); - - reachableFeeds = GetReachableNuGetFeeds(feedsToCheck, isFallback: false, out var isTimeout).ToHashSet(); - - // Always consider feeds excluded for the reachability check as reachable. - reachableFeeds.UnionWith(feeds.Where(feed => excludedFeeds.Contains(feed))); - - return isTimeout; - } - /// /// If is `false`, logs this and emits a diagnostic. /// Adds a `CompilationInfos` entry either way. @@ -899,56 +627,15 @@ namespace Semmle.Extraction.CSharp.DependencyFetching compilationInfoContainer.CompilationInfos.Add(("All NuGet feeds reachable", allFeedsReachable ? "1" : "0")); } - private IEnumerable GetFeeds(Func> getNugetFeeds) + private void EmitNugetConfigDiagnostics() { - var results = getNugetFeeds(); - var regex = EnabledNugetFeed(); - foreach (var result in results) - { - var match = regex.Match(result); - if (!match.Success) - { - logger.LogError($"Failed to parse feed from '{result}'"); - continue; - } - - var url = match.Groups[1].Value; - if (!url.StartsWith("https://", StringComparison.InvariantCultureIgnoreCase) && - !url.StartsWith("http://", StringComparison.InvariantCultureIgnoreCase)) - { - logger.LogInfo($"Skipping feed '{url}' as it is not a valid URL."); - continue; - } - - if (!string.IsNullOrWhiteSpace(url)) - { - yield return url; - } - } - } - - private string? GetDirectoryName(string path) - { - try - { - return new FileInfo(path).Directory?.FullName; - } - catch (Exception exc) - { - logger.LogWarning($"Failed to get directory of '{path}': {exc}"); - } - return null; - } - - private (HashSet explicitFeeds, HashSet allFeeds) GetAllFeeds() - { - var nugetConfigs = fileProvider.NugetConfigs; - // On systems with case-sensitive file systems (for simplicity, we assume that is Linux), the // filenames of NuGet configuration files must be named correctly. For compatibility with projects // that are typically built on Windows or macOS where this doesn't matter, we accept all variants // of `nuget.config` ourselves. However, `dotnet` does not. If we detect that incorrectly-named // files are present, we emit a diagnostic to warn the user. + var nugetConfigs = fileProvider.NugetConfigs; + if (SystemBuildActions.Instance.IsLinux()) { string[] acceptedNugetConfigNames = ["nuget.config", "NuGet.config", "NuGet.Config"]; @@ -978,53 +665,6 @@ namespace Semmle.Extraction.CSharp.DependencyFetching )); } } - - // Find feeds that are explicitly configured in the NuGet configuration files that we found. - var explicitFeeds = nugetConfigs - .SelectMany(config => GetFeeds(() => dotnet.GetNugetFeeds(config))) - .ToHashSet(); - - if (explicitFeeds.Count > 0) - { - logger.LogInfo($"Found {explicitFeeds.Count} NuGet feeds in nuget.config files: {string.Join(", ", explicitFeeds.OrderBy(f => f))}"); - } - else - { - logger.LogDebug("No NuGet feeds found in nuget.config files."); - } - - // If private package registries are configured for C#, then consider those - // in addition to the ones that are configured in `nuget.config` files. - if (hasPrivateRegistryFeeds) - { - logger.LogInfo($"Found {privateRegistryFeeds.Count} private registry feeds configured for C#: {string.Join(", ", privateRegistryFeeds.OrderBy(f => f))}"); - explicitFeeds.UnionWith(privateRegistryFeeds); - } - - HashSet allFeeds = []; - - // Add all explicitFeeds to the set of all feeds. - allFeeds.UnionWith(explicitFeeds); - - // Obtain the list of feeds from the root source directory. - // If a NuGet file is present it will be respected, otherwise we will just get the machine/environment specific feeds. - var nugetFeedsFromRoot = GetFeeds(() => dotnet.GetNugetFeedsFromFolder(fileProvider.SourceDir.FullName)); - allFeeds.UnionWith(nugetFeedsFromRoot); - - if (nugetConfigs.Count > 0) - { - var nugetConfigFeeds = nugetConfigs - .Select(GetDirectoryName) - .Where(folder => folder != null) - .SelectMany(folder => GetFeeds(() => dotnet.GetNugetFeedsFromFolder(folder!))) - .ToHashSet(); - - allFeeds.UnionWith(nugetConfigFeeds); - } - - logger.LogInfo($"Found {allFeeds.Count} NuGet feeds (with inherited ones) in nuget.config files: {string.Join(", ", allFeeds.OrderBy(f => f))}"); - - return (explicitFeeds, allFeeds); } [GeneratedRegex(@".*", RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.Singleline)] @@ -1036,15 +676,12 @@ namespace Semmle.Extraction.CSharp.DependencyFetching [GeneratedRegex(@"^(.+)\.(\d+\.\d+\.\d+(-(.+))?)$", RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.Singleline)] private static partial Regex LegacyNugetPackage(); - [GeneratedRegex(@"^E\s(.*)$", RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.Singleline)] - private static partial Regex EnabledNugetFeed(); - public void Dispose() { PackageDirectory?.Dispose(); legacyPackageDirectory?.Dispose(); missingPackageDirectory?.Dispose(); - emptyPackageDirectory?.Dispose(); + feedManager.Dispose(); } /// @@ -1052,7 +689,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching /// private static string ComputeTempDirectoryPath(string subfolderName) { - return Path.Combine(FileUtils.GetTemporaryWorkingDirectory(out _), subfolderName); + return Path.Join(FileUtils.GetTemporaryWorkingDirectory(out _), subfolderName); } /// @@ -1060,7 +697,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching /// private static string ComputeTempDirectoryPath(string srcDir, string subfolderName) { - return Path.Combine(FileUtils.GetTemporaryWorkingDirectory(out _), FileUtils.ComputeHash(srcDir), subfolderName); + return Path.Join(FileUtils.GetTemporaryWorkingDirectory(out _), FileUtils.ComputeHash(srcDir), subfolderName); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/PackagesConfigRestorer.cs b/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/PackagesConfigRestorer.cs new file mode 100644 index 00000000000..51cd2755578 --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/PackagesConfigRestorer.cs @@ -0,0 +1,368 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using Semmle.Util; + +namespace Semmle.Extraction.CSharp.DependencyFetching +{ + internal interface IPackagesConfigRestore : IDisposable + { + /// + /// The number of packages.config files found in the source tree. + /// + int PackageCount { get; } + + /// + /// Download the packages to the temp folder. + /// + int InstallPackages(); + } + + /// + /// Factory for creating a package manager to restore NuGet packages referenced in packages.config files. + /// If the environment doesn't support using nuget.exe to restore packages from packages.config files, a no-op implementation is returned. + /// It is worth noting that for macOS and Linux, nuget.exe is used with mono. However, mono is being deprecated and the last GitHub images + /// to contain mono are: + /// - Ubuntu 22.04 + /// - macOS 14 + /// + /// If the packages from the packages.config files are not restored with the packages.config restore functionality below, there is a subsequent + /// step that still may succeed in restoring the packages without the help of nuget.exe (by attempting to restore using dotnet). + /// + internal class PackagesConfigRestoreFactory + { + public static IPackagesConfigRestore Create(FileProvider fileProvider, DependencyDirectory packageDirectory, Semmle.Util.Logging.ILogger logger, Func useDefaultFeed) + { + if (SystemBuildActions.Instance.IsWindows() || SystemBuildActions.Instance.IsMonoInstalled()) + { + return new NugetExeWrapper(fileProvider, packageDirectory, logger, useDefaultFeed); + } + + return new NoOpPackagesConfig(fileProvider.PackagesConfigs, logger); + } + + /// + /// Manage the downloading of NuGet packages with nuget.exe. + /// Locates packages in a source tree and downloads all of the + /// referenced assemblies to a temp folder. + /// + private class NugetExeWrapper : IPackagesConfigRestore + { + private readonly string? nugetExe; + private readonly Semmle.Util.Logging.ILogger logger; + + public int PackageCount => fileProvider.PackagesConfigs.Count; + + private readonly string? backupNugetConfig; + private readonly string? nugetConfigPath; + private readonly FileProvider fileProvider; + + /// + /// The packages directory. + /// This will be in the user-specified or computed Temp location + /// so as to not trample the source tree. + /// + private readonly DependencyDirectory packageDirectory; + + private bool IsWindows => SystemBuildActions.Instance.IsWindows(); + + /// + /// Create the package manager for a specified source tree. + /// + public NugetExeWrapper(FileProvider fileProvider, DependencyDirectory packageDirectory, Semmle.Util.Logging.ILogger logger, Func useDefaultFeed) + { + this.fileProvider = fileProvider; + this.packageDirectory = packageDirectory; + this.logger = logger; + + if (fileProvider.PackagesConfigs.Count > 0) + { + logger.LogInfo($"Found packages.config files, trying to use nuget.exe for package restore"); + nugetExe = ResolveNugetExe(); + if (!HasPackageSource() && useDefaultFeed()) + { + // We only modify or add a top level nuget.config file + nugetConfigPath = Path.Join(fileProvider.SourceDir.FullName, "nuget.config"); + try + { + if (File.Exists(nugetConfigPath)) + { + var tempFolderPath = FileUtils.GetTemporaryWorkingDirectory(out _); + + do + { + backupNugetConfig = Path.Join(tempFolderPath, Path.GetRandomFileName()); + } + while (File.Exists(backupNugetConfig)); + File.Copy(nugetConfigPath, backupNugetConfig, true); + } + else + { + File.WriteAllText(nugetConfigPath, + """ + + + + + + """); + } + AddDefaultPackageSource(nugetConfigPath); + } + catch (Exception e) + { + logger.LogError($"Failed to add default package source to {nugetConfigPath}: {e}"); + } + } + } + } + + /// + /// Tries to find the location of `nuget.exe`. It looks for + /// - the environment variable specifying a location, + /// - files in the repository, + /// - tries to resolve nuget from the PATH, or + /// - downloads it if it is not found. + /// + private string ResolveNugetExe() + { + var envVarPath = Environment.GetEnvironmentVariable(EnvironmentVariableNames.NugetExePath); + if (!string.IsNullOrEmpty(envVarPath)) + { + logger.LogInfo($"Using nuget.exe from environment variable: '{envVarPath}'"); + return envVarPath; + } + + try + { + return DownloadNugetExe(fileProvider.SourceDir.FullName); + } + catch (Exception exc) + { + logger.LogInfo($"Download of nuget.exe failed: {exc.Message}"); + } + + var nugetExesInRepo = fileProvider.NugetExes; + if (nugetExesInRepo.Count > 1) + { + logger.LogInfo($"Found multiple nuget.exe files in the repository: {string.Join(", ", nugetExesInRepo.OrderBy(s => s))}"); + } + + if (nugetExesInRepo.Count > 0) + { + var path = nugetExesInRepo.First(); + logger.LogInfo($"Using nuget.exe from path '{path}'"); + return path; + } + + var executableName = IsWindows ? "nuget.exe" : "nuget"; + var nugetPath = FileUtils.FindProgramOnPath(executableName); + if (nugetPath is not null) + { + nugetPath = Path.Join(nugetPath, executableName); + logger.LogInfo($"Using nuget.exe from PATH: {nugetPath}"); + return nugetPath; + } + + throw new Exception("Could not find or download nuget.exe."); + } + + private string DownloadNugetExe(string sourceDir) + { + var directory = Path.Join(sourceDir, ".nuget"); + var nuget = Path.Join(directory, "nuget.exe"); + + // Nuget.exe already exists in the .nuget directory. + if (File.Exists(nuget)) + { + logger.LogInfo($"Found nuget.exe at {nuget}"); + return nuget; + } + + Directory.CreateDirectory(directory); + logger.LogInfo("Attempting to download nuget.exe"); + FileUtils.DownloadFile(FileUtils.NugetExeUrl, nuget, logger); + logger.LogInfo($"Downloaded nuget.exe to {nuget}"); + return nuget; + } + + private bool RunWithMono => !IsWindows && !string.IsNullOrEmpty(Path.GetExtension(nugetExe)); + + /// + /// Restore all packages in the specified packages.config file. + /// + /// The packages.config file. + private bool TryRestoreNugetPackage(string packagesConfig) + { + logger.LogInfo($"Restoring file \"{packagesConfig}\"..."); + + /* Use nuget.exe to install a package. + * Note that there is a clutch of NuGet assemblies which could be used to + * invoke this directly, which would arguably be nicer. However they are + * really unwieldy and this solution works for now. + */ + + string exe, args; + if (RunWithMono) + { + exe = "mono"; + args = $"\"{nugetExe}\" install -OutputDirectory \"{packageDirectory}\" \"{packagesConfig}\""; + } + else + { + exe = nugetExe!; + args = $"install -OutputDirectory \"{packageDirectory}\" \"{packagesConfig}\""; + } + + var pi = new ProcessStartInfo(exe, args) + { + RedirectStandardOutput = true, + RedirectStandardError = true, + UseShellExecute = false + }; + + var threadId = Environment.CurrentManagedThreadId; + void onOut(string s) => logger.LogDebug(s, threadId); + void onError(string s) => logger.LogError(s, threadId); + var exitCode = pi.ReadOutput(out _, onOut, onError); + if (exitCode != 0) + { + logger.LogError($"Command {pi.FileName} {pi.Arguments} failed with exit code {exitCode}"); + return false; + } + else + { + logger.LogInfo($"Restored file \"{packagesConfig}\""); + return true; + } + } + + /// + /// Download the packages to the temp folder. + /// + public int InstallPackages() + { + return fileProvider.PackagesConfigs.Count(TryRestoreNugetPackage); + } + + private bool HasPackageSource() + { + if (IsWindows) + { + return true; + } + + try + { + logger.LogInfo("Checking if default package source is available..."); + RunMonoNugetCommand("sources list -ForceEnglishOutput", out var stdout); + if (stdout.All(line => line != "No sources found.")) + { + return true; + } + + return false; + } + catch (Exception e) + { + logger.LogWarning($"Failed to check if default package source is added: {e}"); + return true; + } + } + + private void RunMonoNugetCommand(string command, out IList stdout) + { + string exe, args; + if (RunWithMono) + { + exe = "mono"; + args = $"\"{nugetExe}\" {command}"; + } + else + { + exe = nugetExe!; + args = command; + } + + var pi = new ProcessStartInfo(exe, args) + { + RedirectStandardOutput = true, + RedirectStandardError = true, + UseShellExecute = false + }; + + var threadId = Environment.CurrentManagedThreadId; + void onOut(string s) => logger.LogDebug(s, threadId); + void onError(string s) => logger.LogError(s, threadId); + pi.ReadOutput(out stdout, onOut, onError); + } + + private void AddDefaultPackageSource(string nugetConfig) + { + logger.LogInfo("Adding default package source..."); + RunMonoNugetCommand($"sources add -Name DefaultNugetOrg -Source {FeedManager.PublicNugetOrgFeed} -ConfigFile \"{nugetConfig}\"", out _); + } + + public void Dispose() + { + if (nugetConfigPath is null) + { + return; + } + + try + { + if (backupNugetConfig is null) + { + logger.LogInfo("Removing nuget.config file"); + File.Delete(nugetConfigPath); + return; + } + + logger.LogInfo("Reverting nuget.config file content"); + // The content of the original nuget.config file is reverted without changing the file's attributes or casing: + using (var backup = File.OpenRead(backupNugetConfig)) + using (var current = File.OpenWrite(nugetConfigPath)) + { + current.SetLength(0); // Truncate file + backup.CopyTo(current); // Restore original content + } + + logger.LogInfo("Deleting backup nuget.config file"); + File.Delete(backupNugetConfig); + } + catch (Exception exc) + { + logger.LogError($"Failed to restore original nuget.config file: {exc}"); + } + } + } + + private class NoOpPackagesConfig : IPackagesConfigRestore + { + private readonly Semmle.Util.Logging.ILogger logger; + private readonly ICollection packagesConfigs; + + public NoOpPackagesConfig(ICollection packagesConfigs, Semmle.Util.Logging.ILogger logger) + { + this.packagesConfigs = packagesConfigs; + this.logger = logger; + } + + public int PackageCount => packagesConfigs.Count; + + public int InstallPackages() + { + if (PackageCount > 0) + { + logger.LogInfo("Found packages.config files, but nuget.exe cannot be used to restore packages on this platform. Skipping restore of packages.config files."); + } + return 0; + } + + public void Dispose() { } + } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/Runtime.cs b/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/Runtime.cs index 64c835d27fc..0ed2713b6f9 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/Runtime.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/Runtime.cs @@ -79,7 +79,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching var monoPath = FileUtils.FindProgramOnPath(Win32.IsWindows() ? "mono.exe" : "mono"); string[] monoDirs = monoPath is not null - ? [Path.GetFullPath(Path.Combine(monoPath, "..", "lib", "mono")), monoPath] + ? [Path.GetFullPath(Path.Join(monoPath, "..", "lib", "mono")), monoPath] : ["/usr/lib/mono", "/usr/local/mono", "/usr/local/bin/mono", @"C:\Program Files\Mono\lib\mono"]; var monoDir = monoDirs.FirstOrDefault(Directory.Exists); diff --git a/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/Sdk.cs b/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/Sdk.cs index c4d1ba9ac08..20e188e625a 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/Sdk.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/Sdk.cs @@ -63,7 +63,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching return null; } - var path = Path.Combine(version.FullPath, "Roslyn", "bincore", "csc.dll"); + var path = Path.Join(version.FullPath, "Roslyn", "bincore", "csc.dll"); logger.LogDebug($"Source generator CSC: '{path}'"); if (!File.Exists(path)) { diff --git a/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/SourceGenerators/DotnetSourceGeneratorWrapper/DotnetSourceGeneratorWrapper.cs b/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/SourceGenerators/DotnetSourceGeneratorWrapper/DotnetSourceGeneratorWrapper.cs index 68080244901..9518afac400 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/SourceGenerators/DotnetSourceGeneratorWrapper/DotnetSourceGeneratorWrapper.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/SourceGenerators/DotnetSourceGeneratorWrapper/DotnetSourceGeneratorWrapper.cs @@ -41,10 +41,10 @@ namespace Semmle.Extraction.CSharp.DependencyFetching .Replace('\\', '/'); // Ensure we're generating the same hash regardless of the OS var name = FileUtils.ComputeHash($"{relativePathToCsProj}\n{this.GetType().Name}"); using var tempDir = new TemporaryDirectory(Path.Join(FileUtils.GetTemporaryWorkingDirectory(out _), "source-generator"), "source generator temporary", logger); - var analyzerConfigPath = Path.Combine(tempDir.DirInfo.FullName, $"{name}.txt"); - var dllPath = Path.Combine(tempDir.DirInfo.FullName, $"{name}.dll"); - var cscArgsPath = Path.Combine(tempDir.DirInfo.FullName, $"{name}.rsp"); - var outputFolder = Path.Combine(targetDir, name); + var analyzerConfigPath = Path.Join(tempDir.DirInfo.FullName, $"{name}.txt"); + var dllPath = Path.Join(tempDir.DirInfo.FullName, $"{name}.dll"); + var cscArgsPath = Path.Join(tempDir.DirInfo.FullName, $"{name}.rsp"); + var outputFolder = Path.Join(targetDir, name); Directory.CreateDirectory(outputFolder); logger.LogInfo("Producing analyzer config content."); GenerateAnalyzerConfig(additionalFiles, csprojFile, analyzerConfigPath); diff --git a/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/SourceGenerators/DotnetSourceGeneratorWrapper/Razor.cs b/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/SourceGenerators/DotnetSourceGeneratorWrapper/Razor.cs index 24423e6a129..fa509bb50b8 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/SourceGenerators/DotnetSourceGeneratorWrapper/Razor.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/SourceGenerators/DotnetSourceGeneratorWrapper/Razor.cs @@ -21,7 +21,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching throw new Exception("No SDK path available."); } - SourceGeneratorFolder = Path.Combine(sdkPath, "Sdks", "Microsoft.NET.Sdk.Razor", "source-generators"); + SourceGeneratorFolder = Path.Join(sdkPath, "Sdks", "Microsoft.NET.Sdk.Razor", "source-generators"); this.logger.LogInfo($"Razor source generator folder: {SourceGeneratorFolder}"); if (!Directory.Exists(SourceGeneratorFolder)) { diff --git a/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/SourceGenerators/ImplicitUsingsGenerator.cs b/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/SourceGenerators/ImplicitUsingsGenerator.cs index f3bcdae3ac6..4d169b8c9f4 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/SourceGenerators/ImplicitUsingsGenerator.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/SourceGenerators/ImplicitUsingsGenerator.cs @@ -50,7 +50,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching if (usings.Count > 0) { var tempDir = GetTemporaryWorkingDirectory("implicitUsings"); - var path = Path.Combine(tempDir, "GlobalUsings.g.cs"); + var path = Path.Join(tempDir, "GlobalUsings.g.cs"); using (var writer = new StreamWriter(path)) { writer.WriteLine("// "); diff --git a/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/SourceGenerators/ResxGenerator.cs b/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/SourceGenerators/ResxGenerator.cs index ff24bf0ea6f..da66ef27544 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/SourceGenerators/ResxGenerator.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/SourceGenerators/ResxGenerator.cs @@ -32,7 +32,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching var nugetFolder = nugetPackageRestorer.TryRestore("Microsoft.CodeAnalysis.ResxSourceGenerator"); if (nugetFolder is not null) { - sourceGeneratorFolder = System.IO.Path.Combine(nugetFolder, "analyzers", "dotnet", "cs"); + sourceGeneratorFolder = System.IO.Path.Join(nugetFolder, "analyzers", "dotnet", "cs"); } } catch (Exception e) diff --git a/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/SourceGenerators/SourceGeneratorBase.cs b/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/SourceGenerators/SourceGeneratorBase.cs index 36890f2d89c..545497dbd2b 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/SourceGenerators/SourceGeneratorBase.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/SourceGenerators/SourceGeneratorBase.cs @@ -35,7 +35,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching /// protected string GetTemporaryWorkingDirectory(string subfolder) { - var temp = Path.Combine(tempWorkingDirectory.ToString(), subfolder); + var temp = Path.Join(tempWorkingDirectory.ToString(), subfolder); Directory.CreateDirectory(temp); return temp; diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Catch.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Catch.cs index f3a10f4ef68..cc497ed0f49 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Catch.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Catch.cs @@ -23,7 +23,9 @@ namespace Semmle.Extraction.CSharp.Entities.Statements } else if (isSpecificCatchClause) // A catch clause of the form 'catch(Ex) { ... }' { - trapFile.catch_type(this, Type.Create(Context, Context.GetType(Stmt.Declaration!.Type)).TypeRef, true); + var type = Type.Create(Context, Context.GetType(Stmt.Declaration!.Type)); + trapFile.catch_type(this, type.TypeRef, true); + Expression.Create(Context, Stmt.Declaration!.Type, this, 0); } else // A catch clause of the form 'catch { ... }' { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Extractor/CompilerVersion.cs b/csharp/extractor/Semmle.Extraction.CSharp/Extractor/CompilerVersion.cs index 5429f2bba07..d894cbbe2ec 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Extractor/CompilerVersion.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Extractor/CompilerVersion.cs @@ -67,7 +67,7 @@ namespace Semmle.Extraction.CSharp return; } - var mscorlibExists = File.Exists(Path.Combine(compilerDir, "mscorlib.dll")); + var mscorlibExists = File.Exists(Path.Join(compilerDir, "mscorlib.dll")); if (specifiedFramework is null && mscorlibExists) { @@ -107,7 +107,7 @@ namespace Semmle.Extraction.CSharp /// /// The file csc.rsp. /// - private string CscRsp => Path.Combine(FrameworkPath, csc_rsp); + private string CscRsp => Path.Join(FrameworkPath, csc_rsp); /// /// Should we skip extraction? diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Extractor/Context.cs b/csharp/extractor/Semmle.Extraction.CSharp/Extractor/Context.cs index c3752165204..829561d37ae 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Extractor/Context.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Extractor/Context.cs @@ -680,7 +680,7 @@ namespace Semmle.Extraction.CSharp { try { - var fullPath = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(mappedFromPath)!, mappedToPath)); + var fullPath = Path.GetFullPath(Path.Join(Path.GetDirectoryName(mappedFromPath)!, mappedToPath)); ExtractionContext.Logger.LogDebug($"Found relative path in line mapping: '{mappedToPath}', interpreting it as '{fullPath}'"); mappedToPath = fullPath; diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Extractor/CsProjFile.cs b/csharp/extractor/Semmle.Extraction.CSharp/Extractor/CsProjFile.cs index 665eb0bf346..844f16086c6 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Extractor/CsProjFile.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Extractor/CsProjFile.cs @@ -159,7 +159,11 @@ namespace Semmle.Extraction.CSharp return null; } - return Path.GetFullPath(Path.Combine(projDir?.FullName ?? string.Empty, Path.DirectorySeparatorChar == '/' ? file.Replace("\\", "/") : file)); + var normalized = Path.DirectorySeparatorChar == '/' ? file.Replace("\\", "/") : file; + var path = projDir is not null && !Path.IsPathRooted(normalized) + ? Path.Join(projDir.FullName, normalized) + : normalized; + return Path.GetFullPath(path); } private readonly string[] references; diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Extractor/Extractor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Extractor/Extractor.cs index 69aa7c47909..659fea49e9b 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Extractor/Extractor.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Extractor/Extractor.cs @@ -210,7 +210,7 @@ namespace Semmle.Extraction.CSharp TracingAnalyser.GetOutputName(compilation, args), compilation, generatedSyntaxTrees, - Path.Combine(compilationIdentifierPath, diagnosticName), + Path.Join(compilationIdentifierPath, diagnosticName), options), () => { }); @@ -377,7 +377,7 @@ namespace Semmle.Extraction.CSharp else { var composed = referencePaths.Value - .Select(path => Path.Combine(path, clref.Reference)) + .Select(path => Path.Join(path, clref.Reference)) .Where(path => File.Exists(path)) .Select(path => analyser.PathCache.GetCanonicalPath(path)) .FirstOrDefault(); @@ -559,13 +559,13 @@ namespace Semmle.Extraction.CSharp /// Gets the path to the `csharp.log` file written to by the C# extractor. /// public static string GetCSharpLogPath() => - Path.Combine(GetCSharpLogDirectory(), "csharp.log"); + Path.Join(GetCSharpLogDirectory(), "csharp.log"); /// /// Gets the path to a `csharp.{hash}.txt` file written to by the C# extractor. /// public static string GetCSharpArgsLogPath(string hash) => - Path.Combine(GetCSharpLogDirectory(), $"csharp.{hash}.txt"); + Path.Join(GetCSharpLogDirectory(), $"csharp.{hash}.txt"); /// /// Gets a list of all `csharp.{hash}.txt` files currently written to the log directory. diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Extractor/TracingAnalyser.cs b/csharp/extractor/Semmle.Extraction.CSharp/Extractor/TracingAnalyser.cs index 9f2a1256f1a..b66dba798dd 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Extractor/TracingAnalyser.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Extractor/TracingAnalyser.cs @@ -131,7 +131,7 @@ namespace Semmle.Extraction.CSharp return Path.ChangeExtension(entryPointFilename, ".exe"); } - return Path.Combine(commandLineArguments.OutputDirectory, commandLineArguments.OutputFileName); + return Path.Join(commandLineArguments.OutputDirectory, commandLineArguments.OutputFileName); } private int LogDiagnostics() diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Extractor/TrapWriter.cs b/csharp/extractor/Semmle.Extraction.CSharp/Extractor/TrapWriter.cs index 42e933c8eaf..ea6adb22642 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Extractor/TrapWriter.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Extractor/TrapWriter.cs @@ -61,7 +61,7 @@ namespace Semmle.Extraction.CSharp * Although GetRandomFileName() is cryptographically secure, * there's a tiny chance the file could already exists. */ - tmpFile = Path.Combine(tempPath, Path.GetRandomFileName()); + tmpFile = Path.Join(tempPath, Path.GetRandomFileName()); } while (File.Exists(tmpFile)); diff --git a/csharp/extractor/Semmle.Util.Tests/CanonicalPathCache.cs b/csharp/extractor/Semmle.Util.Tests/CanonicalPathCache.cs index 313b949810d..e75821a4cb1 100644 --- a/csharp/extractor/Semmle.Util.Tests/CanonicalPathCache.cs +++ b/csharp/extractor/Semmle.Util.Tests/CanonicalPathCache.cs @@ -82,13 +82,13 @@ namespace SemmleTests.Semmle.Util [Fact] public void CanonicalPathMissingFile() { - Assert.Equal(Path.Combine(Directory.GetCurrentDirectory(), "NOSUCHFILE"), cache.GetCanonicalPath("NOSUCHFILE")); + Assert.Equal(Path.Join(Directory.GetCurrentDirectory(), "NOSUCHFILE"), cache.GetCanonicalPath("NOSUCHFILE")); } [Fact] public void CanonicalPathMissingAbsolutePath() { - Assert.Equal(Path.Combine(root, "no", "such", "file"), cache.GetCanonicalPath(Path.Combine(root, "no", "such", "file"))); + Assert.Equal(Path.Join(root, "no", "such", "file"), cache.GetCanonicalPath(Path.Join(root, "no", "such", "file"))); if (Win32.IsWindows()) Assert.Equal(@"C:\Windows\no\such\file", cache.GetCanonicalPath(@"C:\windOws\no\such\file")); @@ -97,7 +97,7 @@ namespace SemmleTests.Semmle.Util [Fact] public void CanonicalPathMissingRelativePath() { - Assert.Equal(Path.Combine(Directory.GetCurrentDirectory(), "NO", "SUCH"), cache.GetCanonicalPath(Path.Combine("NO", "SUCH"))); + Assert.Equal(Path.Join(Directory.GetCurrentDirectory(), "NO", "SUCH"), cache.GetCanonicalPath(Path.Join("NO", "SUCH"))); } [Fact] @@ -125,7 +125,7 @@ namespace SemmleTests.Semmle.Util public void CanonicalPathDots() { var abcPath = Path.GetFullPath("abc"); - Assert.Equal(abcPath, cache.GetCanonicalPath(Path.Combine("foo", ".", "..", "abc"))); + Assert.Equal(abcPath, cache.GetCanonicalPath(Path.Join("foo", ".", "..", "abc"))); } [Fact] diff --git a/csharp/extractor/Semmle.Util.Tests/LongPaths.cs b/csharp/extractor/Semmle.Util.Tests/LongPaths.cs index 90607bc8f02..381fd97e214 100644 --- a/csharp/extractor/Semmle.Util.Tests/LongPaths.cs +++ b/csharp/extractor/Semmle.Util.Tests/LongPaths.cs @@ -14,20 +14,20 @@ namespace SemmleTests.Semmle.Util public sealed class LongPaths { private static readonly string tmpDir = Environment.GetEnvironmentVariable("TEST_TMPDIR") ?? Path.GetTempPath(); - private static readonly string longPathDir = Path.Combine(tmpDir, "aaaaaaaaaaaaaaaaaaaaaaaaaaaa", "bbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + private static readonly string longPathDir = Path.Join(tmpDir, "aaaaaaaaaaaaaaaaaaaaaaaaaaaa", "bbbbbbbbbbbbbbbbbbbbbbbbbbbbb", "ccccccccccccccccccccccccccccccc", "ddddddddddddddddddddddddddddddddddddd", "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", "fffffffffffffffffffffffffffffffff", "ggggggggggggggggggggggggggggggggggg", "hhhhhhhhhhhhhhhhhhhhhhhhhhhhhh"); private static string MakeLongPath() { var uniquePostfix = Guid.NewGuid().ToString("N"); - return Path.Combine(longPathDir, $"iiiiiiiiiiiiiiii{uniquePostfix}.txt"); + return Path.Join(longPathDir, $"iiiiiiiiiiiiiiii{uniquePostfix}.txt"); } private static string MakeShortPath() { var uniquePostfix = Guid.NewGuid().ToString("N"); - return Path.Combine(tmpDir, $"test{uniquePostfix}.txt"); + return Path.Join(tmpDir, $"test{uniquePostfix}.txt"); } public LongPaths() @@ -62,7 +62,7 @@ namespace SemmleTests.Semmle.Util [Fact] public void ParentDirectory() { - Assert.Equal("abc", Path.GetDirectoryName(Path.Combine("abc", "def"))); + Assert.Equal("abc", Path.GetDirectoryName(Path.Join("abc", "def"))); Assert.Equal(Win32.IsWindows() ? "\\" : "/", Path.GetDirectoryName($@"{Path.DirectorySeparatorChar}def")); Assert.Equal("", Path.GetDirectoryName(@"def")); diff --git a/csharp/extractor/Semmle.Util/BuildActions.cs b/csharp/extractor/Semmle.Util/BuildActions.cs index 09696564efc..20c5ee70841 100644 --- a/csharp/extractor/Semmle.Util/BuildActions.cs +++ b/csharp/extractor/Semmle.Util/BuildActions.cs @@ -137,11 +137,11 @@ namespace Semmle.Util bool IsMonoInstalled(); /// - /// Combine path segments, Path.Combine(). + /// Joins path segments, Path.Join(). /// /// The parts of the path. /// The combined path. - string PathCombine(params string[] parts); + string PathJoin(params string[] parts); /// /// Gets the full path for , Path.GetFullPath(). @@ -293,7 +293,7 @@ namespace Semmle.Util } } - string IBuildActions.PathCombine(params string[] parts) => Path.Combine(parts); + string IBuildActions.PathJoin(params string[] parts) => Path.Join(parts); void IBuildActions.WriteAllText(string filename, string contents) => File.WriteAllText(filename, contents); diff --git a/csharp/extractor/Semmle.Util/CanonicalPathCache.cs b/csharp/extractor/Semmle.Util/CanonicalPathCache.cs index d3cbf41fa10..2dc04e074f6 100644 --- a/csharp/extractor/Semmle.Util/CanonicalPathCache.cs +++ b/csharp/extractor/Semmle.Util/CanonicalPathCache.cs @@ -43,7 +43,7 @@ namespace Semmle.Util var parent = Directory.GetParent(path); return parent is not null ? - Path.Combine(cache.GetCanonicalPath(parent.FullName), Path.GetFileName(path)) : + Path.Join(cache.GetCanonicalPath(parent.FullName), Path.GetFileName(path)) : path.ToUpperInvariant(); } } @@ -138,12 +138,12 @@ namespace Semmle.Util var entries = Directory.GetFileSystemEntries(parentPath, name); return entries.Length == 1 ? entries[0] - : Path.Combine(parentPath, name); + : Path.Join(parentPath, name); } catch // lgtm[cs/catch-of-all-exceptions] { // IO error or security error querying directory. - return Path.Combine(parentPath, name); + return Path.Join(parentPath, name); } } } diff --git a/csharp/extractor/Semmle.Util/FileUtils.cs b/csharp/extractor/Semmle.Util/FileUtils.cs index ce157a8268a..4706c18f72b 100644 --- a/csharp/extractor/Semmle.Util/FileUtils.cs +++ b/csharp/extractor/Semmle.Util/FileUtils.cs @@ -82,7 +82,7 @@ namespace Semmle.Util { exes = new[] { prog }; } - var candidates = paths?.Where(path => exes.Any(exe0 => File.Exists(Path.Combine(path, exe0)))); + var candidates = paths?.Where(path => exes.Any(exe0 => File.Exists(Path.Join(path, exe0)))); return candidates?.FirstOrDefault(); } @@ -179,7 +179,7 @@ namespace Semmle.Util { innerpath = ConvertPathToSafeRelativePath(innerpath); - nested = Path.Combine(outerpath, innerpath); + nested = Path.Join(outerpath, innerpath); } try { @@ -203,7 +203,7 @@ namespace Semmle.Util { var tempPath = Path.GetTempPath(); var name = Guid.NewGuid().ToString("N").ToUpper(); - var tempFolder = Path.Combine(tempPath, "GitHub", name); + var tempFolder = Path.Join(tempPath, "GitHub", name); Directory.CreateDirectory(tempFolder); return tempFolder; }); @@ -231,7 +231,7 @@ namespace Semmle.Util string outputPath; do { - outputPath = Path.Combine(tempFolder, Path.GetRandomFileName() + extension); + outputPath = Path.Join(tempFolder, Path.GetRandomFileName() + extension); } while (File.Exists(outputPath)); diff --git a/csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md b/csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md index 3ceb4374a77..e1fbde4a626 100644 --- a/csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md +++ b/csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.7.69 + +No user-facing changes. + ## 1.7.68 No user-facing changes. diff --git a/csharp/ql/campaigns/Solorigate/lib/change-notes/released/1.7.69.md b/csharp/ql/campaigns/Solorigate/lib/change-notes/released/1.7.69.md new file mode 100644 index 00000000000..77e5690eb75 --- /dev/null +++ b/csharp/ql/campaigns/Solorigate/lib/change-notes/released/1.7.69.md @@ -0,0 +1,3 @@ +## 1.7.69 + +No user-facing changes. diff --git a/csharp/ql/campaigns/Solorigate/lib/codeql-pack.release.yml b/csharp/ql/campaigns/Solorigate/lib/codeql-pack.release.yml index f737dfa0972..711f9a5b58f 100644 --- a/csharp/ql/campaigns/Solorigate/lib/codeql-pack.release.yml +++ b/csharp/ql/campaigns/Solorigate/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.7.68 +lastReleaseVersion: 1.7.69 diff --git a/csharp/ql/campaigns/Solorigate/lib/qlpack.yml b/csharp/ql/campaigns/Solorigate/lib/qlpack.yml index 52172a7a189..88080d5df9a 100644 --- a/csharp/ql/campaigns/Solorigate/lib/qlpack.yml +++ b/csharp/ql/campaigns/Solorigate/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/csharp-solorigate-all -version: 1.7.69-dev +version: 1.7.70-dev groups: - csharp - solorigate diff --git a/csharp/ql/campaigns/Solorigate/src/CHANGELOG.md b/csharp/ql/campaigns/Solorigate/src/CHANGELOG.md index 3ceb4374a77..e1fbde4a626 100644 --- a/csharp/ql/campaigns/Solorigate/src/CHANGELOG.md +++ b/csharp/ql/campaigns/Solorigate/src/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.7.69 + +No user-facing changes. + ## 1.7.68 No user-facing changes. diff --git a/csharp/ql/campaigns/Solorigate/src/change-notes/released/1.7.69.md b/csharp/ql/campaigns/Solorigate/src/change-notes/released/1.7.69.md new file mode 100644 index 00000000000..77e5690eb75 --- /dev/null +++ b/csharp/ql/campaigns/Solorigate/src/change-notes/released/1.7.69.md @@ -0,0 +1,3 @@ +## 1.7.69 + +No user-facing changes. diff --git a/csharp/ql/campaigns/Solorigate/src/codeql-pack.release.yml b/csharp/ql/campaigns/Solorigate/src/codeql-pack.release.yml index f737dfa0972..711f9a5b58f 100644 --- a/csharp/ql/campaigns/Solorigate/src/codeql-pack.release.yml +++ b/csharp/ql/campaigns/Solorigate/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.7.68 +lastReleaseVersion: 1.7.69 diff --git a/csharp/ql/campaigns/Solorigate/src/qlpack.yml b/csharp/ql/campaigns/Solorigate/src/qlpack.yml index cf63a439518..effa1c940c0 100644 --- a/csharp/ql/campaigns/Solorigate/src/qlpack.yml +++ b/csharp/ql/campaigns/Solorigate/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/csharp-solorigate-queries -version: 1.7.69-dev +version: 1.7.70-dev groups: - csharp - solorigate diff --git a/csharp/ql/lib/CHANGELOG.md b/csharp/ql/lib/CHANGELOG.md index a45a993832e..7987a729ec6 100644 --- a/csharp/ql/lib/CHANGELOG.md +++ b/csharp/ql/lib/CHANGELOG.md @@ -1,3 +1,19 @@ +## 7.0.0 + +### Breaking Changes + +* Renamed types related to *operation* expressions. The QL classes `BinaryArithmeticOperation`, `BinaryBitwiseOperation`, and `BinaryLogicalOperation` now include compound assignments; for example, `BinaryArithmeticOperation` now includes `a += b`. + +### Major Analysis Improvements + +* Added Razor Page handler method parameters (e.g., `OnGet`, `OnPost`, `OnPostAsync`) as remote flow sources, enabling security queries such as `cs/sql-injection` to detect vulnerabilities in `PageModel` subclasses. + +### Minor Analysis Improvements + +* Improved property and indexer call target resolution for partially overridden properties and indexers. +* Improved extraction of range-access expressions on spans and strings (for example, `a[0..3]`). These expressions are now extracted as `Slice` (span) or `Substring` (string) calls. +* Improved call target resolution for ref-return properties and indexers. + ## 6.0.2 ### Minor Analysis Improvements diff --git a/csharp/ql/lib/change-notes/2026-05-19-properties-indexers-refreturn.md b/csharp/ql/lib/change-notes/2026-05-19-properties-indexers-refreturn.md deleted file mode 100644 index d92d5fdf819..00000000000 --- a/csharp/ql/lib/change-notes/2026-05-19-properties-indexers-refreturn.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: minorAnalysis ---- -* Improved call target resolution for ref-return properties and indexers. diff --git a/csharp/ql/lib/change-notes/2026-05-21-spanaccess-range.md b/csharp/ql/lib/change-notes/2026-05-21-spanaccess-range.md deleted file mode 100644 index b5e81d9adb9..00000000000 --- a/csharp/ql/lib/change-notes/2026-05-21-spanaccess-range.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: minorAnalysis ---- -* Improved extraction of range-access expressions on spans and strings (for example, `a[0..3]`). These expressions are now extracted as `Slice` (span) or `Substring` (string) calls. diff --git a/csharp/ql/lib/change-notes/2026-05-22-property-indexer-partial-override.md b/csharp/ql/lib/change-notes/2026-05-22-property-indexer-partial-override.md deleted file mode 100644 index 4be78a49c1f..00000000000 --- a/csharp/ql/lib/change-notes/2026-05-22-property-indexer-partial-override.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: minorAnalysis ---- -* Improved property and indexer call target resolution for partially overridden properties and indexers. diff --git a/csharp/ql/lib/change-notes/2026-06-12-razor-page-handler-sources.md b/csharp/ql/lib/change-notes/2026-06-12-razor-page-handler-sources.md deleted file mode 100644 index aca9d7631cd..00000000000 --- a/csharp/ql/lib/change-notes/2026-06-12-razor-page-handler-sources.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: majorAnalysis ---- -* Added Razor Page handler method parameters (e.g., `OnGet`, `OnPost`, `OnPostAsync`) as remote flow sources, enabling security queries such as `cs/sql-injection` to detect vulnerabilities in `PageModel` subclasses. diff --git a/csharp/ql/lib/change-notes/2026-06-12-restructure-operations.md b/csharp/ql/lib/change-notes/2026-06-12-restructure-operations.md deleted file mode 100644 index 89459c5b981..00000000000 --- a/csharp/ql/lib/change-notes/2026-06-12-restructure-operations.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: breaking ---- -* Renamed types related to *operation* expressions. The QL classes `BinaryArithmeticOperation`, `BinaryBitwiseOperation`, and `BinaryLogicalOperation` now include compound assignments; for example, `BinaryArithmeticOperation` now includes `a += b`. diff --git a/csharp/ql/lib/change-notes/released/7.0.0.md b/csharp/ql/lib/change-notes/released/7.0.0.md new file mode 100644 index 00000000000..3c1aabbfc4d --- /dev/null +++ b/csharp/ql/lib/change-notes/released/7.0.0.md @@ -0,0 +1,15 @@ +## 7.0.0 + +### Breaking Changes + +* Renamed types related to *operation* expressions. The QL classes `BinaryArithmeticOperation`, `BinaryBitwiseOperation`, and `BinaryLogicalOperation` now include compound assignments; for example, `BinaryArithmeticOperation` now includes `a += b`. + +### Major Analysis Improvements + +* Added Razor Page handler method parameters (e.g., `OnGet`, `OnPost`, `OnPostAsync`) as remote flow sources, enabling security queries such as `cs/sql-injection` to detect vulnerabilities in `PageModel` subclasses. + +### Minor Analysis Improvements + +* Improved property and indexer call target resolution for partially overridden properties and indexers. +* Improved extraction of range-access expressions on spans and strings (for example, `a[0..3]`). These expressions are now extracted as `Slice` (span) or `Substring` (string) calls. +* Improved call target resolution for ref-return properties and indexers. diff --git a/csharp/ql/lib/codeql-pack.release.yml b/csharp/ql/lib/codeql-pack.release.yml index 70437ec53b8..e0db21c7869 100644 --- a/csharp/ql/lib/codeql-pack.release.yml +++ b/csharp/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 6.0.2 +lastReleaseVersion: 7.0.0 diff --git a/csharp/ql/lib/qlpack.yml b/csharp/ql/lib/qlpack.yml index 638f9902642..0749eea574d 100644 --- a/csharp/ql/lib/qlpack.yml +++ b/csharp/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/csharp-all -version: 6.0.3-dev +version: 7.0.1-dev groups: csharp dbscheme: semmlecode.csharp.dbscheme extractor: csharp diff --git a/csharp/ql/lib/semmle/code/csharp/Stmt.qll b/csharp/ql/lib/semmle/code/csharp/Stmt.qll index 4d79bf9fa54..3be818e43a5 100644 --- a/csharp/ql/lib/semmle/code/csharp/Stmt.qll +++ b/csharp/ql/lib/semmle/code/csharp/Stmt.qll @@ -995,6 +995,23 @@ class SpecificCatchClause extends CatchClause { /** Gets the local variable declaration of this catch clause, if any. */ LocalVariableDeclExpr getVariableDeclExpr() { result.getParent() = this } + /** + * Gets the type access of this catch clause, if it has no variable declaration. + * + * For example, the type access in + * + * ```csharp + * try { ... } + * catch (IOException) { ... } + * ``` + * + * is `IOException`. + */ + TypeAccess getTypeAccess() { + not exists(this.getVariableDeclExpr()) and + result = this.getChild(0) + } + override string toString() { result = "catch (...) {...}" } override string getAPrimaryQlClass() { result = "SpecificCatchClause" } diff --git a/csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraph.qll b/csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraph.qll index 18a967eee28..14bbb025172 100644 --- a/csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraph.qll +++ b/csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraph.qll @@ -75,7 +75,8 @@ module Ast implements AstSig { additional predicate skipControlFlow(AstNode e) { e instanceof TypeAccess and - not e instanceof TypeAccessPatternExpr + not e instanceof TypeAccessPatternExpr and + not any(CS::SpecificCatchClause sc).getTypeAccess() = e or not e.getFile().fromSource() } @@ -90,6 +91,7 @@ module Ast implements AstSig { private AstNode getStmtChild0(Stmt s, int i) { not s instanceof FixedStmt and not s instanceof UsingBlockStmt and + not skipControlFlow(result) and result = s.getChild(i) or s = @@ -145,6 +147,8 @@ module Ast implements AstSig { final private class ParameterFinal = CS::Parameter; class Parameter extends ParameterFinal { + AstNode getPattern() { result = this } + Expr getDefaultValue() { // Avoid combinatorial explosions for callables with multiple bodies result = unique( | | super.getDefaultValue()) @@ -217,7 +221,12 @@ module Ast implements AstSig { final private class FinalCatchClause = CS::CatchClause; class CatchClause extends FinalCatchClause { - AstNode getVariable() { result = this.(CS::SpecificCatchClause).getVariableDeclExpr() } + AstNode getPattern() { + result = this.(CS::SpecificCatchClause).getVariableDeclExpr() or + result = this.(CS::SpecificCatchClause).getTypeAccess() + } + + AstNode getVariable() { none() } Expr getCondition() { result = this.getFilterClause() } diff --git a/csharp/ql/src/CHANGELOG.md b/csharp/ql/src/CHANGELOG.md index 5c196df3614..2e316088da5 100644 --- a/csharp/ql/src/CHANGELOG.md +++ b/csharp/ql/src/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.7.5 + +No user-facing changes. + ## 1.7.4 No user-facing changes. diff --git a/csharp/ql/src/Dead Code/DeadStoreOfLocal.ql b/csharp/ql/src/Dead Code/DeadStoreOfLocal.ql index cf57707608b..20f522e7b48 100644 --- a/csharp/ql/src/Dead Code/DeadStoreOfLocal.ql +++ b/csharp/ql/src/Dead Code/DeadStoreOfLocal.ql @@ -14,54 +14,6 @@ import csharp -/** - * Gets a callable that either directly captures local variable `v`, or which - * is enclosed by the callable that declares `v` and encloses a callable that - * captures `v`. - */ -Callable getACapturingCallableAncestor(LocalVariable v) { - result = v.getACapturingCallable() - or - exists(Callable mid | mid = getACapturingCallableAncestor(v) | - result = mid.getEnclosingCallable() and - not v.getEnclosingCallable() = result - ) -} - -Expr getADelegateExpr(Callable c) { - c = result.(CallableAccess).getTarget() - or - result = c.(AnonymousFunctionExpr) -} - -/** - * Holds if `c` is a call where any delegate argument is evaluated immediately. - */ -predicate nonEscapingCall(Call c) { - exists(string name | c.getTarget().hasName(name) | - name = - [ - "ForEach", "Count", "Any", "All", "Average", "Aggregate", "First", "Last", "FirstOrDefault", - "LastOrDefault", "LongCount", "Max", "Single", "SingleOrDefault", "Sum" - ] - ) -} - -/** - * Holds if `v` is a captured local variable, and one of the callables capturing - * `v` may escape the local scope. - */ -predicate mayEscape(LocalVariable v) { - exists(Callable c, Expr e, Expr succ | c = getACapturingCallableAncestor(v) | - e = getADelegateExpr(c) and - DataFlow::localExprFlow(e, succ) and - not succ = any(DelegateCall dc).getExpr() and - not succ = any(Cast cast).getExpr() and - not succ = any(Call call | nonEscapingCall(call)).getAnArgument() and - not succ = any(AssignableDefinition ad | ad.getTarget() instanceof LocalVariable).getSource() - ) -} - class RelevantDefinition extends AssignableDefinition { RelevantDefinition() { this.(AssignableDefinitions::AssignmentDefinition).getAssignment() = @@ -94,8 +46,6 @@ class RelevantDefinition extends AssignableDefinition { // SSA definitions are only created for live variables this = any(SsaExplicitWrite ssaDef).getDefinition() or - mayEscape(v) - or v.isCaptured() ) } diff --git a/csharp/ql/src/change-notes/released/1.7.5.md b/csharp/ql/src/change-notes/released/1.7.5.md new file mode 100644 index 00000000000..f17d9279e0d --- /dev/null +++ b/csharp/ql/src/change-notes/released/1.7.5.md @@ -0,0 +1,3 @@ +## 1.7.5 + +No user-facing changes. diff --git a/csharp/ql/src/codeql-pack.release.yml b/csharp/ql/src/codeql-pack.release.yml index f4f3a4d5120..83aebd7c12a 100644 --- a/csharp/ql/src/codeql-pack.release.yml +++ b/csharp/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.7.4 +lastReleaseVersion: 1.7.5 diff --git a/csharp/ql/src/qlpack.yml b/csharp/ql/src/qlpack.yml index 378d02fee3f..9110c334a2e 100644 --- a/csharp/ql/src/qlpack.yml +++ b/csharp/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/csharp-queries -version: 1.7.5-dev +version: 1.7.6-dev groups: - csharp - queries diff --git a/csharp/ql/test/library-tests/controlflow/graph/BasicBlock.expected b/csharp/ql/test/library-tests/controlflow/graph/BasicBlock.expected index 819674d2746..b955551e55b 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/BasicBlock.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/BasicBlock.expected @@ -447,13 +447,13 @@ | ExitMethods.cs:20:10:20:11 | Entry | ExitMethods.cs:20:10:20:11 | Exit | 8 | | ExitMethods.cs:26:10:26:11 | Entry | ExitMethods.cs:26:10:26:11 | Exit | 8 | | ExitMethods.cs:32:10:32:11 | Entry | ExitMethods.cs:32:10:32:11 | Exit | 8 | -| ExitMethods.cs:38:10:38:11 | Entry | ExitMethods.cs:44:9:47:9 | catch (...) {...} | 9 | +| ExitMethods.cs:38:10:38:11 | Entry | ExitMethods.cs:44:16:44:32 | access to type ArgumentException | 10 | | ExitMethods.cs:38:10:38:11 | Exit | ExitMethods.cs:38:10:38:11 | Exit | 1 | | ExitMethods.cs:38:10:38:11 | Normal Exit | ExitMethods.cs:38:10:38:11 | Normal Exit | 1 | -| ExitMethods.cs:44:9:47:9 | After catch (...) {...} [match] | ExitMethods.cs:46:13:46:19 | return ...; | 4 | -| ExitMethods.cs:44:9:47:9 | After catch (...) {...} [no-match] | ExitMethods.cs:48:9:51:9 | catch (...) {...} | 2 | -| ExitMethods.cs:48:9:51:9 | After catch (...) {...} [match] | ExitMethods.cs:50:13:50:19 | return ...; | 4 | -| ExitMethods.cs:48:9:51:9 | After catch (...) {...} [no-match] | ExitMethods.cs:38:10:38:11 | Exceptional Exit | 2 | +| ExitMethods.cs:44:16:44:32 | After access to type ArgumentException [match] | ExitMethods.cs:46:13:46:19 | return ...; | 4 | +| ExitMethods.cs:44:16:44:32 | After access to type ArgumentException [no-match] | ExitMethods.cs:48:16:48:24 | access to type Exception | 4 | +| ExitMethods.cs:48:16:48:24 | After access to type Exception [match] | ExitMethods.cs:50:13:50:19 | return ...; | 4 | +| ExitMethods.cs:48:16:48:24 | After access to type Exception [no-match] | ExitMethods.cs:38:10:38:11 | Exceptional Exit | 3 | | ExitMethods.cs:54:10:54:11 | Entry | ExitMethods.cs:54:10:54:11 | Exit | 7 | | ExitMethods.cs:60:10:60:11 | Entry | ExitMethods.cs:60:10:60:11 | Exit | 7 | | ExitMethods.cs:66:17:66:26 | Entry | ExitMethods.cs:68:13:68:13 | access to parameter b | 5 | @@ -508,13 +508,13 @@ | Finally.cs:19:10:19:11 | Normal Exit | Finally.cs:19:10:19:11 | Normal Exit | 1 | | Finally.cs:21:9:51:9 | After try {...} ... | Finally.cs:20:5:52:5 | After {...} | 2 | | Finally.cs:23:13:23:37 | After call to method WriteLine | Finally.cs:24:13:24:19 | return ...; | 4 | -| Finally.cs:26:9:29:9 | After catch (...) {...} [match] | Finally.cs:28:13:28:18 | throw ...; | 7 | -| Finally.cs:26:9:29:9 | After catch (...) {...} [no-match] | Finally.cs:30:9:40:9 | catch (...) {...} | 2 | -| Finally.cs:26:9:29:9 | catch (...) {...} | Finally.cs:26:9:29:9 | catch (...) {...} | 1 | -| Finally.cs:30:9:40:9 | After catch (...) {...} [match] | Finally.cs:38:17:38:44 | throw ...; | 17 | -| Finally.cs:30:9:40:9 | After catch (...) {...} [no-match] | Finally.cs:41:9:43:9 | catch (...) {...} | 2 | -| Finally.cs:41:9:43:9 | After catch (...) {...} [match] | Finally.cs:42:9:43:9 | {...} | 2 | -| Finally.cs:41:9:43:9 | After catch (...) {...} [no-match] | Finally.cs:46:13:46:19 | return ...; | 6 | +| Finally.cs:26:9:29:9 | catch (...) {...} | Finally.cs:26:38:26:39 | IOException ex | 2 | +| Finally.cs:26:38:26:39 | After IOException ex [match] | Finally.cs:28:13:28:18 | throw ...; | 6 | +| Finally.cs:26:38:26:39 | After IOException ex [no-match] | Finally.cs:30:41:30:42 | ArgumentException ex | 4 | +| Finally.cs:30:41:30:42 | After ArgumentException ex [match] | Finally.cs:38:17:38:44 | throw ...; | 16 | +| Finally.cs:30:41:30:42 | After ArgumentException ex [no-match] | Finally.cs:41:16:41:24 | access to type Exception | 4 | +| Finally.cs:41:16:41:24 | After access to type Exception [match] | Finally.cs:42:9:43:9 | {...} | 2 | +| Finally.cs:41:16:41:24 | After access to type Exception [no-match] | Finally.cs:46:13:46:19 | return ...; | 6 | | Finally.cs:49:9:51:9 | {...} | Finally.cs:49:9:51:9 | After {...} | 8 | | Finally.cs:54:10:54:11 | Entry | Finally.cs:58:13:58:37 | call to method WriteLine | 8 | | Finally.cs:54:10:54:11 | Exceptional Exit | Finally.cs:54:10:54:11 | Exceptional Exit | 1 | @@ -522,11 +522,12 @@ | Finally.cs:54:10:54:11 | Normal Exit | Finally.cs:54:10:54:11 | Normal Exit | 1 | | Finally.cs:56:9:71:9 | After try {...} ... | Finally.cs:55:5:72:5 | After {...} | 2 | | Finally.cs:58:13:58:37 | After call to method WriteLine | Finally.cs:59:13:59:19 | return ...; | 4 | -| Finally.cs:61:9:64:9 | After catch (...) {...} [match] | Finally.cs:63:13:63:18 | throw ...; | 7 | -| Finally.cs:61:9:64:9 | After catch (...) {...} [no-match] | Finally.cs:65:9:67:9 | catch (...) {...} | 2 | -| Finally.cs:61:9:64:9 | catch (...) {...} | Finally.cs:61:9:64:9 | catch (...) {...} | 1 | -| Finally.cs:65:9:67:9 | After catch (...) {...} [match] | Finally.cs:65:35:65:51 | ... != ... | 9 | +| Finally.cs:61:9:64:9 | catch (...) {...} | Finally.cs:61:38:61:39 | IOException ex | 2 | +| Finally.cs:61:38:61:39 | After IOException ex [match] | Finally.cs:63:13:63:18 | throw ...; | 6 | +| Finally.cs:61:38:61:39 | After IOException ex [no-match] | Finally.cs:65:26:65:26 | Exception e | 4 | | Finally.cs:65:9:67:9 | After catch (...) {...} [no-match] | Finally.cs:65:9:67:9 | After catch (...) {...} [no-match] | 1 | +| Finally.cs:65:26:65:26 | After Exception e [match] | Finally.cs:65:35:65:51 | ... != ... | 8 | +| Finally.cs:65:26:65:26 | After Exception e [no-match] | Finally.cs:65:26:65:26 | After Exception e [no-match] | 1 | | Finally.cs:65:35:65:51 | After ... != ... [false] | Finally.cs:65:35:65:51 | After ... != ... [false] | 1 | | Finally.cs:65:35:65:51 | After ... != ... [true] | Finally.cs:66:9:67:9 | {...} | 2 | | Finally.cs:69:9:71:9 | {...} | Finally.cs:69:9:71:9 | After {...} | 8 | @@ -589,9 +590,10 @@ | Finally.cs:158:21:158:36 | After ... == ... [false] | Finally.cs:157:13:160:13 | After {...} | 3 | | Finally.cs:158:21:158:36 | After ... == ... [true] | Finally.cs:159:27:159:44 | object creation of type Exception | 5 | | Finally.cs:159:27:159:44 | After object creation of type Exception | Finally.cs:159:21:159:45 | throw ...; | 2 | -| Finally.cs:161:13:164:13 | After catch (...) {...} [match] | Finally.cs:161:39:161:54 | ... == ... | 9 | -| Finally.cs:161:13:164:13 | After catch (...) {...} [no-match] | Finally.cs:166:13:168:13 | After {...} | 11 | -| Finally.cs:161:13:164:13 | catch (...) {...} | Finally.cs:161:13:164:13 | catch (...) {...} | 1 | +| Finally.cs:161:13:164:13 | After catch (...) {...} [no-match] | Finally.cs:166:13:168:13 | After {...} | 10 | +| Finally.cs:161:13:164:13 | catch (...) {...} | Finally.cs:161:30:161:30 | Exception e | 2 | +| Finally.cs:161:30:161:30 | After Exception e [match] | Finally.cs:161:39:161:54 | ... == ... | 8 | +| Finally.cs:161:30:161:30 | After Exception e [no-match] | Finally.cs:161:30:161:30 | After Exception e [no-match] | 1 | | Finally.cs:161:39:161:54 | After ... == ... [false] | Finally.cs:161:39:161:54 | After ... == ... [false] | 1 | | Finally.cs:161:39:161:54 | After ... == ... [true] | Finally.cs:162:13:164:13 | After {...} | 13 | | Finally.cs:172:11:172:20 | Entry | Finally.cs:172:11:172:20 | Exit | 11 | @@ -609,9 +611,10 @@ | Finally.cs:186:21:186:22 | After access to parameter b2 [false] | Finally.cs:185:13:187:13 | After {...} | 3 | | Finally.cs:186:21:186:22 | After access to parameter b2 [true] | Finally.cs:186:31:186:46 | object creation of type ExceptionB | 4 | | Finally.cs:186:31:186:46 | After object creation of type ExceptionB | Finally.cs:186:25:186:47 | throw ...; | 2 | -| Finally.cs:188:13:191:13 | After catch (...) {...} [match] | Finally.cs:188:38:188:39 | access to parameter b2 | 2 | | Finally.cs:188:13:191:13 | After catch (...) {...} [no-match] | Finally.cs:188:13:191:13 | After catch (...) {...} [no-match] | 1 | -| Finally.cs:188:13:191:13 | catch (...) {...} | Finally.cs:188:13:191:13 | catch (...) {...} | 1 | +| Finally.cs:188:13:191:13 | catch (...) {...} | Finally.cs:188:20:188:29 | access to type ExceptionB | 2 | +| Finally.cs:188:20:188:29 | After access to type ExceptionB [match] | Finally.cs:188:38:188:39 | access to parameter b2 | 2 | +| Finally.cs:188:20:188:29 | After access to type ExceptionB [no-match] | Finally.cs:188:20:188:29 | After access to type ExceptionB [no-match] | 1 | | Finally.cs:188:38:188:39 | After access to parameter b2 [false] | Finally.cs:188:38:188:39 | After access to parameter b2 [false] | 1 | | Finally.cs:188:38:188:39 | After access to parameter b2 [true] | Finally.cs:190:21:190:22 | access to parameter b1 | 4 | | Finally.cs:190:21:190:22 | After access to parameter b1 [false] | Finally.cs:189:13:191:13 | After {...} | 3 | @@ -633,7 +636,7 @@ | Finally.cs:209:21:209:22 | After access to parameter b3 [true] | Finally.cs:209:25:209:47 | throw ...; | 6 | | Finally.cs:216:10:216:12 | Entry | Finally.cs:220:13:220:36 | call to method WriteLine | 8 | | Finally.cs:220:13:220:36 | After call to method WriteLine | Finally.cs:219:9:221:9 | After {...} | 3 | -| Finally.cs:222:9:225:9 | catch {...} | Finally.cs:223:9:225:9 | After {...} | 10 | +| Finally.cs:222:9:225:9 | catch {...} | Finally.cs:223:9:225:9 | After {...} | 9 | | Finally.cs:227:9:229:9 | {...} | Finally.cs:216:10:216:12 | Exit | 18 | | Finally.cs:233:10:233:12 | Entry | Finally.cs:239:21:239:22 | access to parameter b1 | 10 | | Finally.cs:233:10:233:12 | Exceptional Exit | Finally.cs:233:10:233:12 | Exceptional Exit | 1 | diff --git a/csharp/ql/test/library-tests/controlflow/graph/Condition.expected b/csharp/ql/test/library-tests/controlflow/graph/Condition.expected index 4ed3508dd69..784bf2a5872 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/Condition.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/Condition.expected @@ -264,12 +264,12 @@ conditionBlock | DefaultParam.cs:3:12:3:13 | Entry | DefaultParam.cs:3:30:3:30 | After s [no-match] | false | | DefaultParam.cs:3:42:3:42 | i | DefaultParam.cs:3:42:3:42 | After i [match] | true | | DefaultParam.cs:3:42:3:42 | i | DefaultParam.cs:3:42:3:42 | After i [no-match] | false | -| ExitMethods.cs:38:10:38:11 | Entry | ExitMethods.cs:44:9:47:9 | After catch (...) {...} [match] | true | -| ExitMethods.cs:38:10:38:11 | Entry | ExitMethods.cs:44:9:47:9 | After catch (...) {...} [no-match] | false | -| ExitMethods.cs:38:10:38:11 | Entry | ExitMethods.cs:48:9:51:9 | After catch (...) {...} [match] | false | -| ExitMethods.cs:38:10:38:11 | Entry | ExitMethods.cs:48:9:51:9 | After catch (...) {...} [no-match] | false | -| ExitMethods.cs:44:9:47:9 | After catch (...) {...} [no-match] | ExitMethods.cs:48:9:51:9 | After catch (...) {...} [match] | true | -| ExitMethods.cs:44:9:47:9 | After catch (...) {...} [no-match] | ExitMethods.cs:48:9:51:9 | After catch (...) {...} [no-match] | false | +| ExitMethods.cs:38:10:38:11 | Entry | ExitMethods.cs:44:16:44:32 | After access to type ArgumentException [match] | true | +| ExitMethods.cs:38:10:38:11 | Entry | ExitMethods.cs:44:16:44:32 | After access to type ArgumentException [no-match] | false | +| ExitMethods.cs:38:10:38:11 | Entry | ExitMethods.cs:48:16:48:24 | After access to type Exception [match] | false | +| ExitMethods.cs:38:10:38:11 | Entry | ExitMethods.cs:48:16:48:24 | After access to type Exception [no-match] | false | +| ExitMethods.cs:44:16:44:32 | After access to type ArgumentException [no-match] | ExitMethods.cs:48:16:48:24 | After access to type Exception [match] | true | +| ExitMethods.cs:44:16:44:32 | After access to type ArgumentException [no-match] | ExitMethods.cs:48:16:48:24 | After access to type Exception [no-match] | false | | ExitMethods.cs:66:17:66:26 | Entry | ExitMethods.cs:68:13:68:13 | After access to parameter b [false] | false | | ExitMethods.cs:66:17:66:26 | Entry | ExitMethods.cs:68:13:68:13 | After access to parameter b [true] | true | | ExitMethods.cs:72:17:72:27 | Entry | ExitMethods.cs:74:13:74:13 | After access to parameter b [false] | false | @@ -280,29 +280,31 @@ conditionBlock | ExitMethods.cs:115:16:115:34 | Entry | ExitMethods.cs:117:16:117:30 | After call to method Contains [true] | true | | ExitMethods.cs:140:17:140:42 | Entry | ExitMethods.cs:142:13:142:13 | After access to parameter b [false] | false | | ExitMethods.cs:140:17:140:42 | Entry | ExitMethods.cs:142:13:142:13 | After access to parameter b [true] | true | -| Finally.cs:26:9:29:9 | After catch (...) {...} [no-match] | Finally.cs:30:9:40:9 | After catch (...) {...} [match] | true | -| Finally.cs:26:9:29:9 | After catch (...) {...} [no-match] | Finally.cs:30:9:40:9 | After catch (...) {...} [no-match] | false | -| Finally.cs:26:9:29:9 | After catch (...) {...} [no-match] | Finally.cs:41:9:43:9 | After catch (...) {...} [match] | false | -| Finally.cs:26:9:29:9 | After catch (...) {...} [no-match] | Finally.cs:41:9:43:9 | After catch (...) {...} [no-match] | false | -| Finally.cs:26:9:29:9 | catch (...) {...} | Finally.cs:26:9:29:9 | After catch (...) {...} [match] | true | -| Finally.cs:26:9:29:9 | catch (...) {...} | Finally.cs:26:9:29:9 | After catch (...) {...} [no-match] | false | -| Finally.cs:26:9:29:9 | catch (...) {...} | Finally.cs:30:9:40:9 | After catch (...) {...} [match] | false | -| Finally.cs:26:9:29:9 | catch (...) {...} | Finally.cs:30:9:40:9 | After catch (...) {...} [no-match] | false | -| Finally.cs:26:9:29:9 | catch (...) {...} | Finally.cs:41:9:43:9 | After catch (...) {...} [match] | false | -| Finally.cs:26:9:29:9 | catch (...) {...} | Finally.cs:41:9:43:9 | After catch (...) {...} [no-match] | false | -| Finally.cs:30:9:40:9 | After catch (...) {...} [no-match] | Finally.cs:41:9:43:9 | After catch (...) {...} [match] | true | -| Finally.cs:30:9:40:9 | After catch (...) {...} [no-match] | Finally.cs:41:9:43:9 | After catch (...) {...} [no-match] | false | -| Finally.cs:61:9:64:9 | After catch (...) {...} [no-match] | Finally.cs:65:9:67:9 | After catch (...) {...} [match] | true | -| Finally.cs:61:9:64:9 | After catch (...) {...} [no-match] | Finally.cs:65:35:65:51 | After ... != ... [false] | true | -| Finally.cs:61:9:64:9 | After catch (...) {...} [no-match] | Finally.cs:65:35:65:51 | After ... != ... [true] | true | -| Finally.cs:61:9:64:9 | catch (...) {...} | Finally.cs:61:9:64:9 | After catch (...) {...} [match] | true | -| Finally.cs:61:9:64:9 | catch (...) {...} | Finally.cs:61:9:64:9 | After catch (...) {...} [no-match] | false | -| Finally.cs:61:9:64:9 | catch (...) {...} | Finally.cs:65:9:67:9 | After catch (...) {...} [match] | false | +| Finally.cs:26:9:29:9 | catch (...) {...} | Finally.cs:26:38:26:39 | After IOException ex [match] | true | +| Finally.cs:26:9:29:9 | catch (...) {...} | Finally.cs:26:38:26:39 | After IOException ex [no-match] | false | +| Finally.cs:26:9:29:9 | catch (...) {...} | Finally.cs:30:41:30:42 | After ArgumentException ex [match] | false | +| Finally.cs:26:9:29:9 | catch (...) {...} | Finally.cs:30:41:30:42 | After ArgumentException ex [no-match] | false | +| Finally.cs:26:9:29:9 | catch (...) {...} | Finally.cs:41:16:41:24 | After access to type Exception [match] | false | +| Finally.cs:26:9:29:9 | catch (...) {...} | Finally.cs:41:16:41:24 | After access to type Exception [no-match] | false | +| Finally.cs:26:38:26:39 | After IOException ex [no-match] | Finally.cs:30:41:30:42 | After ArgumentException ex [match] | true | +| Finally.cs:26:38:26:39 | After IOException ex [no-match] | Finally.cs:30:41:30:42 | After ArgumentException ex [no-match] | false | +| Finally.cs:26:38:26:39 | After IOException ex [no-match] | Finally.cs:41:16:41:24 | After access to type Exception [match] | false | +| Finally.cs:26:38:26:39 | After IOException ex [no-match] | Finally.cs:41:16:41:24 | After access to type Exception [no-match] | false | +| Finally.cs:30:41:30:42 | After ArgumentException ex [no-match] | Finally.cs:41:16:41:24 | After access to type Exception [match] | true | +| Finally.cs:30:41:30:42 | After ArgumentException ex [no-match] | Finally.cs:41:16:41:24 | After access to type Exception [no-match] | false | +| Finally.cs:61:9:64:9 | catch (...) {...} | Finally.cs:61:38:61:39 | After IOException ex [match] | true | +| Finally.cs:61:9:64:9 | catch (...) {...} | Finally.cs:61:38:61:39 | After IOException ex [no-match] | false | | Finally.cs:61:9:64:9 | catch (...) {...} | Finally.cs:65:9:67:9 | After catch (...) {...} [no-match] | false | +| Finally.cs:61:9:64:9 | catch (...) {...} | Finally.cs:65:26:65:26 | After Exception e [match] | false | +| Finally.cs:61:9:64:9 | catch (...) {...} | Finally.cs:65:26:65:26 | After Exception e [no-match] | false | | Finally.cs:61:9:64:9 | catch (...) {...} | Finally.cs:65:35:65:51 | After ... != ... [false] | false | | Finally.cs:61:9:64:9 | catch (...) {...} | Finally.cs:65:35:65:51 | After ... != ... [true] | false | -| Finally.cs:65:9:67:9 | After catch (...) {...} [match] | Finally.cs:65:35:65:51 | After ... != ... [false] | false | -| Finally.cs:65:9:67:9 | After catch (...) {...} [match] | Finally.cs:65:35:65:51 | After ... != ... [true] | true | +| Finally.cs:61:38:61:39 | After IOException ex [no-match] | Finally.cs:65:26:65:26 | After Exception e [match] | true | +| Finally.cs:61:38:61:39 | After IOException ex [no-match] | Finally.cs:65:26:65:26 | After Exception e [no-match] | false | +| Finally.cs:61:38:61:39 | After IOException ex [no-match] | Finally.cs:65:35:65:51 | After ... != ... [false] | true | +| Finally.cs:61:38:61:39 | After IOException ex [no-match] | Finally.cs:65:35:65:51 | After ... != ... [true] | true | +| Finally.cs:65:26:65:26 | After Exception e [match] | Finally.cs:65:35:65:51 | After ... != ... [false] | false | +| Finally.cs:65:26:65:26 | After Exception e [match] | Finally.cs:65:35:65:51 | After ... != ... [true] | true | | Finally.cs:77:9:100:9 | [LoopHeader] while (...) ... | Finally.cs:74:10:74:11 | Exceptional Exit | true | | Finally.cs:77:9:100:9 | [LoopHeader] while (...) ... | Finally.cs:77:16:77:20 | After ... > ... [false] | false | | Finally.cs:77:9:100:9 | [LoopHeader] while (...) ... | Finally.cs:77:16:77:20 | After ... > ... [true] | true | @@ -354,33 +356,36 @@ conditionBlock | Finally.cs:158:21:158:31 | After access to property Length | Finally.cs:158:21:158:36 | After ... == ... [false] | false | | Finally.cs:158:21:158:31 | After access to property Length | Finally.cs:158:21:158:36 | After ... == ... [true] | true | | Finally.cs:158:21:158:31 | After access to property Length | Finally.cs:159:27:159:44 | After object creation of type Exception | true | -| Finally.cs:161:13:164:13 | After catch (...) {...} [match] | Finally.cs:161:39:161:54 | After ... == ... [false] | false | -| Finally.cs:161:13:164:13 | After catch (...) {...} [match] | Finally.cs:161:39:161:54 | After ... == ... [true] | true | -| Finally.cs:161:13:164:13 | catch (...) {...} | Finally.cs:161:13:164:13 | After catch (...) {...} [match] | true | +| Finally.cs:161:13:164:13 | catch (...) {...} | Finally.cs:161:30:161:30 | After Exception e [match] | true | +| Finally.cs:161:13:164:13 | catch (...) {...} | Finally.cs:161:30:161:30 | After Exception e [no-match] | false | | Finally.cs:161:13:164:13 | catch (...) {...} | Finally.cs:161:39:161:54 | After ... == ... [false] | true | | Finally.cs:161:13:164:13 | catch (...) {...} | Finally.cs:161:39:161:54 | After ... == ... [true] | true | +| Finally.cs:161:30:161:30 | After Exception e [match] | Finally.cs:161:39:161:54 | After ... == ... [false] | false | +| Finally.cs:161:30:161:30 | After Exception e [match] | Finally.cs:161:39:161:54 | After ... == ... [true] | true | | Finally.cs:176:10:176:11 | Entry | Finally.cs:180:17:180:18 | After access to parameter b1 [false] | false | | Finally.cs:176:10:176:11 | Entry | Finally.cs:180:17:180:18 | After access to parameter b1 [true] | true | | Finally.cs:176:10:176:11 | Entry | Finally.cs:180:27:180:42 | After object creation of type ExceptionA | true | | Finally.cs:183:9:192:9 | {...} | Finally.cs:186:21:186:22 | After access to parameter b2 [false] | false | | Finally.cs:183:9:192:9 | {...} | Finally.cs:186:21:186:22 | After access to parameter b2 [true] | true | | Finally.cs:183:9:192:9 | {...} | Finally.cs:186:31:186:46 | After object creation of type ExceptionB | true | -| Finally.cs:183:9:192:9 | {...} | Finally.cs:188:13:191:13 | After catch (...) {...} [match] | true | | Finally.cs:183:9:192:9 | {...} | Finally.cs:188:13:191:13 | After catch (...) {...} [no-match] | true | | Finally.cs:183:9:192:9 | {...} | Finally.cs:188:13:191:13 | catch (...) {...} | true | +| Finally.cs:183:9:192:9 | {...} | Finally.cs:188:20:188:29 | After access to type ExceptionB [match] | true | +| Finally.cs:183:9:192:9 | {...} | Finally.cs:188:20:188:29 | After access to type ExceptionB [no-match] | true | | Finally.cs:183:9:192:9 | {...} | Finally.cs:188:38:188:39 | After access to parameter b2 [false] | true | | Finally.cs:183:9:192:9 | {...} | Finally.cs:188:38:188:39 | After access to parameter b2 [true] | true | | Finally.cs:183:9:192:9 | {...} | Finally.cs:190:21:190:22 | After access to parameter b1 [false] | true | | Finally.cs:183:9:192:9 | {...} | Finally.cs:190:21:190:22 | After access to parameter b1 [true] | true | -| Finally.cs:188:13:191:13 | After catch (...) {...} [match] | Finally.cs:188:38:188:39 | After access to parameter b2 [false] | false | -| Finally.cs:188:13:191:13 | After catch (...) {...} [match] | Finally.cs:188:38:188:39 | After access to parameter b2 [true] | true | -| Finally.cs:188:13:191:13 | After catch (...) {...} [match] | Finally.cs:190:21:190:22 | After access to parameter b1 [false] | true | -| Finally.cs:188:13:191:13 | After catch (...) {...} [match] | Finally.cs:190:21:190:22 | After access to parameter b1 [true] | true | -| Finally.cs:188:13:191:13 | catch (...) {...} | Finally.cs:188:13:191:13 | After catch (...) {...} [match] | true | +| Finally.cs:188:13:191:13 | catch (...) {...} | Finally.cs:188:20:188:29 | After access to type ExceptionB [match] | true | +| Finally.cs:188:13:191:13 | catch (...) {...} | Finally.cs:188:20:188:29 | After access to type ExceptionB [no-match] | false | | Finally.cs:188:13:191:13 | catch (...) {...} | Finally.cs:188:38:188:39 | After access to parameter b2 [false] | true | | Finally.cs:188:13:191:13 | catch (...) {...} | Finally.cs:188:38:188:39 | After access to parameter b2 [true] | true | | Finally.cs:188:13:191:13 | catch (...) {...} | Finally.cs:190:21:190:22 | After access to parameter b1 [false] | true | | Finally.cs:188:13:191:13 | catch (...) {...} | Finally.cs:190:21:190:22 | After access to parameter b1 [true] | true | +| Finally.cs:188:20:188:29 | After access to type ExceptionB [match] | Finally.cs:188:38:188:39 | After access to parameter b2 [false] | false | +| Finally.cs:188:20:188:29 | After access to type ExceptionB [match] | Finally.cs:188:38:188:39 | After access to parameter b2 [true] | true | +| Finally.cs:188:20:188:29 | After access to type ExceptionB [match] | Finally.cs:190:21:190:22 | After access to parameter b1 [false] | true | +| Finally.cs:188:20:188:29 | After access to type ExceptionB [match] | Finally.cs:190:21:190:22 | After access to parameter b1 [true] | true | | Finally.cs:188:38:188:39 | After access to parameter b2 [true] | Finally.cs:190:21:190:22 | After access to parameter b1 [false] | false | | Finally.cs:188:38:188:39 | After access to parameter b2 [true] | Finally.cs:190:21:190:22 | After access to parameter b1 [true] | true | | Finally.cs:195:10:195:12 | Entry | Finally.cs:199:17:199:18 | After access to parameter b1 [false] | false | diff --git a/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected b/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected index 5001f49300a..a5da568e89e 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected @@ -2816,16 +2816,20 @@ dominance | ExitMethods.cs:42:13:42:30 | call to method ErrorAlways | ExitMethods.cs:44:9:47:9 | catch (...) {...} | | ExitMethods.cs:42:13:42:31 | ...; | ExitMethods.cs:42:13:42:30 | Before call to method ErrorAlways | | ExitMethods.cs:42:25:42:29 | false | ExitMethods.cs:42:13:42:30 | call to method ErrorAlways | -| ExitMethods.cs:44:9:47:9 | After catch (...) {...} [match] | ExitMethods.cs:45:9:47:9 | {...} | | ExitMethods.cs:44:9:47:9 | After catch (...) {...} [no-match] | ExitMethods.cs:48:9:51:9 | catch (...) {...} | -| ExitMethods.cs:44:9:47:9 | catch (...) {...} | ExitMethods.cs:44:9:47:9 | After catch (...) {...} [match] | -| ExitMethods.cs:44:9:47:9 | catch (...) {...} | ExitMethods.cs:44:9:47:9 | After catch (...) {...} [no-match] | +| ExitMethods.cs:44:9:47:9 | catch (...) {...} | ExitMethods.cs:44:16:44:32 | access to type ArgumentException | +| ExitMethods.cs:44:16:44:32 | After access to type ArgumentException [match] | ExitMethods.cs:45:9:47:9 | {...} | +| ExitMethods.cs:44:16:44:32 | After access to type ArgumentException [no-match] | ExitMethods.cs:44:9:47:9 | After catch (...) {...} [no-match] | +| ExitMethods.cs:44:16:44:32 | access to type ArgumentException | ExitMethods.cs:44:16:44:32 | After access to type ArgumentException [match] | +| ExitMethods.cs:44:16:44:32 | access to type ArgumentException | ExitMethods.cs:44:16:44:32 | After access to type ArgumentException [no-match] | | ExitMethods.cs:45:9:47:9 | {...} | ExitMethods.cs:46:13:46:19 | Before return ...; | | ExitMethods.cs:46:13:46:19 | Before return ...; | ExitMethods.cs:46:13:46:19 | return ...; | -| ExitMethods.cs:48:9:51:9 | After catch (...) {...} [match] | ExitMethods.cs:49:9:51:9 | {...} | | ExitMethods.cs:48:9:51:9 | After catch (...) {...} [no-match] | ExitMethods.cs:38:10:38:11 | Exceptional Exit | -| ExitMethods.cs:48:9:51:9 | catch (...) {...} | ExitMethods.cs:48:9:51:9 | After catch (...) {...} [match] | -| ExitMethods.cs:48:9:51:9 | catch (...) {...} | ExitMethods.cs:48:9:51:9 | After catch (...) {...} [no-match] | +| ExitMethods.cs:48:9:51:9 | catch (...) {...} | ExitMethods.cs:48:16:48:24 | access to type Exception | +| ExitMethods.cs:48:16:48:24 | After access to type Exception [match] | ExitMethods.cs:49:9:51:9 | {...} | +| ExitMethods.cs:48:16:48:24 | After access to type Exception [no-match] | ExitMethods.cs:48:9:51:9 | After catch (...) {...} [no-match] | +| ExitMethods.cs:48:16:48:24 | access to type Exception | ExitMethods.cs:48:16:48:24 | After access to type Exception [match] | +| ExitMethods.cs:48:16:48:24 | access to type Exception | ExitMethods.cs:48:16:48:24 | After access to type Exception [no-match] | | ExitMethods.cs:49:9:51:9 | {...} | ExitMethods.cs:50:13:50:19 | Before return ...; | | ExitMethods.cs:50:13:50:19 | Before return ...; | ExitMethods.cs:50:13:50:19 | return ...; | | ExitMethods.cs:54:10:54:11 | Entry | ExitMethods.cs:55:5:58:5 | {...} | @@ -3124,20 +3128,22 @@ dominance | Finally.cs:23:13:23:38 | After ...; | Finally.cs:24:13:24:19 | Before return ...; | | Finally.cs:23:31:23:36 | "Try2" | Finally.cs:23:13:23:37 | call to method WriteLine | | Finally.cs:24:13:24:19 | Before return ...; | Finally.cs:24:13:24:19 | return ...; | -| Finally.cs:26:9:29:9 | After catch (...) {...} [match] | Finally.cs:26:38:26:39 | IOException ex | | Finally.cs:26:9:29:9 | After catch (...) {...} [no-match] | Finally.cs:30:9:40:9 | catch (...) {...} | -| Finally.cs:26:9:29:9 | catch (...) {...} | Finally.cs:26:9:29:9 | After catch (...) {...} [match] | -| Finally.cs:26:9:29:9 | catch (...) {...} | Finally.cs:26:9:29:9 | After catch (...) {...} [no-match] | -| Finally.cs:26:38:26:39 | IOException ex | Finally.cs:26:48:26:51 | true | +| Finally.cs:26:9:29:9 | catch (...) {...} | Finally.cs:26:38:26:39 | IOException ex | +| Finally.cs:26:38:26:39 | After IOException ex [match] | Finally.cs:26:48:26:51 | true | +| Finally.cs:26:38:26:39 | After IOException ex [no-match] | Finally.cs:26:9:29:9 | After catch (...) {...} [no-match] | +| Finally.cs:26:38:26:39 | IOException ex | Finally.cs:26:38:26:39 | After IOException ex [match] | +| Finally.cs:26:38:26:39 | IOException ex | Finally.cs:26:38:26:39 | After IOException ex [no-match] | | Finally.cs:26:48:26:51 | After true [true] | Finally.cs:27:9:29:9 | {...} | | Finally.cs:26:48:26:51 | true | Finally.cs:26:48:26:51 | After true [true] | | Finally.cs:27:9:29:9 | {...} | Finally.cs:28:13:28:18 | Before throw ...; | | Finally.cs:28:13:28:18 | Before throw ...; | Finally.cs:28:13:28:18 | throw ...; | -| Finally.cs:30:9:40:9 | After catch (...) {...} [match] | Finally.cs:30:41:30:42 | ArgumentException ex | | Finally.cs:30:9:40:9 | After catch (...) {...} [no-match] | Finally.cs:41:9:43:9 | catch (...) {...} | -| Finally.cs:30:9:40:9 | catch (...) {...} | Finally.cs:30:9:40:9 | After catch (...) {...} [match] | -| Finally.cs:30:9:40:9 | catch (...) {...} | Finally.cs:30:9:40:9 | After catch (...) {...} [no-match] | -| Finally.cs:30:41:30:42 | ArgumentException ex | Finally.cs:31:9:40:9 | {...} | +| Finally.cs:30:9:40:9 | catch (...) {...} | Finally.cs:30:41:30:42 | ArgumentException ex | +| Finally.cs:30:41:30:42 | After ArgumentException ex [match] | Finally.cs:31:9:40:9 | {...} | +| Finally.cs:30:41:30:42 | After ArgumentException ex [no-match] | Finally.cs:30:9:40:9 | After catch (...) {...} [no-match] | +| Finally.cs:30:41:30:42 | ArgumentException ex | Finally.cs:30:41:30:42 | After ArgumentException ex [match] | +| Finally.cs:30:41:30:42 | ArgumentException ex | Finally.cs:30:41:30:42 | After ArgumentException ex [no-match] | | Finally.cs:31:9:40:9 | {...} | Finally.cs:32:13:39:13 | try {...} ... | | Finally.cs:32:13:39:13 | try {...} ... | Finally.cs:33:13:35:13 | {...} | | Finally.cs:33:13:35:13 | {...} | Finally.cs:34:17:34:32 | if (...) ... | @@ -3152,12 +3158,13 @@ dominance | Finally.cs:38:23:38:43 | Before object creation of type Exception | Finally.cs:38:37:38:42 | "Boo!" | | Finally.cs:38:23:38:43 | object creation of type Exception | Finally.cs:38:23:38:43 | After object creation of type Exception | | Finally.cs:38:37:38:42 | "Boo!" | Finally.cs:38:23:38:43 | object creation of type Exception | -| Finally.cs:41:9:43:9 | After catch (...) {...} [match] | Finally.cs:42:9:43:9 | {...} | | Finally.cs:41:9:43:9 | After catch (...) {...} [no-match] | Finally.cs:44:9:47:9 | catch {...} | -| Finally.cs:41:9:43:9 | catch (...) {...} | Finally.cs:41:9:43:9 | After catch (...) {...} [match] | -| Finally.cs:41:9:43:9 | catch (...) {...} | Finally.cs:41:9:43:9 | After catch (...) {...} [no-match] | -| Finally.cs:44:9:47:9 | After catch {...} [match] | Finally.cs:45:9:47:9 | {...} | -| Finally.cs:44:9:47:9 | catch {...} | Finally.cs:44:9:47:9 | After catch {...} [match] | +| Finally.cs:41:9:43:9 | catch (...) {...} | Finally.cs:41:16:41:24 | access to type Exception | +| Finally.cs:41:16:41:24 | After access to type Exception [match] | Finally.cs:42:9:43:9 | {...} | +| Finally.cs:41:16:41:24 | After access to type Exception [no-match] | Finally.cs:41:9:43:9 | After catch (...) {...} [no-match] | +| Finally.cs:41:16:41:24 | access to type Exception | Finally.cs:41:16:41:24 | After access to type Exception [match] | +| Finally.cs:41:16:41:24 | access to type Exception | Finally.cs:41:16:41:24 | After access to type Exception [no-match] | +| Finally.cs:44:9:47:9 | catch {...} | Finally.cs:45:9:47:9 | {...} | | Finally.cs:45:9:47:9 | {...} | Finally.cs:46:13:46:19 | Before return ...; | | Finally.cs:46:13:46:19 | Before return ...; | Finally.cs:46:13:46:19 | return ...; | | Finally.cs:49:9:51:9 | After {...} | Finally.cs:19:10:19:11 | Exceptional Exit | @@ -3183,19 +3190,20 @@ dominance | Finally.cs:58:13:58:38 | After ...; | Finally.cs:59:13:59:19 | Before return ...; | | Finally.cs:58:31:58:36 | "Try3" | Finally.cs:58:13:58:37 | call to method WriteLine | | Finally.cs:59:13:59:19 | Before return ...; | Finally.cs:59:13:59:19 | return ...; | -| Finally.cs:61:9:64:9 | After catch (...) {...} [match] | Finally.cs:61:38:61:39 | IOException ex | | Finally.cs:61:9:64:9 | After catch (...) {...} [no-match] | Finally.cs:65:9:67:9 | catch (...) {...} | -| Finally.cs:61:9:64:9 | catch (...) {...} | Finally.cs:61:9:64:9 | After catch (...) {...} [match] | -| Finally.cs:61:9:64:9 | catch (...) {...} | Finally.cs:61:9:64:9 | After catch (...) {...} [no-match] | -| Finally.cs:61:38:61:39 | IOException ex | Finally.cs:61:48:61:51 | true | +| Finally.cs:61:9:64:9 | catch (...) {...} | Finally.cs:61:38:61:39 | IOException ex | +| Finally.cs:61:38:61:39 | After IOException ex [match] | Finally.cs:61:48:61:51 | true | +| Finally.cs:61:38:61:39 | After IOException ex [no-match] | Finally.cs:61:9:64:9 | After catch (...) {...} [no-match] | +| Finally.cs:61:38:61:39 | IOException ex | Finally.cs:61:38:61:39 | After IOException ex [match] | +| Finally.cs:61:38:61:39 | IOException ex | Finally.cs:61:38:61:39 | After IOException ex [no-match] | | Finally.cs:61:48:61:51 | After true [true] | Finally.cs:62:9:64:9 | {...} | | Finally.cs:61:48:61:51 | true | Finally.cs:61:48:61:51 | After true [true] | | Finally.cs:62:9:64:9 | {...} | Finally.cs:63:13:63:18 | Before throw ...; | | Finally.cs:63:13:63:18 | Before throw ...; | Finally.cs:63:13:63:18 | throw ...; | -| Finally.cs:65:9:67:9 | After catch (...) {...} [match] | Finally.cs:65:26:65:26 | Exception e | -| Finally.cs:65:9:67:9 | catch (...) {...} | Finally.cs:65:9:67:9 | After catch (...) {...} [match] | -| Finally.cs:65:9:67:9 | catch (...) {...} | Finally.cs:65:9:67:9 | After catch (...) {...} [no-match] | -| Finally.cs:65:26:65:26 | Exception e | Finally.cs:65:35:65:51 | Before ... != ... | +| Finally.cs:65:9:67:9 | catch (...) {...} | Finally.cs:65:26:65:26 | Exception e | +| Finally.cs:65:26:65:26 | After Exception e [match] | Finally.cs:65:35:65:51 | Before ... != ... | +| Finally.cs:65:26:65:26 | Exception e | Finally.cs:65:26:65:26 | After Exception e [match] | +| Finally.cs:65:26:65:26 | Exception e | Finally.cs:65:26:65:26 | After Exception e [no-match] | | Finally.cs:65:35:65:35 | access to local variable e | Finally.cs:65:35:65:43 | access to property Message | | Finally.cs:65:35:65:43 | After access to property Message | Finally.cs:65:48:65:51 | null | | Finally.cs:65:35:65:43 | Before access to property Message | Finally.cs:65:35:65:35 | access to local variable e | @@ -3468,11 +3476,11 @@ dominance | Finally.cs:159:27:159:44 | Before object creation of type Exception | Finally.cs:159:41:159:43 | "1" | | Finally.cs:159:27:159:44 | object creation of type Exception | Finally.cs:159:27:159:44 | After object creation of type Exception | | Finally.cs:159:41:159:43 | "1" | Finally.cs:159:27:159:44 | object creation of type Exception | -| Finally.cs:161:13:164:13 | After catch (...) {...} [match] | Finally.cs:161:30:161:30 | Exception e | | Finally.cs:161:13:164:13 | After catch (...) {...} [no-match] | Finally.cs:165:13:168:13 | catch {...} | -| Finally.cs:161:13:164:13 | catch (...) {...} | Finally.cs:161:13:164:13 | After catch (...) {...} [match] | -| Finally.cs:161:13:164:13 | catch (...) {...} | Finally.cs:161:13:164:13 | After catch (...) {...} [no-match] | -| Finally.cs:161:30:161:30 | Exception e | Finally.cs:161:39:161:54 | Before ... == ... | +| Finally.cs:161:13:164:13 | catch (...) {...} | Finally.cs:161:30:161:30 | Exception e | +| Finally.cs:161:30:161:30 | After Exception e [match] | Finally.cs:161:39:161:54 | Before ... == ... | +| Finally.cs:161:30:161:30 | Exception e | Finally.cs:161:30:161:30 | After Exception e [match] | +| Finally.cs:161:30:161:30 | Exception e | Finally.cs:161:30:161:30 | After Exception e [no-match] | | Finally.cs:161:39:161:39 | access to local variable e | Finally.cs:161:39:161:47 | access to property Message | | Finally.cs:161:39:161:47 | After access to property Message | Finally.cs:161:52:161:54 | "1" | | Finally.cs:161:39:161:47 | Before access to property Message | Finally.cs:161:39:161:39 | access to local variable e | @@ -3493,8 +3501,7 @@ dominance | Finally.cs:163:35:163:41 | Before access to array element | Finally.cs:163:35:163:38 | access to parameter args | | Finally.cs:163:35:163:41 | access to array element | Finally.cs:163:35:163:41 | After access to array element | | Finally.cs:163:40:163:40 | 0 | Finally.cs:163:35:163:41 | access to array element | -| Finally.cs:165:13:168:13 | After catch {...} [match] | Finally.cs:166:13:168:13 | {...} | -| Finally.cs:165:13:168:13 | catch {...} | Finally.cs:165:13:168:13 | After catch {...} [match] | +| Finally.cs:165:13:168:13 | catch {...} | Finally.cs:166:13:168:13 | {...} | | Finally.cs:166:13:168:13 | {...} | Finally.cs:167:17:167:38 | ...; | | Finally.cs:167:17:167:37 | After call to method WriteLine | Finally.cs:167:17:167:38 | After ...; | | Finally.cs:167:17:167:37 | Before call to method WriteLine | Finally.cs:167:35:167:36 | "" | @@ -3566,9 +3573,10 @@ dominance | Finally.cs:186:31:186:46 | Before object creation of type ExceptionB | Finally.cs:186:31:186:46 | object creation of type ExceptionB | | Finally.cs:186:31:186:46 | object creation of type ExceptionB | Finally.cs:186:31:186:46 | After object creation of type ExceptionB | | Finally.cs:186:31:186:46 | object creation of type ExceptionB | Finally.cs:188:13:191:13 | catch (...) {...} | -| Finally.cs:188:13:191:13 | After catch (...) {...} [match] | Finally.cs:188:38:188:39 | access to parameter b2 | -| Finally.cs:188:13:191:13 | catch (...) {...} | Finally.cs:188:13:191:13 | After catch (...) {...} [match] | -| Finally.cs:188:13:191:13 | catch (...) {...} | Finally.cs:188:13:191:13 | After catch (...) {...} [no-match] | +| Finally.cs:188:13:191:13 | catch (...) {...} | Finally.cs:188:20:188:29 | access to type ExceptionB | +| Finally.cs:188:20:188:29 | After access to type ExceptionB [match] | Finally.cs:188:38:188:39 | access to parameter b2 | +| Finally.cs:188:20:188:29 | access to type ExceptionB | Finally.cs:188:20:188:29 | After access to type ExceptionB [match] | +| Finally.cs:188:20:188:29 | access to type ExceptionB | Finally.cs:188:20:188:29 | After access to type ExceptionB [no-match] | | Finally.cs:188:38:188:39 | After access to parameter b2 [true] | Finally.cs:189:13:191:13 | {...} | | Finally.cs:188:38:188:39 | access to parameter b2 | Finally.cs:188:38:188:39 | After access to parameter b2 [false] | | Finally.cs:188:38:188:39 | access to parameter b2 | Finally.cs:188:38:188:39 | After access to parameter b2 [true] | @@ -3663,8 +3671,7 @@ dominance | Finally.cs:220:13:220:37 | ...; | Finally.cs:220:13:220:36 | Before call to method WriteLine | | Finally.cs:220:13:220:37 | After ...; | Finally.cs:219:9:221:9 | After {...} | | Finally.cs:220:31:220:35 | "Try" | Finally.cs:220:13:220:36 | call to method WriteLine | -| Finally.cs:222:9:225:9 | After catch {...} [match] | Finally.cs:223:9:225:9 | {...} | -| Finally.cs:222:9:225:9 | catch {...} | Finally.cs:222:9:225:9 | After catch {...} [match] | +| Finally.cs:222:9:225:9 | catch {...} | Finally.cs:223:9:225:9 | {...} | | Finally.cs:223:9:225:9 | {...} | Finally.cs:224:13:224:39 | ...; | | Finally.cs:224:13:224:38 | After call to method WriteLine | Finally.cs:224:13:224:39 | After ...; | | Finally.cs:224:13:224:38 | Before call to method WriteLine | Finally.cs:224:31:224:37 | "Catch" | @@ -10615,13 +10622,17 @@ postDominance | ExitMethods.cs:42:13:42:30 | call to method ErrorAlways | ExitMethods.cs:42:25:42:29 | false | | ExitMethods.cs:42:13:42:31 | ...; | ExitMethods.cs:41:9:43:9 | {...} | | ExitMethods.cs:42:25:42:29 | false | ExitMethods.cs:42:13:42:30 | Before call to method ErrorAlways | +| ExitMethods.cs:44:9:47:9 | After catch (...) {...} [no-match] | ExitMethods.cs:44:16:44:32 | After access to type ArgumentException [no-match] | | ExitMethods.cs:44:9:47:9 | catch (...) {...} | ExitMethods.cs:42:13:42:30 | call to method ErrorAlways | -| ExitMethods.cs:45:9:47:9 | {...} | ExitMethods.cs:44:9:47:9 | After catch (...) {...} [match] | +| ExitMethods.cs:44:16:44:32 | access to type ArgumentException | ExitMethods.cs:44:9:47:9 | catch (...) {...} | +| ExitMethods.cs:45:9:47:9 | {...} | ExitMethods.cs:44:16:44:32 | After access to type ArgumentException [match] | | ExitMethods.cs:46:13:46:19 | Before return ...; | ExitMethods.cs:45:9:47:9 | {...} | | ExitMethods.cs:46:13:46:19 | return ...; | ExitMethods.cs:46:13:46:19 | Before return ...; | -| ExitMethods.cs:48:9:51:9 | After catch (...) {...} [match] | ExitMethods.cs:48:9:51:9 | catch (...) {...} | +| ExitMethods.cs:48:9:51:9 | After catch (...) {...} [no-match] | ExitMethods.cs:48:16:48:24 | After access to type Exception [no-match] | | ExitMethods.cs:48:9:51:9 | catch (...) {...} | ExitMethods.cs:44:9:47:9 | After catch (...) {...} [no-match] | -| ExitMethods.cs:49:9:51:9 | {...} | ExitMethods.cs:48:9:51:9 | After catch (...) {...} [match] | +| ExitMethods.cs:48:16:48:24 | After access to type Exception [match] | ExitMethods.cs:48:16:48:24 | access to type Exception | +| ExitMethods.cs:48:16:48:24 | access to type Exception | ExitMethods.cs:48:9:51:9 | catch (...) {...} | +| ExitMethods.cs:49:9:51:9 | {...} | ExitMethods.cs:48:16:48:24 | After access to type Exception [match] | | ExitMethods.cs:50:13:50:19 | Before return ...; | ExitMethods.cs:49:9:51:9 | {...} | | ExitMethods.cs:50:13:50:19 | return ...; | ExitMethods.cs:50:13:50:19 | Before return ...; | | ExitMethods.cs:54:10:54:11 | Exceptional Exit | ExitMethods.cs:56:9:56:22 | call to method ErrorAlways2 | @@ -10911,15 +10922,17 @@ postDominance | Finally.cs:23:31:23:36 | "Try2" | Finally.cs:23:13:23:37 | Before call to method WriteLine | | Finally.cs:24:13:24:19 | Before return ...; | Finally.cs:23:13:23:38 | After ...; | | Finally.cs:24:13:24:19 | return ...; | Finally.cs:24:13:24:19 | Before return ...; | -| Finally.cs:26:38:26:39 | IOException ex | Finally.cs:26:9:29:9 | After catch (...) {...} [match] | +| Finally.cs:26:9:29:9 | After catch (...) {...} [no-match] | Finally.cs:26:38:26:39 | After IOException ex [no-match] | +| Finally.cs:26:38:26:39 | IOException ex | Finally.cs:26:9:29:9 | catch (...) {...} | | Finally.cs:26:48:26:51 | After true [true] | Finally.cs:26:48:26:51 | true | -| Finally.cs:26:48:26:51 | true | Finally.cs:26:38:26:39 | IOException ex | +| Finally.cs:26:48:26:51 | true | Finally.cs:26:38:26:39 | After IOException ex [match] | | Finally.cs:27:9:29:9 | {...} | Finally.cs:26:48:26:51 | After true [true] | | Finally.cs:28:13:28:18 | Before throw ...; | Finally.cs:27:9:29:9 | {...} | | Finally.cs:28:13:28:18 | throw ...; | Finally.cs:28:13:28:18 | Before throw ...; | +| Finally.cs:30:9:40:9 | After catch (...) {...} [no-match] | Finally.cs:30:41:30:42 | After ArgumentException ex [no-match] | | Finally.cs:30:9:40:9 | catch (...) {...} | Finally.cs:26:9:29:9 | After catch (...) {...} [no-match] | -| Finally.cs:30:41:30:42 | ArgumentException ex | Finally.cs:30:9:40:9 | After catch (...) {...} [match] | -| Finally.cs:31:9:40:9 | {...} | Finally.cs:30:41:30:42 | ArgumentException ex | +| Finally.cs:30:41:30:42 | ArgumentException ex | Finally.cs:30:9:40:9 | catch (...) {...} | +| Finally.cs:31:9:40:9 | {...} | Finally.cs:30:41:30:42 | After ArgumentException ex [match] | | Finally.cs:32:13:39:13 | try {...} ... | Finally.cs:31:9:40:9 | {...} | | Finally.cs:33:13:35:13 | {...} | Finally.cs:32:13:39:13 | try {...} ... | | Finally.cs:34:17:34:32 | if (...) ... | Finally.cs:33:13:35:13 | {...} | @@ -10934,11 +10947,12 @@ postDominance | Finally.cs:38:23:38:43 | Before object creation of type Exception | Finally.cs:38:17:38:44 | Before throw ...; | | Finally.cs:38:23:38:43 | object creation of type Exception | Finally.cs:38:37:38:42 | "Boo!" | | Finally.cs:38:37:38:42 | "Boo!" | Finally.cs:38:23:38:43 | Before object creation of type Exception | +| Finally.cs:41:9:43:9 | After catch (...) {...} [no-match] | Finally.cs:41:16:41:24 | After access to type Exception [no-match] | | Finally.cs:41:9:43:9 | catch (...) {...} | Finally.cs:30:9:40:9 | After catch (...) {...} [no-match] | -| Finally.cs:42:9:43:9 | {...} | Finally.cs:41:9:43:9 | After catch (...) {...} [match] | -| Finally.cs:44:9:47:9 | After catch {...} [match] | Finally.cs:44:9:47:9 | catch {...} | +| Finally.cs:41:16:41:24 | access to type Exception | Finally.cs:41:9:43:9 | catch (...) {...} | +| Finally.cs:42:9:43:9 | {...} | Finally.cs:41:16:41:24 | After access to type Exception [match] | | Finally.cs:44:9:47:9 | catch {...} | Finally.cs:41:9:43:9 | After catch (...) {...} [no-match] | -| Finally.cs:45:9:47:9 | {...} | Finally.cs:44:9:47:9 | After catch {...} [match] | +| Finally.cs:45:9:47:9 | {...} | Finally.cs:44:9:47:9 | catch {...} | | Finally.cs:46:13:46:19 | Before return ...; | Finally.cs:45:9:47:9 | {...} | | Finally.cs:46:13:46:19 | return ...; | Finally.cs:46:13:46:19 | Before return ...; | | Finally.cs:49:9:51:9 | After {...} | Finally.cs:50:13:50:41 | After ...; | @@ -10966,21 +10980,23 @@ postDominance | Finally.cs:58:31:58:36 | "Try3" | Finally.cs:58:13:58:37 | Before call to method WriteLine | | Finally.cs:59:13:59:19 | Before return ...; | Finally.cs:58:13:58:38 | After ...; | | Finally.cs:59:13:59:19 | return ...; | Finally.cs:59:13:59:19 | Before return ...; | -| Finally.cs:61:38:61:39 | IOException ex | Finally.cs:61:9:64:9 | After catch (...) {...} [match] | +| Finally.cs:61:9:64:9 | After catch (...) {...} [no-match] | Finally.cs:61:38:61:39 | After IOException ex [no-match] | +| Finally.cs:61:38:61:39 | IOException ex | Finally.cs:61:9:64:9 | catch (...) {...} | | Finally.cs:61:48:61:51 | After true [true] | Finally.cs:61:48:61:51 | true | -| Finally.cs:61:48:61:51 | true | Finally.cs:61:38:61:39 | IOException ex | +| Finally.cs:61:48:61:51 | true | Finally.cs:61:38:61:39 | After IOException ex [match] | | Finally.cs:62:9:64:9 | {...} | Finally.cs:61:48:61:51 | After true [true] | | Finally.cs:63:13:63:18 | Before throw ...; | Finally.cs:62:9:64:9 | {...} | | Finally.cs:63:13:63:18 | throw ...; | Finally.cs:63:13:63:18 | Before throw ...; | +| Finally.cs:65:9:67:9 | After catch (...) {...} [no-match] | Finally.cs:65:26:65:26 | After Exception e [no-match] | | Finally.cs:65:9:67:9 | After catch (...) {...} [no-match] | Finally.cs:65:35:65:51 | After ... != ... [false] | | Finally.cs:65:9:67:9 | catch (...) {...} | Finally.cs:61:9:64:9 | After catch (...) {...} [no-match] | -| Finally.cs:65:26:65:26 | Exception e | Finally.cs:65:9:67:9 | After catch (...) {...} [match] | +| Finally.cs:65:26:65:26 | Exception e | Finally.cs:65:9:67:9 | catch (...) {...} | | Finally.cs:65:35:65:35 | access to local variable e | Finally.cs:65:35:65:43 | Before access to property Message | | Finally.cs:65:35:65:43 | After access to property Message | Finally.cs:65:35:65:43 | access to property Message | | Finally.cs:65:35:65:43 | Before access to property Message | Finally.cs:65:35:65:51 | Before ... != ... | | Finally.cs:65:35:65:43 | access to property Message | Finally.cs:65:35:65:35 | access to local variable e | | Finally.cs:65:35:65:51 | ... != ... | Finally.cs:65:48:65:51 | null | -| Finally.cs:65:35:65:51 | Before ... != ... | Finally.cs:65:26:65:26 | Exception e | +| Finally.cs:65:35:65:51 | Before ... != ... | Finally.cs:65:26:65:26 | After Exception e [match] | | Finally.cs:65:48:65:51 | null | Finally.cs:65:35:65:43 | After access to property Message | | Finally.cs:66:9:67:9 | {...} | Finally.cs:65:35:65:51 | After ... != ... [true] | | Finally.cs:69:9:71:9 | After {...} | Finally.cs:70:13:70:41 | After ...; | @@ -11237,16 +11253,17 @@ postDominance | Finally.cs:159:27:159:44 | Before object creation of type Exception | Finally.cs:159:21:159:45 | Before throw ...; | | Finally.cs:159:27:159:44 | object creation of type Exception | Finally.cs:159:41:159:43 | "1" | | Finally.cs:159:41:159:43 | "1" | Finally.cs:159:27:159:44 | Before object creation of type Exception | +| Finally.cs:161:13:164:13 | After catch (...) {...} [no-match] | Finally.cs:161:30:161:30 | After Exception e [no-match] | | Finally.cs:161:13:164:13 | After catch (...) {...} [no-match] | Finally.cs:161:39:161:54 | After ... == ... [false] | | Finally.cs:161:13:164:13 | catch (...) {...} | Finally.cs:159:21:159:45 | throw ...; | | Finally.cs:161:13:164:13 | catch (...) {...} | Finally.cs:159:27:159:44 | object creation of type Exception | -| Finally.cs:161:30:161:30 | Exception e | Finally.cs:161:13:164:13 | After catch (...) {...} [match] | +| Finally.cs:161:30:161:30 | Exception e | Finally.cs:161:13:164:13 | catch (...) {...} | | Finally.cs:161:39:161:39 | access to local variable e | Finally.cs:161:39:161:47 | Before access to property Message | | Finally.cs:161:39:161:47 | After access to property Message | Finally.cs:161:39:161:47 | access to property Message | | Finally.cs:161:39:161:47 | Before access to property Message | Finally.cs:161:39:161:54 | Before ... == ... | | Finally.cs:161:39:161:47 | access to property Message | Finally.cs:161:39:161:39 | access to local variable e | | Finally.cs:161:39:161:54 | ... == ... | Finally.cs:161:52:161:54 | "1" | -| Finally.cs:161:39:161:54 | Before ... == ... | Finally.cs:161:30:161:30 | Exception e | +| Finally.cs:161:39:161:54 | Before ... == ... | Finally.cs:161:30:161:30 | After Exception e [match] | | Finally.cs:161:52:161:54 | "1" | Finally.cs:161:39:161:47 | After access to property Message | | Finally.cs:162:13:164:13 | After {...} | Finally.cs:163:17:163:43 | After ...; | | Finally.cs:162:13:164:13 | {...} | Finally.cs:161:39:161:54 | After ... == ... [true] | @@ -11260,10 +11277,9 @@ postDominance | Finally.cs:163:35:163:41 | Before access to array element | Finally.cs:163:17:163:42 | Before call to method WriteLine | | Finally.cs:163:35:163:41 | access to array element | Finally.cs:163:40:163:40 | 0 | | Finally.cs:163:40:163:40 | 0 | Finally.cs:163:35:163:38 | access to parameter args | -| Finally.cs:165:13:168:13 | After catch {...} [match] | Finally.cs:165:13:168:13 | catch {...} | | Finally.cs:165:13:168:13 | catch {...} | Finally.cs:161:13:164:13 | After catch (...) {...} [no-match] | | Finally.cs:166:13:168:13 | After {...} | Finally.cs:167:17:167:38 | After ...; | -| Finally.cs:166:13:168:13 | {...} | Finally.cs:165:13:168:13 | After catch {...} [match] | +| Finally.cs:166:13:168:13 | {...} | Finally.cs:165:13:168:13 | catch {...} | | Finally.cs:167:17:167:37 | After call to method WriteLine | Finally.cs:167:17:167:37 | call to method WriteLine | | Finally.cs:167:17:167:37 | Before call to method WriteLine | Finally.cs:167:17:167:38 | ...; | | Finally.cs:167:17:167:37 | call to method WriteLine | Finally.cs:167:35:167:36 | "" | @@ -11332,11 +11348,12 @@ postDominance | Finally.cs:186:25:186:47 | throw ...; | Finally.cs:186:31:186:46 | After object creation of type ExceptionB | | Finally.cs:186:31:186:46 | Before object creation of type ExceptionB | Finally.cs:186:25:186:47 | Before throw ...; | | Finally.cs:186:31:186:46 | object creation of type ExceptionB | Finally.cs:186:31:186:46 | Before object creation of type ExceptionB | -| Finally.cs:188:13:191:13 | After catch (...) {...} [match] | Finally.cs:188:13:191:13 | catch (...) {...} | | Finally.cs:188:13:191:13 | catch (...) {...} | Finally.cs:186:25:186:47 | throw ...; | | Finally.cs:188:13:191:13 | catch (...) {...} | Finally.cs:186:31:186:46 | object creation of type ExceptionB | +| Finally.cs:188:20:188:29 | After access to type ExceptionB [match] | Finally.cs:188:20:188:29 | access to type ExceptionB | +| Finally.cs:188:20:188:29 | access to type ExceptionB | Finally.cs:188:13:191:13 | catch (...) {...} | | Finally.cs:188:38:188:39 | After access to parameter b2 [true] | Finally.cs:188:38:188:39 | access to parameter b2 | -| Finally.cs:188:38:188:39 | access to parameter b2 | Finally.cs:188:13:191:13 | After catch (...) {...} [match] | +| Finally.cs:188:38:188:39 | access to parameter b2 | Finally.cs:188:20:188:29 | After access to type ExceptionB [match] | | Finally.cs:189:13:191:13 | After {...} | Finally.cs:190:17:190:47 | After if (...) ... | | Finally.cs:189:13:191:13 | {...} | Finally.cs:188:38:188:39 | After access to parameter b2 [true] | | Finally.cs:190:17:190:47 | After if (...) ... | Finally.cs:190:21:190:22 | After access to parameter b1 [false] | @@ -11426,9 +11443,8 @@ postDominance | Finally.cs:220:13:220:37 | ...; | Finally.cs:219:9:221:9 | {...} | | Finally.cs:220:13:220:37 | After ...; | Finally.cs:220:13:220:36 | After call to method WriteLine | | Finally.cs:220:31:220:35 | "Try" | Finally.cs:220:13:220:36 | Before call to method WriteLine | -| Finally.cs:222:9:225:9 | After catch {...} [match] | Finally.cs:222:9:225:9 | catch {...} | | Finally.cs:223:9:225:9 | After {...} | Finally.cs:224:13:224:39 | After ...; | -| Finally.cs:223:9:225:9 | {...} | Finally.cs:222:9:225:9 | After catch {...} [match] | +| Finally.cs:223:9:225:9 | {...} | Finally.cs:222:9:225:9 | catch {...} | | Finally.cs:224:13:224:38 | After call to method WriteLine | Finally.cs:224:13:224:38 | call to method WriteLine | | Finally.cs:224:13:224:38 | Before call to method WriteLine | Finally.cs:224:13:224:39 | ...; | | Finally.cs:224:13:224:38 | call to method WriteLine | Finally.cs:224:31:224:37 | "Catch" | @@ -17407,18 +17423,18 @@ blockDominance | ExitMethods.cs:38:10:38:11 | Entry | ExitMethods.cs:38:10:38:11 | Entry | | ExitMethods.cs:38:10:38:11 | Entry | ExitMethods.cs:38:10:38:11 | Exit | | ExitMethods.cs:38:10:38:11 | Entry | ExitMethods.cs:38:10:38:11 | Normal Exit | -| ExitMethods.cs:38:10:38:11 | Entry | ExitMethods.cs:44:9:47:9 | After catch (...) {...} [match] | -| ExitMethods.cs:38:10:38:11 | Entry | ExitMethods.cs:44:9:47:9 | After catch (...) {...} [no-match] | -| ExitMethods.cs:38:10:38:11 | Entry | ExitMethods.cs:48:9:51:9 | After catch (...) {...} [match] | -| ExitMethods.cs:38:10:38:11 | Entry | ExitMethods.cs:48:9:51:9 | After catch (...) {...} [no-match] | +| ExitMethods.cs:38:10:38:11 | Entry | ExitMethods.cs:44:16:44:32 | After access to type ArgumentException [match] | +| ExitMethods.cs:38:10:38:11 | Entry | ExitMethods.cs:44:16:44:32 | After access to type ArgumentException [no-match] | +| ExitMethods.cs:38:10:38:11 | Entry | ExitMethods.cs:48:16:48:24 | After access to type Exception [match] | +| ExitMethods.cs:38:10:38:11 | Entry | ExitMethods.cs:48:16:48:24 | After access to type Exception [no-match] | | ExitMethods.cs:38:10:38:11 | Exit | ExitMethods.cs:38:10:38:11 | Exit | | ExitMethods.cs:38:10:38:11 | Normal Exit | ExitMethods.cs:38:10:38:11 | Normal Exit | -| ExitMethods.cs:44:9:47:9 | After catch (...) {...} [match] | ExitMethods.cs:44:9:47:9 | After catch (...) {...} [match] | -| ExitMethods.cs:44:9:47:9 | After catch (...) {...} [no-match] | ExitMethods.cs:44:9:47:9 | After catch (...) {...} [no-match] | -| ExitMethods.cs:44:9:47:9 | After catch (...) {...} [no-match] | ExitMethods.cs:48:9:51:9 | After catch (...) {...} [match] | -| ExitMethods.cs:44:9:47:9 | After catch (...) {...} [no-match] | ExitMethods.cs:48:9:51:9 | After catch (...) {...} [no-match] | -| ExitMethods.cs:48:9:51:9 | After catch (...) {...} [match] | ExitMethods.cs:48:9:51:9 | After catch (...) {...} [match] | -| ExitMethods.cs:48:9:51:9 | After catch (...) {...} [no-match] | ExitMethods.cs:48:9:51:9 | After catch (...) {...} [no-match] | +| ExitMethods.cs:44:16:44:32 | After access to type ArgumentException [match] | ExitMethods.cs:44:16:44:32 | After access to type ArgumentException [match] | +| ExitMethods.cs:44:16:44:32 | After access to type ArgumentException [no-match] | ExitMethods.cs:44:16:44:32 | After access to type ArgumentException [no-match] | +| ExitMethods.cs:44:16:44:32 | After access to type ArgumentException [no-match] | ExitMethods.cs:48:16:48:24 | After access to type Exception [match] | +| ExitMethods.cs:44:16:44:32 | After access to type ArgumentException [no-match] | ExitMethods.cs:48:16:48:24 | After access to type Exception [no-match] | +| ExitMethods.cs:48:16:48:24 | After access to type Exception [match] | ExitMethods.cs:48:16:48:24 | After access to type Exception [match] | +| ExitMethods.cs:48:16:48:24 | After access to type Exception [no-match] | ExitMethods.cs:48:16:48:24 | After access to type Exception [no-match] | | ExitMethods.cs:54:10:54:11 | Entry | ExitMethods.cs:54:10:54:11 | Entry | | ExitMethods.cs:60:10:60:11 | Entry | ExitMethods.cs:60:10:60:11 | Entry | | ExitMethods.cs:66:17:66:26 | Entry | ExitMethods.cs:66:17:66:26 | Entry | @@ -17502,38 +17518,38 @@ blockDominance | Finally.cs:19:10:19:11 | Entry | Finally.cs:19:10:19:11 | Normal Exit | | Finally.cs:19:10:19:11 | Entry | Finally.cs:21:9:51:9 | After try {...} ... | | Finally.cs:19:10:19:11 | Entry | Finally.cs:23:13:23:37 | After call to method WriteLine | -| Finally.cs:19:10:19:11 | Entry | Finally.cs:26:9:29:9 | After catch (...) {...} [match] | -| Finally.cs:19:10:19:11 | Entry | Finally.cs:26:9:29:9 | After catch (...) {...} [no-match] | | Finally.cs:19:10:19:11 | Entry | Finally.cs:26:9:29:9 | catch (...) {...} | -| Finally.cs:19:10:19:11 | Entry | Finally.cs:30:9:40:9 | After catch (...) {...} [match] | -| Finally.cs:19:10:19:11 | Entry | Finally.cs:30:9:40:9 | After catch (...) {...} [no-match] | -| Finally.cs:19:10:19:11 | Entry | Finally.cs:41:9:43:9 | After catch (...) {...} [match] | -| Finally.cs:19:10:19:11 | Entry | Finally.cs:41:9:43:9 | After catch (...) {...} [no-match] | +| Finally.cs:19:10:19:11 | Entry | Finally.cs:26:38:26:39 | After IOException ex [match] | +| Finally.cs:19:10:19:11 | Entry | Finally.cs:26:38:26:39 | After IOException ex [no-match] | +| Finally.cs:19:10:19:11 | Entry | Finally.cs:30:41:30:42 | After ArgumentException ex [match] | +| Finally.cs:19:10:19:11 | Entry | Finally.cs:30:41:30:42 | After ArgumentException ex [no-match] | +| Finally.cs:19:10:19:11 | Entry | Finally.cs:41:16:41:24 | After access to type Exception [match] | +| Finally.cs:19:10:19:11 | Entry | Finally.cs:41:16:41:24 | After access to type Exception [no-match] | | Finally.cs:19:10:19:11 | Entry | Finally.cs:49:9:51:9 | {...} | | Finally.cs:19:10:19:11 | Exceptional Exit | Finally.cs:19:10:19:11 | Exceptional Exit | | Finally.cs:19:10:19:11 | Exit | Finally.cs:19:10:19:11 | Exit | | Finally.cs:19:10:19:11 | Normal Exit | Finally.cs:19:10:19:11 | Normal Exit | | Finally.cs:21:9:51:9 | After try {...} ... | Finally.cs:21:9:51:9 | After try {...} ... | | Finally.cs:23:13:23:37 | After call to method WriteLine | Finally.cs:23:13:23:37 | After call to method WriteLine | -| Finally.cs:26:9:29:9 | After catch (...) {...} [match] | Finally.cs:26:9:29:9 | After catch (...) {...} [match] | -| Finally.cs:26:9:29:9 | After catch (...) {...} [no-match] | Finally.cs:26:9:29:9 | After catch (...) {...} [no-match] | -| Finally.cs:26:9:29:9 | After catch (...) {...} [no-match] | Finally.cs:30:9:40:9 | After catch (...) {...} [match] | -| Finally.cs:26:9:29:9 | After catch (...) {...} [no-match] | Finally.cs:30:9:40:9 | After catch (...) {...} [no-match] | -| Finally.cs:26:9:29:9 | After catch (...) {...} [no-match] | Finally.cs:41:9:43:9 | After catch (...) {...} [match] | -| Finally.cs:26:9:29:9 | After catch (...) {...} [no-match] | Finally.cs:41:9:43:9 | After catch (...) {...} [no-match] | -| Finally.cs:26:9:29:9 | catch (...) {...} | Finally.cs:26:9:29:9 | After catch (...) {...} [match] | -| Finally.cs:26:9:29:9 | catch (...) {...} | Finally.cs:26:9:29:9 | After catch (...) {...} [no-match] | | Finally.cs:26:9:29:9 | catch (...) {...} | Finally.cs:26:9:29:9 | catch (...) {...} | -| Finally.cs:26:9:29:9 | catch (...) {...} | Finally.cs:30:9:40:9 | After catch (...) {...} [match] | -| Finally.cs:26:9:29:9 | catch (...) {...} | Finally.cs:30:9:40:9 | After catch (...) {...} [no-match] | -| Finally.cs:26:9:29:9 | catch (...) {...} | Finally.cs:41:9:43:9 | After catch (...) {...} [match] | -| Finally.cs:26:9:29:9 | catch (...) {...} | Finally.cs:41:9:43:9 | After catch (...) {...} [no-match] | -| Finally.cs:30:9:40:9 | After catch (...) {...} [match] | Finally.cs:30:9:40:9 | After catch (...) {...} [match] | -| Finally.cs:30:9:40:9 | After catch (...) {...} [no-match] | Finally.cs:30:9:40:9 | After catch (...) {...} [no-match] | -| Finally.cs:30:9:40:9 | After catch (...) {...} [no-match] | Finally.cs:41:9:43:9 | After catch (...) {...} [match] | -| Finally.cs:30:9:40:9 | After catch (...) {...} [no-match] | Finally.cs:41:9:43:9 | After catch (...) {...} [no-match] | -| Finally.cs:41:9:43:9 | After catch (...) {...} [match] | Finally.cs:41:9:43:9 | After catch (...) {...} [match] | -| Finally.cs:41:9:43:9 | After catch (...) {...} [no-match] | Finally.cs:41:9:43:9 | After catch (...) {...} [no-match] | +| Finally.cs:26:9:29:9 | catch (...) {...} | Finally.cs:26:38:26:39 | After IOException ex [match] | +| Finally.cs:26:9:29:9 | catch (...) {...} | Finally.cs:26:38:26:39 | After IOException ex [no-match] | +| Finally.cs:26:9:29:9 | catch (...) {...} | Finally.cs:30:41:30:42 | After ArgumentException ex [match] | +| Finally.cs:26:9:29:9 | catch (...) {...} | Finally.cs:30:41:30:42 | After ArgumentException ex [no-match] | +| Finally.cs:26:9:29:9 | catch (...) {...} | Finally.cs:41:16:41:24 | After access to type Exception [match] | +| Finally.cs:26:9:29:9 | catch (...) {...} | Finally.cs:41:16:41:24 | After access to type Exception [no-match] | +| Finally.cs:26:38:26:39 | After IOException ex [match] | Finally.cs:26:38:26:39 | After IOException ex [match] | +| Finally.cs:26:38:26:39 | After IOException ex [no-match] | Finally.cs:26:38:26:39 | After IOException ex [no-match] | +| Finally.cs:26:38:26:39 | After IOException ex [no-match] | Finally.cs:30:41:30:42 | After ArgumentException ex [match] | +| Finally.cs:26:38:26:39 | After IOException ex [no-match] | Finally.cs:30:41:30:42 | After ArgumentException ex [no-match] | +| Finally.cs:26:38:26:39 | After IOException ex [no-match] | Finally.cs:41:16:41:24 | After access to type Exception [match] | +| Finally.cs:26:38:26:39 | After IOException ex [no-match] | Finally.cs:41:16:41:24 | After access to type Exception [no-match] | +| Finally.cs:30:41:30:42 | After ArgumentException ex [match] | Finally.cs:30:41:30:42 | After ArgumentException ex [match] | +| Finally.cs:30:41:30:42 | After ArgumentException ex [no-match] | Finally.cs:30:41:30:42 | After ArgumentException ex [no-match] | +| Finally.cs:30:41:30:42 | After ArgumentException ex [no-match] | Finally.cs:41:16:41:24 | After access to type Exception [match] | +| Finally.cs:30:41:30:42 | After ArgumentException ex [no-match] | Finally.cs:41:16:41:24 | After access to type Exception [no-match] | +| Finally.cs:41:16:41:24 | After access to type Exception [match] | Finally.cs:41:16:41:24 | After access to type Exception [match] | +| Finally.cs:41:16:41:24 | After access to type Exception [no-match] | Finally.cs:41:16:41:24 | After access to type Exception [no-match] | | Finally.cs:49:9:51:9 | {...} | Finally.cs:19:10:19:11 | Exceptional Exit | | Finally.cs:49:9:51:9 | {...} | Finally.cs:19:10:19:11 | Exit | | Finally.cs:49:9:51:9 | {...} | Finally.cs:19:10:19:11 | Normal Exit | @@ -17545,11 +17561,12 @@ blockDominance | Finally.cs:54:10:54:11 | Entry | Finally.cs:54:10:54:11 | Normal Exit | | Finally.cs:54:10:54:11 | Entry | Finally.cs:56:9:71:9 | After try {...} ... | | Finally.cs:54:10:54:11 | Entry | Finally.cs:58:13:58:37 | After call to method WriteLine | -| Finally.cs:54:10:54:11 | Entry | Finally.cs:61:9:64:9 | After catch (...) {...} [match] | -| Finally.cs:54:10:54:11 | Entry | Finally.cs:61:9:64:9 | After catch (...) {...} [no-match] | | Finally.cs:54:10:54:11 | Entry | Finally.cs:61:9:64:9 | catch (...) {...} | -| Finally.cs:54:10:54:11 | Entry | Finally.cs:65:9:67:9 | After catch (...) {...} [match] | +| Finally.cs:54:10:54:11 | Entry | Finally.cs:61:38:61:39 | After IOException ex [match] | +| Finally.cs:54:10:54:11 | Entry | Finally.cs:61:38:61:39 | After IOException ex [no-match] | | Finally.cs:54:10:54:11 | Entry | Finally.cs:65:9:67:9 | After catch (...) {...} [no-match] | +| Finally.cs:54:10:54:11 | Entry | Finally.cs:65:26:65:26 | After Exception e [match] | +| Finally.cs:54:10:54:11 | Entry | Finally.cs:65:26:65:26 | After Exception e [no-match] | | Finally.cs:54:10:54:11 | Entry | Finally.cs:65:35:65:51 | After ... != ... [false] | | Finally.cs:54:10:54:11 | Entry | Finally.cs:65:35:65:51 | After ... != ... [true] | | Finally.cs:54:10:54:11 | Entry | Finally.cs:69:9:71:9 | {...} | @@ -17558,23 +17575,26 @@ blockDominance | Finally.cs:54:10:54:11 | Normal Exit | Finally.cs:54:10:54:11 | Normal Exit | | Finally.cs:56:9:71:9 | After try {...} ... | Finally.cs:56:9:71:9 | After try {...} ... | | Finally.cs:58:13:58:37 | After call to method WriteLine | Finally.cs:58:13:58:37 | After call to method WriteLine | -| Finally.cs:61:9:64:9 | After catch (...) {...} [match] | Finally.cs:61:9:64:9 | After catch (...) {...} [match] | -| Finally.cs:61:9:64:9 | After catch (...) {...} [no-match] | Finally.cs:61:9:64:9 | After catch (...) {...} [no-match] | -| Finally.cs:61:9:64:9 | After catch (...) {...} [no-match] | Finally.cs:65:9:67:9 | After catch (...) {...} [match] | -| Finally.cs:61:9:64:9 | After catch (...) {...} [no-match] | Finally.cs:65:9:67:9 | After catch (...) {...} [no-match] | -| Finally.cs:61:9:64:9 | After catch (...) {...} [no-match] | Finally.cs:65:35:65:51 | After ... != ... [false] | -| Finally.cs:61:9:64:9 | After catch (...) {...} [no-match] | Finally.cs:65:35:65:51 | After ... != ... [true] | -| Finally.cs:61:9:64:9 | catch (...) {...} | Finally.cs:61:9:64:9 | After catch (...) {...} [match] | -| Finally.cs:61:9:64:9 | catch (...) {...} | Finally.cs:61:9:64:9 | After catch (...) {...} [no-match] | | Finally.cs:61:9:64:9 | catch (...) {...} | Finally.cs:61:9:64:9 | catch (...) {...} | -| Finally.cs:61:9:64:9 | catch (...) {...} | Finally.cs:65:9:67:9 | After catch (...) {...} [match] | +| Finally.cs:61:9:64:9 | catch (...) {...} | Finally.cs:61:38:61:39 | After IOException ex [match] | +| Finally.cs:61:9:64:9 | catch (...) {...} | Finally.cs:61:38:61:39 | After IOException ex [no-match] | | Finally.cs:61:9:64:9 | catch (...) {...} | Finally.cs:65:9:67:9 | After catch (...) {...} [no-match] | +| Finally.cs:61:9:64:9 | catch (...) {...} | Finally.cs:65:26:65:26 | After Exception e [match] | +| Finally.cs:61:9:64:9 | catch (...) {...} | Finally.cs:65:26:65:26 | After Exception e [no-match] | | Finally.cs:61:9:64:9 | catch (...) {...} | Finally.cs:65:35:65:51 | After ... != ... [false] | | Finally.cs:61:9:64:9 | catch (...) {...} | Finally.cs:65:35:65:51 | After ... != ... [true] | -| Finally.cs:65:9:67:9 | After catch (...) {...} [match] | Finally.cs:65:9:67:9 | After catch (...) {...} [match] | -| Finally.cs:65:9:67:9 | After catch (...) {...} [match] | Finally.cs:65:35:65:51 | After ... != ... [false] | -| Finally.cs:65:9:67:9 | After catch (...) {...} [match] | Finally.cs:65:35:65:51 | After ... != ... [true] | +| Finally.cs:61:38:61:39 | After IOException ex [match] | Finally.cs:61:38:61:39 | After IOException ex [match] | +| Finally.cs:61:38:61:39 | After IOException ex [no-match] | Finally.cs:61:38:61:39 | After IOException ex [no-match] | +| Finally.cs:61:38:61:39 | After IOException ex [no-match] | Finally.cs:65:9:67:9 | After catch (...) {...} [no-match] | +| Finally.cs:61:38:61:39 | After IOException ex [no-match] | Finally.cs:65:26:65:26 | After Exception e [match] | +| Finally.cs:61:38:61:39 | After IOException ex [no-match] | Finally.cs:65:26:65:26 | After Exception e [no-match] | +| Finally.cs:61:38:61:39 | After IOException ex [no-match] | Finally.cs:65:35:65:51 | After ... != ... [false] | +| Finally.cs:61:38:61:39 | After IOException ex [no-match] | Finally.cs:65:35:65:51 | After ... != ... [true] | | Finally.cs:65:9:67:9 | After catch (...) {...} [no-match] | Finally.cs:65:9:67:9 | After catch (...) {...} [no-match] | +| Finally.cs:65:26:65:26 | After Exception e [match] | Finally.cs:65:26:65:26 | After Exception e [match] | +| Finally.cs:65:26:65:26 | After Exception e [match] | Finally.cs:65:35:65:51 | After ... != ... [false] | +| Finally.cs:65:26:65:26 | After Exception e [match] | Finally.cs:65:35:65:51 | After ... != ... [true] | +| Finally.cs:65:26:65:26 | After Exception e [no-match] | Finally.cs:65:26:65:26 | After Exception e [no-match] | | Finally.cs:65:35:65:51 | After ... != ... [false] | Finally.cs:65:35:65:51 | After ... != ... [false] | | Finally.cs:65:35:65:51 | After ... != ... [true] | Finally.cs:65:35:65:51 | After ... != ... [true] | | Finally.cs:69:9:71:9 | {...} | Finally.cs:54:10:54:11 | Exceptional Exit | @@ -17783,9 +17803,10 @@ blockDominance | Finally.cs:147:10:147:11 | Entry | Finally.cs:158:21:158:36 | After ... == ... [false] | | Finally.cs:147:10:147:11 | Entry | Finally.cs:158:21:158:36 | After ... == ... [true] | | Finally.cs:147:10:147:11 | Entry | Finally.cs:159:27:159:44 | After object creation of type Exception | -| Finally.cs:147:10:147:11 | Entry | Finally.cs:161:13:164:13 | After catch (...) {...} [match] | | Finally.cs:147:10:147:11 | Entry | Finally.cs:161:13:164:13 | After catch (...) {...} [no-match] | | Finally.cs:147:10:147:11 | Entry | Finally.cs:161:13:164:13 | catch (...) {...} | +| Finally.cs:147:10:147:11 | Entry | Finally.cs:161:30:161:30 | After Exception e [match] | +| Finally.cs:147:10:147:11 | Entry | Finally.cs:161:30:161:30 | After Exception e [no-match] | | Finally.cs:147:10:147:11 | Entry | Finally.cs:161:39:161:54 | After ... == ... [false] | | Finally.cs:147:10:147:11 | Entry | Finally.cs:161:39:161:54 | After ... == ... [true] | | Finally.cs:147:10:147:11 | Exceptional Exit | Finally.cs:147:10:147:11 | Exceptional Exit | @@ -17804,9 +17825,10 @@ blockDominance | Finally.cs:155:9:169:9 | {...} | Finally.cs:158:21:158:36 | After ... == ... [false] | | Finally.cs:155:9:169:9 | {...} | Finally.cs:158:21:158:36 | After ... == ... [true] | | Finally.cs:155:9:169:9 | {...} | Finally.cs:159:27:159:44 | After object creation of type Exception | -| Finally.cs:155:9:169:9 | {...} | Finally.cs:161:13:164:13 | After catch (...) {...} [match] | | Finally.cs:155:9:169:9 | {...} | Finally.cs:161:13:164:13 | After catch (...) {...} [no-match] | | Finally.cs:155:9:169:9 | {...} | Finally.cs:161:13:164:13 | catch (...) {...} | +| Finally.cs:155:9:169:9 | {...} | Finally.cs:161:30:161:30 | After Exception e [match] | +| Finally.cs:155:9:169:9 | {...} | Finally.cs:161:30:161:30 | After Exception e [no-match] | | Finally.cs:155:9:169:9 | {...} | Finally.cs:161:39:161:54 | After ... == ... [false] | | Finally.cs:155:9:169:9 | {...} | Finally.cs:161:39:161:54 | After ... == ... [true] | | Finally.cs:156:13:168:13 | After try {...} ... | Finally.cs:147:10:147:11 | Exceptional Exit | @@ -17821,15 +17843,17 @@ blockDominance | Finally.cs:158:21:158:36 | After ... == ... [true] | Finally.cs:158:21:158:36 | After ... == ... [true] | | Finally.cs:158:21:158:36 | After ... == ... [true] | Finally.cs:159:27:159:44 | After object creation of type Exception | | Finally.cs:159:27:159:44 | After object creation of type Exception | Finally.cs:159:27:159:44 | After object creation of type Exception | -| Finally.cs:161:13:164:13 | After catch (...) {...} [match] | Finally.cs:161:13:164:13 | After catch (...) {...} [match] | -| Finally.cs:161:13:164:13 | After catch (...) {...} [match] | Finally.cs:161:39:161:54 | After ... == ... [false] | -| Finally.cs:161:13:164:13 | After catch (...) {...} [match] | Finally.cs:161:39:161:54 | After ... == ... [true] | | Finally.cs:161:13:164:13 | After catch (...) {...} [no-match] | Finally.cs:161:13:164:13 | After catch (...) {...} [no-match] | -| Finally.cs:161:13:164:13 | catch (...) {...} | Finally.cs:161:13:164:13 | After catch (...) {...} [match] | | Finally.cs:161:13:164:13 | catch (...) {...} | Finally.cs:161:13:164:13 | After catch (...) {...} [no-match] | | Finally.cs:161:13:164:13 | catch (...) {...} | Finally.cs:161:13:164:13 | catch (...) {...} | +| Finally.cs:161:13:164:13 | catch (...) {...} | Finally.cs:161:30:161:30 | After Exception e [match] | +| Finally.cs:161:13:164:13 | catch (...) {...} | Finally.cs:161:30:161:30 | After Exception e [no-match] | | Finally.cs:161:13:164:13 | catch (...) {...} | Finally.cs:161:39:161:54 | After ... == ... [false] | | Finally.cs:161:13:164:13 | catch (...) {...} | Finally.cs:161:39:161:54 | After ... == ... [true] | +| Finally.cs:161:30:161:30 | After Exception e [match] | Finally.cs:161:30:161:30 | After Exception e [match] | +| Finally.cs:161:30:161:30 | After Exception e [match] | Finally.cs:161:39:161:54 | After ... == ... [false] | +| Finally.cs:161:30:161:30 | After Exception e [match] | Finally.cs:161:39:161:54 | After ... == ... [true] | +| Finally.cs:161:30:161:30 | After Exception e [no-match] | Finally.cs:161:30:161:30 | After Exception e [no-match] | | Finally.cs:161:39:161:54 | After ... == ... [false] | Finally.cs:161:39:161:54 | After ... == ... [false] | | Finally.cs:161:39:161:54 | After ... == ... [true] | Finally.cs:161:39:161:54 | After ... == ... [true] | | Finally.cs:172:11:172:20 | Entry | Finally.cs:172:11:172:20 | Entry | @@ -17847,9 +17871,10 @@ blockDominance | Finally.cs:176:10:176:11 | Entry | Finally.cs:186:21:186:22 | After access to parameter b2 [false] | | Finally.cs:176:10:176:11 | Entry | Finally.cs:186:21:186:22 | After access to parameter b2 [true] | | Finally.cs:176:10:176:11 | Entry | Finally.cs:186:31:186:46 | After object creation of type ExceptionB | -| Finally.cs:176:10:176:11 | Entry | Finally.cs:188:13:191:13 | After catch (...) {...} [match] | | Finally.cs:176:10:176:11 | Entry | Finally.cs:188:13:191:13 | After catch (...) {...} [no-match] | | Finally.cs:176:10:176:11 | Entry | Finally.cs:188:13:191:13 | catch (...) {...} | +| Finally.cs:176:10:176:11 | Entry | Finally.cs:188:20:188:29 | After access to type ExceptionB [match] | +| Finally.cs:176:10:176:11 | Entry | Finally.cs:188:20:188:29 | After access to type ExceptionB [no-match] | | Finally.cs:176:10:176:11 | Entry | Finally.cs:188:38:188:39 | After access to parameter b2 [false] | | Finally.cs:176:10:176:11 | Entry | Finally.cs:188:38:188:39 | After access to parameter b2 [true] | | Finally.cs:176:10:176:11 | Entry | Finally.cs:190:21:190:22 | After access to parameter b1 [false] | @@ -17869,9 +17894,10 @@ blockDominance | Finally.cs:183:9:192:9 | {...} | Finally.cs:186:21:186:22 | After access to parameter b2 [false] | | Finally.cs:183:9:192:9 | {...} | Finally.cs:186:21:186:22 | After access to parameter b2 [true] | | Finally.cs:183:9:192:9 | {...} | Finally.cs:186:31:186:46 | After object creation of type ExceptionB | -| Finally.cs:183:9:192:9 | {...} | Finally.cs:188:13:191:13 | After catch (...) {...} [match] | | Finally.cs:183:9:192:9 | {...} | Finally.cs:188:13:191:13 | After catch (...) {...} [no-match] | | Finally.cs:183:9:192:9 | {...} | Finally.cs:188:13:191:13 | catch (...) {...} | +| Finally.cs:183:9:192:9 | {...} | Finally.cs:188:20:188:29 | After access to type ExceptionB [match] | +| Finally.cs:183:9:192:9 | {...} | Finally.cs:188:20:188:29 | After access to type ExceptionB [no-match] | | Finally.cs:183:9:192:9 | {...} | Finally.cs:188:38:188:39 | After access to parameter b2 [false] | | Finally.cs:183:9:192:9 | {...} | Finally.cs:188:38:188:39 | After access to parameter b2 [true] | | Finally.cs:183:9:192:9 | {...} | Finally.cs:190:21:190:22 | After access to parameter b1 [false] | @@ -17881,27 +17907,30 @@ blockDominance | Finally.cs:186:21:186:22 | After access to parameter b2 [false] | Finally.cs:186:21:186:22 | After access to parameter b2 [false] | | Finally.cs:186:21:186:22 | After access to parameter b2 [true] | Finally.cs:186:21:186:22 | After access to parameter b2 [true] | | Finally.cs:186:21:186:22 | After access to parameter b2 [true] | Finally.cs:186:31:186:46 | After object creation of type ExceptionB | -| Finally.cs:186:21:186:22 | After access to parameter b2 [true] | Finally.cs:188:13:191:13 | After catch (...) {...} [match] | | Finally.cs:186:21:186:22 | After access to parameter b2 [true] | Finally.cs:188:13:191:13 | After catch (...) {...} [no-match] | | Finally.cs:186:21:186:22 | After access to parameter b2 [true] | Finally.cs:188:13:191:13 | catch (...) {...} | +| Finally.cs:186:21:186:22 | After access to parameter b2 [true] | Finally.cs:188:20:188:29 | After access to type ExceptionB [match] | +| Finally.cs:186:21:186:22 | After access to parameter b2 [true] | Finally.cs:188:20:188:29 | After access to type ExceptionB [no-match] | | Finally.cs:186:21:186:22 | After access to parameter b2 [true] | Finally.cs:188:38:188:39 | After access to parameter b2 [false] | | Finally.cs:186:21:186:22 | After access to parameter b2 [true] | Finally.cs:188:38:188:39 | After access to parameter b2 [true] | | Finally.cs:186:21:186:22 | After access to parameter b2 [true] | Finally.cs:190:21:190:22 | After access to parameter b1 [false] | | Finally.cs:186:21:186:22 | After access to parameter b2 [true] | Finally.cs:190:21:190:22 | After access to parameter b1 [true] | | Finally.cs:186:31:186:46 | After object creation of type ExceptionB | Finally.cs:186:31:186:46 | After object creation of type ExceptionB | -| Finally.cs:188:13:191:13 | After catch (...) {...} [match] | Finally.cs:188:13:191:13 | After catch (...) {...} [match] | -| Finally.cs:188:13:191:13 | After catch (...) {...} [match] | Finally.cs:188:38:188:39 | After access to parameter b2 [false] | -| Finally.cs:188:13:191:13 | After catch (...) {...} [match] | Finally.cs:188:38:188:39 | After access to parameter b2 [true] | -| Finally.cs:188:13:191:13 | After catch (...) {...} [match] | Finally.cs:190:21:190:22 | After access to parameter b1 [false] | -| Finally.cs:188:13:191:13 | After catch (...) {...} [match] | Finally.cs:190:21:190:22 | After access to parameter b1 [true] | | Finally.cs:188:13:191:13 | After catch (...) {...} [no-match] | Finally.cs:188:13:191:13 | After catch (...) {...} [no-match] | -| Finally.cs:188:13:191:13 | catch (...) {...} | Finally.cs:188:13:191:13 | After catch (...) {...} [match] | | Finally.cs:188:13:191:13 | catch (...) {...} | Finally.cs:188:13:191:13 | After catch (...) {...} [no-match] | | Finally.cs:188:13:191:13 | catch (...) {...} | Finally.cs:188:13:191:13 | catch (...) {...} | +| Finally.cs:188:13:191:13 | catch (...) {...} | Finally.cs:188:20:188:29 | After access to type ExceptionB [match] | +| Finally.cs:188:13:191:13 | catch (...) {...} | Finally.cs:188:20:188:29 | After access to type ExceptionB [no-match] | | Finally.cs:188:13:191:13 | catch (...) {...} | Finally.cs:188:38:188:39 | After access to parameter b2 [false] | | Finally.cs:188:13:191:13 | catch (...) {...} | Finally.cs:188:38:188:39 | After access to parameter b2 [true] | | Finally.cs:188:13:191:13 | catch (...) {...} | Finally.cs:190:21:190:22 | After access to parameter b1 [false] | | Finally.cs:188:13:191:13 | catch (...) {...} | Finally.cs:190:21:190:22 | After access to parameter b1 [true] | +| Finally.cs:188:20:188:29 | After access to type ExceptionB [match] | Finally.cs:188:20:188:29 | After access to type ExceptionB [match] | +| Finally.cs:188:20:188:29 | After access to type ExceptionB [match] | Finally.cs:188:38:188:39 | After access to parameter b2 [false] | +| Finally.cs:188:20:188:29 | After access to type ExceptionB [match] | Finally.cs:188:38:188:39 | After access to parameter b2 [true] | +| Finally.cs:188:20:188:29 | After access to type ExceptionB [match] | Finally.cs:190:21:190:22 | After access to parameter b1 [false] | +| Finally.cs:188:20:188:29 | After access to type ExceptionB [match] | Finally.cs:190:21:190:22 | After access to parameter b1 [true] | +| Finally.cs:188:20:188:29 | After access to type ExceptionB [no-match] | Finally.cs:188:20:188:29 | After access to type ExceptionB [no-match] | | Finally.cs:188:38:188:39 | After access to parameter b2 [false] | Finally.cs:188:38:188:39 | After access to parameter b2 [false] | | Finally.cs:188:38:188:39 | After access to parameter b2 [true] | Finally.cs:188:38:188:39 | After access to parameter b2 [true] | | Finally.cs:188:38:188:39 | After access to parameter b2 [true] | Finally.cs:190:21:190:22 | After access to parameter b1 [false] | @@ -21668,14 +21697,14 @@ postBlockDominance | ExitMethods.cs:38:10:38:11 | Exit | ExitMethods.cs:38:10:38:11 | Exit | | ExitMethods.cs:38:10:38:11 | Normal Exit | ExitMethods.cs:38:10:38:11 | Entry | | ExitMethods.cs:38:10:38:11 | Normal Exit | ExitMethods.cs:38:10:38:11 | Normal Exit | -| ExitMethods.cs:38:10:38:11 | Normal Exit | ExitMethods.cs:44:9:47:9 | After catch (...) {...} [match] | -| ExitMethods.cs:38:10:38:11 | Normal Exit | ExitMethods.cs:44:9:47:9 | After catch (...) {...} [no-match] | -| ExitMethods.cs:38:10:38:11 | Normal Exit | ExitMethods.cs:48:9:51:9 | After catch (...) {...} [match] | -| ExitMethods.cs:44:9:47:9 | After catch (...) {...} [match] | ExitMethods.cs:44:9:47:9 | After catch (...) {...} [match] | -| ExitMethods.cs:44:9:47:9 | After catch (...) {...} [no-match] | ExitMethods.cs:44:9:47:9 | After catch (...) {...} [no-match] | -| ExitMethods.cs:48:9:51:9 | After catch (...) {...} [match] | ExitMethods.cs:44:9:47:9 | After catch (...) {...} [no-match] | -| ExitMethods.cs:48:9:51:9 | After catch (...) {...} [match] | ExitMethods.cs:48:9:51:9 | After catch (...) {...} [match] | -| ExitMethods.cs:48:9:51:9 | After catch (...) {...} [no-match] | ExitMethods.cs:48:9:51:9 | After catch (...) {...} [no-match] | +| ExitMethods.cs:38:10:38:11 | Normal Exit | ExitMethods.cs:44:16:44:32 | After access to type ArgumentException [match] | +| ExitMethods.cs:38:10:38:11 | Normal Exit | ExitMethods.cs:44:16:44:32 | After access to type ArgumentException [no-match] | +| ExitMethods.cs:38:10:38:11 | Normal Exit | ExitMethods.cs:48:16:48:24 | After access to type Exception [match] | +| ExitMethods.cs:44:16:44:32 | After access to type ArgumentException [match] | ExitMethods.cs:44:16:44:32 | After access to type ArgumentException [match] | +| ExitMethods.cs:44:16:44:32 | After access to type ArgumentException [no-match] | ExitMethods.cs:44:16:44:32 | After access to type ArgumentException [no-match] | +| ExitMethods.cs:48:16:48:24 | After access to type Exception [match] | ExitMethods.cs:44:16:44:32 | After access to type ArgumentException [no-match] | +| ExitMethods.cs:48:16:48:24 | After access to type Exception [match] | ExitMethods.cs:48:16:48:24 | After access to type Exception [match] | +| ExitMethods.cs:48:16:48:24 | After access to type Exception [no-match] | ExitMethods.cs:48:16:48:24 | After access to type Exception [no-match] | | ExitMethods.cs:54:10:54:11 | Entry | ExitMethods.cs:54:10:54:11 | Entry | | ExitMethods.cs:60:10:60:11 | Entry | ExitMethods.cs:60:10:60:11 | Entry | | ExitMethods.cs:66:17:66:26 | Entry | ExitMethods.cs:66:17:66:26 | Entry | @@ -21743,32 +21772,32 @@ postBlockDominance | Finally.cs:19:10:19:11 | Normal Exit | Finally.cs:19:10:19:11 | Normal Exit | | Finally.cs:19:10:19:11 | Normal Exit | Finally.cs:21:9:51:9 | After try {...} ... | | Finally.cs:19:10:19:11 | Normal Exit | Finally.cs:23:13:23:37 | After call to method WriteLine | -| Finally.cs:19:10:19:11 | Normal Exit | Finally.cs:26:9:29:9 | After catch (...) {...} [match] | -| Finally.cs:19:10:19:11 | Normal Exit | Finally.cs:26:9:29:9 | After catch (...) {...} [no-match] | | Finally.cs:19:10:19:11 | Normal Exit | Finally.cs:26:9:29:9 | catch (...) {...} | -| Finally.cs:19:10:19:11 | Normal Exit | Finally.cs:30:9:40:9 | After catch (...) {...} [match] | -| Finally.cs:19:10:19:11 | Normal Exit | Finally.cs:30:9:40:9 | After catch (...) {...} [no-match] | -| Finally.cs:19:10:19:11 | Normal Exit | Finally.cs:41:9:43:9 | After catch (...) {...} [match] | -| Finally.cs:19:10:19:11 | Normal Exit | Finally.cs:41:9:43:9 | After catch (...) {...} [no-match] | +| Finally.cs:19:10:19:11 | Normal Exit | Finally.cs:26:38:26:39 | After IOException ex [match] | +| Finally.cs:19:10:19:11 | Normal Exit | Finally.cs:26:38:26:39 | After IOException ex [no-match] | +| Finally.cs:19:10:19:11 | Normal Exit | Finally.cs:30:41:30:42 | After ArgumentException ex [match] | +| Finally.cs:19:10:19:11 | Normal Exit | Finally.cs:30:41:30:42 | After ArgumentException ex [no-match] | +| Finally.cs:19:10:19:11 | Normal Exit | Finally.cs:41:16:41:24 | After access to type Exception [match] | +| Finally.cs:19:10:19:11 | Normal Exit | Finally.cs:41:16:41:24 | After access to type Exception [no-match] | | Finally.cs:19:10:19:11 | Normal Exit | Finally.cs:49:9:51:9 | {...} | | Finally.cs:21:9:51:9 | After try {...} ... | Finally.cs:21:9:51:9 | After try {...} ... | | Finally.cs:23:13:23:37 | After call to method WriteLine | Finally.cs:23:13:23:37 | After call to method WriteLine | -| Finally.cs:26:9:29:9 | After catch (...) {...} [match] | Finally.cs:26:9:29:9 | After catch (...) {...} [match] | -| Finally.cs:26:9:29:9 | After catch (...) {...} [no-match] | Finally.cs:26:9:29:9 | After catch (...) {...} [no-match] | | Finally.cs:26:9:29:9 | catch (...) {...} | Finally.cs:26:9:29:9 | catch (...) {...} | -| Finally.cs:30:9:40:9 | After catch (...) {...} [match] | Finally.cs:30:9:40:9 | After catch (...) {...} [match] | -| Finally.cs:30:9:40:9 | After catch (...) {...} [no-match] | Finally.cs:30:9:40:9 | After catch (...) {...} [no-match] | -| Finally.cs:41:9:43:9 | After catch (...) {...} [match] | Finally.cs:41:9:43:9 | After catch (...) {...} [match] | -| Finally.cs:41:9:43:9 | After catch (...) {...} [no-match] | Finally.cs:41:9:43:9 | After catch (...) {...} [no-match] | +| Finally.cs:26:38:26:39 | After IOException ex [match] | Finally.cs:26:38:26:39 | After IOException ex [match] | +| Finally.cs:26:38:26:39 | After IOException ex [no-match] | Finally.cs:26:38:26:39 | After IOException ex [no-match] | +| Finally.cs:30:41:30:42 | After ArgumentException ex [match] | Finally.cs:30:41:30:42 | After ArgumentException ex [match] | +| Finally.cs:30:41:30:42 | After ArgumentException ex [no-match] | Finally.cs:30:41:30:42 | After ArgumentException ex [no-match] | +| Finally.cs:41:16:41:24 | After access to type Exception [match] | Finally.cs:41:16:41:24 | After access to type Exception [match] | +| Finally.cs:41:16:41:24 | After access to type Exception [no-match] | Finally.cs:41:16:41:24 | After access to type Exception [no-match] | | Finally.cs:49:9:51:9 | {...} | Finally.cs:19:10:19:11 | Entry | | Finally.cs:49:9:51:9 | {...} | Finally.cs:23:13:23:37 | After call to method WriteLine | -| Finally.cs:49:9:51:9 | {...} | Finally.cs:26:9:29:9 | After catch (...) {...} [match] | -| Finally.cs:49:9:51:9 | {...} | Finally.cs:26:9:29:9 | After catch (...) {...} [no-match] | | Finally.cs:49:9:51:9 | {...} | Finally.cs:26:9:29:9 | catch (...) {...} | -| Finally.cs:49:9:51:9 | {...} | Finally.cs:30:9:40:9 | After catch (...) {...} [match] | -| Finally.cs:49:9:51:9 | {...} | Finally.cs:30:9:40:9 | After catch (...) {...} [no-match] | -| Finally.cs:49:9:51:9 | {...} | Finally.cs:41:9:43:9 | After catch (...) {...} [match] | -| Finally.cs:49:9:51:9 | {...} | Finally.cs:41:9:43:9 | After catch (...) {...} [no-match] | +| Finally.cs:49:9:51:9 | {...} | Finally.cs:26:38:26:39 | After IOException ex [match] | +| Finally.cs:49:9:51:9 | {...} | Finally.cs:26:38:26:39 | After IOException ex [no-match] | +| Finally.cs:49:9:51:9 | {...} | Finally.cs:30:41:30:42 | After ArgumentException ex [match] | +| Finally.cs:49:9:51:9 | {...} | Finally.cs:30:41:30:42 | After ArgumentException ex [no-match] | +| Finally.cs:49:9:51:9 | {...} | Finally.cs:41:16:41:24 | After access to type Exception [match] | +| Finally.cs:49:9:51:9 | {...} | Finally.cs:41:16:41:24 | After access to type Exception [no-match] | | Finally.cs:49:9:51:9 | {...} | Finally.cs:49:9:51:9 | {...} | | Finally.cs:54:10:54:11 | Entry | Finally.cs:54:10:54:11 | Entry | | Finally.cs:54:10:54:11 | Exceptional Exit | Finally.cs:54:10:54:11 | Exceptional Exit | @@ -21777,31 +21806,35 @@ postBlockDominance | Finally.cs:54:10:54:11 | Normal Exit | Finally.cs:54:10:54:11 | Normal Exit | | Finally.cs:54:10:54:11 | Normal Exit | Finally.cs:56:9:71:9 | After try {...} ... | | Finally.cs:54:10:54:11 | Normal Exit | Finally.cs:58:13:58:37 | After call to method WriteLine | -| Finally.cs:54:10:54:11 | Normal Exit | Finally.cs:61:9:64:9 | After catch (...) {...} [match] | -| Finally.cs:54:10:54:11 | Normal Exit | Finally.cs:61:9:64:9 | After catch (...) {...} [no-match] | | Finally.cs:54:10:54:11 | Normal Exit | Finally.cs:61:9:64:9 | catch (...) {...} | -| Finally.cs:54:10:54:11 | Normal Exit | Finally.cs:65:9:67:9 | After catch (...) {...} [match] | +| Finally.cs:54:10:54:11 | Normal Exit | Finally.cs:61:38:61:39 | After IOException ex [match] | +| Finally.cs:54:10:54:11 | Normal Exit | Finally.cs:61:38:61:39 | After IOException ex [no-match] | | Finally.cs:54:10:54:11 | Normal Exit | Finally.cs:65:9:67:9 | After catch (...) {...} [no-match] | +| Finally.cs:54:10:54:11 | Normal Exit | Finally.cs:65:26:65:26 | After Exception e [match] | +| Finally.cs:54:10:54:11 | Normal Exit | Finally.cs:65:26:65:26 | After Exception e [no-match] | | Finally.cs:54:10:54:11 | Normal Exit | Finally.cs:65:35:65:51 | After ... != ... [false] | | Finally.cs:54:10:54:11 | Normal Exit | Finally.cs:65:35:65:51 | After ... != ... [true] | | Finally.cs:54:10:54:11 | Normal Exit | Finally.cs:69:9:71:9 | {...} | | Finally.cs:56:9:71:9 | After try {...} ... | Finally.cs:56:9:71:9 | After try {...} ... | | Finally.cs:58:13:58:37 | After call to method WriteLine | Finally.cs:58:13:58:37 | After call to method WriteLine | -| Finally.cs:61:9:64:9 | After catch (...) {...} [match] | Finally.cs:61:9:64:9 | After catch (...) {...} [match] | -| Finally.cs:61:9:64:9 | After catch (...) {...} [no-match] | Finally.cs:61:9:64:9 | After catch (...) {...} [no-match] | | Finally.cs:61:9:64:9 | catch (...) {...} | Finally.cs:61:9:64:9 | catch (...) {...} | -| Finally.cs:65:9:67:9 | After catch (...) {...} [match] | Finally.cs:65:9:67:9 | After catch (...) {...} [match] | +| Finally.cs:61:38:61:39 | After IOException ex [match] | Finally.cs:61:38:61:39 | After IOException ex [match] | +| Finally.cs:61:38:61:39 | After IOException ex [no-match] | Finally.cs:61:38:61:39 | After IOException ex [no-match] | | Finally.cs:65:9:67:9 | After catch (...) {...} [no-match] | Finally.cs:65:9:67:9 | After catch (...) {...} [no-match] | +| Finally.cs:65:9:67:9 | After catch (...) {...} [no-match] | Finally.cs:65:26:65:26 | After Exception e [no-match] | | Finally.cs:65:9:67:9 | After catch (...) {...} [no-match] | Finally.cs:65:35:65:51 | After ... != ... [false] | +| Finally.cs:65:26:65:26 | After Exception e [match] | Finally.cs:65:26:65:26 | After Exception e [match] | +| Finally.cs:65:26:65:26 | After Exception e [no-match] | Finally.cs:65:26:65:26 | After Exception e [no-match] | | Finally.cs:65:35:65:51 | After ... != ... [false] | Finally.cs:65:35:65:51 | After ... != ... [false] | | Finally.cs:65:35:65:51 | After ... != ... [true] | Finally.cs:65:35:65:51 | After ... != ... [true] | | Finally.cs:69:9:71:9 | {...} | Finally.cs:54:10:54:11 | Entry | | Finally.cs:69:9:71:9 | {...} | Finally.cs:58:13:58:37 | After call to method WriteLine | -| Finally.cs:69:9:71:9 | {...} | Finally.cs:61:9:64:9 | After catch (...) {...} [match] | -| Finally.cs:69:9:71:9 | {...} | Finally.cs:61:9:64:9 | After catch (...) {...} [no-match] | | Finally.cs:69:9:71:9 | {...} | Finally.cs:61:9:64:9 | catch (...) {...} | -| Finally.cs:69:9:71:9 | {...} | Finally.cs:65:9:67:9 | After catch (...) {...} [match] | +| Finally.cs:69:9:71:9 | {...} | Finally.cs:61:38:61:39 | After IOException ex [match] | +| Finally.cs:69:9:71:9 | {...} | Finally.cs:61:38:61:39 | After IOException ex [no-match] | | Finally.cs:69:9:71:9 | {...} | Finally.cs:65:9:67:9 | After catch (...) {...} [no-match] | +| Finally.cs:69:9:71:9 | {...} | Finally.cs:65:26:65:26 | After Exception e [match] | +| Finally.cs:69:9:71:9 | {...} | Finally.cs:65:26:65:26 | After Exception e [no-match] | | Finally.cs:69:9:71:9 | {...} | Finally.cs:65:35:65:51 | After ... != ... [false] | | Finally.cs:69:9:71:9 | {...} | Finally.cs:65:35:65:51 | After ... != ... [true] | | Finally.cs:69:9:71:9 | {...} | Finally.cs:69:9:71:9 | {...} | @@ -21973,9 +22006,10 @@ postBlockDominance | Finally.cs:149:9:169:9 | After try {...} ... | Finally.cs:158:21:158:36 | After ... == ... [false] | | Finally.cs:149:9:169:9 | After try {...} ... | Finally.cs:158:21:158:36 | After ... == ... [true] | | Finally.cs:149:9:169:9 | After try {...} ... | Finally.cs:159:27:159:44 | After object creation of type Exception | -| Finally.cs:149:9:169:9 | After try {...} ... | Finally.cs:161:13:164:13 | After catch (...) {...} [match] | | Finally.cs:149:9:169:9 | After try {...} ... | Finally.cs:161:13:164:13 | After catch (...) {...} [no-match] | | Finally.cs:149:9:169:9 | After try {...} ... | Finally.cs:161:13:164:13 | catch (...) {...} | +| Finally.cs:149:9:169:9 | After try {...} ... | Finally.cs:161:30:161:30 | After Exception e [match] | +| Finally.cs:149:9:169:9 | After try {...} ... | Finally.cs:161:30:161:30 | After Exception e [no-match] | | Finally.cs:149:9:169:9 | After try {...} ... | Finally.cs:161:39:161:54 | After ... == ... [false] | | Finally.cs:149:9:169:9 | After try {...} ... | Finally.cs:161:39:161:54 | After ... == ... [true] | | Finally.cs:151:17:151:28 | After ... == ... [false] | Finally.cs:151:17:151:28 | After ... == ... [false] | @@ -21996,21 +22030,24 @@ postBlockDominance | Finally.cs:156:13:168:13 | After try {...} ... | Finally.cs:158:21:158:36 | After ... == ... [false] | | Finally.cs:156:13:168:13 | After try {...} ... | Finally.cs:158:21:158:36 | After ... == ... [true] | | Finally.cs:156:13:168:13 | After try {...} ... | Finally.cs:159:27:159:44 | After object creation of type Exception | -| Finally.cs:156:13:168:13 | After try {...} ... | Finally.cs:161:13:164:13 | After catch (...) {...} [match] | | Finally.cs:156:13:168:13 | After try {...} ... | Finally.cs:161:13:164:13 | After catch (...) {...} [no-match] | | Finally.cs:156:13:168:13 | After try {...} ... | Finally.cs:161:13:164:13 | catch (...) {...} | +| Finally.cs:156:13:168:13 | After try {...} ... | Finally.cs:161:30:161:30 | After Exception e [match] | +| Finally.cs:156:13:168:13 | After try {...} ... | Finally.cs:161:30:161:30 | After Exception e [no-match] | | Finally.cs:156:13:168:13 | After try {...} ... | Finally.cs:161:39:161:54 | After ... == ... [false] | | Finally.cs:156:13:168:13 | After try {...} ... | Finally.cs:161:39:161:54 | After ... == ... [true] | | Finally.cs:158:21:158:31 | After access to property Length | Finally.cs:158:21:158:31 | After access to property Length | | Finally.cs:158:21:158:36 | After ... == ... [false] | Finally.cs:158:21:158:36 | After ... == ... [false] | | Finally.cs:158:21:158:36 | After ... == ... [true] | Finally.cs:158:21:158:36 | After ... == ... [true] | | Finally.cs:159:27:159:44 | After object creation of type Exception | Finally.cs:159:27:159:44 | After object creation of type Exception | -| Finally.cs:161:13:164:13 | After catch (...) {...} [match] | Finally.cs:161:13:164:13 | After catch (...) {...} [match] | | Finally.cs:161:13:164:13 | After catch (...) {...} [no-match] | Finally.cs:161:13:164:13 | After catch (...) {...} [no-match] | +| Finally.cs:161:13:164:13 | After catch (...) {...} [no-match] | Finally.cs:161:30:161:30 | After Exception e [no-match] | | Finally.cs:161:13:164:13 | After catch (...) {...} [no-match] | Finally.cs:161:39:161:54 | After ... == ... [false] | | Finally.cs:161:13:164:13 | catch (...) {...} | Finally.cs:158:21:158:36 | After ... == ... [true] | | Finally.cs:161:13:164:13 | catch (...) {...} | Finally.cs:159:27:159:44 | After object creation of type Exception | | Finally.cs:161:13:164:13 | catch (...) {...} | Finally.cs:161:13:164:13 | catch (...) {...} | +| Finally.cs:161:30:161:30 | After Exception e [match] | Finally.cs:161:30:161:30 | After Exception e [match] | +| Finally.cs:161:30:161:30 | After Exception e [no-match] | Finally.cs:161:30:161:30 | After Exception e [no-match] | | Finally.cs:161:39:161:54 | After ... == ... [false] | Finally.cs:161:39:161:54 | After ... == ... [false] | | Finally.cs:161:39:161:54 | After ... == ... [true] | Finally.cs:161:39:161:54 | After ... == ... [true] | | Finally.cs:172:11:172:20 | Entry | Finally.cs:172:11:172:20 | Entry | @@ -22029,8 +22066,8 @@ postBlockDominance | Finally.cs:178:9:192:9 | After try {...} ... | Finally.cs:186:21:186:22 | After access to parameter b2 [false] | | Finally.cs:178:9:192:9 | After try {...} ... | Finally.cs:186:21:186:22 | After access to parameter b2 [true] | | Finally.cs:178:9:192:9 | After try {...} ... | Finally.cs:186:31:186:46 | After object creation of type ExceptionB | -| Finally.cs:178:9:192:9 | After try {...} ... | Finally.cs:188:13:191:13 | After catch (...) {...} [match] | | Finally.cs:178:9:192:9 | After try {...} ... | Finally.cs:188:13:191:13 | catch (...) {...} | +| Finally.cs:178:9:192:9 | After try {...} ... | Finally.cs:188:20:188:29 | After access to type ExceptionB [match] | | Finally.cs:178:9:192:9 | After try {...} ... | Finally.cs:188:38:188:39 | After access to parameter b2 [true] | | Finally.cs:178:9:192:9 | After try {...} ... | Finally.cs:190:21:190:22 | After access to parameter b1 [false] | | Finally.cs:180:17:180:18 | After access to parameter b1 [false] | Finally.cs:180:17:180:18 | After access to parameter b1 [false] | @@ -22050,31 +22087,32 @@ postBlockDominance | Finally.cs:184:13:191:13 | After try {...} ... | Finally.cs:186:21:186:22 | After access to parameter b2 [false] | | Finally.cs:184:13:191:13 | After try {...} ... | Finally.cs:186:21:186:22 | After access to parameter b2 [true] | | Finally.cs:184:13:191:13 | After try {...} ... | Finally.cs:186:31:186:46 | After object creation of type ExceptionB | -| Finally.cs:184:13:191:13 | After try {...} ... | Finally.cs:188:13:191:13 | After catch (...) {...} [match] | | Finally.cs:184:13:191:13 | After try {...} ... | Finally.cs:188:13:191:13 | catch (...) {...} | +| Finally.cs:184:13:191:13 | After try {...} ... | Finally.cs:188:20:188:29 | After access to type ExceptionB [match] | | Finally.cs:184:13:191:13 | After try {...} ... | Finally.cs:188:38:188:39 | After access to parameter b2 [true] | | Finally.cs:184:13:191:13 | After try {...} ... | Finally.cs:190:21:190:22 | After access to parameter b1 [false] | | Finally.cs:186:21:186:22 | After access to parameter b2 [false] | Finally.cs:186:21:186:22 | After access to parameter b2 [false] | | Finally.cs:186:21:186:22 | After access to parameter b2 [true] | Finally.cs:186:21:186:22 | After access to parameter b2 [true] | | Finally.cs:186:31:186:46 | After object creation of type ExceptionB | Finally.cs:186:31:186:46 | After object creation of type ExceptionB | -| Finally.cs:188:13:191:13 | After catch (...) {...} [match] | Finally.cs:186:21:186:22 | After access to parameter b2 [true] | -| Finally.cs:188:13:191:13 | After catch (...) {...} [match] | Finally.cs:186:31:186:46 | After object creation of type ExceptionB | -| Finally.cs:188:13:191:13 | After catch (...) {...} [match] | Finally.cs:188:13:191:13 | After catch (...) {...} [match] | -| Finally.cs:188:13:191:13 | After catch (...) {...} [match] | Finally.cs:188:13:191:13 | catch (...) {...} | | Finally.cs:188:13:191:13 | After catch (...) {...} [no-match] | Finally.cs:188:13:191:13 | After catch (...) {...} [no-match] | | Finally.cs:188:13:191:13 | catch (...) {...} | Finally.cs:186:21:186:22 | After access to parameter b2 [true] | | Finally.cs:188:13:191:13 | catch (...) {...} | Finally.cs:186:31:186:46 | After object creation of type ExceptionB | | Finally.cs:188:13:191:13 | catch (...) {...} | Finally.cs:188:13:191:13 | catch (...) {...} | +| Finally.cs:188:20:188:29 | After access to type ExceptionB [match] | Finally.cs:186:21:186:22 | After access to parameter b2 [true] | +| Finally.cs:188:20:188:29 | After access to type ExceptionB [match] | Finally.cs:186:31:186:46 | After object creation of type ExceptionB | +| Finally.cs:188:20:188:29 | After access to type ExceptionB [match] | Finally.cs:188:13:191:13 | catch (...) {...} | +| Finally.cs:188:20:188:29 | After access to type ExceptionB [match] | Finally.cs:188:20:188:29 | After access to type ExceptionB [match] | +| Finally.cs:188:20:188:29 | After access to type ExceptionB [no-match] | Finally.cs:188:20:188:29 | After access to type ExceptionB [no-match] | | Finally.cs:188:38:188:39 | After access to parameter b2 [false] | Finally.cs:188:38:188:39 | After access to parameter b2 [false] | | Finally.cs:188:38:188:39 | After access to parameter b2 [true] | Finally.cs:186:21:186:22 | After access to parameter b2 [true] | | Finally.cs:188:38:188:39 | After access to parameter b2 [true] | Finally.cs:186:31:186:46 | After object creation of type ExceptionB | -| Finally.cs:188:38:188:39 | After access to parameter b2 [true] | Finally.cs:188:13:191:13 | After catch (...) {...} [match] | | Finally.cs:188:38:188:39 | After access to parameter b2 [true] | Finally.cs:188:13:191:13 | catch (...) {...} | +| Finally.cs:188:38:188:39 | After access to parameter b2 [true] | Finally.cs:188:20:188:29 | After access to type ExceptionB [match] | | Finally.cs:188:38:188:39 | After access to parameter b2 [true] | Finally.cs:188:38:188:39 | After access to parameter b2 [true] | | Finally.cs:190:21:190:22 | After access to parameter b1 [false] | Finally.cs:186:21:186:22 | After access to parameter b2 [true] | | Finally.cs:190:21:190:22 | After access to parameter b1 [false] | Finally.cs:186:31:186:46 | After object creation of type ExceptionB | -| Finally.cs:190:21:190:22 | After access to parameter b1 [false] | Finally.cs:188:13:191:13 | After catch (...) {...} [match] | | Finally.cs:190:21:190:22 | After access to parameter b1 [false] | Finally.cs:188:13:191:13 | catch (...) {...} | +| Finally.cs:190:21:190:22 | After access to parameter b1 [false] | Finally.cs:188:20:188:29 | After access to type ExceptionB [match] | | Finally.cs:190:21:190:22 | After access to parameter b1 [false] | Finally.cs:188:38:188:39 | After access to parameter b2 [true] | | Finally.cs:190:21:190:22 | After access to parameter b1 [false] | Finally.cs:190:21:190:22 | After access to parameter b1 [false] | | Finally.cs:190:21:190:22 | After access to parameter b1 [true] | Finally.cs:190:21:190:22 | After access to parameter b1 [true] | diff --git a/csharp/ql/test/library-tests/controlflow/graph/EnclosingCallable.expected b/csharp/ql/test/library-tests/controlflow/graph/EnclosingCallable.expected index 2a3a0a7020f..1b41c809f59 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/EnclosingCallable.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/EnclosingCallable.expected @@ -3016,15 +3016,19 @@ nodeEnclosing | ExitMethods.cs:42:13:42:30 | call to method ErrorAlways | ExitMethods.cs:38:10:38:11 | M6 | | ExitMethods.cs:42:13:42:31 | ...; | ExitMethods.cs:38:10:38:11 | M6 | | ExitMethods.cs:42:25:42:29 | false | ExitMethods.cs:38:10:38:11 | M6 | -| ExitMethods.cs:44:9:47:9 | After catch (...) {...} [match] | ExitMethods.cs:38:10:38:11 | M6 | | ExitMethods.cs:44:9:47:9 | After catch (...) {...} [no-match] | ExitMethods.cs:38:10:38:11 | M6 | | ExitMethods.cs:44:9:47:9 | catch (...) {...} | ExitMethods.cs:38:10:38:11 | M6 | +| ExitMethods.cs:44:16:44:32 | After access to type ArgumentException [match] | ExitMethods.cs:38:10:38:11 | M6 | +| ExitMethods.cs:44:16:44:32 | After access to type ArgumentException [no-match] | ExitMethods.cs:38:10:38:11 | M6 | +| ExitMethods.cs:44:16:44:32 | access to type ArgumentException | ExitMethods.cs:38:10:38:11 | M6 | | ExitMethods.cs:45:9:47:9 | {...} | ExitMethods.cs:38:10:38:11 | M6 | | ExitMethods.cs:46:13:46:19 | Before return ...; | ExitMethods.cs:38:10:38:11 | M6 | | ExitMethods.cs:46:13:46:19 | return ...; | ExitMethods.cs:38:10:38:11 | M6 | -| ExitMethods.cs:48:9:51:9 | After catch (...) {...} [match] | ExitMethods.cs:38:10:38:11 | M6 | | ExitMethods.cs:48:9:51:9 | After catch (...) {...} [no-match] | ExitMethods.cs:38:10:38:11 | M6 | | ExitMethods.cs:48:9:51:9 | catch (...) {...} | ExitMethods.cs:38:10:38:11 | M6 | +| ExitMethods.cs:48:16:48:24 | After access to type Exception [match] | ExitMethods.cs:38:10:38:11 | M6 | +| ExitMethods.cs:48:16:48:24 | After access to type Exception [no-match] | ExitMethods.cs:38:10:38:11 | M6 | +| ExitMethods.cs:48:16:48:24 | access to type Exception | ExitMethods.cs:38:10:38:11 | M6 | | ExitMethods.cs:49:9:51:9 | {...} | ExitMethods.cs:38:10:38:11 | M6 | | ExitMethods.cs:50:13:50:19 | Before return ...; | ExitMethods.cs:38:10:38:11 | M6 | | ExitMethods.cs:50:13:50:19 | return ...; | ExitMethods.cs:38:10:38:11 | M6 | @@ -3358,18 +3362,20 @@ nodeEnclosing | Finally.cs:23:31:23:36 | "Try2" | Finally.cs:19:10:19:11 | M2 | | Finally.cs:24:13:24:19 | Before return ...; | Finally.cs:19:10:19:11 | M2 | | Finally.cs:24:13:24:19 | return ...; | Finally.cs:19:10:19:11 | M2 | -| Finally.cs:26:9:29:9 | After catch (...) {...} [match] | Finally.cs:19:10:19:11 | M2 | | Finally.cs:26:9:29:9 | After catch (...) {...} [no-match] | Finally.cs:19:10:19:11 | M2 | | Finally.cs:26:9:29:9 | catch (...) {...} | Finally.cs:19:10:19:11 | M2 | +| Finally.cs:26:38:26:39 | After IOException ex [match] | Finally.cs:19:10:19:11 | M2 | +| Finally.cs:26:38:26:39 | After IOException ex [no-match] | Finally.cs:19:10:19:11 | M2 | | Finally.cs:26:38:26:39 | IOException ex | Finally.cs:19:10:19:11 | M2 | | Finally.cs:26:48:26:51 | After true [true] | Finally.cs:19:10:19:11 | M2 | | Finally.cs:26:48:26:51 | true | Finally.cs:19:10:19:11 | M2 | | Finally.cs:27:9:29:9 | {...} | Finally.cs:19:10:19:11 | M2 | | Finally.cs:28:13:28:18 | Before throw ...; | Finally.cs:19:10:19:11 | M2 | | Finally.cs:28:13:28:18 | throw ...; | Finally.cs:19:10:19:11 | M2 | -| Finally.cs:30:9:40:9 | After catch (...) {...} [match] | Finally.cs:19:10:19:11 | M2 | | Finally.cs:30:9:40:9 | After catch (...) {...} [no-match] | Finally.cs:19:10:19:11 | M2 | | Finally.cs:30:9:40:9 | catch (...) {...} | Finally.cs:19:10:19:11 | M2 | +| Finally.cs:30:41:30:42 | After ArgumentException ex [match] | Finally.cs:19:10:19:11 | M2 | +| Finally.cs:30:41:30:42 | After ArgumentException ex [no-match] | Finally.cs:19:10:19:11 | M2 | | Finally.cs:30:41:30:42 | ArgumentException ex | Finally.cs:19:10:19:11 | M2 | | Finally.cs:31:9:40:9 | {...} | Finally.cs:19:10:19:11 | M2 | | Finally.cs:32:13:39:13 | try {...} ... | Finally.cs:19:10:19:11 | M2 | @@ -3386,11 +3392,12 @@ nodeEnclosing | Finally.cs:38:23:38:43 | Before object creation of type Exception | Finally.cs:19:10:19:11 | M2 | | Finally.cs:38:23:38:43 | object creation of type Exception | Finally.cs:19:10:19:11 | M2 | | Finally.cs:38:37:38:42 | "Boo!" | Finally.cs:19:10:19:11 | M2 | -| Finally.cs:41:9:43:9 | After catch (...) {...} [match] | Finally.cs:19:10:19:11 | M2 | | Finally.cs:41:9:43:9 | After catch (...) {...} [no-match] | Finally.cs:19:10:19:11 | M2 | | Finally.cs:41:9:43:9 | catch (...) {...} | Finally.cs:19:10:19:11 | M2 | +| Finally.cs:41:16:41:24 | After access to type Exception [match] | Finally.cs:19:10:19:11 | M2 | +| Finally.cs:41:16:41:24 | After access to type Exception [no-match] | Finally.cs:19:10:19:11 | M2 | +| Finally.cs:41:16:41:24 | access to type Exception | Finally.cs:19:10:19:11 | M2 | | Finally.cs:42:9:43:9 | {...} | Finally.cs:19:10:19:11 | M2 | -| Finally.cs:44:9:47:9 | After catch {...} [match] | Finally.cs:19:10:19:11 | M2 | | Finally.cs:44:9:47:9 | catch {...} | Finally.cs:19:10:19:11 | M2 | | Finally.cs:45:9:47:9 | {...} | Finally.cs:19:10:19:11 | M2 | | Finally.cs:46:13:46:19 | Before return ...; | Finally.cs:19:10:19:11 | M2 | @@ -3420,18 +3427,20 @@ nodeEnclosing | Finally.cs:58:31:58:36 | "Try3" | Finally.cs:54:10:54:11 | M3 | | Finally.cs:59:13:59:19 | Before return ...; | Finally.cs:54:10:54:11 | M3 | | Finally.cs:59:13:59:19 | return ...; | Finally.cs:54:10:54:11 | M3 | -| Finally.cs:61:9:64:9 | After catch (...) {...} [match] | Finally.cs:54:10:54:11 | M3 | | Finally.cs:61:9:64:9 | After catch (...) {...} [no-match] | Finally.cs:54:10:54:11 | M3 | | Finally.cs:61:9:64:9 | catch (...) {...} | Finally.cs:54:10:54:11 | M3 | +| Finally.cs:61:38:61:39 | After IOException ex [match] | Finally.cs:54:10:54:11 | M3 | +| Finally.cs:61:38:61:39 | After IOException ex [no-match] | Finally.cs:54:10:54:11 | M3 | | Finally.cs:61:38:61:39 | IOException ex | Finally.cs:54:10:54:11 | M3 | | Finally.cs:61:48:61:51 | After true [true] | Finally.cs:54:10:54:11 | M3 | | Finally.cs:61:48:61:51 | true | Finally.cs:54:10:54:11 | M3 | | Finally.cs:62:9:64:9 | {...} | Finally.cs:54:10:54:11 | M3 | | Finally.cs:63:13:63:18 | Before throw ...; | Finally.cs:54:10:54:11 | M3 | | Finally.cs:63:13:63:18 | throw ...; | Finally.cs:54:10:54:11 | M3 | -| Finally.cs:65:9:67:9 | After catch (...) {...} [match] | Finally.cs:54:10:54:11 | M3 | | Finally.cs:65:9:67:9 | After catch (...) {...} [no-match] | Finally.cs:54:10:54:11 | M3 | | Finally.cs:65:9:67:9 | catch (...) {...} | Finally.cs:54:10:54:11 | M3 | +| Finally.cs:65:26:65:26 | After Exception e [match] | Finally.cs:54:10:54:11 | M3 | +| Finally.cs:65:26:65:26 | After Exception e [no-match] | Finally.cs:54:10:54:11 | M3 | | Finally.cs:65:26:65:26 | Exception e | Finally.cs:54:10:54:11 | M3 | | Finally.cs:65:35:65:35 | access to local variable e | Finally.cs:54:10:54:11 | M3 | | Finally.cs:65:35:65:43 | After access to property Message | Finally.cs:54:10:54:11 | M3 | @@ -3719,9 +3728,10 @@ nodeEnclosing | Finally.cs:159:27:159:44 | Before object creation of type Exception | Finally.cs:147:10:147:11 | M8 | | Finally.cs:159:27:159:44 | object creation of type Exception | Finally.cs:147:10:147:11 | M8 | | Finally.cs:159:41:159:43 | "1" | Finally.cs:147:10:147:11 | M8 | -| Finally.cs:161:13:164:13 | After catch (...) {...} [match] | Finally.cs:147:10:147:11 | M8 | | Finally.cs:161:13:164:13 | After catch (...) {...} [no-match] | Finally.cs:147:10:147:11 | M8 | | Finally.cs:161:13:164:13 | catch (...) {...} | Finally.cs:147:10:147:11 | M8 | +| Finally.cs:161:30:161:30 | After Exception e [match] | Finally.cs:147:10:147:11 | M8 | +| Finally.cs:161:30:161:30 | After Exception e [no-match] | Finally.cs:147:10:147:11 | M8 | | Finally.cs:161:30:161:30 | Exception e | Finally.cs:147:10:147:11 | M8 | | Finally.cs:161:39:161:39 | access to local variable e | Finally.cs:147:10:147:11 | M8 | | Finally.cs:161:39:161:47 | After access to property Message | Finally.cs:147:10:147:11 | M8 | @@ -3744,7 +3754,6 @@ nodeEnclosing | Finally.cs:163:35:163:41 | Before access to array element | Finally.cs:147:10:147:11 | M8 | | Finally.cs:163:35:163:41 | access to array element | Finally.cs:147:10:147:11 | M8 | | Finally.cs:163:40:163:40 | 0 | Finally.cs:147:10:147:11 | M8 | -| Finally.cs:165:13:168:13 | After catch {...} [match] | Finally.cs:147:10:147:11 | M8 | | Finally.cs:165:13:168:13 | catch {...} | Finally.cs:147:10:147:11 | M8 | | Finally.cs:166:13:168:13 | After {...} | Finally.cs:147:10:147:11 | M8 | | Finally.cs:166:13:168:13 | {...} | Finally.cs:147:10:147:11 | M8 | @@ -3825,9 +3834,11 @@ nodeEnclosing | Finally.cs:186:31:186:46 | After object creation of type ExceptionB | Finally.cs:176:10:176:11 | M9 | | Finally.cs:186:31:186:46 | Before object creation of type ExceptionB | Finally.cs:176:10:176:11 | M9 | | Finally.cs:186:31:186:46 | object creation of type ExceptionB | Finally.cs:176:10:176:11 | M9 | -| Finally.cs:188:13:191:13 | After catch (...) {...} [match] | Finally.cs:176:10:176:11 | M9 | | Finally.cs:188:13:191:13 | After catch (...) {...} [no-match] | Finally.cs:176:10:176:11 | M9 | | Finally.cs:188:13:191:13 | catch (...) {...} | Finally.cs:176:10:176:11 | M9 | +| Finally.cs:188:20:188:29 | After access to type ExceptionB [match] | Finally.cs:176:10:176:11 | M9 | +| Finally.cs:188:20:188:29 | After access to type ExceptionB [no-match] | Finally.cs:176:10:176:11 | M9 | +| Finally.cs:188:20:188:29 | access to type ExceptionB | Finally.cs:176:10:176:11 | M9 | | Finally.cs:188:38:188:39 | After access to parameter b2 [false] | Finally.cs:176:10:176:11 | M9 | | Finally.cs:188:38:188:39 | After access to parameter b2 [true] | Finally.cs:176:10:176:11 | M9 | | Finally.cs:188:38:188:39 | access to parameter b2 | Finally.cs:176:10:176:11 | M9 | @@ -3929,7 +3940,6 @@ nodeEnclosing | Finally.cs:220:13:220:37 | ...; | Finally.cs:216:10:216:12 | M11 | | Finally.cs:220:13:220:37 | After ...; | Finally.cs:216:10:216:12 | M11 | | Finally.cs:220:31:220:35 | "Try" | Finally.cs:216:10:216:12 | M11 | -| Finally.cs:222:9:225:9 | After catch {...} [match] | Finally.cs:216:10:216:12 | M11 | | Finally.cs:222:9:225:9 | catch {...} | Finally.cs:216:10:216:12 | M11 | | Finally.cs:223:9:225:9 | After {...} | Finally.cs:216:10:216:12 | M11 | | Finally.cs:223:9:225:9 | {...} | Finally.cs:216:10:216:12 | M11 | @@ -8830,10 +8840,10 @@ blockEnclosing | ExitMethods.cs:38:10:38:11 | Entry | ExitMethods.cs:38:10:38:11 | M6 | | ExitMethods.cs:38:10:38:11 | Exit | ExitMethods.cs:38:10:38:11 | M6 | | ExitMethods.cs:38:10:38:11 | Normal Exit | ExitMethods.cs:38:10:38:11 | M6 | -| ExitMethods.cs:44:9:47:9 | After catch (...) {...} [match] | ExitMethods.cs:38:10:38:11 | M6 | -| ExitMethods.cs:44:9:47:9 | After catch (...) {...} [no-match] | ExitMethods.cs:38:10:38:11 | M6 | -| ExitMethods.cs:48:9:51:9 | After catch (...) {...} [match] | ExitMethods.cs:38:10:38:11 | M6 | -| ExitMethods.cs:48:9:51:9 | After catch (...) {...} [no-match] | ExitMethods.cs:38:10:38:11 | M6 | +| ExitMethods.cs:44:16:44:32 | After access to type ArgumentException [match] | ExitMethods.cs:38:10:38:11 | M6 | +| ExitMethods.cs:44:16:44:32 | After access to type ArgumentException [no-match] | ExitMethods.cs:38:10:38:11 | M6 | +| ExitMethods.cs:48:16:48:24 | After access to type Exception [match] | ExitMethods.cs:38:10:38:11 | M6 | +| ExitMethods.cs:48:16:48:24 | After access to type Exception [no-match] | ExitMethods.cs:38:10:38:11 | M6 | | ExitMethods.cs:54:10:54:11 | Entry | ExitMethods.cs:54:10:54:11 | M7 | | ExitMethods.cs:60:10:60:11 | Entry | ExitMethods.cs:60:10:60:11 | M8 | | ExitMethods.cs:66:17:66:26 | Entry | ExitMethods.cs:66:17:66:26 | ErrorMaybe | @@ -8888,13 +8898,13 @@ blockEnclosing | Finally.cs:19:10:19:11 | Normal Exit | Finally.cs:19:10:19:11 | M2 | | Finally.cs:21:9:51:9 | After try {...} ... | Finally.cs:19:10:19:11 | M2 | | Finally.cs:23:13:23:37 | After call to method WriteLine | Finally.cs:19:10:19:11 | M2 | -| Finally.cs:26:9:29:9 | After catch (...) {...} [match] | Finally.cs:19:10:19:11 | M2 | -| Finally.cs:26:9:29:9 | After catch (...) {...} [no-match] | Finally.cs:19:10:19:11 | M2 | | Finally.cs:26:9:29:9 | catch (...) {...} | Finally.cs:19:10:19:11 | M2 | -| Finally.cs:30:9:40:9 | After catch (...) {...} [match] | Finally.cs:19:10:19:11 | M2 | -| Finally.cs:30:9:40:9 | After catch (...) {...} [no-match] | Finally.cs:19:10:19:11 | M2 | -| Finally.cs:41:9:43:9 | After catch (...) {...} [match] | Finally.cs:19:10:19:11 | M2 | -| Finally.cs:41:9:43:9 | After catch (...) {...} [no-match] | Finally.cs:19:10:19:11 | M2 | +| Finally.cs:26:38:26:39 | After IOException ex [match] | Finally.cs:19:10:19:11 | M2 | +| Finally.cs:26:38:26:39 | After IOException ex [no-match] | Finally.cs:19:10:19:11 | M2 | +| Finally.cs:30:41:30:42 | After ArgumentException ex [match] | Finally.cs:19:10:19:11 | M2 | +| Finally.cs:30:41:30:42 | After ArgumentException ex [no-match] | Finally.cs:19:10:19:11 | M2 | +| Finally.cs:41:16:41:24 | After access to type Exception [match] | Finally.cs:19:10:19:11 | M2 | +| Finally.cs:41:16:41:24 | After access to type Exception [no-match] | Finally.cs:19:10:19:11 | M2 | | Finally.cs:49:9:51:9 | {...} | Finally.cs:19:10:19:11 | M2 | | Finally.cs:54:10:54:11 | Entry | Finally.cs:54:10:54:11 | M3 | | Finally.cs:54:10:54:11 | Exceptional Exit | Finally.cs:54:10:54:11 | M3 | @@ -8902,11 +8912,12 @@ blockEnclosing | Finally.cs:54:10:54:11 | Normal Exit | Finally.cs:54:10:54:11 | M3 | | Finally.cs:56:9:71:9 | After try {...} ... | Finally.cs:54:10:54:11 | M3 | | Finally.cs:58:13:58:37 | After call to method WriteLine | Finally.cs:54:10:54:11 | M3 | -| Finally.cs:61:9:64:9 | After catch (...) {...} [match] | Finally.cs:54:10:54:11 | M3 | -| Finally.cs:61:9:64:9 | After catch (...) {...} [no-match] | Finally.cs:54:10:54:11 | M3 | | Finally.cs:61:9:64:9 | catch (...) {...} | Finally.cs:54:10:54:11 | M3 | -| Finally.cs:65:9:67:9 | After catch (...) {...} [match] | Finally.cs:54:10:54:11 | M3 | +| Finally.cs:61:38:61:39 | After IOException ex [match] | Finally.cs:54:10:54:11 | M3 | +| Finally.cs:61:38:61:39 | After IOException ex [no-match] | Finally.cs:54:10:54:11 | M3 | | Finally.cs:65:9:67:9 | After catch (...) {...} [no-match] | Finally.cs:54:10:54:11 | M3 | +| Finally.cs:65:26:65:26 | After Exception e [match] | Finally.cs:54:10:54:11 | M3 | +| Finally.cs:65:26:65:26 | After Exception e [no-match] | Finally.cs:54:10:54:11 | M3 | | Finally.cs:65:35:65:51 | After ... != ... [false] | Finally.cs:54:10:54:11 | M3 | | Finally.cs:65:35:65:51 | After ... != ... [true] | Finally.cs:54:10:54:11 | M3 | | Finally.cs:69:9:71:9 | {...} | Finally.cs:54:10:54:11 | M3 | @@ -8969,9 +8980,10 @@ blockEnclosing | Finally.cs:158:21:158:36 | After ... == ... [false] | Finally.cs:147:10:147:11 | M8 | | Finally.cs:158:21:158:36 | After ... == ... [true] | Finally.cs:147:10:147:11 | M8 | | Finally.cs:159:27:159:44 | After object creation of type Exception | Finally.cs:147:10:147:11 | M8 | -| Finally.cs:161:13:164:13 | After catch (...) {...} [match] | Finally.cs:147:10:147:11 | M8 | | Finally.cs:161:13:164:13 | After catch (...) {...} [no-match] | Finally.cs:147:10:147:11 | M8 | | Finally.cs:161:13:164:13 | catch (...) {...} | Finally.cs:147:10:147:11 | M8 | +| Finally.cs:161:30:161:30 | After Exception e [match] | Finally.cs:147:10:147:11 | M8 | +| Finally.cs:161:30:161:30 | After Exception e [no-match] | Finally.cs:147:10:147:11 | M8 | | Finally.cs:161:39:161:54 | After ... == ... [false] | Finally.cs:147:10:147:11 | M8 | | Finally.cs:161:39:161:54 | After ... == ... [true] | Finally.cs:147:10:147:11 | M8 | | Finally.cs:172:11:172:20 | Entry | Finally.cs:172:11:172:20 | ExceptionA | @@ -8989,9 +9001,10 @@ blockEnclosing | Finally.cs:186:21:186:22 | After access to parameter b2 [false] | Finally.cs:176:10:176:11 | M9 | | Finally.cs:186:21:186:22 | After access to parameter b2 [true] | Finally.cs:176:10:176:11 | M9 | | Finally.cs:186:31:186:46 | After object creation of type ExceptionB | Finally.cs:176:10:176:11 | M9 | -| Finally.cs:188:13:191:13 | After catch (...) {...} [match] | Finally.cs:176:10:176:11 | M9 | | Finally.cs:188:13:191:13 | After catch (...) {...} [no-match] | Finally.cs:176:10:176:11 | M9 | | Finally.cs:188:13:191:13 | catch (...) {...} | Finally.cs:176:10:176:11 | M9 | +| Finally.cs:188:20:188:29 | After access to type ExceptionB [match] | Finally.cs:176:10:176:11 | M9 | +| Finally.cs:188:20:188:29 | After access to type ExceptionB [no-match] | Finally.cs:176:10:176:11 | M9 | | Finally.cs:188:38:188:39 | After access to parameter b2 [false] | Finally.cs:176:10:176:11 | M9 | | Finally.cs:188:38:188:39 | After access to parameter b2 [true] | Finally.cs:176:10:176:11 | M9 | | Finally.cs:190:21:190:22 | After access to parameter b1 [false] | Finally.cs:176:10:176:11 | M9 | diff --git a/csharp/ql/test/library-tests/controlflow/graph/EntryElement.expected b/csharp/ql/test/library-tests/controlflow/graph/EntryElement.expected index a6c15e141d0..24bd5a4c74e 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/EntryElement.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/EntryElement.expected @@ -1398,9 +1398,11 @@ | ExitMethods.cs:42:13:42:31 | ...; | ExitMethods.cs:42:13:42:31 | ...; | | ExitMethods.cs:42:25:42:29 | false | ExitMethods.cs:42:25:42:29 | false | | ExitMethods.cs:44:9:47:9 | catch (...) {...} | ExitMethods.cs:44:9:47:9 | catch (...) {...} | +| ExitMethods.cs:44:16:44:32 | access to type ArgumentException | ExitMethods.cs:44:16:44:32 | access to type ArgumentException | | ExitMethods.cs:45:9:47:9 | {...} | ExitMethods.cs:45:9:47:9 | {...} | | ExitMethods.cs:46:13:46:19 | return ...; | ExitMethods.cs:46:13:46:19 | return ...; | | ExitMethods.cs:48:9:51:9 | catch (...) {...} | ExitMethods.cs:48:9:51:9 | catch (...) {...} | +| ExitMethods.cs:48:16:48:24 | access to type Exception | ExitMethods.cs:48:16:48:24 | access to type Exception | | ExitMethods.cs:49:9:51:9 | {...} | ExitMethods.cs:49:9:51:9 | {...} | | ExitMethods.cs:50:13:50:19 | return ...; | ExitMethods.cs:50:13:50:19 | return ...; | | ExitMethods.cs:55:5:58:5 | {...} | ExitMethods.cs:55:5:58:5 | {...} | @@ -1569,6 +1571,7 @@ | Finally.cs:38:23:38:43 | object creation of type Exception | Finally.cs:38:37:38:42 | "Boo!" | | Finally.cs:38:37:38:42 | "Boo!" | Finally.cs:38:37:38:42 | "Boo!" | | Finally.cs:41:9:43:9 | catch (...) {...} | Finally.cs:41:9:43:9 | catch (...) {...} | +| Finally.cs:41:16:41:24 | access to type Exception | Finally.cs:41:16:41:24 | access to type Exception | | Finally.cs:42:9:43:9 | {...} | Finally.cs:42:9:43:9 | {...} | | Finally.cs:44:9:47:9 | catch {...} | Finally.cs:44:9:47:9 | catch {...} | | Finally.cs:45:9:47:9 | {...} | Finally.cs:45:9:47:9 | {...} | @@ -1766,6 +1769,7 @@ | Finally.cs:186:25:186:47 | throw ...; | Finally.cs:186:31:186:46 | object creation of type ExceptionB | | Finally.cs:186:31:186:46 | object creation of type ExceptionB | Finally.cs:186:31:186:46 | object creation of type ExceptionB | | Finally.cs:188:13:191:13 | catch (...) {...} | Finally.cs:188:13:191:13 | catch (...) {...} | +| Finally.cs:188:20:188:29 | access to type ExceptionB | Finally.cs:188:20:188:29 | access to type ExceptionB | | Finally.cs:188:38:188:39 | access to parameter b2 | Finally.cs:188:38:188:39 | access to parameter b2 | | Finally.cs:189:13:191:13 | {...} | Finally.cs:189:13:191:13 | {...} | | Finally.cs:190:17:190:47 | if (...) ... | Finally.cs:190:17:190:47 | if (...) ... | diff --git a/csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected b/csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected index da56986ea09..65f023491b2 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected @@ -3062,17 +3062,21 @@ | ExitMethods.cs:42:13:42:30 | call to method ErrorAlways | ExitMethods.cs:44:9:47:9 | catch (...) {...} | exception | | ExitMethods.cs:42:13:42:31 | ...; | ExitMethods.cs:42:13:42:30 | Before call to method ErrorAlways | | | ExitMethods.cs:42:25:42:29 | false | ExitMethods.cs:42:13:42:30 | call to method ErrorAlways | | -| ExitMethods.cs:44:9:47:9 | After catch (...) {...} [match] | ExitMethods.cs:45:9:47:9 | {...} | | | ExitMethods.cs:44:9:47:9 | After catch (...) {...} [no-match] | ExitMethods.cs:48:9:51:9 | catch (...) {...} | | -| ExitMethods.cs:44:9:47:9 | catch (...) {...} | ExitMethods.cs:44:9:47:9 | After catch (...) {...} [match] | match | -| ExitMethods.cs:44:9:47:9 | catch (...) {...} | ExitMethods.cs:44:9:47:9 | After catch (...) {...} [no-match] | no-match | +| ExitMethods.cs:44:9:47:9 | catch (...) {...} | ExitMethods.cs:44:16:44:32 | access to type ArgumentException | | +| ExitMethods.cs:44:16:44:32 | After access to type ArgumentException [match] | ExitMethods.cs:45:9:47:9 | {...} | | +| ExitMethods.cs:44:16:44:32 | After access to type ArgumentException [no-match] | ExitMethods.cs:44:9:47:9 | After catch (...) {...} [no-match] | no-match | +| ExitMethods.cs:44:16:44:32 | access to type ArgumentException | ExitMethods.cs:44:16:44:32 | After access to type ArgumentException [match] | match | +| ExitMethods.cs:44:16:44:32 | access to type ArgumentException | ExitMethods.cs:44:16:44:32 | After access to type ArgumentException [no-match] | no-match | | ExitMethods.cs:45:9:47:9 | {...} | ExitMethods.cs:46:13:46:19 | Before return ...; | | | ExitMethods.cs:46:13:46:19 | Before return ...; | ExitMethods.cs:46:13:46:19 | return ...; | | | ExitMethods.cs:46:13:46:19 | return ...; | ExitMethods.cs:38:10:38:11 | Normal Exit | return | -| ExitMethods.cs:48:9:51:9 | After catch (...) {...} [match] | ExitMethods.cs:49:9:51:9 | {...} | | | ExitMethods.cs:48:9:51:9 | After catch (...) {...} [no-match] | ExitMethods.cs:38:10:38:11 | Exceptional Exit | exception | -| ExitMethods.cs:48:9:51:9 | catch (...) {...} | ExitMethods.cs:48:9:51:9 | After catch (...) {...} [match] | match | -| ExitMethods.cs:48:9:51:9 | catch (...) {...} | ExitMethods.cs:48:9:51:9 | After catch (...) {...} [no-match] | no-match | +| ExitMethods.cs:48:9:51:9 | catch (...) {...} | ExitMethods.cs:48:16:48:24 | access to type Exception | | +| ExitMethods.cs:48:16:48:24 | After access to type Exception [match] | ExitMethods.cs:49:9:51:9 | {...} | | +| ExitMethods.cs:48:16:48:24 | After access to type Exception [no-match] | ExitMethods.cs:48:9:51:9 | After catch (...) {...} [no-match] | no-match | +| ExitMethods.cs:48:16:48:24 | access to type Exception | ExitMethods.cs:48:16:48:24 | After access to type Exception [match] | match | +| ExitMethods.cs:48:16:48:24 | access to type Exception | ExitMethods.cs:48:16:48:24 | After access to type Exception [no-match] | no-match | | ExitMethods.cs:49:9:51:9 | {...} | ExitMethods.cs:50:13:50:19 | Before return ...; | | | ExitMethods.cs:50:13:50:19 | Before return ...; | ExitMethods.cs:50:13:50:19 | return ...; | | | ExitMethods.cs:50:13:50:19 | return ...; | ExitMethods.cs:38:10:38:11 | Normal Exit | return | @@ -3393,21 +3397,23 @@ | Finally.cs:23:31:23:36 | "Try2" | Finally.cs:23:13:23:37 | call to method WriteLine | | | Finally.cs:24:13:24:19 | Before return ...; | Finally.cs:24:13:24:19 | return ...; | | | Finally.cs:24:13:24:19 | return ...; | Finally.cs:49:9:51:9 | {...} | return | -| Finally.cs:26:9:29:9 | After catch (...) {...} [match] | Finally.cs:26:38:26:39 | IOException ex | | | Finally.cs:26:9:29:9 | After catch (...) {...} [no-match] | Finally.cs:30:9:40:9 | catch (...) {...} | | -| Finally.cs:26:9:29:9 | catch (...) {...} | Finally.cs:26:9:29:9 | After catch (...) {...} [match] | match | -| Finally.cs:26:9:29:9 | catch (...) {...} | Finally.cs:26:9:29:9 | After catch (...) {...} [no-match] | no-match | -| Finally.cs:26:38:26:39 | IOException ex | Finally.cs:26:48:26:51 | true | | +| Finally.cs:26:9:29:9 | catch (...) {...} | Finally.cs:26:38:26:39 | IOException ex | | +| Finally.cs:26:38:26:39 | After IOException ex [match] | Finally.cs:26:48:26:51 | true | | +| Finally.cs:26:38:26:39 | After IOException ex [no-match] | Finally.cs:26:9:29:9 | After catch (...) {...} [no-match] | no-match | +| Finally.cs:26:38:26:39 | IOException ex | Finally.cs:26:38:26:39 | After IOException ex [match] | match | +| Finally.cs:26:38:26:39 | IOException ex | Finally.cs:26:38:26:39 | After IOException ex [no-match] | no-match | | Finally.cs:26:48:26:51 | After true [true] | Finally.cs:27:9:29:9 | {...} | | | Finally.cs:26:48:26:51 | true | Finally.cs:26:48:26:51 | After true [true] | true | | Finally.cs:27:9:29:9 | {...} | Finally.cs:28:13:28:18 | Before throw ...; | | | Finally.cs:28:13:28:18 | Before throw ...; | Finally.cs:28:13:28:18 | throw ...; | | | Finally.cs:28:13:28:18 | throw ...; | Finally.cs:49:9:51:9 | {...} | exception | -| Finally.cs:30:9:40:9 | After catch (...) {...} [match] | Finally.cs:30:41:30:42 | ArgumentException ex | | | Finally.cs:30:9:40:9 | After catch (...) {...} [no-match] | Finally.cs:41:9:43:9 | catch (...) {...} | | -| Finally.cs:30:9:40:9 | catch (...) {...} | Finally.cs:30:9:40:9 | After catch (...) {...} [match] | match | -| Finally.cs:30:9:40:9 | catch (...) {...} | Finally.cs:30:9:40:9 | After catch (...) {...} [no-match] | no-match | -| Finally.cs:30:41:30:42 | ArgumentException ex | Finally.cs:31:9:40:9 | {...} | | +| Finally.cs:30:9:40:9 | catch (...) {...} | Finally.cs:30:41:30:42 | ArgumentException ex | | +| Finally.cs:30:41:30:42 | After ArgumentException ex [match] | Finally.cs:31:9:40:9 | {...} | | +| Finally.cs:30:41:30:42 | After ArgumentException ex [no-match] | Finally.cs:30:9:40:9 | After catch (...) {...} [no-match] | no-match | +| Finally.cs:30:41:30:42 | ArgumentException ex | Finally.cs:30:41:30:42 | After ArgumentException ex [match] | match | +| Finally.cs:30:41:30:42 | ArgumentException ex | Finally.cs:30:41:30:42 | After ArgumentException ex [no-match] | no-match | | Finally.cs:31:9:40:9 | {...} | Finally.cs:32:13:39:13 | try {...} ... | | | Finally.cs:32:13:39:13 | try {...} ... | Finally.cs:33:13:35:13 | {...} | | | Finally.cs:33:13:35:13 | {...} | Finally.cs:34:17:34:32 | if (...) ... | | @@ -3423,13 +3429,14 @@ | Finally.cs:38:23:38:43 | Before object creation of type Exception | Finally.cs:38:37:38:42 | "Boo!" | | | Finally.cs:38:23:38:43 | object creation of type Exception | Finally.cs:38:23:38:43 | After object creation of type Exception | | | Finally.cs:38:37:38:42 | "Boo!" | Finally.cs:38:23:38:43 | object creation of type Exception | | -| Finally.cs:41:9:43:9 | After catch (...) {...} [match] | Finally.cs:42:9:43:9 | {...} | | | Finally.cs:41:9:43:9 | After catch (...) {...} [no-match] | Finally.cs:44:9:47:9 | catch {...} | | -| Finally.cs:41:9:43:9 | catch (...) {...} | Finally.cs:41:9:43:9 | After catch (...) {...} [match] | match | -| Finally.cs:41:9:43:9 | catch (...) {...} | Finally.cs:41:9:43:9 | After catch (...) {...} [no-match] | no-match | +| Finally.cs:41:9:43:9 | catch (...) {...} | Finally.cs:41:16:41:24 | access to type Exception | | +| Finally.cs:41:16:41:24 | After access to type Exception [match] | Finally.cs:42:9:43:9 | {...} | | +| Finally.cs:41:16:41:24 | After access to type Exception [no-match] | Finally.cs:41:9:43:9 | After catch (...) {...} [no-match] | no-match | +| Finally.cs:41:16:41:24 | access to type Exception | Finally.cs:41:16:41:24 | After access to type Exception [match] | match | +| Finally.cs:41:16:41:24 | access to type Exception | Finally.cs:41:16:41:24 | After access to type Exception [no-match] | no-match | | Finally.cs:42:9:43:9 | {...} | Finally.cs:49:9:51:9 | {...} | | -| Finally.cs:44:9:47:9 | After catch {...} [match] | Finally.cs:45:9:47:9 | {...} | | -| Finally.cs:44:9:47:9 | catch {...} | Finally.cs:44:9:47:9 | After catch {...} [match] | match | +| Finally.cs:44:9:47:9 | catch {...} | Finally.cs:45:9:47:9 | {...} | | | Finally.cs:45:9:47:9 | {...} | Finally.cs:46:13:46:19 | Before return ...; | | | Finally.cs:46:13:46:19 | Before return ...; | Finally.cs:46:13:46:19 | return ...; | | | Finally.cs:46:13:46:19 | return ...; | Finally.cs:49:9:51:9 | {...} | return | @@ -3460,21 +3467,23 @@ | Finally.cs:58:31:58:36 | "Try3" | Finally.cs:58:13:58:37 | call to method WriteLine | | | Finally.cs:59:13:59:19 | Before return ...; | Finally.cs:59:13:59:19 | return ...; | | | Finally.cs:59:13:59:19 | return ...; | Finally.cs:69:9:71:9 | {...} | return | -| Finally.cs:61:9:64:9 | After catch (...) {...} [match] | Finally.cs:61:38:61:39 | IOException ex | | | Finally.cs:61:9:64:9 | After catch (...) {...} [no-match] | Finally.cs:65:9:67:9 | catch (...) {...} | | -| Finally.cs:61:9:64:9 | catch (...) {...} | Finally.cs:61:9:64:9 | After catch (...) {...} [match] | match | -| Finally.cs:61:9:64:9 | catch (...) {...} | Finally.cs:61:9:64:9 | After catch (...) {...} [no-match] | no-match | -| Finally.cs:61:38:61:39 | IOException ex | Finally.cs:61:48:61:51 | true | | +| Finally.cs:61:9:64:9 | catch (...) {...} | Finally.cs:61:38:61:39 | IOException ex | | +| Finally.cs:61:38:61:39 | After IOException ex [match] | Finally.cs:61:48:61:51 | true | | +| Finally.cs:61:38:61:39 | After IOException ex [no-match] | Finally.cs:61:9:64:9 | After catch (...) {...} [no-match] | no-match | +| Finally.cs:61:38:61:39 | IOException ex | Finally.cs:61:38:61:39 | After IOException ex [match] | match | +| Finally.cs:61:38:61:39 | IOException ex | Finally.cs:61:38:61:39 | After IOException ex [no-match] | no-match | | Finally.cs:61:48:61:51 | After true [true] | Finally.cs:62:9:64:9 | {...} | | | Finally.cs:61:48:61:51 | true | Finally.cs:61:48:61:51 | After true [true] | true | | Finally.cs:62:9:64:9 | {...} | Finally.cs:63:13:63:18 | Before throw ...; | | | Finally.cs:63:13:63:18 | Before throw ...; | Finally.cs:63:13:63:18 | throw ...; | | | Finally.cs:63:13:63:18 | throw ...; | Finally.cs:69:9:71:9 | {...} | exception | -| Finally.cs:65:9:67:9 | After catch (...) {...} [match] | Finally.cs:65:26:65:26 | Exception e | | | Finally.cs:65:9:67:9 | After catch (...) {...} [no-match] | Finally.cs:69:9:71:9 | {...} | exception | -| Finally.cs:65:9:67:9 | catch (...) {...} | Finally.cs:65:9:67:9 | After catch (...) {...} [match] | match | -| Finally.cs:65:9:67:9 | catch (...) {...} | Finally.cs:65:9:67:9 | After catch (...) {...} [no-match] | no-match | -| Finally.cs:65:26:65:26 | Exception e | Finally.cs:65:35:65:51 | Before ... != ... | | +| Finally.cs:65:9:67:9 | catch (...) {...} | Finally.cs:65:26:65:26 | Exception e | | +| Finally.cs:65:26:65:26 | After Exception e [match] | Finally.cs:65:35:65:51 | Before ... != ... | | +| Finally.cs:65:26:65:26 | After Exception e [no-match] | Finally.cs:65:9:67:9 | After catch (...) {...} [no-match] | no-match | +| Finally.cs:65:26:65:26 | Exception e | Finally.cs:65:26:65:26 | After Exception e [match] | match | +| Finally.cs:65:26:65:26 | Exception e | Finally.cs:65:26:65:26 | After Exception e [no-match] | no-match | | Finally.cs:65:35:65:35 | access to local variable e | Finally.cs:65:35:65:43 | access to property Message | | | Finally.cs:65:35:65:43 | After access to property Message | Finally.cs:65:48:65:51 | null | | | Finally.cs:65:35:65:43 | Before access to property Message | Finally.cs:65:35:65:35 | access to local variable e | | @@ -3787,11 +3796,12 @@ | Finally.cs:159:27:159:44 | object creation of type Exception | Finally.cs:159:27:159:44 | After object creation of type Exception | | | Finally.cs:159:27:159:44 | object creation of type Exception | Finally.cs:161:13:164:13 | catch (...) {...} | exception | | Finally.cs:159:41:159:43 | "1" | Finally.cs:159:27:159:44 | object creation of type Exception | | -| Finally.cs:161:13:164:13 | After catch (...) {...} [match] | Finally.cs:161:30:161:30 | Exception e | | | Finally.cs:161:13:164:13 | After catch (...) {...} [no-match] | Finally.cs:165:13:168:13 | catch {...} | | -| Finally.cs:161:13:164:13 | catch (...) {...} | Finally.cs:161:13:164:13 | After catch (...) {...} [match] | match | -| Finally.cs:161:13:164:13 | catch (...) {...} | Finally.cs:161:13:164:13 | After catch (...) {...} [no-match] | no-match | -| Finally.cs:161:30:161:30 | Exception e | Finally.cs:161:39:161:54 | Before ... == ... | | +| Finally.cs:161:13:164:13 | catch (...) {...} | Finally.cs:161:30:161:30 | Exception e | | +| Finally.cs:161:30:161:30 | After Exception e [match] | Finally.cs:161:39:161:54 | Before ... == ... | | +| Finally.cs:161:30:161:30 | After Exception e [no-match] | Finally.cs:161:13:164:13 | After catch (...) {...} [no-match] | no-match | +| Finally.cs:161:30:161:30 | Exception e | Finally.cs:161:30:161:30 | After Exception e [match] | match | +| Finally.cs:161:30:161:30 | Exception e | Finally.cs:161:30:161:30 | After Exception e [no-match] | no-match | | Finally.cs:161:39:161:39 | access to local variable e | Finally.cs:161:39:161:47 | access to property Message | | | Finally.cs:161:39:161:47 | After access to property Message | Finally.cs:161:52:161:54 | "1" | | | Finally.cs:161:39:161:47 | Before access to property Message | Finally.cs:161:39:161:39 | access to local variable e | | @@ -3814,8 +3824,7 @@ | Finally.cs:163:35:163:41 | Before access to array element | Finally.cs:163:35:163:38 | access to parameter args | | | Finally.cs:163:35:163:41 | access to array element | Finally.cs:163:35:163:41 | After access to array element | | | Finally.cs:163:40:163:40 | 0 | Finally.cs:163:35:163:41 | access to array element | | -| Finally.cs:165:13:168:13 | After catch {...} [match] | Finally.cs:166:13:168:13 | {...} | | -| Finally.cs:165:13:168:13 | catch {...} | Finally.cs:165:13:168:13 | After catch {...} [match] | match | +| Finally.cs:165:13:168:13 | catch {...} | Finally.cs:166:13:168:13 | {...} | | | Finally.cs:166:13:168:13 | After {...} | Finally.cs:156:13:168:13 | After try {...} ... | | | Finally.cs:166:13:168:13 | {...} | Finally.cs:167:17:167:38 | ...; | | | Finally.cs:167:17:167:37 | After call to method WriteLine | Finally.cs:167:17:167:38 | After ...; | | @@ -3896,10 +3905,12 @@ | Finally.cs:186:31:186:46 | Before object creation of type ExceptionB | Finally.cs:186:31:186:46 | object creation of type ExceptionB | | | Finally.cs:186:31:186:46 | object creation of type ExceptionB | Finally.cs:186:31:186:46 | After object creation of type ExceptionB | | | Finally.cs:186:31:186:46 | object creation of type ExceptionB | Finally.cs:188:13:191:13 | catch (...) {...} | exception | -| Finally.cs:188:13:191:13 | After catch (...) {...} [match] | Finally.cs:188:38:188:39 | access to parameter b2 | | | Finally.cs:188:13:191:13 | After catch (...) {...} [no-match] | Finally.cs:176:10:176:11 | Exceptional Exit | exception | -| Finally.cs:188:13:191:13 | catch (...) {...} | Finally.cs:188:13:191:13 | After catch (...) {...} [match] | match | -| Finally.cs:188:13:191:13 | catch (...) {...} | Finally.cs:188:13:191:13 | After catch (...) {...} [no-match] | no-match | +| Finally.cs:188:13:191:13 | catch (...) {...} | Finally.cs:188:20:188:29 | access to type ExceptionB | | +| Finally.cs:188:20:188:29 | After access to type ExceptionB [match] | Finally.cs:188:38:188:39 | access to parameter b2 | | +| Finally.cs:188:20:188:29 | After access to type ExceptionB [no-match] | Finally.cs:188:13:191:13 | After catch (...) {...} [no-match] | no-match | +| Finally.cs:188:20:188:29 | access to type ExceptionB | Finally.cs:188:20:188:29 | After access to type ExceptionB [match] | match | +| Finally.cs:188:20:188:29 | access to type ExceptionB | Finally.cs:188:20:188:29 | After access to type ExceptionB [no-match] | no-match | | Finally.cs:188:38:188:39 | After access to parameter b2 [false] | Finally.cs:188:13:191:13 | After catch (...) {...} [no-match] | no-match | | Finally.cs:188:38:188:39 | After access to parameter b2 [true] | Finally.cs:189:13:191:13 | {...} | | | Finally.cs:188:38:188:39 | access to parameter b2 | Finally.cs:188:38:188:39 | After access to parameter b2 [false] | false | @@ -4009,8 +4020,7 @@ | Finally.cs:220:13:220:37 | ...; | Finally.cs:220:13:220:36 | Before call to method WriteLine | | | Finally.cs:220:13:220:37 | After ...; | Finally.cs:219:9:221:9 | After {...} | | | Finally.cs:220:31:220:35 | "Try" | Finally.cs:220:13:220:36 | call to method WriteLine | | -| Finally.cs:222:9:225:9 | After catch {...} [match] | Finally.cs:223:9:225:9 | {...} | | -| Finally.cs:222:9:225:9 | catch {...} | Finally.cs:222:9:225:9 | After catch {...} [match] | match | +| Finally.cs:222:9:225:9 | catch {...} | Finally.cs:223:9:225:9 | {...} | | | Finally.cs:223:9:225:9 | After {...} | Finally.cs:227:9:229:9 | {...} | | | Finally.cs:223:9:225:9 | {...} | Finally.cs:224:13:224:39 | ...; | | | Finally.cs:224:13:224:38 | After call to method WriteLine | Finally.cs:224:13:224:39 | After ...; | | diff --git a/csharp/ql/test/library-tests/csharp6/PrintAst.expected b/csharp/ql/test/library-tests/csharp6/PrintAst.expected index 78747650190..7471277e1ce 100644 --- a/csharp/ql/test/library-tests/csharp6/PrintAst.expected +++ b/csharp/ql/test/library-tests/csharp6/PrintAst.expected @@ -101,6 +101,8 @@ csharp6.cs: # 32| 0: [IntLiteral] 2 # 32| 0: [IntLiteral] 1 # 34| 1: [SpecificCatchClause] catch (...) {...} +# 34| 0: [TypeAccess] access to type IndexOutOfRangeException +# 34| 0: [TypeMention] IndexOutOfRangeException # 35| 1: [BlockStmt] {...} # 34| 2: [EQExpr] ... == ... # 34| 0: [PropertyCall] access to property Value diff --git a/csharp/ql/test/library-tests/csharp8/switchexprcontrolflow.expected b/csharp/ql/test/library-tests/csharp8/switchexprcontrolflow.expected index 4493882fa47..5eacd99b7e6 100644 --- a/csharp/ql/test/library-tests/csharp8/switchexprcontrolflow.expected +++ b/csharp/ql/test/library-tests/csharp8/switchexprcontrolflow.expected @@ -336,11 +336,12 @@ | patterns.cs:142:26:142:34 | { ... } | patterns.cs:142:26:142:34 | After { ... } | semmle.label | successor | | patterns.cs:142:31:142:32 | 10 | patterns.cs:142:26:142:34 | { ... } | semmle.label | successor | | patterns.cs:142:41:142:41 | 6 | patterns.cs:136:17:143:13 | After ... switch { ... } | semmle.label | successor | -| patterns.cs:145:9:148:9 | After catch (...) {...} [match] | patterns.cs:145:41:145:42 | InvalidOperationException ex | semmle.label | successor | | patterns.cs:145:9:148:9 | After catch (...) {...} [no-match] | patterns.cs:123:10:123:21 | Exceptional Exit | semmle.label | exception | -| patterns.cs:145:9:148:9 | catch (...) {...} | patterns.cs:145:9:148:9 | After catch (...) {...} [match] | semmle.label | match | -| patterns.cs:145:9:148:9 | catch (...) {...} | patterns.cs:145:9:148:9 | After catch (...) {...} [no-match] | semmle.label | no-match | -| patterns.cs:145:41:145:42 | InvalidOperationException ex | patterns.cs:146:9:148:9 | {...} | semmle.label | successor | +| patterns.cs:145:9:148:9 | catch (...) {...} | patterns.cs:145:41:145:42 | InvalidOperationException ex | semmle.label | successor | +| patterns.cs:145:41:145:42 | After InvalidOperationException ex [match] | patterns.cs:146:9:148:9 | {...} | semmle.label | successor | +| patterns.cs:145:41:145:42 | After InvalidOperationException ex [no-match] | patterns.cs:145:9:148:9 | After catch (...) {...} [no-match] | semmle.label | no-match | +| patterns.cs:145:41:145:42 | InvalidOperationException ex | patterns.cs:145:41:145:42 | After InvalidOperationException ex [match] | semmle.label | match | +| patterns.cs:145:41:145:42 | InvalidOperationException ex | patterns.cs:145:41:145:42 | After InvalidOperationException ex [no-match] | semmle.label | no-match | | patterns.cs:146:9:148:9 | After {...} | patterns.cs:134:9:148:9 | After try {...} ... | semmle.label | successor | | patterns.cs:146:9:148:9 | {...} | patterns.cs:147:13:147:51 | ...; | semmle.label | successor | | patterns.cs:147:13:147:50 | After call to method WriteLine | patterns.cs:147:13:147:51 | After ...; | semmle.label | successor | diff --git a/csharp/ql/test/library-tests/regressions/Program.cs b/csharp/ql/test/library-tests/regressions/Program.cs index dd73876f1a3..74bcf994681 100644 --- a/csharp/ql/test/library-tests/regressions/Program.cs +++ b/csharp/ql/test/library-tests/regressions/Program.cs @@ -194,3 +194,16 @@ class C3 : C2> { } class C4 : C2> { } class C5 : C4 { } + +class CatchTypeMentions +{ + void F() + { + try + { + } + catch (Exception) + { + } + } +} diff --git a/csharp/ql/test/library-tests/regressions/TypeMentions.expected b/csharp/ql/test/library-tests/regressions/TypeMentions.expected index 6c9e25efd0a..c5aad0df1bd 100644 --- a/csharp/ql/test/library-tests/regressions/TypeMentions.expected +++ b/csharp/ql/test/library-tests/regressions/TypeMentions.expected @@ -100,3 +100,5 @@ | Program.cs:194:21:194:21 | T | | Program.cs:196:12:196:17 | C4 | | Program.cs:196:15:196:16 | C5 | +| Program.cs:200:5:200:8 | Void | +| Program.cs:205:16:205:24 | Exception | diff --git a/docs/codeql/reusables/supported-versions-compilers.rst b/docs/codeql/reusables/supported-versions-compilers.rst index b73c9d7e6e9..7a88dd035c2 100644 --- a/docs/codeql/reusables/supported-versions-compilers.rst +++ b/docs/codeql/reusables/supported-versions-compilers.rst @@ -21,7 +21,7 @@ Java,"Java 7 to 26 [6]_","javac (OpenJDK and Oracle JDK), Eclipse compiler for Java (ECJ) [7]_",``.java`` - Kotlin,"Kotlin 1.8.0 to 2.3.2\ *x*","kotlinc",``.kt`` + Kotlin,"Kotlin 1.8.0 to 2.4.0\ *x*","kotlinc",``.kt`` JavaScript,ECMAScript 2022 or lower,Not applicable,"``.js``, ``.jsx``, ``.mjs``, ``.es``, ``.es6``, ``.htm``, ``.html``, ``.xhtm``, ``.xhtml``, ``.vue``, ``.hbs``, ``.ejs``, ``.njk``, ``.json``, ``.yaml``, ``.yml``, ``.raml``, ``.xml`` [8]_" Python [9]_,"2.7, 3.5, 3.6, 3.7, 3.8, 3.9, 3.10, 3.11, 3.12, 3.13",Not applicable,``.py`` Ruby [10]_,"up to 3.3",Not applicable,"``.rb``, ``.erb``, ``.gemspec``, ``Gemfile``" diff --git a/go/documentation/library-coverage/coverage.csv b/go/documentation/library-coverage/coverage.csv index 2c76dcf1155..12b10fbb9e1 100644 --- a/go/documentation/library-coverage/coverage.csv +++ b/go/documentation/library-coverage/coverage.csv @@ -123,7 +123,7 @@ k8s.io/api/core,,,10,,,,,,,,,,,,,,,,,,,,,,,10, k8s.io/apimachinery/pkg/runtime,,,47,,,,,,,,,,,,,,,,,,,,,,,47, k8s.io/klog,90,,,,,,90,,,,,,,,,,,,,,,,,,,, launchpad.net/xmlpath,2,,,,,,,,,,,,,,,,,,2,,,,,,,, -log,20,,3,,,,20,,,,,,,,,,,,,,,,,,,3, +log,40,,3,,,,40,,,,,,,,,,,,,,,,,,,3, math/big,,,1,,,,,,,,,,,,,,,,,,,,,,,1, mime,,,14,,,,,,,,,,,,,,,,,,,,,,,14, net,2,16,100,,,,,,1,,,,,,,,1,,,,,,,16,,100, diff --git a/go/documentation/library-coverage/coverage.rst b/go/documentation/library-coverage/coverage.rst index 80330c3715e..7d84b2022da 100644 --- a/go/documentation/library-coverage/coverage.rst +++ b/go/documentation/library-coverage/coverage.rst @@ -32,7 +32,7 @@ Go framework & library support `Revel `_,"``github.com/revel/revel*``, ``github.com/robfig/revel*``",46,20,4 `SendGrid `_,``github.com/sendgrid/sendgrid-go*``,,1, `Squirrel `_,"``github.com/Masterminds/squirrel*``, ``github.com/lann/squirrel*``, ``gopkg.in/Masterminds/squirrel``",81,,96 - `Standard library `_,"````, ``archive/*``, ``bufio``, ``bytes``, ``cmp``, ``compress/*``, ``container/*``, ``context``, ``crypto``, ``crypto/*``, ``database/*``, ``debug/*``, ``embed``, ``encoding``, ``encoding/*``, ``errors``, ``expvar``, ``flag``, ``fmt``, ``go/*``, ``hash``, ``hash/*``, ``html``, ``html/*``, ``image``, ``image/*``, ``index/*``, ``io``, ``io/*``, ``log``, ``log/*``, ``maps``, ``math``, ``math/*``, ``mime``, ``mime/*``, ``net``, ``net/*``, ``os``, ``os/*``, ``path``, ``path/*``, ``plugin``, ``reflect``, ``reflect/*``, ``regexp``, ``regexp/*``, ``slices``, ``sort``, ``strconv``, ``strings``, ``sync``, ``sync/*``, ``syscall``, ``syscall/*``, ``testing``, ``testing/*``, ``text/*``, ``time``, ``time/*``, ``unicode``, ``unicode/*``, ``unsafe``, ``weak``",52,612,104 + `Standard library `_,"````, ``archive/*``, ``bufio``, ``bytes``, ``cmp``, ``compress/*``, ``container/*``, ``context``, ``crypto``, ``crypto/*``, ``database/*``, ``debug/*``, ``embed``, ``encoding``, ``encoding/*``, ``errors``, ``expvar``, ``flag``, ``fmt``, ``go/*``, ``hash``, ``hash/*``, ``html``, ``html/*``, ``image``, ``image/*``, ``index/*``, ``io``, ``io/*``, ``log``, ``log/*``, ``maps``, ``math``, ``math/*``, ``mime``, ``mime/*``, ``net``, ``net/*``, ``os``, ``os/*``, ``path``, ``path/*``, ``plugin``, ``reflect``, ``reflect/*``, ``regexp``, ``regexp/*``, ``slices``, ``sort``, ``strconv``, ``strings``, ``sync``, ``sync/*``, ``syscall``, ``syscall/*``, ``testing``, ``testing/*``, ``text/*``, ``time``, ``time/*``, ``unicode``, ``unicode/*``, ``unsafe``, ``weak``",52,612,124 `XORM `_,"``github.com/go-xorm/xorm*``, ``xorm.io/xorm*``",,,68 `XPath `_,``github.com/antchfx/xpath*``,,,4 `appleboy/gin-jwt `_,``github.com/appleboy/gin-jwt*``,,,1 @@ -74,5 +74,5 @@ Go framework & library support `xpathparser `_,``github.com/santhosh-tekuri/xpathparser*``,,,2 `yaml `_,``gopkg.in/yaml*``,,9, `zap `_,``go.uber.org/zap*``,,11,33 - Totals,,688,1072,1557 + Totals,,688,1072,1577 diff --git a/go/extractor/go.mod b/go/extractor/go.mod index 5de56683a3e..cea20f1bd4a 100644 --- a/go/extractor/go.mod +++ b/go/extractor/go.mod @@ -10,7 +10,7 @@ toolchain go1.26.4 // bazel mod tidy require ( golang.org/x/mod v0.37.0 - golang.org/x/tools v0.46.0 + golang.org/x/tools v0.47.0 ) require github.com/stretchr/testify v1.11.1 diff --git a/go/extractor/go.sum b/go/extractor/go.sum index 55bcadfe98a..a928a105f68 100644 --- a/go/extractor/go.sum +++ b/go/extractor/go.sum @@ -10,8 +10,8 @@ golang.org/x/mod v0.37.0 h1:vF1DjpVEshcIqoEaauuHebaLk1O1forxjxBaVn884JQ= golang.org/x/mod v0.37.0/go.mod h1:m8S8VeM9r4dzDwjrKO0a1sZP3YjeMamRRlD+fmR2Q/0= golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM= golang.org/x/sync v0.21.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= -golang.org/x/tools v0.46.0 h1:7jTurBkPZu4moS/Uy4OQT1M+QBlsj3wejyZwsT8Z7rk= -golang.org/x/tools v0.46.0/go.mod h1:FrD85F8l+NWL+9XWBSyVSHO6Ne4jutsfIFba7AWQ5Ys= +golang.org/x/tools v0.47.0 h1:7Kn5x/d1svx/PzryTsqeoZN4TZwqeH5pGWjefhLi/1Q= +golang.org/x/tools v0.47.0/go.mod h1:dFHnyTvFWY212G+h7ZY4Vsp/K3U4/7W9TyVaAul8uCA= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/go/ql/consistency-queries/CHANGELOG.md b/go/ql/consistency-queries/CHANGELOG.md index 14258018aea..1b79dbf69e2 100644 --- a/go/ql/consistency-queries/CHANGELOG.md +++ b/go/ql/consistency-queries/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.52 + +No user-facing changes. + ## 1.0.51 No user-facing changes. diff --git a/go/ql/consistency-queries/change-notes/released/1.0.52.md b/go/ql/consistency-queries/change-notes/released/1.0.52.md new file mode 100644 index 00000000000..a91f5a8025d --- /dev/null +++ b/go/ql/consistency-queries/change-notes/released/1.0.52.md @@ -0,0 +1,3 @@ +## 1.0.52 + +No user-facing changes. diff --git a/go/ql/consistency-queries/codeql-pack.release.yml b/go/ql/consistency-queries/codeql-pack.release.yml index 232dbe38ec8..ea1d2eed4d2 100644 --- a/go/ql/consistency-queries/codeql-pack.release.yml +++ b/go/ql/consistency-queries/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.0.51 +lastReleaseVersion: 1.0.52 diff --git a/go/ql/consistency-queries/qlpack.yml b/go/ql/consistency-queries/qlpack.yml index 6938858c6ba..486dcf5c9f8 100644 --- a/go/ql/consistency-queries/qlpack.yml +++ b/go/ql/consistency-queries/qlpack.yml @@ -1,5 +1,5 @@ name: codeql-go-consistency-queries -version: 1.0.52-dev +version: 1.0.53-dev groups: - go - queries diff --git a/go/ql/lib/CHANGELOG.md b/go/ql/lib/CHANGELOG.md index 0d5738ad029..29a5bfbf178 100644 --- a/go/ql/lib/CHANGELOG.md +++ b/go/ql/lib/CHANGELOG.md @@ -1,3 +1,20 @@ +## 7.2.0 + +### Deprecated APIs + +* `FuncTypeExpr.getResultDecl()` has been deprecated. Use `FuncTypeExpr.getResultDecl(int i)` instead. + +### Minor Analysis Improvements + +* Added models for the `log/slog` package (Go 1.21+). Its logging functions and + `*slog.Logger` methods (`Debug`/`Info`/`Warn`/`Error`, their `Context` + variants, and `Log`/`LogAttrs`) are now recognized as logging sinks, so the + `go/log-injection` and `go/clear-text-logging` queries cover code that logs + through `slog`. +* `DataFlow::ResultNode`s are no longer created for returned expressions in functions with named result parameters. In this case there are already result nodes corresponding to `IR::ReadResultInstruction`s at the end of the function body. +* `FuncTypeExpr.getNumResult()` now gets the number of result parameters. It previously got the number of result declarations, which is different when one result declaration declares more than one variable, as in `x, y int`. All uses of it expected the number of result parameters. Its QLDoc has been updated. +* More logging functions are now recognized as not returning or panicking. + ## 7.1.2 No user-facing changes. diff --git a/go/ql/lib/change-notes/2026-06-01-non-returning-functions.md b/go/ql/lib/change-notes/2026-06-01-non-returning-functions.md deleted file mode 100644 index c48b2f32f83..00000000000 --- a/go/ql/lib/change-notes/2026-06-01-non-returning-functions.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: minorAnalysis ---- -* More logging functions are now recognized as not returning or panicking. diff --git a/go/ql/lib/change-notes/2026-06-08-deprecate-functypeexpr-getresultdecl.md b/go/ql/lib/change-notes/2026-06-08-deprecate-functypeexpr-getresultdecl.md deleted file mode 100644 index 157fa33bf6a..00000000000 --- a/go/ql/lib/change-notes/2026-06-08-deprecate-functypeexpr-getresultdecl.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: deprecated ---- -* `FuncTypeExpr.getResultDecl()` has been deprecated. Use `FuncTypeExpr.getResultDecl(int i)` instead. diff --git a/go/ql/lib/change-notes/2026-06-08-fix-result-nodes.md b/go/ql/lib/change-notes/2026-06-08-fix-result-nodes.md deleted file mode 100644 index a567dd4edda..00000000000 --- a/go/ql/lib/change-notes/2026-06-08-fix-result-nodes.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: minorAnalysis ---- -* `DataFlow::ResultNode`s are no longer created for returned expressions in functions with named result parameters. In this case there are already result nodes corresponding to `IR::ReadResultInstruction`s at the end of the function body. diff --git a/go/ql/lib/change-notes/2026-06-08-functypeexpr-getnumresult.md b/go/ql/lib/change-notes/2026-06-08-functypeexpr-getnumresult.md deleted file mode 100644 index 70564beef11..00000000000 --- a/go/ql/lib/change-notes/2026-06-08-functypeexpr-getnumresult.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: minorAnalysis ---- -* `FuncTypeExpr.getNumResult()` now gets the number of result parameters. It previously got the number of result declarations, which is different when one result declaration declares more than one variable, as in `x, y int`. All uses of it expected the number of result parameters. Its QLDoc has been updated. diff --git a/go/ql/lib/change-notes/2026-06-17-model-log-slog.md b/go/ql/lib/change-notes/2026-06-17-model-log-slog.md deleted file mode 100644 index 06bba53a6ed..00000000000 --- a/go/ql/lib/change-notes/2026-06-17-model-log-slog.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -category: minorAnalysis ---- -* Added models for the `log/slog` package (Go 1.21+). Its logging functions and - `*slog.Logger` methods (`Debug`/`Info`/`Warn`/`Error`, their `Context` - variants, and `Log`/`LogAttrs`) are now recognized as logging sinks, so the - `go/log-injection` and `go/clear-text-logging` queries cover code that logs - through `slog`. diff --git a/go/ql/lib/change-notes/released/7.2.0.md b/go/ql/lib/change-notes/released/7.2.0.md new file mode 100644 index 00000000000..0d3035c4a05 --- /dev/null +++ b/go/ql/lib/change-notes/released/7.2.0.md @@ -0,0 +1,16 @@ +## 7.2.0 + +### Deprecated APIs + +* `FuncTypeExpr.getResultDecl()` has been deprecated. Use `FuncTypeExpr.getResultDecl(int i)` instead. + +### Minor Analysis Improvements + +* Added models for the `log/slog` package (Go 1.21+). Its logging functions and + `*slog.Logger` methods (`Debug`/`Info`/`Warn`/`Error`, their `Context` + variants, and `Log`/`LogAttrs`) are now recognized as logging sinks, so the + `go/log-injection` and `go/clear-text-logging` queries cover code that logs + through `slog`. +* `DataFlow::ResultNode`s are no longer created for returned expressions in functions with named result parameters. In this case there are already result nodes corresponding to `IR::ReadResultInstruction`s at the end of the function body. +* `FuncTypeExpr.getNumResult()` now gets the number of result parameters. It previously got the number of result declarations, which is different when one result declaration declares more than one variable, as in `x, y int`. All uses of it expected the number of result parameters. Its QLDoc has been updated. +* More logging functions are now recognized as not returning or panicking. diff --git a/go/ql/lib/codeql-pack.release.yml b/go/ql/lib/codeql-pack.release.yml index 547681cc440..fda9ea165fc 100644 --- a/go/ql/lib/codeql-pack.release.yml +++ b/go/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 7.1.2 +lastReleaseVersion: 7.2.0 diff --git a/go/ql/lib/qlpack.yml b/go/ql/lib/qlpack.yml index 6084bfbfee3..f65b3855cf7 100644 --- a/go/ql/lib/qlpack.yml +++ b/go/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/go-all -version: 7.1.3-dev +version: 7.2.1-dev groups: go dbscheme: go.dbscheme extractor: go @@ -10,6 +10,7 @@ dependencies: codeql/controlflow: ${workspace} codeql/dataflow: ${workspace} codeql/mad: ${workspace} + codeql/ssa: ${workspace} codeql/threat-models: ${workspace} codeql/tutorial: ${workspace} codeql/util: ${workspace} diff --git a/go/ql/lib/semmle/go/controlflow/BasicBlocks.qll b/go/ql/lib/semmle/go/controlflow/BasicBlocks.qll index dc52abb25ab..9bb92bb7d46 100644 --- a/go/ql/lib/semmle/go/controlflow/BasicBlocks.qll +++ b/go/ql/lib/semmle/go/controlflow/BasicBlocks.qll @@ -42,11 +42,11 @@ private module Input implements BB::InputSig { predicate nodeIsPostDominanceExit(Node node) { node instanceof ExitNode } } -private module BbImpl = BB::Make; +module Cfg = BB::Make; -class BasicBlock = BbImpl::BasicBlock; +class BasicBlock = Cfg::BasicBlock; -class EntryBasicBlock = BbImpl::EntryBasicBlock; +class EntryBasicBlock = Cfg::EntryBasicBlock; cached private predicate reachableBB(BasicBlock bb) { diff --git a/go/ql/lib/semmle/go/dataflow/SSA.qll b/go/ql/lib/semmle/go/dataflow/SSA.qll index 46ce4da3935..0b8895f43a0 100644 --- a/go/ql/lib/semmle/go/dataflow/SSA.qll +++ b/go/ql/lib/semmle/go/dataflow/SSA.qll @@ -63,10 +63,7 @@ private predicate unresolvedIdentifier(Ident id, string name) { /** * An SSA variable. */ -class SsaVariable extends TSsaDefinition { - /** Gets the source variable corresponding to this SSA variable. */ - SsaSourceVariable getSourceVariable() { result = this.(SsaDefinition).getSourceVariable() } - +class SsaVariable extends Definition { /** Gets the (unique) definition of this SSA variable. */ SsaDefinition getDefinition() { result = this } @@ -74,22 +71,17 @@ class SsaVariable extends TSsaDefinition { Type getType() { result = this.getSourceVariable().getType() } /** Gets a use in basic block `bb` that refers to this SSA variable. */ - IR::Instruction getAUseIn(ReachableBasicBlock bb) { + IR::Instruction getAUseIn(BasicBlock bb) { exists(int i, SsaSourceVariable v | v = this.getSourceVariable() | result = bb.getNode(i) and - this = getDefinition(bb, i, v) + ssaDefReachesRead(v, this, bb, i) and + useAt(bb, i, v) ) } /** Gets a use that refers to this SSA variable. */ IR::Instruction getAUse() { result = this.getAUseIn(_) } - /** Gets a textual representation of this element. */ - string toString() { result = this.getDefinition().prettyPrintRef() } - - /** Gets the location of this SSA variable. */ - Location getLocation() { result = this.getDefinition().getLocation() } - /** * DEPRECATED: Use `getLocation()` instead. * @@ -109,50 +101,20 @@ class SsaVariable extends TSsaDefinition { /** * An SSA definition. */ -class SsaDefinition extends TSsaDefinition { +class SsaDefinition extends Definition { /** Gets the SSA variable defined by this definition. */ SsaVariable getVariable() { result = this } - /** Gets the source variable defined by this definition. */ - abstract SsaSourceVariable getSourceVariable(); - - /** - * Gets the basic block to which this definition belongs. - */ - abstract ReachableBasicBlock getBasicBlock(); - - /** - * INTERNAL: Use `getBasicBlock()` and `getSourceVariable()` instead. - * - * Holds if this is a definition of source variable `v` at index `idx` in basic block `bb`. - * - * Phi nodes are considered to be at index `-1`, all other definitions at the index of - * the control flow node they correspond to. - */ - abstract predicate definesAt(ReachableBasicBlock bb, int idx, SsaSourceVariable v); - - /** - * INTERNAL: Use `toString()` instead. - * - * Gets a pretty-printed representation of this SSA definition. - */ - abstract string prettyPrintDef(); - - /** - * INTERNAL: Do not use. - * - * Gets a pretty-printed representation of a reference to this SSA definition. - */ - abstract string prettyPrintRef(); - /** Gets the innermost function or file to which this SSA definition belongs. */ ControlFlow::Root getRoot() { result = this.getBasicBlock().getScope() } - /** Gets a textual representation of this element. */ - string toString() { result = this.prettyPrintDef() } - - /** Gets the source location for this element. */ - abstract Location getLocation(); + /** + * INTERNAL: Do not use. + * + * Gets a short string identifying the kind of this SSA definition, + * used in reference formatting (e.g., `"def"`, `"capture"`, `"phi"`). + */ + string getKind() { none() } /** * DEPRECATED: Use `getLocation()` instead. @@ -180,32 +142,23 @@ class SsaDefinition extends TSsaDefinition { /** * An SSA definition that corresponds to an explicit assignment or other variable definition. */ -class SsaExplicitDefinition extends SsaDefinition, TExplicitDef { +class SsaExplicitDefinition extends SsaDefinition, WriteDefinition { + SsaExplicitDefinition() { + exists(BasicBlock bb, int i, SsaSourceVariable v | + this.definesAt(v, bb, i) and + defAt(bb, i, v) + ) + } + /** Gets the instruction where the definition happens. */ IR::Instruction getInstruction() { - exists(BasicBlock bb, int i | this = TExplicitDef(bb, i, _) | result = bb.getNode(i)) + exists(BasicBlock bb, int i | this.definesAt(_, bb, i) | result = bb.getNode(i)) } /** Gets the right-hand side of the definition. */ IR::Instruction getRhs() { this.getInstruction().writes(_, result) } - override predicate definesAt(ReachableBasicBlock bb, int i, SsaSourceVariable v) { - this = TExplicitDef(bb, i, v) - } - - override ReachableBasicBlock getBasicBlock() { this.definesAt(result, _, _) } - - override SsaSourceVariable getSourceVariable() { this = TExplicitDef(_, _, result) } - - override string prettyPrintRef() { - exists(Location loc | loc = this.getLocation() | - result = "def@" + loc.getStartLine() + ":" + loc.getStartColumn() - ) - } - - override string prettyPrintDef() { result = "definition of " + this.getSourceVariable() } - - override Location getLocation() { result = this.getInstruction().getLocation() } + override string getKind() { result = "def" } } /** Provides a helper predicate for working with explicit SSA definitions. */ @@ -219,22 +172,7 @@ module SsaExplicitDefinition { /** * An SSA definition that does not correspond to an explicit variable definition. */ -abstract class SsaImplicitDefinition extends SsaDefinition { - /** - * INTERNAL: Do not use. - * - * Gets the definition kind to include in `prettyPrintRef`. - */ - abstract string getKind(); - - override string prettyPrintRef() { - exists(Location loc | loc = this.getLocation() | - result = this.getKind() + "@" + loc.getStartLine() + ":" + loc.getStartColumn() - ) - } - - override Location getLocation() { result = this.getBasicBlock().getLocation() } -} +abstract class SsaImplicitDefinition extends SsaDefinition { } /** * An SSA definition representing the capturing of an SSA-convertible variable @@ -243,24 +181,8 @@ abstract class SsaImplicitDefinition extends SsaDefinition { * Capturing definitions appear at the beginning of such functions, as well as * at any function call that may affect the value of the variable. */ -class SsaVariableCapture extends SsaImplicitDefinition, TCapture { - override predicate definesAt(ReachableBasicBlock bb, int i, SsaSourceVariable v) { - this = TCapture(bb, i, v) - } - - override ReachableBasicBlock getBasicBlock() { this.definesAt(result, _, _) } - - override SsaSourceVariable getSourceVariable() { this.definesAt(_, _, result) } - +class SsaVariableCapture extends SsaImplicitDefinition, UncertainWriteDefinition { override string getKind() { result = "capture" } - - override string prettyPrintDef() { result = "capture variable " + this.getSourceVariable() } - - override Location getLocation() { - exists(ReachableBasicBlock bb, int i | this.definesAt(bb, i, _) | - result = bb.getNode(i).getLocation() - ) - } } /** @@ -272,12 +194,6 @@ abstract class SsaPseudoDefinition extends SsaImplicitDefinition { * Gets an input of this pseudo-definition. */ abstract SsaVariable getAnInput(); - - /** - * Gets a textual representation of the inputs of this pseudo-definition - * in lexicographical order. - */ - string ppInputs() { result = concat(this.getAnInput().getDefinition().prettyPrintRef(), ", ") } } /** @@ -285,26 +201,10 @@ abstract class SsaPseudoDefinition extends SsaImplicitDefinition { * in the flow graph where otherwise two or more definitions for the variable * would be visible. */ -class SsaPhiNode extends SsaPseudoDefinition, TPhi { - override SsaVariable getAnInput() { - result = getDefReachingEndOf(this.getBasicBlock().getAPredecessor(_), this.getSourceVariable()) - } - - override predicate definesAt(ReachableBasicBlock bb, int i, SsaSourceVariable v) { - bb = this.getBasicBlock() and v = this.getSourceVariable() and i = -1 - } - - override ReachableBasicBlock getBasicBlock() { this = TPhi(result, _) } - - override SsaSourceVariable getSourceVariable() { this = TPhi(_, result) } +class SsaPhiNode extends SsaPseudoDefinition, PhiNode { + override SsaVariable getAnInput() { phiHasInputFromBlock(this, result, _) } override string getKind() { result = "phi" } - - override string prettyPrintDef() { - result = this.getSourceVariable() + " = phi(" + this.ppInputs() + ")" - } - - override Location getLocation() { result = this.getBasicBlock().getLocation() } } /** diff --git a/go/ql/lib/semmle/go/dataflow/SsaImpl.qll b/go/ql/lib/semmle/go/dataflow/SsaImpl.qll index 9648335a6dd..f4f62ab9f1d 100644 --- a/go/ql/lib/semmle/go/dataflow/SsaImpl.qll +++ b/go/ql/lib/semmle/go/dataflow/SsaImpl.qll @@ -7,76 +7,25 @@ overlay[local] module; import go +private import codeql.ssa.Ssa as SsaImplCommon +private import semmle.go.controlflow.BasicBlocks as BasicBlocks + +private class BasicBlock = BasicBlocks::BasicBlock; cached private module Internal { /** Holds if the `i`th node of `bb` defines `v`. */ cached - predicate defAt(ReachableBasicBlock bb, int i, SsaSourceVariable v) { + predicate defAt(BasicBlock bb, int i, SsaSourceVariable v) { bb.getNode(i).(IR::Instruction).writes(v, _) } /** Holds if the `i`th node of `bb` reads `v`. */ cached - predicate useAt(ReachableBasicBlock bb, int i, SsaSourceVariable v) { + predicate useAt(BasicBlock bb, int i, SsaSourceVariable v) { bb.getNode(i).(IR::Instruction).reads(v) } - /** - * A data type representing SSA definitions. - * - * We distinguish three kinds of SSA definitions: - * - * 1. Variable definitions, including declarations, assignments and increments/decrements. - * 2. Pseudo-definitions for captured variables at the beginning of the capturing function - * as well as after calls. - * 3. Phi nodes. - * - * SSA definitions are only introduced where necessary. In particular, - * unreachable code has no SSA definitions associated with it, and neither - * have dead assignments (that is, assignments whose value is never read). - */ - cached - newtype TSsaDefinition = - /** - * An SSA definition that corresponds to an explicit assignment or other variable definition. - */ - TExplicitDef(ReachableBasicBlock bb, int i, SsaSourceVariable v) { - defAt(bb, i, v) and - (liveAfterDef(bb, i, v) or v.isCaptured()) - } or - /** - * An SSA definition representing the capturing of an SSA-convertible variable - * in the closure of a nested function. - * - * Capturing definitions appear at the beginning of such functions, as well as - * at any function call that may affect the value of the variable. - */ - TCapture(ReachableBasicBlock bb, int i, SsaSourceVariable v) { - mayCapture(bb, i, v) and - liveAfterDef(bb, i, v) - } or - /** - * An SSA phi node, that is, a pseudo-definition for a variable at a point - * in the flow graph where otherwise two or more definitions for the variable - * would be visible. - */ - TPhi(ReachableJoinBlock bb, SsaSourceVariable v) { - liveAtEntry(bb, v) and - inDefDominanceFrontier(bb, v) - } - - /** - * Holds if `bb` is in the dominance frontier of a block containing a definition of `v`. - */ - pragma[noinline] - private predicate inDefDominanceFrontier(ReachableJoinBlock bb, SsaSourceVariable v) { - exists(ReachableBasicBlock defbb, SsaDefinition def | - def.definesAt(defbb, _, v) and - defbb.inDominanceFrontier(bb) - ) - } - /** * Holds if `v` is a captured variable which is declared in `declFun` and read in `useFun`. */ @@ -87,7 +36,7 @@ private module Internal { } /** Holds if the `i`th node of `bb` in function `f` is an entry node. */ - private predicate entryNode(FuncDef f, ReachableBasicBlock bb, int i) { + private predicate entryNode(FuncDef f, BasicBlock bb, int i) { f = bb.getScope() and bb.getNode(i).isEntryNode() } @@ -95,17 +44,17 @@ private module Internal { /** * Holds if the `i`th node of `bb` in function `f` is a function call. */ - private predicate callNode(FuncDef f, ReachableBasicBlock bb, int i) { + private predicate callNode(FuncDef f, BasicBlock bb, int i) { f = bb.getScope() and bb.getNode(i).(IR::EvalInstruction).getExpr() instanceof CallExpr } /** * Holds if the `i`th node of basic block `bb` may induce a pseudo-definition for - * modeling updates to captured variable `v`. Whether the definition is actually - * introduced depends on whether `v` is live at this point in the program. + * modeling updates to captured variable `v`. */ - private predicate mayCapture(ReachableBasicBlock bb, int i, SsaSourceVariable v) { + cached + predicate mayUpdateCapturedVariable(BasicBlock bb, int i, SsaSourceVariable v) { exists(FuncDef capturingContainer, FuncDef declContainer | // capture initial value of variable declared in enclosing scope readsCapturedVar(capturingContainer, v, declContainer) and @@ -119,347 +68,134 @@ private module Internal { ) } - /** A classification of variable references into reads and writes. */ - private newtype RefKind = - ReadRef() or - WriteRef() - - /** - * Holds if the `i`th node of basic block `bb` is a reference to `v`, either a read - * (when `tp` is `ReadRef()`) or a direct or indirect write (when `tp` is `WriteRef()`). - */ - private predicate ref(ReachableBasicBlock bb, int i, SsaSourceVariable v, RefKind tp) { - useAt(bb, i, v) and tp = ReadRef() - or - (mayCapture(bb, i, v) or defAt(bb, i, v)) and - tp = WriteRef() - } - - /** - * Gets the (1-based) rank of the reference to `v` at the `i`th node of basic block `bb`, - * which has the given reference kind `tp`. - */ - private int refRank(ReachableBasicBlock bb, int i, SsaSourceVariable v, RefKind tp) { - i = rank[result](int j | ref(bb, j, v, _)) and - ref(bb, i, v, tp) - } - - /** - * Gets the maximum rank among all references to `v` in basic block `bb`. - */ - private int maxRefRank(ReachableBasicBlock bb, SsaSourceVariable v) { - result = max(refRank(bb, _, v, _)) - } - - /** - * Holds if variable `v` is live after the `i`th node of basic block `bb`, where - * `i` is the index of a node that may assign or capture `v`. - * - * For the purposes of this predicate, function calls are considered as writes of captured variables. - */ - private predicate liveAfterDef(ReachableBasicBlock bb, int i, SsaSourceVariable v) { - exists(int r | r = refRank(bb, i, v, WriteRef()) | - // the next reference to `v` inside `bb` is a read - r + 1 = refRank(bb, _, v, ReadRef()) - or - // this is the last reference to `v` inside `bb`, but `v` is live at entry - // to a successor basic block of `bb` - r = maxRefRank(bb, v) and - liveAtSuccEntry(bb, v) - ) - } - - /** - * Holds if variable `v` is live at the beginning of basic block `bb`. - * - * For the purposes of this predicate, function calls are considered as writes of captured variables. - */ - private predicate liveAtEntry(ReachableBasicBlock bb, SsaSourceVariable v) { - // the first reference to `v` inside `bb` is a read - refRank(bb, _, v, ReadRef()) = 1 - or - // there is no reference to `v` inside `bb`, but `v` is live at entry - // to a successor basic block of `bb` - not exists(refRank(bb, _, v, _)) and - liveAtSuccEntry(bb, v) - } - - /** - * Holds if `v` is live at the beginning of any successor of basic block `bb`. - */ - private predicate liveAtSuccEntry(ReachableBasicBlock bb, SsaSourceVariable v) { - liveAtEntry(bb.getASuccessor(_), v) - } - /** * Holds if `v` is assigned outside its declaring function. */ - private predicate assignedThroughClosure(SsaSourceVariable v) { + cached + predicate assignedThroughClosure(SsaSourceVariable v) { any(IR::Instruction def | def.writes(v, _)).getRoot() != v.getDeclaringFunction() } - /** - * Holds if the `i`th node of `bb` is a use or an SSA definition of variable `v`, with - * `k` indicating whether it is the former or the latter. - * - * Note this includes phi nodes, whereas `ref` above only includes explicit writes and captures. - */ - private predicate ssaRef(ReachableBasicBlock bb, int i, SsaSourceVariable v, RefKind k) { - useAt(bb, i, v) and k = ReadRef() - or - any(SsaDefinition def).definesAt(bb, i, v) and k = WriteRef() - } + /** SSA input. */ + cached + module SsaInput implements SsaImplCommon::InputSig { + class SourceVariable = SsaSourceVariable; - /** - * Gets the (1-based) rank of the `i`th node of `bb` among all SSA definitions - * and uses of `v` in `bb`, with `k` indicating whether it is a definition or a use. - * - * For example, if `bb` is a basic block with a phi node for `v` (considered - * to be at index -1), uses `v` at node 2 and defines it at node 5, we have: - * - * ``` - * ssaRefRank(bb, -1, v, WriteRef()) = 1 // phi node - * ssaRefRank(bb, 2, v, ReadRef()) = 2 // use at node 2 - * ssaRefRank(bb, 5, v, WriteRef()) = 3 // definition at node 5 - * ``` - */ - private int ssaRefRank(ReachableBasicBlock bb, int i, SsaSourceVariable v, RefKind k) { - i = rank[result](int j | ssaRef(bb, j, v, _)) and - ssaRef(bb, i, v, k) - } + /** + * Holds if the `i`th node of basic block `bb` is a (potential) write to source + * variable `v`. The Boolean `certain` indicates whether the write is certain. + * + * Certain writes are explicit definitions; uncertain writes are captures. + */ + cached + predicate variableWrite(BasicBlock bb, int i, SourceVariable v, boolean certain) { + defAt(bb, i, v) and certain = true + or + mayUpdateCapturedVariable(bb, i, v) and certain = false + } - /** - * Gets the minimum rank of a read in `bb` such that all references to `v` between that - * read and the read at index `i` are reads (and not writes). - */ - private int rewindReads(ReachableBasicBlock bb, int i, SsaSourceVariable v) { - exists(int r | r = ssaRefRank(bb, i, v, ReadRef()) | - exists(int j, RefKind k | r - 1 = ssaRefRank(bb, j, v, k) | - k = ReadRef() and result = rewindReads(bb, j, v) + /** + * Holds if the `i`th node of basic block `bb` reads source variable `v`. + * + * We add a synthetic uncertain read at the exit node of every function + * that references a captured variable `v`. This ensures that definitions + * of captured variables are included in the SSA graph even when the + * variable is not locally read in that function scope (but may be read + * by another function sharing the same closure). + */ + cached + predicate variableRead(BasicBlock bb, int i, SourceVariable v, boolean certain) { + useAt(bb, i, v) and certain = true + or + v.isCaptured() and + exists(FuncDef f | + f = bb.getScope() and + bb.getLastNode().isExitNode() and + i = bb.length() - 1 and + certain = false + | + // The declaring function: captures may be read after calls to closures + f = v.getDeclaringFunction() or - k = WriteRef() and result = r - ) - or - r = 1 and result = r - ) - } - - /** - * Gets the SSA definition of `v` in `bb` that reaches the read of `v` at node `i`, if any. - */ - private SsaDefinition getLocalDefinition(ReachableBasicBlock bb, int i, SsaSourceVariable v) { - exists(int r | r = rewindReads(bb, i, v) | - exists(int j | result.definesAt(bb, j, v) and ssaRefRank(bb, j, v, _) = r - 1) - ) - } - - /** - * Gets an SSA definition of `v` that reaches the end of the immediate dominator of `bb`. - */ - pragma[noinline] - private SsaDefinition getDefReachingEndOfImmediateDominator( - ReachableBasicBlock bb, SsaSourceVariable v - ) { - result = getDefReachingEndOf(bb.getImmediateDominator(), v) - } - - /** - * Gets an SSA definition of `v` that reaches the end of basic block `bb`. - */ - cached - SsaDefinition getDefReachingEndOf(ReachableBasicBlock bb, SsaSourceVariable v) { - exists(int lastRef | lastRef = max(int i | ssaRef(bb, i, v, _)) | - result = getLocalDefinition(bb, lastRef, v) - or - result.definesAt(bb, lastRef, v) and - liveAtSuccEntry(bb, v) - ) - or - // In SSA form, the (unique) reaching definition of a use is the closest - // definition that dominates the use. If two definitions dominate a node - // then one must dominate the other, so we can find the reaching definition - // by following the idominance relation backwards. - result = getDefReachingEndOfImmediateDominator(bb, v) and - not exists(SsaDefinition ssa | ssa.definesAt(bb, _, v)) and - liveAtSuccEntry(bb, v) - } - - /** - * Gets the unique SSA definition of `v` whose value reaches the `i`th node of `bb`, - * which is a use of `v`. - */ - cached - SsaDefinition getDefinition(ReachableBasicBlock bb, int i, SsaSourceVariable v) { - result = getLocalDefinition(bb, i, v) - or - rewindReads(bb, i, v) = 1 and result = getDefReachingEndOf(bb.getImmediateDominator(), v) - } - - private module AdjacentUsesImpl { - /** Holds if `v` is defined or used in `b`. */ - private predicate varOccursInBlock(SsaSourceVariable v, ReachableBasicBlock b) { - ssaRef(b, _, v, _) - } - - /** Holds if `v` occurs in `b` or one of `b`'s transitive successors. */ - private predicate blockPrecedesVar(SsaSourceVariable v, ReachableBasicBlock b) { - varOccursInBlock(v, b) - or - exists(getDefReachingEndOf(b, v)) - } - - /** - * Holds if `v` occurs in `b1` and `b2` is one of `b1`'s successors. - * - * Factored out of `varBlockReaches` to force join order compared to the larger - * set `blockPrecedesVar(v, b2)`. - */ - pragma[noinline] - private predicate varBlockReachesBaseCand( - SsaSourceVariable v, ReachableBasicBlock b1, ReachableBasicBlock b2 - ) { - varOccursInBlock(v, b1) and - b2 = b1.getASuccessor(_) - } - - /** - * Holds if `b2` is a transitive successor of `b1` and `v` occurs in `b1` and - * in `b2` or one of its transitive successors but not in any block on the path - * between `b1` and `b2`. Unlike `varBlockReaches` this may include blocks `b2` - * where `v` is dead. - * - * Factored out of `varBlockReaches` to force join order compared to the larger - * set `blockPrecedesVar(v, b2)`. - */ - pragma[noinline] - private predicate varBlockReachesRecCand( - SsaSourceVariable v, ReachableBasicBlock b1, ReachableBasicBlock mid, ReachableBasicBlock b2 - ) { - varBlockReaches(v, b1, mid) and - not varOccursInBlock(v, mid) and - b2 = mid.getASuccessor(_) - } - - /** - * Holds if `b2` is a transitive successor of `b1` and `v` occurs in `b1` and - * in `b2` or one of its transitive successors but not in any block on the path - * between `b1` and `b2`. - */ - private predicate varBlockReaches( - SsaSourceVariable v, ReachableBasicBlock b1, ReachableBasicBlock b2 - ) { - varBlockReachesBaseCand(v, b1, b2) and - blockPrecedesVar(v, b2) - or - varBlockReachesRecCand(v, b1, _, b2) and - blockPrecedesVar(v, b2) - } - - /** - * Holds if `b2` is a transitive successor of `b1` and `v` occurs in `b1` and - * `b2` but not in any block on the path between `b1` and `b2`. - */ - private predicate varBlockStep( - SsaSourceVariable v, ReachableBasicBlock b1, ReachableBasicBlock b2 - ) { - varBlockReaches(v, b1, b2) and - varOccursInBlock(v, b2) - } - - /** - * Gets the maximum rank among all SSA references to `v` in basic block `bb`. - */ - private int maxSsaRefRank(ReachableBasicBlock bb, SsaSourceVariable v) { - result = max(ssaRefRank(bb, _, v, _)) - } - - /** - * Holds if `v` occurs at index `i1` in `b1` and at index `i2` in `b2` and - * there is a path between them without any occurrence of `v`. - */ - pragma[nomagic] - predicate adjacentVarRefs( - SsaSourceVariable v, ReachableBasicBlock b1, int i1, ReachableBasicBlock b2, int i2 - ) { - exists(int rankix | - b1 = b2 and - ssaRefRank(b1, i1, v, _) = rankix and - ssaRefRank(b2, i2, v, _) = rankix + 1 - ) - or - maxSsaRefRank(b1, v) = ssaRefRank(b1, i1, v, _) and - varBlockStep(v, b1, b2) and - ssaRefRank(b2, i2, v, _) = 1 - } - - predicate variableUse(SsaSourceVariable v, IR::Instruction use, ReachableBasicBlock bb, int i) { - bb.getNode(i) = use and - exists(SsaVariable sv | - sv.getSourceVariable() = v and - use = sv.getAUse() + // Any function that writes `v`: the write may be observed by the + // declaring function or another closure sharing the same variable + any(IR::Instruction def | def.writes(v, _)).getRoot() = f ) } } - - private import AdjacentUsesImpl - - /** - * Holds if the value defined at `def` can reach `use` without passing through - * any other uses, but possibly through phi nodes. - */ - cached - predicate firstUse(SsaDefinition def, IR::Instruction use) { - exists(SsaSourceVariable v, ReachableBasicBlock b1, int i1, ReachableBasicBlock b2, int i2 | - adjacentVarRefs(v, b1, i1, b2, i2) and - def.definesAt(b1, i1, v) and - variableUse(v, use, b2, i2) - ) - or - exists( - SsaSourceVariable v, SsaPhiNode redef, ReachableBasicBlock b1, int i1, ReachableBasicBlock b2, - int i2 - | - adjacentVarRefs(v, b1, i1, b2, i2) and - def.definesAt(b1, i1, v) and - redef.definesAt(b2, i2, v) and - firstUse(redef, use) - ) - } - - /** - * Holds if `use1` and `use2` form an adjacent use-use-pair of the same SSA - * variable, that is, the value read in `use1` can reach `use2` without passing - * through any other use or any SSA definition of the variable. - */ - cached - predicate adjacentUseUseSameVar(IR::Instruction use1, IR::Instruction use2) { - exists(SsaSourceVariable v, ReachableBasicBlock b1, int i1, ReachableBasicBlock b2, int i2 | - adjacentVarRefs(v, b1, i1, b2, i2) and - variableUse(v, use1, b1, i1) and - variableUse(v, use2, b2, i2) - ) - } - - /** - * Holds if `use1` and `use2` form an adjacent use-use-pair of the same - * `SsaSourceVariable`, that is, the value read in `use1` can reach `use2` - * without passing through any other use or any SSA definition of the variable - * except for phi nodes and uncertain implicit updates. - */ - cached - predicate adjacentUseUse(IR::Instruction use1, IR::Instruction use2) { - adjacentUseUseSameVar(use1, use2) - or - exists( - SsaSourceVariable v, SsaPhiNode def, ReachableBasicBlock b1, int i1, ReachableBasicBlock b2, - int i2 - | - adjacentVarRefs(v, b1, i1, b2, i2) and - variableUse(v, use1, b1, i1) and - def.definesAt(b2, i2, v) and - firstUse(def, use2) - ) - } } import Internal +import SsaImplCommon::Make as Impl + +final class Definition = Impl::Definition; + +final class WriteDefinition = Impl::WriteDefinition; + +final class UncertainWriteDefinition = Impl::UncertainWriteDefinition; + +final class PhiNode = Impl::PhiNode; + +module Consistency = Impl::Consistency; + +/** + * NB: This predicate should be cached. + * + * Holds if the SSA definition of `v` at `def` reaches a read at index `i` in + * basic block `bb`. + */ +cached +predicate ssaDefReachesRead(SsaSourceVariable v, Definition def, BasicBlock bb, int i) { + Impl::ssaDefReachesRead(v, def, bb, i) +} + +/** + * NB: This predicate should be cached. + * + * Holds if the SSA definition of `v` at `def` reaches the end of basic block `bb`. + */ +cached +predicate ssaDefReachesEndOfBlock(BasicBlock bb, Definition def, SsaSourceVariable v) { + Impl::ssaDefReachesEndOfBlock(bb, def, v) +} + +/** + * NB: This predicate should be cached. + * + * Holds if `inp` is an input to the phi node `phi` along the edge originating in `bb`. + */ +cached +predicate phiHasInputFromBlock(PhiNode phi, Definition inp, BasicBlock bb) { + Impl::phiHasInputFromBlock(phi, inp, bb) +} + +/** + * NB: This predicate should be cached. + * + * Holds if `def` reaches the first use `use` without going through any other use, + * but possibly through phi nodes. + */ +cached +predicate firstUse(Definition def, IR::Instruction use) { + exists(BasicBlock bb, int i | + Impl::firstUse(def, bb, i, _) and + use = bb.getNode(i) + ) +} + +/** + * NB: This predicate should be cached. + * + * Holds if `use1` and `use2` form an adjacent use-use-pair of the same SSA + * variable, that is, the value read in `use1` can reach `use2` without passing + * through any other use or any SSA definition of the variable except for phi nodes + * and uncertain implicit updates. + */ +cached +predicate adjacentUseUse(IR::Instruction use1, IR::Instruction use2) { + exists(BasicBlock bb1, int i1, BasicBlock bb2, int i2 | + Impl::adjacentUseUse(bb1, i1, bb2, i2, _, _) and + use1 = bb1.getNode(i1) and + use2 = bb2.getNode(i2) + ) +} diff --git a/go/ql/lib/semmle/go/security/StoredXssCustomizations.qll b/go/ql/lib/semmle/go/security/StoredXssCustomizations.qll index 1216844f994..43c2e0c9119 100644 --- a/go/ql/lib/semmle/go/security/StoredXssCustomizations.qll +++ b/go/ql/lib/semmle/go/security/StoredXssCustomizations.qll @@ -33,9 +33,11 @@ module StoredXss { walkFn.getACall().getArgument(1) = f.getASuccessor*() ) or - // A call to os.FileInfo.Name - exists(Method m | m.implements("io/fs", "FileInfo", "Name") | - m = this.(DataFlow::CallNode).getTarget() + // The return value of a call to `os.DirEntry.Name`, `os.FileInfo.Name` + // or `os.File.ReadDirNames`. + exists(DataFlow::CallNode cn, Method m | m = cn.getTarget() and this = cn.getResult(0) | + m.implements("io/fs", ["DirEntry", "FileInfo"], "Name") or + m.hasQualifiedName("os", "File", "ReadDirNames") ) } } diff --git a/go/ql/src/CHANGELOG.md b/go/ql/src/CHANGELOG.md index c58883ee3c2..b74b08295b2 100644 --- a/go/ql/src/CHANGELOG.md +++ b/go/ql/src/CHANGELOG.md @@ -1,3 +1,9 @@ +## 1.6.5 + +### Minor Analysis Improvements + +* The query `go/unhandled-writable-file-close` ("Writable file handle closed without error handling") now produces fewer false positives. A deferred call to `Close` that is preceded on every execution path by a handled call to `Sync` on the same file handle is no longer flagged. + ## 1.6.4 No user-facing changes. diff --git a/go/ql/src/change-notes/2026-06-04-unhandled-writable-file-close.md b/go/ql/src/change-notes/released/1.6.5.md similarity index 86% rename from go/ql/src/change-notes/2026-06-04-unhandled-writable-file-close.md rename to go/ql/src/change-notes/released/1.6.5.md index f2da5d217f8..38a8f0a4028 100644 --- a/go/ql/src/change-notes/2026-06-04-unhandled-writable-file-close.md +++ b/go/ql/src/change-notes/released/1.6.5.md @@ -1,4 +1,5 @@ ---- -category: minorAnalysis ---- +## 1.6.5 + +### Minor Analysis Improvements + * The query `go/unhandled-writable-file-close` ("Writable file handle closed without error handling") now produces fewer false positives. A deferred call to `Close` that is preceded on every execution path by a handled call to `Sync` on the same file handle is no longer flagged. diff --git a/go/ql/src/codeql-pack.release.yml b/go/ql/src/codeql-pack.release.yml index 1910e09d6a6..03153270557 100644 --- a/go/ql/src/codeql-pack.release.yml +++ b/go/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.6.4 +lastReleaseVersion: 1.6.5 diff --git a/go/ql/src/qlpack.yml b/go/ql/src/qlpack.yml index 3357004e466..2db1c639026 100644 --- a/go/ql/src/qlpack.yml +++ b/go/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/go-queries -version: 1.6.5-dev +version: 1.6.6-dev groups: - go - queries diff --git a/go/ql/test/example-tests/snippets/typeinfo.expected b/go/ql/test/example-tests/snippets/typeinfo.expected index 91ea716693f..c3a0ff5dacb 100644 --- a/go/ql/test/example-tests/snippets/typeinfo.expected +++ b/go/ql/test/example-tests/snippets/typeinfo.expected @@ -2,7 +2,7 @@ | file://:0:0:0:0 | [summary param] -1 in Clone | | file://:0:0:0:0 | [summary param] -1 in Write | | file://:0:0:0:0 | [summary param] -1 in WriteProxy | +| main.go:18:12:18:14 | SSA def(req) | | main.go:18:12:18:14 | argument corresponding to req | -| main.go:18:12:18:14 | definition of req | | main.go:20:5:20:7 | req | | main.go:20:5:20:7 | req [postupdate] | diff --git a/go/ql/test/experimental/CWE-522-DecompressionBombs/DecompressionBombs.expected b/go/ql/test/experimental/CWE-522-DecompressionBombs/DecompressionBombs.expected index 46bccc77a97..c770dc825d7 100644 --- a/go/ql/test/experimental/CWE-522-DecompressionBombs/DecompressionBombs.expected +++ b/go/ql/test/experimental/CWE-522-DecompressionBombs/DecompressionBombs.expected @@ -47,27 +47,27 @@ | test.go:621:25:621:31 | tarRead | test.go:93:5:93:16 | selection of Body | test.go:621:25:621:31 | tarRead | This decompression is $@. | test.go:93:5:93:16 | selection of Body | decompressing compressed data without managing output size | | test.go:629:2:629:8 | tarRead | test.go:93:5:93:16 | selection of Body | test.go:629:2:629:8 | tarRead | This decompression is $@. | test.go:93:5:93:16 | selection of Body | decompressing compressed data without managing output size | edges -| test.go:59:16:59:44 | call to FormValue | test.go:128:20:128:27 | definition of filename | provenance | Src:MaD:2 | -| test.go:60:15:60:26 | selection of Body | test.go:158:19:158:22 | definition of file | provenance | Src:MaD:1 | -| test.go:61:24:61:35 | selection of Body | test.go:169:28:169:31 | definition of file | provenance | Src:MaD:1 | -| test.go:62:13:62:24 | selection of Body | test.go:181:17:181:20 | definition of file | provenance | Src:MaD:1 | -| test.go:64:8:64:19 | selection of Body | test.go:208:12:208:15 | definition of file | provenance | Src:MaD:1 | -| test.go:66:8:66:19 | selection of Body | test.go:233:12:233:15 | definition of file | provenance | Src:MaD:1 | -| test.go:68:17:68:28 | selection of Body | test.go:258:21:258:24 | definition of file | provenance | Src:MaD:1 | -| test.go:70:13:70:24 | selection of Body | test.go:283:17:283:20 | definition of file | provenance | Src:MaD:1 | -| test.go:72:16:72:27 | selection of Body | test.go:308:20:308:23 | definition of file | provenance | Src:MaD:1 | -| test.go:74:7:74:18 | selection of Body | test.go:333:11:333:14 | definition of file | provenance | Src:MaD:1 | -| test.go:76:9:76:20 | selection of Body | test.go:358:13:358:16 | definition of file | provenance | Src:MaD:1 | -| test.go:78:18:78:29 | selection of Body | test.go:384:22:384:25 | definition of file | provenance | Src:MaD:1 | -| test.go:80:5:80:16 | selection of Body | test.go:412:9:412:12 | definition of file | provenance | Src:MaD:1 | -| test.go:82:7:82:18 | selection of Body | test.go:447:11:447:14 | definition of file | provenance | Src:MaD:1 | -| test.go:84:15:84:26 | selection of Body | test.go:440:19:440:21 | definition of src | provenance | Src:MaD:1 | -| test.go:85:16:85:27 | selection of Body | test.go:472:20:472:23 | definition of file | provenance | Src:MaD:1 | -| test.go:87:16:87:27 | selection of Body | test.go:499:20:499:23 | definition of file | provenance | Src:MaD:1 | -| test.go:89:17:89:28 | selection of Body | test.go:526:21:526:24 | definition of file | provenance | Src:MaD:1 | -| test.go:91:15:91:26 | selection of Body | test.go:555:19:555:22 | definition of file | provenance | Src:MaD:1 | -| test.go:93:5:93:16 | selection of Body | test.go:580:9:580:12 | definition of file | provenance | Src:MaD:1 | -| test.go:128:20:128:27 | definition of filename | test.go:130:33:130:40 | filename | provenance | | +| test.go:59:16:59:44 | call to FormValue | test.go:128:20:128:27 | SSA def(filename) | provenance | Src:MaD:2 | +| test.go:60:15:60:26 | selection of Body | test.go:158:19:158:22 | SSA def(file) | provenance | Src:MaD:1 | +| test.go:61:24:61:35 | selection of Body | test.go:169:28:169:31 | SSA def(file) | provenance | Src:MaD:1 | +| test.go:62:13:62:24 | selection of Body | test.go:181:17:181:20 | SSA def(file) | provenance | Src:MaD:1 | +| test.go:64:8:64:19 | selection of Body | test.go:208:12:208:15 | SSA def(file) | provenance | Src:MaD:1 | +| test.go:66:8:66:19 | selection of Body | test.go:233:12:233:15 | SSA def(file) | provenance | Src:MaD:1 | +| test.go:68:17:68:28 | selection of Body | test.go:258:21:258:24 | SSA def(file) | provenance | Src:MaD:1 | +| test.go:70:13:70:24 | selection of Body | test.go:283:17:283:20 | SSA def(file) | provenance | Src:MaD:1 | +| test.go:72:16:72:27 | selection of Body | test.go:308:20:308:23 | SSA def(file) | provenance | Src:MaD:1 | +| test.go:74:7:74:18 | selection of Body | test.go:333:11:333:14 | SSA def(file) | provenance | Src:MaD:1 | +| test.go:76:9:76:20 | selection of Body | test.go:358:13:358:16 | SSA def(file) | provenance | Src:MaD:1 | +| test.go:78:18:78:29 | selection of Body | test.go:384:22:384:25 | SSA def(file) | provenance | Src:MaD:1 | +| test.go:80:5:80:16 | selection of Body | test.go:412:9:412:12 | SSA def(file) | provenance | Src:MaD:1 | +| test.go:82:7:82:18 | selection of Body | test.go:447:11:447:14 | SSA def(file) | provenance | Src:MaD:1 | +| test.go:84:15:84:26 | selection of Body | test.go:440:19:440:21 | SSA def(src) | provenance | Src:MaD:1 | +| test.go:85:16:85:27 | selection of Body | test.go:472:20:472:23 | SSA def(file) | provenance | Src:MaD:1 | +| test.go:87:16:87:27 | selection of Body | test.go:499:20:499:23 | SSA def(file) | provenance | Src:MaD:1 | +| test.go:89:17:89:28 | selection of Body | test.go:526:21:526:24 | SSA def(file) | provenance | Src:MaD:1 | +| test.go:91:15:91:26 | selection of Body | test.go:555:19:555:22 | SSA def(file) | provenance | Src:MaD:1 | +| test.go:93:5:93:16 | selection of Body | test.go:580:9:580:12 | SSA def(file) | provenance | Src:MaD:1 | +| test.go:128:20:128:27 | SSA def(filename) | test.go:130:33:130:40 | filename | provenance | | | test.go:130:2:130:41 | ... := ...[0] | test.go:132:12:132:12 | f | provenance | | | test.go:130:33:130:40 | filename | test.go:130:2:130:41 | ... := ...[0] | provenance | Config | | test.go:130:33:130:40 | filename | test.go:143:51:143:58 | filename | provenance | | @@ -77,7 +77,7 @@ edges | test.go:143:51:143:58 | filename | test.go:143:2:143:59 | ... := ...[0] | provenance | Config | | test.go:145:12:145:12 | f | test.go:145:12:145:19 | call to Open | provenance | Config | | test.go:145:12:145:19 | call to Open | test.go:147:37:147:38 | rc | provenance | | -| test.go:158:19:158:22 | definition of file | test.go:159:25:159:28 | file | provenance | | +| test.go:158:19:158:22 | SSA def(file) | test.go:159:25:159:28 | file | provenance | | | test.go:159:2:159:29 | ... := ...[0] | test.go:160:48:160:52 | file1 | provenance | | | test.go:159:25:159:28 | file | test.go:159:2:159:29 | ... := ...[0] | provenance | MaD:6 | | test.go:160:2:160:69 | ... := ...[0] | test.go:163:26:163:29 | file | provenance | | @@ -85,7 +85,7 @@ edges | test.go:160:48:160:52 | file1 | test.go:160:32:160:53 | call to NewReader | provenance | MaD:5 | | test.go:163:3:163:36 | ... := ...[0] | test.go:164:36:164:51 | fileReaderCloser | provenance | | | test.go:163:26:163:29 | file | test.go:163:3:163:36 | ... := ...[0] | provenance | MaD:4 | -| test.go:169:28:169:31 | definition of file | test.go:170:25:170:28 | file | provenance | | +| test.go:169:28:169:31 | SSA def(file) | test.go:170:25:170:28 | file | provenance | | | test.go:170:2:170:29 | ... := ...[0] | test.go:171:57:171:61 | file2 | provenance | | | test.go:170:25:170:28 | file | test.go:170:2:170:29 | ... := ...[0] | provenance | MaD:6 | | test.go:171:2:171:78 | ... := ...[0] | test.go:175:26:175:29 | file | provenance | | @@ -93,64 +93,64 @@ edges | test.go:171:57:171:61 | file2 | test.go:171:41:171:62 | call to NewReader | provenance | MaD:5 | | test.go:175:26:175:29 | file | test.go:175:26:175:36 | call to Open | provenance | Config | | test.go:175:26:175:36 | call to Open | test.go:176:36:176:51 | fileReaderCloser | provenance | | -| test.go:181:17:181:20 | definition of file | test.go:184:41:184:44 | file | provenance | | +| test.go:181:17:181:20 | SSA def(file) | test.go:184:41:184:44 | file | provenance | | | test.go:184:2:184:73 | ... := ...[0] | test.go:186:2:186:12 | bzip2Reader | provenance | | | test.go:184:2:184:73 | ... := ...[0] | test.go:187:26:187:36 | bzip2Reader | provenance | | | test.go:184:41:184:44 | file | test.go:184:2:184:73 | ... := ...[0] | provenance | Config | | test.go:187:12:187:37 | call to NewReader | test.go:189:18:189:24 | tarRead | provenance | | | test.go:187:26:187:36 | bzip2Reader | test.go:187:12:187:37 | call to NewReader | provenance | MaD:3 | -| test.go:189:18:189:24 | tarRead | test.go:611:22:611:28 | definition of tarRead | provenance | | -| test.go:208:12:208:15 | definition of file | test.go:211:33:211:36 | file | provenance | | +| test.go:189:18:189:24 | tarRead | test.go:611:22:611:28 | SSA def(tarRead) | provenance | | +| test.go:208:12:208:15 | SSA def(file) | test.go:211:33:211:36 | file | provenance | | | test.go:211:17:211:37 | call to NewReader | test.go:213:2:213:12 | bzip2Reader | provenance | | | test.go:211:17:211:37 | call to NewReader | test.go:214:26:214:36 | bzip2Reader | provenance | | | test.go:211:33:211:36 | file | test.go:211:17:211:37 | call to NewReader | provenance | Config | | test.go:214:12:214:37 | call to NewReader | test.go:216:18:216:24 | tarRead | provenance | | | test.go:214:26:214:36 | bzip2Reader | test.go:214:12:214:37 | call to NewReader | provenance | MaD:3 | -| test.go:216:18:216:24 | tarRead | test.go:611:22:611:28 | definition of tarRead | provenance | | -| test.go:233:12:233:15 | definition of file | test.go:236:33:236:36 | file | provenance | | +| test.go:216:18:216:24 | tarRead | test.go:611:22:611:28 | SSA def(tarRead) | provenance | | +| test.go:233:12:233:15 | SSA def(file) | test.go:236:33:236:36 | file | provenance | | | test.go:236:17:236:37 | call to NewReader | test.go:238:2:238:12 | flateReader | provenance | | | test.go:236:17:236:37 | call to NewReader | test.go:239:26:239:36 | flateReader | provenance | | | test.go:236:33:236:36 | file | test.go:236:17:236:37 | call to NewReader | provenance | Config | | test.go:239:12:239:37 | call to NewReader | test.go:241:18:241:24 | tarRead | provenance | | | test.go:239:26:239:36 | flateReader | test.go:239:12:239:37 | call to NewReader | provenance | MaD:3 | -| test.go:241:18:241:24 | tarRead | test.go:611:22:611:28 | definition of tarRead | provenance | | -| test.go:258:21:258:24 | definition of file | test.go:261:42:261:45 | file | provenance | | +| test.go:241:18:241:24 | tarRead | test.go:611:22:611:28 | SSA def(tarRead) | provenance | | +| test.go:258:21:258:24 | SSA def(file) | test.go:261:42:261:45 | file | provenance | | | test.go:261:17:261:46 | call to NewReader | test.go:263:2:263:12 | flateReader | provenance | | | test.go:261:17:261:46 | call to NewReader | test.go:264:26:264:36 | flateReader | provenance | | | test.go:261:42:261:45 | file | test.go:261:17:261:46 | call to NewReader | provenance | Config | | test.go:264:12:264:37 | call to NewReader | test.go:266:18:266:24 | tarRead | provenance | | | test.go:264:26:264:36 | flateReader | test.go:264:12:264:37 | call to NewReader | provenance | MaD:3 | -| test.go:266:18:266:24 | tarRead | test.go:611:22:611:28 | definition of tarRead | provenance | | -| test.go:283:17:283:20 | definition of file | test.go:286:41:286:44 | file | provenance | | +| test.go:266:18:266:24 | tarRead | test.go:611:22:611:28 | SSA def(tarRead) | provenance | | +| test.go:283:17:283:20 | SSA def(file) | test.go:286:41:286:44 | file | provenance | | | test.go:286:2:286:73 | ... := ...[0] | test.go:288:2:288:12 | flateReader | provenance | | | test.go:286:2:286:73 | ... := ...[0] | test.go:289:26:289:36 | flateReader | provenance | | | test.go:286:41:286:44 | file | test.go:286:2:286:73 | ... := ...[0] | provenance | Config | | test.go:289:12:289:37 | call to NewReader | test.go:291:18:291:24 | tarRead | provenance | | | test.go:289:26:289:36 | flateReader | test.go:289:12:289:37 | call to NewReader | provenance | MaD:3 | -| test.go:291:18:291:24 | tarRead | test.go:611:22:611:28 | definition of tarRead | provenance | | -| test.go:308:20:308:23 | definition of file | test.go:311:43:311:46 | file | provenance | | +| test.go:291:18:291:24 | tarRead | test.go:611:22:611:28 | SSA def(tarRead) | provenance | | +| test.go:308:20:308:23 | SSA def(file) | test.go:311:43:311:46 | file | provenance | | | test.go:311:2:311:47 | ... := ...[0] | test.go:313:2:313:11 | zlibReader | provenance | | | test.go:311:2:311:47 | ... := ...[0] | test.go:314:26:314:35 | zlibReader | provenance | | | test.go:311:43:311:46 | file | test.go:311:2:311:47 | ... := ...[0] | provenance | Config | | test.go:314:12:314:36 | call to NewReader | test.go:316:18:316:24 | tarRead | provenance | | | test.go:314:26:314:35 | zlibReader | test.go:314:12:314:36 | call to NewReader | provenance | MaD:3 | -| test.go:316:18:316:24 | tarRead | test.go:611:22:611:28 | definition of tarRead | provenance | | -| test.go:333:11:333:14 | definition of file | test.go:336:34:336:37 | file | provenance | | +| test.go:316:18:316:24 | tarRead | test.go:611:22:611:28 | SSA def(tarRead) | provenance | | +| test.go:333:11:333:14 | SSA def(file) | test.go:336:34:336:37 | file | provenance | | | test.go:336:2:336:38 | ... := ...[0] | test.go:338:2:338:11 | zlibReader | provenance | | | test.go:336:2:336:38 | ... := ...[0] | test.go:339:26:339:35 | zlibReader | provenance | | | test.go:336:34:336:37 | file | test.go:336:2:336:38 | ... := ...[0] | provenance | Config | | test.go:339:12:339:36 | call to NewReader | test.go:341:18:341:24 | tarRead | provenance | | | test.go:339:26:339:35 | zlibReader | test.go:339:12:339:36 | call to NewReader | provenance | MaD:3 | -| test.go:341:18:341:24 | tarRead | test.go:611:22:611:28 | definition of tarRead | provenance | | -| test.go:358:13:358:16 | definition of file | test.go:361:35:361:38 | file | provenance | | +| test.go:341:18:341:24 | tarRead | test.go:611:22:611:28 | SSA def(tarRead) | provenance | | +| test.go:358:13:358:16 | SSA def(file) | test.go:361:35:361:38 | file | provenance | | | test.go:361:18:361:39 | call to NewReader | test.go:363:2:363:13 | snappyReader | provenance | | | test.go:361:18:361:39 | call to NewReader | test.go:364:2:364:13 | snappyReader | provenance | | | test.go:361:18:361:39 | call to NewReader | test.go:365:26:365:37 | snappyReader | provenance | | | test.go:361:35:361:38 | file | test.go:361:18:361:39 | call to NewReader | provenance | Config | | test.go:365:12:365:38 | call to NewReader | test.go:367:18:367:24 | tarRead | provenance | | | test.go:365:26:365:37 | snappyReader | test.go:365:12:365:38 | call to NewReader | provenance | MaD:3 | -| test.go:367:18:367:24 | tarRead | test.go:611:22:611:28 | definition of tarRead | provenance | | -| test.go:384:22:384:25 | definition of file | test.go:387:44:387:47 | file | provenance | | +| test.go:367:18:367:24 | tarRead | test.go:611:22:611:28 | SSA def(tarRead) | provenance | | +| test.go:384:22:384:25 | SSA def(file) | test.go:387:44:387:47 | file | provenance | | | test.go:387:18:387:48 | call to NewReader | test.go:389:2:389:13 | snappyReader | provenance | | | test.go:387:18:387:48 | call to NewReader | test.go:391:2:391:13 | snappyReader | provenance | | | test.go:387:18:387:48 | call to NewReader | test.go:392:2:392:13 | snappyReader | provenance | | @@ -158,8 +158,8 @@ edges | test.go:387:44:387:47 | file | test.go:387:18:387:48 | call to NewReader | provenance | Config | | test.go:393:12:393:38 | call to NewReader | test.go:395:18:395:24 | tarRead | provenance | | | test.go:393:26:393:37 | snappyReader | test.go:393:12:393:38 | call to NewReader | provenance | MaD:3 | -| test.go:395:18:395:24 | tarRead | test.go:611:22:611:28 | definition of tarRead | provenance | | -| test.go:412:9:412:12 | definition of file | test.go:415:27:415:30 | file | provenance | | +| test.go:395:18:395:24 | tarRead | test.go:611:22:611:28 | SSA def(tarRead) | provenance | | +| test.go:412:9:412:12 | SSA def(file) | test.go:415:27:415:30 | file | provenance | | | test.go:415:14:415:31 | call to NewReader | test.go:417:2:417:9 | s2Reader | provenance | | | test.go:415:14:415:31 | call to NewReader | test.go:418:2:418:9 | s2Reader | provenance | | | test.go:415:14:415:31 | call to NewReader | test.go:420:2:420:9 | s2Reader | provenance | | @@ -167,35 +167,35 @@ edges | test.go:415:27:415:30 | file | test.go:415:14:415:31 | call to NewReader | provenance | Config | | test.go:421:12:421:34 | call to NewReader | test.go:423:18:423:24 | tarRead | provenance | | | test.go:421:26:421:33 | s2Reader | test.go:421:12:421:34 | call to NewReader | provenance | MaD:3 | -| test.go:423:18:423:24 | tarRead | test.go:611:22:611:28 | definition of tarRead | provenance | | -| test.go:440:19:440:21 | definition of src | test.go:441:34:441:36 | src | provenance | | +| test.go:423:18:423:24 | tarRead | test.go:611:22:611:28 | SSA def(tarRead) | provenance | | +| test.go:440:19:440:21 | SSA def(src) | test.go:441:34:441:36 | src | provenance | | | test.go:441:2:441:37 | ... := ...[0] | test.go:444:12:444:32 | type conversion | provenance | | | test.go:441:34:441:36 | src | test.go:441:2:441:37 | ... := ...[0] | provenance | Config | | test.go:444:12:444:32 | type conversion | test.go:445:23:445:28 | newSrc | provenance | | -| test.go:447:11:447:14 | definition of file | test.go:450:34:450:37 | file | provenance | | +| test.go:447:11:447:14 | SSA def(file) | test.go:450:34:450:37 | file | provenance | | | test.go:450:2:450:38 | ... := ...[0] | test.go:452:2:452:11 | gzipReader | provenance | | | test.go:450:2:450:38 | ... := ...[0] | test.go:453:26:453:35 | gzipReader | provenance | | | test.go:450:34:450:37 | file | test.go:450:2:450:38 | ... := ...[0] | provenance | Config | | test.go:453:12:453:36 | call to NewReader | test.go:455:18:455:24 | tarRead | provenance | | | test.go:453:26:453:35 | gzipReader | test.go:453:12:453:36 | call to NewReader | provenance | MaD:3 | -| test.go:455:18:455:24 | tarRead | test.go:611:22:611:28 | definition of tarRead | provenance | | -| test.go:472:20:472:23 | definition of file | test.go:475:43:475:46 | file | provenance | | +| test.go:455:18:455:24 | tarRead | test.go:611:22:611:28 | SSA def(tarRead) | provenance | | +| test.go:472:20:472:23 | SSA def(file) | test.go:475:43:475:46 | file | provenance | | | test.go:475:2:475:47 | ... := ...[0] | test.go:477:2:477:11 | gzipReader | provenance | | | test.go:475:2:475:47 | ... := ...[0] | test.go:479:2:479:11 | gzipReader | provenance | | | test.go:475:2:475:47 | ... := ...[0] | test.go:480:26:480:35 | gzipReader | provenance | | | test.go:475:43:475:46 | file | test.go:475:2:475:47 | ... := ...[0] | provenance | Config | | test.go:480:12:480:36 | call to NewReader | test.go:482:18:482:24 | tarRead | provenance | | | test.go:480:26:480:35 | gzipReader | test.go:480:12:480:36 | call to NewReader | provenance | MaD:3 | -| test.go:482:18:482:24 | tarRead | test.go:611:22:611:28 | definition of tarRead | provenance | | -| test.go:499:20:499:23 | definition of file | test.go:502:45:502:48 | file | provenance | | +| test.go:482:18:482:24 | tarRead | test.go:611:22:611:28 | SSA def(tarRead) | provenance | | +| test.go:499:20:499:23 | SSA def(file) | test.go:502:45:502:48 | file | provenance | | | test.go:502:2:502:49 | ... := ...[0] | test.go:504:2:504:12 | pgzipReader | provenance | | | test.go:502:2:502:49 | ... := ...[0] | test.go:506:2:506:12 | pgzipReader | provenance | | | test.go:502:2:502:49 | ... := ...[0] | test.go:507:26:507:36 | pgzipReader | provenance | | | test.go:502:45:502:48 | file | test.go:502:2:502:49 | ... := ...[0] | provenance | Config | | test.go:507:12:507:37 | call to NewReader | test.go:509:18:509:24 | tarRead | provenance | | | test.go:507:26:507:36 | pgzipReader | test.go:507:12:507:37 | call to NewReader | provenance | MaD:3 | -| test.go:509:18:509:24 | tarRead | test.go:611:22:611:28 | definition of tarRead | provenance | | -| test.go:526:21:526:24 | definition of file | test.go:529:43:529:46 | file | provenance | | +| test.go:509:18:509:24 | tarRead | test.go:611:22:611:28 | SSA def(tarRead) | provenance | | +| test.go:526:21:526:24 | SSA def(file) | test.go:529:43:529:46 | file | provenance | | | test.go:529:2:529:47 | ... := ...[0] | test.go:531:2:531:11 | zstdReader | provenance | | | test.go:529:2:529:47 | ... := ...[0] | test.go:533:2:533:11 | zstdReader | provenance | | | test.go:529:2:529:47 | ... := ...[0] | test.go:535:2:535:11 | zstdReader | provenance | | @@ -203,33 +203,33 @@ edges | test.go:529:43:529:46 | file | test.go:529:2:529:47 | ... := ...[0] | provenance | Config | | test.go:536:12:536:36 | call to NewReader | test.go:538:18:538:24 | tarRead | provenance | | | test.go:536:26:536:35 | zstdReader | test.go:536:12:536:36 | call to NewReader | provenance | MaD:3 | -| test.go:538:18:538:24 | tarRead | test.go:611:22:611:28 | definition of tarRead | provenance | | -| test.go:555:19:555:22 | definition of file | test.go:558:38:558:41 | file | provenance | | +| test.go:538:18:538:24 | tarRead | test.go:611:22:611:28 | SSA def(tarRead) | provenance | | +| test.go:555:19:555:22 | SSA def(file) | test.go:558:38:558:41 | file | provenance | | | test.go:558:16:558:42 | call to NewReader | test.go:560:2:560:11 | zstdReader | provenance | | | test.go:558:16:558:42 | call to NewReader | test.go:561:26:561:35 | zstdReader | provenance | | | test.go:558:38:558:41 | file | test.go:558:16:558:42 | call to NewReader | provenance | Config | | test.go:561:12:561:36 | call to NewReader | test.go:563:18:563:24 | tarRead | provenance | | | test.go:561:26:561:35 | zstdReader | test.go:561:12:561:36 | call to NewReader | provenance | MaD:3 | -| test.go:563:18:563:24 | tarRead | test.go:611:22:611:28 | definition of tarRead | provenance | | -| test.go:580:9:580:12 | definition of file | test.go:583:30:583:33 | file | provenance | | +| test.go:563:18:563:24 | tarRead | test.go:611:22:611:28 | SSA def(tarRead) | provenance | | +| test.go:580:9:580:12 | SSA def(file) | test.go:583:30:583:33 | file | provenance | | | test.go:583:2:583:34 | ... := ...[0] | test.go:585:2:585:9 | xzReader | provenance | | | test.go:583:2:583:34 | ... := ...[0] | test.go:586:26:586:33 | xzReader | provenance | | | test.go:583:30:583:33 | file | test.go:583:2:583:34 | ... := ...[0] | provenance | Config | | test.go:586:12:586:34 | call to NewReader | test.go:589:18:589:24 | tarRead | provenance | | | test.go:586:12:586:34 | call to NewReader | test.go:590:19:590:25 | tarRead | provenance | | | test.go:586:26:586:33 | xzReader | test.go:586:12:586:34 | call to NewReader | provenance | MaD:3 | -| test.go:589:18:589:24 | tarRead | test.go:611:22:611:28 | definition of tarRead | provenance | | -| test.go:590:19:590:25 | tarRead | test.go:627:23:627:29 | definition of tarRead | provenance | | -| test.go:611:22:611:28 | definition of tarRead | test.go:621:25:621:31 | tarRead | provenance | | -| test.go:611:22:611:28 | definition of tarRead | test.go:621:25:621:31 | tarRead | provenance | | -| test.go:611:22:611:28 | definition of tarRead | test.go:621:25:621:31 | tarRead | provenance | | -| test.go:611:22:611:28 | definition of tarRead | test.go:621:25:621:31 | tarRead | provenance | | -| test.go:611:22:611:28 | definition of tarRead | test.go:621:25:621:31 | tarRead | provenance | | -| test.go:611:22:611:28 | definition of tarRead | test.go:621:25:621:31 | tarRead | provenance | | -| test.go:611:22:611:28 | definition of tarRead | test.go:621:25:621:31 | tarRead | provenance | | -| test.go:611:22:611:28 | definition of tarRead | test.go:621:25:621:31 | tarRead | provenance | | -| test.go:611:22:611:28 | definition of tarRead | test.go:621:25:621:31 | tarRead | provenance | | -| test.go:627:23:627:29 | definition of tarRead | test.go:629:2:629:8 | tarRead | provenance | | +| test.go:589:18:589:24 | tarRead | test.go:611:22:611:28 | SSA def(tarRead) | provenance | | +| test.go:590:19:590:25 | tarRead | test.go:627:23:627:29 | SSA def(tarRead) | provenance | | +| test.go:611:22:611:28 | SSA def(tarRead) | test.go:621:25:621:31 | tarRead | provenance | | +| test.go:611:22:611:28 | SSA def(tarRead) | test.go:621:25:621:31 | tarRead | provenance | | +| test.go:611:22:611:28 | SSA def(tarRead) | test.go:621:25:621:31 | tarRead | provenance | | +| test.go:611:22:611:28 | SSA def(tarRead) | test.go:621:25:621:31 | tarRead | provenance | | +| test.go:611:22:611:28 | SSA def(tarRead) | test.go:621:25:621:31 | tarRead | provenance | | +| test.go:611:22:611:28 | SSA def(tarRead) | test.go:621:25:621:31 | tarRead | provenance | | +| test.go:611:22:611:28 | SSA def(tarRead) | test.go:621:25:621:31 | tarRead | provenance | | +| test.go:611:22:611:28 | SSA def(tarRead) | test.go:621:25:621:31 | tarRead | provenance | | +| test.go:611:22:611:28 | SSA def(tarRead) | test.go:621:25:621:31 | tarRead | provenance | | +| test.go:627:23:627:29 | SSA def(tarRead) | test.go:629:2:629:8 | tarRead | provenance | | models | 1 | Source: net/http; Request; true; Body; ; ; ; remote; manual | | 2 | Source: net/http; Request; true; FormValue; ; ; ReturnValue; remote; manual | @@ -258,7 +258,7 @@ nodes | test.go:89:17:89:28 | selection of Body | semmle.label | selection of Body | | test.go:91:15:91:26 | selection of Body | semmle.label | selection of Body | | test.go:93:5:93:16 | selection of Body | semmle.label | selection of Body | -| test.go:128:20:128:27 | definition of filename | semmle.label | definition of filename | +| test.go:128:20:128:27 | SSA def(filename) | semmle.label | SSA def(filename) | | test.go:130:2:130:41 | ... := ...[0] | semmle.label | ... := ...[0] | | test.go:130:33:130:40 | filename | semmle.label | filename | | test.go:132:3:132:19 | ... := ...[0] | semmle.label | ... := ...[0] | @@ -269,7 +269,7 @@ nodes | test.go:145:12:145:12 | f | semmle.label | f | | test.go:145:12:145:19 | call to Open | semmle.label | call to Open | | test.go:147:37:147:38 | rc | semmle.label | rc | -| test.go:158:19:158:22 | definition of file | semmle.label | definition of file | +| test.go:158:19:158:22 | SSA def(file) | semmle.label | SSA def(file) | | test.go:159:2:159:29 | ... := ...[0] | semmle.label | ... := ...[0] | | test.go:159:25:159:28 | file | semmle.label | file | | test.go:160:2:160:69 | ... := ...[0] | semmle.label | ... := ...[0] | @@ -278,7 +278,7 @@ nodes | test.go:163:3:163:36 | ... := ...[0] | semmle.label | ... := ...[0] | | test.go:163:26:163:29 | file | semmle.label | file | | test.go:164:36:164:51 | fileReaderCloser | semmle.label | fileReaderCloser | -| test.go:169:28:169:31 | definition of file | semmle.label | definition of file | +| test.go:169:28:169:31 | SSA def(file) | semmle.label | SSA def(file) | | test.go:170:2:170:29 | ... := ...[0] | semmle.label | ... := ...[0] | | test.go:170:25:170:28 | file | semmle.label | file | | test.go:171:2:171:78 | ... := ...[0] | semmle.label | ... := ...[0] | @@ -287,56 +287,56 @@ nodes | test.go:175:26:175:29 | file | semmle.label | file | | test.go:175:26:175:36 | call to Open | semmle.label | call to Open | | test.go:176:36:176:51 | fileReaderCloser | semmle.label | fileReaderCloser | -| test.go:181:17:181:20 | definition of file | semmle.label | definition of file | +| test.go:181:17:181:20 | SSA def(file) | semmle.label | SSA def(file) | | test.go:184:2:184:73 | ... := ...[0] | semmle.label | ... := ...[0] | | test.go:184:41:184:44 | file | semmle.label | file | | test.go:186:2:186:12 | bzip2Reader | semmle.label | bzip2Reader | | test.go:187:12:187:37 | call to NewReader | semmle.label | call to NewReader | | test.go:187:26:187:36 | bzip2Reader | semmle.label | bzip2Reader | | test.go:189:18:189:24 | tarRead | semmle.label | tarRead | -| test.go:208:12:208:15 | definition of file | semmle.label | definition of file | +| test.go:208:12:208:15 | SSA def(file) | semmle.label | SSA def(file) | | test.go:211:17:211:37 | call to NewReader | semmle.label | call to NewReader | | test.go:211:33:211:36 | file | semmle.label | file | | test.go:213:2:213:12 | bzip2Reader | semmle.label | bzip2Reader | | test.go:214:12:214:37 | call to NewReader | semmle.label | call to NewReader | | test.go:214:26:214:36 | bzip2Reader | semmle.label | bzip2Reader | | test.go:216:18:216:24 | tarRead | semmle.label | tarRead | -| test.go:233:12:233:15 | definition of file | semmle.label | definition of file | +| test.go:233:12:233:15 | SSA def(file) | semmle.label | SSA def(file) | | test.go:236:17:236:37 | call to NewReader | semmle.label | call to NewReader | | test.go:236:33:236:36 | file | semmle.label | file | | test.go:238:2:238:12 | flateReader | semmle.label | flateReader | | test.go:239:12:239:37 | call to NewReader | semmle.label | call to NewReader | | test.go:239:26:239:36 | flateReader | semmle.label | flateReader | | test.go:241:18:241:24 | tarRead | semmle.label | tarRead | -| test.go:258:21:258:24 | definition of file | semmle.label | definition of file | +| test.go:258:21:258:24 | SSA def(file) | semmle.label | SSA def(file) | | test.go:261:17:261:46 | call to NewReader | semmle.label | call to NewReader | | test.go:261:42:261:45 | file | semmle.label | file | | test.go:263:2:263:12 | flateReader | semmle.label | flateReader | | test.go:264:12:264:37 | call to NewReader | semmle.label | call to NewReader | | test.go:264:26:264:36 | flateReader | semmle.label | flateReader | | test.go:266:18:266:24 | tarRead | semmle.label | tarRead | -| test.go:283:17:283:20 | definition of file | semmle.label | definition of file | +| test.go:283:17:283:20 | SSA def(file) | semmle.label | SSA def(file) | | test.go:286:2:286:73 | ... := ...[0] | semmle.label | ... := ...[0] | | test.go:286:41:286:44 | file | semmle.label | file | | test.go:288:2:288:12 | flateReader | semmle.label | flateReader | | test.go:289:12:289:37 | call to NewReader | semmle.label | call to NewReader | | test.go:289:26:289:36 | flateReader | semmle.label | flateReader | | test.go:291:18:291:24 | tarRead | semmle.label | tarRead | -| test.go:308:20:308:23 | definition of file | semmle.label | definition of file | +| test.go:308:20:308:23 | SSA def(file) | semmle.label | SSA def(file) | | test.go:311:2:311:47 | ... := ...[0] | semmle.label | ... := ...[0] | | test.go:311:43:311:46 | file | semmle.label | file | | test.go:313:2:313:11 | zlibReader | semmle.label | zlibReader | | test.go:314:12:314:36 | call to NewReader | semmle.label | call to NewReader | | test.go:314:26:314:35 | zlibReader | semmle.label | zlibReader | | test.go:316:18:316:24 | tarRead | semmle.label | tarRead | -| test.go:333:11:333:14 | definition of file | semmle.label | definition of file | +| test.go:333:11:333:14 | SSA def(file) | semmle.label | SSA def(file) | | test.go:336:2:336:38 | ... := ...[0] | semmle.label | ... := ...[0] | | test.go:336:34:336:37 | file | semmle.label | file | | test.go:338:2:338:11 | zlibReader | semmle.label | zlibReader | | test.go:339:12:339:36 | call to NewReader | semmle.label | call to NewReader | | test.go:339:26:339:35 | zlibReader | semmle.label | zlibReader | | test.go:341:18:341:24 | tarRead | semmle.label | tarRead | -| test.go:358:13:358:16 | definition of file | semmle.label | definition of file | +| test.go:358:13:358:16 | SSA def(file) | semmle.label | SSA def(file) | | test.go:361:18:361:39 | call to NewReader | semmle.label | call to NewReader | | test.go:361:35:361:38 | file | semmle.label | file | | test.go:363:2:363:13 | snappyReader | semmle.label | snappyReader | @@ -344,7 +344,7 @@ nodes | test.go:365:12:365:38 | call to NewReader | semmle.label | call to NewReader | | test.go:365:26:365:37 | snappyReader | semmle.label | snappyReader | | test.go:367:18:367:24 | tarRead | semmle.label | tarRead | -| test.go:384:22:384:25 | definition of file | semmle.label | definition of file | +| test.go:384:22:384:25 | SSA def(file) | semmle.label | SSA def(file) | | test.go:387:18:387:48 | call to NewReader | semmle.label | call to NewReader | | test.go:387:44:387:47 | file | semmle.label | file | | test.go:389:2:389:13 | snappyReader | semmle.label | snappyReader | @@ -353,7 +353,7 @@ nodes | test.go:393:12:393:38 | call to NewReader | semmle.label | call to NewReader | | test.go:393:26:393:37 | snappyReader | semmle.label | snappyReader | | test.go:395:18:395:24 | tarRead | semmle.label | tarRead | -| test.go:412:9:412:12 | definition of file | semmle.label | definition of file | +| test.go:412:9:412:12 | SSA def(file) | semmle.label | SSA def(file) | | test.go:415:14:415:31 | call to NewReader | semmle.label | call to NewReader | | test.go:415:27:415:30 | file | semmle.label | file | | test.go:417:2:417:9 | s2Reader | semmle.label | s2Reader | @@ -362,19 +362,19 @@ nodes | test.go:421:12:421:34 | call to NewReader | semmle.label | call to NewReader | | test.go:421:26:421:33 | s2Reader | semmle.label | s2Reader | | test.go:423:18:423:24 | tarRead | semmle.label | tarRead | -| test.go:440:19:440:21 | definition of src | semmle.label | definition of src | +| test.go:440:19:440:21 | SSA def(src) | semmle.label | SSA def(src) | | test.go:441:2:441:37 | ... := ...[0] | semmle.label | ... := ...[0] | | test.go:441:34:441:36 | src | semmle.label | src | | test.go:444:12:444:32 | type conversion | semmle.label | type conversion | | test.go:445:23:445:28 | newSrc | semmle.label | newSrc | -| test.go:447:11:447:14 | definition of file | semmle.label | definition of file | +| test.go:447:11:447:14 | SSA def(file) | semmle.label | SSA def(file) | | test.go:450:2:450:38 | ... := ...[0] | semmle.label | ... := ...[0] | | test.go:450:34:450:37 | file | semmle.label | file | | test.go:452:2:452:11 | gzipReader | semmle.label | gzipReader | | test.go:453:12:453:36 | call to NewReader | semmle.label | call to NewReader | | test.go:453:26:453:35 | gzipReader | semmle.label | gzipReader | | test.go:455:18:455:24 | tarRead | semmle.label | tarRead | -| test.go:472:20:472:23 | definition of file | semmle.label | definition of file | +| test.go:472:20:472:23 | SSA def(file) | semmle.label | SSA def(file) | | test.go:475:2:475:47 | ... := ...[0] | semmle.label | ... := ...[0] | | test.go:475:43:475:46 | file | semmle.label | file | | test.go:477:2:477:11 | gzipReader | semmle.label | gzipReader | @@ -382,7 +382,7 @@ nodes | test.go:480:12:480:36 | call to NewReader | semmle.label | call to NewReader | | test.go:480:26:480:35 | gzipReader | semmle.label | gzipReader | | test.go:482:18:482:24 | tarRead | semmle.label | tarRead | -| test.go:499:20:499:23 | definition of file | semmle.label | definition of file | +| test.go:499:20:499:23 | SSA def(file) | semmle.label | SSA def(file) | | test.go:502:2:502:49 | ... := ...[0] | semmle.label | ... := ...[0] | | test.go:502:45:502:48 | file | semmle.label | file | | test.go:504:2:504:12 | pgzipReader | semmle.label | pgzipReader | @@ -390,7 +390,7 @@ nodes | test.go:507:12:507:37 | call to NewReader | semmle.label | call to NewReader | | test.go:507:26:507:36 | pgzipReader | semmle.label | pgzipReader | | test.go:509:18:509:24 | tarRead | semmle.label | tarRead | -| test.go:526:21:526:24 | definition of file | semmle.label | definition of file | +| test.go:526:21:526:24 | SSA def(file) | semmle.label | SSA def(file) | | test.go:529:2:529:47 | ... := ...[0] | semmle.label | ... := ...[0] | | test.go:529:43:529:46 | file | semmle.label | file | | test.go:531:2:531:11 | zstdReader | semmle.label | zstdReader | @@ -399,14 +399,14 @@ nodes | test.go:536:12:536:36 | call to NewReader | semmle.label | call to NewReader | | test.go:536:26:536:35 | zstdReader | semmle.label | zstdReader | | test.go:538:18:538:24 | tarRead | semmle.label | tarRead | -| test.go:555:19:555:22 | definition of file | semmle.label | definition of file | +| test.go:555:19:555:22 | SSA def(file) | semmle.label | SSA def(file) | | test.go:558:16:558:42 | call to NewReader | semmle.label | call to NewReader | | test.go:558:38:558:41 | file | semmle.label | file | | test.go:560:2:560:11 | zstdReader | semmle.label | zstdReader | | test.go:561:12:561:36 | call to NewReader | semmle.label | call to NewReader | | test.go:561:26:561:35 | zstdReader | semmle.label | zstdReader | | test.go:563:18:563:24 | tarRead | semmle.label | tarRead | -| test.go:580:9:580:12 | definition of file | semmle.label | definition of file | +| test.go:580:9:580:12 | SSA def(file) | semmle.label | SSA def(file) | | test.go:583:2:583:34 | ... := ...[0] | semmle.label | ... := ...[0] | | test.go:583:30:583:33 | file | semmle.label | file | | test.go:585:2:585:9 | xzReader | semmle.label | xzReader | @@ -414,15 +414,15 @@ nodes | test.go:586:26:586:33 | xzReader | semmle.label | xzReader | | test.go:589:18:589:24 | tarRead | semmle.label | tarRead | | test.go:590:19:590:25 | tarRead | semmle.label | tarRead | -| test.go:611:22:611:28 | definition of tarRead | semmle.label | definition of tarRead | -| test.go:611:22:611:28 | definition of tarRead | semmle.label | definition of tarRead | -| test.go:611:22:611:28 | definition of tarRead | semmle.label | definition of tarRead | -| test.go:611:22:611:28 | definition of tarRead | semmle.label | definition of tarRead | -| test.go:611:22:611:28 | definition of tarRead | semmle.label | definition of tarRead | -| test.go:611:22:611:28 | definition of tarRead | semmle.label | definition of tarRead | -| test.go:611:22:611:28 | definition of tarRead | semmle.label | definition of tarRead | -| test.go:611:22:611:28 | definition of tarRead | semmle.label | definition of tarRead | -| test.go:611:22:611:28 | definition of tarRead | semmle.label | definition of tarRead | +| test.go:611:22:611:28 | SSA def(tarRead) | semmle.label | SSA def(tarRead) | +| test.go:611:22:611:28 | SSA def(tarRead) | semmle.label | SSA def(tarRead) | +| test.go:611:22:611:28 | SSA def(tarRead) | semmle.label | SSA def(tarRead) | +| test.go:611:22:611:28 | SSA def(tarRead) | semmle.label | SSA def(tarRead) | +| test.go:611:22:611:28 | SSA def(tarRead) | semmle.label | SSA def(tarRead) | +| test.go:611:22:611:28 | SSA def(tarRead) | semmle.label | SSA def(tarRead) | +| test.go:611:22:611:28 | SSA def(tarRead) | semmle.label | SSA def(tarRead) | +| test.go:611:22:611:28 | SSA def(tarRead) | semmle.label | SSA def(tarRead) | +| test.go:611:22:611:28 | SSA def(tarRead) | semmle.label | SSA def(tarRead) | | test.go:621:25:621:31 | tarRead | semmle.label | tarRead | | test.go:621:25:621:31 | tarRead | semmle.label | tarRead | | test.go:621:25:621:31 | tarRead | semmle.label | tarRead | @@ -432,6 +432,6 @@ nodes | test.go:621:25:621:31 | tarRead | semmle.label | tarRead | | test.go:621:25:621:31 | tarRead | semmle.label | tarRead | | test.go:621:25:621:31 | tarRead | semmle.label | tarRead | -| test.go:627:23:627:29 | definition of tarRead | semmle.label | definition of tarRead | +| test.go:627:23:627:29 | SSA def(tarRead) | semmle.label | SSA def(tarRead) | | test.go:629:2:629:8 | tarRead | semmle.label | tarRead | subpaths diff --git a/go/ql/test/experimental/Unsafe/WrongUsageOfUnsafe.expected b/go/ql/test/experimental/Unsafe/WrongUsageOfUnsafe.expected index 0dfdf1d7c15..728d0b54da8 100644 --- a/go/ql/test/experimental/Unsafe/WrongUsageOfUnsafe.expected +++ b/go/ql/test/experimental/Unsafe/WrongUsageOfUnsafe.expected @@ -22,8 +22,8 @@ edges | WrongUsageOfUnsafe.go:166:33:166:57 | type conversion | WrongUsageOfUnsafe.go:166:16:166:58 | type conversion | provenance | | | WrongUsageOfUnsafe.go:189:31:189:55 | type conversion | WrongUsageOfUnsafe.go:189:16:189:56 | type conversion | provenance | | | WrongUsageOfUnsafe.go:211:31:211:60 | type conversion | WrongUsageOfUnsafe.go:211:16:211:61 | type conversion | provenance | | -| WrongUsageOfUnsafe.go:227:31:227:55 | type conversion | WrongUsageOfUnsafe.go:236:21:236:23 | definition of req | provenance | | -| WrongUsageOfUnsafe.go:236:21:236:23 | definition of req | WrongUsageOfUnsafe.go:243:9:243:27 | type conversion | provenance | | +| WrongUsageOfUnsafe.go:227:31:227:55 | type conversion | WrongUsageOfUnsafe.go:236:21:236:23 | SSA def(req) | provenance | | +| WrongUsageOfUnsafe.go:236:21:236:23 | SSA def(req) | WrongUsageOfUnsafe.go:243:9:243:27 | type conversion | provenance | | | WrongUsageOfUnsafe.go:256:28:256:52 | type conversion | WrongUsageOfUnsafe.go:256:16:256:53 | type conversion | provenance | | | WrongUsageOfUnsafe.go:274:25:274:49 | type conversion | WrongUsageOfUnsafe.go:274:16:274:50 | type conversion | provenance | | | WrongUsageOfUnsafe.go:292:23:292:47 | type conversion | WrongUsageOfUnsafe.go:292:16:292:48 | type conversion | provenance | | @@ -51,7 +51,7 @@ nodes | WrongUsageOfUnsafe.go:211:16:211:61 | type conversion | semmle.label | type conversion | | WrongUsageOfUnsafe.go:211:31:211:60 | type conversion | semmle.label | type conversion | | WrongUsageOfUnsafe.go:227:31:227:55 | type conversion | semmle.label | type conversion | -| WrongUsageOfUnsafe.go:236:21:236:23 | definition of req | semmle.label | definition of req | +| WrongUsageOfUnsafe.go:236:21:236:23 | SSA def(req) | semmle.label | SSA def(req) | | WrongUsageOfUnsafe.go:243:9:243:27 | type conversion | semmle.label | type conversion | | WrongUsageOfUnsafe.go:256:16:256:53 | type conversion | semmle.label | type conversion | | WrongUsageOfUnsafe.go:256:28:256:52 | type conversion | semmle.label | type conversion | diff --git a/go/ql/test/library-tests/semmle/go/concepts/LoggerCall/logrus.go b/go/ql/test/library-tests/semmle/go/concepts/LoggerCall/logrus.go index bdb57aae2e1..56677fff99b 100644 --- a/go/ql/test/library-tests/semmle/go/concepts/LoggerCall/logrus.go +++ b/go/ql/test/library-tests/semmle/go/concepts/LoggerCall/logrus.go @@ -13,7 +13,7 @@ func logSomething(entry *logrus.Entry) { entry.Traceln(text) // $ logger=text } -func logrusCalls() { +func logrusCalls(selector int) { err := errors.New("Error") var fields logrus.Fields = nil var fn logrus.LogFunction = nil @@ -27,11 +27,15 @@ func logrusCalls() { tmp = logrus.WithFields(fields) // $ logger=fields logSomething(tmp) - logrus.Error(text) // $ logger=text - logrus.Fatalf(fmt, text) // $ logger=fmt logger=text - logrus.Panicln(text) // $ logger=text - logrus.Infof(fmt, text) // $ logger=fmt logger=text - logrus.FatalFn(fn) // $ logger=fn + logrus.Error(text) // $ logger=text + logrus.Infof(fmt, text) // $ logger=fmt logger=text + if selector == 0 { + logrus.Fatalf(fmt, text) // $ logger=fmt logger=text + } else if selector == 1 { + logrus.Panicln(text) // $ logger=text + } else if selector == 2 { + logrus.FatalFn(fn) // $ logger=fn + } // components corresponding to the format specifier "%T" are not considered vulnerable logrus.Infof("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v diff --git a/go/ql/test/library-tests/semmle/go/concepts/LoggerCall/main.go b/go/ql/test/library-tests/semmle/go/concepts/LoggerCall/main.go index ae3699c1966..fd393f0d204 100644 --- a/go/ql/test/library-tests/semmle/go/concepts/LoggerCall/main.go +++ b/go/ql/test/library-tests/semmle/go/concepts/LoggerCall/main.go @@ -8,6 +8,6 @@ var v []byte func main() { glogTest(len(v)) - stdlib() + stdlib(len(v)) slogTest() } diff --git a/go/ql/test/library-tests/semmle/go/concepts/LoggerCall/stdlib.go b/go/ql/test/library-tests/semmle/go/concepts/LoggerCall/stdlib.go index 6fbf3c43fd3..e77e83a2ac5 100644 --- a/go/ql/test/library-tests/semmle/go/concepts/LoggerCall/stdlib.go +++ b/go/ql/test/library-tests/semmle/go/concepts/LoggerCall/stdlib.go @@ -4,37 +4,69 @@ import ( "log" ) -func stdlib() { +func stdlib(selector int) { var logger log.Logger logger.SetPrefix("prefix: ") - logger.Fatal(text) // $ logger=text - logger.Fatalf(fmt, text) // $ logger=fmt logger=text - logger.Fatalln(text) // $ logger=text - logger.Panic(text) // $ logger=text - logger.Panicf(fmt, text) // $ logger=fmt logger=text - logger.Panicln(text) // $ logger=text - logger.Print(text) // $ logger=text - logger.Printf(fmt, text) // $ logger=fmt logger=text - logger.Println(text) // $ logger=text + switch selector { + case 0: + logger.Fatal(text) // $ logger=text + case 1: + logger.Fatalf(fmt, text) // $ logger=fmt logger=text + case 2: + logger.Fatalln(text) // $ logger=text + case 3: + logger.Panic(text) // $ logger=text + case 4: + logger.Panicf(fmt, text) // $ logger=fmt logger=text + case 5: + logger.Panicln(text) // $ logger=text + case 6: + logger.Print(text) // $ logger=text + case 7: + logger.Printf(fmt, text) // $ logger=fmt logger=text + case 8: + logger.Println(text) // $ logger=text + } // components corresponding to the format specifier "%T" are not considered vulnerable - logger.Fatalf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v - logger.Panicf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v - logger.Printf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v + switch selector { + case 9: + logger.Fatalf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v + case 10: + logger.Panicf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v + case 11: + logger.Printf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v + } log.SetPrefix("prefix: ") - log.Fatal(text) // $ logger=text - log.Fatalf(fmt, text) // $ logger=fmt logger=text - log.Fatalln(text) // $ logger=text - log.Panic(text) // $ logger=text - log.Panicf(fmt, text) // $ logger=fmt logger=text - log.Panicln(text) // $ logger=text - log.Print(text) // $ logger=text - log.Printf(fmt, text) // $ logger=fmt logger=text - log.Println(text) // $ logger=text + switch selector { + case 12: + log.Fatal(text) // $ logger=text + case 13: + log.Fatalf(fmt, text) // $ logger=fmt logger=text + case 14: + log.Fatalln(text) // $ logger=text + case 15: + log.Panic(text) // $ logger=text + case 16: + log.Panicf(fmt, text) // $ logger=fmt logger=text + case 17: + log.Panicln(text) // $ logger=text + case 18: + log.Print(text) // $ logger=text + case 19: + log.Printf(fmt, text) // $ logger=fmt logger=text + case 20: + log.Println(text) // $ logger=text + } // components corresponding to the format specifier "%T" are not considered vulnerable - log.Fatalf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v - log.Panicf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v - log.Printf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v + switch selector { + case 21: + log.Fatalf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v + case 22: + log.Panicf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v + case 23: + log.Printf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v + } } diff --git a/go/ql/test/library-tests/semmle/go/concepts/Regexp/RegexpPattern.expected b/go/ql/test/library-tests/semmle/go/concepts/Regexp/RegexpPattern.expected index 1890c5c4ad9..63adab35d7b 100644 --- a/go/ql/test/library-tests/semmle/go/concepts/Regexp/RegexpPattern.expected +++ b/go/ql/test/library-tests/semmle/go/concepts/Regexp/RegexpPattern.expected @@ -3,7 +3,7 @@ | stdlib.go:13:21:13:24 | "ab" | ab | stdlib.go:13:21:13:24 | "ab" | | stdlib.go:15:26:15:39 | "[so]me\|regex" | [so]me\|regex | stdlib.go:15:2:15:40 | ... := ...[0] | | stdlib.go:15:26:15:39 | "[so]me\|regex" | [so]me\|regex | stdlib.go:15:26:15:39 | "[so]me\|regex" | -| stdlib.go:16:30:16:37 | "posix?" | posix? | stdlib.go:16:2:16:3 | definition of re | +| stdlib.go:16:30:16:37 | "posix?" | posix? | stdlib.go:16:2:16:3 | SSA def(re) | | stdlib.go:16:30:16:37 | "posix?" | posix? | stdlib.go:16:2:16:38 | ... = ...[0] | | stdlib.go:16:30:16:37 | "posix?" | posix? | stdlib.go:16:30:16:37 | "posix?" | | stdlib.go:16:30:16:37 | "posix?" | posix? | stdlib.go:17:2:17:3 | re | diff --git a/go/ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph/ControlFlowNode_getASuccessor.expected b/go/ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph/ControlFlowNode_getASuccessor.expected index f14d1319795..3768d015167 100644 --- a/go/ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph/ControlFlowNode_getASuccessor.expected +++ b/go/ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph/ControlFlowNode_getASuccessor.expected @@ -34,6 +34,265 @@ | DuplicateSwitchCase.go:16:1:16:14 | function declaration | DuplicateSwitchCase.go:0:0:0:0 | exit | | DuplicateSwitchCase.go:16:6:16:9 | skip | DuplicateSwitchCase.go:16:1:16:14 | function declaration | | DuplicateSwitchCase.go:16:13:16:14 | skip | DuplicateSwitchCase.go:16:1:16:14 | exit | +| epilogues.go:0:0:0:0 | entry | epilogues.go:3:1:3:12 | skip | +| epilogues.go:3:1:3:12 | skip | epilogues.go:8:1:10:1 | skip | +| epilogues.go:8:1:10:1 | skip | epilogues.go:12:21:12:23 | skip | +| epilogues.go:12:1:14:1 | entry | epilogues.go:12:7:12:7 | argument corresponding to l | +| epilogues.go:12:1:14:1 | function declaration | epilogues.go:16:20:16:27 | skip | +| epilogues.go:12:7:12:7 | argument corresponding to l | epilogues.go:12:7:12:7 | initialization of l | +| epilogues.go:12:7:12:7 | initialization of l | epilogues.go:12:25:12:27 | argument corresponding to msg | +| epilogues.go:12:21:12:23 | skip | epilogues.go:12:1:14:1 | function declaration | +| epilogues.go:12:25:12:27 | argument corresponding to msg | epilogues.go:12:25:12:27 | initialization of msg | +| epilogues.go:12:25:12:27 | initialization of msg | epilogues.go:12:37:12:40 | argument corresponding to code | +| epilogues.go:12:37:12:40 | argument corresponding to code | epilogues.go:12:37:12:40 | initialization of code | +| epilogues.go:12:37:12:40 | initialization of code | epilogues.go:13:2:13:12 | selection of Println | +| epilogues.go:13:2:13:12 | selection of Println | epilogues.go:13:14:13:14 | l | +| epilogues.go:13:2:13:33 | call to Println | epilogues.go:12:1:14:1 | exit | +| epilogues.go:13:14:13:14 | implicit dereference | epilogues.go:12:1:14:1 | exit | +| epilogues.go:13:14:13:14 | implicit dereference | epilogues.go:13:14:13:21 | selection of prefix | +| epilogues.go:13:14:13:14 | l | epilogues.go:13:14:13:14 | implicit dereference | +| epilogues.go:13:14:13:21 | selection of prefix | epilogues.go:13:24:13:26 | msg | +| epilogues.go:13:24:13:26 | msg | epilogues.go:13:29:13:32 | code | +| epilogues.go:13:29:13:32 | code | epilogues.go:13:2:13:33 | call to Println | +| epilogues.go:16:1:18:1 | entry | epilogues.go:16:7:16:7 | argument corresponding to l | +| epilogues.go:16:1:18:1 | function declaration | epilogues.go:23:6:23:15 | skip | +| epilogues.go:16:7:16:7 | argument corresponding to l | epilogues.go:16:7:16:7 | initialization of l | +| epilogues.go:16:7:16:7 | initialization of l | epilogues.go:16:29:16:31 | argument corresponding to msg | +| epilogues.go:16:20:16:27 | skip | epilogues.go:16:1:18:1 | function declaration | +| epilogues.go:16:29:16:31 | argument corresponding to msg | epilogues.go:16:29:16:31 | initialization of msg | +| epilogues.go:16:29:16:31 | initialization of msg | epilogues.go:17:2:17:12 | selection of Println | +| epilogues.go:17:2:17:12 | selection of Println | epilogues.go:17:14:17:14 | l | +| epilogues.go:17:2:17:27 | call to Println | epilogues.go:16:1:18:1 | exit | +| epilogues.go:17:14:17:14 | l | epilogues.go:17:14:17:21 | selection of prefix | +| epilogues.go:17:14:17:21 | selection of prefix | epilogues.go:17:24:17:26 | msg | +| epilogues.go:17:24:17:26 | msg | epilogues.go:17:2:17:27 | call to Println | +| epilogues.go:23:1:27:1 | entry | epilogues.go:24:5:24:5 | skip | +| epilogues.go:23:1:27:1 | function declaration | epilogues.go:31:6:31:13 | skip | +| epilogues.go:23:6:23:15 | skip | epilogues.go:23:1:27:1 | function declaration | +| epilogues.go:24:5:24:5 | assignment to r | epilogues.go:24:21:24:21 | r | +| epilogues.go:24:5:24:5 | skip | epilogues.go:24:10:24:16 | recover | +| epilogues.go:24:10:24:16 | recover | epilogues.go:24:10:24:18 | call to recover | +| epilogues.go:24:10:24:18 | call to recover | epilogues.go:24:5:24:5 | assignment to r | +| epilogues.go:24:21:24:21 | r | epilogues.go:24:26:24:28 | nil | +| epilogues.go:24:21:24:28 | ...!=... | epilogues.go:23:1:27:1 | exit | +| epilogues.go:24:21:24:28 | ...!=... | epilogues.go:24:21:24:28 | ...!=... is false | +| epilogues.go:24:21:24:28 | ...!=... | epilogues.go:24:21:24:28 | ...!=... is true | +| epilogues.go:24:21:24:28 | ...!=... is false | epilogues.go:23:1:27:1 | exit | +| epilogues.go:24:21:24:28 | ...!=... is true | epilogues.go:25:3:25:13 | selection of Println | +| epilogues.go:24:26:24:28 | nil | epilogues.go:24:21:24:28 | ...!=... | +| epilogues.go:25:3:25:13 | selection of Println | epilogues.go:25:15:25:26 | "recovered:" | +| epilogues.go:25:3:25:30 | call to Println | epilogues.go:23:1:27:1 | exit | +| epilogues.go:25:15:25:26 | "recovered:" | epilogues.go:25:29:25:29 | r | +| epilogues.go:25:29:25:29 | r | epilogues.go:25:3:25:30 | call to Println | +| epilogues.go:31:1:33:1 | entry | epilogues.go:31:15:31:15 | argument corresponding to x | +| epilogues.go:31:1:33:1 | function declaration | epilogues.go:36:6:36:12 | skip | +| epilogues.go:31:6:31:13 | skip | epilogues.go:31:1:33:1 | function declaration | +| epilogues.go:31:15:31:15 | argument corresponding to x | epilogues.go:31:15:31:15 | initialization of x | +| epilogues.go:31:15:31:15 | initialization of x | epilogues.go:32:9:32:9 | x | +| epilogues.go:32:2:32:13 | return statement | epilogues.go:31:1:33:1 | exit | +| epilogues.go:32:9:32:9 | x | epilogues.go:32:13:32:13 | 2 | +| epilogues.go:32:9:32:13 | ...*... | epilogues.go:32:2:32:13 | return statement | +| epilogues.go:32:13:32:13 | 2 | epilogues.go:32:9:32:13 | ...*... | +| epilogues.go:36:1:38:1 | entry | epilogues.go:37:2:37:12 | selection of Println | +| epilogues.go:36:1:38:1 | function declaration | epilogues.go:42:6:42:18 | skip | +| epilogues.go:36:6:36:12 | skip | epilogues.go:36:1:38:1 | function declaration | +| epilogues.go:37:2:37:12 | selection of Println | epilogues.go:37:14:37:19 | "void" | +| epilogues.go:37:2:37:20 | call to Println | epilogues.go:36:1:38:1 | exit | +| epilogues.go:37:14:37:19 | "void" | epilogues.go:37:2:37:20 | call to Println | +| epilogues.go:42:1:48:1 | entry | epilogues.go:42:20:42:20 | argument corresponding to x | +| epilogues.go:42:1:48:1 | function declaration | epilogues.go:51:6:51:21 | skip | +| epilogues.go:42:6:42:18 | skip | epilogues.go:42:1:48:1 | function declaration | +| epilogues.go:42:20:42:20 | argument corresponding to x | epilogues.go:42:20:42:20 | initialization of x | +| epilogues.go:42:20:42:20 | initialization of x | epilogues.go:42:28:42:33 | zero value for result | +| epilogues.go:42:28:42:33 | implicit read of result | epilogues.go:42:40:42:42 | implicit read of err | +| epilogues.go:42:28:42:33 | initialization of result | epilogues.go:42:40:42:42 | zero value for err | +| epilogues.go:42:28:42:33 | zero value for result | epilogues.go:42:28:42:33 | initialization of result | +| epilogues.go:42:40:42:42 | implicit read of err | epilogues.go:42:1:48:1 | exit | +| epilogues.go:42:40:42:42 | initialization of err | epilogues.go:43:5:43:5 | x | +| epilogues.go:42:40:42:42 | zero value for err | epilogues.go:42:40:42:42 | initialization of err | +| epilogues.go:43:5:43:5 | x | epilogues.go:43:9:43:9 | 0 | +| epilogues.go:43:5:43:9 | ...<... | epilogues.go:43:5:43:9 | ...<... is false | +| epilogues.go:43:5:43:9 | ...<... | epilogues.go:43:5:43:9 | ...<... is true | +| epilogues.go:43:5:43:9 | ...<... is false | epilogues.go:47:9:47:9 | x | +| epilogues.go:43:5:43:9 | ...<... is true | epilogues.go:44:3:44:8 | skip | +| epilogues.go:43:9:43:9 | 0 | epilogues.go:43:5:43:9 | ...<... | +| epilogues.go:44:3:44:8 | assignment to result | epilogues.go:45:3:45:8 | return statement | +| epilogues.go:44:3:44:8 | skip | epilogues.go:44:13:44:13 | x | +| epilogues.go:44:12:44:13 | -... | epilogues.go:44:3:44:8 | assignment to result | +| epilogues.go:44:13:44:13 | x | epilogues.go:44:12:44:13 | -... | +| epilogues.go:45:3:45:8 | return statement | epilogues.go:42:28:42:33 | implicit read of result | +| epilogues.go:47:2:47:14 | return statement | epilogues.go:42:28:42:33 | implicit read of result | +| epilogues.go:47:9:47:9 | implicit write of result | epilogues.go:47:12:47:14 | nil | +| epilogues.go:47:9:47:9 | x | epilogues.go:47:9:47:9 | implicit write of result | +| epilogues.go:47:12:47:14 | implicit write of err | epilogues.go:47:2:47:14 | return statement | +| epilogues.go:47:12:47:14 | nil | epilogues.go:47:12:47:14 | implicit write of err | +| epilogues.go:51:1:54:1 | entry | epilogues.go:51:23:51:23 | argument corresponding to x | +| epilogues.go:51:1:54:1 | function declaration | epilogues.go:59:6:59:25 | skip | +| epilogues.go:51:6:51:21 | skip | epilogues.go:51:1:54:1 | function declaration | +| epilogues.go:51:23:51:23 | argument corresponding to x | epilogues.go:51:23:51:23 | initialization of x | +| epilogues.go:51:23:51:23 | initialization of x | epilogues.go:51:31:51:31 | zero value for n | +| epilogues.go:51:31:51:31 | implicit read of n | epilogues.go:51:1:54:1 | exit | +| epilogues.go:51:31:51:31 | initialization of n | epilogues.go:52:2:52:2 | skip | +| epilogues.go:51:31:51:31 | zero value for n | epilogues.go:51:31:51:31 | initialization of n | +| epilogues.go:52:2:52:2 | assignment to n | epilogues.go:53:2:53:7 | return statement | +| epilogues.go:52:2:52:2 | skip | epilogues.go:52:6:52:6 | x | +| epilogues.go:52:6:52:6 | x | epilogues.go:52:10:52:10 | 1 | +| epilogues.go:52:6:52:10 | ...+... | epilogues.go:52:2:52:2 | assignment to n | +| epilogues.go:52:10:52:10 | 1 | epilogues.go:52:6:52:10 | ...+... | +| epilogues.go:53:2:53:7 | return statement | epilogues.go:51:31:51:31 | implicit read of n | +| epilogues.go:59:1:62:1 | entry | epilogues.go:59:27:59:27 | argument corresponding to l | +| epilogues.go:59:1:62:1 | function declaration | epilogues.go:66:6:66:26 | skip | +| epilogues.go:59:6:59:25 | skip | epilogues.go:59:1:62:1 | function declaration | +| epilogues.go:59:27:59:27 | argument corresponding to l | epilogues.go:59:27:59:27 | initialization of l | +| epilogues.go:59:27:59:27 | initialization of l | epilogues.go:59:41:59:45 | argument corresponding to items | +| epilogues.go:59:41:59:45 | argument corresponding to items | epilogues.go:59:41:59:45 | initialization of items | +| epilogues.go:59:41:59:45 | initialization of items | epilogues.go:60:8:60:8 | l | +| epilogues.go:60:2:60:33 | defer statement | epilogues.go:61:2:61:12 | selection of Println | +| epilogues.go:60:8:60:8 | l | epilogues.go:60:8:60:12 | selection of log | +| epilogues.go:60:8:60:12 | selection of log | epilogues.go:60:14:60:20 | "count" | +| epilogues.go:60:8:60:33 | call to log | epilogues.go:59:1:62:1 | exit | +| epilogues.go:60:14:60:20 | "count" | epilogues.go:60:23:60:25 | len | +| epilogues.go:60:23:60:25 | len | epilogues.go:60:27:60:31 | items | +| epilogues.go:60:23:60:32 | call to len | epilogues.go:60:2:60:33 | defer statement | +| epilogues.go:60:27:60:31 | items | epilogues.go:60:23:60:32 | call to len | +| epilogues.go:61:2:61:12 | selection of Println | epilogues.go:61:14:61:25 | "processing" | +| epilogues.go:61:2:61:38 | call to Println | epilogues.go:60:8:60:33 | call to log | +| epilogues.go:61:14:61:25 | "processing" | epilogues.go:61:28:61:30 | len | +| epilogues.go:61:28:61:30 | len | epilogues.go:61:32:61:36 | items | +| epilogues.go:61:28:61:37 | call to len | epilogues.go:61:2:61:38 | call to Println | +| epilogues.go:61:32:61:36 | items | epilogues.go:61:28:61:37 | call to len | +| epilogues.go:66:1:71:1 | entry | epilogues.go:66:28:66:33 | argument corresponding to prefix | +| epilogues.go:66:1:71:1 | function declaration | epilogues.go:77:6:77:20 | skip | +| epilogues.go:66:6:66:26 | skip | epilogues.go:66:1:71:1 | function declaration | +| epilogues.go:66:28:66:33 | argument corresponding to prefix | epilogues.go:66:28:66:33 | initialization of prefix | +| epilogues.go:66:28:66:33 | initialization of prefix | epilogues.go:67:2:67:2 | skip | +| epilogues.go:67:2:67:2 | assignment to l | epilogues.go:68:8:68:8 | l | +| epilogues.go:67:2:67:2 | skip | epilogues.go:67:7:67:31 | struct literal | +| epilogues.go:67:7:67:31 | struct literal | epilogues.go:67:25:67:30 | prefix | +| epilogues.go:67:17:67:30 | init of key-value pair | epilogues.go:67:2:67:2 | assignment to l | +| epilogues.go:67:25:67:30 | prefix | epilogues.go:67:17:67:30 | init of key-value pair | +| epilogues.go:68:2:68:24 | defer statement | epilogues.go:69:10:69:10 | l | +| epilogues.go:68:8:68:8 | l | epilogues.go:68:8:68:17 | selection of logValue | +| epilogues.go:68:8:68:17 | selection of logValue | epilogues.go:68:19:68:23 | "bye" | +| epilogues.go:68:8:68:24 | call to logValue | epilogues.go:66:1:71:1 | exit | +| epilogues.go:68:19:68:23 | "bye" | epilogues.go:68:2:68:24 | defer statement | +| epilogues.go:69:2:69:25 | defer statement | epilogues.go:70:2:70:12 | selection of Println | +| epilogues.go:69:8:69:15 | selection of log | epilogues.go:69:17:69:21 | "ptr" | +| epilogues.go:69:8:69:25 | call to log | epilogues.go:68:8:68:24 | call to logValue | +| epilogues.go:69:9:69:10 | &... | epilogues.go:69:8:69:15 | selection of log | +| epilogues.go:69:10:69:10 | l | epilogues.go:69:9:69:10 | &... | +| epilogues.go:69:17:69:21 | "ptr" | epilogues.go:69:24:69:24 | 7 | +| epilogues.go:69:24:69:24 | 7 | epilogues.go:69:2:69:25 | defer statement | +| epilogues.go:70:2:70:12 | selection of Println | epilogues.go:70:14:70:19 | "body" | +| epilogues.go:70:2:70:20 | call to Println | epilogues.go:69:8:69:25 | call to log | +| epilogues.go:70:14:70:19 | "body" | epilogues.go:70:2:70:20 | call to Println | +| epilogues.go:77:1:82:1 | entry | epilogues.go:77:22:77:22 | argument corresponding to x | +| epilogues.go:77:1:82:1 | function declaration | epilogues.go:87:6:87:20 | skip | +| epilogues.go:77:6:77:20 | skip | epilogues.go:77:1:82:1 | function declaration | +| epilogues.go:77:22:77:22 | argument corresponding to x | epilogues.go:77:22:77:22 | initialization of x | +| epilogues.go:77:22:77:22 | initialization of x | epilogues.go:78:8:80:2 | function literal | +| epilogues.go:78:2:80:15 | defer statement | epilogues.go:81:2:81:12 | selection of Println | +| epilogues.go:78:8:80:2 | entry | epilogues.go:78:13:78:17 | argument corresponding to label | +| epilogues.go:78:8:80:2 | function literal | epilogues.go:80:4:80:9 | "done" | +| epilogues.go:78:8:80:15 | function call | epilogues.go:77:1:82:1 | exit | +| epilogues.go:78:13:78:17 | argument corresponding to label | epilogues.go:78:13:78:17 | initialization of label | +| epilogues.go:78:13:78:17 | initialization of label | epilogues.go:78:27:78:27 | argument corresponding to n | +| epilogues.go:78:27:78:27 | argument corresponding to n | epilogues.go:78:27:78:27 | initialization of n | +| epilogues.go:78:27:78:27 | initialization of n | epilogues.go:79:3:79:13 | selection of Println | +| epilogues.go:79:3:79:13 | selection of Println | epilogues.go:79:15:79:19 | label | +| epilogues.go:79:3:79:23 | call to Println | epilogues.go:78:8:80:2 | exit | +| epilogues.go:79:15:79:19 | label | epilogues.go:79:22:79:22 | n | +| epilogues.go:79:22:79:22 | n | epilogues.go:79:3:79:23 | call to Println | +| epilogues.go:80:4:80:9 | "done" | epilogues.go:80:12:80:12 | x | +| epilogues.go:80:12:80:12 | x | epilogues.go:80:14:80:14 | 1 | +| epilogues.go:80:12:80:14 | ...+... | epilogues.go:78:2:80:15 | defer statement | +| epilogues.go:80:14:80:14 | 1 | epilogues.go:80:12:80:14 | ...+... | +| epilogues.go:81:2:81:12 | selection of Println | epilogues.go:81:14:81:19 | "body" | +| epilogues.go:81:2:81:23 | call to Println | epilogues.go:78:8:80:15 | function call | +| epilogues.go:81:14:81:19 | "body" | epilogues.go:81:22:81:22 | x | +| epilogues.go:81:22:81:22 | x | epilogues.go:81:2:81:23 | call to Println | +| epilogues.go:87:1:98:1 | entry | epilogues.go:87:22:87:22 | argument corresponding to x | +| epilogues.go:87:1:98:1 | function declaration | epilogues.go:102:6:102:24 | skip | +| epilogues.go:87:6:87:20 | skip | epilogues.go:87:1:98:1 | function declaration | +| epilogues.go:87:22:87:22 | argument corresponding to x | epilogues.go:87:22:87:22 | initialization of x | +| epilogues.go:87:22:87:22 | initialization of x | epilogues.go:87:30:87:35 | zero value for result | +| epilogues.go:87:30:87:35 | implicit read of result | epilogues.go:87:1:98:1 | exit | +| epilogues.go:87:30:87:35 | initialization of result | epilogues.go:88:8:92:2 | function literal | +| epilogues.go:87:30:87:35 | zero value for result | epilogues.go:87:30:87:35 | initialization of result | +| epilogues.go:88:2:92:4 | defer statement | epilogues.go:93:5:93:5 | x | +| epilogues.go:88:8:92:2 | entry | epilogues.go:89:6:89:6 | skip | +| epilogues.go:88:8:92:2 | function literal | epilogues.go:88:2:92:4 | defer statement | +| epilogues.go:88:8:92:4 | function call | epilogues.go:87:1:98:1 | exit | +| epilogues.go:88:8:92:4 | function call | epilogues.go:87:30:87:35 | implicit read of result | +| epilogues.go:89:6:89:6 | assignment to r | epilogues.go:89:22:89:22 | r | +| epilogues.go:89:6:89:6 | skip | epilogues.go:89:11:89:17 | recover | +| epilogues.go:89:11:89:17 | recover | epilogues.go:89:11:89:19 | call to recover | +| epilogues.go:89:11:89:19 | call to recover | epilogues.go:89:6:89:6 | assignment to r | +| epilogues.go:89:22:89:22 | r | epilogues.go:89:27:89:29 | nil | +| epilogues.go:89:22:89:29 | ...!=... | epilogues.go:88:8:92:2 | exit | +| epilogues.go:89:22:89:29 | ...!=... | epilogues.go:89:22:89:29 | ...!=... is false | +| epilogues.go:89:22:89:29 | ...!=... | epilogues.go:89:22:89:29 | ...!=... is true | +| epilogues.go:89:22:89:29 | ...!=... is false | epilogues.go:88:8:92:2 | exit | +| epilogues.go:89:22:89:29 | ...!=... is true | epilogues.go:90:4:90:9 | skip | +| epilogues.go:89:27:89:29 | nil | epilogues.go:89:22:89:29 | ...!=... | +| epilogues.go:90:4:90:9 | assignment to result | epilogues.go:88:8:92:2 | exit | +| epilogues.go:90:4:90:9 | skip | epilogues.go:90:13:90:14 | -... | +| epilogues.go:90:13:90:14 | -... | epilogues.go:90:4:90:9 | assignment to result | +| epilogues.go:93:5:93:5 | x | epilogues.go:93:9:93:9 | 0 | +| epilogues.go:93:5:93:9 | ...<... | epilogues.go:93:5:93:9 | ...<... is false | +| epilogues.go:93:5:93:9 | ...<... | epilogues.go:93:5:93:9 | ...<... is true | +| epilogues.go:93:5:93:9 | ...<... is false | epilogues.go:96:2:96:7 | skip | +| epilogues.go:93:5:93:9 | ...<... is true | epilogues.go:94:3:94:7 | panic | +| epilogues.go:93:9:93:9 | 0 | epilogues.go:93:5:93:9 | ...<... | +| epilogues.go:94:3:94:7 | panic | epilogues.go:94:9:94:13 | "neg" | +| epilogues.go:94:3:94:14 | call to panic | epilogues.go:88:8:92:4 | function call | +| epilogues.go:94:9:94:13 | "neg" | epilogues.go:94:3:94:14 | call to panic | +| epilogues.go:96:2:96:7 | assignment to result | epilogues.go:97:9:97:14 | result | +| epilogues.go:96:2:96:7 | skip | epilogues.go:96:11:96:11 | x | +| epilogues.go:96:11:96:11 | x | epilogues.go:96:15:96:15 | x | +| epilogues.go:96:11:96:15 | ...*... | epilogues.go:96:2:96:7 | assignment to result | +| epilogues.go:96:15:96:15 | x | epilogues.go:96:11:96:15 | ...*... | +| epilogues.go:97:2:97:14 | return statement | epilogues.go:88:8:92:4 | function call | +| epilogues.go:97:9:97:14 | implicit write of result | epilogues.go:97:2:97:14 | return statement | +| epilogues.go:97:9:97:14 | result | epilogues.go:97:9:97:14 | implicit write of result | +| epilogues.go:102:1:110:1 | entry | epilogues.go:102:26:102:26 | argument corresponding to x | +| epilogues.go:102:1:110:1 | function declaration | epilogues.go:115:6:115:22 | skip | +| epilogues.go:102:6:102:24 | skip | epilogues.go:102:1:110:1 | function declaration | +| epilogues.go:102:26:102:26 | argument corresponding to x | epilogues.go:102:26:102:26 | initialization of x | +| epilogues.go:102:26:102:26 | initialization of x | epilogues.go:102:34:102:35 | zero value for ok | +| epilogues.go:102:34:102:35 | implicit read of ok | epilogues.go:102:43:102:43 | implicit read of n | +| epilogues.go:102:34:102:35 | initialization of ok | epilogues.go:102:43:102:43 | zero value for n | +| epilogues.go:102:34:102:35 | zero value for ok | epilogues.go:102:34:102:35 | initialization of ok | +| epilogues.go:102:43:102:43 | implicit read of n | epilogues.go:102:1:110:1 | exit | +| epilogues.go:102:43:102:43 | initialization of n | epilogues.go:103:8:103:17 | epiRecover | +| epilogues.go:102:43:102:43 | zero value for n | epilogues.go:102:43:102:43 | initialization of n | +| epilogues.go:103:2:103:19 | defer statement | epilogues.go:104:5:104:5 | x | +| epilogues.go:103:8:103:17 | epiRecover | epilogues.go:103:2:103:19 | defer statement | +| epilogues.go:103:8:103:19 | call to epiRecover | epilogues.go:102:1:110:1 | exit | +| epilogues.go:103:8:103:19 | call to epiRecover | epilogues.go:102:34:102:35 | implicit read of ok | +| epilogues.go:104:5:104:5 | x | epilogues.go:104:10:104:10 | 0 | +| epilogues.go:104:5:104:10 | ...==... | epilogues.go:104:5:104:10 | ...==... is false | +| epilogues.go:104:5:104:10 | ...==... | epilogues.go:104:5:104:10 | ...==... is true | +| epilogues.go:104:5:104:10 | ...==... is false | epilogues.go:107:2:107:2 | skip | +| epilogues.go:104:5:104:10 | ...==... is true | epilogues.go:105:3:105:8 | return statement | +| epilogues.go:104:10:104:10 | 0 | epilogues.go:104:5:104:10 | ...==... | +| epilogues.go:105:3:105:8 | return statement | epilogues.go:103:8:103:19 | call to epiRecover | +| epilogues.go:107:2:107:2 | assignment to n | epilogues.go:108:2:108:3 | skip | +| epilogues.go:107:2:107:2 | skip | epilogues.go:107:6:107:6 | x | +| epilogues.go:107:6:107:6 | x | epilogues.go:107:2:107:2 | assignment to n | +| epilogues.go:108:2:108:3 | assignment to ok | epilogues.go:109:2:109:7 | return statement | +| epilogues.go:108:2:108:3 | skip | epilogues.go:108:7:108:10 | true | +| epilogues.go:108:7:108:10 | true | epilogues.go:108:2:108:3 | assignment to ok | +| epilogues.go:109:2:109:7 | return statement | epilogues.go:103:8:103:19 | call to epiRecover | +| epilogues.go:115:1:118:1 | entry | epilogues.go:116:8:116:17 | epiRecover | +| epilogues.go:115:1:118:1 | function declaration | epilogues.go:0:0:0:0 | exit | +| epilogues.go:115:6:115:22 | skip | epilogues.go:115:1:118:1 | function declaration | +| epilogues.go:116:2:116:19 | defer statement | epilogues.go:117:2:117:6 | panic | +| epilogues.go:116:8:116:17 | epiRecover | epilogues.go:116:2:116:19 | defer statement | +| epilogues.go:116:8:116:19 | call to epiRecover | epilogues.go:115:1:118:1 | exit | +| epilogues.go:117:2:117:6 | panic | epilogues.go:117:8:117:13 | "boom" | +| epilogues.go:117:2:117:14 | call to panic | epilogues.go:116:8:116:19 | call to epiRecover | +| epilogues.go:117:8:117:13 | "boom" | epilogues.go:117:2:117:14 | call to panic | | equalitytests.go:0:0:0:0 | entry | equalitytests.go:3:1:5:1 | skip | | equalitytests.go:3:1:5:1 | skip | equalitytests.go:7:1:9:1 | skip | | equalitytests.go:7:1:9:1 | skip | equalitytests.go:11:6:11:18 | skip | diff --git a/go/ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph/NoretFunctions.expected b/go/ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph/NoretFunctions.expected index 4e466b74504..2715352ef25 100644 --- a/go/ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph/NoretFunctions.expected +++ b/go/ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph/NoretFunctions.expected @@ -1,3 +1,4 @@ +| epilogues.go:115:6:115:22 | epiRecoverUnnamed | github.com/github/codeql-go/ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph.epiRecoverUnnamed | | file://:0:0:0:0 | Exit | os.Exit | | file://:0:0:0:0 | Fatal | log.Fatal | | file://:0:0:0:0 | Fatal | log.Logger.Fatal | diff --git a/go/ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph/epilogues.go b/go/ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph/epilogues.go new file mode 100644 index 00000000000..ed87a94c8e0 --- /dev/null +++ b/go/ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph/epilogues.go @@ -0,0 +1,118 @@ +package main + +import "fmt" + +// epiLogger has methods with both pointer and value receivers, used to check +// that the receiver and arguments of a deferred call are evaluated at the +// `defer` statement rather than in the function epilogue. +type epiLogger struct { + prefix string +} + +func (l *epiLogger) log(msg string, code int) { + fmt.Println(l.prefix, msg, code) +} + +func (l epiLogger) logValue(msg string) { + fmt.Println(l.prefix, msg) +} + +// epiRecover recovers from a panic. It is used as a deferred function so we can +// check that control flow returns to the result-read nodes and the normal exit +// node after recovering. +func epiRecover() { + if r := recover(); r != nil { + fmt.Println("recovered:", r) + } +} + +// epiPlain has no named result variable and a single `return` with a child +// expression. +func epiPlain(x int) int { + return x * 2 +} + +// epiVoid has no named result variable and no `return` statement at all. +func epiVoid() { + fmt.Println("void") +} + +// epiNamedMixed has named result variables and a mix of a bare `return` (no +// child expressions) and a `return` with child expressions. +func epiNamedMixed(x int) (result int, err error) { + if x < 0 { + result = -x + return + } + return x, nil +} + +// epiNamedBareOnly has a named result variable and only a bare `return`. +func epiNamedBareOnly(x int) (n int) { + n = x + 1 + return +} + +// epiDeferReceiverArgs has a deferred call with a (pointer) receiver and +// arguments that are expressions, so we can check the receiver `l` and the +// arguments `"count"` and `len(items)` are evaluated at the `defer` statement. +func epiDeferReceiverArgs(l *epiLogger, items []int) { + defer l.log("count", len(items)) + fmt.Println("processing", len(items)) +} + +// epiDeferValueReceiver has deferred calls with a value receiver and an +// address-of receiver, both with arguments evaluated at the `defer` statement. +func epiDeferValueReceiver(prefix string) { + l := epiLogger{prefix: prefix} + defer l.logValue("bye") + defer (&l).log("ptr", 7) + fmt.Println("body") +} + +// epiDeferFuncLit has a deferred function literal with parameters, so we can +// check that the arguments `"done"` and `x+1` are evaluated at the `defer` +// statement and that control flow enters the function literal body when it is +// invoked at the function epilogue. +func epiDeferFuncLit(x int) { + defer func(label string, n int) { + fmt.Println(label, n) + }("done", x+1) + fmt.Println("body", x) +} + +// epiRecoverNamed has a named result variable and a deferred closure containing +// `recover()`. After recovering on the panic path, control flow should return +// to the result-read nodes and the normal exit node. +func epiRecoverNamed(x int) (result int) { + defer func() { + if r := recover(); r != nil { + result = -1 + } + }() + if x < 0 { + panic("neg") + } + result = x * x + return result +} + +// epiRecoverNamedBare has named result variables, a deferred function +// containing `recover()`, and only bare `return` statements. +func epiRecoverNamedBare(x int) (ok bool, n int) { + defer epiRecover() + if x == 0 { + return + } + n = x + ok = true + return +} + +// epiRecoverUnnamed has no named result variables and a deferred function +// containing `recover()`; after recovering, control flow should reach the +// normal exit node directly (there are no result-read nodes). +func epiRecoverUnnamed() { + defer epiRecover() + panic("boom") +} diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalTaintFlow/srcs.expected b/go/ql/test/library-tests/semmle/go/dataflow/ExternalTaintFlow/srcs.expected index e04fcf75309..dac98957550 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalTaintFlow/srcs.expected +++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalTaintFlow/srcs.expected @@ -22,4 +22,4 @@ invalidModelRow | test.go:187:24:187:31 | call to Src1 | qltest | | test.go:191:24:191:31 | call to Src1 | qltest | | test.go:201:10:201:28 | selection of SourceVariable | qltest | -| test.go:208:15:208:17 | definition of src | qltest | +| test.go:208:15:208:17 | SSA def(src) | qltest | diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalValueFlow/srcs.expected b/go/ql/test/library-tests/semmle/go/dataflow/ExternalValueFlow/srcs.expected index f5768d49d1b..87ca46d4c13 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalValueFlow/srcs.expected +++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalValueFlow/srcs.expected @@ -22,4 +22,4 @@ invalidModelRow | test.go:187:24:187:31 | call to Src1 | qltest | | test.go:191:24:191:31 | call to Src1 | qltest | | test.go:209:10:209:28 | selection of SourceVariable | qltest | -| test.go:216:15:216:17 | definition of src | qltest | +| test.go:216:15:216:17 | SSA def(src) | qltest | diff --git a/go/ql/test/library-tests/semmle/go/dataflow/FlowSteps/LocalFlowStep.expected b/go/ql/test/library-tests/semmle/go/dataflow/FlowSteps/LocalFlowStep.expected index 7fa8b681d7f..0f34d658917 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/FlowSteps/LocalFlowStep.expected +++ b/go/ql/test/library-tests/semmle/go/dataflow/FlowSteps/LocalFlowStep.expected @@ -1,169 +1,169 @@ -| main.go:3:12:3:12 | argument corresponding to x | main.go:3:12:3:12 | definition of x | -| main.go:3:12:3:12 | definition of x | main.go:5:5:5:5 | x | -| main.go:3:19:3:20 | argument corresponding to fn | main.go:3:19:3:20 | definition of fn | -| main.go:3:19:3:20 | definition of fn | main.go:10:24:10:25 | fn | +| main.go:3:12:3:12 | SSA def(x) | main.go:5:5:5:5 | x | +| main.go:3:12:3:12 | argument corresponding to x | main.go:3:12:3:12 | SSA def(x) | +| main.go:3:19:3:20 | SSA def(fn) | main.go:10:24:10:25 | fn | +| main.go:3:19:3:20 | argument corresponding to fn | main.go:3:19:3:20 | SSA def(fn) | | main.go:5:5:5:5 | x | main.go:6:7:6:7 | x | | main.go:5:5:5:5 | x | main.go:8:8:8:8 | x | -| main.go:6:3:6:3 | definition of y | main.go:10:12:10:12 | y | -| main.go:6:7:6:7 | x | main.go:6:3:6:3 | definition of y | +| main.go:6:3:6:3 | SSA def(y) | main.go:10:12:10:12 | y | +| main.go:6:7:6:7 | x | main.go:6:3:6:3 | SSA def(y) | | main.go:6:7:6:7 | x | main.go:10:7:10:7 | x | -| main.go:8:3:8:3 | definition of y | main.go:10:12:10:12 | y | -| main.go:8:7:8:8 | -... | main.go:8:3:8:3 | definition of y | +| main.go:8:3:8:3 | SSA def(y) | main.go:10:12:10:12 | y | +| main.go:8:7:8:8 | -... | main.go:8:3:8:3 | SSA def(y) | | main.go:8:8:8:8 | x | main.go:10:7:10:7 | x | -| main.go:10:2:10:2 | definition of z | main.go:11:14:11:14 | z | +| main.go:10:2:10:2 | SSA def(z) | main.go:11:14:11:14 | z | | main.go:10:7:10:7 | x | main.go:10:22:10:22 | x | | main.go:10:7:10:12 | ...<=... | main.go:10:7:10:27 | ...&&... | -| main.go:10:7:10:27 | ...&&... | main.go:10:2:10:2 | definition of z | +| main.go:10:7:10:27 | ...&&... | main.go:10:2:10:2 | SSA def(z) | | main.go:10:12:10:12 | y | main.go:10:17:10:17 | y | | main.go:10:17:10:27 | ...>=... | main.go:10:7:10:27 | ...&&... | | main.go:11:14:11:14 | z | main.go:11:9:11:15 | type conversion | -| main.go:15:9:15:9 | 0 | main.go:15:2:15:4 | definition of acc | -| main.go:16:9:19:2 | capture variable acc | main.go:17:3:17:5 | acc | -| main.go:17:3:17:7 | definition of acc | main.go:18:10:18:12 | acc | -| main.go:17:3:17:7 | rhs of increment statement | main.go:17:3:17:7 | definition of acc | -| main.go:22:12:22:12 | argument corresponding to b | main.go:22:12:22:12 | definition of b | -| main.go:22:12:22:12 | definition of b | main.go:23:5:23:5 | b | -| main.go:22:20:22:20 | argument corresponding to x | main.go:22:20:22:20 | definition of x | -| main.go:22:20:22:20 | definition of x | main.go:24:10:24:10 | x | -| main.go:22:20:22:20 | definition of x | main.go:26:11:26:11 | x | +| main.go:15:9:15:9 | 0 | main.go:15:2:15:4 | SSA def(acc) | +| main.go:16:9:19:2 | SSA def(acc) | main.go:17:3:17:5 | acc | +| main.go:17:3:17:7 | SSA def(acc) | main.go:18:10:18:12 | acc | +| main.go:17:3:17:7 | rhs of increment statement | main.go:17:3:17:7 | SSA def(acc) | +| main.go:22:12:22:12 | SSA def(b) | main.go:23:5:23:5 | b | +| main.go:22:12:22:12 | argument corresponding to b | main.go:22:12:22:12 | SSA def(b) | +| main.go:22:20:22:20 | SSA def(x) | main.go:24:10:24:10 | x | +| main.go:22:20:22:20 | SSA def(x) | main.go:26:11:26:11 | x | +| main.go:22:20:22:20 | argument corresponding to x | main.go:22:20:22:20 | SSA def(x) | | main.go:24:10:24:10 | x | main.go:24:10:24:19 | type assertion | -| main.go:26:2:26:2 | definition of n | main.go:27:11:27:11 | n | -| main.go:26:2:26:17 | ... := ...[0] | main.go:26:2:26:2 | definition of n | -| main.go:26:2:26:17 | ... := ...[1] | main.go:26:5:26:6 | definition of ok | -| main.go:26:5:26:6 | definition of ok | main.go:27:5:27:6 | ok | +| main.go:26:2:26:2 | SSA def(n) | main.go:27:11:27:11 | n | +| main.go:26:2:26:17 | ... := ...[0] | main.go:26:2:26:2 | SSA def(n) | +| main.go:26:2:26:17 | ... := ...[1] | main.go:26:5:26:6 | SSA def(ok) | +| main.go:26:5:26:6 | SSA def(ok) | main.go:27:5:27:6 | ok | | main.go:26:11:26:11 | x | main.go:26:2:26:17 | ... := ...[0] | -| main.go:38:2:38:2 | definition of s | main.go:39:15:39:15 | s | -| main.go:38:7:38:20 | slice literal | main.go:38:2:38:2 | definition of s | -| main.go:38:7:38:20 | slice literal [postupdate] | main.go:38:2:38:2 | definition of s | -| main.go:39:2:39:3 | definition of s1 | main.go:40:18:40:19 | s1 | -| main.go:39:8:39:25 | call to append | main.go:39:2:39:3 | definition of s1 | +| main.go:38:2:38:2 | SSA def(s) | main.go:39:15:39:15 | s | +| main.go:38:7:38:20 | slice literal | main.go:38:2:38:2 | SSA def(s) | +| main.go:38:7:38:20 | slice literal [postupdate] | main.go:38:2:38:2 | SSA def(s) | +| main.go:39:2:39:3 | SSA def(s1) | main.go:40:18:40:19 | s1 | +| main.go:39:8:39:25 | call to append | main.go:39:2:39:3 | SSA def(s1) | | main.go:39:15:39:15 | s | main.go:40:15:40:15 | s | | main.go:39:15:39:15 | s [postupdate] | main.go:40:15:40:15 | s | -| main.go:40:2:40:3 | definition of s2 | main.go:43:9:43:10 | s2 | -| main.go:40:8:40:23 | call to append | main.go:40:2:40:3 | definition of s2 | +| main.go:40:2:40:3 | SSA def(s2) | main.go:43:9:43:10 | s2 | +| main.go:40:8:40:23 | call to append | main.go:40:2:40:3 | SSA def(s2) | | main.go:40:15:40:15 | s | main.go:42:7:42:7 | s | | main.go:40:15:40:15 | s [postupdate] | main.go:42:7:42:7 | s | -| main.go:41:2:41:3 | definition of s4 | main.go:42:10:42:11 | s4 | -| main.go:41:8:41:21 | call to make | main.go:41:2:41:3 | definition of s4 | -| main.go:46:13:46:14 | argument corresponding to xs | main.go:46:13:46:14 | definition of xs | -| main.go:46:13:46:14 | definition of xs | main.go:47:20:47:21 | xs | -| main.go:46:24:46:27 | definition of keys | main.go:46:24:46:27 | implicit read of keys | -| main.go:46:24:46:27 | definition of keys | main.go:49:3:49:6 | keys | -| main.go:46:24:46:27 | zero value for keys | main.go:46:24:46:27 | definition of keys | -| main.go:46:34:46:37 | definition of vals | main.go:46:34:46:37 | implicit read of vals | -| main.go:46:34:46:37 | definition of vals | main.go:48:3:48:6 | vals | -| main.go:46:34:46:37 | zero value for vals | main.go:46:34:46:37 | definition of vals | -| main.go:47:2:50:2 | range statement[0] | main.go:47:6:47:6 | definition of k | -| main.go:47:2:50:2 | range statement[1] | main.go:47:9:47:9 | definition of v | -| main.go:47:6:47:6 | definition of k | main.go:49:11:49:11 | k | -| main.go:47:9:47:9 | definition of v | main.go:48:11:48:11 | v | -| main.go:48:3:48:6 | definition of vals | main.go:46:34:46:37 | implicit read of vals | -| main.go:48:3:48:6 | definition of vals | main.go:48:3:48:6 | vals | -| main.go:48:3:48:11 | ... += ... | main.go:48:3:48:6 | definition of vals | -| main.go:49:3:49:6 | definition of keys | main.go:46:24:46:27 | implicit read of keys | -| main.go:49:3:49:6 | definition of keys | main.go:49:3:49:6 | keys | -| main.go:49:3:49:11 | ... += ... | main.go:49:3:49:6 | definition of keys | -| main.go:55:6:55:7 | definition of ch | main.go:56:2:56:3 | ch | -| main.go:55:6:55:7 | zero value for ch | main.go:55:6:55:7 | definition of ch | +| main.go:41:2:41:3 | SSA def(s4) | main.go:42:10:42:11 | s4 | +| main.go:41:8:41:21 | call to make | main.go:41:2:41:3 | SSA def(s4) | +| main.go:46:13:46:14 | SSA def(xs) | main.go:47:20:47:21 | xs | +| main.go:46:13:46:14 | argument corresponding to xs | main.go:46:13:46:14 | SSA def(xs) | +| main.go:46:24:46:27 | SSA def(keys) | main.go:46:24:46:27 | implicit read of keys | +| main.go:46:24:46:27 | SSA def(keys) | main.go:49:3:49:6 | keys | +| main.go:46:24:46:27 | zero value for keys | main.go:46:24:46:27 | SSA def(keys) | +| main.go:46:34:46:37 | SSA def(vals) | main.go:46:34:46:37 | implicit read of vals | +| main.go:46:34:46:37 | SSA def(vals) | main.go:48:3:48:6 | vals | +| main.go:46:34:46:37 | zero value for vals | main.go:46:34:46:37 | SSA def(vals) | +| main.go:47:2:50:2 | range statement[0] | main.go:47:6:47:6 | SSA def(k) | +| main.go:47:2:50:2 | range statement[1] | main.go:47:9:47:9 | SSA def(v) | +| main.go:47:6:47:6 | SSA def(k) | main.go:49:11:49:11 | k | +| main.go:47:9:47:9 | SSA def(v) | main.go:48:11:48:11 | v | +| main.go:48:3:48:6 | SSA def(vals) | main.go:46:34:46:37 | implicit read of vals | +| main.go:48:3:48:6 | SSA def(vals) | main.go:48:3:48:6 | vals | +| main.go:48:3:48:11 | ... += ... | main.go:48:3:48:6 | SSA def(vals) | +| main.go:49:3:49:6 | SSA def(keys) | main.go:46:24:46:27 | implicit read of keys | +| main.go:49:3:49:6 | SSA def(keys) | main.go:49:3:49:6 | keys | +| main.go:49:3:49:11 | ... += ... | main.go:49:3:49:6 | SSA def(keys) | +| main.go:55:6:55:7 | SSA def(ch) | main.go:56:2:56:3 | ch | +| main.go:55:6:55:7 | zero value for ch | main.go:55:6:55:7 | SSA def(ch) | | main.go:56:2:56:3 | ch | main.go:57:4:57:5 | ch | | main.go:56:2:56:3 | ch [postupdate] | main.go:57:4:57:5 | ch | -| main.go:61:2:61:2 | definition of x | main.go:64:11:64:11 | x | -| main.go:61:7:61:7 | 1 | main.go:61:2:61:2 | definition of x | -| main.go:62:2:62:2 | definition of y | main.go:64:14:64:14 | y | -| main.go:62:7:62:7 | 2 | main.go:62:2:62:2 | definition of y | -| main.go:63:2:63:2 | definition of z | main.go:64:17:64:17 | z | -| main.go:63:7:63:7 | 3 | main.go:63:2:63:2 | definition of z | -| main.go:64:2:64:2 | definition of a | main.go:66:9:66:9 | a | -| main.go:64:7:64:18 | call to min | main.go:64:2:64:2 | definition of a | +| main.go:61:2:61:2 | SSA def(x) | main.go:64:11:64:11 | x | +| main.go:61:7:61:7 | 1 | main.go:61:2:61:2 | SSA def(x) | +| main.go:62:2:62:2 | SSA def(y) | main.go:64:14:64:14 | y | +| main.go:62:7:62:7 | 2 | main.go:62:2:62:2 | SSA def(y) | +| main.go:63:2:63:2 | SSA def(z) | main.go:64:17:64:17 | z | +| main.go:63:7:63:7 | 3 | main.go:63:2:63:2 | SSA def(z) | +| main.go:64:2:64:2 | SSA def(a) | main.go:66:9:66:9 | a | +| main.go:64:7:64:18 | call to min | main.go:64:2:64:2 | SSA def(a) | | main.go:64:11:64:11 | x | main.go:64:7:64:18 | call to min | | main.go:64:11:64:11 | x | main.go:65:11:65:11 | x | | main.go:64:14:64:14 | y | main.go:64:7:64:18 | call to min | | main.go:64:14:64:14 | y | main.go:65:14:65:14 | y | | main.go:64:17:64:17 | z | main.go:64:7:64:18 | call to min | | main.go:64:17:64:17 | z | main.go:65:17:65:17 | z | -| main.go:65:2:65:2 | definition of b | main.go:66:12:66:12 | b | -| main.go:65:7:65:18 | call to max | main.go:65:2:65:2 | definition of b | +| main.go:65:2:65:2 | SSA def(b) | main.go:66:12:66:12 | b | +| main.go:65:7:65:18 | call to max | main.go:65:2:65:2 | SSA def(b) | | main.go:65:11:65:11 | x | main.go:65:7:65:18 | call to max | | main.go:65:14:65:14 | y | main.go:65:7:65:18 | call to max | | main.go:65:17:65:17 | z | main.go:65:7:65:18 | call to max | -| strings.go:8:12:8:12 | argument corresponding to s | strings.go:8:12:8:12 | definition of s | -| strings.go:8:12:8:12 | definition of s | strings.go:9:24:9:24 | s | -| strings.go:9:2:9:3 | definition of s2 | strings.go:11:20:11:21 | s2 | -| strings.go:9:8:9:38 | call to Replace | strings.go:9:2:9:3 | definition of s2 | +| strings.go:8:12:8:12 | SSA def(s) | strings.go:9:24:9:24 | s | +| strings.go:8:12:8:12 | argument corresponding to s | strings.go:8:12:8:12 | SSA def(s) | +| strings.go:9:2:9:3 | SSA def(s2) | strings.go:11:20:11:21 | s2 | +| strings.go:9:8:9:38 | call to Replace | strings.go:9:2:9:3 | SSA def(s2) | | strings.go:9:24:9:24 | s | strings.go:10:27:10:27 | s | -| strings.go:10:2:10:3 | definition of s3 | strings.go:11:24:11:25 | s3 | -| strings.go:10:8:10:42 | call to ReplaceAll | strings.go:10:2:10:3 | definition of s3 | +| strings.go:10:2:10:3 | SSA def(s3) | strings.go:11:24:11:25 | s3 | +| strings.go:10:8:10:42 | call to ReplaceAll | strings.go:10:2:10:3 | SSA def(s3) | | strings.go:11:20:11:21 | s2 | strings.go:11:48:11:49 | s2 | | strings.go:11:24:11:25 | s3 | strings.go:11:67:11:68 | s3 | -| url.go:8:12:8:12 | argument corresponding to b | url.go:8:12:8:12 | definition of b | -| url.go:8:12:8:12 | definition of b | url.go:11:5:11:5 | b | -| url.go:8:20:8:20 | argument corresponding to s | url.go:8:20:8:20 | definition of s | -| url.go:8:20:8:20 | definition of s | url.go:12:46:12:46 | s | -| url.go:8:20:8:20 | definition of s | url.go:14:48:14:48 | s | -| url.go:12:3:12:5 | definition of res | url.go:19:9:19:11 | res | -| url.go:12:3:12:48 | ... = ...[0] | url.go:12:3:12:5 | definition of res | -| url.go:12:3:12:48 | ... = ...[1] | url.go:12:8:12:10 | definition of err | -| url.go:12:8:12:10 | definition of err | url.go:16:5:16:7 | err | -| url.go:14:3:14:5 | definition of res | url.go:19:9:19:11 | res | -| url.go:14:3:14:50 | ... = ...[0] | url.go:14:3:14:5 | definition of res | -| url.go:14:3:14:50 | ... = ...[1] | url.go:14:8:14:10 | definition of err | -| url.go:14:8:14:10 | definition of err | url.go:16:5:16:7 | err | -| url.go:22:12:22:12 | argument corresponding to i | url.go:22:12:22:12 | definition of i | -| url.go:22:12:22:12 | definition of i | url.go:24:5:24:5 | i | -| url.go:22:19:22:19 | argument corresponding to s | url.go:22:19:22:19 | definition of s | -| url.go:22:19:22:19 | definition of s | url.go:23:20:23:20 | s | -| url.go:23:2:23:2 | definition of u | url.go:25:10:25:10 | u | -| url.go:23:2:23:21 | ... := ...[0] | url.go:23:2:23:2 | definition of u | +| url.go:8:12:8:12 | SSA def(b) | url.go:11:5:11:5 | b | +| url.go:8:12:8:12 | argument corresponding to b | url.go:8:12:8:12 | SSA def(b) | +| url.go:8:20:8:20 | SSA def(s) | url.go:12:46:12:46 | s | +| url.go:8:20:8:20 | SSA def(s) | url.go:14:48:14:48 | s | +| url.go:8:20:8:20 | argument corresponding to s | url.go:8:20:8:20 | SSA def(s) | +| url.go:12:3:12:5 | SSA def(res) | url.go:19:9:19:11 | res | +| url.go:12:3:12:48 | ... = ...[0] | url.go:12:3:12:5 | SSA def(res) | +| url.go:12:3:12:48 | ... = ...[1] | url.go:12:8:12:10 | SSA def(err) | +| url.go:12:8:12:10 | SSA def(err) | url.go:16:5:16:7 | err | +| url.go:14:3:14:5 | SSA def(res) | url.go:19:9:19:11 | res | +| url.go:14:3:14:50 | ... = ...[0] | url.go:14:3:14:5 | SSA def(res) | +| url.go:14:3:14:50 | ... = ...[1] | url.go:14:8:14:10 | SSA def(err) | +| url.go:14:8:14:10 | SSA def(err) | url.go:16:5:16:7 | err | +| url.go:22:12:22:12 | SSA def(i) | url.go:24:5:24:5 | i | +| url.go:22:12:22:12 | argument corresponding to i | url.go:22:12:22:12 | SSA def(i) | +| url.go:22:19:22:19 | SSA def(s) | url.go:23:20:23:20 | s | +| url.go:22:19:22:19 | argument corresponding to s | url.go:22:19:22:19 | SSA def(s) | +| url.go:23:2:23:2 | SSA def(u) | url.go:25:10:25:10 | u | +| url.go:23:2:23:21 | ... := ...[0] | url.go:23:2:23:2 | SSA def(u) | | url.go:23:20:23:20 | s | url.go:27:29:27:29 | s | -| url.go:27:2:27:2 | definition of u | url.go:28:14:28:14 | u | -| url.go:27:2:27:30 | ... = ...[0] | url.go:27:2:27:2 | definition of u | +| url.go:27:2:27:2 | SSA def(u) | url.go:28:14:28:14 | u | +| url.go:27:2:27:30 | ... = ...[0] | url.go:27:2:27:2 | SSA def(u) | | url.go:28:14:28:14 | u | url.go:29:14:29:14 | u | | url.go:28:14:28:14 | u [postupdate] | url.go:29:14:29:14 | u | | url.go:29:14:29:14 | u | url.go:30:11:30:11 | u | | url.go:29:14:29:14 | u [postupdate] | url.go:30:11:30:11 | u | -| url.go:30:2:30:3 | definition of bs | url.go:31:14:31:15 | bs | -| url.go:30:2:30:27 | ... := ...[0] | url.go:30:2:30:3 | definition of bs | +| url.go:30:2:30:3 | SSA def(bs) | url.go:31:14:31:15 | bs | +| url.go:30:2:30:27 | ... := ...[0] | url.go:30:2:30:3 | SSA def(bs) | | url.go:30:11:30:11 | u | url.go:32:9:32:9 | u | | url.go:30:11:30:11 | u [postupdate] | url.go:32:9:32:9 | u | -| url.go:32:2:32:2 | definition of u | url.go:33:14:33:14 | u | -| url.go:32:2:32:23 | ... = ...[0] | url.go:32:2:32:2 | definition of u | +| url.go:32:2:32:2 | SSA def(u) | url.go:33:14:33:14 | u | +| url.go:32:2:32:23 | ... = ...[0] | url.go:32:2:32:2 | SSA def(u) | | url.go:33:14:33:14 | u | url.go:34:14:34:14 | u | | url.go:33:14:33:14 | u [postupdate] | url.go:34:14:34:14 | u | | url.go:34:14:34:14 | u | url.go:35:14:35:14 | u | | url.go:34:14:34:14 | u [postupdate] | url.go:35:14:35:14 | u | | url.go:35:14:35:14 | u | url.go:36:6:36:6 | u | | url.go:35:14:35:14 | u [postupdate] | url.go:36:6:36:6 | u | -| url.go:36:2:36:2 | definition of u | url.go:37:9:37:9 | u | +| url.go:36:2:36:2 | SSA def(u) | url.go:37:9:37:9 | u | | url.go:36:6:36:6 | u | url.go:36:25:36:25 | u | | url.go:36:6:36:6 | u [postupdate] | url.go:36:25:36:25 | u | -| url.go:36:6:36:26 | call to ResolveReference | url.go:36:2:36:2 | definition of u | -| url.go:42:2:42:3 | definition of ui | url.go:43:11:43:12 | ui | -| url.go:42:7:42:38 | call to UserPassword | url.go:42:2:42:3 | definition of ui | -| url.go:43:2:43:3 | definition of pw | url.go:44:14:44:15 | pw | -| url.go:43:2:43:23 | ... := ...[0] | url.go:43:2:43:3 | definition of pw | +| url.go:36:6:36:26 | call to ResolveReference | url.go:36:2:36:2 | SSA def(u) | +| url.go:42:2:42:3 | SSA def(ui) | url.go:43:11:43:12 | ui | +| url.go:42:7:42:38 | call to UserPassword | url.go:42:2:42:3 | SSA def(ui) | +| url.go:43:2:43:3 | SSA def(pw) | url.go:44:14:44:15 | pw | +| url.go:43:2:43:23 | ... := ...[0] | url.go:43:2:43:3 | SSA def(pw) | | url.go:43:11:43:12 | ui | url.go:45:14:45:15 | ui | | url.go:43:11:43:12 | ui [postupdate] | url.go:45:14:45:15 | ui | | url.go:45:14:45:15 | ui | url.go:46:9:46:10 | ui | | url.go:45:14:45:15 | ui [postupdate] | url.go:46:9:46:10 | ui | -| url.go:49:12:49:12 | argument corresponding to q | url.go:49:12:49:12 | definition of q | -| url.go:49:12:49:12 | definition of q | url.go:50:25:50:25 | q | -| url.go:50:2:50:2 | definition of v | url.go:51:14:51:14 | v | -| url.go:50:2:50:26 | ... := ...[0] | url.go:50:2:50:2 | definition of v | +| url.go:49:12:49:12 | SSA def(q) | url.go:50:25:50:25 | q | +| url.go:49:12:49:12 | argument corresponding to q | url.go:49:12:49:12 | SSA def(q) | +| url.go:50:2:50:2 | SSA def(v) | url.go:51:14:51:14 | v | +| url.go:50:2:50:26 | ... := ...[0] | url.go:50:2:50:2 | SSA def(v) | | url.go:51:14:51:14 | v | url.go:52:14:52:14 | v | | url.go:51:14:51:14 | v [postupdate] | url.go:52:14:52:14 | v | | url.go:52:14:52:14 | v | url.go:53:9:53:9 | v | | url.go:52:14:52:14 | v [postupdate] | url.go:53:9:53:9 | v | -| url.go:56:12:56:12 | argument corresponding to q | url.go:56:12:56:12 | definition of q | -| url.go:56:12:56:12 | definition of q | url.go:57:29:57:29 | q | -| url.go:57:2:57:8 | definition of joined1 | url.go:58:38:58:44 | joined1 | -| url.go:57:2:57:39 | ... := ...[0] | url.go:57:2:57:8 | definition of joined1 | -| url.go:58:2:58:8 | definition of joined2 | url.go:59:24:59:30 | joined2 | -| url.go:58:2:58:45 | ... := ...[0] | url.go:58:2:58:8 | definition of joined2 | -| url.go:59:2:59:6 | definition of asUrl | url.go:60:15:60:19 | asUrl | -| url.go:59:2:59:31 | ... := ...[0] | url.go:59:2:59:6 | definition of asUrl | -| url.go:60:2:60:10 | definition of joinedUrl | url.go:61:9:61:17 | joinedUrl | -| url.go:60:15:60:37 | call to JoinPath | url.go:60:2:60:10 | definition of joinedUrl | -| url.go:64:13:64:13 | argument corresponding to q | url.go:64:13:64:13 | definition of q | -| url.go:64:13:64:13 | definition of q | url.go:66:27:66:27 | q | -| url.go:65:2:65:9 | definition of cleanUrl | url.go:66:9:66:16 | cleanUrl | -| url.go:65:2:65:48 | ... := ...[0] | url.go:65:2:65:9 | definition of cleanUrl | +| url.go:56:12:56:12 | SSA def(q) | url.go:57:29:57:29 | q | +| url.go:56:12:56:12 | argument corresponding to q | url.go:56:12:56:12 | SSA def(q) | +| url.go:57:2:57:8 | SSA def(joined1) | url.go:58:38:58:44 | joined1 | +| url.go:57:2:57:39 | ... := ...[0] | url.go:57:2:57:8 | SSA def(joined1) | +| url.go:58:2:58:8 | SSA def(joined2) | url.go:59:24:59:30 | joined2 | +| url.go:58:2:58:45 | ... := ...[0] | url.go:58:2:58:8 | SSA def(joined2) | +| url.go:59:2:59:6 | SSA def(asUrl) | url.go:60:15:60:19 | asUrl | +| url.go:59:2:59:31 | ... := ...[0] | url.go:59:2:59:6 | SSA def(asUrl) | +| url.go:60:2:60:10 | SSA def(joinedUrl) | url.go:61:9:61:17 | joinedUrl | +| url.go:60:15:60:37 | call to JoinPath | url.go:60:2:60:10 | SSA def(joinedUrl) | +| url.go:64:13:64:13 | SSA def(q) | url.go:66:27:66:27 | q | +| url.go:64:13:64:13 | argument corresponding to q | url.go:64:13:64:13 | SSA def(q) | +| url.go:65:2:65:9 | SSA def(cleanUrl) | url.go:66:9:66:16 | cleanUrl | +| url.go:65:2:65:48 | ... := ...[0] | url.go:65:2:65:9 | SSA def(cleanUrl) | diff --git a/go/ql/test/library-tests/semmle/go/dataflow/FunctionInputsAndOutputs/FunctionInput_getEntryNode.expected b/go/ql/test/library-tests/semmle/go/dataflow/FunctionInputsAndOutputs/FunctionInput_getEntryNode.expected index 8c3a2b043dc..a64298b6444 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/FunctionInputsAndOutputs/FunctionInput_getEntryNode.expected +++ b/go/ql/test/library-tests/semmle/go/dataflow/FunctionInputsAndOutputs/FunctionInput_getEntryNode.expected @@ -25,15 +25,15 @@ | result | main.go:53:2:53:22 | call to op2 | main.go:53:2:53:22 | call to op2 | | result | main.go:53:14:53:21 | call to bump | main.go:53:14:53:21 | call to bump | | result | tst2.go:10:9:10:26 | call to NewEncoder | tst2.go:10:9:10:26 | call to NewEncoder | -| result | tst2.go:10:9:10:39 | call to Encode | tst2.go:10:2:10:4 | definition of err | -| result | tst.go:9:17:9:33 | call to new | tst.go:9:2:9:12 | definition of bytesBuffer | +| result | tst2.go:10:9:10:39 | call to Encode | tst2.go:10:2:10:4 | SSA def(err) | +| result | tst.go:9:17:9:33 | call to new | tst.go:9:2:9:12 | SSA def(bytesBuffer) | | result 0 | main.go:51:2:51:14 | call to op | main.go:51:2:51:14 | call to op | | result 0 | main.go:53:2:53:22 | call to op2 | main.go:53:2:53:22 | call to op2 | | result 0 | main.go:53:14:53:21 | call to bump | main.go:53:14:53:21 | call to bump | -| result 0 | main.go:54:10:54:15 | call to test | main.go:54:2:54:2 | definition of x | -| result 0 | main.go:56:9:56:15 | call to test2 | main.go:56:2:56:2 | definition of x | +| result 0 | main.go:54:10:54:15 | call to test | main.go:54:2:54:2 | SSA def(x) | +| result 0 | main.go:56:9:56:15 | call to test2 | main.go:56:2:56:2 | SSA def(x) | | result 0 | tst2.go:10:9:10:26 | call to NewEncoder | tst2.go:10:9:10:26 | call to NewEncoder | -| result 0 | tst2.go:10:9:10:39 | call to Encode | tst2.go:10:2:10:4 | definition of err | -| result 0 | tst.go:9:17:9:33 | call to new | tst.go:9:2:9:12 | definition of bytesBuffer | -| result 1 | main.go:54:10:54:15 | call to test | main.go:54:5:54:5 | definition of y | -| result 1 | main.go:56:9:56:15 | call to test2 | main.go:56:5:56:5 | definition of y | +| result 0 | tst2.go:10:9:10:39 | call to Encode | tst2.go:10:2:10:4 | SSA def(err) | +| result 0 | tst.go:9:17:9:33 | call to new | tst.go:9:2:9:12 | SSA def(bytesBuffer) | +| result 1 | main.go:54:10:54:15 | call to test | main.go:54:5:54:5 | SSA def(y) | +| result 1 | main.go:56:9:56:15 | call to test2 | main.go:56:5:56:5 | SSA def(y) | diff --git a/go/ql/test/library-tests/semmle/go/dataflow/FunctionInputsAndOutputs/FunctionInput_getExitNode.expected b/go/ql/test/library-tests/semmle/go/dataflow/FunctionInputsAndOutputs/FunctionInput_getExitNode.expected index b9878f7e169..b101ce537fc 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/FunctionInputsAndOutputs/FunctionInput_getExitNode.expected +++ b/go/ql/test/library-tests/semmle/go/dataflow/FunctionInputsAndOutputs/FunctionInput_getExitNode.expected @@ -1,14 +1,14 @@ -| parameter 0 | main.go:5:1:11:1 | function declaration | main.go:5:9:5:10 | definition of op | -| parameter 0 | main.go:13:1:20:1 | function declaration | main.go:13:10:13:11 | definition of op | -| parameter 0 | main.go:40:1:48:1 | function declaration | main.go:40:12:40:12 | definition of b | -| parameter 0 | reset.go:8:1:16:1 | function declaration | reset.go:8:27:8:27 | definition of r | -| parameter 0 | tst2.go:8:1:12:1 | function declaration | tst2.go:8:12:8:15 | definition of data | -| parameter 0 | tst.go:8:1:11:1 | function declaration | tst.go:8:12:8:17 | definition of reader | +| parameter 0 | main.go:5:1:11:1 | function declaration | main.go:5:9:5:10 | SSA def(op) | +| parameter 0 | main.go:13:1:20:1 | function declaration | main.go:13:10:13:11 | SSA def(op) | +| parameter 0 | main.go:40:1:48:1 | function declaration | main.go:40:12:40:12 | SSA def(b) | +| parameter 0 | reset.go:8:1:16:1 | function declaration | reset.go:8:27:8:27 | SSA def(r) | +| parameter 0 | tst2.go:8:1:12:1 | function declaration | tst2.go:8:12:8:15 | SSA def(data) | +| parameter 0 | tst.go:8:1:11:1 | function declaration | tst.go:8:12:8:17 | SSA def(reader) | | parameter 0 | tst.go:13:1:13:25 | function declaration | tst.go:13:12:13:13 | initialization of xs | -| parameter 0 | tst.go:15:1:19:1 | function declaration | tst.go:15:12:15:12 | definition of x | -| parameter 1 | main.go:5:1:11:1 | function declaration | main.go:5:20:5:20 | definition of x | -| parameter 1 | main.go:13:1:20:1 | function declaration | main.go:13:21:13:21 | definition of x | -| parameter 1 | tst.go:15:1:19:1 | function declaration | tst.go:15:15:15:15 | definition of y | -| parameter 2 | main.go:5:1:11:1 | function declaration | main.go:5:27:5:27 | definition of y | -| parameter 2 | main.go:13:1:20:1 | function declaration | main.go:13:28:13:28 | definition of y | -| receiver | main.go:26:1:29:1 | function declaration | main.go:26:7:26:7 | definition of c | +| parameter 0 | tst.go:15:1:19:1 | function declaration | tst.go:15:12:15:12 | SSA def(x) | +| parameter 1 | main.go:5:1:11:1 | function declaration | main.go:5:20:5:20 | SSA def(x) | +| parameter 1 | main.go:13:1:20:1 | function declaration | main.go:13:21:13:21 | SSA def(x) | +| parameter 1 | tst.go:15:1:19:1 | function declaration | tst.go:15:15:15:15 | SSA def(y) | +| parameter 2 | main.go:5:1:11:1 | function declaration | main.go:5:27:5:27 | SSA def(y) | +| parameter 2 | main.go:13:1:20:1 | function declaration | main.go:13:28:13:28 | SSA def(y) | +| receiver | main.go:26:1:29:1 | function declaration | main.go:26:7:26:7 | SSA def(c) | diff --git a/go/ql/test/library-tests/semmle/go/dataflow/GlobalValueNumbering/GlobalValueNumber.expected b/go/ql/test/library-tests/semmle/go/dataflow/GlobalValueNumbering/GlobalValueNumber.expected index 93b3593ec94..287a7f735f2 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/GlobalValueNumbering/GlobalValueNumber.expected +++ b/go/ql/test/library-tests/semmle/go/dataflow/GlobalValueNumbering/GlobalValueNumber.expected @@ -1,18 +1,18 @@ | main.go:6:2:6:5 | 1 | main.go:14:7:14:7 | 1 | -| main.go:10:2:10:2 | definition of x | main.go:10:7:10:7 | 0 | +| main.go:10:2:10:2 | SSA def(x) | main.go:10:7:10:7 | 0 | | main.go:10:7:10:7 | 0 | main.go:10:7:10:7 | 0 | -| main.go:11:6:11:6 | definition of y | main.go:10:7:10:7 | 0 | +| main.go:11:6:11:6 | SSA def(y) | main.go:10:7:10:7 | 0 | | main.go:11:6:11:6 | zero value for y | main.go:10:7:10:7 | 0 | | main.go:12:2:12:18 | call to Println | main.go:12:2:12:18 | call to Println | | main.go:12:14:12:14 | x | main.go:10:7:10:7 | 0 | | main.go:12:17:12:17 | y | main.go:10:7:10:7 | 0 | -| main.go:14:2:14:2 | definition of z | main.go:14:7:14:7 | 1 | +| main.go:14:2:14:2 | SSA def(z) | main.go:14:7:14:7 | 1 | | main.go:14:7:14:7 | 1 | main.go:14:7:14:7 | 1 | | main.go:15:2:15:9 | call to bump | main.go:15:2:15:9 | call to bump | | main.go:16:2:16:21 | call to Println | main.go:16:2:16:21 | call to Println | | main.go:16:14:16:14 | x | main.go:10:7:10:7 | 0 | | main.go:16:17:16:17 | y | main.go:10:7:10:7 | 0 | -| main.go:18:2:18:3 | definition of ss | main.go:18:8:18:24 | call to make | +| main.go:18:2:18:3 | SSA def(ss) | main.go:18:8:18:24 | call to make | | main.go:18:8:18:24 | call to make | main.go:18:8:18:24 | call to make | | main.go:18:23:18:23 | 3 | main.go:18:23:18:23 | 3 | | main.go:19:5:19:5 | 2 | main.go:19:5:19:5 | 2 | @@ -20,22 +20,20 @@ | main.go:20:2:20:16 | call to Println | main.go:20:2:20:16 | call to Println | | main.go:23:14:23:16 | implicit read of res | main.go:24:8:24:8 | 4 | | main.go:23:14:23:16 | zero value for res | main.go:10:7:10:7 | 0 | -| main.go:24:2:24:4 | definition of res | main.go:24:8:24:8 | 4 | +| main.go:24:2:24:4 | SSA def(res) | main.go:24:8:24:8 | 4 | | main.go:24:8:24:8 | 4 | main.go:24:8:24:8 | 4 | | main.go:28:15:28:17 | implicit read of res | main.go:30:9:30:9 | 6 | | main.go:28:15:28:17 | zero value for res | main.go:10:7:10:7 | 0 | | main.go:29:8:29:8 | 5 | main.go:29:8:29:8 | 5 | | main.go:30:9:30:9 | 6 | main.go:30:9:30:9 | 6 | -| main.go:30:9:30:9 | definition of res | main.go:30:9:30:9 | 6 | -| main.go:33:15:33:17 | definition of res | main.go:10:7:10:7 | 0 | +| main.go:30:9:30:9 | SSA def(res) | main.go:30:9:30:9 | 6 | | main.go:33:15:33:17 | zero value for res | main.go:10:7:10:7 | 0 | -| main.go:34:2:34:4 | definition of res | main.go:34:8:34:8 | 7 | | main.go:34:8:34:8 | 7 | main.go:34:8:34:8 | 7 | | main.go:35:8:37:4 | function call | main.go:35:8:37:4 | function call | -| main.go:36:3:36:5 | definition of res | main.go:36:9:36:9 | 8 | +| main.go:36:3:36:5 | SSA def(res) | main.go:36:9:36:9 | 8 | | main.go:36:9:36:9 | 8 | main.go:36:9:36:9 | 8 | | main.go:38:9:38:9 | 9 | main.go:38:9:38:9 | 9 | -| main.go:38:9:38:9 | definition of res | main.go:38:9:38:9 | 9 | +| main.go:38:9:38:9 | SSA def(res) | main.go:38:9:38:9 | 9 | | regressions.go:5:11:5:31 | call to Sizeof | regressions.go:5:11:5:31 | call to Sizeof | | regressions.go:7:11:7:15 | false | regressions.go:7:11:7:15 | false | | regressions.go:9:11:9:12 | !... | regressions.go:11:11:11:14 | true | diff --git a/go/ql/test/library-tests/semmle/go/dataflow/PromotedFields/LocalFlowStep.expected b/go/ql/test/library-tests/semmle/go/dataflow/PromotedFields/LocalFlowStep.expected index 3767cd57b5d..950a3a5ae98 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/PromotedFields/LocalFlowStep.expected +++ b/go/ql/test/library-tests/semmle/go/dataflow/PromotedFields/LocalFlowStep.expected @@ -1,132 +1,132 @@ -| main.go:22:2:22:6 | definition of outer | main.go:25:7:25:11 | outer | -| main.go:22:11:24:2 | struct literal | main.go:22:2:22:6 | definition of outer | -| main.go:22:11:24:2 | struct literal [postupdate] | main.go:22:2:22:6 | definition of outer | +| main.go:22:2:22:6 | SSA def(outer) | main.go:25:7:25:11 | outer | +| main.go:22:11:24:2 | struct literal | main.go:22:2:22:6 | SSA def(outer) | +| main.go:22:11:24:2 | struct literal [postupdate] | main.go:22:2:22:6 | SSA def(outer) | | main.go:25:7:25:11 | outer | main.go:26:7:26:11 | outer | | main.go:26:7:26:11 | outer | main.go:27:7:27:11 | outer | | main.go:27:7:27:11 | outer | main.go:28:7:28:11 | outer | -| main.go:30:2:30:7 | definition of outerp | main.go:33:7:33:12 | outerp | -| main.go:30:12:32:2 | &... | main.go:30:2:30:7 | definition of outerp | -| main.go:30:12:32:2 | &... [postupdate] | main.go:30:2:30:7 | definition of outerp | +| main.go:30:2:30:7 | SSA def(outerp) | main.go:33:7:33:12 | outerp | +| main.go:30:12:32:2 | &... | main.go:30:2:30:7 | SSA def(outerp) | +| main.go:30:12:32:2 | &... [postupdate] | main.go:30:2:30:7 | SSA def(outerp) | | main.go:33:7:33:12 | outerp | main.go:34:7:34:12 | outerp | | main.go:33:7:33:12 | outerp [postupdate] | main.go:34:7:34:12 | outerp | | main.go:34:7:34:12 | outerp | main.go:35:7:35:12 | outerp | | main.go:34:7:34:12 | outerp [postupdate] | main.go:35:7:35:12 | outerp | | main.go:35:7:35:12 | outerp | main.go:36:7:36:12 | outerp | | main.go:35:7:35:12 | outerp [postupdate] | main.go:36:7:36:12 | outerp | -| main.go:40:2:40:6 | definition of outer | main.go:41:7:41:11 | outer | -| main.go:40:11:40:40 | struct literal | main.go:40:2:40:6 | definition of outer | -| main.go:40:11:40:40 | struct literal [postupdate] | main.go:40:2:40:6 | definition of outer | +| main.go:40:2:40:6 | SSA def(outer) | main.go:41:7:41:11 | outer | +| main.go:40:11:40:40 | struct literal | main.go:40:2:40:6 | SSA def(outer) | +| main.go:40:11:40:40 | struct literal [postupdate] | main.go:40:2:40:6 | SSA def(outer) | | main.go:41:7:41:11 | outer | main.go:42:7:42:11 | outer | | main.go:42:7:42:11 | outer | main.go:43:7:43:11 | outer | | main.go:43:7:43:11 | outer | main.go:44:7:44:11 | outer | -| main.go:46:2:46:7 | definition of outerp | main.go:47:7:47:12 | outerp | -| main.go:46:12:46:42 | &... | main.go:46:2:46:7 | definition of outerp | -| main.go:46:12:46:42 | &... [postupdate] | main.go:46:2:46:7 | definition of outerp | +| main.go:46:2:46:7 | SSA def(outerp) | main.go:47:7:47:12 | outerp | +| main.go:46:12:46:42 | &... | main.go:46:2:46:7 | SSA def(outerp) | +| main.go:46:12:46:42 | &... [postupdate] | main.go:46:2:46:7 | SSA def(outerp) | | main.go:47:7:47:12 | outerp | main.go:48:7:48:12 | outerp | | main.go:47:7:47:12 | outerp [postupdate] | main.go:48:7:48:12 | outerp | | main.go:48:7:48:12 | outerp | main.go:49:7:49:12 | outerp | | main.go:48:7:48:12 | outerp [postupdate] | main.go:49:7:49:12 | outerp | | main.go:49:7:49:12 | outerp | main.go:50:7:50:12 | outerp | | main.go:49:7:49:12 | outerp [postupdate] | main.go:50:7:50:12 | outerp | -| main.go:54:2:54:6 | definition of inner | main.go:55:19:55:23 | inner | -| main.go:54:11:54:25 | struct literal | main.go:54:2:54:6 | definition of inner | -| main.go:54:11:54:25 | struct literal [postupdate] | main.go:54:2:54:6 | definition of inner | -| main.go:55:2:55:7 | definition of middle | main.go:56:17:56:22 | middle | -| main.go:55:12:55:24 | struct literal | main.go:55:2:55:7 | definition of middle | -| main.go:55:12:55:24 | struct literal [postupdate] | main.go:55:2:55:7 | definition of middle | -| main.go:56:2:56:6 | definition of outer | main.go:57:7:57:11 | outer | -| main.go:56:11:56:23 | struct literal | main.go:56:2:56:6 | definition of outer | -| main.go:56:11:56:23 | struct literal [postupdate] | main.go:56:2:56:6 | definition of outer | +| main.go:54:2:54:6 | SSA def(inner) | main.go:55:19:55:23 | inner | +| main.go:54:11:54:25 | struct literal | main.go:54:2:54:6 | SSA def(inner) | +| main.go:54:11:54:25 | struct literal [postupdate] | main.go:54:2:54:6 | SSA def(inner) | +| main.go:55:2:55:7 | SSA def(middle) | main.go:56:17:56:22 | middle | +| main.go:55:12:55:24 | struct literal | main.go:55:2:55:7 | SSA def(middle) | +| main.go:55:12:55:24 | struct literal [postupdate] | main.go:55:2:55:7 | SSA def(middle) | +| main.go:56:2:56:6 | SSA def(outer) | main.go:57:7:57:11 | outer | +| main.go:56:11:56:23 | struct literal | main.go:56:2:56:6 | SSA def(outer) | +| main.go:56:11:56:23 | struct literal [postupdate] | main.go:56:2:56:6 | SSA def(outer) | | main.go:57:7:57:11 | outer | main.go:58:7:58:11 | outer | | main.go:58:7:58:11 | outer | main.go:59:7:59:11 | outer | | main.go:59:7:59:11 | outer | main.go:60:7:60:11 | outer | -| main.go:62:2:62:7 | definition of innerp | main.go:63:20:63:25 | innerp | -| main.go:62:12:62:26 | struct literal | main.go:62:2:62:7 | definition of innerp | -| main.go:62:12:62:26 | struct literal [postupdate] | main.go:62:2:62:7 | definition of innerp | -| main.go:63:2:63:8 | definition of middlep | main.go:64:18:64:24 | middlep | -| main.go:63:13:63:26 | struct literal | main.go:63:2:63:8 | definition of middlep | -| main.go:63:13:63:26 | struct literal [postupdate] | main.go:63:2:63:8 | definition of middlep | -| main.go:64:2:64:7 | definition of outerp | main.go:65:7:65:12 | outerp | -| main.go:64:12:64:25 | struct literal | main.go:64:2:64:7 | definition of outerp | -| main.go:64:12:64:25 | struct literal [postupdate] | main.go:64:2:64:7 | definition of outerp | +| main.go:62:2:62:7 | SSA def(innerp) | main.go:63:20:63:25 | innerp | +| main.go:62:12:62:26 | struct literal | main.go:62:2:62:7 | SSA def(innerp) | +| main.go:62:12:62:26 | struct literal [postupdate] | main.go:62:2:62:7 | SSA def(innerp) | +| main.go:63:2:63:8 | SSA def(middlep) | main.go:64:18:64:24 | middlep | +| main.go:63:13:63:26 | struct literal | main.go:63:2:63:8 | SSA def(middlep) | +| main.go:63:13:63:26 | struct literal [postupdate] | main.go:63:2:63:8 | SSA def(middlep) | +| main.go:64:2:64:7 | SSA def(outerp) | main.go:65:7:65:12 | outerp | +| main.go:64:12:64:25 | struct literal | main.go:64:2:64:7 | SSA def(outerp) | +| main.go:64:12:64:25 | struct literal [postupdate] | main.go:64:2:64:7 | SSA def(outerp) | | main.go:65:7:65:12 | outerp | main.go:66:7:66:12 | outerp | | main.go:66:7:66:12 | outerp | main.go:67:7:67:12 | outerp | | main.go:67:7:67:12 | outerp | main.go:68:7:68:12 | outerp | -| main.go:72:2:72:6 | definition of inner | main.go:73:26:73:30 | inner | -| main.go:72:11:72:25 | struct literal | main.go:72:2:72:6 | definition of inner | -| main.go:72:11:72:25 | struct literal [postupdate] | main.go:72:2:72:6 | definition of inner | -| main.go:73:2:73:7 | definition of middle | main.go:74:25:74:30 | middle | -| main.go:73:12:73:31 | struct literal | main.go:73:2:73:7 | definition of middle | -| main.go:73:12:73:31 | struct literal [postupdate] | main.go:73:2:73:7 | definition of middle | -| main.go:74:2:74:6 | definition of outer | main.go:75:7:75:11 | outer | -| main.go:74:11:74:31 | struct literal | main.go:74:2:74:6 | definition of outer | -| main.go:74:11:74:31 | struct literal [postupdate] | main.go:74:2:74:6 | definition of outer | +| main.go:72:2:72:6 | SSA def(inner) | main.go:73:26:73:30 | inner | +| main.go:72:11:72:25 | struct literal | main.go:72:2:72:6 | SSA def(inner) | +| main.go:72:11:72:25 | struct literal [postupdate] | main.go:72:2:72:6 | SSA def(inner) | +| main.go:73:2:73:7 | SSA def(middle) | main.go:74:25:74:30 | middle | +| main.go:73:12:73:31 | struct literal | main.go:73:2:73:7 | SSA def(middle) | +| main.go:73:12:73:31 | struct literal [postupdate] | main.go:73:2:73:7 | SSA def(middle) | +| main.go:74:2:74:6 | SSA def(outer) | main.go:75:7:75:11 | outer | +| main.go:74:11:74:31 | struct literal | main.go:74:2:74:6 | SSA def(outer) | +| main.go:74:11:74:31 | struct literal [postupdate] | main.go:74:2:74:6 | SSA def(outer) | | main.go:75:7:75:11 | outer | main.go:76:7:76:11 | outer | | main.go:76:7:76:11 | outer | main.go:77:7:77:11 | outer | | main.go:77:7:77:11 | outer | main.go:78:7:78:11 | outer | -| main.go:80:2:80:7 | definition of innerp | main.go:81:27:81:32 | innerp | -| main.go:80:12:80:26 | struct literal | main.go:80:2:80:7 | definition of innerp | -| main.go:80:12:80:26 | struct literal [postupdate] | main.go:80:2:80:7 | definition of innerp | -| main.go:81:2:81:8 | definition of middlep | main.go:82:26:82:32 | middlep | -| main.go:81:13:81:33 | struct literal | main.go:81:2:81:8 | definition of middlep | -| main.go:81:13:81:33 | struct literal [postupdate] | main.go:81:2:81:8 | definition of middlep | -| main.go:82:2:82:7 | definition of outerp | main.go:83:7:83:12 | outerp | -| main.go:82:12:82:33 | struct literal | main.go:82:2:82:7 | definition of outerp | -| main.go:82:12:82:33 | struct literal [postupdate] | main.go:82:2:82:7 | definition of outerp | +| main.go:80:2:80:7 | SSA def(innerp) | main.go:81:27:81:32 | innerp | +| main.go:80:12:80:26 | struct literal | main.go:80:2:80:7 | SSA def(innerp) | +| main.go:80:12:80:26 | struct literal [postupdate] | main.go:80:2:80:7 | SSA def(innerp) | +| main.go:81:2:81:8 | SSA def(middlep) | main.go:82:26:82:32 | middlep | +| main.go:81:13:81:33 | struct literal | main.go:81:2:81:8 | SSA def(middlep) | +| main.go:81:13:81:33 | struct literal [postupdate] | main.go:81:2:81:8 | SSA def(middlep) | +| main.go:82:2:82:7 | SSA def(outerp) | main.go:83:7:83:12 | outerp | +| main.go:82:12:82:33 | struct literal | main.go:82:2:82:7 | SSA def(outerp) | +| main.go:82:12:82:33 | struct literal [postupdate] | main.go:82:2:82:7 | SSA def(outerp) | | main.go:83:7:83:12 | outerp | main.go:84:7:84:12 | outerp | | main.go:84:7:84:12 | outerp | main.go:85:7:85:12 | outerp | | main.go:85:7:85:12 | outerp | main.go:86:7:86:12 | outerp | -| main.go:90:6:90:10 | definition of outer | main.go:91:2:91:6 | outer | -| main.go:90:6:90:10 | zero value for outer | main.go:90:6:90:10 | definition of outer | +| main.go:90:6:90:10 | SSA def(outer) | main.go:91:2:91:6 | outer | +| main.go:90:6:90:10 | zero value for outer | main.go:90:6:90:10 | SSA def(outer) | | main.go:91:2:91:6 | outer | main.go:92:7:92:11 | outer | | main.go:91:2:91:6 | outer [postupdate] | main.go:92:7:92:11 | outer | | main.go:92:7:92:11 | outer | main.go:93:7:93:11 | outer | | main.go:93:7:93:11 | outer | main.go:94:7:94:11 | outer | | main.go:94:7:94:11 | outer | main.go:95:7:95:11 | outer | -| main.go:97:6:97:11 | definition of outerp | main.go:98:2:98:7 | outerp | -| main.go:97:6:97:11 | zero value for outerp | main.go:97:6:97:11 | definition of outerp | +| main.go:97:6:97:11 | SSA def(outerp) | main.go:98:2:98:7 | outerp | +| main.go:97:6:97:11 | zero value for outerp | main.go:97:6:97:11 | SSA def(outerp) | | main.go:98:2:98:7 | outerp | main.go:99:7:99:12 | outerp | | main.go:98:2:98:7 | outerp [postupdate] | main.go:99:7:99:12 | outerp | | main.go:99:7:99:12 | outerp | main.go:100:7:100:12 | outerp | | main.go:100:7:100:12 | outerp | main.go:101:7:101:12 | outerp | | main.go:101:7:101:12 | outerp | main.go:102:7:102:12 | outerp | -| main.go:106:6:106:10 | definition of outer | main.go:107:2:107:6 | outer | -| main.go:106:6:106:10 | zero value for outer | main.go:106:6:106:10 | definition of outer | +| main.go:106:6:106:10 | SSA def(outer) | main.go:107:2:107:6 | outer | +| main.go:106:6:106:10 | zero value for outer | main.go:106:6:106:10 | SSA def(outer) | | main.go:107:2:107:6 | outer | main.go:108:7:108:11 | outer | | main.go:107:2:107:6 | outer [postupdate] | main.go:108:7:108:11 | outer | | main.go:108:7:108:11 | outer | main.go:109:7:109:11 | outer | | main.go:109:7:109:11 | outer | main.go:110:7:110:11 | outer | | main.go:110:7:110:11 | outer | main.go:111:7:111:11 | outer | -| main.go:113:6:113:11 | definition of outerp | main.go:114:2:114:7 | outerp | -| main.go:113:6:113:11 | zero value for outerp | main.go:113:6:113:11 | definition of outerp | +| main.go:113:6:113:11 | SSA def(outerp) | main.go:114:2:114:7 | outerp | +| main.go:113:6:113:11 | zero value for outerp | main.go:113:6:113:11 | SSA def(outerp) | | main.go:114:2:114:7 | outerp | main.go:115:7:115:12 | outerp | | main.go:114:2:114:7 | outerp [postupdate] | main.go:115:7:115:12 | outerp | | main.go:115:7:115:12 | outerp | main.go:116:7:116:12 | outerp | | main.go:116:7:116:12 | outerp | main.go:117:7:117:12 | outerp | | main.go:117:7:117:12 | outerp | main.go:118:7:118:12 | outerp | -| main.go:122:6:122:10 | definition of outer | main.go:123:2:123:6 | outer | -| main.go:122:6:122:10 | zero value for outer | main.go:122:6:122:10 | definition of outer | +| main.go:122:6:122:10 | SSA def(outer) | main.go:123:2:123:6 | outer | +| main.go:122:6:122:10 | zero value for outer | main.go:122:6:122:10 | SSA def(outer) | | main.go:123:2:123:6 | outer | main.go:124:7:124:11 | outer | | main.go:123:2:123:6 | outer [postupdate] | main.go:124:7:124:11 | outer | | main.go:124:7:124:11 | outer | main.go:125:7:125:11 | outer | | main.go:125:7:125:11 | outer | main.go:126:7:126:11 | outer | | main.go:126:7:126:11 | outer | main.go:127:7:127:11 | outer | -| main.go:129:6:129:11 | definition of outerp | main.go:130:2:130:7 | outerp | -| main.go:129:6:129:11 | zero value for outerp | main.go:129:6:129:11 | definition of outerp | +| main.go:129:6:129:11 | SSA def(outerp) | main.go:130:2:130:7 | outerp | +| main.go:129:6:129:11 | zero value for outerp | main.go:129:6:129:11 | SSA def(outerp) | | main.go:130:2:130:7 | outerp | main.go:131:7:131:12 | outerp | | main.go:130:2:130:7 | outerp [postupdate] | main.go:131:7:131:12 | outerp | | main.go:131:7:131:12 | outerp | main.go:132:7:132:12 | outerp | | main.go:132:7:132:12 | outerp | main.go:133:7:133:12 | outerp | | main.go:133:7:133:12 | outerp | main.go:134:7:134:12 | outerp | -| main.go:138:6:138:10 | definition of outer | main.go:139:2:139:6 | outer | -| main.go:138:6:138:10 | zero value for outer | main.go:138:6:138:10 | definition of outer | +| main.go:138:6:138:10 | SSA def(outer) | main.go:139:2:139:6 | outer | +| main.go:138:6:138:10 | zero value for outer | main.go:138:6:138:10 | SSA def(outer) | | main.go:139:2:139:6 | outer | main.go:140:7:140:11 | outer | | main.go:139:2:139:6 | outer [postupdate] | main.go:140:7:140:11 | outer | | main.go:140:7:140:11 | outer | main.go:141:7:141:11 | outer | | main.go:141:7:141:11 | outer | main.go:142:7:142:11 | outer | | main.go:142:7:142:11 | outer | main.go:143:7:143:11 | outer | -| main.go:145:6:145:11 | definition of outerp | main.go:146:2:146:7 | outerp | -| main.go:145:6:145:11 | zero value for outerp | main.go:145:6:145:11 | definition of outerp | +| main.go:145:6:145:11 | SSA def(outerp) | main.go:146:2:146:7 | outerp | +| main.go:145:6:145:11 | zero value for outerp | main.go:145:6:145:11 | SSA def(outerp) | | main.go:146:2:146:7 | outerp | main.go:147:7:147:12 | outerp | | main.go:146:2:146:7 | outerp [postupdate] | main.go:147:7:147:12 | outerp | | main.go:147:7:147:12 | outerp | main.go:148:7:148:12 | outerp | diff --git a/go/ql/test/library-tests/semmle/go/dataflow/SSA/CONSISTENCY/DataFlowConsistency.expected b/go/ql/test/library-tests/semmle/go/dataflow/SSA/CONSISTENCY/DataFlowConsistency.expected index b435a5fa62d..3870f4b071b 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/SSA/CONSISTENCY/DataFlowConsistency.expected +++ b/go/ql/test/library-tests/semmle/go/dataflow/SSA/CONSISTENCY/DataFlowConsistency.expected @@ -1,3 +1,5 @@ reverseRead | main.go:97:2:97:8 | wrapper | Origin of readStep is missing a PostUpdateNode. | -| main.go:117:2:117:2 | p | Origin of readStep is missing a PostUpdateNode. | +| main.go:105:2:105:8 | wrapper | Origin of readStep is missing a PostUpdateNode. | +| main.go:114:2:114:8 | wrapper | Origin of readStep is missing a PostUpdateNode. | +| main.go:135:2:135:2 | p | Origin of readStep is missing a PostUpdateNode. | diff --git a/go/ql/test/library-tests/semmle/go/dataflow/SSA/DefUse.expected b/go/ql/test/library-tests/semmle/go/dataflow/SSA/DefUse.expected index aad16b89ab6..775eff4a49e 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/SSA/DefUse.expected +++ b/go/ql/test/library-tests/semmle/go/dataflow/SSA/DefUse.expected @@ -1,34 +1,42 @@ -| main.go:15:12:15:12 | x | main.go:13:6:13:6 | definition of x | main.go:13:6:13:6 | x | -| main.go:15:15:15:15 | y | main.go:14:2:14:2 | definition of y | main.go:14:2:14:2 | y | -| main.go:17:3:17:3 | y | main.go:14:2:14:2 | definition of y | main.go:14:2:14:2 | y | -| main.go:19:12:19:12 | x | main.go:13:6:13:6 | definition of x | main.go:13:6:13:6 | x | -| main.go:19:15:19:15 | y | main.go:19:2:19:10 | y = phi(def@14:2, def@17:3) | main.go:14:2:14:2 | y | -| main.go:21:7:21:7 | y | main.go:19:2:19:10 | y = phi(def@14:2, def@17:3) | main.go:14:2:14:2 | y | -| main.go:23:12:23:12 | x | main.go:23:2:23:10 | x = phi(def@13:6, def@21:3) | main.go:13:6:13:6 | x | -| main.go:23:15:23:15 | y | main.go:19:2:19:10 | y = phi(def@14:2, def@17:3) | main.go:14:2:14:2 | y | -| main.go:27:10:27:10 | x | main.go:26:10:26:10 | definition of x | main.go:26:10:26:10 | x | -| main.go:29:10:29:10 | b | main.go:27:5:27:5 | definition of b | main.go:27:5:27:5 | b | -| main.go:29:13:29:13 | a | main.go:27:2:27:2 | definition of a | main.go:27:2:27:2 | a | -| main.go:31:9:31:9 | a | main.go:31:9:31:9 | a = phi(def@27:2, def@29:3) | main.go:27:2:27:2 | a | -| main.go:31:12:31:12 | b | main.go:31:9:31:9 | b = phi(def@27:5, def@29:6) | main.go:27:5:27:5 | b | -| main.go:35:3:35:3 | x | main.go:34:11:34:11 | definition of x | main.go:34:11:34:11 | x | -| main.go:40:10:40:10 | x | main.go:39:2:39:2 | definition of x | main.go:39:2:39:2 | x | -| main.go:42:8:42:10 | ptr | main.go:40:2:40:4 | definition of ptr | main.go:40:2:40:4 | ptr | -| main.go:44:12:44:12 | x | main.go:39:2:39:2 | definition of x | main.go:39:2:39:2 | x | -| main.go:47:13:47:18 | implicit read of result | main.go:48:2:48:7 | definition of result | main.go:47:13:47:18 | result | -| main.go:52:14:52:19 | implicit read of result | main.go:52:14:52:19 | definition of result | main.go:52:14:52:19 | result | -| main.go:61:12:61:12 | x | main.go:58:6:58:9 | x = phi(def@57:6, def@59:3) | main.go:57:6:57:6 | x | -| main.go:64:16:64:16 | i | main.go:65:6:65:9 | i = phi(def@64:16, def@64:6) | main.go:64:6:64:6 | i | -| main.go:70:12:70:12 | y | main.go:65:6:65:9 | y = phi(def@63:2, def@68:3) | main.go:63:2:63:2 | y | -| main.go:73:16:73:16 | i | main.go:74:3:74:3 | i = phi(def@73:16, def@73:6) | main.go:73:6:73:6 | i | -| main.go:79:12:79:12 | z | main.go:74:3:74:3 | definition of z | main.go:72:2:72:2 | z | -| main.go:82:18:82:18 | implicit read of a | main.go:84:5:84:5 | definition of a | main.go:82:18:82:18 | a | -| main.go:82:25:82:25 | implicit read of b | main.go:82:25:82:25 | definition of b | main.go:82:25:82:25 | b | -| main.go:84:9:84:9 | x | main.go:83:2:83:2 | definition of x | main.go:83:2:83:2 | x | -| main.go:84:15:84:15 | x | main.go:83:2:83:2 | definition of x | main.go:83:2:83:2 | x | -| main.go:97:2:97:8 | wrapper | main.go:95:22:95:28 | definition of wrapper | main.go:95:22:95:28 | wrapper | -| main.go:100:9:100:9 | x | main.go:97:2:99:3 | capture variable x | main.go:96:2:96:2 | x | -| main.go:117:2:117:2 | p | main.go:117:2:117:2 | p = phi(def@112:3, def@114:3) | main.go:110:6:110:6 | p | -| main.go:119:12:119:12 | p | main.go:117:2:117:2 | p = phi(def@112:3, def@114:3) | main.go:110:6:110:6 | p | -| main.go:119:17:119:17 | p | main.go:117:2:117:2 | p = phi(def@112:3, def@114:3) | main.go:110:6:110:6 | p | -| main.go:119:24:119:24 | p | main.go:117:2:117:2 | p = phi(def@112:3, def@114:3) | main.go:110:6:110:6 | p | +| main.go:15:12:15:12 | x | main.go:13:6:13:6 | SSA def(x) | main.go:13:6:13:6 | x | +| main.go:15:15:15:15 | y | main.go:14:2:14:2 | SSA def(y) | main.go:14:2:14:2 | y | +| main.go:17:3:17:3 | y | main.go:14:2:14:2 | SSA def(y) | main.go:14:2:14:2 | y | +| main.go:19:12:19:12 | x | main.go:13:6:13:6 | SSA def(x) | main.go:13:6:13:6 | x | +| main.go:19:15:19:15 | y | main.go:19:2:19:10 | SSA phi(y) | main.go:14:2:14:2 | y | +| main.go:21:7:21:7 | y | main.go:19:2:19:10 | SSA phi(y) | main.go:14:2:14:2 | y | +| main.go:23:12:23:12 | x | main.go:23:2:23:10 | SSA phi(x) | main.go:13:6:13:6 | x | +| main.go:23:15:23:15 | y | main.go:19:2:19:10 | SSA phi(y) | main.go:14:2:14:2 | y | +| main.go:27:10:27:10 | x | main.go:26:10:26:10 | SSA def(x) | main.go:26:10:26:10 | x | +| main.go:29:10:29:10 | b | main.go:27:5:27:5 | SSA def(b) | main.go:27:5:27:5 | b | +| main.go:29:13:29:13 | a | main.go:27:2:27:2 | SSA def(a) | main.go:27:2:27:2 | a | +| main.go:31:9:31:9 | a | main.go:31:9:31:9 | SSA phi(a) | main.go:27:2:27:2 | a | +| main.go:31:12:31:12 | b | main.go:31:9:31:9 | SSA phi(b) | main.go:27:5:27:5 | b | +| main.go:35:3:35:3 | x | main.go:34:11:34:11 | SSA def(x) | main.go:34:11:34:11 | x | +| main.go:40:10:40:10 | x | main.go:39:2:39:2 | SSA def(x) | main.go:39:2:39:2 | x | +| main.go:42:8:42:10 | ptr | main.go:40:2:40:4 | SSA def(ptr) | main.go:40:2:40:4 | ptr | +| main.go:44:12:44:12 | x | main.go:39:2:39:2 | SSA def(x) | main.go:39:2:39:2 | x | +| main.go:47:13:47:18 | implicit read of result | main.go:48:2:48:7 | SSA def(result) | main.go:47:13:47:18 | result | +| main.go:52:14:52:19 | implicit read of result | main.go:52:14:52:19 | SSA def(result) | main.go:52:14:52:19 | result | +| main.go:61:12:61:12 | x | main.go:58:6:58:9 | SSA phi(x) | main.go:57:6:57:6 | x | +| main.go:64:16:64:16 | i | main.go:65:6:65:9 | SSA phi(i) | main.go:64:6:64:6 | i | +| main.go:70:12:70:12 | y | main.go:65:6:65:9 | SSA phi(y) | main.go:63:2:63:2 | y | +| main.go:73:16:73:16 | i | main.go:74:3:74:3 | SSA phi(i) | main.go:73:6:73:6 | i | +| main.go:79:12:79:12 | z | main.go:74:3:74:3 | SSA def(z) | main.go:72:2:72:2 | z | +| main.go:82:18:82:18 | implicit read of a | main.go:84:5:84:5 | SSA def(a) | main.go:82:18:82:18 | a | +| main.go:82:25:82:25 | implicit read of b | main.go:82:25:82:25 | SSA def(b) | main.go:82:25:82:25 | b | +| main.go:84:9:84:9 | x | main.go:83:2:83:2 | SSA def(x) | main.go:83:2:83:2 | x | +| main.go:84:15:84:15 | x | main.go:83:2:83:2 | SSA def(x) | main.go:83:2:83:2 | x | +| main.go:97:2:97:8 | wrapper | main.go:95:22:95:28 | SSA def(wrapper) | main.go:95:22:95:28 | wrapper | +| main.go:100:9:100:9 | x | main.go:97:2:99:3 | SSA def(x) | main.go:96:2:96:2 | x | +| main.go:105:2:105:8 | wrapper | main.go:103:20:103:26 | SSA def(wrapper) | main.go:103:20:103:26 | wrapper | +| main.go:106:8:106:8 | x | main.go:105:16:108:2 | SSA def(x) | main.go:104:2:104:2 | x | +| main.go:107:7:107:7 | y | main.go:106:3:106:3 | SSA def(y) | main.go:106:3:106:3 | y | +| main.go:109:9:109:9 | x | main.go:104:2:104:2 | SSA def(x) | main.go:104:2:104:2 | x | +| main.go:114:2:114:8 | wrapper | main.go:112:29:112:35 | SSA def(wrapper) | main.go:112:29:112:35 | wrapper | +| main.go:115:8:115:8 | x | main.go:114:16:117:2 | SSA def(x) | main.go:113:2:113:2 | x | +| main.go:116:7:116:7 | y | main.go:115:3:115:3 | SSA def(y) | main.go:115:3:115:3 | y | +| main.go:118:9:118:9 | x | main.go:114:2:117:3 | SSA def(x) | main.go:113:2:113:2 | x | +| main.go:135:2:135:2 | p | main.go:135:2:135:2 | SSA phi(p) | main.go:128:6:128:6 | p | +| main.go:137:12:137:12 | p | main.go:135:2:135:2 | SSA phi(p) | main.go:128:6:128:6 | p | +| main.go:137:17:137:17 | p | main.go:135:2:135:2 | SSA phi(p) | main.go:128:6:128:6 | p | +| main.go:137:24:137:24 | p | main.go:135:2:135:2 | SSA phi(p) | main.go:128:6:128:6 | p | diff --git a/go/ql/test/library-tests/semmle/go/dataflow/SSA/SsaDefinition.expected b/go/ql/test/library-tests/semmle/go/dataflow/SSA/SsaDefinition.expected index bd905b5c2a7..3ff2faf872c 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/SSA/SsaDefinition.expected +++ b/go/ql/test/library-tests/semmle/go/dataflow/SSA/SsaDefinition.expected @@ -1,41 +1,51 @@ -| main.go:13:6:13:6 | definition of x | -| main.go:14:2:14:2 | definition of y | -| main.go:17:3:17:3 | definition of y | -| main.go:19:2:19:10 | y = phi(def@14:2, def@17:3) | -| main.go:21:3:21:3 | definition of x | -| main.go:23:2:23:10 | x = phi(def@13:6, def@21:3) | -| main.go:26:10:26:10 | definition of x | -| main.go:27:2:27:2 | definition of a | -| main.go:27:5:27:5 | definition of b | -| main.go:29:3:29:3 | definition of a | -| main.go:29:6:29:6 | definition of b | -| main.go:31:9:31:9 | a = phi(def@27:2, def@29:3) | -| main.go:31:9:31:9 | b = phi(def@27:5, def@29:6) | -| main.go:34:11:34:11 | definition of x | -| main.go:39:2:39:2 | definition of x | -| main.go:40:2:40:4 | definition of ptr | -| main.go:48:2:48:7 | definition of result | -| main.go:52:14:52:19 | definition of result | -| main.go:57:6:57:6 | definition of x | -| main.go:58:6:58:9 | x = phi(def@57:6, def@59:3) | -| main.go:59:3:59:3 | definition of x | -| main.go:63:2:63:2 | definition of y | -| main.go:64:6:64:6 | definition of i | -| main.go:64:16:64:18 | definition of i | -| main.go:65:6:65:9 | i = phi(def@64:16, def@64:6) | -| main.go:65:6:65:9 | y = phi(def@63:2, def@68:3) | -| main.go:68:3:68:3 | definition of y | -| main.go:73:6:73:6 | definition of i | -| main.go:73:16:73:18 | definition of i | -| main.go:74:3:74:3 | definition of z | -| main.go:74:3:74:3 | i = phi(def@73:16, def@73:6) | -| main.go:82:25:82:25 | definition of b | -| main.go:83:2:83:2 | definition of x | -| main.go:84:5:84:5 | definition of a | -| main.go:95:22:95:28 | definition of wrapper | -| main.go:96:2:96:2 | definition of x | -| main.go:97:2:99:3 | capture variable x | -| main.go:98:3:98:3 | definition of x | -| main.go:112:3:112:3 | definition of p | -| main.go:114:3:114:3 | definition of p | -| main.go:117:2:117:2 | p = phi(def@112:3, def@114:3) | +| main.go:13:6:13:6 | SSA def(x) | +| main.go:14:2:14:2 | SSA def(y) | +| main.go:17:3:17:3 | SSA def(y) | +| main.go:19:2:19:10 | SSA phi(y) | +| main.go:21:3:21:3 | SSA def(x) | +| main.go:23:2:23:10 | SSA phi(x) | +| main.go:26:10:26:10 | SSA def(x) | +| main.go:27:2:27:2 | SSA def(a) | +| main.go:27:5:27:5 | SSA def(b) | +| main.go:29:3:29:3 | SSA def(a) | +| main.go:29:6:29:6 | SSA def(b) | +| main.go:31:9:31:9 | SSA phi(a) | +| main.go:31:9:31:9 | SSA phi(b) | +| main.go:34:11:34:11 | SSA def(x) | +| main.go:39:2:39:2 | SSA def(x) | +| main.go:40:2:40:4 | SSA def(ptr) | +| main.go:48:2:48:7 | SSA def(result) | +| main.go:52:14:52:19 | SSA def(result) | +| main.go:57:6:57:6 | SSA def(x) | +| main.go:58:6:58:9 | SSA phi(x) | +| main.go:59:3:59:3 | SSA def(x) | +| main.go:63:2:63:2 | SSA def(y) | +| main.go:64:6:64:6 | SSA def(i) | +| main.go:64:16:64:18 | SSA def(i) | +| main.go:65:6:65:9 | SSA phi(i) | +| main.go:65:6:65:9 | SSA phi(y) | +| main.go:68:3:68:3 | SSA def(y) | +| main.go:73:6:73:6 | SSA def(i) | +| main.go:73:16:73:18 | SSA def(i) | +| main.go:74:3:74:3 | SSA def(z) | +| main.go:74:3:74:3 | SSA phi(i) | +| main.go:82:25:82:25 | SSA def(b) | +| main.go:83:2:83:2 | SSA def(x) | +| main.go:84:5:84:5 | SSA def(a) | +| main.go:95:22:95:28 | SSA def(wrapper) | +| main.go:96:2:96:2 | SSA def(x) | +| main.go:97:2:99:3 | SSA def(x) | +| main.go:98:3:98:3 | SSA def(x) | +| main.go:103:20:103:26 | SSA def(wrapper) | +| main.go:104:2:104:2 | SSA def(x) | +| main.go:105:16:108:2 | SSA def(x) | +| main.go:106:3:106:3 | SSA def(y) | +| main.go:112:29:112:35 | SSA def(wrapper) | +| main.go:113:2:113:2 | SSA def(x) | +| main.go:114:2:117:3 | SSA def(x) | +| main.go:114:16:117:2 | SSA def(x) | +| main.go:115:3:115:3 | SSA def(y) | +| main.go:116:3:116:3 | SSA def(x) | +| main.go:130:3:130:3 | SSA def(p) | +| main.go:132:3:132:3 | SSA def(p) | +| main.go:135:2:135:2 | SSA phi(p) | diff --git a/go/ql/test/library-tests/semmle/go/dataflow/SSA/SsaWithFields.expected b/go/ql/test/library-tests/semmle/go/dataflow/SSA/SsaWithFields.expected index 245a82acc83..2c43f05257a 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/SSA/SsaWithFields.expected +++ b/go/ql/test/library-tests/semmle/go/dataflow/SSA/SsaWithFields.expected @@ -1,46 +1,58 @@ -| main.go:13:6:13:6 | (def@13:6) | x | -| main.go:14:2:14:2 | (def@14:2) | y | -| main.go:17:3:17:3 | (def@17:3) | y | -| main.go:19:2:19:10 | (phi@19:2) | y | -| main.go:21:3:21:3 | (def@21:3) | x | -| main.go:23:2:23:10 | (phi@23:2) | x | -| main.go:26:10:26:10 | (def@26:10) | x | -| main.go:27:2:27:2 | (def@27:2) | a | -| main.go:27:5:27:5 | (def@27:5) | b | -| main.go:29:3:29:3 | (def@29:3) | a | -| main.go:29:6:29:6 | (def@29:6) | b | -| main.go:31:9:31:9 | (phi@31:9) | a | -| main.go:31:9:31:9 | (phi@31:9) | b | -| main.go:34:11:34:11 | (def@34:11) | x | -| main.go:39:2:39:2 | (def@39:2) | x | -| main.go:40:2:40:4 | (def@40:2) | ptr | -| main.go:48:2:48:7 | (def@48:2) | result | -| main.go:52:14:52:19 | (def@52:14) | result | -| main.go:57:6:57:6 | (def@57:6) | x | -| main.go:58:6:58:9 | (phi@58:6) | x | -| main.go:59:3:59:3 | (def@59:3) | x | -| main.go:63:2:63:2 | (def@63:2) | y | -| main.go:64:6:64:6 | (def@64:6) | i | -| main.go:64:16:64:18 | (def@64:16) | i | -| main.go:65:6:65:9 | (phi@65:6) | i | -| main.go:65:6:65:9 | (phi@65:6) | y | -| main.go:68:3:68:3 | (def@68:3) | y | -| main.go:73:6:73:6 | (def@73:6) | i | -| main.go:73:16:73:18 | (def@73:16) | i | -| main.go:74:3:74:3 | (def@74:3) | z | -| main.go:74:3:74:3 | (phi@74:3) | i | -| main.go:82:25:82:25 | (def@82:25) | b | -| main.go:83:2:83:2 | (def@83:2) | x | -| main.go:84:5:84:5 | (def@84:5) | a | -| main.go:95:22:95:28 | (def@95:22) | wrapper | -| main.go:95:22:95:28 | (def@95:22).s | wrapper.s | -| main.go:96:2:96:2 | (def@96:2) | x | -| main.go:97:2:99:3 | (capture@97:2) | x | -| main.go:98:3:98:3 | (def@98:3) | x | -| main.go:112:3:112:3 | (def@112:3) | p | -| main.go:114:3:114:3 | (def@114:3) | p | -| main.go:117:2:117:2 | (phi@117:2) | p | -| main.go:117:2:117:2 | (phi@117:2).a | p.a | -| main.go:117:2:117:2 | (phi@117:2).b | p.b | -| main.go:117:2:117:2 | (phi@117:2).b.a | p.b.a | -| main.go:117:2:117:2 | (phi@117:2).c | p.c | +| main.go:13:6:13:6 | (SSA def(x)) | x | +| main.go:14:2:14:2 | (SSA def(y)) | y | +| main.go:17:3:17:3 | (SSA def(y)) | y | +| main.go:19:2:19:10 | (SSA phi(y)) | y | +| main.go:21:3:21:3 | (SSA def(x)) | x | +| main.go:23:2:23:10 | (SSA phi(x)) | x | +| main.go:26:10:26:10 | (SSA def(x)) | x | +| main.go:27:2:27:2 | (SSA def(a)) | a | +| main.go:27:5:27:5 | (SSA def(b)) | b | +| main.go:29:3:29:3 | (SSA def(a)) | a | +| main.go:29:6:29:6 | (SSA def(b)) | b | +| main.go:31:9:31:9 | (SSA phi(a)) | a | +| main.go:31:9:31:9 | (SSA phi(b)) | b | +| main.go:34:11:34:11 | (SSA def(x)) | x | +| main.go:39:2:39:2 | (SSA def(x)) | x | +| main.go:40:2:40:4 | (SSA def(ptr)) | ptr | +| main.go:48:2:48:7 | (SSA def(result)) | result | +| main.go:52:14:52:19 | (SSA def(result)) | result | +| main.go:57:6:57:6 | (SSA def(x)) | x | +| main.go:58:6:58:9 | (SSA phi(x)) | x | +| main.go:59:3:59:3 | (SSA def(x)) | x | +| main.go:63:2:63:2 | (SSA def(y)) | y | +| main.go:64:6:64:6 | (SSA def(i)) | i | +| main.go:64:16:64:18 | (SSA def(i)) | i | +| main.go:65:6:65:9 | (SSA phi(i)) | i | +| main.go:65:6:65:9 | (SSA phi(y)) | y | +| main.go:68:3:68:3 | (SSA def(y)) | y | +| main.go:73:6:73:6 | (SSA def(i)) | i | +| main.go:73:16:73:18 | (SSA def(i)) | i | +| main.go:74:3:74:3 | (SSA def(z)) | z | +| main.go:74:3:74:3 | (SSA phi(i)) | i | +| main.go:82:25:82:25 | (SSA def(b)) | b | +| main.go:83:2:83:2 | (SSA def(x)) | x | +| main.go:84:5:84:5 | (SSA def(a)) | a | +| main.go:95:22:95:28 | (SSA def(wrapper)) | wrapper | +| main.go:95:22:95:28 | (SSA def(wrapper)).s | wrapper.s | +| main.go:96:2:96:2 | (SSA def(x)) | x | +| main.go:97:2:99:3 | (SSA def(x)) | x | +| main.go:98:3:98:3 | (SSA def(x)) | x | +| main.go:103:20:103:26 | (SSA def(wrapper)) | wrapper | +| main.go:103:20:103:26 | (SSA def(wrapper)).s | wrapper.s | +| main.go:104:2:104:2 | (SSA def(x)) | x | +| main.go:105:16:108:2 | (SSA def(x)) | x | +| main.go:106:3:106:3 | (SSA def(y)) | y | +| main.go:112:29:112:35 | (SSA def(wrapper)) | wrapper | +| main.go:112:29:112:35 | (SSA def(wrapper)).s | wrapper.s | +| main.go:113:2:113:2 | (SSA def(x)) | x | +| main.go:114:2:117:3 | (SSA def(x)) | x | +| main.go:114:16:117:2 | (SSA def(x)) | x | +| main.go:115:3:115:3 | (SSA def(y)) | y | +| main.go:116:3:116:3 | (SSA def(x)) | x | +| main.go:130:3:130:3 | (SSA def(p)) | p | +| main.go:132:3:132:3 | (SSA def(p)) | p | +| main.go:135:2:135:2 | (SSA phi(p)) | p | +| main.go:135:2:135:2 | (SSA phi(p)).a | p.a | +| main.go:135:2:135:2 | (SSA phi(p)).b | p.b | +| main.go:135:2:135:2 | (SSA phi(p)).b.a | p.b.a | +| main.go:135:2:135:2 | (SSA phi(p)).c | p.c | diff --git a/go/ql/test/library-tests/semmle/go/dataflow/SSA/VarDefs.expected b/go/ql/test/library-tests/semmle/go/dataflow/SSA/VarDefs.expected index 2cadf9f87ab..6149ddfbb54 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/SSA/VarDefs.expected +++ b/go/ql/test/library-tests/semmle/go/dataflow/SSA/VarDefs.expected @@ -32,16 +32,23 @@ | main.go:95:22:95:28 | initialization of wrapper | main.go:95:22:95:28 | wrapper | main.go:95:22:95:28 | argument corresponding to wrapper | | main.go:96:2:96:2 | assignment to x | main.go:96:2:96:2 | x | main.go:96:7:96:7 | 0 | | main.go:98:3:98:3 | assignment to x | main.go:96:2:96:2 | x | main.go:98:7:98:7 | 1 | -| main.go:110:6:110:6 | assignment to p | main.go:110:6:110:6 | p | main.go:110:6:110:6 | zero value for p | -| main.go:112:3:112:3 | assignment to p | main.go:110:6:110:6 | p | main.go:112:7:112:24 | struct literal | -| main.go:112:9:112:9 | init of 2 | main.go:104:2:104:2 | a | main.go:112:9:112:9 | 2 | -| main.go:112:12:112:18 | init of struct literal | main.go:105:2:105:2 | b | main.go:112:12:112:18 | struct literal | -| main.go:112:14:112:14 | init of 1 | main.go:89:2:89:2 | a | main.go:112:14:112:14 | 1 | -| main.go:112:17:112:17 | init of 5 | main.go:90:2:90:2 | b | main.go:112:17:112:17 | 5 | -| main.go:112:21:112:23 | init of 'n' | main.go:106:2:106:2 | c | main.go:112:21:112:23 | 'n' | -| main.go:114:3:114:3 | assignment to p | main.go:110:6:110:6 | p | main.go:114:7:114:24 | struct literal | -| main.go:114:9:114:9 | init of 3 | main.go:104:2:104:2 | a | main.go:114:9:114:9 | 3 | -| main.go:114:12:114:18 | init of struct literal | main.go:105:2:105:2 | b | main.go:114:12:114:18 | struct literal | -| main.go:114:14:114:14 | init of 4 | main.go:89:2:89:2 | a | main.go:114:14:114:14 | 4 | -| main.go:114:17:114:17 | init of 5 | main.go:90:2:90:2 | b | main.go:114:17:114:17 | 5 | -| main.go:114:21:114:23 | init of '2' | main.go:106:2:106:2 | c | main.go:114:21:114:23 | '2' | +| main.go:103:20:103:26 | initialization of wrapper | main.go:103:20:103:26 | wrapper | main.go:103:20:103:26 | argument corresponding to wrapper | +| main.go:104:2:104:2 | assignment to x | main.go:104:2:104:2 | x | main.go:104:7:104:7 | 0 | +| main.go:106:3:106:3 | assignment to y | main.go:106:3:106:3 | y | main.go:106:8:106:8 | x | +| main.go:112:29:112:35 | initialization of wrapper | main.go:112:29:112:35 | wrapper | main.go:112:29:112:35 | argument corresponding to wrapper | +| main.go:113:2:113:2 | assignment to x | main.go:113:2:113:2 | x | main.go:113:7:113:7 | 0 | +| main.go:115:3:115:3 | assignment to y | main.go:115:3:115:3 | y | main.go:115:8:115:12 | ...+... | +| main.go:116:3:116:3 | assignment to x | main.go:113:2:113:2 | x | main.go:116:7:116:7 | y | +| main.go:128:6:128:6 | assignment to p | main.go:128:6:128:6 | p | main.go:128:6:128:6 | zero value for p | +| main.go:130:3:130:3 | assignment to p | main.go:128:6:128:6 | p | main.go:130:7:130:24 | struct literal | +| main.go:130:9:130:9 | init of 2 | main.go:122:2:122:2 | a | main.go:130:9:130:9 | 2 | +| main.go:130:12:130:18 | init of struct literal | main.go:123:2:123:2 | b | main.go:130:12:130:18 | struct literal | +| main.go:130:14:130:14 | init of 1 | main.go:89:2:89:2 | a | main.go:130:14:130:14 | 1 | +| main.go:130:17:130:17 | init of 5 | main.go:90:2:90:2 | b | main.go:130:17:130:17 | 5 | +| main.go:130:21:130:23 | init of 'n' | main.go:124:2:124:2 | c | main.go:130:21:130:23 | 'n' | +| main.go:132:3:132:3 | assignment to p | main.go:128:6:128:6 | p | main.go:132:7:132:24 | struct literal | +| main.go:132:9:132:9 | init of 3 | main.go:122:2:122:2 | a | main.go:132:9:132:9 | 3 | +| main.go:132:12:132:18 | init of struct literal | main.go:123:2:123:2 | b | main.go:132:12:132:18 | struct literal | +| main.go:132:14:132:14 | init of 4 | main.go:89:2:89:2 | a | main.go:132:14:132:14 | 4 | +| main.go:132:17:132:17 | init of 5 | main.go:90:2:90:2 | b | main.go:132:17:132:17 | 5 | +| main.go:132:21:132:23 | init of '2' | main.go:124:2:124:2 | c | main.go:132:21:132:23 | '2' | diff --git a/go/ql/test/library-tests/semmle/go/dataflow/SSA/VarUses.expected b/go/ql/test/library-tests/semmle/go/dataflow/SSA/VarUses.expected index 332f859f051..2e6b3c855c3 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/SSA/VarUses.expected +++ b/go/ql/test/library-tests/semmle/go/dataflow/SSA/VarUses.expected @@ -28,13 +28,29 @@ | main.go:84:15:84:15 | x | main.go:83:2:83:2 | x | | main.go:97:2:97:8 | wrapper | main.go:95:22:95:28 | wrapper | | main.go:97:2:97:10 | selection of s | main.go:95:38:95:38 | s | +| main.go:97:2:97:10 | selection of s | main.go:103:36:103:36 | s | +| main.go:97:2:97:10 | selection of s | main.go:112:45:112:45 | s | | main.go:100:9:100:9 | x | main.go:96:2:96:2 | x | -| main.go:117:2:117:2 | p | main.go:110:6:110:6 | p | -| main.go:117:2:117:4 | selection of b | main.go:105:2:105:2 | b | -| main.go:119:12:119:12 | p | main.go:110:6:110:6 | p | -| main.go:119:12:119:14 | selection of a | main.go:104:2:104:2 | a | -| main.go:119:17:119:17 | p | main.go:110:6:110:6 | p | -| main.go:119:17:119:19 | selection of b | main.go:105:2:105:2 | b | -| main.go:119:17:119:21 | selection of a | main.go:89:2:89:2 | a | -| main.go:119:24:119:24 | p | main.go:110:6:110:6 | p | -| main.go:119:24:119:26 | selection of c | main.go:106:2:106:2 | c | +| main.go:105:2:105:8 | wrapper | main.go:103:20:103:26 | wrapper | +| main.go:105:2:105:10 | selection of s | main.go:95:38:95:38 | s | +| main.go:105:2:105:10 | selection of s | main.go:103:36:103:36 | s | +| main.go:105:2:105:10 | selection of s | main.go:112:45:112:45 | s | +| main.go:106:8:106:8 | x | main.go:104:2:104:2 | x | +| main.go:107:7:107:7 | y | main.go:106:3:106:3 | y | +| main.go:109:9:109:9 | x | main.go:104:2:104:2 | x | +| main.go:114:2:114:8 | wrapper | main.go:112:29:112:35 | wrapper | +| main.go:114:2:114:10 | selection of s | main.go:95:38:95:38 | s | +| main.go:114:2:114:10 | selection of s | main.go:103:36:103:36 | s | +| main.go:114:2:114:10 | selection of s | main.go:112:45:112:45 | s | +| main.go:115:8:115:8 | x | main.go:113:2:113:2 | x | +| main.go:116:7:116:7 | y | main.go:115:3:115:3 | y | +| main.go:118:9:118:9 | x | main.go:113:2:113:2 | x | +| main.go:135:2:135:2 | p | main.go:128:6:128:6 | p | +| main.go:135:2:135:4 | selection of b | main.go:123:2:123:2 | b | +| main.go:137:12:137:12 | p | main.go:128:6:128:6 | p | +| main.go:137:12:137:14 | selection of a | main.go:122:2:122:2 | a | +| main.go:137:17:137:17 | p | main.go:128:6:128:6 | p | +| main.go:137:17:137:19 | selection of b | main.go:123:2:123:2 | b | +| main.go:137:17:137:21 | selection of a | main.go:89:2:89:2 | a | +| main.go:137:24:137:24 | p | main.go:128:6:128:6 | p | +| main.go:137:24:137:26 | selection of c | main.go:124:2:124:2 | c | diff --git a/go/ql/test/library-tests/semmle/go/dataflow/SSA/main.go b/go/ql/test/library-tests/semmle/go/dataflow/SSA/main.go index cda85fdfc66..3967c14469f 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/SSA/main.go +++ b/go/ql/test/library-tests/semmle/go/dataflow/SSA/main.go @@ -100,6 +100,24 @@ func updateInClosure(wrapper struct{ s }) int { return x } +func readInClosure(wrapper struct{ s }) int { + x := 0 + wrapper.s.foo(func() { + y := x + _ = y + }) + return x +} + +func readAndUpdateInClosure(wrapper struct{ s }) int { + x := 0 + wrapper.s.foo(func() { + y := x + 1 + x = y + }) + return x +} + type t struct { a int b s diff --git a/go/ql/test/library-tests/semmle/go/frameworks/Beego/CleartextLogging.expected b/go/ql/test/library-tests/semmle/go/frameworks/Beego/CleartextLogging.expected index 30a38580f78..76c71bdea20 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/Beego/CleartextLogging.expected +++ b/go/ql/test/library-tests/semmle/go/frameworks/Beego/CleartextLogging.expected @@ -1,73 +1,73 @@ #select -| test.go:154:14:154:21 | password | test.go:153:17:153:24 | definition of password | test.go:154:14:154:21 | password | $@ flows to a logging call. | test.go:153:17:153:24 | definition of password | Sensitive data returned by an access to password | -| test.go:155:17:155:24 | password | test.go:153:17:153:24 | definition of password | test.go:155:17:155:24 | password | $@ flows to a logging call. | test.go:153:17:153:24 | definition of password | Sensitive data returned by an access to password | -| test.go:156:14:156:21 | password | test.go:153:17:153:24 | definition of password | test.go:156:14:156:21 | password | $@ flows to a logging call. | test.go:153:17:153:24 | definition of password | Sensitive data returned by an access to password | -| test.go:157:18:157:25 | password | test.go:153:17:153:24 | definition of password | test.go:157:18:157:25 | password | $@ flows to a logging call. | test.go:153:17:153:24 | definition of password | Sensitive data returned by an access to password | -| test.go:158:14:158:21 | password | test.go:153:17:153:24 | definition of password | test.go:158:14:158:21 | password | $@ flows to a logging call. | test.go:153:17:153:24 | definition of password | Sensitive data returned by an access to password | -| test.go:159:13:159:20 | password | test.go:153:17:153:24 | definition of password | test.go:159:13:159:20 | password | $@ flows to a logging call. | test.go:153:17:153:24 | definition of password | Sensitive data returned by an access to password | -| test.go:160:22:160:29 | password | test.go:153:17:153:24 | definition of password | test.go:160:22:160:29 | password | $@ flows to a logging call. | test.go:153:17:153:24 | definition of password | Sensitive data returned by an access to password | -| test.go:161:15:161:22 | password | test.go:153:17:153:24 | definition of password | test.go:161:15:161:22 | password | $@ flows to a logging call. | test.go:153:17:153:24 | definition of password | Sensitive data returned by an access to password | -| test.go:162:14:162:21 | password | test.go:153:17:153:24 | definition of password | test.go:162:14:162:21 | password | $@ flows to a logging call. | test.go:153:17:153:24 | definition of password | Sensitive data returned by an access to password | -| test.go:163:13:163:20 | password | test.go:153:17:153:24 | definition of password | test.go:163:13:163:20 | password | $@ flows to a logging call. | test.go:153:17:153:24 | definition of password | Sensitive data returned by an access to password | -| test.go:164:16:164:23 | password | test.go:153:17:153:24 | definition of password | test.go:164:16:164:23 | password | $@ flows to a logging call. | test.go:153:17:153:24 | definition of password | Sensitive data returned by an access to password | -| test.go:165:13:165:20 | password | test.go:153:17:153:24 | definition of password | test.go:165:13:165:20 | password | $@ flows to a logging call. | test.go:153:17:153:24 | definition of password | Sensitive data returned by an access to password | -| test.go:166:16:166:23 | password | test.go:153:17:153:24 | definition of password | test.go:166:16:166:23 | password | $@ flows to a logging call. | test.go:153:17:153:24 | definition of password | Sensitive data returned by an access to password | -| test.go:167:13:167:20 | password | test.go:153:17:153:24 | definition of password | test.go:167:13:167:20 | password | $@ flows to a logging call. | test.go:153:17:153:24 | definition of password | Sensitive data returned by an access to password | -| test.go:168:17:168:24 | password | test.go:153:17:153:24 | definition of password | test.go:168:17:168:24 | password | $@ flows to a logging call. | test.go:153:17:153:24 | definition of password | Sensitive data returned by an access to password | -| test.go:169:13:169:20 | password | test.go:153:17:153:24 | definition of password | test.go:169:13:169:20 | password | $@ flows to a logging call. | test.go:153:17:153:24 | definition of password | Sensitive data returned by an access to password | -| test.go:170:12:170:19 | password | test.go:153:17:153:24 | definition of password | test.go:170:12:170:19 | password | $@ flows to a logging call. | test.go:153:17:153:24 | definition of password | Sensitive data returned by an access to password | -| test.go:171:21:171:28 | password | test.go:153:17:153:24 | definition of password | test.go:171:21:171:28 | password | $@ flows to a logging call. | test.go:153:17:153:24 | definition of password | Sensitive data returned by an access to password | -| test.go:172:14:172:21 | password | test.go:153:17:153:24 | definition of password | test.go:172:14:172:21 | password | $@ flows to a logging call. | test.go:153:17:153:24 | definition of password | Sensitive data returned by an access to password | -| test.go:173:13:173:20 | password | test.go:153:17:153:24 | definition of password | test.go:173:13:173:20 | password | $@ flows to a logging call. | test.go:153:17:153:24 | definition of password | Sensitive data returned by an access to password | -| test.go:174:12:174:19 | password | test.go:153:17:153:24 | definition of password | test.go:174:12:174:19 | password | $@ flows to a logging call. | test.go:153:17:153:24 | definition of password | Sensitive data returned by an access to password | -| test.go:175:15:175:22 | password | test.go:153:17:153:24 | definition of password | test.go:175:15:175:22 | password | $@ flows to a logging call. | test.go:153:17:153:24 | definition of password | Sensitive data returned by an access to password | -| test.go:176:15:176:22 | password | test.go:153:17:153:24 | definition of password | test.go:176:15:176:22 | password | $@ flows to a logging call. | test.go:153:17:153:24 | definition of password | Sensitive data returned by an access to password | -| test.go:177:18:177:25 | password | test.go:153:17:153:24 | definition of password | test.go:177:18:177:25 | password | $@ flows to a logging call. | test.go:153:17:153:24 | definition of password | Sensitive data returned by an access to password | -| test.go:178:15:178:22 | password | test.go:153:17:153:24 | definition of password | test.go:178:15:178:22 | password | $@ flows to a logging call. | test.go:153:17:153:24 | definition of password | Sensitive data returned by an access to password | -| test.go:179:19:179:26 | password | test.go:153:17:153:24 | definition of password | test.go:179:19:179:26 | password | $@ flows to a logging call. | test.go:153:17:153:24 | definition of password | Sensitive data returned by an access to password | -| test.go:180:15:180:22 | password | test.go:153:17:153:24 | definition of password | test.go:180:15:180:22 | password | $@ flows to a logging call. | test.go:153:17:153:24 | definition of password | Sensitive data returned by an access to password | -| test.go:181:14:181:21 | password | test.go:153:17:153:24 | definition of password | test.go:181:14:181:21 | password | $@ flows to a logging call. | test.go:153:17:153:24 | definition of password | Sensitive data returned by an access to password | -| test.go:182:23:182:30 | password | test.go:153:17:153:24 | definition of password | test.go:182:23:182:30 | password | $@ flows to a logging call. | test.go:153:17:153:24 | definition of password | Sensitive data returned by an access to password | -| test.go:183:16:183:23 | password | test.go:153:17:153:24 | definition of password | test.go:183:16:183:23 | password | $@ flows to a logging call. | test.go:153:17:153:24 | definition of password | Sensitive data returned by an access to password | -| test.go:184:15:184:22 | password | test.go:153:17:153:24 | definition of password | test.go:184:15:184:22 | password | $@ flows to a logging call. | test.go:153:17:153:24 | definition of password | Sensitive data returned by an access to password | -| test.go:185:14:185:21 | password | test.go:153:17:153:24 | definition of password | test.go:185:14:185:21 | password | $@ flows to a logging call. | test.go:153:17:153:24 | definition of password | Sensitive data returned by an access to password | -| test.go:186:17:186:24 | password | test.go:153:17:153:24 | definition of password | test.go:186:17:186:24 | password | $@ flows to a logging call. | test.go:153:17:153:24 | definition of password | Sensitive data returned by an access to password | -| test.go:187:16:187:23 | password | test.go:153:17:153:24 | definition of password | test.go:187:16:187:23 | password | $@ flows to a logging call. | test.go:153:17:153:24 | definition of password | Sensitive data returned by an access to password | +| test.go:154:14:154:21 | password | test.go:153:17:153:24 | SSA def(password) | test.go:154:14:154:21 | password | $@ flows to a logging call. | test.go:153:17:153:24 | SSA def(password) | Sensitive data returned by an access to password | +| test.go:155:17:155:24 | password | test.go:153:17:153:24 | SSA def(password) | test.go:155:17:155:24 | password | $@ flows to a logging call. | test.go:153:17:153:24 | SSA def(password) | Sensitive data returned by an access to password | +| test.go:156:14:156:21 | password | test.go:153:17:153:24 | SSA def(password) | test.go:156:14:156:21 | password | $@ flows to a logging call. | test.go:153:17:153:24 | SSA def(password) | Sensitive data returned by an access to password | +| test.go:157:18:157:25 | password | test.go:153:17:153:24 | SSA def(password) | test.go:157:18:157:25 | password | $@ flows to a logging call. | test.go:153:17:153:24 | SSA def(password) | Sensitive data returned by an access to password | +| test.go:158:14:158:21 | password | test.go:153:17:153:24 | SSA def(password) | test.go:158:14:158:21 | password | $@ flows to a logging call. | test.go:153:17:153:24 | SSA def(password) | Sensitive data returned by an access to password | +| test.go:159:13:159:20 | password | test.go:153:17:153:24 | SSA def(password) | test.go:159:13:159:20 | password | $@ flows to a logging call. | test.go:153:17:153:24 | SSA def(password) | Sensitive data returned by an access to password | +| test.go:160:22:160:29 | password | test.go:153:17:153:24 | SSA def(password) | test.go:160:22:160:29 | password | $@ flows to a logging call. | test.go:153:17:153:24 | SSA def(password) | Sensitive data returned by an access to password | +| test.go:161:15:161:22 | password | test.go:153:17:153:24 | SSA def(password) | test.go:161:15:161:22 | password | $@ flows to a logging call. | test.go:153:17:153:24 | SSA def(password) | Sensitive data returned by an access to password | +| test.go:162:14:162:21 | password | test.go:153:17:153:24 | SSA def(password) | test.go:162:14:162:21 | password | $@ flows to a logging call. | test.go:153:17:153:24 | SSA def(password) | Sensitive data returned by an access to password | +| test.go:163:13:163:20 | password | test.go:153:17:153:24 | SSA def(password) | test.go:163:13:163:20 | password | $@ flows to a logging call. | test.go:153:17:153:24 | SSA def(password) | Sensitive data returned by an access to password | +| test.go:164:16:164:23 | password | test.go:153:17:153:24 | SSA def(password) | test.go:164:16:164:23 | password | $@ flows to a logging call. | test.go:153:17:153:24 | SSA def(password) | Sensitive data returned by an access to password | +| test.go:165:13:165:20 | password | test.go:153:17:153:24 | SSA def(password) | test.go:165:13:165:20 | password | $@ flows to a logging call. | test.go:153:17:153:24 | SSA def(password) | Sensitive data returned by an access to password | +| test.go:166:16:166:23 | password | test.go:153:17:153:24 | SSA def(password) | test.go:166:16:166:23 | password | $@ flows to a logging call. | test.go:153:17:153:24 | SSA def(password) | Sensitive data returned by an access to password | +| test.go:167:13:167:20 | password | test.go:153:17:153:24 | SSA def(password) | test.go:167:13:167:20 | password | $@ flows to a logging call. | test.go:153:17:153:24 | SSA def(password) | Sensitive data returned by an access to password | +| test.go:168:17:168:24 | password | test.go:153:17:153:24 | SSA def(password) | test.go:168:17:168:24 | password | $@ flows to a logging call. | test.go:153:17:153:24 | SSA def(password) | Sensitive data returned by an access to password | +| test.go:169:13:169:20 | password | test.go:153:17:153:24 | SSA def(password) | test.go:169:13:169:20 | password | $@ flows to a logging call. | test.go:153:17:153:24 | SSA def(password) | Sensitive data returned by an access to password | +| test.go:170:12:170:19 | password | test.go:153:17:153:24 | SSA def(password) | test.go:170:12:170:19 | password | $@ flows to a logging call. | test.go:153:17:153:24 | SSA def(password) | Sensitive data returned by an access to password | +| test.go:171:21:171:28 | password | test.go:153:17:153:24 | SSA def(password) | test.go:171:21:171:28 | password | $@ flows to a logging call. | test.go:153:17:153:24 | SSA def(password) | Sensitive data returned by an access to password | +| test.go:172:14:172:21 | password | test.go:153:17:153:24 | SSA def(password) | test.go:172:14:172:21 | password | $@ flows to a logging call. | test.go:153:17:153:24 | SSA def(password) | Sensitive data returned by an access to password | +| test.go:173:13:173:20 | password | test.go:153:17:153:24 | SSA def(password) | test.go:173:13:173:20 | password | $@ flows to a logging call. | test.go:153:17:153:24 | SSA def(password) | Sensitive data returned by an access to password | +| test.go:174:12:174:19 | password | test.go:153:17:153:24 | SSA def(password) | test.go:174:12:174:19 | password | $@ flows to a logging call. | test.go:153:17:153:24 | SSA def(password) | Sensitive data returned by an access to password | +| test.go:175:15:175:22 | password | test.go:153:17:153:24 | SSA def(password) | test.go:175:15:175:22 | password | $@ flows to a logging call. | test.go:153:17:153:24 | SSA def(password) | Sensitive data returned by an access to password | +| test.go:176:15:176:22 | password | test.go:153:17:153:24 | SSA def(password) | test.go:176:15:176:22 | password | $@ flows to a logging call. | test.go:153:17:153:24 | SSA def(password) | Sensitive data returned by an access to password | +| test.go:177:18:177:25 | password | test.go:153:17:153:24 | SSA def(password) | test.go:177:18:177:25 | password | $@ flows to a logging call. | test.go:153:17:153:24 | SSA def(password) | Sensitive data returned by an access to password | +| test.go:178:15:178:22 | password | test.go:153:17:153:24 | SSA def(password) | test.go:178:15:178:22 | password | $@ flows to a logging call. | test.go:153:17:153:24 | SSA def(password) | Sensitive data returned by an access to password | +| test.go:179:19:179:26 | password | test.go:153:17:153:24 | SSA def(password) | test.go:179:19:179:26 | password | $@ flows to a logging call. | test.go:153:17:153:24 | SSA def(password) | Sensitive data returned by an access to password | +| test.go:180:15:180:22 | password | test.go:153:17:153:24 | SSA def(password) | test.go:180:15:180:22 | password | $@ flows to a logging call. | test.go:153:17:153:24 | SSA def(password) | Sensitive data returned by an access to password | +| test.go:181:14:181:21 | password | test.go:153:17:153:24 | SSA def(password) | test.go:181:14:181:21 | password | $@ flows to a logging call. | test.go:153:17:153:24 | SSA def(password) | Sensitive data returned by an access to password | +| test.go:182:23:182:30 | password | test.go:153:17:153:24 | SSA def(password) | test.go:182:23:182:30 | password | $@ flows to a logging call. | test.go:153:17:153:24 | SSA def(password) | Sensitive data returned by an access to password | +| test.go:183:16:183:23 | password | test.go:153:17:153:24 | SSA def(password) | test.go:183:16:183:23 | password | $@ flows to a logging call. | test.go:153:17:153:24 | SSA def(password) | Sensitive data returned by an access to password | +| test.go:184:15:184:22 | password | test.go:153:17:153:24 | SSA def(password) | test.go:184:15:184:22 | password | $@ flows to a logging call. | test.go:153:17:153:24 | SSA def(password) | Sensitive data returned by an access to password | +| test.go:185:14:185:21 | password | test.go:153:17:153:24 | SSA def(password) | test.go:185:14:185:21 | password | $@ flows to a logging call. | test.go:153:17:153:24 | SSA def(password) | Sensitive data returned by an access to password | +| test.go:186:17:186:24 | password | test.go:153:17:153:24 | SSA def(password) | test.go:186:17:186:24 | password | $@ flows to a logging call. | test.go:153:17:153:24 | SSA def(password) | Sensitive data returned by an access to password | +| test.go:187:16:187:23 | password | test.go:153:17:153:24 | SSA def(password) | test.go:187:16:187:23 | password | $@ flows to a logging call. | test.go:153:17:153:24 | SSA def(password) | Sensitive data returned by an access to password | edges -| test.go:153:17:153:24 | definition of password | test.go:154:14:154:21 | password | provenance | | -| test.go:153:17:153:24 | definition of password | test.go:155:17:155:24 | password | provenance | | -| test.go:153:17:153:24 | definition of password | test.go:156:14:156:21 | password | provenance | | -| test.go:153:17:153:24 | definition of password | test.go:157:18:157:25 | password | provenance | | -| test.go:153:17:153:24 | definition of password | test.go:158:14:158:21 | password | provenance | | -| test.go:153:17:153:24 | definition of password | test.go:159:13:159:20 | password | provenance | | -| test.go:153:17:153:24 | definition of password | test.go:160:22:160:29 | password | provenance | | -| test.go:153:17:153:24 | definition of password | test.go:161:15:161:22 | password | provenance | | -| test.go:153:17:153:24 | definition of password | test.go:162:14:162:21 | password | provenance | | -| test.go:153:17:153:24 | definition of password | test.go:163:13:163:20 | password | provenance | | -| test.go:153:17:153:24 | definition of password | test.go:164:16:164:23 | password | provenance | | -| test.go:153:17:153:24 | definition of password | test.go:165:13:165:20 | password | provenance | Sink:MaD:1 | -| test.go:153:17:153:24 | definition of password | test.go:166:16:166:23 | password | provenance | Sink:MaD:2 | -| test.go:153:17:153:24 | definition of password | test.go:167:13:167:20 | password | provenance | Sink:MaD:3 | -| test.go:153:17:153:24 | definition of password | test.go:168:17:168:24 | password | provenance | Sink:MaD:4 | -| test.go:153:17:153:24 | definition of password | test.go:169:13:169:20 | password | provenance | Sink:MaD:5 | -| test.go:153:17:153:24 | definition of password | test.go:170:12:170:19 | password | provenance | Sink:MaD:6 | -| test.go:153:17:153:24 | definition of password | test.go:171:21:171:28 | password | provenance | Sink:MaD:7 | -| test.go:153:17:153:24 | definition of password | test.go:172:14:172:21 | password | provenance | Sink:MaD:8 | -| test.go:153:17:153:24 | definition of password | test.go:173:13:173:20 | password | provenance | Sink:MaD:9 | -| test.go:153:17:153:24 | definition of password | test.go:174:12:174:19 | password | provenance | Sink:MaD:10 | -| test.go:153:17:153:24 | definition of password | test.go:175:15:175:22 | password | provenance | Sink:MaD:11 | -| test.go:153:17:153:24 | definition of password | test.go:176:15:176:22 | password | provenance | Sink:MaD:12 | -| test.go:153:17:153:24 | definition of password | test.go:177:18:177:25 | password | provenance | Sink:MaD:13 | -| test.go:153:17:153:24 | definition of password | test.go:178:15:178:22 | password | provenance | Sink:MaD:14 | -| test.go:153:17:153:24 | definition of password | test.go:179:19:179:26 | password | provenance | Sink:MaD:15 | -| test.go:153:17:153:24 | definition of password | test.go:180:15:180:22 | password | provenance | Sink:MaD:16 | -| test.go:153:17:153:24 | definition of password | test.go:181:14:181:21 | password | provenance | Sink:MaD:17 | -| test.go:153:17:153:24 | definition of password | test.go:182:23:182:30 | password | provenance | Sink:MaD:18 | -| test.go:153:17:153:24 | definition of password | test.go:183:16:183:23 | password | provenance | Sink:MaD:19 | -| test.go:153:17:153:24 | definition of password | test.go:184:15:184:22 | password | provenance | Sink:MaD:20 | -| test.go:153:17:153:24 | definition of password | test.go:185:14:185:21 | password | provenance | Sink:MaD:21 | -| test.go:153:17:153:24 | definition of password | test.go:186:17:186:24 | password | provenance | Sink:MaD:22 | -| test.go:153:17:153:24 | definition of password | test.go:187:16:187:23 | password | provenance | | +| test.go:153:17:153:24 | SSA def(password) | test.go:154:14:154:21 | password | provenance | | +| test.go:153:17:153:24 | SSA def(password) | test.go:155:17:155:24 | password | provenance | | +| test.go:153:17:153:24 | SSA def(password) | test.go:156:14:156:21 | password | provenance | | +| test.go:153:17:153:24 | SSA def(password) | test.go:157:18:157:25 | password | provenance | | +| test.go:153:17:153:24 | SSA def(password) | test.go:158:14:158:21 | password | provenance | | +| test.go:153:17:153:24 | SSA def(password) | test.go:159:13:159:20 | password | provenance | | +| test.go:153:17:153:24 | SSA def(password) | test.go:160:22:160:29 | password | provenance | | +| test.go:153:17:153:24 | SSA def(password) | test.go:161:15:161:22 | password | provenance | | +| test.go:153:17:153:24 | SSA def(password) | test.go:162:14:162:21 | password | provenance | | +| test.go:153:17:153:24 | SSA def(password) | test.go:163:13:163:20 | password | provenance | | +| test.go:153:17:153:24 | SSA def(password) | test.go:164:16:164:23 | password | provenance | | +| test.go:153:17:153:24 | SSA def(password) | test.go:165:13:165:20 | password | provenance | Sink:MaD:1 | +| test.go:153:17:153:24 | SSA def(password) | test.go:166:16:166:23 | password | provenance | Sink:MaD:2 | +| test.go:153:17:153:24 | SSA def(password) | test.go:167:13:167:20 | password | provenance | Sink:MaD:3 | +| test.go:153:17:153:24 | SSA def(password) | test.go:168:17:168:24 | password | provenance | Sink:MaD:4 | +| test.go:153:17:153:24 | SSA def(password) | test.go:169:13:169:20 | password | provenance | Sink:MaD:5 | +| test.go:153:17:153:24 | SSA def(password) | test.go:170:12:170:19 | password | provenance | Sink:MaD:6 | +| test.go:153:17:153:24 | SSA def(password) | test.go:171:21:171:28 | password | provenance | Sink:MaD:7 | +| test.go:153:17:153:24 | SSA def(password) | test.go:172:14:172:21 | password | provenance | Sink:MaD:8 | +| test.go:153:17:153:24 | SSA def(password) | test.go:173:13:173:20 | password | provenance | Sink:MaD:9 | +| test.go:153:17:153:24 | SSA def(password) | test.go:174:12:174:19 | password | provenance | Sink:MaD:10 | +| test.go:153:17:153:24 | SSA def(password) | test.go:175:15:175:22 | password | provenance | Sink:MaD:11 | +| test.go:153:17:153:24 | SSA def(password) | test.go:176:15:176:22 | password | provenance | Sink:MaD:12 | +| test.go:153:17:153:24 | SSA def(password) | test.go:177:18:177:25 | password | provenance | Sink:MaD:13 | +| test.go:153:17:153:24 | SSA def(password) | test.go:178:15:178:22 | password | provenance | Sink:MaD:14 | +| test.go:153:17:153:24 | SSA def(password) | test.go:179:19:179:26 | password | provenance | Sink:MaD:15 | +| test.go:153:17:153:24 | SSA def(password) | test.go:180:15:180:22 | password | provenance | Sink:MaD:16 | +| test.go:153:17:153:24 | SSA def(password) | test.go:181:14:181:21 | password | provenance | Sink:MaD:17 | +| test.go:153:17:153:24 | SSA def(password) | test.go:182:23:182:30 | password | provenance | Sink:MaD:18 | +| test.go:153:17:153:24 | SSA def(password) | test.go:183:16:183:23 | password | provenance | Sink:MaD:19 | +| test.go:153:17:153:24 | SSA def(password) | test.go:184:15:184:22 | password | provenance | Sink:MaD:20 | +| test.go:153:17:153:24 | SSA def(password) | test.go:185:14:185:21 | password | provenance | Sink:MaD:21 | +| test.go:153:17:153:24 | SSA def(password) | test.go:186:17:186:24 | password | provenance | Sink:MaD:22 | +| test.go:153:17:153:24 | SSA def(password) | test.go:187:16:187:23 | password | provenance | | models | 1 | Sink: group:beego-logs; ; false; Alert; ; ; Argument[0..1]; log-injection; manual | | 2 | Sink: group:beego-logs; ; false; Critical; ; ; Argument[0..1]; log-injection; manual | @@ -92,7 +92,7 @@ models | 21 | Sink: group:beego-logs; BeeLogger; true; Warn; ; ; Argument[0..1]; log-injection; manual | | 22 | Sink: group:beego-logs; BeeLogger; true; Warning; ; ; Argument[0..1]; log-injection; manual | nodes -| test.go:153:17:153:24 | definition of password | semmle.label | definition of password | +| test.go:153:17:153:24 | SSA def(password) | semmle.label | SSA def(password) | | test.go:154:14:154:21 | password | semmle.label | password | | test.go:155:17:155:24 | password | semmle.label | password | | test.go:156:14:156:21 | password | semmle.label | password | diff --git a/go/ql/test/library-tests/semmle/go/frameworks/GoKit/main.go b/go/ql/test/library-tests/semmle/go/frameworks/GoKit/main.go index 1d0edf14c4d..cfd62e0de3a 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/GoKit/main.go +++ b/go/ql/test/library-tests/semmle/go/frameworks/GoKit/main.go @@ -12,12 +12,12 @@ type MyService interface { } func makeEndpointLit(svc MyService) endpoint.Endpoint { - return func(_ context.Context, request interface{}) (interface{}, error) { // $ source="definition of request" + return func(_ context.Context, request interface{}) (interface{}, error) { // $ source="SSA def(request)" return request, nil } } -func endpointfn(_ context.Context, request interface{}) (interface{}, error) { // $ source="definition of request" +func endpointfn(_ context.Context, request interface{}) (interface{}, error) { // $ source="SSA def(request)" return request, nil } diff --git a/go/ql/test/library-tests/semmle/go/frameworks/GoMicro/LogInjection.expected b/go/ql/test/library-tests/semmle/go/frameworks/GoMicro/LogInjection.expected index 4ec65220a52..44c5b85039c 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/GoMicro/LogInjection.expected +++ b/go/ql/test/library-tests/semmle/go/frameworks/GoMicro/LogInjection.expected @@ -1,8 +1,8 @@ #select -| main.go:21:28:21:31 | name | main.go:18:46:18:48 | definition of req | main.go:21:28:21:31 | name | This log entry depends on a $@. | main.go:18:46:18:48 | definition of req | user-provided value | +| main.go:21:28:21:31 | name | main.go:18:46:18:48 | SSA def(req) | main.go:21:28:21:31 | name | This log entry depends on a $@. | main.go:18:46:18:48 | SSA def(req) | user-provided value | edges -| main.go:18:46:18:48 | definition of req | main.go:21:28:21:31 | name | provenance | | +| main.go:18:46:18:48 | SSA def(req) | main.go:21:28:21:31 | name | provenance | | nodes -| main.go:18:46:18:48 | definition of req | semmle.label | definition of req | +| main.go:18:46:18:48 | SSA def(req) | semmle.label | SSA def(req) | | main.go:21:28:21:31 | name | semmle.label | name | subpaths diff --git a/go/ql/test/library-tests/semmle/go/frameworks/GoMicro/main.go b/go/ql/test/library-tests/semmle/go/frameworks/GoMicro/main.go index 5acaded1e7a..17e554ee4b1 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/GoMicro/main.go +++ b/go/ql/test/library-tests/semmle/go/frameworks/GoMicro/main.go @@ -15,7 +15,7 @@ import ( type Greeter struct{} -func (g *Greeter) Hello(ctx context.Context, req *pb.Request, rsp *pb.Response) error { // $ serverRequest="definition of req" Source +func (g *Greeter) Hello(ctx context.Context, req *pb.Request, rsp *pb.Response) error { // $ serverRequest="SSA def(req)" Source // var access name := req.Name fmt.Println("Name :: %s", name) // $ Alert diff --git a/go/ql/test/library-tests/semmle/go/frameworks/Twirp/RequestForgery.expected b/go/ql/test/library-tests/semmle/go/frameworks/Twirp/RequestForgery.expected index 7b1fa1a3121..a50f131a747 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/Twirp/RequestForgery.expected +++ b/go/ql/test/library-tests/semmle/go/frameworks/Twirp/RequestForgery.expected @@ -1,19 +1,19 @@ #select | server/main.go:30:38:30:48 | selection of Text | rpc/notes/service.twirp.go:538:25:538:32 | selection of Body | server/main.go:30:38:30:48 | selection of Text | The $@ of this request depends on a $@. | server/main.go:30:38:30:48 | selection of Text | URL | rpc/notes/service.twirp.go:538:25:538:32 | selection of Body | user-provided value | -| server/main.go:30:38:30:48 | selection of Text | server/main.go:19:56:19:61 | definition of params | server/main.go:30:38:30:48 | selection of Text | The $@ of this request depends on a $@. | server/main.go:30:38:30:48 | selection of Text | URL | server/main.go:19:56:19:61 | definition of params | user-provided value | +| server/main.go:30:38:30:48 | selection of Text | server/main.go:19:56:19:61 | SSA def(params) | server/main.go:30:38:30:48 | selection of Text | The $@ of this request depends on a $@. | server/main.go:30:38:30:48 | selection of Text | URL | server/main.go:19:56:19:61 | SSA def(params) | user-provided value | edges -| client/main.go:16:35:16:78 | &... | server/main.go:19:56:19:61 | definition of params | provenance | | +| client/main.go:16:35:16:78 | &... | server/main.go:19:56:19:61 | SSA def(params) | provenance | | | client/main.go:16:35:16:78 | &... [postupdate] | client/main.go:16:35:16:78 | &... | provenance | | | rpc/notes/service.twirp.go:538:2:538:33 | ... := ...[0] | rpc/notes/service.twirp.go:544:27:544:29 | buf | provenance | | | rpc/notes/service.twirp.go:538:25:538:32 | selection of Body | rpc/notes/service.twirp.go:538:2:538:33 | ... := ...[0] | provenance | Src:MaD:1 MaD:3 | | rpc/notes/service.twirp.go:544:27:544:29 | buf | rpc/notes/service.twirp.go:544:32:544:41 | reqContent [postupdate] | provenance | MaD:2 | -| rpc/notes/service.twirp.go:544:32:544:41 | reqContent [postupdate] | rpc/notes/service.twirp.go:574:2:577:2 | capture variable reqContent | provenance | | -| rpc/notes/service.twirp.go:574:2:577:2 | capture variable reqContent | rpc/notes/service.twirp.go:576:35:576:44 | reqContent | provenance | | -| rpc/notes/service.twirp.go:576:35:576:44 | reqContent | server/main.go:19:56:19:61 | definition of params | provenance | | -| server/main.go:19:56:19:61 | definition of params | server/main.go:19:56:19:61 | definition of params [Return] | provenance | | -| server/main.go:19:56:19:61 | definition of params | server/main.go:30:38:30:48 | selection of Text | provenance | | -| server/main.go:19:56:19:61 | definition of params | server/main.go:30:38:30:48 | selection of Text | provenance | | -| server/main.go:19:56:19:61 | definition of params [Return] | client/main.go:16:35:16:78 | &... [postupdate] | provenance | | +| rpc/notes/service.twirp.go:544:32:544:41 | reqContent [postupdate] | rpc/notes/service.twirp.go:574:2:577:2 | SSA def(reqContent) | provenance | | +| rpc/notes/service.twirp.go:574:2:577:2 | SSA def(reqContent) | rpc/notes/service.twirp.go:576:35:576:44 | reqContent | provenance | | +| rpc/notes/service.twirp.go:576:35:576:44 | reqContent | server/main.go:19:56:19:61 | SSA def(params) | provenance | | +| server/main.go:19:56:19:61 | SSA def(params) | server/main.go:19:56:19:61 | SSA def(params) [Return] | provenance | | +| server/main.go:19:56:19:61 | SSA def(params) | server/main.go:30:38:30:48 | selection of Text | provenance | | +| server/main.go:19:56:19:61 | SSA def(params) | server/main.go:30:38:30:48 | selection of Text | provenance | | +| server/main.go:19:56:19:61 | SSA def(params) [Return] | client/main.go:16:35:16:78 | &... [postupdate] | provenance | | models | 1 | Source: net/http; Request; true; Body; ; ; ; remote; manual | | 2 | Summary: google.golang.org/protobuf/proto; ; false; Unmarshal; ; ; Argument[0]; Argument[1]; taint; manual | @@ -25,10 +25,10 @@ nodes | rpc/notes/service.twirp.go:538:25:538:32 | selection of Body | semmle.label | selection of Body | | rpc/notes/service.twirp.go:544:27:544:29 | buf | semmle.label | buf | | rpc/notes/service.twirp.go:544:32:544:41 | reqContent [postupdate] | semmle.label | reqContent [postupdate] | -| rpc/notes/service.twirp.go:574:2:577:2 | capture variable reqContent | semmle.label | capture variable reqContent | +| rpc/notes/service.twirp.go:574:2:577:2 | SSA def(reqContent) | semmle.label | SSA def(reqContent) | | rpc/notes/service.twirp.go:576:35:576:44 | reqContent | semmle.label | reqContent | -| server/main.go:19:56:19:61 | definition of params | semmle.label | definition of params | -| server/main.go:19:56:19:61 | definition of params | semmle.label | definition of params | -| server/main.go:19:56:19:61 | definition of params [Return] | semmle.label | definition of params [Return] | +| server/main.go:19:56:19:61 | SSA def(params) | semmle.label | SSA def(params) | +| server/main.go:19:56:19:61 | SSA def(params) | semmle.label | SSA def(params) | +| server/main.go:19:56:19:61 | SSA def(params) [Return] | semmle.label | SSA def(params) [Return] | | server/main.go:30:38:30:48 | selection of Text | semmle.label | selection of Text | subpaths diff --git a/go/ql/test/library-tests/semmle/go/frameworks/Yaml/yaml.go b/go/ql/test/library-tests/semmle/go/frameworks/Yaml/yaml.go index fb8f7ea4bfa..388d884f38b 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/Yaml/yaml.go +++ b/go/ql/test/library-tests/semmle/go/frameworks/Yaml/yaml.go @@ -24,7 +24,7 @@ func main() { d.Decode(out) // $ ttfnmodelstep="d -> out [postupdate]" var w io.Writer - e := yaml2.NewEncoder(w) // $ ttfnmodelstep="definition of e -> w [postupdate]" + e := yaml2.NewEncoder(w) // $ ttfnmodelstep="SSA def(e) -> w [postupdate]" e.Encode(in) // $ ttfnmodelstep="in -> e [postupdate]" out, _ = yaml3.Marshal(in) // $ marshaler="yaml: in -> ... = ...[0]" ttfnmodelstep="in -> ... = ...[0]" @@ -33,7 +33,7 @@ func main() { d1 := yaml3.NewDecoder(r) // $ ttfnmodelstep="r -> call to NewDecoder" d1.Decode(out) // $ ttfnmodelstep="d1 -> out [postupdate]" - e1 := yaml3.NewEncoder(w) // $ ttfnmodelstep="definition of e1 -> w [postupdate]" + e1 := yaml3.NewEncoder(w) // $ ttfnmodelstep="SSA def(e1) -> w [postupdate]" e1.Encode(in) // $ ttfnmodelstep="in -> e1 [postupdate]" var n1 yaml3.Node diff --git a/go/ql/test/library-tests/semmle/go/frameworks/gqlgen/graph/schema.resolvers.go b/go/ql/test/library-tests/semmle/go/frameworks/gqlgen/graph/schema.resolvers.go index c22fb450e74..92d73f09364 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/gqlgen/graph/schema.resolvers.go +++ b/go/ql/test/library-tests/semmle/go/frameworks/gqlgen/graph/schema.resolvers.go @@ -11,7 +11,7 @@ import ( ) // CreateTodo is the resolver for the createTodo field. -func (r *mutationResolver) CreateTodo(ctx context.Context, input model.NewTodo) (*model.Todo, error) { // $ resolverParameter="definition of input" +func (r *mutationResolver) CreateTodo(ctx context.Context, input model.NewTodo) (*model.Todo, error) { // $ resolverParameter="SSA def(input)" panic(fmt.Errorf("not implemented: CreateTodo - createTodo %v", input)) } diff --git a/go/ql/test/query-tests/InconsistentCode/MissingErrorCheck/MissingErrorCheck.expected b/go/ql/test/query-tests/InconsistentCode/MissingErrorCheck/MissingErrorCheck.expected index b4bd7b815d5..9db748ebabd 100644 --- a/go/ql/test/query-tests/InconsistentCode/MissingErrorCheck/MissingErrorCheck.expected +++ b/go/ql/test/query-tests/InconsistentCode/MissingErrorCheck/MissingErrorCheck.expected @@ -1,2 +1,2 @@ -| tests.go:61:30:61:35 | result | $@ may be nil at this dereference because $@ may not have been checked. | tests.go:59:2:59:7 | definition of result | result | tests.go:59:10:59:12 | definition of err | err | -| tests.go:243:27:243:32 | result | $@ may be nil at this dereference because $@ may not have been checked. | tests.go:241:2:241:7 | definition of result | result | tests.go:241:10:241:12 | definition of err | err | +| tests.go:61:30:61:35 | result | $@ may be nil at this dereference because $@ may not have been checked. | tests.go:59:2:59:7 | SSA def(result) | result | tests.go:59:10:59:12 | SSA def(err) | err | +| tests.go:243:27:243:32 | result | $@ may be nil at this dereference because $@ may not have been checked. | tests.go:241:2:241:7 | SSA def(result) | result | tests.go:241:10:241:12 | SSA def(err) | err | diff --git a/go/ql/test/query-tests/InconsistentCode/UnhandledCloseWritableHandle/UnhandledCloseWritableHandle.expected b/go/ql/test/query-tests/InconsistentCode/UnhandledCloseWritableHandle/UnhandledCloseWritableHandle.expected index faf2702011f..5ded10ee1bd 100644 --- a/go/ql/test/query-tests/InconsistentCode/UnhandledCloseWritableHandle/UnhandledCloseWritableHandle.expected +++ b/go/ql/test/query-tests/InconsistentCode/UnhandledCloseWritableHandle/UnhandledCloseWritableHandle.expected @@ -9,17 +9,17 @@ | tests.go:145:3:145:3 | f | tests.go:141:5:141:78 | ... := ...[0] | tests.go:145:3:145:3 | f | File handle may be writable as a result of data flow from a $@ and closing it may result in data loss upon failure, which is not handled explicitly. | tests.go:141:15:141:78 | call to OpenFile | call to OpenFile | | tests.go:166:8:166:8 | f | tests.go:162:2:162:74 | ... := ...[0] | tests.go:166:8:166:8 | f | File handle may be writable as a result of data flow from a $@ and closing it may result in data loss upon failure, which is not handled explicitly. | tests.go:162:12:162:74 | call to OpenFile | call to OpenFile | edges -| tests.go:9:24:9:24 | definition of f | tests.go:10:8:10:8 | f | provenance | | -| tests.go:13:32:13:32 | definition of f | tests.go:14:13:16:2 | capture variable f | provenance | | -| tests.go:14:13:16:2 | capture variable f | tests.go:15:3:15:3 | f | provenance | | +| tests.go:9:24:9:24 | SSA def(f) | tests.go:10:8:10:8 | f | provenance | | +| tests.go:13:32:13:32 | SSA def(f) | tests.go:14:13:16:2 | SSA def(f) | provenance | | +| tests.go:14:13:16:2 | SSA def(f) | tests.go:15:3:15:3 | f | provenance | | | tests.go:32:5:32:78 | ... := ...[0] | tests.go:33:21:33:21 | f | provenance | Src:MaD:1 | | tests.go:32:5:32:78 | ... := ...[0] | tests.go:34:29:34:29 | f | provenance | Src:MaD:1 | -| tests.go:33:21:33:21 | f | tests.go:9:24:9:24 | definition of f | provenance | | -| tests.go:34:29:34:29 | f | tests.go:13:32:13:32 | definition of f | provenance | | +| tests.go:33:21:33:21 | f | tests.go:9:24:9:24 | SSA def(f) | provenance | | +| tests.go:34:29:34:29 | f | tests.go:13:32:13:32 | SSA def(f) | provenance | | | tests.go:46:5:46:76 | ... := ...[0] | tests.go:47:21:47:21 | f | provenance | Src:MaD:1 | | tests.go:46:5:46:76 | ... := ...[0] | tests.go:48:29:48:29 | f | provenance | Src:MaD:1 | -| tests.go:47:21:47:21 | f | tests.go:9:24:9:24 | definition of f | provenance | | -| tests.go:48:29:48:29 | f | tests.go:13:32:13:32 | definition of f | provenance | | +| tests.go:47:21:47:21 | f | tests.go:9:24:9:24 | SSA def(f) | provenance | | +| tests.go:48:29:48:29 | f | tests.go:13:32:13:32 | SSA def(f) | provenance | | | tests.go:55:5:55:78 | ... := ...[0] | tests.go:57:3:57:3 | f | provenance | Src:MaD:1 | | tests.go:67:5:67:76 | ... := ...[0] | tests.go:69:3:69:3 | f | provenance | Src:MaD:1 | | tests.go:124:5:124:78 | ... := ...[0] | tests.go:126:9:126:9 | f | provenance | Src:MaD:1 | @@ -28,10 +28,10 @@ edges models | 1 | Source: os; ; false; OpenFile; ; ; ReturnValue[0]; file; manual | nodes -| tests.go:9:24:9:24 | definition of f | semmle.label | definition of f | +| tests.go:9:24:9:24 | SSA def(f) | semmle.label | SSA def(f) | | tests.go:10:8:10:8 | f | semmle.label | f | -| tests.go:13:32:13:32 | definition of f | semmle.label | definition of f | -| tests.go:14:13:16:2 | capture variable f | semmle.label | capture variable f | +| tests.go:13:32:13:32 | SSA def(f) | semmle.label | SSA def(f) | +| tests.go:14:13:16:2 | SSA def(f) | semmle.label | SSA def(f) | | tests.go:15:3:15:3 | f | semmle.label | f | | tests.go:32:5:32:78 | ... := ...[0] | semmle.label | ... := ...[0] | | tests.go:33:21:33:21 | f | semmle.label | f | diff --git a/go/ql/test/query-tests/Security/CWE-022/UnsafeUnzipSymlink.expected b/go/ql/test/query-tests/Security/CWE-022/UnsafeUnzipSymlink.expected index 3276c077109..73e5f0aa503 100644 --- a/go/ql/test/query-tests/Security/CWE-022/UnsafeUnzipSymlink.expected +++ b/go/ql/test/query-tests/Security/CWE-022/UnsafeUnzipSymlink.expected @@ -5,18 +5,18 @@ | UnsafeUnzipSymlink.go:126:17:126:31 | selection of Linkname | UnsafeUnzipSymlink.go:126:17:126:31 | selection of Linkname | UnsafeUnzipSymlink.go:112:13:112:20 | linkName | Unresolved path from an archive header, which may point outside the archive root, is used in $@. | UnsafeUnzipSymlink.go:112:13:112:20 | linkName | symlink creation | | UnsafeUnzipSymlink.go:126:34:126:44 | selection of Name | UnsafeUnzipSymlink.go:126:34:126:44 | selection of Name | UnsafeUnzipSymlink.go:112:23:112:30 | fileName | Unresolved path from an archive header, which may point outside the archive root, is used in $@. | UnsafeUnzipSymlink.go:112:23:112:30 | fileName | symlink creation | edges -| UnsafeUnzipSymlink.go:111:19:111:26 | definition of linkName | UnsafeUnzipSymlink.go:112:13:112:20 | linkName | provenance | Sink:MaD:1 | -| UnsafeUnzipSymlink.go:111:29:111:36 | definition of fileName | UnsafeUnzipSymlink.go:112:23:112:30 | fileName | provenance | Sink:MaD:1 | -| UnsafeUnzipSymlink.go:126:17:126:31 | selection of Linkname | UnsafeUnzipSymlink.go:111:19:111:26 | definition of linkName | provenance | | -| UnsafeUnzipSymlink.go:126:34:126:44 | selection of Name | UnsafeUnzipSymlink.go:111:29:111:36 | definition of fileName | provenance | | +| UnsafeUnzipSymlink.go:111:19:111:26 | SSA def(linkName) | UnsafeUnzipSymlink.go:112:13:112:20 | linkName | provenance | Sink:MaD:1 | +| UnsafeUnzipSymlink.go:111:29:111:36 | SSA def(fileName) | UnsafeUnzipSymlink.go:112:23:112:30 | fileName | provenance | Sink:MaD:1 | +| UnsafeUnzipSymlink.go:126:17:126:31 | selection of Linkname | UnsafeUnzipSymlink.go:111:19:111:26 | SSA def(linkName) | provenance | | +| UnsafeUnzipSymlink.go:126:34:126:44 | selection of Name | UnsafeUnzipSymlink.go:111:29:111:36 | SSA def(fileName) | provenance | | models | 1 | Sink: os; ; false; Symlink; ; ; Argument[0..1]; path-injection; manual | nodes | UnsafeUnzipSymlink.go:31:15:31:29 | selection of Linkname | semmle.label | selection of Linkname | | UnsafeUnzipSymlink.go:31:32:31:42 | selection of Name | semmle.label | selection of Name | | UnsafeUnzipSymlink.go:43:25:43:35 | selection of Name | semmle.label | selection of Name | -| UnsafeUnzipSymlink.go:111:19:111:26 | definition of linkName | semmle.label | definition of linkName | -| UnsafeUnzipSymlink.go:111:29:111:36 | definition of fileName | semmle.label | definition of fileName | +| UnsafeUnzipSymlink.go:111:19:111:26 | SSA def(linkName) | semmle.label | SSA def(linkName) | +| UnsafeUnzipSymlink.go:111:29:111:36 | SSA def(fileName) | semmle.label | SSA def(fileName) | | UnsafeUnzipSymlink.go:112:13:112:20 | linkName | semmle.label | linkName | | UnsafeUnzipSymlink.go:112:23:112:30 | fileName | semmle.label | fileName | | UnsafeUnzipSymlink.go:126:17:126:31 | selection of Linkname | semmle.label | selection of Linkname | diff --git a/go/ql/test/query-tests/Security/CWE-022/ZipSlip.expected b/go/ql/test/query-tests/Security/CWE-022/ZipSlip.expected index 7cb981667da..3bfd80a120c 100644 --- a/go/ql/test/query-tests/Security/CWE-022/ZipSlip.expected +++ b/go/ql/test/query-tests/Security/CWE-022/ZipSlip.expected @@ -4,12 +4,12 @@ | tarslip.go:15:2:15:30 | ... := ...[0] | tarslip.go:15:2:15:30 | ... := ...[0] | tarslip.go:16:14:16:34 | call to Dir | Unsanitized archive entry, which may contain '..', is used in a $@. | tarslip.go:16:14:16:34 | call to Dir | file system operation | | tst.go:23:2:43:2 | range statement[1] | tst.go:23:2:43:2 | range statement[1] | tst.go:29:20:29:23 | path | Unsanitized archive entry, which may contain '..', is used in a $@. | tst.go:29:20:29:23 | path | file system operation | edges -| UnsafeUnzipSymlinkGood.go:52:24:52:32 | definition of candidate | UnsafeUnzipSymlinkGood.go:61:53:61:61 | candidate | provenance | | +| UnsafeUnzipSymlinkGood.go:52:24:52:32 | SSA def(candidate) | UnsafeUnzipSymlinkGood.go:61:53:61:61 | candidate | provenance | | | UnsafeUnzipSymlinkGood.go:61:53:61:61 | candidate | UnsafeUnzipSymlinkGood.go:61:31:61:62 | call to Join | provenance | FunctionModel Sink:MaD:3 | | UnsafeUnzipSymlinkGood.go:72:3:72:25 | ... := ...[0] | UnsafeUnzipSymlinkGood.go:76:24:76:38 | selection of Linkname | provenance | | | UnsafeUnzipSymlinkGood.go:72:3:72:25 | ... := ...[0] | UnsafeUnzipSymlinkGood.go:76:70:76:80 | selection of Name | provenance | | -| UnsafeUnzipSymlinkGood.go:76:24:76:38 | selection of Linkname | UnsafeUnzipSymlinkGood.go:52:24:52:32 | definition of candidate | provenance | | -| UnsafeUnzipSymlinkGood.go:76:70:76:80 | selection of Name | UnsafeUnzipSymlinkGood.go:52:24:52:32 | definition of candidate | provenance | | +| UnsafeUnzipSymlinkGood.go:76:24:76:38 | selection of Linkname | UnsafeUnzipSymlinkGood.go:52:24:52:32 | SSA def(candidate) | provenance | | +| UnsafeUnzipSymlinkGood.go:76:70:76:80 | selection of Name | UnsafeUnzipSymlinkGood.go:52:24:52:32 | SSA def(candidate) | provenance | | | ZipSlip.go:11:2:15:2 | range statement[1] | ZipSlip.go:12:24:12:29 | selection of Name | provenance | | | ZipSlip.go:12:3:12:30 | ... := ...[0] | ZipSlip.go:14:20:14:20 | p | provenance | Sink:MaD:1 | | ZipSlip.go:12:24:12:29 | selection of Name | ZipSlip.go:12:3:12:30 | ... := ...[0] | provenance | MaD:4 | @@ -23,7 +23,7 @@ models | 4 | Summary: path/filepath; ; false; Abs; ; ; Argument[0]; ReturnValue[0]; taint; manual | | 5 | Summary: path; ; false; Dir; ; ; Argument[0]; ReturnValue; taint; manual | nodes -| UnsafeUnzipSymlinkGood.go:52:24:52:32 | definition of candidate | semmle.label | definition of candidate | +| UnsafeUnzipSymlinkGood.go:52:24:52:32 | SSA def(candidate) | semmle.label | SSA def(candidate) | | UnsafeUnzipSymlinkGood.go:61:31:61:62 | call to Join | semmle.label | call to Join | | UnsafeUnzipSymlinkGood.go:61:53:61:61 | candidate | semmle.label | candidate | | UnsafeUnzipSymlinkGood.go:72:3:72:25 | ... := ...[0] | semmle.label | ... := ...[0] | diff --git a/go/ql/test/query-tests/Security/CWE-078/CommandInjection.expected b/go/ql/test/query-tests/Security/CWE-078/CommandInjection.expected index 78dde84a947..b029c6d2b84 100644 --- a/go/ql/test/query-tests/Security/CWE-078/CommandInjection.expected +++ b/go/ql/test/query-tests/Security/CWE-078/CommandInjection.expected @@ -48,14 +48,14 @@ edges | GitSubcommands.go:11:13:11:27 | call to Query | GitSubcommands.go:17:36:17:42 | tainted | provenance | | | GitSubcommands.go:33:13:33:19 | selection of URL | GitSubcommands.go:33:13:33:27 | call to Query | provenance | Src:MaD:2 MaD:7 | | GitSubcommands.go:33:13:33:27 | call to Query | GitSubcommands.go:38:32:38:38 | tainted | provenance | | -| SanitizingDoubleDash.go:9:2:9:8 | definition of tainted | SanitizingDoubleDash.go:13:25:13:31 | tainted | provenance | | -| SanitizingDoubleDash.go:9:2:9:8 | definition of tainted | SanitizingDoubleDash.go:14:23:14:33 | slice expression | provenance | | -| SanitizingDoubleDash.go:9:2:9:8 | definition of tainted | SanitizingDoubleDash.go:39:31:39:37 | tainted | provenance | Config | -| SanitizingDoubleDash.go:9:2:9:8 | definition of tainted | SanitizingDoubleDash.go:52:24:52:30 | tainted | provenance | Config | -| SanitizingDoubleDash.go:9:2:9:8 | definition of tainted | SanitizingDoubleDash.go:68:31:68:37 | tainted | provenance | Config | -| SanitizingDoubleDash.go:9:2:9:8 | definition of tainted | SanitizingDoubleDash.go:80:23:80:29 | tainted | provenance | Config | +| SanitizingDoubleDash.go:9:2:9:8 | SSA def(tainted) | SanitizingDoubleDash.go:13:25:13:31 | tainted | provenance | | +| SanitizingDoubleDash.go:9:2:9:8 | SSA def(tainted) | SanitizingDoubleDash.go:14:23:14:33 | slice expression | provenance | | +| SanitizingDoubleDash.go:9:2:9:8 | SSA def(tainted) | SanitizingDoubleDash.go:39:31:39:37 | tainted | provenance | Config | +| SanitizingDoubleDash.go:9:2:9:8 | SSA def(tainted) | SanitizingDoubleDash.go:52:24:52:30 | tainted | provenance | Config | +| SanitizingDoubleDash.go:9:2:9:8 | SSA def(tainted) | SanitizingDoubleDash.go:68:31:68:37 | tainted | provenance | Config | +| SanitizingDoubleDash.go:9:2:9:8 | SSA def(tainted) | SanitizingDoubleDash.go:80:23:80:29 | tainted | provenance | Config | | SanitizingDoubleDash.go:9:13:9:19 | selection of URL | SanitizingDoubleDash.go:9:13:9:27 | call to Query | provenance | Src:MaD:2 MaD:7 | -| SanitizingDoubleDash.go:9:13:9:27 | call to Query | SanitizingDoubleDash.go:9:2:9:8 | definition of tainted | provenance | | +| SanitizingDoubleDash.go:9:13:9:27 | call to Query | SanitizingDoubleDash.go:9:2:9:8 | SSA def(tainted) | provenance | | | SanitizingDoubleDash.go:13:15:13:32 | array literal [array] | SanitizingDoubleDash.go:14:23:14:30 | arrayLit [array] | provenance | | | SanitizingDoubleDash.go:13:25:13:31 | tainted | SanitizingDoubleDash.go:13:15:13:32 | array literal [array] | provenance | | | SanitizingDoubleDash.go:14:23:14:30 | arrayLit [array] | SanitizingDoubleDash.go:14:23:14:33 | slice element node | provenance | | @@ -181,7 +181,7 @@ nodes | GitSubcommands.go:33:13:33:19 | selection of URL | semmle.label | selection of URL | | GitSubcommands.go:33:13:33:27 | call to Query | semmle.label | call to Query | | GitSubcommands.go:38:32:38:38 | tainted | semmle.label | tainted | -| SanitizingDoubleDash.go:9:2:9:8 | definition of tainted | semmle.label | definition of tainted | +| SanitizingDoubleDash.go:9:2:9:8 | SSA def(tainted) | semmle.label | SSA def(tainted) | | SanitizingDoubleDash.go:9:13:9:19 | selection of URL | semmle.label | selection of URL | | SanitizingDoubleDash.go:9:13:9:27 | call to Query | semmle.label | call to Query | | SanitizingDoubleDash.go:13:15:13:32 | array literal [array] | semmle.label | array literal [array] | diff --git a/go/ql/test/query-tests/Security/CWE-079/ReflectedXss.expected b/go/ql/test/query-tests/Security/CWE-079/ReflectedXss.expected index b95abaa47c5..3e593f0c202 100644 --- a/go/ql/test/query-tests/Security/CWE-079/ReflectedXss.expected +++ b/go/ql/test/query-tests/Security/CWE-079/ReflectedXss.expected @@ -156,12 +156,3 @@ nodes | websocketXss.go:54:3:54:38 | ... := ...[1] | semmle.label | ... := ...[1] | | websocketXss.go:55:24:55:31 | gorilla3 | semmle.label | gorilla3 | subpaths -testFailures -| websocketXss.go:30:32:30:60 | comment | Missing result: Source[go/reflected-xss] | -| websocketXss.go:31:11:31:14 | xnet [postupdate] | Unexpected result: Source | -| websocketXss.go:34:30:34:58 | comment | Missing result: Source[go/reflected-xss] | -| websocketXss.go:35:21:35:25 | xnet2 [postupdate] | Unexpected result: Source | -| websocketXss.go:46:38:46:66 | comment | Missing result: Source[go/reflected-xss] | -| websocketXss.go:47:26:47:35 | gorillaMsg [postupdate] | Unexpected result: Source | -| websocketXss.go:50:33:50:61 | comment | Missing result: Source[go/reflected-xss] | -| websocketXss.go:51:17:51:24 | gorilla2 [postupdate] | Unexpected result: Source | diff --git a/go/ql/test/query-tests/Security/CWE-079/StoredXss.expected b/go/ql/test/query-tests/Security/CWE-079/StoredXss.expected index 41ec62706d0..cde1a866c75 100644 --- a/go/ql/test/query-tests/Security/CWE-079/StoredXss.expected +++ b/go/ql/test/query-tests/Security/CWE-079/StoredXss.expected @@ -1,20 +1,22 @@ #select +| StoredXss.go:13:21:13:36 | ...+... | StoredXss.go:13:21:13:31 | call to Name | StoredXss.go:13:21:13:36 | ...+... | Stored cross-site scripting vulnerability due to $@. | StoredXss.go:13:21:13:31 | call to Name | stored value | | stored.go:30:22:30:25 | name | stored.go:18:3:18:28 | ... := ...[0] | stored.go:30:22:30:25 | name | Stored cross-site scripting vulnerability due to $@. | stored.go:18:3:18:28 | ... := ...[0] | stored value | -| stored.go:61:22:61:25 | path | stored.go:59:30:59:33 | definition of path | stored.go:61:22:61:25 | path | Stored cross-site scripting vulnerability due to $@. | stored.go:59:30:59:33 | definition of path | stored value | +| stored.go:61:22:61:25 | path | stored.go:59:30:59:33 | SSA def(path) | stored.go:61:22:61:25 | path | Stored cross-site scripting vulnerability due to $@. | stored.go:59:30:59:33 | SSA def(path) | stored value | edges +| StoredXss.go:13:21:13:31 | call to Name | StoredXss.go:13:21:13:36 | ...+... | provenance | | | stored.go:18:3:18:28 | ... := ...[0] | stored.go:25:14:25:17 | rows | provenance | Src:MaD:1 | | stored.go:25:14:25:17 | rows | stored.go:25:29:25:33 | &... [postupdate] | provenance | FunctionModel | | stored.go:25:29:25:33 | &... [postupdate] | stored.go:30:22:30:25 | name | provenance | | -| stored.go:59:30:59:33 | definition of path | stored.go:61:22:61:25 | path | provenance | | +| stored.go:59:30:59:33 | SSA def(path) | stored.go:61:22:61:25 | path | provenance | | models | 1 | Source: database/sql; DB; true; Query; ; ; ReturnValue[0]; database; manual | nodes +| StoredXss.go:13:21:13:31 | call to Name | semmle.label | call to Name | +| StoredXss.go:13:21:13:36 | ...+... | semmle.label | ...+... | | stored.go:18:3:18:28 | ... := ...[0] | semmle.label | ... := ...[0] | | stored.go:25:14:25:17 | rows | semmle.label | rows | | stored.go:25:29:25:33 | &... [postupdate] | semmle.label | &... [postupdate] | | stored.go:30:22:30:25 | name | semmle.label | name | -| stored.go:59:30:59:33 | definition of path | semmle.label | definition of path | +| stored.go:59:30:59:33 | SSA def(path) | semmle.label | SSA def(path) | | stored.go:61:22:61:25 | path | semmle.label | path | subpaths -testFailures -| StoredXss.go:13:39:13:63 | comment | Missing result: Alert[go/stored-xss] | diff --git a/go/ql/test/query-tests/Security/CWE-079/websocketXss.go b/go/ql/test/query-tests/Security/CWE-079/websocketXss.go index aa8bc8e41ad..eadc87b2c9f 100644 --- a/go/ql/test/query-tests/Security/CWE-079/websocketXss.go +++ b/go/ql/test/query-tests/Security/CWE-079/websocketXss.go @@ -27,12 +27,12 @@ func xss(w http.ResponseWriter, r *http.Request) { origin := "test" { ws, _ := websocket.Dial(uri, "", origin) - var xnet = make([]byte, 512) // $ Source[go/reflected-xss] - ws.Read(xnet) + var xnet = make([]byte, 512) + ws.Read(xnet) // $ Source[go/reflected-xss] fmt.Fprintf(w, "%v", xnet) // $ Alert[go/reflected-xss] codec := &websocket.Codec{Marshal: marshal, Unmarshal: unmarshal} - xnet2 := make([]byte, 512) // $ Source[go/reflected-xss] - codec.Receive(ws, xnet2) + xnet2 := make([]byte, 512) + codec.Receive(ws, xnet2) // $ Source[go/reflected-xss] fmt.Fprintf(w, "%v", xnet2) // $ Alert[go/reflected-xss] } { @@ -43,12 +43,12 @@ func xss(w http.ResponseWriter, r *http.Request) { { dialer := gorilla.Dialer{} conn, _, _ := dialer.Dial(uri, nil) - var gorillaMsg = make([]byte, 512) // $ Source[go/reflected-xss] - gorilla.ReadJSON(conn, gorillaMsg) - fmt.Fprintf(w, "%v", gorillaMsg) // $ Alert[go/reflected-xss] + var gorillaMsg = make([]byte, 512) + gorilla.ReadJSON(conn, gorillaMsg) // $ Source[go/reflected-xss] + fmt.Fprintf(w, "%v", gorillaMsg) // $ Alert[go/reflected-xss] - gorilla2 := make([]byte, 512) // $ Source[go/reflected-xss] - conn.ReadJSON(gorilla2) + gorilla2 := make([]byte, 512) + conn.ReadJSON(gorilla2) // $ Source[go/reflected-xss] fmt.Fprintf(w, "%v", gorilla2) // $ Alert[go/reflected-xss] _, gorilla3, _ := conn.ReadMessage() // $ Source[go/reflected-xss] diff --git a/go/ql/test/query-tests/Security/CWE-312/CleartextLogging.expected b/go/ql/test/query-tests/Security/CWE-312/CleartextLogging.expected index 66392b22752..7a195352f39 100644 --- a/go/ql/test/query-tests/Security/CWE-312/CleartextLogging.expected +++ b/go/ql/test/query-tests/Security/CWE-312/CleartextLogging.expected @@ -1,80 +1,80 @@ #select | klog.go:23:15:23:20 | header | klog.go:21:30:21:37 | selection of Header | klog.go:23:15:23:20 | header | $@ flows to a logging call. | klog.go:21:30:21:37 | selection of Header | Sensitive data returned by HTTP request headers | | klog.go:29:13:29:41 | call to Get | klog.go:29:13:29:20 | selection of Header | klog.go:29:13:29:41 | call to Get | $@ flows to a logging call. | klog.go:29:13:29:20 | selection of Header | Sensitive data returned by HTTP request headers | -| main.go:19:12:19:19 | password | main.go:17:2:17:9 | definition of password | main.go:19:12:19:19 | password | $@ flows to a logging call. | main.go:17:2:17:9 | definition of password | Sensitive data returned by an access to password | -| main.go:20:19:20:26 | password | main.go:17:2:17:9 | definition of password | main.go:20:19:20:26 | password | $@ flows to a logging call. | main.go:17:2:17:9 | definition of password | Sensitive data returned by an access to password | -| main.go:21:13:21:20 | password | main.go:17:2:17:9 | definition of password | main.go:21:13:21:20 | password | $@ flows to a logging call. | main.go:17:2:17:9 | definition of password | Sensitive data returned by an access to password | -| main.go:22:14:22:21 | password | main.go:17:2:17:9 | definition of password | main.go:22:14:22:21 | password | $@ flows to a logging call. | main.go:17:2:17:9 | definition of password | Sensitive data returned by an access to password | -| main.go:24:13:24:20 | password | main.go:17:2:17:9 | definition of password | main.go:24:13:24:20 | password | $@ flows to a logging call. | main.go:17:2:17:9 | definition of password | Sensitive data returned by an access to password | -| main.go:27:20:27:27 | password | main.go:17:2:17:9 | definition of password | main.go:27:20:27:27 | password | $@ flows to a logging call. | main.go:17:2:17:9 | definition of password | Sensitive data returned by an access to password | -| main.go:30:14:30:21 | password | main.go:17:2:17:9 | definition of password | main.go:30:14:30:21 | password | $@ flows to a logging call. | main.go:17:2:17:9 | definition of password | Sensitive data returned by an access to password | -| main.go:33:15:33:22 | password | main.go:17:2:17:9 | definition of password | main.go:33:15:33:22 | password | $@ flows to a logging call. | main.go:17:2:17:9 | definition of password | Sensitive data returned by an access to password | -| main.go:36:13:36:20 | password | main.go:17:2:17:9 | definition of password | main.go:36:13:36:20 | password | $@ flows to a logging call. | main.go:17:2:17:9 | definition of password | Sensitive data returned by an access to password | -| main.go:39:20:39:27 | password | main.go:17:2:17:9 | definition of password | main.go:39:20:39:27 | password | $@ flows to a logging call. | main.go:17:2:17:9 | definition of password | Sensitive data returned by an access to password | -| main.go:42:14:42:21 | password | main.go:17:2:17:9 | definition of password | main.go:42:14:42:21 | password | $@ flows to a logging call. | main.go:17:2:17:9 | definition of password | Sensitive data returned by an access to password | -| main.go:45:15:45:22 | password | main.go:17:2:17:9 | definition of password | main.go:45:15:45:22 | password | $@ flows to a logging call. | main.go:17:2:17:9 | definition of password | Sensitive data returned by an access to password | -| main.go:47:16:47:23 | password | main.go:17:2:17:9 | definition of password | main.go:47:16:47:23 | password | $@ flows to a logging call. | main.go:17:2:17:9 | definition of password | Sensitive data returned by an access to password | -| main.go:51:10:51:17 | password | main.go:17:2:17:9 | definition of password | main.go:51:10:51:17 | password | $@ flows to a logging call. | main.go:17:2:17:9 | definition of password | Sensitive data returned by an access to password | -| main.go:52:17:52:24 | password | main.go:17:2:17:9 | definition of password | main.go:52:17:52:24 | password | $@ flows to a logging call. | main.go:17:2:17:9 | definition of password | Sensitive data returned by an access to password | -| main.go:53:11:53:18 | password | main.go:17:2:17:9 | definition of password | main.go:53:11:53:18 | password | $@ flows to a logging call. | main.go:17:2:17:9 | definition of password | Sensitive data returned by an access to password | -| main.go:54:12:54:19 | password | main.go:17:2:17:9 | definition of password | main.go:54:12:54:19 | password | $@ flows to a logging call. | main.go:17:2:17:9 | definition of password | Sensitive data returned by an access to password | -| main.go:56:11:56:18 | password | main.go:17:2:17:9 | definition of password | main.go:56:11:56:18 | password | $@ flows to a logging call. | main.go:17:2:17:9 | definition of password | Sensitive data returned by an access to password | -| main.go:59:18:59:25 | password | main.go:17:2:17:9 | definition of password | main.go:59:18:59:25 | password | $@ flows to a logging call. | main.go:17:2:17:9 | definition of password | Sensitive data returned by an access to password | -| main.go:62:12:62:19 | password | main.go:17:2:17:9 | definition of password | main.go:62:12:62:19 | password | $@ flows to a logging call. | main.go:17:2:17:9 | definition of password | Sensitive data returned by an access to password | -| main.go:65:13:65:20 | password | main.go:17:2:17:9 | definition of password | main.go:65:13:65:20 | password | $@ flows to a logging call. | main.go:17:2:17:9 | definition of password | Sensitive data returned by an access to password | -| main.go:68:11:68:18 | password | main.go:17:2:17:9 | definition of password | main.go:68:11:68:18 | password | $@ flows to a logging call. | main.go:17:2:17:9 | definition of password | Sensitive data returned by an access to password | -| main.go:71:18:71:25 | password | main.go:17:2:17:9 | definition of password | main.go:71:18:71:25 | password | $@ flows to a logging call. | main.go:17:2:17:9 | definition of password | Sensitive data returned by an access to password | -| main.go:74:12:74:19 | password | main.go:17:2:17:9 | definition of password | main.go:74:12:74:19 | password | $@ flows to a logging call. | main.go:17:2:17:9 | definition of password | Sensitive data returned by an access to password | -| main.go:77:13:77:20 | password | main.go:17:2:17:9 | definition of password | main.go:77:13:77:20 | password | $@ flows to a logging call. | main.go:17:2:17:9 | definition of password | Sensitive data returned by an access to password | -| main.go:79:14:79:21 | password | main.go:17:2:17:9 | definition of password | main.go:79:14:79:21 | password | $@ flows to a logging call. | main.go:17:2:17:9 | definition of password | Sensitive data returned by an access to password | -| main.go:82:12:82:19 | password | main.go:17:2:17:9 | definition of password | main.go:82:12:82:19 | password | $@ flows to a logging call. | main.go:17:2:17:9 | definition of password | Sensitive data returned by an access to password | -| main.go:83:17:83:24 | password | main.go:17:2:17:9 | definition of password | main.go:83:17:83:24 | password | $@ flows to a logging call. | main.go:17:2:17:9 | definition of password | Sensitive data returned by an access to password | -| main.go:87:29:87:34 | fields | main.go:17:2:17:9 | definition of password | main.go:87:29:87:34 | fields | $@ flows to a logging call. | main.go:17:2:17:9 | definition of password | Sensitive data returned by an access to password | -| main.go:90:35:90:42 | password | main.go:17:2:17:9 | definition of password | main.go:90:35:90:42 | password | $@ flows to a logging call. | main.go:17:2:17:9 | definition of password | Sensitive data returned by an access to password | -| overrides.go:13:14:13:23 | call to String | overrides.go:8:2:8:9 | definition of password | overrides.go:13:14:13:23 | call to String | $@ flows to a logging call. | overrides.go:8:2:8:9 | definition of password | Sensitive data returned by an access to password | -| passwords.go:9:14:9:14 | x | passwords.go:21:2:21:9 | definition of password | passwords.go:9:14:9:14 | x | $@ flows to a logging call. | passwords.go:21:2:21:9 | definition of password | Sensitive data returned by an access to password | -| passwords.go:25:14:25:21 | password | passwords.go:21:2:21:9 | definition of password | passwords.go:25:14:25:21 | password | $@ flows to a logging call. | passwords.go:21:2:21:9 | definition of password | Sensitive data returned by an access to password | +| main.go:19:12:19:19 | password | main.go:17:2:17:9 | SSA def(password) | main.go:19:12:19:19 | password | $@ flows to a logging call. | main.go:17:2:17:9 | SSA def(password) | Sensitive data returned by an access to password | +| main.go:20:19:20:26 | password | main.go:17:2:17:9 | SSA def(password) | main.go:20:19:20:26 | password | $@ flows to a logging call. | main.go:17:2:17:9 | SSA def(password) | Sensitive data returned by an access to password | +| main.go:21:13:21:20 | password | main.go:17:2:17:9 | SSA def(password) | main.go:21:13:21:20 | password | $@ flows to a logging call. | main.go:17:2:17:9 | SSA def(password) | Sensitive data returned by an access to password | +| main.go:22:14:22:21 | password | main.go:17:2:17:9 | SSA def(password) | main.go:22:14:22:21 | password | $@ flows to a logging call. | main.go:17:2:17:9 | SSA def(password) | Sensitive data returned by an access to password | +| main.go:24:13:24:20 | password | main.go:17:2:17:9 | SSA def(password) | main.go:24:13:24:20 | password | $@ flows to a logging call. | main.go:17:2:17:9 | SSA def(password) | Sensitive data returned by an access to password | +| main.go:27:20:27:27 | password | main.go:17:2:17:9 | SSA def(password) | main.go:27:20:27:27 | password | $@ flows to a logging call. | main.go:17:2:17:9 | SSA def(password) | Sensitive data returned by an access to password | +| main.go:30:14:30:21 | password | main.go:17:2:17:9 | SSA def(password) | main.go:30:14:30:21 | password | $@ flows to a logging call. | main.go:17:2:17:9 | SSA def(password) | Sensitive data returned by an access to password | +| main.go:33:15:33:22 | password | main.go:17:2:17:9 | SSA def(password) | main.go:33:15:33:22 | password | $@ flows to a logging call. | main.go:17:2:17:9 | SSA def(password) | Sensitive data returned by an access to password | +| main.go:36:13:36:20 | password | main.go:17:2:17:9 | SSA def(password) | main.go:36:13:36:20 | password | $@ flows to a logging call. | main.go:17:2:17:9 | SSA def(password) | Sensitive data returned by an access to password | +| main.go:39:20:39:27 | password | main.go:17:2:17:9 | SSA def(password) | main.go:39:20:39:27 | password | $@ flows to a logging call. | main.go:17:2:17:9 | SSA def(password) | Sensitive data returned by an access to password | +| main.go:42:14:42:21 | password | main.go:17:2:17:9 | SSA def(password) | main.go:42:14:42:21 | password | $@ flows to a logging call. | main.go:17:2:17:9 | SSA def(password) | Sensitive data returned by an access to password | +| main.go:45:15:45:22 | password | main.go:17:2:17:9 | SSA def(password) | main.go:45:15:45:22 | password | $@ flows to a logging call. | main.go:17:2:17:9 | SSA def(password) | Sensitive data returned by an access to password | +| main.go:47:16:47:23 | password | main.go:17:2:17:9 | SSA def(password) | main.go:47:16:47:23 | password | $@ flows to a logging call. | main.go:17:2:17:9 | SSA def(password) | Sensitive data returned by an access to password | +| main.go:51:10:51:17 | password | main.go:17:2:17:9 | SSA def(password) | main.go:51:10:51:17 | password | $@ flows to a logging call. | main.go:17:2:17:9 | SSA def(password) | Sensitive data returned by an access to password | +| main.go:52:17:52:24 | password | main.go:17:2:17:9 | SSA def(password) | main.go:52:17:52:24 | password | $@ flows to a logging call. | main.go:17:2:17:9 | SSA def(password) | Sensitive data returned by an access to password | +| main.go:53:11:53:18 | password | main.go:17:2:17:9 | SSA def(password) | main.go:53:11:53:18 | password | $@ flows to a logging call. | main.go:17:2:17:9 | SSA def(password) | Sensitive data returned by an access to password | +| main.go:54:12:54:19 | password | main.go:17:2:17:9 | SSA def(password) | main.go:54:12:54:19 | password | $@ flows to a logging call. | main.go:17:2:17:9 | SSA def(password) | Sensitive data returned by an access to password | +| main.go:56:11:56:18 | password | main.go:17:2:17:9 | SSA def(password) | main.go:56:11:56:18 | password | $@ flows to a logging call. | main.go:17:2:17:9 | SSA def(password) | Sensitive data returned by an access to password | +| main.go:59:18:59:25 | password | main.go:17:2:17:9 | SSA def(password) | main.go:59:18:59:25 | password | $@ flows to a logging call. | main.go:17:2:17:9 | SSA def(password) | Sensitive data returned by an access to password | +| main.go:62:12:62:19 | password | main.go:17:2:17:9 | SSA def(password) | main.go:62:12:62:19 | password | $@ flows to a logging call. | main.go:17:2:17:9 | SSA def(password) | Sensitive data returned by an access to password | +| main.go:65:13:65:20 | password | main.go:17:2:17:9 | SSA def(password) | main.go:65:13:65:20 | password | $@ flows to a logging call. | main.go:17:2:17:9 | SSA def(password) | Sensitive data returned by an access to password | +| main.go:68:11:68:18 | password | main.go:17:2:17:9 | SSA def(password) | main.go:68:11:68:18 | password | $@ flows to a logging call. | main.go:17:2:17:9 | SSA def(password) | Sensitive data returned by an access to password | +| main.go:71:18:71:25 | password | main.go:17:2:17:9 | SSA def(password) | main.go:71:18:71:25 | password | $@ flows to a logging call. | main.go:17:2:17:9 | SSA def(password) | Sensitive data returned by an access to password | +| main.go:74:12:74:19 | password | main.go:17:2:17:9 | SSA def(password) | main.go:74:12:74:19 | password | $@ flows to a logging call. | main.go:17:2:17:9 | SSA def(password) | Sensitive data returned by an access to password | +| main.go:77:13:77:20 | password | main.go:17:2:17:9 | SSA def(password) | main.go:77:13:77:20 | password | $@ flows to a logging call. | main.go:17:2:17:9 | SSA def(password) | Sensitive data returned by an access to password | +| main.go:79:14:79:21 | password | main.go:17:2:17:9 | SSA def(password) | main.go:79:14:79:21 | password | $@ flows to a logging call. | main.go:17:2:17:9 | SSA def(password) | Sensitive data returned by an access to password | +| main.go:82:12:82:19 | password | main.go:17:2:17:9 | SSA def(password) | main.go:82:12:82:19 | password | $@ flows to a logging call. | main.go:17:2:17:9 | SSA def(password) | Sensitive data returned by an access to password | +| main.go:83:17:83:24 | password | main.go:17:2:17:9 | SSA def(password) | main.go:83:17:83:24 | password | $@ flows to a logging call. | main.go:17:2:17:9 | SSA def(password) | Sensitive data returned by an access to password | +| main.go:87:29:87:34 | fields | main.go:17:2:17:9 | SSA def(password) | main.go:87:29:87:34 | fields | $@ flows to a logging call. | main.go:17:2:17:9 | SSA def(password) | Sensitive data returned by an access to password | +| main.go:90:35:90:42 | password | main.go:17:2:17:9 | SSA def(password) | main.go:90:35:90:42 | password | $@ flows to a logging call. | main.go:17:2:17:9 | SSA def(password) | Sensitive data returned by an access to password | +| overrides.go:13:14:13:23 | call to String | overrides.go:8:2:8:9 | SSA def(password) | overrides.go:13:14:13:23 | call to String | $@ flows to a logging call. | overrides.go:8:2:8:9 | SSA def(password) | Sensitive data returned by an access to password | +| passwords.go:9:14:9:14 | x | passwords.go:21:2:21:9 | SSA def(password) | passwords.go:9:14:9:14 | x | $@ flows to a logging call. | passwords.go:21:2:21:9 | SSA def(password) | Sensitive data returned by an access to password | +| passwords.go:25:14:25:21 | password | passwords.go:21:2:21:9 | SSA def(password) | passwords.go:25:14:25:21 | password | $@ flows to a logging call. | passwords.go:21:2:21:9 | SSA def(password) | Sensitive data returned by an access to password | | passwords.go:26:14:26:23 | selection of password | passwords.go:26:14:26:23 | selection of password | passwords.go:26:14:26:23 | selection of password | $@ flows to a logging call. | passwords.go:26:14:26:23 | selection of password | Sensitive data returned by an access to password | | passwords.go:27:14:27:26 | call to getPassword | passwords.go:27:14:27:26 | call to getPassword | passwords.go:27:14:27:26 | call to getPassword | $@ flows to a logging call. | passwords.go:27:14:27:26 | call to getPassword | Sensitive data returned by a call to getPassword | | passwords.go:28:14:28:28 | call to getPassword | passwords.go:28:14:28:28 | call to getPassword | passwords.go:28:14:28:28 | call to getPassword | $@ flows to a logging call. | passwords.go:28:14:28:28 | call to getPassword | Sensitive data returned by a call to getPassword | -| passwords.go:33:13:33:20 | password | passwords.go:21:2:21:9 | definition of password | passwords.go:33:13:33:20 | password | $@ flows to a logging call. | passwords.go:21:2:21:9 | definition of password | Sensitive data returned by an access to password | -| passwords.go:36:14:36:35 | ...+... | passwords.go:21:2:21:9 | definition of password | passwords.go:36:14:36:35 | ...+... | $@ flows to a logging call. | passwords.go:21:2:21:9 | definition of password | Sensitive data returned by an access to password | +| passwords.go:33:13:33:20 | password | passwords.go:21:2:21:9 | SSA def(password) | passwords.go:33:13:33:20 | password | $@ flows to a logging call. | passwords.go:21:2:21:9 | SSA def(password) | Sensitive data returned by an access to password | +| passwords.go:36:14:36:35 | ...+... | passwords.go:21:2:21:9 | SSA def(password) | passwords.go:36:14:36:35 | ...+... | $@ flows to a logging call. | passwords.go:21:2:21:9 | SSA def(password) | Sensitive data returned by an access to password | | passwords.go:41:14:41:17 | obj1 | passwords.go:39:13:39:13 | x | passwords.go:41:14:41:17 | obj1 | $@ flows to a logging call. | passwords.go:39:13:39:13 | x | Sensitive data returned by an access to password | -| passwords.go:46:14:46:17 | obj2 | passwords.go:21:2:21:9 | definition of password | passwords.go:46:14:46:17 | obj2 | $@ flows to a logging call. | passwords.go:21:2:21:9 | definition of password | Sensitive data returned by an access to password | -| passwords.go:53:14:53:27 | fixed_password | passwords.go:52:2:52:15 | definition of fixed_password | passwords.go:53:14:53:27 | fixed_password | $@ flows to a logging call. | passwords.go:52:2:52:15 | definition of fixed_password | Sensitive data returned by an access to fixed_password | +| passwords.go:46:14:46:17 | obj2 | passwords.go:21:2:21:9 | SSA def(password) | passwords.go:46:14:46:17 | obj2 | $@ flows to a logging call. | passwords.go:21:2:21:9 | SSA def(password) | Sensitive data returned by an access to password | +| passwords.go:53:14:53:27 | fixed_password | passwords.go:52:2:52:15 | SSA def(fixed_password) | passwords.go:53:14:53:27 | fixed_password | $@ flows to a logging call. | passwords.go:52:2:52:15 | SSA def(fixed_password) | Sensitive data returned by an access to fixed_password | | passwords.go:91:14:91:26 | utilityObject | passwords.go:89:16:89:36 | call to make | passwords.go:91:14:91:26 | utilityObject | $@ flows to a logging call. | passwords.go:89:16:89:36 | call to make | Sensitive data returned by an access to passwordSet | -| passwords.go:94:23:94:28 | secret | passwords.go:21:2:21:9 | definition of password | passwords.go:94:23:94:28 | secret | $@ flows to a logging call. | passwords.go:21:2:21:9 | definition of password | Sensitive data returned by an access to password | -| passwords.go:104:15:104:40 | ...+... | passwords.go:21:2:21:9 | definition of password | passwords.go:104:15:104:40 | ...+... | $@ flows to a logging call. | passwords.go:21:2:21:9 | definition of password | Sensitive data returned by an access to password | -| passwords.go:110:16:110:41 | ...+... | passwords.go:21:2:21:9 | definition of password | passwords.go:110:16:110:41 | ...+... | $@ flows to a logging call. | passwords.go:21:2:21:9 | definition of password | Sensitive data returned by an access to password | -| passwords.go:115:15:115:40 | ...+... | passwords.go:21:2:21:9 | definition of password | passwords.go:115:15:115:40 | ...+... | $@ flows to a logging call. | passwords.go:21:2:21:9 | definition of password | Sensitive data returned by an access to password | -| passwords.go:119:14:119:45 | ...+... | passwords.go:118:6:118:14 | definition of password1 | passwords.go:119:14:119:45 | ...+... | $@ flows to a logging call. | passwords.go:118:6:118:14 | definition of password1 | Sensitive data returned by an access to password1 | -| passwords.go:129:14:129:19 | config | passwords.go:21:2:21:9 | definition of password | passwords.go:129:14:129:19 | config | $@ flows to a logging call. | passwords.go:21:2:21:9 | definition of password | Sensitive data returned by an access to password | +| passwords.go:94:23:94:28 | secret | passwords.go:21:2:21:9 | SSA def(password) | passwords.go:94:23:94:28 | secret | $@ flows to a logging call. | passwords.go:21:2:21:9 | SSA def(password) | Sensitive data returned by an access to password | +| passwords.go:104:15:104:40 | ...+... | passwords.go:21:2:21:9 | SSA def(password) | passwords.go:104:15:104:40 | ...+... | $@ flows to a logging call. | passwords.go:21:2:21:9 | SSA def(password) | Sensitive data returned by an access to password | +| passwords.go:110:16:110:41 | ...+... | passwords.go:21:2:21:9 | SSA def(password) | passwords.go:110:16:110:41 | ...+... | $@ flows to a logging call. | passwords.go:21:2:21:9 | SSA def(password) | Sensitive data returned by an access to password | +| passwords.go:115:15:115:40 | ...+... | passwords.go:21:2:21:9 | SSA def(password) | passwords.go:115:15:115:40 | ...+... | $@ flows to a logging call. | passwords.go:21:2:21:9 | SSA def(password) | Sensitive data returned by an access to password | +| passwords.go:119:14:119:45 | ...+... | passwords.go:118:6:118:14 | SSA def(password1) | passwords.go:119:14:119:45 | ...+... | $@ flows to a logging call. | passwords.go:118:6:118:14 | SSA def(password1) | Sensitive data returned by an access to password1 | +| passwords.go:129:14:129:19 | config | passwords.go:21:2:21:9 | SSA def(password) | passwords.go:129:14:129:19 | config | $@ flows to a logging call. | passwords.go:21:2:21:9 | SSA def(password) | Sensitive data returned by an access to password | | passwords.go:129:14:129:19 | config | passwords.go:123:13:123:14 | x3 | passwords.go:129:14:129:19 | config | $@ flows to a logging call. | passwords.go:123:13:123:14 | x3 | Sensitive data returned by an access to password | | passwords.go:129:14:129:19 | config | passwords.go:126:13:126:25 | call to getPassword | passwords.go:129:14:129:19 | config | $@ flows to a logging call. | passwords.go:126:13:126:25 | call to getPassword | Sensitive data returned by a call to getPassword | -| passwords.go:130:14:130:21 | selection of x | passwords.go:21:2:21:9 | definition of password | passwords.go:130:14:130:21 | selection of x | $@ flows to a logging call. | passwords.go:21:2:21:9 | definition of password | Sensitive data returned by an access to password | +| passwords.go:130:14:130:21 | selection of x | passwords.go:21:2:21:9 | SSA def(password) | passwords.go:130:14:130:21 | selection of x | $@ flows to a logging call. | passwords.go:21:2:21:9 | SSA def(password) | Sensitive data returned by an access to password | | passwords.go:131:14:131:21 | selection of y | passwords.go:126:13:126:25 | call to getPassword | passwords.go:131:14:131:21 | selection of y | $@ flows to a logging call. | passwords.go:126:13:126:25 | call to getPassword | Sensitive data returned by a call to getPassword | -| protobuf.go:14:14:14:35 | call to GetDescription | protobuf.go:9:2:9:9 | definition of password | protobuf.go:14:14:14:35 | call to GetDescription | $@ flows to a logging call. | protobuf.go:9:2:9:9 | definition of password | Sensitive data returned by an access to password | +| protobuf.go:14:14:14:35 | call to GetDescription | protobuf.go:9:2:9:9 | SSA def(password) | protobuf.go:14:14:14:35 | call to GetDescription | $@ flows to a logging call. | protobuf.go:9:2:9:9 | SSA def(password) | Sensitive data returned by an access to password | edges | klog.go:21:3:26:3 | range statement[1] | klog.go:22:27:22:33 | headers | provenance | | | klog.go:21:30:21:37 | selection of Header | klog.go:21:3:26:3 | range statement[1] | provenance | Src:MaD:11 Config | | klog.go:22:4:25:4 | range statement[1] | klog.go:23:15:23:20 | header | provenance | | | klog.go:22:27:22:33 | headers | klog.go:22:4:25:4 | range statement[1] | provenance | Config | | klog.go:29:13:29:20 | selection of Header | klog.go:29:13:29:41 | call to Get | provenance | Src:MaD:11 Config | -| main.go:17:2:17:9 | definition of password | main.go:19:12:19:19 | password | provenance | | -| main.go:17:2:17:9 | definition of password | main.go:20:19:20:26 | password | provenance | | -| main.go:17:2:17:9 | definition of password | main.go:21:13:21:20 | password | provenance | Sink:MaD:6 | -| main.go:17:2:17:9 | definition of password | main.go:22:14:22:21 | password | provenance | | -| main.go:17:2:17:9 | definition of password | main.go:24:13:24:20 | password | provenance | | -| main.go:17:2:17:9 | definition of password | main.go:27:20:27:27 | password | provenance | | -| main.go:17:2:17:9 | definition of password | main.go:30:14:30:21 | password | provenance | Sink:MaD:3 | -| main.go:17:2:17:9 | definition of password | main.go:33:15:33:22 | password | provenance | | -| main.go:17:2:17:9 | definition of password | main.go:36:13:36:20 | password | provenance | | -| main.go:17:2:17:9 | definition of password | main.go:39:20:39:27 | password | provenance | | -| main.go:17:2:17:9 | definition of password | main.go:42:14:42:21 | password | provenance | Sink:MaD:5 | -| main.go:17:2:17:9 | definition of password | main.go:45:15:45:22 | password | provenance | | -| main.go:17:2:17:9 | definition of password | main.go:47:16:47:23 | password | provenance | Sink:MaD:4 | -| main.go:17:2:17:9 | definition of password | main.go:51:10:51:17 | password | provenance | | -| main.go:17:2:17:9 | definition of password | main.go:51:10:51:17 | password | provenance | | +| main.go:17:2:17:9 | SSA def(password) | main.go:19:12:19:19 | password | provenance | | +| main.go:17:2:17:9 | SSA def(password) | main.go:20:19:20:26 | password | provenance | | +| main.go:17:2:17:9 | SSA def(password) | main.go:21:13:21:20 | password | provenance | Sink:MaD:6 | +| main.go:17:2:17:9 | SSA def(password) | main.go:22:14:22:21 | password | provenance | | +| main.go:17:2:17:9 | SSA def(password) | main.go:24:13:24:20 | password | provenance | | +| main.go:17:2:17:9 | SSA def(password) | main.go:27:20:27:27 | password | provenance | | +| main.go:17:2:17:9 | SSA def(password) | main.go:30:14:30:21 | password | provenance | Sink:MaD:3 | +| main.go:17:2:17:9 | SSA def(password) | main.go:33:15:33:22 | password | provenance | | +| main.go:17:2:17:9 | SSA def(password) | main.go:36:13:36:20 | password | provenance | | +| main.go:17:2:17:9 | SSA def(password) | main.go:39:20:39:27 | password | provenance | | +| main.go:17:2:17:9 | SSA def(password) | main.go:42:14:42:21 | password | provenance | Sink:MaD:5 | +| main.go:17:2:17:9 | SSA def(password) | main.go:45:15:45:22 | password | provenance | | +| main.go:17:2:17:9 | SSA def(password) | main.go:47:16:47:23 | password | provenance | Sink:MaD:4 | +| main.go:17:2:17:9 | SSA def(password) | main.go:51:10:51:17 | password | provenance | | +| main.go:17:2:17:9 | SSA def(password) | main.go:51:10:51:17 | password | provenance | | | main.go:51:10:51:17 | password | main.go:52:17:52:24 | password | provenance | | | main.go:51:10:51:17 | password | main.go:52:17:52:24 | password | provenance | | | main.go:52:17:52:24 | password | main.go:53:11:53:18 | password | provenance | | @@ -97,14 +97,14 @@ edges | main.go:86:2:86:7 | fields [postupdate] | main.go:87:29:87:34 | fields | provenance | Sink:MaD:2 | | main.go:86:19:86:26 | password | main.go:86:2:86:7 | fields [postupdate] | provenance | Config | | main.go:86:19:86:26 | password | main.go:90:35:90:42 | password | provenance | Sink:MaD:1 | -| overrides.go:8:2:8:9 | definition of password | overrides.go:9:9:9:16 | password | provenance | | +| overrides.go:8:2:8:9 | SSA def(password) | overrides.go:9:9:9:16 | password | provenance | | | overrides.go:9:9:9:16 | password | overrides.go:13:14:13:23 | call to String | provenance | | -| passwords.go:8:12:8:12 | definition of x | passwords.go:9:14:9:14 | x | provenance | | -| passwords.go:21:2:21:9 | definition of password | passwords.go:25:14:25:21 | password | provenance | | -| passwords.go:21:2:21:9 | definition of password | passwords.go:30:8:30:15 | password | provenance | | -| passwords.go:21:2:21:9 | definition of password | passwords.go:33:13:33:20 | password | provenance | | -| passwords.go:21:2:21:9 | definition of password | passwords.go:36:28:36:35 | password | provenance | | -| passwords.go:30:8:30:15 | password | passwords.go:8:12:8:12 | definition of x | provenance | | +| passwords.go:8:12:8:12 | SSA def(x) | passwords.go:9:14:9:14 | x | provenance | | +| passwords.go:21:2:21:9 | SSA def(password) | passwords.go:25:14:25:21 | password | provenance | | +| passwords.go:21:2:21:9 | SSA def(password) | passwords.go:30:8:30:15 | password | provenance | | +| passwords.go:21:2:21:9 | SSA def(password) | passwords.go:33:13:33:20 | password | provenance | | +| passwords.go:21:2:21:9 | SSA def(password) | passwords.go:36:28:36:35 | password | provenance | | +| passwords.go:30:8:30:15 | password | passwords.go:8:12:8:12 | SSA def(x) | provenance | | | passwords.go:36:28:36:35 | password | passwords.go:36:14:36:35 | ...+... | provenance | Config | | passwords.go:36:28:36:35 | password | passwords.go:44:6:44:13 | password | provenance | | | passwords.go:38:10:40:2 | struct literal | passwords.go:41:14:41:17 | obj1 | provenance | | @@ -117,7 +117,7 @@ edges | passwords.go:50:11:50:18 | password | passwords.go:110:34:110:41 | password | provenance | | | passwords.go:50:11:50:18 | password | passwords.go:115:33:115:40 | password | provenance | | | passwords.go:50:11:50:18 | password | passwords.go:125:13:125:20 | password | provenance | | -| passwords.go:52:2:52:15 | definition of fixed_password | passwords.go:53:14:53:27 | fixed_password | provenance | | +| passwords.go:52:2:52:15 | SSA def(fixed_password) | passwords.go:53:14:53:27 | fixed_password | provenance | | | passwords.go:88:19:90:2 | struct literal | passwords.go:91:14:91:26 | utilityObject | provenance | | | passwords.go:89:16:89:36 | call to make | passwords.go:88:19:90:2 | struct literal | provenance | Config | | passwords.go:104:33:104:40 | password | passwords.go:104:15:104:40 | ...+... | provenance | Config | @@ -129,7 +129,7 @@ edges | passwords.go:110:34:110:41 | password | passwords.go:125:13:125:20 | password | provenance | | | passwords.go:115:33:115:40 | password | passwords.go:115:15:115:40 | ...+... | provenance | Config | | passwords.go:115:33:115:40 | password | passwords.go:125:13:125:20 | password | provenance | | -| passwords.go:118:6:118:14 | definition of password1 | passwords.go:119:28:119:36 | password1 | provenance | | +| passwords.go:118:6:118:14 | SSA def(password1) | passwords.go:119:28:119:36 | password1 | provenance | | | passwords.go:119:28:119:36 | password1 | passwords.go:119:28:119:45 | call to String | provenance | Config | | passwords.go:119:28:119:45 | call to String | passwords.go:119:14:119:45 | ...+... | provenance | Config | | passwords.go:122:12:127:2 | struct literal | passwords.go:129:14:129:19 | config | provenance | | @@ -142,13 +142,13 @@ edges | passwords.go:126:13:126:25 | call to getPassword | passwords.go:122:12:127:2 | struct literal [y] | provenance | | | passwords.go:130:14:130:19 | config [x] | passwords.go:130:14:130:21 | selection of x | provenance | | | passwords.go:131:14:131:19 | config [y] | passwords.go:131:14:131:21 | selection of y | provenance | | -| protobuf.go:9:2:9:9 | definition of password | protobuf.go:12:22:12:29 | password | provenance | | +| protobuf.go:9:2:9:9 | SSA def(password) | protobuf.go:12:22:12:29 | password | provenance | | | protobuf.go:12:2:12:6 | implicit dereference [postupdate] [Description] | protobuf.go:12:2:12:6 | query [postupdate] [pointer, Description] | provenance | | | protobuf.go:12:2:12:6 | query [postupdate] [pointer, Description] | protobuf.go:14:14:14:18 | query [pointer, Description] | provenance | | | protobuf.go:12:22:12:29 | password | protobuf.go:12:2:12:6 | implicit dereference [postupdate] [Description] | provenance | | | protobuf.go:14:14:14:18 | query [pointer, Description] | protobuf.go:14:14:14:35 | call to GetDescription | provenance | | -| protobuf.go:14:14:14:18 | query [pointer, Description] | protos/query/query.pb.go:117:7:117:7 | definition of x [pointer, Description] | provenance | | -| protos/query/query.pb.go:117:7:117:7 | definition of x [pointer, Description] | protos/query/query.pb.go:119:10:119:10 | x [pointer, Description] | provenance | | +| protobuf.go:14:14:14:18 | query [pointer, Description] | protos/query/query.pb.go:117:7:117:7 | SSA def(x) [pointer, Description] | provenance | | +| protos/query/query.pb.go:117:7:117:7 | SSA def(x) [pointer, Description] | protos/query/query.pb.go:119:10:119:10 | x [pointer, Description] | provenance | | | protos/query/query.pb.go:119:10:119:10 | implicit dereference [Description] | protos/query/query.pb.go:119:10:119:22 | selection of Description | provenance | | | protos/query/query.pb.go:119:10:119:10 | x [pointer, Description] | protos/query/query.pb.go:119:10:119:10 | implicit dereference [Description] | provenance | | models @@ -171,7 +171,7 @@ nodes | klog.go:23:15:23:20 | header | semmle.label | header | | klog.go:29:13:29:20 | selection of Header | semmle.label | selection of Header | | klog.go:29:13:29:41 | call to Get | semmle.label | call to Get | -| main.go:17:2:17:9 | definition of password | semmle.label | definition of password | +| main.go:17:2:17:9 | SSA def(password) | semmle.label | SSA def(password) | | main.go:19:12:19:19 | password | semmle.label | password | | main.go:20:19:20:26 | password | semmle.label | password | | main.go:21:13:21:20 | password | semmle.label | password | @@ -209,12 +209,12 @@ nodes | main.go:86:19:86:26 | password | semmle.label | password | | main.go:87:29:87:34 | fields | semmle.label | fields | | main.go:90:35:90:42 | password | semmle.label | password | -| overrides.go:8:2:8:9 | definition of password | semmle.label | definition of password | +| overrides.go:8:2:8:9 | SSA def(password) | semmle.label | SSA def(password) | | overrides.go:9:9:9:16 | password | semmle.label | password | | overrides.go:13:14:13:23 | call to String | semmle.label | call to String | -| passwords.go:8:12:8:12 | definition of x | semmle.label | definition of x | +| passwords.go:8:12:8:12 | SSA def(x) | semmle.label | SSA def(x) | | passwords.go:9:14:9:14 | x | semmle.label | x | -| passwords.go:21:2:21:9 | definition of password | semmle.label | definition of password | +| passwords.go:21:2:21:9 | SSA def(password) | semmle.label | SSA def(password) | | passwords.go:25:14:25:21 | password | semmle.label | password | | passwords.go:26:14:26:23 | selection of password | semmle.label | selection of password | | passwords.go:27:14:27:26 | call to getPassword | semmle.label | call to getPassword | @@ -230,7 +230,7 @@ nodes | passwords.go:44:6:44:13 | password | semmle.label | password | | passwords.go:46:14:46:17 | obj2 | semmle.label | obj2 | | passwords.go:50:11:50:18 | password | semmle.label | password | -| passwords.go:52:2:52:15 | definition of fixed_password | semmle.label | definition of fixed_password | +| passwords.go:52:2:52:15 | SSA def(fixed_password) | semmle.label | SSA def(fixed_password) | | passwords.go:53:14:53:27 | fixed_password | semmle.label | fixed_password | | passwords.go:88:19:90:2 | struct literal | semmle.label | struct literal | | passwords.go:89:16:89:36 | call to make | semmle.label | call to make | @@ -242,7 +242,7 @@ nodes | passwords.go:110:34:110:41 | password | semmle.label | password | | passwords.go:115:15:115:40 | ...+... | semmle.label | ...+... | | passwords.go:115:33:115:40 | password | semmle.label | password | -| passwords.go:118:6:118:14 | definition of password1 | semmle.label | definition of password1 | +| passwords.go:118:6:118:14 | SSA def(password1) | semmle.label | SSA def(password1) | | passwords.go:119:14:119:45 | ...+... | semmle.label | ...+... | | passwords.go:119:28:119:36 | password1 | semmle.label | password1 | | passwords.go:119:28:119:45 | call to String | semmle.label | call to String | @@ -257,15 +257,15 @@ nodes | passwords.go:130:14:130:21 | selection of x | semmle.label | selection of x | | passwords.go:131:14:131:19 | config [y] | semmle.label | config [y] | | passwords.go:131:14:131:21 | selection of y | semmle.label | selection of y | -| protobuf.go:9:2:9:9 | definition of password | semmle.label | definition of password | +| protobuf.go:9:2:9:9 | SSA def(password) | semmle.label | SSA def(password) | | protobuf.go:12:2:12:6 | implicit dereference [postupdate] [Description] | semmle.label | implicit dereference [postupdate] [Description] | | protobuf.go:12:2:12:6 | query [postupdate] [pointer, Description] | semmle.label | query [postupdate] [pointer, Description] | | protobuf.go:12:22:12:29 | password | semmle.label | password | | protobuf.go:14:14:14:18 | query [pointer, Description] | semmle.label | query [pointer, Description] | | protobuf.go:14:14:14:35 | call to GetDescription | semmle.label | call to GetDescription | -| protos/query/query.pb.go:117:7:117:7 | definition of x [pointer, Description] | semmle.label | definition of x [pointer, Description] | +| protos/query/query.pb.go:117:7:117:7 | SSA def(x) [pointer, Description] | semmle.label | SSA def(x) [pointer, Description] | | protos/query/query.pb.go:119:10:119:10 | implicit dereference [Description] | semmle.label | implicit dereference [Description] | | protos/query/query.pb.go:119:10:119:10 | x [pointer, Description] | semmle.label | x [pointer, Description] | | protos/query/query.pb.go:119:10:119:22 | selection of Description | semmle.label | selection of Description | subpaths -| protobuf.go:14:14:14:18 | query [pointer, Description] | protos/query/query.pb.go:117:7:117:7 | definition of x [pointer, Description] | protos/query/query.pb.go:119:10:119:22 | selection of Description | protobuf.go:14:14:14:35 | call to GetDescription | +| protobuf.go:14:14:14:18 | query [pointer, Description] | protos/query/query.pb.go:117:7:117:7 | SSA def(x) [pointer, Description] | protos/query/query.pb.go:119:10:119:22 | selection of Description | protobuf.go:14:14:14:35 | call to GetDescription | diff --git a/go/ql/test/query-tests/Security/CWE-322/InsecureHostKeyCallback.expected b/go/ql/test/query-tests/Security/CWE-322/InsecureHostKeyCallback.expected index b05736dc4c4..0f0bc8bf259 100644 --- a/go/ql/test/query-tests/Security/CWE-322/InsecureHostKeyCallback.expected +++ b/go/ql/test/query-tests/Security/CWE-322/InsecureHostKeyCallback.expected @@ -8,18 +8,18 @@ edges | InsecureHostKeyCallbackExample.go:31:14:34:4 | type conversion | InsecureHostKeyCallbackExample.go:39:20:39:27 | callback | provenance | | | InsecureHostKeyCallbackExample.go:32:3:34:3 | function literal | InsecureHostKeyCallbackExample.go:31:14:34:4 | type conversion | provenance | | | InsecureHostKeyCallbackExample.go:45:3:47:3 | function literal | InsecureHostKeyCallbackExample.go:52:20:52:48 | type conversion | provenance | | -| InsecureHostKeyCallbackExample.go:58:39:58:46 | definition of callback | InsecureHostKeyCallbackExample.go:62:20:62:27 | callback | provenance | | -| InsecureHostKeyCallbackExample.go:68:48:68:55 | definition of callback | InsecureHostKeyCallbackExample.go:78:28:78:35 | callback | provenance | | +| InsecureHostKeyCallbackExample.go:58:39:58:46 | SSA def(callback) | InsecureHostKeyCallbackExample.go:62:20:62:27 | callback | provenance | | +| InsecureHostKeyCallbackExample.go:68:48:68:55 | SSA def(callback) | InsecureHostKeyCallbackExample.go:78:28:78:35 | callback | provenance | | | InsecureHostKeyCallbackExample.go:94:3:94:43 | ... := ...[0] | InsecureHostKeyCallbackExample.go:95:28:95:35 | callback | provenance | | | InsecureHostKeyCallbackExample.go:102:22:105:4 | type conversion | InsecureHostKeyCallbackExample.go:107:35:107:50 | insecureCallback | provenance | | | InsecureHostKeyCallbackExample.go:103:3:105:3 | function literal | InsecureHostKeyCallbackExample.go:102:22:105:4 | type conversion | provenance | | -| InsecureHostKeyCallbackExample.go:107:35:107:50 | insecureCallback | InsecureHostKeyCallbackExample.go:58:39:58:46 | definition of callback | provenance | | +| InsecureHostKeyCallbackExample.go:107:35:107:50 | insecureCallback | InsecureHostKeyCallbackExample.go:58:39:58:46 | SSA def(callback) | provenance | | | InsecureHostKeyCallbackExample.go:109:31:115:4 | type conversion | InsecureHostKeyCallbackExample.go:117:35:117:59 | potentiallySecureCallback | provenance | | | InsecureHostKeyCallbackExample.go:109:31:115:4 | type conversion | InsecureHostKeyCallbackExample.go:120:44:120:68 | potentiallySecureCallback | provenance | | | InsecureHostKeyCallbackExample.go:110:3:115:3 | function literal | InsecureHostKeyCallbackExample.go:109:31:115:4 | type conversion | provenance | | -| InsecureHostKeyCallbackExample.go:117:35:117:59 | potentiallySecureCallback | InsecureHostKeyCallbackExample.go:58:39:58:46 | definition of callback | provenance | | -| InsecureHostKeyCallbackExample.go:118:35:118:61 | call to InsecureIgnoreHostKey | InsecureHostKeyCallbackExample.go:58:39:58:46 | definition of callback | provenance | | -| InsecureHostKeyCallbackExample.go:120:44:120:68 | potentiallySecureCallback | InsecureHostKeyCallbackExample.go:68:48:68:55 | definition of callback | provenance | | +| InsecureHostKeyCallbackExample.go:117:35:117:59 | potentiallySecureCallback | InsecureHostKeyCallbackExample.go:58:39:58:46 | SSA def(callback) | provenance | | +| InsecureHostKeyCallbackExample.go:118:35:118:61 | call to InsecureIgnoreHostKey | InsecureHostKeyCallbackExample.go:58:39:58:46 | SSA def(callback) | provenance | | +| InsecureHostKeyCallbackExample.go:120:44:120:68 | potentiallySecureCallback | InsecureHostKeyCallbackExample.go:68:48:68:55 | SSA def(callback) | provenance | | nodes | InsecureHostKeyCallbackExample.go:15:20:18:5 | type conversion | semmle.label | type conversion | | InsecureHostKeyCallbackExample.go:16:4:18:4 | function literal | semmle.label | function literal | @@ -29,9 +29,9 @@ nodes | InsecureHostKeyCallbackExample.go:39:20:39:27 | callback | semmle.label | callback | | InsecureHostKeyCallbackExample.go:45:3:47:3 | function literal | semmle.label | function literal | | InsecureHostKeyCallbackExample.go:52:20:52:48 | type conversion | semmle.label | type conversion | -| InsecureHostKeyCallbackExample.go:58:39:58:46 | definition of callback | semmle.label | definition of callback | +| InsecureHostKeyCallbackExample.go:58:39:58:46 | SSA def(callback) | semmle.label | SSA def(callback) | | InsecureHostKeyCallbackExample.go:62:20:62:27 | callback | semmle.label | callback | -| InsecureHostKeyCallbackExample.go:68:48:68:55 | definition of callback | semmle.label | definition of callback | +| InsecureHostKeyCallbackExample.go:68:48:68:55 | SSA def(callback) | semmle.label | SSA def(callback) | | InsecureHostKeyCallbackExample.go:76:28:76:54 | call to InsecureIgnoreHostKey | semmle.label | call to InsecureIgnoreHostKey | | InsecureHostKeyCallbackExample.go:78:28:78:35 | callback | semmle.label | callback | | InsecureHostKeyCallbackExample.go:92:28:92:54 | call to InsecureIgnoreHostKey | semmle.label | call to InsecureIgnoreHostKey | diff --git a/go/ql/test/query-tests/Security/CWE-326/InsufficientKeySize.expected b/go/ql/test/query-tests/Security/CWE-326/InsufficientKeySize.expected index 556b1722b59..b37e3395a86 100644 --- a/go/ql/test/query-tests/Security/CWE-326/InsufficientKeySize.expected +++ b/go/ql/test/query-tests/Security/CWE-326/InsufficientKeySize.expected @@ -1,7 +1,7 @@ edges | InsufficientKeySize.go:13:10:13:13 | 1024 | InsufficientKeySize.go:14:31:14:34 | size | provenance | | -| InsufficientKeySize.go:18:7:18:10 | 1024 | InsufficientKeySize.go:25:11:25:14 | definition of size | provenance | | -| InsufficientKeySize.go:25:11:25:14 | definition of size | InsufficientKeySize.go:26:31:26:34 | size | provenance | | +| InsufficientKeySize.go:18:7:18:10 | 1024 | InsufficientKeySize.go:25:11:25:14 | SSA def(size) | provenance | | +| InsufficientKeySize.go:25:11:25:14 | SSA def(size) | InsufficientKeySize.go:26:31:26:34 | size | provenance | | | InsufficientKeySize.go:30:13:30:16 | 1024 | InsufficientKeySize.go:32:32:32:38 | keyBits | provenance | | | InsufficientKeySize.go:44:13:44:16 | 1024 | InsufficientKeySize.go:47:32:47:38 | keyBits | provenance | | | InsufficientKeySize.go:61:21:61:24 | 1024 | InsufficientKeySize.go:67:31:67:37 | keyBits | provenance | | @@ -10,7 +10,7 @@ nodes | InsufficientKeySize.go:13:10:13:13 | 1024 | semmle.label | 1024 | | InsufficientKeySize.go:14:31:14:34 | size | semmle.label | size | | InsufficientKeySize.go:18:7:18:10 | 1024 | semmle.label | 1024 | -| InsufficientKeySize.go:25:11:25:14 | definition of size | semmle.label | definition of size | +| InsufficientKeySize.go:25:11:25:14 | SSA def(size) | semmle.label | SSA def(size) | | InsufficientKeySize.go:26:31:26:34 | size | semmle.label | size | | InsufficientKeySize.go:30:13:30:16 | 1024 | semmle.label | 1024 | | InsufficientKeySize.go:32:32:32:38 | keyBits | semmle.label | keyBits | diff --git a/go/ql/test/query-tests/Security/CWE-347/MissingJwtSignatureCheck.expected b/go/ql/test/query-tests/Security/CWE-347/MissingJwtSignatureCheck.expected index 2bfca2aa643..c1f41d118e7 100644 --- a/go/ql/test/query-tests/Security/CWE-347/MissingJwtSignatureCheck.expected +++ b/go/ql/test/query-tests/Security/CWE-347/MissingJwtSignatureCheck.expected @@ -5,15 +5,15 @@ edges | go-jose.v3.go:25:16:25:20 | selection of URL | go-jose.v3.go:25:16:25:28 | call to Query | provenance | Src:MaD:3 MaD:5 | | go-jose.v3.go:25:16:25:28 | call to Query | go-jose.v3.go:25:16:25:47 | call to Get | provenance | MaD:6 | | go-jose.v3.go:25:16:25:47 | call to Get | go-jose.v3.go:26:15:26:25 | signedToken | provenance | | -| go-jose.v3.go:26:15:26:25 | signedToken | go-jose.v3.go:29:19:29:29 | definition of signedToken | provenance | | -| go-jose.v3.go:29:19:29:29 | definition of signedToken | go-jose.v3.go:31:37:31:47 | signedToken | provenance | | +| go-jose.v3.go:26:15:26:25 | signedToken | go-jose.v3.go:29:19:29:29 | SSA def(signedToken) | provenance | | +| go-jose.v3.go:29:19:29:29 | SSA def(signedToken) | go-jose.v3.go:31:37:31:47 | signedToken | provenance | | | go-jose.v3.go:31:2:31:48 | ... := ...[0] | go-jose.v3.go:33:12:33:23 | DecodedToken | provenance | Sink:MaD:2 | | go-jose.v3.go:31:37:31:47 | signedToken | go-jose.v3.go:31:2:31:48 | ... := ...[0] | provenance | MaD:4 | | golang-jwt-v5.go:28:16:28:20 | selection of URL | golang-jwt-v5.go:28:16:28:28 | call to Query | provenance | Src:MaD:3 MaD:5 | | golang-jwt-v5.go:28:16:28:28 | call to Query | golang-jwt-v5.go:28:16:28:47 | call to Get | provenance | MaD:6 | | golang-jwt-v5.go:28:16:28:47 | call to Get | golang-jwt-v5.go:29:25:29:35 | signedToken | provenance | | -| golang-jwt-v5.go:29:25:29:35 | signedToken | golang-jwt-v5.go:32:29:32:39 | definition of signedToken | provenance | | -| golang-jwt-v5.go:32:29:32:39 | definition of signedToken | golang-jwt-v5.go:34:58:34:68 | signedToken | provenance | Sink:MaD:1 | +| golang-jwt-v5.go:29:25:29:35 | signedToken | golang-jwt-v5.go:32:29:32:39 | SSA def(signedToken) | provenance | | +| golang-jwt-v5.go:32:29:32:39 | SSA def(signedToken) | golang-jwt-v5.go:34:58:34:68 | signedToken | provenance | Sink:MaD:1 | models | 1 | Sink: github.com/golang-jwt/jwt; Parser; true; ParseUnverified; ; ; Argument[0]; jwt; manual | | 2 | Sink: group:go-jose/jwt; JSONWebToken; true; UnsafeClaimsWithoutVerification; ; ; Argument[receiver]; jwt; manual | @@ -26,7 +26,7 @@ nodes | go-jose.v3.go:25:16:25:28 | call to Query | semmle.label | call to Query | | go-jose.v3.go:25:16:25:47 | call to Get | semmle.label | call to Get | | go-jose.v3.go:26:15:26:25 | signedToken | semmle.label | signedToken | -| go-jose.v3.go:29:19:29:29 | definition of signedToken | semmle.label | definition of signedToken | +| go-jose.v3.go:29:19:29:29 | SSA def(signedToken) | semmle.label | SSA def(signedToken) | | go-jose.v3.go:31:2:31:48 | ... := ...[0] | semmle.label | ... := ...[0] | | go-jose.v3.go:31:37:31:47 | signedToken | semmle.label | signedToken | | go-jose.v3.go:33:12:33:23 | DecodedToken | semmle.label | DecodedToken | @@ -34,6 +34,6 @@ nodes | golang-jwt-v5.go:28:16:28:28 | call to Query | semmle.label | call to Query | | golang-jwt-v5.go:28:16:28:47 | call to Get | semmle.label | call to Get | | golang-jwt-v5.go:29:25:29:35 | signedToken | semmle.label | signedToken | -| golang-jwt-v5.go:32:29:32:39 | definition of signedToken | semmle.label | definition of signedToken | +| golang-jwt-v5.go:32:29:32:39 | SSA def(signedToken) | semmle.label | SSA def(signedToken) | | golang-jwt-v5.go:34:58:34:68 | signedToken | semmle.label | signedToken | subpaths diff --git a/go/ql/test/query-tests/Security/CWE-601/BadRedirectCheck/BadRedirectCheck.expected b/go/ql/test/query-tests/Security/CWE-601/BadRedirectCheck/BadRedirectCheck.expected index 8d4aaba1446..9135bafbf54 100644 --- a/go/ql/test/query-tests/Security/CWE-601/BadRedirectCheck/BadRedirectCheck.expected +++ b/go/ql/test/query-tests/Security/CWE-601/BadRedirectCheck/BadRedirectCheck.expected @@ -9,31 +9,31 @@ | main.go:69:5:69:22 | ...!=... | main.go:76:19:76:21 | argument corresponding to url | main.go:77:25:77:39 | call to getTarget1 | This is a check that $@, which flows into a $@, has a leading slash, but not that it does not have '/' or '\\' in its second position. | main.go:76:19:76:21 | argument corresponding to url | this value | main.go:77:25:77:39 | call to getTarget1 | redirect | | main.go:83:5:83:20 | ...!=... | main.go:87:9:87:14 | selection of Path | main.go:91:25:91:39 | call to getTarget2 | This is a check that $@, which flows into a $@, has a leading slash, but not that it does not have '/' or '\\' in its second position. | main.go:87:9:87:14 | selection of Path | this value | main.go:91:25:91:39 | call to getTarget2 | redirect | edges +| BadRedirectCheck.go:3:18:3:22 | SSA def(redir) | BadRedirectCheck.go:5:10:5:14 | redir | provenance | | | BadRedirectCheck.go:3:18:3:22 | argument corresponding to redir | BadRedirectCheck.go:5:10:5:14 | redir | provenance | | -| BadRedirectCheck.go:3:18:3:22 | definition of redir | BadRedirectCheck.go:5:10:5:14 | redir | provenance | | | BadRedirectCheck.go:5:10:5:14 | redir | main.go:11:25:11:45 | call to sanitizeUrl | provenance | Sink:MaD:1 | | cves.go:14:23:14:25 | argument corresponding to url | cves.go:16:26:16:28 | url | provenance | Sink:MaD:1 | | cves.go:33:14:33:34 | call to Get | cves.go:37:25:37:32 | redirect | provenance | Sink:MaD:1 | | cves.go:41:14:41:34 | call to Get | cves.go:45:25:45:32 | redirect | provenance | Sink:MaD:1 | | main.go:10:18:10:25 | argument corresponding to redirect | main.go:11:37:11:44 | redirect | provenance | | -| main.go:11:37:11:44 | redirect | BadRedirectCheck.go:3:18:3:22 | definition of redir | provenance | | +| main.go:11:37:11:44 | redirect | BadRedirectCheck.go:3:18:3:22 | SSA def(redir) | provenance | | | main.go:11:37:11:44 | redirect | main.go:11:25:11:45 | call to sanitizeUrl | provenance | Sink:MaD:1 | | main.go:32:24:32:26 | argument corresponding to url | main.go:34:26:34:28 | url | provenance | Sink:MaD:1 | +| main.go:68:17:68:24 | SSA def(redirect) | main.go:73:20:73:27 | redirect | provenance | | | main.go:68:17:68:24 | argument corresponding to redirect | main.go:73:20:73:27 | redirect | provenance | | -| main.go:68:17:68:24 | definition of redirect | main.go:73:20:73:27 | redirect | provenance | | | main.go:73:9:73:28 | call to Clean | main.go:77:25:77:39 | call to getTarget1 | provenance | Sink:MaD:1 | | main.go:73:20:73:27 | redirect | main.go:73:9:73:28 | call to Clean | provenance | MaD:2 | | main.go:73:20:73:27 | redirect | main.go:73:9:73:28 | call to Clean | provenance | MaD:2 | | main.go:76:19:76:21 | argument corresponding to url | main.go:77:36:77:38 | url | provenance | | -| main.go:77:36:77:38 | url | main.go:68:17:68:24 | definition of redirect | provenance | | +| main.go:77:36:77:38 | url | main.go:68:17:68:24 | SSA def(redirect) | provenance | | | main.go:77:36:77:38 | url | main.go:77:25:77:39 | call to getTarget1 | provenance | MaD:2 Sink:MaD:1 | | main.go:87:9:87:14 | selection of Path | main.go:91:25:91:39 | call to getTarget2 | provenance | Sink:MaD:1 | models | 1 | Sink: net/http; ; false; Redirect; ; ; Argument[2]; url-redirection[0]; manual | | 2 | Summary: path; ; false; Clean; ; ; Argument[0]; ReturnValue; taint; manual | nodes +| BadRedirectCheck.go:3:18:3:22 | SSA def(redir) | semmle.label | SSA def(redir) | | BadRedirectCheck.go:3:18:3:22 | argument corresponding to redir | semmle.label | argument corresponding to redir | -| BadRedirectCheck.go:3:18:3:22 | definition of redir | semmle.label | definition of redir | | BadRedirectCheck.go:5:10:5:14 | redir | semmle.label | redir | | BadRedirectCheck.go:5:10:5:14 | redir | semmle.label | redir | | cves.go:14:23:14:25 | argument corresponding to url | semmle.label | argument corresponding to url | @@ -47,8 +47,8 @@ nodes | main.go:11:37:11:44 | redirect | semmle.label | redirect | | main.go:32:24:32:26 | argument corresponding to url | semmle.label | argument corresponding to url | | main.go:34:26:34:28 | url | semmle.label | url | +| main.go:68:17:68:24 | SSA def(redirect) | semmle.label | SSA def(redirect) | | main.go:68:17:68:24 | argument corresponding to redirect | semmle.label | argument corresponding to redirect | -| main.go:68:17:68:24 | definition of redirect | semmle.label | definition of redirect | | main.go:73:9:73:28 | call to Clean | semmle.label | call to Clean | | main.go:73:9:73:28 | call to Clean | semmle.label | call to Clean | | main.go:73:20:73:27 | redirect | semmle.label | redirect | @@ -59,5 +59,5 @@ nodes | main.go:87:9:87:14 | selection of Path | semmle.label | selection of Path | | main.go:91:25:91:39 | call to getTarget2 | semmle.label | call to getTarget2 | subpaths -| main.go:11:37:11:44 | redirect | BadRedirectCheck.go:3:18:3:22 | definition of redir | BadRedirectCheck.go:5:10:5:14 | redir | main.go:11:25:11:45 | call to sanitizeUrl | -| main.go:77:36:77:38 | url | main.go:68:17:68:24 | definition of redirect | main.go:73:9:73:28 | call to Clean | main.go:77:25:77:39 | call to getTarget1 | +| main.go:11:37:11:44 | redirect | BadRedirectCheck.go:3:18:3:22 | SSA def(redir) | BadRedirectCheck.go:5:10:5:14 | redir | main.go:11:25:11:45 | call to sanitizeUrl | +| main.go:77:36:77:38 | url | main.go:68:17:68:24 | SSA def(redirect) | main.go:73:9:73:28 | call to Clean | main.go:77:25:77:39 | call to getTarget1 | diff --git a/java/kotlin-extractor/BUILD.bazel b/java/kotlin-extractor/BUILD.bazel index a4356af1835..f33949f8391 100644 --- a/java/kotlin-extractor/BUILD.bazel +++ b/java/kotlin-extractor/BUILD.bazel @@ -53,6 +53,10 @@ _extractor_name_prefix = "%s-%s" % ( "embeddable" if _for_embeddable else "standalone", ) +_compiler_plugin_registrar_service_source = "src/main/resources/META-INF/services/org.jetbrains.kotlin.compiler.plugin.CompilerPluginRegistrar" + +_compiler_plugin_registrar_service_target = "META-INF/services/org.jetbrains.kotlin.compiler.plugin.CompilerPluginRegistrar" + py_binary( name = "generate_dbscheme", srcs = ["generate_dbscheme.py"], @@ -64,8 +68,14 @@ _resources = [ r[len("src/main/resources/"):], ) for r in glob(["src/main/resources/**"]) + if r != _compiler_plugin_registrar_service_source ] +_compiler_plugin_registrar_service = ( + _compiler_plugin_registrar_service_source, + _compiler_plugin_registrar_service_target, +) + kt_javac_options( name = "javac-options", release = "8", @@ -91,19 +101,32 @@ kt_javac_options( # * `resource_strip_prefix` is unique per jar, so we must also put other resources under the same version prefix genrule( name = "resources-%s" % v, - srcs = [src for src, _ in _resources], + srcs = [src for src, _ in _resources] + ( + [_compiler_plugin_registrar_service[0]] if not version_less(v, "2.4.0") else [] + ), outs = [ "%s/com/github/codeql/extractor.name" % v, ] + [ "%s/%s" % (v, target) for _, target in _resources - ], + ] + ( + ["%s/%s" % ( + v, + _compiler_plugin_registrar_service[1], + )] if not version_less(v, "2.4.0") else [] + ), cmd = "\n".join([ "echo %s-%s > $(RULEDIR)/%s/com/github/codeql/extractor.name" % (_extractor_name_prefix, v, v), ] + [ "cp $(execpath %s) $(RULEDIR)/%s/%s" % (source, v, target) for source, target in _resources - ]), + ] + ( + ["cp $(execpath %s) $(RULEDIR)/%s/%s" % ( + _compiler_plugin_registrar_service[0], + v, + _compiler_plugin_registrar_service[1], + )] if not version_less(v, "2.4.0") else [] + )), ), kt_jvm_library( name = "%s-%s" % (_extractor_name_prefix, v), diff --git a/java/kotlin-extractor/deps/kotlin-compiler-2.4.0.jar b/java/kotlin-extractor/deps/kotlin-compiler-2.4.0.jar new file mode 100644 index 00000000000..39d9779c219 --- /dev/null +++ b/java/kotlin-extractor/deps/kotlin-compiler-2.4.0.jar @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:66e73eacd619c9beb7c22042117af36b443529c4d80237ee82cc4b2acb6f3d0b +size 61902486 diff --git a/java/kotlin-extractor/deps/kotlin-compiler-embeddable-2.4.0.jar b/java/kotlin-extractor/deps/kotlin-compiler-embeddable-2.4.0.jar new file mode 100644 index 00000000000..bda62390cc7 --- /dev/null +++ b/java/kotlin-extractor/deps/kotlin-compiler-embeddable-2.4.0.jar @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c2b25e8c1c93ec416ba4327f5e31eaec0f0c8847241b9353e294b8db9dce564f +size 60351320 diff --git a/java/kotlin-extractor/deps/kotlin-stdlib-2.4.0.jar b/java/kotlin-extractor/deps/kotlin-stdlib-2.4.0.jar new file mode 100644 index 00000000000..7733acaf0aa --- /dev/null +++ b/java/kotlin-extractor/deps/kotlin-stdlib-2.4.0.jar @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ccb14ff83fabcb11458b798dbc9824748ccdffeec79c9aba789e6ed1cda86b1c +size 1841929 diff --git a/java/kotlin-extractor/dev/wrapper.py b/java/kotlin-extractor/dev/wrapper.py index 6fc51aded79..34b9d6b9425 100755 --- a/java/kotlin-extractor/dev/wrapper.py +++ b/java/kotlin-extractor/dev/wrapper.py @@ -27,7 +27,7 @@ import shutil import io import os -DEFAULT_VERSION = "2.3.20" +DEFAULT_VERSION = "2.4.0" def options(): diff --git a/java/kotlin-extractor/src/main/kotlin/KotlinExtractorComponentRegistrar.kt b/java/kotlin-extractor/src/main/kotlin/KotlinExtractorComponentRegistrar.kt index 81e3c2bba36..c2ca017cbce 100644 --- a/java/kotlin-extractor/src/main/kotlin/KotlinExtractorComponentRegistrar.kt +++ b/java/kotlin-extractor/src/main/kotlin/KotlinExtractorComponentRegistrar.kt @@ -3,32 +3,21 @@ package com.github.codeql -import com.intellij.mock.MockProject -import com.intellij.openapi.extensions.LoadingOrder -import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension import org.jetbrains.kotlin.config.CompilerConfiguration class KotlinExtractorComponentRegistrar : Kotlin2ComponentRegistrar() { - override fun registerProjectComponents( - project: MockProject, - configuration: CompilerConfiguration - ) { + override fun doRegisterExtensions(configuration: CompilerConfiguration) { val invocationTrapFile = configuration[KEY_INVOCATION_TRAP_FILE] if (invocationTrapFile == null) { throw Exception("Required argument for TRAP invocation file not given") } - // Register with LoadingOrder.LAST to ensure the extractor runs after other - // IR generation plugins (like kotlinx.serialization) have generated their code. - val extensionPoint = project.extensionArea.getExtensionPoint(IrGenerationExtension.extensionPointName) - extensionPoint.registerExtension( + registerExtractorExtension( KotlinExtractorExtension( invocationTrapFile, configuration[KEY_CHECK_TRAP_IDENTICAL] ?: false, configuration[KEY_COMPILATION_STARTTIME], configuration[KEY_EXIT_AFTER_EXTRACTION] ?: false - ), - LoadingOrder.LAST, - project + ) ) } } diff --git a/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt b/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt index 1c2ed959caf..0b975d9b829 100644 --- a/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt +++ b/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt @@ -173,9 +173,9 @@ open class KotlinFileExtractor( when (d) { is IrFunction -> when (d.name.asString()) { - "toString" -> d.valueParameters.isEmpty() - "hashCode" -> d.valueParameters.isEmpty() - "equals" -> d.valueParameters.singleOrNull()?.type?.isNullableAny() ?: false + "toString" -> d.codeQlValueParameters.isEmpty() + "hashCode" -> d.codeQlValueParameters.isEmpty() + "equals" -> d.codeQlValueParameters.singleOrNull()?.type?.isNullableAny() ?: false else -> false } && isJavaBinaryDeclaration(d) else -> false @@ -721,7 +721,7 @@ open class KotlinFileExtractor( (it.type as? IrSimpleType)?.classFqName?.asString() != "kotlin.Deprecated" } + // Note we lose any arguments to @java.lang.Deprecated that were written in source. - IrConstructorCallImpl.fromSymbolOwner( + codeQlAnnotationFromSymbolOwner( UNDEFINED_OFFSET, UNDEFINED_OFFSET, jldConstructor.returnType, @@ -781,13 +781,13 @@ open class KotlinFileExtractor( val locId = tw.getLocation(constructorCall) tw.writeHasLocation(id, locId) - for (i in 0 until constructorCall.valueArgumentsCount) { - val param = constructorCall.symbol.owner.valueParameters[i] + for (i in 0 until constructorCall.codeQlValueArgumentsCount) { + val param = constructorCall.symbol.owner.codeQlValueParameters[i] val prop = constructorCall.symbol.owner.parentAsClass.declarations .filterIsInstance() .first { it.name == param.name } - val v = constructorCall.getValueArgument(i) ?: param.defaultValue?.expression + val v = constructorCall.codeQlGetValueArgument(i) ?: param.defaultValue?.expression val getter = prop.getter if (getter == null) { logger.warnElement("Expected annotation property to define a getter", prop) @@ -1115,9 +1115,9 @@ open class KotlinFileExtractor( returnId, 0, returnId, - f.valueParameters.size, + f.codeQlValueParameters.size, { argParent, idxOffset -> - f.valueParameters.forEachIndexed { idx, param -> + f.codeQlValueParameters.forEachIndexed { idx, param -> val syntheticParamId = useValueParameter(param, proxyFunctionId) extractVariableAccess( syntheticParamId, @@ -1695,9 +1695,9 @@ open class KotlinFileExtractor( returnId, 0, returnId, - f.valueParameters.size, + f.codeQlValueParameters.size, { argParentId, idxOffset -> - f.valueParameters.mapIndexed { idx, param -> + f.codeQlValueParameters.mapIndexed { idx, param -> val syntheticParamId = useValueParameter(param, functionId) extractVariableAccess( syntheticParamId, @@ -1792,7 +1792,7 @@ open class KotlinFileExtractor( extractBody: Boolean, extractMethodAndParameterTypeAccesses: Boolean ) { - if (f.valueParameters.none { it.defaultValue != null }) return + if (f.codeQlValueParameters.none { it.defaultValue != null }) return val id = getDefaultsMethodLabel(f) if (id == null) { @@ -1800,7 +1800,7 @@ open class KotlinFileExtractor( return } val locId = getLocation(f, null) - val extReceiver = f.extensionReceiverParameter + val extReceiver = f.codeQlExtensionReceiverParameter val dispatchReceiver = if (f.shouldExtractAsStatic) null else f.dispatchReceiverParameter val parameterTypes = getDefaultsMethodArgTypes(f) val allParamTypeResults = @@ -1869,7 +1869,7 @@ open class KotlinFileExtractor( tw.writeCompiler_generated(id, CompilerGeneratedKinds.DEFAULT_ARGUMENTS_METHOD.kind) if (extractBody) { - val nonSyntheticParams = listOfNotNull(dispatchReceiver) + f.valueParameters + val nonSyntheticParams = listOfNotNull(dispatchReceiver) + f.codeQlValueParameters // This stack entry represents as if we're extracting the 'real' function `f`, giving // the indices of its non-synthetic parameters // such that when we extract the default expressions below, any reference to f's nth @@ -1895,12 +1895,12 @@ open class KotlinFileExtractor( val realParamsVarId = getValueParameterLabel(id, parameterTypes.size - 2) val intType = pluginContext.irBuiltIns.intType val paramIdxOffset = - listOf(dispatchReceiver, f.extensionReceiverParameter).count { it != null } + listOf(dispatchReceiver, f.codeQlExtensionReceiverParameter).count { it != null } extractBlockBody(id, locId).also { blockId -> var nextStmt = 0 // For each parameter with a default, sub in the default value if the caller // hasn't supplied a value: - f.valueParameters.forEachIndexed { paramIdx, param -> + f.codeQlValueParameters.forEachIndexed { paramIdx, param -> val defaultVal = param.defaultValue if (defaultVal != null) { extractIfStmt(locId, blockId, nextStmt++, id).also { ifId -> @@ -1975,7 +1975,7 @@ open class KotlinFileExtractor( id ) tw.writeHasLocation(thisCallId, locId) - f.valueParameters.forEachIndexed { idx, param -> + f.codeQlValueParameters.forEachIndexed { idx, param -> extractVariableAccess( tw.getLabelFor(getValueParameterLabel(id, idx)), param.type, @@ -2003,9 +2003,9 @@ open class KotlinFileExtractor( ) .also { thisCallId -> val realFnIdxOffset = - if (f.extensionReceiverParameter != null) 1 else 0 + if (f.codeQlExtensionReceiverParameter != null) 1 else 0 val paramMappings = - f.valueParameters.mapIndexed { idx, param -> + f.codeQlValueParameters.mapIndexed { idx, param -> Triple( param.type, idx + paramIdxOffset, @@ -2156,7 +2156,7 @@ open class KotlinFileExtractor( val dispatchReceiver = f.dispatchReceiverParameter?.let { IrGetValueImpl(-1, -1, it.symbol) } val extensionReceiver = - f.extensionReceiverParameter?.let { IrGetValueImpl(-1, -1, it.symbol) } + f.codeQlExtensionReceiverParameter?.let { IrGetValueImpl(-1, -1, it.symbol) } extractExpressionBody(overloadId, realFunctionLocId).also { returnId -> extractsDefaultsCall( @@ -2180,28 +2180,28 @@ open class KotlinFileExtractor( if (!f.hasAnnotation(jvmOverloadsFqName)) { if ( f is IrConstructor && - f.valueParameters.isNotEmpty() && - f.valueParameters.all { it.defaultValue != null } && + f.codeQlValueParameters.isNotEmpty() && + f.codeQlValueParameters.all { it.defaultValue != null } && f.parentClassOrNull?.let { // Don't create a default constructor for an annotation class, or a class // that explicitly declares a no-arg constructor. !it.isAnnotationClass && it.declarations.none { d -> - d is IrConstructor && d.valueParameters.isEmpty() + d is IrConstructor && d.codeQlValueParameters.isEmpty() } } == true ) { // Per https://kotlinlang.org/docs/classes.html#creating-instances-of-classes, a // single default overload gets created specifically // when we have all default parameters, regardless of `@JvmOverloads`. - extractGeneratedOverload(f.valueParameters.map { _ -> null }) + extractGeneratedOverload(f.codeQlValueParameters.map { _ -> null }) } return } - val paramList: MutableList = f.valueParameters.toMutableList() - for (n in (f.valueParameters.size - 1) downTo 0) { - if (f.valueParameters[n].defaultValue != null) { + val paramList: MutableList = f.codeQlValueParameters.toMutableList() + for (n in (f.codeQlValueParameters.size - 1) downTo 0) { + if (f.codeQlValueParameters[n].defaultValue != null) { paramList[n] = null // Remove this parameter, to be replaced by a default value extractGeneratedOverload(paramList) } @@ -2327,7 +2327,7 @@ open class KotlinFileExtractor( getClassByFqName(pluginContext, it)?.let { annotationClass -> annotationClass.owner.declarations.firstIsInstanceOrNull()?.let { annotationConstructor -> - IrConstructorCallImpl.fromSymbolOwner( + codeQlAnnotationFromSymbolOwner( UNDEFINED_OFFSET, UNDEFINED_OFFSET, annotationConstructor.returnType, @@ -2388,13 +2388,13 @@ open class KotlinFileExtractor( id } - val extReceiver = f.extensionReceiverParameter + val extReceiver = f.codeQlExtensionReceiverParameter // The following parameter order is correct, because member $default methods (where // the order would be [dispatchParam], [extensionParam], normalParams) are not // extracted here val fParameters = listOfNotNull(extReceiver) + - (overriddenAttributes?.valueParameters ?: f.valueParameters) + (overriddenAttributes?.valueParameters ?: f.codeQlValueParameters) val paramTypes = fParameters.mapIndexed { i, vp -> extractValueParameter( @@ -3069,14 +3069,14 @@ open class KotlinFileExtractor( logger.errorElement("Unexpected dispatch receiver found", c) } - if (c.valueArgumentsCount < 1) { + if (c.codeQlValueArgumentsCount < 1) { logger.errorElement("No arguments found", c) return } extractArgument(id, c, callable, enclosingStmt, 0, "Operand null") - if (c.valueArgumentsCount > 1) { + if (c.codeQlValueArgumentsCount > 1) { logger.errorElement("Extra arguments found", c) } } @@ -3095,21 +3095,21 @@ open class KotlinFileExtractor( logger.errorElement("Unexpected dispatch receiver found", c) } - if (c.valueArgumentsCount < 1) { + if (c.codeQlValueArgumentsCount < 1) { logger.errorElement("No arguments found", c) return } extractArgument(id, c, callable, enclosingStmt, 0, "LHS null") - if (c.valueArgumentsCount < 2) { + if (c.codeQlValueArgumentsCount < 2) { logger.errorElement("No RHS found", c) return } extractArgument(id, c, callable, enclosingStmt, 1, "RHS null") - if (c.valueArgumentsCount > 2) { + if (c.codeQlValueArgumentsCount > 2) { logger.errorElement("Extra arguments found", c) } } @@ -3122,7 +3122,7 @@ open class KotlinFileExtractor( idx: Int, msg: String ) { - val op = c.getValueArgument(idx) + val op = c.codeQlGetValueArgument(idx) if (op == null) { logger.errorElement(msg, c) } else { @@ -3267,8 +3267,8 @@ open class KotlinFileExtractor( // and which should be replaced by defaults. The final Object parameter is apparently always // null. (listOfNotNull(if (f.shouldExtractAsStatic) null else f.dispatchReceiverParameter?.type) + - listOfNotNull(f.extensionReceiverParameter?.type) + - f.valueParameters.map { it.type } + + listOfNotNull(f.codeQlExtensionReceiverParameter?.type) + + f.codeQlValueParameters.map { it.type } + listOf(pluginContext.irBuiltIns.intType, getDefaultsMethodLastArgType(f))) .map { erase(it) } @@ -3345,7 +3345,7 @@ open class KotlinFileExtractor( val overriddenCallTarget = (callTarget as? IrSimpleFunction)?.allOverridden(includeSelf = true)?.firstOrNull { it.overriddenSymbols.isEmpty() && - it.valueParameters.any { p -> p.defaultValue != null } + it.codeQlValueParameters.any { p -> p.defaultValue != null } } ?: callTarget if (isExternalDeclaration(overriddenCallTarget)) { // Likewise, ensure the overridden target gets extracted. @@ -3419,7 +3419,7 @@ open class KotlinFileExtractor( } val valueArgsWithDummies = - valueArguments.zip(callTarget.valueParameters).map { (expr, param) -> + valueArguments.zip(callTarget.codeQlValueParameters).map { (expr, param) -> expr ?: IrConstImpl.defaultValueForType(0, 0, param.type) } @@ -3529,7 +3529,7 @@ open class KotlinFileExtractor( callTarget: IrFunction, valueArguments: List ): Boolean { - val varargParam = callTarget.valueParameters.withIndex().find { it.value.isVararg } + val varargParam = callTarget.codeQlValueParameters.withIndex().find { it.value.isVararg } // If the vararg param is the only one not specified, and it has no default value, then we // don't need to call a $default method, // as omitting it already implies passing an empty vararg array. @@ -3805,7 +3805,7 @@ open class KotlinFileExtractor( ) = extractCallValueArguments( callId, - (0 until call.valueArgumentsCount).map { call.getValueArgument(it) }, + (0 until call.codeQlValueArgumentsCount).map { call.codeQlGetValueArgument(it) }, enclosingStmt, enclosingCallable, idxOffset @@ -3874,7 +3874,7 @@ open class KotlinFileExtractor( (owner.parentClassOrNull?.fqNameWhenAvailable?.asString() == type || (owner.parent is IrExternalPackageFragment && getFileClassFqName(owner)?.asString() == type)) && - owner.valueParameters + owner.codeQlValueParameters .map { it.type.classFqName?.asString() } .toTypedArray() contentEquals parameterTypes } @@ -3926,8 +3926,8 @@ open class KotlinFileExtractor( val result = javaLangString?.declarations?.findSubType { it.name.asString() == "valueOf" && - it.valueParameters.size == 1 && - it.valueParameters[0].type == pluginContext.irBuiltIns.anyNType + it.codeQlValueParameters.size == 1 && + it.codeQlValueParameters[0].type == pluginContext.irBuiltIns.anyNType } if (result == null) { logger.error("Couldn't find declaration java.lang.String.valueOf(Object)") @@ -3951,7 +3951,7 @@ open class KotlinFileExtractor( val kotlinNoWhenBranchMatchedConstructor by lazy { val result = kotlinNoWhenBranchMatchedExn?.declarations?.findSubType { - it.valueParameters.isEmpty() + it.codeQlValueParameters.isEmpty() } if (result == null) { logger.error("Couldn't find no-arg constructor for kotlin.NoWhenBranchMatchedException") @@ -3990,7 +3990,7 @@ open class KotlinFileExtractor( verboseln("No match as function name is ${target.name.asString()} not $fName") return false } - val extensionReceiverParameter = target.extensionReceiverParameter + val extensionReceiverParameter = target.codeQlExtensionReceiverParameter val targetClass = if (extensionReceiverParameter == null) { if (isNullable == true) { @@ -4098,8 +4098,8 @@ open class KotlinFileExtractor( ) { val typeArgs = if (extractMethodTypeArguments) - (0 until c.typeArgumentsCount) - .map { c.getTypeArgument(it) } + (0 until c.codeQlTypeArgumentsCount) + .map { c.codeQlGetTypeArgument(it) } .requireNoNullsOrNull() else listOf() @@ -4116,9 +4116,9 @@ open class KotlinFileExtractor( parent, idx, enclosingStmt, - (0 until c.valueArgumentsCount).map { c.getValueArgument(it) }, + (0 until c.codeQlValueArgumentsCount).map { c.codeQlGetValueArgument(it) }, c.dispatchReceiver, - c.extensionReceiver, + c.codeQlExtensionReceiver, typeArgs, extractClassTypeArguments, c.superQualifierSymbol @@ -4126,12 +4126,12 @@ open class KotlinFileExtractor( } fun extractSpecialEnumFunction(fnName: String) { - if (c.typeArgumentsCount != 1) { + if (c.codeQlTypeArgumentsCount != 1) { logger.errorElement("Expected to find exactly one type argument", c) return } - val enumType = (c.getTypeArgument(0) as? IrSimpleType)?.classifier?.owner + val enumType = (c.codeQlGetTypeArgument(0) as? IrSimpleType)?.classifier?.owner if (enumType == null) { logger.errorElement("Couldn't find type of enum type", c) return @@ -4178,13 +4178,13 @@ open class KotlinFileExtractor( } else { extractExpressionExpr(receiver, callable, id, 0, enclosingStmt) } - if (c.valueArgumentsCount < 1) { + if (c.codeQlValueArgumentsCount < 1) { logger.errorElement("No RHS found", c) } else { - if (c.valueArgumentsCount > 1) { + if (c.codeQlValueArgumentsCount > 1) { logger.errorElement("Extra arguments found", c) } - val arg = c.getValueArgument(0) + val arg = c.codeQlGetValueArgument(0) if (arg == null) { logger.errorElement("RHS null", c) } else { @@ -4205,7 +4205,7 @@ open class KotlinFileExtractor( } else { extractExpressionExpr(receiver, callable, id, 0, enclosingStmt) } - if (c.valueArgumentsCount > 0) { + if (c.codeQlValueArgumentsCount > 0) { logger.errorElement("Extra arguments found", c) } } @@ -4219,7 +4219,7 @@ open class KotlinFileExtractor( } fun binopExt(id: Label) { - binopReceiver(id, c.extensionReceiver, "Extension receiver") + binopReceiver(id, c.codeQlExtensionReceiver, "Extension receiver") } fun unaryopDisp(id: Label) { @@ -4227,7 +4227,7 @@ open class KotlinFileExtractor( } fun unaryopExt(id: Label) { - unaryopReceiver(id, c.extensionReceiver, "Extension receiver") + unaryopReceiver(id, c.codeQlExtensionReceiver, "Extension receiver") } val dr = c.dispatchReceiver @@ -4249,7 +4249,7 @@ open class KotlinFileExtractor( parent, idx, enclosingStmt, - listOf(c.extensionReceiver, c.getValueArgument(0)), + listOf(c.codeQlExtensionReceiver, c.codeQlGetValueArgument(0)), null, null ) @@ -4350,7 +4350,7 @@ open class KotlinFileExtractor( // != gets desugared into not and ==. Here we resugar it. c.origin == IrStatementOrigin.EXCLEQ && isFunction(target, "kotlin", "Boolean", "not") && - c.valueArgumentsCount == 0 && + c.codeQlValueArgumentsCount == 0 && dr != null && dr is IrCall && isBuiltinCallInternal(dr, "EQEQ") -> { @@ -4362,7 +4362,7 @@ open class KotlinFileExtractor( } c.origin == IrStatementOrigin.EXCLEQEQ && isFunction(target, "kotlin", "Boolean", "not") && - c.valueArgumentsCount == 0 && + c.codeQlValueArgumentsCount == 0 && dr != null && dr is IrCall && isBuiltinCallInternal(dr, "EQEQEQ") -> { @@ -4374,7 +4374,7 @@ open class KotlinFileExtractor( } c.origin == IrStatementOrigin.EXCLEQ && isFunction(target, "kotlin", "Boolean", "not") && - c.valueArgumentsCount == 0 && + c.codeQlValueArgumentsCount == 0 && dr != null && dr is IrCall && isBuiltinCallInternal(dr, "ieee754equals") -> { @@ -4576,7 +4576,7 @@ open class KotlinFileExtractor( parent, idx, enclosingStmt, - listOf(c.extensionReceiver), + listOf(c.codeQlExtensionReceiver), null, null ) @@ -4596,8 +4596,8 @@ open class KotlinFileExtractor( val locId = tw.getLocation(c) extractExprContext(id, locId, callable, enclosingStmt) - if (c.typeArgumentsCount == 1) { - val typeArgument = c.getTypeArgument(0) + if (c.codeQlTypeArgumentsCount == 1) { + val typeArgument = c.codeQlGetTypeArgument(0) if (typeArgument == null) { logger.errorElement("Type argument missing in an arrayOfNulls call", c) } else { @@ -4618,8 +4618,8 @@ open class KotlinFileExtractor( ) } - if (c.valueArgumentsCount == 1) { - val dim = c.getValueArgument(0) + if (c.codeQlValueArgumentsCount == 1) { + val dim = c.codeQlGetValueArgument(0) if (dim != null) { extractExpressionExpr(dim, callable, id, 0, enclosingStmt) } else { @@ -4651,8 +4651,8 @@ open class KotlinFileExtractor( c.type.getArrayElementTypeCodeQL(pluginContext.irBuiltIns) } else { // TODO: is there any reason not to always use getArrayElementTypeCodeQL? - if (c.typeArgumentsCount == 1) { - c.getTypeArgument(0).also { + if (c.codeQlTypeArgumentsCount == 1) { + c.codeQlGetTypeArgument(0).also { if (it == null) { logger.errorElement( "Type argument missing in an arrayOf call", @@ -4670,7 +4670,7 @@ open class KotlinFileExtractor( } val arg = - if (c.valueArgumentsCount == 1) c.getValueArgument(0) + if (c.codeQlValueArgumentsCount == 1) c.codeQlGetValueArgument(0) else { logger.errorElement( "Expected to find only one (vararg) argument in ${c.symbol.owner.name.asString()} call", @@ -4719,7 +4719,7 @@ open class KotlinFileExtractor( return } - val ext = c.extensionReceiver + val ext = c.codeQlExtensionReceiver if (ext == null) { logger.errorElement( "No extension receiver found for `KClass::java` call", @@ -4826,8 +4826,8 @@ open class KotlinFileExtractor( c.origin == IrStatementOrigin.EQ && c.dispatchReceiver != null -> { val array = c.dispatchReceiver - val arrayIdx = c.getValueArgument(0) - val assignedValue = c.getValueArgument(1) + val arrayIdx = c.codeQlGetValueArgument(0) + val assignedValue = c.codeQlGetValueArgument(1) if (array != null && arrayIdx != null && assignedValue != null) { @@ -4882,22 +4882,22 @@ open class KotlinFileExtractor( } isBuiltinCall(c, "", "kotlin.jvm.internal") -> { - if (c.valueArgumentsCount != 1) { + if (c.codeQlValueArgumentsCount != 1) { logger.errorElement( - "Expected to find one argument for a kotlin.jvm.internal.() call, but found ${c.valueArgumentsCount}", + "Expected to find one argument for a kotlin.jvm.internal.() call, but found ${c.codeQlValueArgumentsCount}", c ) return } - if (c.typeArgumentsCount != 2) { + if (c.codeQlTypeArgumentsCount != 2) { logger.errorElement( - "Expected to find two type arguments for a kotlin.jvm.internal.() call, but found ${c.typeArgumentsCount}", + "Expected to find two type arguments for a kotlin.jvm.internal.() call, but found ${c.codeQlTypeArgumentsCount}", c ) return } - val valueArg = c.getValueArgument(0) + val valueArg = c.codeQlGetValueArgument(0) if (valueArg == null) { logger.errorElement( "Cannot find value argument for a kotlin.jvm.internal.() call", @@ -4905,7 +4905,7 @@ open class KotlinFileExtractor( ) return } - val typeArg = c.getTypeArgument(1) + val typeArg = c.codeQlGetTypeArgument(1) if (typeArg == null) { logger.errorElement( "Cannot find type argument for a kotlin.jvm.internal.() call", @@ -4924,7 +4924,7 @@ open class KotlinFileExtractor( extractExpressionExpr(valueArg, callable, id, 1, enclosingStmt) } isBuiltinCallInternal(c, "dataClassArrayMemberToString") -> { - val arrayArg = c.getValueArgument(0) + val arrayArg = c.codeQlGetValueArgument(0) val realArrayClass = arrayArg?.type?.classOrNull if (realArrayClass == null) { logger.errorElement( @@ -4936,8 +4936,8 @@ open class KotlinFileExtractor( val realCallee = javaUtilArrays?.declarations?.findSubType { decl -> decl.name.asString() == "toString" && - decl.valueParameters.size == 1 && - decl.valueParameters[0].type.classOrNull?.let { + decl.codeQlValueParameters.size == 1 && + decl.codeQlValueParameters[0].type.classOrNull?.let { it == realArrayClass } == true } @@ -4962,7 +4962,7 @@ open class KotlinFileExtractor( } } isBuiltinCallInternal(c, "dataClassArrayMemberHashCode") -> { - val arrayArg = c.getValueArgument(0) + val arrayArg = c.codeQlGetValueArgument(0) val realArrayClass = arrayArg?.type?.classOrNull if (realArrayClass == null) { logger.errorElement( @@ -4974,8 +4974,8 @@ open class KotlinFileExtractor( val realCallee = javaUtilArrays?.declarations?.findSubType { decl -> decl.name.asString() == "hashCode" && - decl.valueParameters.size == 1 && - decl.valueParameters[0].type.classOrNull?.let { + decl.codeQlValueParameters.size == 1 && + decl.codeQlValueParameters[0].type.classOrNull?.let { it == realArrayClass } == true } @@ -5155,7 +5155,7 @@ open class KotlinFileExtractor( val type = useType(eType) val isAnonymous = eType.isAnonymous val locId = tw.getLocation(e) - val valueArgs = (0 until e.valueArgumentsCount).map { e.getValueArgument(it) } + val valueArgs = (0 until e.codeQlValueArgumentsCount).map { e.codeQlGetValueArgument(it) } val id = if ( @@ -5211,10 +5211,10 @@ open class KotlinFileExtractor( realCallTarget is IrConstructor && realCallTarget.parentClassOrNull?.fqNameWhenAvailable?.asString() == "kotlin.Enum" && - realCallTarget.valueParameters.size == 2 && - realCallTarget.valueParameters[0].type == + realCallTarget.codeQlValueParameters.size == 2 && + realCallTarget.codeQlValueParameters[0].type == pluginContext.irBuiltIns.stringType && - realCallTarget.valueParameters[1].type == pluginContext.irBuiltIns.intType + realCallTarget.codeQlValueParameters[1].type == pluginContext.irBuiltIns.intType ) { val id0 = @@ -5287,7 +5287,7 @@ open class KotlinFileExtractor( } val args = - (0 until e.typeArgumentsCount).map { e.getTypeArgument(it) }.requireNoNullsOrNull() + (0 until e.codeQlTypeArgumentsCount).map { e.codeQlGetTypeArgument(it) }.requireNoNullsOrNull() if (args == null) { logger.warnElement("Found null type argument in enum constructor call", e) return @@ -5365,7 +5365,7 @@ open class KotlinFileExtractor( // Check for an expression like x = get(x).op(e): val opReceiver = updateRhs.dispatchReceiver if (isExpectedLhs(opReceiver)) { - updateRhs.getValueArgument(0) + updateRhs.codeQlGetValueArgument(0) } else null } else null } @@ -5560,7 +5560,7 @@ open class KotlinFileExtractor( "set" ) ) { - val updateRhs0 = arraySetCall.getValueArgument(1) + val updateRhs0 = arraySetCall.codeQlGetValueArgument(1) if (updateRhs0 == null) { logger.errorElement("Update RHS not found", e) return false @@ -6403,12 +6403,12 @@ open class KotlinFileExtractor( val ids = getLocallyVisibleFunctionLabels(e.function) val locId = tw.getLocation(e) - val ext = e.function.extensionReceiverParameter + val ext = e.function.codeQlExtensionReceiverParameter val parameters = if (ext != null) { - listOf(ext) + e.function.valueParameters + listOf(ext) + e.function.codeQlValueParameters } else { - e.function.valueParameters + e.function.codeQlValueParameters } var types = parameters.map { it.type } @@ -6670,7 +6670,7 @@ open class KotlinFileExtractor( is IrFunction -> { if ( ownerParent.dispatchReceiverParameter == owner && - ownerParent.extensionReceiverParameter != null + ownerParent.codeQlExtensionReceiverParameter != null ) { val ownerParent2 = ownerParent.parent @@ -7089,7 +7089,7 @@ open class KotlinFileExtractor( makeReceiverInfo(callableReferenceExpr.dispatchReceiver, 0) private val extensionReceiverInfo = makeReceiverInfo( - callableReferenceExpr.extensionReceiver, + callableReferenceExpr.codeQlExtensionReceiver, if (dispatchReceiverInfo == null) 0 else 1 ) @@ -7627,8 +7627,8 @@ open class KotlinFileExtractor( } val expressionTypeArguments = - (0 until propertyReferenceExpr.typeArgumentsCount).mapNotNull { - propertyReferenceExpr.getTypeArgument(it) + (0 until propertyReferenceExpr.codeQlTypeArgumentsCount).mapNotNull { + propertyReferenceExpr.codeQlGetTypeArgument(it) } val idPropertyRef = tw.getFreshIdLabel() @@ -7829,7 +7829,7 @@ open class KotlinFileExtractor( if ( functionReferenceExpr.dispatchReceiver != null && - functionReferenceExpr.extensionReceiver != null + functionReferenceExpr.codeQlExtensionReceiver != null ) { logger.errorElement( "Unexpected: dispatchReceiver and extensionReceiver are both non-null", @@ -7840,7 +7840,7 @@ open class KotlinFileExtractor( if ( target.owner.dispatchReceiverParameter != null && - target.owner.extensionReceiverParameter != null + target.owner.codeQlExtensionReceiverParameter != null ) { logger.errorElement( "Unexpected: dispatch and extension parameters are both non-null", @@ -7899,8 +7899,8 @@ open class KotlinFileExtractor( null } expressionTypeArguments = - (0 until functionReferenceExpr.typeArgumentsCount).mapNotNull { - functionReferenceExpr.getTypeArgument(it) + (0 until functionReferenceExpr.codeQlTypeArgumentsCount).mapNotNull { + functionReferenceExpr.codeQlGetTypeArgument(it) } dispatchReceiverIdx = -1 } @@ -7965,7 +7965,7 @@ open class KotlinFileExtractor( functionReferenceExpr, declarationParent, null, - { it.valueParameters.size == 1 } + { it.codeQlValueParameters.size == 1 } ) { // The argument to FunctionReference's constructor is the function arity. extractConstantInteger( @@ -8572,7 +8572,7 @@ open class KotlinFileExtractor( reverse: Boolean = false ) { val typeArguments = - (0 until c.typeArgumentsCount).map { c.getTypeArgument(it) }.requireNoNullsOrNull() + (0 until c.codeQlTypeArgumentsCount).map { c.codeQlGetTypeArgument(it) }.requireNoNullsOrNull() if (typeArguments == null) { logger.errorElement("Found a null type argument for a member access expression", c) } else { @@ -8923,11 +8923,11 @@ open class KotlinFileExtractor( tw.writeVariableBinding(lhsId, fieldId) val parameters = mutableListOf() - val extParam = samMember.extensionReceiverParameter + val extParam = samMember.codeQlExtensionReceiverParameter if (extParam != null) { parameters.add(extParam) } - parameters.addAll(samMember.valueParameters) + parameters.addAll(samMember.codeQlValueParameters) fun extractArgument( p: IrValueParameter, @@ -9032,7 +9032,7 @@ open class KotlinFileExtractor( elementToReportOn: IrElement, declarationParent: IrDeclarationParent, compilerGeneratedKindOverride: CompilerGeneratedKinds? = null, - superConstructorSelector: (IrFunction) -> Boolean = { it.valueParameters.isEmpty() }, + superConstructorSelector: (IrFunction) -> Boolean = { it.codeQlValueParameters.isEmpty() }, extractSuperconstructorArgs: (Label) -> Unit = {}, ): Label { // Write class diff --git a/java/kotlin-extractor/src/main/kotlin/KotlinUsesExtractor.kt b/java/kotlin-extractor/src/main/kotlin/KotlinUsesExtractor.kt index 93e032a0541..b3577858f99 100644 --- a/java/kotlin-extractor/src/main/kotlin/KotlinUsesExtractor.kt +++ b/java/kotlin-extractor/src/main/kotlin/KotlinUsesExtractor.kt @@ -12,7 +12,7 @@ import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.symbols.* -import org.jetbrains.kotlin.ir.types.addAnnotations +import com.github.codeql.utils.versions.codeQlAddAnnotations import org.jetbrains.kotlin.ir.types.classFqName import org.jetbrains.kotlin.ir.types.classifierOrNull import org.jetbrains.kotlin.ir.types.classOrNull @@ -355,7 +355,7 @@ open class KotlinUsesExtractor( } private fun propertySignature(p: IrProperty) = - ((p.getter ?: p.setter)?.extensionReceiverParameter?.let { + ((p.getter ?: p.setter)?.codeQlExtensionReceiverParameter?.let { useType(erase(it.type)).javaResult.signature } ?: "") @@ -368,7 +368,7 @@ open class KotlinUsesExtractor( // useDeclarationParent -> useFunction // -> extractFunctionLaterIfExternalFileMember, which would result for `fun f(t: // T) { ... }` for example. - (listOfNotNull(d.extensionReceiverParameter) + d.valueParameters) + (listOfNotNull(d.codeQlExtensionReceiverParameter) + d.codeQlValueParameters) .map { useType(erase(it.type)).javaResult.signature } .joinToString(separator = ",", prefix = "(", postfix = ")") is IrProperty -> propertySignature(d) + externalClassExtractor.propertySignature @@ -488,8 +488,8 @@ open class KotlinUsesExtractor( val result = replacementClass.declarations.findSubType { replacementDecl -> replacementDecl.name == f.name && - replacementDecl.valueParameters.size == f.valueParameters.size && - replacementDecl.valueParameters.zip(f.valueParameters).all { + replacementDecl.codeQlValueParameters.size == f.codeQlValueParameters.size && + replacementDecl.codeQlValueParameters.zip(f.codeQlValueParameters).all { erase(it.first.type) == erase(it.second.type) } } @@ -1265,7 +1265,7 @@ open class KotlinUsesExtractor( private fun getWildcardSuppressionDirective(t: IrAnnotationContainer): Boolean? = t.getAnnotation(jvmWildcardSuppressionAnnotation)?.let { @Suppress("USELESS_CAST") // `as? Boolean` is not needed for Kotlin < 2.1 - (it.getValueArgument(0) as? CodeQLIrConst)?.value as? Boolean ?: true + (it.codeQlGetValueArgument(0) as? CodeQLIrConst)?.value as? Boolean ?: true } private fun addJavaLoweringArgumentWildcards( @@ -1376,9 +1376,9 @@ open class KotlinUsesExtractor( f.parent, parentId, getFunctionShortName(f).nameInDB, - (maybeParameterList ?: f.valueParameters).map { it.type }, + (maybeParameterList ?: f.codeQlValueParameters).map { it.type }, getAdjustedReturnType(f), - f.extensionReceiverParameter?.type, + f.codeQlExtensionReceiverParameter?.type, getFunctionTypeParameters(f), classTypeArgsIncludingOuterClasses, overridesCollectionsMethodWithAlteredParameterTypes(f), @@ -1401,12 +1401,12 @@ open class KotlinUsesExtractor( // The name of the function; normally f.name.asString(). name: String, // The types of the value parameters that the functions takes; normally - // f.valueParameters.map { it.type }. + // f.codeQlValueParameters.map { it.type }. parameterTypes: List, // The return type of the function; normally f.returnType. returnType: IrType, // The extension receiver of the function, if any; normally - // f.extensionReceiverParameter?.type. + // f.codeQlExtensionReceiverParameter?.type. extensionParamType: IrType?, // The type parameters of the function. This does not include type parameters of enclosing // classes. @@ -1579,7 +1579,7 @@ open class KotlinUsesExtractor( parentClass.fqNameWhenAvailable?.asString() != "java.util.concurrent.ConcurrentHashMap" || getFunctionShortName(f).nameInDB != "keySet" || - f.valueParameters.isNotEmpty() || + f.codeQlValueParameters.isNotEmpty() || f.returnType.classFqName?.asString() != "kotlin.collections.MutableSet" ) { return f.returnType @@ -1587,7 +1587,7 @@ open class KotlinUsesExtractor( val otherKeySet = parentClass.declarations.findSubType { - it.name.asString() == "keySet" && it.valueParameters.size == 1 + it.name.asString() == "keySet" && it.codeQlValueParameters.size == 1 } ?: return f.returnType return otherKeySet.returnType.codeQlWithHasQuestionMark(false) @@ -1695,8 +1695,8 @@ open class KotlinUsesExtractor( javaClass.declarations.findSubType { decl -> !decl.isFakeOverride && decl.name.asString() == jvmName && - decl.valueParameters.size == f.valueParameters.size && - decl.valueParameters.zip(f.valueParameters).all { p -> + decl.codeQlValueParameters.size == f.codeQlValueParameters.size && + decl.codeQlValueParameters.zip(f.codeQlValueParameters).all { p -> erase(p.first.type).classifierOrNull == erase(p.second.type).classifierOrNull } @@ -2125,7 +2125,7 @@ open class KotlinUsesExtractor( } return if (t.arguments.isNotEmpty()) - t.addAnnotations(listOf(RawTypeAnnotation.annotationConstructor)) + t.codeQlAddAnnotations(listOf(RawTypeAnnotation.annotationConstructor)) else t } } @@ -2153,7 +2153,7 @@ open class KotlinUsesExtractor( val idxOffset = if ( declarationParent is IrFunction && - declarationParent.extensionReceiverParameter != null + declarationParent.codeQlExtensionReceiverParameter != null ) // For extension functions increase the index to match what the java extractor sees: 1 @@ -2187,7 +2187,7 @@ open class KotlinUsesExtractor( // Gets a field's corresponding property's extension receiver type, if any fun getExtensionReceiverType(f: IrField) = f.correspondingPropertySymbol?.owner?.let { - (it.getter ?: it.setter)?.extensionReceiverParameter?.type + (it.getter ?: it.setter)?.codeQlExtensionReceiverParameter?.type } fun getFieldLabel(f: IrField): String { @@ -2222,14 +2222,14 @@ open class KotlinUsesExtractor( val setter = p.setter val func = getter ?: setter - val ext = func?.extensionReceiverParameter + val ext = func?.codeQlExtensionReceiverParameter return if (ext == null) { "@\"property;{$parentId};${p.name.asString()}\"" } else { val returnType = getter?.returnType - ?: setter?.valueParameters?.singleOrNull()?.type + ?: setter?.codeQlValueParameters?.singleOrNull()?.type ?: pluginContext.irBuiltIns.unitType val typeParams = getFunctionTypeParameters(func) diff --git a/java/kotlin-extractor/src/main/kotlin/MetaAnnotationSupport.kt b/java/kotlin-extractor/src/main/kotlin/MetaAnnotationSupport.kt index 96d5dd8bbbd..e215b5ca31d 100644 --- a/java/kotlin-extractor/src/main/kotlin/MetaAnnotationSupport.kt +++ b/java/kotlin-extractor/src/main/kotlin/MetaAnnotationSupport.kt @@ -1,5 +1,10 @@ package com.github.codeql +import com.github.codeql.utils.versions.codeQlAnnotationFromSymbolOwner +import com.github.codeql.utils.versions.codeQlGetValueArgument +import com.github.codeql.utils.versions.codeQlPutValueArgument +import com.github.codeql.utils.versions.codeQlSetAnnotations +import com.github.codeql.utils.versions.codeQlSetDispatchReceiverParameter import com.github.codeql.utils.versions.createImplicitParameterDeclarationWithWrappedDescriptor import java.lang.annotation.ElementType import java.util.HashSet @@ -95,7 +100,7 @@ class MetaAnnotationSupport( JvmAnnotationNames.REPEATABLE_ANNOTATION } return if (jvmRepeatable != null) { - ((jvmRepeatable.getValueArgument(0) as? IrClassReference)?.symbol as? IrClassSymbol) + ((jvmRepeatable.codeQlGetValueArgument(0) as? IrClassReference)?.symbol as? IrClassSymbol) ?.owner } else { getOrCreateSyntheticRepeatableAnnotationContainer(annotationClass) @@ -117,12 +122,12 @@ class MetaAnnotationSupport( ) return null } else { - return IrConstructorCallImpl.fromSymbolOwner( + return codeQlAnnotationFromSymbolOwner( containerClass.defaultType, containerConstructor.symbol ) .apply { - putValueArgument( + codeQlPutValueArgument( 0, IrVarargImpl( UNDEFINED_OFFSET, @@ -144,7 +149,7 @@ class MetaAnnotationSupport( // Taken from AdditionalClassAnnotationLowering.kt private fun loadAnnotationTargets(targetEntry: IrConstructorCall): Set? { - val valueArgument = targetEntry.getValueArgument(0) as? IrVararg ?: return null + val valueArgument = targetEntry.codeQlGetValueArgument(0) as? IrVararg ?: return null return valueArgument.elements .filterIsInstance() .mapNotNull { KotlinTarget.valueOrNull(it.symbol.owner.name.asString()) } @@ -230,14 +235,14 @@ class MetaAnnotationSupport( ) } - return IrConstructorCallImpl.fromSymbolOwner( + return codeQlAnnotationFromSymbolOwner( UNDEFINED_OFFSET, UNDEFINED_OFFSET, targetConstructor.returnType, targetConstructor.symbol, 0 ) - .apply { putValueArgument(0, vararg) } + .apply { codeQlPutValueArgument(0, vararg) } } private val javaAnnotationRetention by lazy { @@ -263,7 +268,7 @@ class MetaAnnotationSupport( // Taken from AnnotationCodegen.kt (not available in Kotlin < 1.6.20) private fun IrClass.getAnnotationRetention(): KotlinRetention? { val retentionArgument = - getAnnotation(StandardNames.FqNames.retention)?.getValueArgument(0) as? IrGetEnumValue + getAnnotation(StandardNames.FqNames.retention)?.codeQlGetValueArgument(0) as? IrGetEnumValue ?: return null val retentionArgumentValue = retentionArgument.symbol.owner return KotlinRetention.valueOf(retentionArgumentValue.name.asString()) @@ -283,7 +288,7 @@ class MetaAnnotationSupport( val targetConstructor = retentionType.declarations.firstIsInstanceOrNull() ?: return null - return IrConstructorCallImpl.fromSymbolOwner( + return codeQlAnnotationFromSymbolOwner( UNDEFINED_OFFSET, UNDEFINED_OFFSET, targetConstructor.returnType, @@ -291,7 +296,7 @@ class MetaAnnotationSupport( 0 ) .apply { - putValueArgument( + codeQlPutValueArgument( 0, IrGetEnumValueImpl( UNDEFINED_OFFSET, @@ -333,7 +338,7 @@ class MetaAnnotationSupport( return } val newParam = thisReceiever.copyTo(this) - dispatchReceiverParameter = newParam + codeQlSetDispatchReceiverParameter(newParam) body = factory .createBlockBody(UNDEFINED_OFFSET, UNDEFINED_OFFSET) @@ -406,7 +411,7 @@ class MetaAnnotationSupport( val repeatableContainerAnnotation = kotlinAnnotationRepeatableContainer?.constructors?.single() - containerClass.annotations = + codeQlSetAnnotations(containerClass, annotationClass.annotations .filter { it.isAnnotationWithEqualFqName(StandardNames.FqNames.retention) || @@ -415,7 +420,7 @@ class MetaAnnotationSupport( .map { it.deepCopyWithSymbols(containerClass) } + listOfNotNull( repeatableContainerAnnotation?.let { - IrConstructorCallImpl.fromSymbolOwner( + codeQlAnnotationFromSymbolOwner( UNDEFINED_OFFSET, UNDEFINED_OFFSET, it.returnType, @@ -424,6 +429,7 @@ class MetaAnnotationSupport( ) } ) + ) containerClass } @@ -462,14 +468,14 @@ class MetaAnnotationSupport( containerClass.symbol, containerClass.defaultType ) - return IrConstructorCallImpl.fromSymbolOwner( + return codeQlAnnotationFromSymbolOwner( UNDEFINED_OFFSET, UNDEFINED_OFFSET, repeatableConstructor.returnType, repeatableConstructor.symbol, 0 ) - .apply { putValueArgument(0, containerReference) } + .apply { codeQlPutValueArgument(0, containerReference) } } private val javaAnnotationDocumented by lazy { @@ -488,7 +494,7 @@ class MetaAnnotationSupport( javaAnnotationDocumented?.declarations?.firstIsInstanceOrNull() ?: return null - return IrConstructorCallImpl.fromSymbolOwner( + return codeQlAnnotationFromSymbolOwner( UNDEFINED_OFFSET, UNDEFINED_OFFSET, documentedConstructor.returnType, diff --git a/java/kotlin-extractor/src/main/kotlin/TrapWriter.kt b/java/kotlin-extractor/src/main/kotlin/TrapWriter.kt index da04893b4d0..3ff4adb2eee 100644 --- a/java/kotlin-extractor/src/main/kotlin/TrapWriter.kt +++ b/java/kotlin-extractor/src/main/kotlin/TrapWriter.kt @@ -1,6 +1,7 @@ package com.github.codeql import com.github.codeql.KotlinUsesExtractor.LocallyVisibleFunctionLabels +import com.github.codeql.utils.versions.codeQlExtensionReceiver import com.semmle.extractor.java.PopulateFile import com.semmle.util.unicode.UTF8Util import java.io.BufferedWriter @@ -331,7 +332,7 @@ open class FileTrapWriter( is IrCall -> { // Calls have incorrect startOffset, so we adjust them: val dr = e.dispatchReceiver?.let { getStartOffset(it) } - val er = e.extensionReceiver?.let { getStartOffset(it) } + val er = e.codeQlExtensionReceiver?.let { getStartOffset(it) } offsetMinOf(e.startOffset, dr, er) } else -> e.startOffset diff --git a/java/kotlin-extractor/src/main/kotlin/comments/CommentExtractor.kt b/java/kotlin-extractor/src/main/kotlin/comments/CommentExtractor.kt index 322cffc87f3..a27af84bb70 100644 --- a/java/kotlin-extractor/src/main/kotlin/comments/CommentExtractor.kt +++ b/java/kotlin-extractor/src/main/kotlin/comments/CommentExtractor.kt @@ -2,6 +2,7 @@ package com.github.codeql.comments import com.github.codeql.* import com.github.codeql.utils.isLocalFunction +import com.github.codeql.utils.versions.codeQlExtensionReceiverParameter import com.github.codeql.utils.versions.isDispatchReceiver import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.declarations.* @@ -11,7 +12,7 @@ import org.jetbrains.kotlin.ir.util.parentClassOrNull private fun IrValueParameter.isExtensionReceiver(): Boolean { val parentFun = parent as? IrFunction ?: return false - return parentFun.extensionReceiverParameter == this + return parentFun.codeQlExtensionReceiverParameter == this } open class CommentExtractor( diff --git a/java/kotlin-extractor/src/main/kotlin/utils/JvmNames.kt b/java/kotlin-extractor/src/main/kotlin/utils/JvmNames.kt index 02059b3db64..cfefb69c111 100644 --- a/java/kotlin-extractor/src/main/kotlin/utils/JvmNames.kt +++ b/java/kotlin-extractor/src/main/kotlin/utils/JvmNames.kt @@ -1,6 +1,8 @@ package com.github.codeql.utils import com.github.codeql.utils.versions.CodeQLIrConst +import com.github.codeql.utils.versions.codeQlGetValueArgument +import com.github.codeql.utils.versions.codeQlValueArgumentsCount import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.ir.declarations.IrAnnotationContainer import org.jetbrains.kotlin.ir.declarations.IrClass @@ -76,9 +78,9 @@ private fun getSpecialJvmName(f: IrFunction): String? { fun getJvmName(container: IrAnnotationContainer): String? { for (a: IrConstructorCall in container.annotations) { val t = a.type - if (t is IrSimpleType && a.valueArgumentsCount == 1) { + if (t is IrSimpleType && a.codeQlValueArgumentsCount == 1) { val owner = t.classifier.owner - val v = a.getValueArgument(0) + val v = a.codeQlGetValueArgument(0) if (owner is IrClass) { val aPkg = owner.packageFqName?.asString() val name = owner.name.asString() diff --git a/java/kotlin-extractor/src/main/kotlin/utils/TypeSubstitution.kt b/java/kotlin-extractor/src/main/kotlin/utils/TypeSubstitution.kt index 10f0dbde887..c990edc213f 100644 --- a/java/kotlin-extractor/src/main/kotlin/utils/TypeSubstitution.kt +++ b/java/kotlin-extractor/src/main/kotlin/utils/TypeSubstitution.kt @@ -18,7 +18,7 @@ import org.jetbrains.kotlin.ir.expressions.IrConstructorCall import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol import org.jetbrains.kotlin.ir.symbols.impl.DescriptorlessExternalPackageFragmentSymbol -import org.jetbrains.kotlin.ir.types.addAnnotations +import com.github.codeql.utils.versions.codeQlAddAnnotations import org.jetbrains.kotlin.ir.types.classifierOrNull import org.jetbrains.kotlin.ir.types.makeNotNull import org.jetbrains.kotlin.ir.types.makeNullable @@ -192,7 +192,7 @@ object RawTypeAnnotation { addConstructor { isPrimary = true } } val constructor = annoClass.constructors.single() - IrConstructorCallImpl.fromSymbolOwner(constructor.constructedClassType, constructor.symbol) + codeQlAnnotationFromSymbolOwner(constructor.constructedClassType, constructor.symbol) } } @@ -202,7 +202,7 @@ fun IrType.toRawType(): IrType = when (val owner = this.classifier.owner) { is IrClass -> { if (this.arguments.isNotEmpty()) - this.addAnnotations(listOf(RawTypeAnnotation.annotationConstructor)) + this.codeQlAddAnnotations(listOf(RawTypeAnnotation.annotationConstructor)) else this } is IrTypeParameter -> owner.superTypes[0].toRawType() @@ -215,7 +215,7 @@ fun IrType.toRawType(): IrType = fun IrClass.toRawType(): IrType { val result = this.typeWith(listOf()) return if (this.typeParameters.isNotEmpty()) - result.addAnnotations(listOf(RawTypeAnnotation.annotationConstructor)) + result.codeQlAddAnnotations(listOf(RawTypeAnnotation.annotationConstructor)) else result } diff --git a/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_8_0/IrCompat.kt b/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_8_0/IrCompat.kt new file mode 100644 index 00000000000..5650b1e1e71 --- /dev/null +++ b/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_8_0/IrCompat.kt @@ -0,0 +1,70 @@ +package com.github.codeql.utils.versions + +import org.jetbrains.kotlin.ir.declarations.IrFunction +import org.jetbrains.kotlin.ir.declarations.IrValueParameter +import org.jetbrains.kotlin.ir.expressions.IrConstructorCall +import org.jetbrains.kotlin.ir.expressions.IrExpression +import org.jetbrains.kotlin.ir.expressions.IrMemberAccessExpression +import org.jetbrains.kotlin.ir.expressions.impl.* +import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol +import org.jetbrains.kotlin.ir.types.IrType +import org.jetbrains.kotlin.ir.types.addAnnotations + +/** + * Compatibility accessors for pre-2.4.0 API patterns. + * In pre-2.4.0 versions, these delegate directly to the existing APIs. + */ + +// IrFunction: valueParameters +val IrFunction.codeQlValueParameters: List + get() = valueParameters + +// IrFunction: extensionReceiverParameter +val IrFunction.codeQlExtensionReceiverParameter: IrValueParameter? + get() = extensionReceiverParameter + +// IrMemberAccessExpression: valueArgumentsCount +val IrMemberAccessExpression<*>.codeQlValueArgumentsCount: Int + get() = valueArgumentsCount + +// IrMemberAccessExpression: getValueArgument +fun IrMemberAccessExpression<*>.codeQlGetValueArgument(index: Int): IrExpression? = getValueArgument(index) + +// IrMemberAccessExpression: putValueArgument +fun IrMemberAccessExpression<*>.codeQlPutValueArgument(index: Int, value: IrExpression?) { + putValueArgument(index, value) +} + +// IrMemberAccessExpression: extensionReceiver +val IrMemberAccessExpression<*>.codeQlExtensionReceiver: IrExpression? + get() = extensionReceiver + +// IrMemberAccessExpression: typeArgumentsCount +val IrMemberAccessExpression<*>.codeQlTypeArgumentsCount: Int + get() = typeArgumentsCount + +// IrMemberAccessExpression: getTypeArgument +fun IrMemberAccessExpression<*>.codeQlGetTypeArgument(index: Int): IrType? = getTypeArgument(index) + +// addAnnotations compat: in pre-2.4.0, addAnnotations expects List +fun IrType.codeQlAddAnnotations(annotations: List): IrType = + addAnnotations(annotations) + +// IrMutableAnnotationContainer.annotations setter: in pre-2.4.0, annotations is var with List +fun codeQlSetAnnotations(container: org.jetbrains.kotlin.ir.declarations.IrMutableAnnotationContainer, annotations: List) { + container.annotations = annotations +} + +// IrFunction: set dispatch receiver parameter (pre-2.4.0 it's a var) +fun IrFunction.codeQlSetDispatchReceiverParameter(param: IrValueParameter?) { + dispatchReceiverParameter = param +} + +// In pre-2.4.0, annotations are List so IrConstructorCallImpl works directly. +fun codeQlAnnotationFromSymbolOwner( + startOffset: Int, endOffset: Int, type: IrType, symbol: IrConstructorSymbol, typeArgumentsCount: Int +): IrConstructorCall = + IrConstructorCallImpl.fromSymbolOwner(startOffset, endOffset, type, symbol, typeArgumentsCount) + +fun codeQlAnnotationFromSymbolOwner(type: IrType, symbol: IrConstructorSymbol): IrConstructorCall = + IrConstructorCallImpl.fromSymbolOwner(type, symbol) diff --git a/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_8_0/Kotlin2ComponentRegistrar.kt b/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_8_0/Kotlin2ComponentRegistrar.kt index 84c5fc3bfb6..4be3767d04f 100644 --- a/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_8_0/Kotlin2ComponentRegistrar.kt +++ b/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_8_0/Kotlin2ComponentRegistrar.kt @@ -3,10 +3,34 @@ package com.github.codeql +import com.intellij.mock.MockProject +import com.intellij.openapi.extensions.LoadingOrder +import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension import org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar import org.jetbrains.kotlin.compiler.plugin.ExperimentalCompilerApi +import org.jetbrains.kotlin.config.CompilerConfiguration @OptIn(ExperimentalCompilerApi::class) abstract class Kotlin2ComponentRegistrar : ComponentRegistrar { /* Nothing to do; supportsK2 doesn't exist yet. */ + + private var project: MockProject? = null + + override fun registerProjectComponents( + project: MockProject, + configuration: CompilerConfiguration + ) { + this.project = project + doRegisterExtensions(configuration) + } + + abstract fun doRegisterExtensions(configuration: CompilerConfiguration) + + fun registerExtractorExtension(extension: IrGenerationExtension) { + val p = project ?: throw IllegalStateException("registerExtractorExtension called before registerProjectComponents") + // Register with LoadingOrder.LAST to ensure the extractor runs after other + // IR generation plugins (like kotlinx.serialization) have generated their code. + val extensionPoint = p.extensionArea.getExtensionPoint(IrGenerationExtension.extensionPointName) + extensionPoint.registerExtension(extension, LoadingOrder.LAST, p) + } } diff --git a/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_9_0-Beta/Kotlin2ComponentRegistrar.kt b/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_9_0-Beta/Kotlin2ComponentRegistrar.kt index e20c45ddc4d..1225339ed40 100644 --- a/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_9_0-Beta/Kotlin2ComponentRegistrar.kt +++ b/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_9_0-Beta/Kotlin2ComponentRegistrar.kt @@ -3,11 +3,35 @@ package com.github.codeql +import com.intellij.mock.MockProject +import com.intellij.openapi.extensions.LoadingOrder +import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension import org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar import org.jetbrains.kotlin.compiler.plugin.ExperimentalCompilerApi +import org.jetbrains.kotlin.config.CompilerConfiguration @OptIn(ExperimentalCompilerApi::class) abstract class Kotlin2ComponentRegistrar : ComponentRegistrar { override val supportsK2: Boolean get() = true + + private var project: MockProject? = null + + override fun registerProjectComponents( + project: MockProject, + configuration: CompilerConfiguration + ) { + this.project = project + doRegisterExtensions(configuration) + } + + abstract fun doRegisterExtensions(configuration: CompilerConfiguration) + + fun registerExtractorExtension(extension: IrGenerationExtension) { + val p = project ?: throw IllegalStateException("registerExtractorExtension called before registerProjectComponents") + // Register with LoadingOrder.LAST to ensure the extractor runs after other + // IR generation plugins (like kotlinx.serialization) have generated their code. + val extensionPoint = p.extensionArea.getExtensionPoint(IrGenerationExtension.extensionPointName) + extensionPoint.registerExtension(extension, LoadingOrder.LAST, p) + } } diff --git a/java/kotlin-extractor/src/main/kotlin/utils/versions/v_2_4_0/IrCompat.kt b/java/kotlin-extractor/src/main/kotlin/utils/versions/v_2_4_0/IrCompat.kt new file mode 100644 index 00000000000..2906b18c314 --- /dev/null +++ b/java/kotlin-extractor/src/main/kotlin/utils/versions/v_2_4_0/IrCompat.kt @@ -0,0 +1,123 @@ +@file:Suppress("DEPRECATION") + +package com.github.codeql.utils.versions + +import org.jetbrains.kotlin.ir.declarations.IrFunction +import org.jetbrains.kotlin.ir.declarations.IrValueParameter +import org.jetbrains.kotlin.ir.expressions.IrAnnotation +import org.jetbrains.kotlin.ir.expressions.IrConstructorCall +import org.jetbrains.kotlin.ir.expressions.IrExpression +import org.jetbrains.kotlin.ir.expressions.IrMemberAccessExpression +import org.jetbrains.kotlin.ir.expressions.impl.IrAnnotationImpl +import org.jetbrains.kotlin.ir.expressions.impl.fromSymbolOwner +import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol +import org.jetbrains.kotlin.ir.types.IrType +import org.jetbrains.kotlin.ir.types.addAnnotations + +/** + * Compatibility accessors for pre-2.4.0 API patterns. + * In 2.4.0, valueParameters/extensionReceiverParameter/extensionReceiver/ + * getValueArgument/putValueArgument/valueArgumentsCount/typeArgumentsCount/getTypeArgument + * have been removed. This file provides the 2.4.0 implementations. + */ + +// IrFunction: valueParameters -> parameters filtered to Regular kind +val IrFunction.codeQlValueParameters: List + get() = parameters.filter { it.kind == org.jetbrains.kotlin.ir.declarations.IrParameterKind.Regular } + +// IrFunction: extensionReceiverParameter +val IrFunction.codeQlExtensionReceiverParameter: IrValueParameter? + get() = parameters.firstOrNull { it.kind == org.jetbrains.kotlin.ir.declarations.IrParameterKind.ExtensionReceiver } + +// Helper: get the offset of value arguments in the arguments list +private fun IrMemberAccessExpression<*>.valueArgumentOffset(): Int { + val owner = symbol.owner as? IrFunction ?: return 0 + return owner.parameters.count { it.kind != org.jetbrains.kotlin.ir.declarations.IrParameterKind.Regular } +} + +// IrMemberAccessExpression: valueArgumentsCount +// In 2.4.0, arguments[] includes dispatch/extension receivers before regular params +val IrMemberAccessExpression<*>.codeQlValueArgumentsCount: Int + get() = arguments.size - valueArgumentOffset() + +// IrMemberAccessExpression: getValueArgument +// In 2.4.0, arguments[] includes dispatch/extension receivers before regular params +fun IrMemberAccessExpression<*>.codeQlGetValueArgument(index: Int): IrExpression? = arguments[index + valueArgumentOffset()] + +// IrMemberAccessExpression: putValueArgument +// In 2.4.0, arguments[] includes dispatch/extension receivers before regular params +fun IrMemberAccessExpression<*>.codeQlPutValueArgument(index: Int, value: IrExpression?) { + arguments[index + valueArgumentOffset()] = value +} + +// Re-add accessor for the extensionReceiver property removed in Kotlin 2.4.0. +val IrMemberAccessExpression<*>.codeQlExtensionReceiver: IrExpression? + get() { + val erp = extensionReceiverParameterIndex() ?: return null + return arguments[erp] + } + +// Find the argument index corresponding to the extension receiver parameter. +// Calls and function references expose an IrFunction owner directly; property +// references need to look through their getter or setter. +private fun IrMemberAccessExpression<*>.extensionReceiverParameterIndex(): Int? { + // Direct function owner (IrCall, IrFunctionReference, etc.) + (symbol.owner as? IrFunction)?.codeQlExtensionReceiverParameter?.let { + return it.indexInParameters + } + // Property reference: look at getter or setter function + (this as? org.jetbrains.kotlin.ir.expressions.IrPropertyReference)?.let { propRef -> + propRef.getter?.owner?.codeQlExtensionReceiverParameter?.let { + return it.indexInParameters + } + propRef.setter?.owner?.codeQlExtensionReceiverParameter?.let { + return it.indexInParameters + } + } + return null +} + +// IrMemberAccessExpression: typeArgumentsCount +val IrMemberAccessExpression<*>.codeQlTypeArgumentsCount: Int + get() = typeArguments.size + +// IrMemberAccessExpression: getTypeArgument +fun IrMemberAccessExpression<*>.codeQlGetTypeArgument(index: Int): IrType? = typeArguments[index] + +// addAnnotations compat: in 2.4.0, addAnnotations expects List +// IrConstructorCall implements IrAnnotation in 2.4.0, so filterIsInstance is identity +fun IrType.codeQlAddAnnotations(annotations: List): IrType = + addAnnotations(annotations.filterIsInstance()) + +// IrMutableAnnotationContainer.annotations setter: in 2.4.0, expects List +fun codeQlSetAnnotations(container: org.jetbrains.kotlin.ir.declarations.IrMutableAnnotationContainer, annotations: List) { + container.annotations = annotations.filterIsInstance() +} + +// IrFunction: set dispatch receiver parameter +// In 2.4.0, dispatchReceiverParameter is val; modify the parameters list directly. +fun IrFunction.codeQlSetDispatchReceiverParameter(param: IrValueParameter?) { + val existing = parameters.indexOfFirst { it.kind == org.jetbrains.kotlin.ir.declarations.IrParameterKind.DispatchReceiver } + val mutableParams = parameters.toMutableList() + if (existing >= 0) { + if (param != null) { + mutableParams[existing] = param + } else { + mutableParams.removeAt(existing) + } + } else if (param != null) { + param.kind = org.jetbrains.kotlin.ir.declarations.IrParameterKind.DispatchReceiver + mutableParams.add(0, param) + } + parameters = mutableParams +} + +// In 2.4.0, annotation lists require IrAnnotation instances. +// Use IrAnnotationImpl.fromSymbolOwner instead of IrConstructorCallImpl.fromSymbolOwner. +fun codeQlAnnotationFromSymbolOwner( + startOffset: Int, endOffset: Int, type: IrType, symbol: IrConstructorSymbol, typeArgumentsCount: Int +): IrConstructorCall = + IrAnnotationImpl.fromSymbolOwner(startOffset, endOffset, type, symbol, typeArgumentsCount) + +fun codeQlAnnotationFromSymbolOwner(type: IrType, symbol: IrConstructorSymbol): IrConstructorCall = + IrAnnotationImpl.fromSymbolOwner(type, symbol) diff --git a/java/kotlin-extractor/src/main/kotlin/utils/versions/v_2_4_0/Kotlin2ComponentRegistrar.kt b/java/kotlin-extractor/src/main/kotlin/utils/versions/v_2_4_0/Kotlin2ComponentRegistrar.kt new file mode 100644 index 00000000000..2138c355679 --- /dev/null +++ b/java/kotlin-extractor/src/main/kotlin/utils/versions/v_2_4_0/Kotlin2ComponentRegistrar.kt @@ -0,0 +1,45 @@ +package com.github.codeql + +import com.intellij.mock.MockProject +import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension +import org.jetbrains.kotlin.compiler.plugin.CompilerPluginRegistrar +import org.jetbrains.kotlin.compiler.plugin.ExperimentalCompilerApi +import org.jetbrains.kotlin.config.CompilerConfiguration + +@OptIn(ExperimentalCompilerApi::class) +@Suppress("DEPRECATION", "DEPRECATION_ERROR") +abstract class Kotlin2ComponentRegistrar : + CompilerPluginRegistrar(), + org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar { + override val supportsK2: Boolean + get() = true + + override val pluginId: String + get() = "kotlin-extractor" + + // ComponentRegistrar implementation (legacy path, still called by Kotlin compiler) + override fun registerProjectComponents( + project: MockProject, + configuration: CompilerConfiguration + ) { + // Registration is done via ExtensionStorage in Kotlin 2.4+. + // This legacy entry point remains for compatibility with service discovery. + } + + private var extensionStorage: CompilerPluginRegistrar.ExtensionStorage? = null + + override fun ExtensionStorage.registerExtensions(configuration: CompilerConfiguration) { + this@Kotlin2ComponentRegistrar.extensionStorage = this + doRegisterExtensions(configuration) + } + + abstract fun doRegisterExtensions(configuration: CompilerConfiguration) + + protected fun registerExtractorExtension(extension: IrGenerationExtension) { + val storage = extensionStorage + ?: throw IllegalStateException("registerExtractorExtension called before registerExtensions") + with(storage) { + IrGenerationExtension.registerExtension(extension) + } + } +} diff --git a/java/kotlin-extractor/src/main/kotlin/utils/versions/v_2_4_0/parameterIndexExcludingReceivers.kt b/java/kotlin-extractor/src/main/kotlin/utils/versions/v_2_4_0/parameterIndexExcludingReceivers.kt new file mode 100644 index 00000000000..5e9b384b47e --- /dev/null +++ b/java/kotlin-extractor/src/main/kotlin/utils/versions/v_2_4_0/parameterIndexExcludingReceivers.kt @@ -0,0 +1,13 @@ +package com.github.codeql.utils.versions + +import org.jetbrains.kotlin.ir.declarations.IrFunction +import org.jetbrains.kotlin.ir.declarations.IrParameterKind +import org.jetbrains.kotlin.ir.declarations.IrValueParameter + +fun parameterIndexExcludingReceivers(vp: IrValueParameter): Int { + val offset = + (vp.parent as? IrFunction)?.let { f -> + f.parameters.count { it.kind == IrParameterKind.DispatchReceiver || it.kind == IrParameterKind.ExtensionReceiver || it.kind == IrParameterKind.Context } + } ?: 0 + return vp.indexInParameters - offset +} diff --git a/java/kotlin-extractor/src/main/resources/META-INF/services/org.jetbrains.kotlin.compiler.plugin.CompilerPluginRegistrar b/java/kotlin-extractor/src/main/resources/META-INF/services/org.jetbrains.kotlin.compiler.plugin.CompilerPluginRegistrar new file mode 100644 index 00000000000..564ed6bfe25 --- /dev/null +++ b/java/kotlin-extractor/src/main/resources/META-INF/services/org.jetbrains.kotlin.compiler.plugin.CompilerPluginRegistrar @@ -0,0 +1 @@ +com.github.codeql.KotlinExtractorComponentRegistrar diff --git a/java/kotlin-extractor/versions.bzl b/java/kotlin-extractor/versions.bzl index cea5d649025..f9642c96b78 100644 --- a/java/kotlin-extractor/versions.bzl +++ b/java/kotlin-extractor/versions.bzl @@ -11,6 +11,7 @@ VERSIONS = [ "2.2.20-Beta2", "2.3.0", "2.3.20", + "2.4.0", ] def _version_to_tuple(v): diff --git a/java/ql/integration-tests/java/android-8-sample/settings.gradle b/java/ql/integration-tests/java/android-8-sample/settings.gradle index 1fa19406e1a..86c0d338f97 100644 --- a/java/ql/integration-tests/java/android-8-sample/settings.gradle +++ b/java/ql/integration-tests/java/android-8-sample/settings.gradle @@ -14,7 +14,9 @@ pluginManagement { repositories { gradlePluginPortal() google() - mavenCentral() + maven { + url = 'https://maven-central.storage-download.googleapis.com/maven2/' + } } } dependencyResolutionManagement { @@ -33,7 +35,9 @@ dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { google() - mavenCentral() + maven { + url = 'https://maven-central.storage-download.googleapis.com/maven2/' + } } } rootProject.name = "Android Sample" diff --git a/java/ql/integration-tests/java/android-sample-kotlin-build-script-no-wrapper/settings.gradle.kts b/java/ql/integration-tests/java/android-sample-kotlin-build-script-no-wrapper/settings.gradle.kts index 1e8eb927d56..ed9a1e9f141 100644 --- a/java/ql/integration-tests/java/android-sample-kotlin-build-script-no-wrapper/settings.gradle.kts +++ b/java/ql/integration-tests/java/android-sample-kotlin-build-script-no-wrapper/settings.gradle.kts @@ -14,7 +14,9 @@ pluginManagement { repositories { gradlePluginPortal() google() - mavenCentral() + maven { + url = uri("https://maven-central.storage-download.googleapis.com/maven2/") + } } } dependencyResolutionManagement { @@ -33,7 +35,9 @@ dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { google() - mavenCentral() + maven { + url = uri("https://maven-central.storage-download.googleapis.com/maven2/") + } } } rootProject.name = "Android Sample" diff --git a/java/ql/integration-tests/java/android-sample-kotlin-build-script/settings.gradle.kts b/java/ql/integration-tests/java/android-sample-kotlin-build-script/settings.gradle.kts index 1e8eb927d56..ed9a1e9f141 100644 --- a/java/ql/integration-tests/java/android-sample-kotlin-build-script/settings.gradle.kts +++ b/java/ql/integration-tests/java/android-sample-kotlin-build-script/settings.gradle.kts @@ -14,7 +14,9 @@ pluginManagement { repositories { gradlePluginPortal() google() - mavenCentral() + maven { + url = uri("https://maven-central.storage-download.googleapis.com/maven2/") + } } } dependencyResolutionManagement { @@ -33,7 +35,9 @@ dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { google() - mavenCentral() + maven { + url = uri("https://maven-central.storage-download.googleapis.com/maven2/") + } } } rootProject.name = "Android Sample" diff --git a/java/ql/integration-tests/java/android-sample-no-wrapper/settings.gradle b/java/ql/integration-tests/java/android-sample-no-wrapper/settings.gradle index 1fa19406e1a..86c0d338f97 100644 --- a/java/ql/integration-tests/java/android-sample-no-wrapper/settings.gradle +++ b/java/ql/integration-tests/java/android-sample-no-wrapper/settings.gradle @@ -14,7 +14,9 @@ pluginManagement { repositories { gradlePluginPortal() google() - mavenCentral() + maven { + url = 'https://maven-central.storage-download.googleapis.com/maven2/' + } } } dependencyResolutionManagement { @@ -33,7 +35,9 @@ dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { google() - mavenCentral() + maven { + url = 'https://maven-central.storage-download.googleapis.com/maven2/' + } } } rootProject.name = "Android Sample" diff --git a/java/ql/integration-tests/java/android-sample-old-style-kotlin-build-script-no-wrapper/build.gradle.kts b/java/ql/integration-tests/java/android-sample-old-style-kotlin-build-script-no-wrapper/build.gradle.kts index 2514b708295..fbb7a4c50ce 100644 --- a/java/ql/integration-tests/java/android-sample-old-style-kotlin-build-script-no-wrapper/build.gradle.kts +++ b/java/ql/integration-tests/java/android-sample-old-style-kotlin-build-script-no-wrapper/build.gradle.kts @@ -13,7 +13,9 @@ buildscript { repositories { google() - jcenter() + maven { + url = uri("https://maven-central.storage-download.googleapis.com/maven2/") + } } /** @@ -39,6 +41,8 @@ buildscript { allprojects { repositories { google() - jcenter() + maven { + url = uri("https://maven-central.storage-download.googleapis.com/maven2/") + } } } diff --git a/java/ql/integration-tests/java/android-sample-old-style-kotlin-build-script/build.gradle.kts b/java/ql/integration-tests/java/android-sample-old-style-kotlin-build-script/build.gradle.kts index 2514b708295..fbb7a4c50ce 100644 --- a/java/ql/integration-tests/java/android-sample-old-style-kotlin-build-script/build.gradle.kts +++ b/java/ql/integration-tests/java/android-sample-old-style-kotlin-build-script/build.gradle.kts @@ -13,7 +13,9 @@ buildscript { repositories { google() - jcenter() + maven { + url = uri("https://maven-central.storage-download.googleapis.com/maven2/") + } } /** @@ -39,6 +41,8 @@ buildscript { allprojects { repositories { google() - jcenter() + maven { + url = uri("https://maven-central.storage-download.googleapis.com/maven2/") + } } } diff --git a/java/ql/integration-tests/java/android-sample-old-style-no-wrapper/build.gradle b/java/ql/integration-tests/java/android-sample-old-style-no-wrapper/build.gradle index caff3a2589f..2073f14c356 100644 --- a/java/ql/integration-tests/java/android-sample-old-style-no-wrapper/build.gradle +++ b/java/ql/integration-tests/java/android-sample-old-style-no-wrapper/build.gradle @@ -13,7 +13,9 @@ buildscript { repositories { google() - jcenter() + maven { + url = 'https://maven-central.storage-download.googleapis.com/maven2/' + } } /** @@ -39,6 +41,8 @@ buildscript { allprojects { repositories { google() - jcenter() + maven { + url = 'https://maven-central.storage-download.googleapis.com/maven2/' + } } } diff --git a/java/ql/integration-tests/java/android-sample-old-style/build.gradle b/java/ql/integration-tests/java/android-sample-old-style/build.gradle index caff3a2589f..2a030dbae65 100644 --- a/java/ql/integration-tests/java/android-sample-old-style/build.gradle +++ b/java/ql/integration-tests/java/android-sample-old-style/build.gradle @@ -13,7 +13,9 @@ buildscript { repositories { google() - jcenter() + maven { + url = 'https://maven-central.storage-download.googleapis.com/maven2/' + } } /** @@ -32,13 +34,15 @@ buildscript { * dependencies used by all modules in your project, such as third-party plugins * or libraries. However, you should configure module-specific dependencies in * each module-level build.gradle file. For new projects, Android Studio - * includes JCenter and Google's Maven repository by default, but it does not + * includes Maven Central and Google's Maven repository by default, but it does not * configure any dependencies (unless you select a template that requires some). */ allprojects { repositories { google() - jcenter() + maven { + url = 'https://maven-central.storage-download.googleapis.com/maven2/' + } } } diff --git a/java/ql/integration-tests/java/android-sample/settings.gradle b/java/ql/integration-tests/java/android-sample/settings.gradle index 1fa19406e1a..86c0d338f97 100644 --- a/java/ql/integration-tests/java/android-sample/settings.gradle +++ b/java/ql/integration-tests/java/android-sample/settings.gradle @@ -14,7 +14,9 @@ pluginManagement { repositories { gradlePluginPortal() google() - mavenCentral() + maven { + url = 'https://maven-central.storage-download.googleapis.com/maven2/' + } } } dependencyResolutionManagement { @@ -33,7 +35,9 @@ dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { google() - mavenCentral() + maven { + url = 'https://maven-central.storage-download.googleapis.com/maven2/' + } } } rootProject.name = "Android Sample" diff --git a/java/ql/integration-tests/java/buildless-erroneous/diagnostics.expected b/java/ql/integration-tests/java/buildless-erroneous/diagnostics.expected index 90aa56bf3f6..ee1b8835665 100644 --- a/java/ql/integration-tests/java/buildless-erroneous/diagnostics.expected +++ b/java/ql/integration-tests/java/buildless-erroneous/diagnostics.expected @@ -1,3 +1,18 @@ +{ + "attributes": {}, + "markdownMessage": "Internal telemetry for the Java extractor.\n\nNo action needed.", + "severity": "note", + "source": { + "extractorName": "java", + "id": "java/extractor/summary", + "name": "Java extractor telemetry" + }, + "visibility": { + "cliSummaryTable": false, + "statusPage": false, + "telemetry": true + } +} { "markdownMessage": "Because no usable build tool (Gradle, Maven, etc) was found, build scripts could not be queried for guidance about the appropriate JDK version for the code being extracted, or precise dependency information. The default JDK will be used, and external dependencies will be inferred from the Java package names used.", "severity": "unknown", diff --git a/java/ql/integration-tests/java/buildless-gradle-boms/build.gradle b/java/ql/integration-tests/java/buildless-gradle-boms/build.gradle index c70d65bed80..9d63a021365 100644 --- a/java/ql/integration-tests/java/buildless-gradle-boms/build.gradle +++ b/java/ql/integration-tests/java/buildless-gradle-boms/build.gradle @@ -8,7 +8,9 @@ apply plugin: 'java-library' repositories { - mavenCentral() + maven { + url = 'https://maven-central.storage-download.googleapis.com/maven2/' + } } dependencies { diff --git a/java/ql/integration-tests/java/buildless-gradle-boms/buildless-fetches.expected b/java/ql/integration-tests/java/buildless-gradle-boms/buildless-fetches.expected index 7b336ba62cb..66642fdbd86 100644 --- a/java/ql/integration-tests/java/buildless-gradle-boms/buildless-fetches.expected +++ b/java/ql/integration-tests/java/buildless-gradle-boms/buildless-fetches.expected @@ -1,5 +1,5 @@ -https://repo.maven.apache.org/maven2/org/apache/commons/commons-math3/3.6.1/commons-math3-3.6.1.jar -https://repo.maven.apache.org/maven2/org/apiguardian/apiguardian-api/1.1.2/apiguardian-api-1.1.2.jar -https://repo.maven.apache.org/maven2/org/junit/jupiter/junit-jupiter-api/5.12.1/junit-jupiter-api-5.12.1.jar -https://repo.maven.apache.org/maven2/org/junit/platform/junit-platform-commons/1.12.1/junit-platform-commons-1.12.1.jar -https://repo.maven.apache.org/maven2/org/opentest4j/opentest4j/1.3.0/opentest4j-1.3.0.jar +https://maven-central.storage-download.googleapis.com/maven2/org/apache/commons/commons-math3/3.6.1/commons-math3-3.6.1.jar +https://maven-central.storage-download.googleapis.com/maven2/org/apiguardian/apiguardian-api/1.1.2/apiguardian-api-1.1.2.jar +https://maven-central.storage-download.googleapis.com/maven2/org/junit/jupiter/junit-jupiter-api/5.12.1/junit-jupiter-api-5.12.1.jar +https://maven-central.storage-download.googleapis.com/maven2/org/junit/platform/junit-platform-commons/1.12.1/junit-platform-commons-1.12.1.jar +https://maven-central.storage-download.googleapis.com/maven2/org/opentest4j/opentest4j/1.3.0/opentest4j-1.3.0.jar diff --git a/java/ql/integration-tests/java/buildless-gradle-boms/diagnostics.expected b/java/ql/integration-tests/java/buildless-gradle-boms/diagnostics.expected index 976e0eb08fc..d78b3ca081a 100644 --- a/java/ql/integration-tests/java/buildless-gradle-boms/diagnostics.expected +++ b/java/ql/integration-tests/java/buildless-gradle-boms/diagnostics.expected @@ -1,3 +1,18 @@ +{ + "attributes": {}, + "markdownMessage": "Internal telemetry for the Java extractor.\n\nNo action needed.", + "severity": "note", + "source": { + "extractorName": "java", + "id": "java/extractor/summary", + "name": "Java extractor telemetry" + }, + "visibility": { + "cliSummaryTable": false, + "statusPage": false, + "telemetry": true + } +} { "markdownMessage": "Java analysis used build tool Gradle to pick a JDK version and/or to recommend external dependencies.", "severity": "unknown", diff --git a/java/ql/integration-tests/java/buildless-gradle-classifiers/build.gradle b/java/ql/integration-tests/java/buildless-gradle-classifiers/build.gradle index 0e054886c3e..46560750b53 100644 --- a/java/ql/integration-tests/java/buildless-gradle-classifiers/build.gradle +++ b/java/ql/integration-tests/java/buildless-gradle-classifiers/build.gradle @@ -8,7 +8,9 @@ apply plugin: 'java-library' repositories { - mavenCentral() + maven { + url = 'https://maven-central.storage-download.googleapis.com/maven2/' + } } dependencies { diff --git a/java/ql/integration-tests/java/buildless-gradle-classifiers/buildless-fetches.expected b/java/ql/integration-tests/java/buildless-gradle-classifiers/buildless-fetches.expected index 7d15e175ca8..601deb65173 100644 --- a/java/ql/integration-tests/java/buildless-gradle-classifiers/buildless-fetches.expected +++ b/java/ql/integration-tests/java/buildless-gradle-classifiers/buildless-fetches.expected @@ -1,2 +1,2 @@ -https://repo.maven.apache.org/maven2/joda-time/joda-time/2.12.7/joda-time-2.12.7-no-tzdb.jar -https://repo.maven.apache.org/maven2/org/apache/commons/commons-math3/3.6.1/commons-math3-3.6.1.jar +https://maven-central.storage-download.googleapis.com/maven2/joda-time/joda-time/2.12.7/joda-time-2.12.7-no-tzdb.jar +https://maven-central.storage-download.googleapis.com/maven2/org/apache/commons/commons-math3/3.6.1/commons-math3-3.6.1.jar diff --git a/java/ql/integration-tests/java/buildless-gradle-classifiers/diagnostics.expected b/java/ql/integration-tests/java/buildless-gradle-classifiers/diagnostics.expected index 7312fdf95ec..906a8f12990 100644 --- a/java/ql/integration-tests/java/buildless-gradle-classifiers/diagnostics.expected +++ b/java/ql/integration-tests/java/buildless-gradle-classifiers/diagnostics.expected @@ -1,3 +1,18 @@ +{ + "attributes": {}, + "markdownMessage": "Internal telemetry for the Java extractor.\n\nNo action needed.", + "severity": "note", + "source": { + "extractorName": "java", + "id": "java/extractor/summary", + "name": "Java extractor telemetry" + }, + "visibility": { + "cliSummaryTable": false, + "statusPage": false, + "telemetry": true + } +} { "markdownMessage": "Java analysis used build tool Gradle to pick a JDK version and/or to recommend external dependencies.", "severity": "unknown", diff --git a/java/ql/integration-tests/java/buildless-gradle-timeout/build.gradle b/java/ql/integration-tests/java/buildless-gradle-timeout/build.gradle index 071a12b7691..0fc1d500219 100644 --- a/java/ql/integration-tests/java/buildless-gradle-timeout/build.gradle +++ b/java/ql/integration-tests/java/buildless-gradle-timeout/build.gradle @@ -12,9 +12,9 @@ apply plugin: 'java' // In this section you declare where to find the dependencies of your project repositories { - // Use 'jcenter' for resolving your dependencies. - // You can declare any Maven/Ivy/file repository here. - jcenter() + maven { + url = 'https://maven-central.storage-download.googleapis.com/maven2/' + } } // In this section you declare the dependencies for your production and test code diff --git a/java/ql/integration-tests/java/buildless-gradle-timeout/diagnostics.expected b/java/ql/integration-tests/java/buildless-gradle-timeout/diagnostics.expected index 779ffa91e71..56072f5b90c 100644 --- a/java/ql/integration-tests/java/buildless-gradle-timeout/diagnostics.expected +++ b/java/ql/integration-tests/java/buildless-gradle-timeout/diagnostics.expected @@ -1,3 +1,18 @@ +{ + "attributes": {}, + "markdownMessage": "Internal telemetry for the Java extractor.\n\nNo action needed.", + "severity": "note", + "source": { + "extractorName": "java", + "id": "java/extractor/summary", + "name": "Java extractor telemetry" + }, + "visibility": { + "cliSummaryTable": false, + "statusPage": false, + "telemetry": true + } +} { "markdownMessage": "A Gradle process was aborted because it didn't write to the console for 5 seconds. Consider either lengthening the timeout if appropriate by setting CODEQL_EXTRACTOR_JAVA_BUILDLESS_CHILD_PROCESS_IDLE_TIMEOUT to a higher value or zero for no timeout, or else investigate why Gradle timed out. Java analysis will continue, but the analysis may be of reduced quality.", "severity": "note", diff --git a/java/ql/integration-tests/java/buildless-gradle/build.gradle b/java/ql/integration-tests/java/buildless-gradle/build.gradle index 98833538000..ae557cf3afa 100644 --- a/java/ql/integration-tests/java/buildless-gradle/build.gradle +++ b/java/ql/integration-tests/java/buildless-gradle/build.gradle @@ -8,7 +8,9 @@ apply plugin: 'java-library' repositories { - mavenCentral() + maven { + url = 'https://maven-central.storage-download.googleapis.com/maven2/' + } } dependencies { diff --git a/java/ql/integration-tests/java/buildless-gradle/buildless-fetches.expected b/java/ql/integration-tests/java/buildless-gradle/buildless-fetches.expected index 631cb23bade..397d226299f 100644 --- a/java/ql/integration-tests/java/buildless-gradle/buildless-fetches.expected +++ b/java/ql/integration-tests/java/buildless-gradle/buildless-fetches.expected @@ -1 +1 @@ -https://repo.maven.apache.org/maven2/org/apache/commons/commons-math3/3.6.1/commons-math3-3.6.1.jar +https://maven-central.storage-download.googleapis.com/maven2/org/apache/commons/commons-math3/3.6.1/commons-math3-3.6.1.jar diff --git a/java/ql/integration-tests/java/buildless-gradle/diagnostics.expected b/java/ql/integration-tests/java/buildless-gradle/diagnostics.expected index 337fa933808..abe6bfaa24c 100644 --- a/java/ql/integration-tests/java/buildless-gradle/diagnostics.expected +++ b/java/ql/integration-tests/java/buildless-gradle/diagnostics.expected @@ -1,3 +1,18 @@ +{ + "attributes": {}, + "markdownMessage": "Internal telemetry for the Java extractor.\n\nNo action needed.", + "severity": "note", + "source": { + "extractorName": "java", + "id": "java/extractor/summary", + "name": "Java extractor telemetry" + }, + "visibility": { + "cliSummaryTable": false, + "statusPage": false, + "telemetry": true + } +} { "markdownMessage": "Java analysis used build tool Gradle to pick a JDK version and/or to recommend external dependencies.", "severity": "unknown", diff --git a/java/ql/integration-tests/java/buildless-inherit-trust-store/diagnostics.expected b/java/ql/integration-tests/java/buildless-inherit-trust-store/diagnostics.expected index 766db40aa62..9faa13e8d8b 100644 --- a/java/ql/integration-tests/java/buildless-inherit-trust-store/diagnostics.expected +++ b/java/ql/integration-tests/java/buildless-inherit-trust-store/diagnostics.expected @@ -1,3 +1,18 @@ +{ + "attributes": {}, + "markdownMessage": "Internal telemetry for the Java extractor.\n\nNo action needed.", + "severity": "note", + "source": { + "extractorName": "java", + "id": "java/extractor/summary", + "name": "Java extractor telemetry" + }, + "visibility": { + "cliSummaryTable": false, + "statusPage": false, + "telemetry": true + } +} { "markdownMessage": "Java analysis used build tool Maven to pick a JDK version and/or to recommend external dependencies.", "severity": "unknown", diff --git a/java/ql/integration-tests/java/buildless-inherit-trust-store/settings.xml b/java/ql/integration-tests/java/buildless-inherit-trust-store/settings.xml new file mode 100644 index 00000000000..a40670670a6 --- /dev/null +++ b/java/ql/integration-tests/java/buildless-inherit-trust-store/settings.xml @@ -0,0 +1,10 @@ + + + + google-maven-central + GCS Maven Central mirror + https://maven-central.storage-download.googleapis.com/maven2/ + central + + + diff --git a/java/ql/integration-tests/java/buildless-inherit-trust-store/test.py b/java/ql/integration-tests/java/buildless-inherit-trust-store/test.py index 06855e43ba2..3839df9cedc 100644 --- a/java/ql/integration-tests/java/buildless-inherit-trust-store/test.py +++ b/java/ql/integration-tests/java/buildless-inherit-trust-store/test.py @@ -21,6 +21,7 @@ def test(codeql, java, cwd, check_diagnostics_java): _env={ "MAVEN_OPTS": maven_opts, "CODEQL_JAVA_EXTRACTOR_TRUST_STORE_PATH": str(certspath), + "LGTM_INDEX_MAVEN_SETTINGS_FILE": os.path.join(os.path.dirname(os.path.realpath(__file__)), "settings.xml"), }, ) finally: diff --git a/java/ql/integration-tests/java/buildless-maven-executable-war/buildless-fetches.expected b/java/ql/integration-tests/java/buildless-maven-executable-war/buildless-fetches.expected index a956477896c..e2c63e182c4 100644 --- a/java/ql/integration-tests/java/buildless-maven-executable-war/buildless-fetches.expected +++ b/java/ql/integration-tests/java/buildless-maven-executable-war/buildless-fetches.expected @@ -1,3 +1,5 @@ +https://maven-central.storage-download.googleapis.com/maven2/junit/junit/4.11/junit-4.11.jar +https://maven-central.storage-download.googleapis.com/maven2/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar https://repo.jenkins-ci.org/releases/org/jenkins-ci/main/jenkins-war/2.249/jenkins-war-2.249.war https://repo.maven.apache.org/maven2/com/feiniaojin/naaf/naaf-graceful-response-example/1.0/naaf-graceful-response-example-1.0.jar https://repo.maven.apache.org/maven2/com/github/MoebiusSolutions/avro-registry-in-source/avro-registry-in-source-tests/1.8/avro-registry-in-source-tests-1.8.jar @@ -10,9 +12,7 @@ https://repo.maven.apache.org/maven2/de/knutwalker/rx-redis-example_2.11/0.1.2/r https://repo.maven.apache.org/maven2/de/knutwalker/rx-redis-java-example_2.11/0.1.2/rx-redis-java-example_2.11-0.1.2.jar https://repo.maven.apache.org/maven2/io/github/scrollsyou/example-spring-boot-starter/1.0.0/example-spring-boot-starter-1.0.0.jar https://repo.maven.apache.org/maven2/io/streamnative/com/example/maven-central-template/server/3.0.0/server-3.0.0.jar -https://repo.maven.apache.org/maven2/junit/junit/4.11/junit-4.11.jar https://repo.maven.apache.org/maven2/no/nav/security/token-validation-ktor-demo/3.1.0/token-validation-ktor-demo-3.1.0.jar -https://repo.maven.apache.org/maven2/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar https://repo.maven.apache.org/maven2/org/minijax/minijax-example-fileupload/0.5.10/minijax-example-fileupload-0.5.10.jar https://repo.maven.apache.org/maven2/org/minijax/minijax-example-inject/0.5.10/minijax-example-inject-0.5.10.jar https://repo.maven.apache.org/maven2/org/minijax/minijax-example-json/0.5.10/minijax-example-json-0.5.10.jar diff --git a/java/ql/integration-tests/java/buildless-maven-executable-war/diagnostics.expected b/java/ql/integration-tests/java/buildless-maven-executable-war/diagnostics.expected index 1058e1528f9..cc4731ad9c2 100644 --- a/java/ql/integration-tests/java/buildless-maven-executable-war/diagnostics.expected +++ b/java/ql/integration-tests/java/buildless-maven-executable-war/diagnostics.expected @@ -1,3 +1,18 @@ +{ + "attributes": {}, + "markdownMessage": "Internal telemetry for the Java extractor.\n\nNo action needed.", + "severity": "note", + "source": { + "extractorName": "java", + "id": "java/extractor/summary", + "name": "Java extractor telemetry" + }, + "visibility": { + "cliSummaryTable": false, + "statusPage": false, + "telemetry": true + } +} { "markdownMessage": "Java analysis used build tool Maven to pick a JDK version and/or to recommend external dependencies.", "severity": "unknown", diff --git a/java/ql/integration-tests/java/buildless-maven-executable-war/settings.xml b/java/ql/integration-tests/java/buildless-maven-executable-war/settings.xml new file mode 100644 index 00000000000..a40670670a6 --- /dev/null +++ b/java/ql/integration-tests/java/buildless-maven-executable-war/settings.xml @@ -0,0 +1,10 @@ + + + + google-maven-central + GCS Maven Central mirror + https://maven-central.storage-download.googleapis.com/maven2/ + central + + + diff --git a/java/ql/integration-tests/java/buildless-maven-executable-war/source_archive.expected b/java/ql/integration-tests/java/buildless-maven-executable-war/source_archive.expected index 0a86ff54645..ac35d94be39 100644 --- a/java/ql/integration-tests/java/buildless-maven-executable-war/source_archive.expected +++ b/java/ql/integration-tests/java/buildless-maven-executable-war/source_archive.expected @@ -1,4 +1,5 @@ pom.xml +settings.xml src/main/java/com/example/App.java src/main/resources/my-app.properties src/main/resources/page.xml diff --git a/java/ql/integration-tests/java/buildless-maven-executable-war/test.py b/java/ql/integration-tests/java/buildless-maven-executable-war/test.py index 2a839a0c294..04ce2aac710 100644 --- a/java/ql/integration-tests/java/buildless-maven-executable-war/test.py +++ b/java/ql/integration-tests/java/buildless-maven-executable-war/test.py @@ -1,7 +1,10 @@ +import os + def test(codeql, java, check_diagnostics_java): codeql.database.create( _env={ "CODEQL_EXTRACTOR_JAVA_OPTION_BUILDLESS": "true", "CODEQL_EXTRACTOR_JAVA_OPTION_BUILDLESS_CLASSPATH_FROM_BUILD_FILES": "true", + "LGTM_INDEX_MAVEN_SETTINGS_FILE": os.path.join(os.path.dirname(os.path.realpath(__file__)), "settings.xml"), } ) diff --git a/java/ql/integration-tests/java/buildless-maven-existing-settings-xml/buildless-fetches.expected b/java/ql/integration-tests/java/buildless-maven-existing-settings-xml/buildless-fetches.expected index 49120865e8d..a4bfbc7a97b 100644 --- a/java/ql/integration-tests/java/buildless-maven-existing-settings-xml/buildless-fetches.expected +++ b/java/ql/integration-tests/java/buildless-maven-existing-settings-xml/buildless-fetches.expected @@ -1,3 +1,5 @@ +https://maven-central.storage-download.googleapis.com/maven2/junit/junit/4.11/junit-4.11.jar +https://maven-central.storage-download.googleapis.com/maven2/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar https://repo.maven.apache.org/maven2/com/feiniaojin/naaf/naaf-graceful-response-example/1.0/naaf-graceful-response-example-1.0.jar https://repo.maven.apache.org/maven2/com/github/MoebiusSolutions/avro-registry-in-source/avro-registry-in-source-tests/1.8/avro-registry-in-source-tests-1.8.jar https://repo.maven.apache.org/maven2/com/github/MoebiusSolutions/avro-registry-in-source/example-project/1.5/example-project-1.5.jar @@ -9,9 +11,7 @@ https://repo.maven.apache.org/maven2/de/knutwalker/rx-redis-example_2.11/0.1.2/r https://repo.maven.apache.org/maven2/de/knutwalker/rx-redis-java-example_2.11/0.1.2/rx-redis-java-example_2.11-0.1.2.jar https://repo.maven.apache.org/maven2/io/github/scrollsyou/example-spring-boot-starter/1.0.0/example-spring-boot-starter-1.0.0.jar https://repo.maven.apache.org/maven2/io/streamnative/com/example/maven-central-template/server/3.0.0/server-3.0.0.jar -https://repo.maven.apache.org/maven2/junit/junit/4.11/junit-4.11.jar https://repo.maven.apache.org/maven2/no/nav/security/token-validation-ktor-demo/3.1.0/token-validation-ktor-demo-3.1.0.jar -https://repo.maven.apache.org/maven2/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar https://repo.maven.apache.org/maven2/org/minijax/minijax-example-fileupload/0.5.10/minijax-example-fileupload-0.5.10.jar https://repo.maven.apache.org/maven2/org/minijax/minijax-example-inject/0.5.10/minijax-example-inject-0.5.10.jar https://repo.maven.apache.org/maven2/org/minijax/minijax-example-json/0.5.10/minijax-example-json-0.5.10.jar diff --git a/java/ql/integration-tests/java/buildless-maven-existing-settings-xml/diagnostics.expected b/java/ql/integration-tests/java/buildless-maven-existing-settings-xml/diagnostics.expected index f3c89bb842a..fdef7e871f5 100644 --- a/java/ql/integration-tests/java/buildless-maven-existing-settings-xml/diagnostics.expected +++ b/java/ql/integration-tests/java/buildless-maven-existing-settings-xml/diagnostics.expected @@ -1,3 +1,18 @@ +{ + "attributes": {}, + "markdownMessage": "Internal telemetry for the Java extractor.\n\nNo action needed.", + "severity": "note", + "source": { + "extractorName": "java", + "id": "java/extractor/summary", + "name": "Java extractor telemetry" + }, + "visibility": { + "cliSummaryTable": false, + "statusPage": false, + "telemetry": true + } +} { "markdownMessage": "Java analysis used build tool Maven to pick a JDK version and/or to recommend external dependencies.", "severity": "unknown", diff --git a/java/ql/integration-tests/java/buildless-maven-existing-settings-xml/maven-fetches.expected b/java/ql/integration-tests/java/buildless-maven-existing-settings-xml/maven-fetches.expected index 208ca501487..bf66bd15f01 100644 --- a/java/ql/integration-tests/java/buildless-maven-existing-settings-xml/maven-fetches.expected +++ b/java/ql/integration-tests/java/buildless-maven-existing-settings-xml/maven-fetches.expected @@ -1,6 +1,6 @@ -Downloaded from central: https://repo.maven.apache.org/maven2/junit/junit/4.11/junit-4.11.pom -Downloaded from central: https://repo.maven.apache.org/maven2/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.pom -Downloaded from central: https://repo.maven.apache.org/maven2/org/hamcrest/hamcrest-parent/1.3/hamcrest-parent-1.3.pom +Downloaded from central: https://maven-central.storage-download.googleapis.com/maven2/junit/junit/4.11/junit-4.11.pom +Downloaded from central: https://maven-central.storage-download.googleapis.com/maven2/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.pom +Downloaded from central: https://maven-central.storage-download.googleapis.com/maven2/org/hamcrest/hamcrest-parent/1.3/hamcrest-parent-1.3.pom Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/com/fasterxml/jackson/core/jackson-annotations/2.18.6/jackson-annotations-2.18.6.jar Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/com/fasterxml/jackson/core/jackson-annotations/2.18.6/jackson-annotations-2.18.6.pom Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/com/fasterxml/jackson/core/jackson-core/2.18.6/jackson-core-2.18.6.jar @@ -11,8 +11,8 @@ Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferst Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/com/fasterxml/jackson/jackson-bom/2.18.6/jackson-bom-2.18.6.pom Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/com/fasterxml/jackson/jackson-parent/2.18.4/jackson-parent-2.18.4.pom Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/com/fasterxml/oss-parent/69/oss-parent-69.pom -Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/com/github/ferstl/depgraph-maven-plugin/4.0.3-CodeQL-2/depgraph-maven-plugin-4.0.3-CodeQL-2.jar -Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/com/github/ferstl/depgraph-maven-plugin/4.0.3-CodeQL-2/depgraph-maven-plugin-4.0.3-CodeQL-2.pom +Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/com/github/ferstl/depgraph-maven-plugin/4.0.3-CodeQL-3/depgraph-maven-plugin-4.0.3-CodeQL-3.jar +Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/com/github/ferstl/depgraph-maven-plugin/4.0.3-CodeQL-3/depgraph-maven-plugin-4.0.3-CodeQL-3.pom Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/com/google/code/findbugs/jsr305/3.0.2/jsr305-3.0.2.jar Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/com/google/code/findbugs/jsr305/3.0.2/jsr305-3.0.2.pom Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/com/google/errorprone/error_prone_annotations/2.36.0/error_prone_annotations-2.36.0.jar @@ -31,12 +31,12 @@ Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferst Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/javax/annotation/javax.annotation-api/1.2/javax.annotation-api-1.2.jar Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/javax/annotation/javax.annotation-api/1.2/javax.annotation-api-1.2.pom Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/net/java/jvnet-parent/3/jvnet-parent-3.pom -Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/apache/apache/19/apache-19.pom Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/apache/apache/25/apache-25.pom Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/apache/apache/27/apache-27.pom -Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/apache/commons/commons-lang3/3.8.1/commons-lang3-3.8.1.jar -Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/apache/commons/commons-lang3/3.8.1/commons-lang3-3.8.1.pom -Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/apache/commons/commons-parent/47/commons-parent-47.pom +Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/apache/apache/35/apache-35.pom +Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/apache/commons/commons-lang3/3.18.0/commons-lang3-3.18.0.jar +Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/apache/commons/commons-lang3/3.18.0/commons-lang3-3.18.0.pom +Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/apache/commons/commons-parent/85/commons-parent-85.pom Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/apache/maven/maven-artifact/3.8.6/maven-artifact-3.8.6.jar Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/apache/maven/maven-artifact/3.8.6/maven-artifact-3.8.6.pom Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/apache/maven/maven-model/3.8.6/maven-model-3.8.6.jar @@ -57,12 +57,11 @@ Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferst Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/codehaus/plexus/plexus-component-annotations/1.5.5/plexus-component-annotations-1.5.5.jar Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/codehaus/plexus/plexus-component-annotations/1.5.5/plexus-component-annotations-1.5.5.pom Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/codehaus/plexus/plexus-containers/1.5.5/plexus-containers-1.5.5.pom -Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/codehaus/plexus/plexus-utils/3.0.24/plexus-utils-3.0.24.pom -Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/codehaus/plexus/plexus-utils/3.3.1/plexus-utils-3.3.1.jar -Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/codehaus/plexus/plexus-utils/3.3.1/plexus-utils-3.3.1.pom +Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/codehaus/plexus/plexus-utils/3.6.1/plexus-utils-3.6.1.jar +Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/codehaus/plexus/plexus-utils/3.6.1/plexus-utils-3.6.1.pom Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/codehaus/plexus/plexus/2.0.7/plexus-2.0.7.pom +Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/codehaus/plexus/plexus/25/plexus-25.pom Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/codehaus/plexus/plexus/3.3.1/plexus-3.3.1.pom -Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/codehaus/plexus/plexus/4.0/plexus-4.0.pom Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/codehaus/plexus/plexus/5.1/plexus-5.1.pom Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/eclipse/sisu/org.eclipse.sisu.inject/0.3.5/org.eclipse.sisu.inject-0.3.5.jar Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/eclipse/sisu/org.eclipse.sisu.inject/0.3.5/org.eclipse.sisu.inject-0.3.5.pom @@ -70,6 +69,8 @@ Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferst Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/eclipse/sisu/org.eclipse.sisu.plexus/0.3.5/org.eclipse.sisu.plexus-0.3.5.pom Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/eclipse/sisu/sisu-inject/0.3.5/sisu-inject-0.3.5.pom Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/eclipse/sisu/sisu-plexus/0.3.5/sisu-plexus-0.3.5.pom +Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/junit/junit-bom/5.13.1/junit-bom-5.13.1.pom +Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/junit/junit-bom/5.14.1/junit-bom-5.14.1.pom Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/junit/junit-bom/5.9.1/junit-bom-5.9.1.pom Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/sonatype/forge/forge-parent/10/forge-parent-10.pom Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/sonatype/oss/oss-parent/7/oss-parent-7.pom diff --git a/java/ql/integration-tests/java/buildless-maven-existing-settings-xml/pom.xml b/java/ql/integration-tests/java/buildless-maven-existing-settings-xml/pom.xml index ec4aaf128c1..debe59e6c03 100644 --- a/java/ql/integration-tests/java/buildless-maven-existing-settings-xml/pom.xml +++ b/java/ql/integration-tests/java/buildless-maven-existing-settings-xml/pom.xml @@ -111,4 +111,30 @@ + + + + + central + https://maven-central.storage-download.googleapis.com/maven2/ + + true + + + true + + + + + + central + https://maven-central.storage-download.googleapis.com/maven2/ + + true + + + true + + + \ No newline at end of file diff --git a/java/ql/integration-tests/java/buildless-maven-mirrorof/buildless-fetches.expected b/java/ql/integration-tests/java/buildless-maven-mirrorof/buildless-fetches.expected index e3710cc4cb9..a4bfbc7a97b 100644 --- a/java/ql/integration-tests/java/buildless-maven-mirrorof/buildless-fetches.expected +++ b/java/ql/integration-tests/java/buildless-maven-mirrorof/buildless-fetches.expected @@ -1,3 +1,5 @@ +https://maven-central.storage-download.googleapis.com/maven2/junit/junit/4.11/junit-4.11.jar +https://maven-central.storage-download.googleapis.com/maven2/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar https://repo.maven.apache.org/maven2/com/feiniaojin/naaf/naaf-graceful-response-example/1.0/naaf-graceful-response-example-1.0.jar https://repo.maven.apache.org/maven2/com/github/MoebiusSolutions/avro-registry-in-source/avro-registry-in-source-tests/1.8/avro-registry-in-source-tests-1.8.jar https://repo.maven.apache.org/maven2/com/github/MoebiusSolutions/avro-registry-in-source/example-project/1.5/example-project-1.5.jar @@ -22,5 +24,3 @@ https://repo.maven.apache.org/maven2/org/minijax/minijax-example-websocket/0.5.1 https://repo.maven.apache.org/maven2/org/scalamock/scalamock-examples_2.10/3.6.0/scalamock-examples_2.10-3.6.0.jar https://repo.maven.apache.org/maven2/org/somda/sdc/glue-examples/4.0.0/glue-examples-4.0.0.jar https://repo.maven.apache.org/maven2/us/fatehi/schemacrawler-examplecode/16.20.2/schemacrawler-examplecode-16.20.2.jar -https://repo1.maven.org/maven2/junit/junit/4.11/junit-4.11.jar -https://repo1.maven.org/maven2/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar diff --git a/java/ql/integration-tests/java/buildless-maven-mirrorof/diagnostics.expected b/java/ql/integration-tests/java/buildless-maven-mirrorof/diagnostics.expected index f3c89bb842a..fdef7e871f5 100644 --- a/java/ql/integration-tests/java/buildless-maven-mirrorof/diagnostics.expected +++ b/java/ql/integration-tests/java/buildless-maven-mirrorof/diagnostics.expected @@ -1,3 +1,18 @@ +{ + "attributes": {}, + "markdownMessage": "Internal telemetry for the Java extractor.\n\nNo action needed.", + "severity": "note", + "source": { + "extractorName": "java", + "id": "java/extractor/summary", + "name": "Java extractor telemetry" + }, + "visibility": { + "cliSummaryTable": false, + "statusPage": false, + "telemetry": true + } +} { "markdownMessage": "Java analysis used build tool Maven to pick a JDK version and/or to recommend external dependencies.", "severity": "unknown", diff --git a/java/ql/integration-tests/java/buildless-maven-mirrorof/maven-fetches.expected b/java/ql/integration-tests/java/buildless-maven-mirrorof/maven-fetches.expected index cffdda2891e..885b2fe28f3 100644 --- a/java/ql/integration-tests/java/buildless-maven-mirrorof/maven-fetches.expected +++ b/java/ql/integration-tests/java/buildless-maven-mirrorof/maven-fetches.expected @@ -8,8 +8,8 @@ Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferst Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/com/fasterxml/jackson/jackson-bom/2.18.6/jackson-bom-2.18.6.pom Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/com/fasterxml/jackson/jackson-parent/2.18.4/jackson-parent-2.18.4.pom Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/com/fasterxml/oss-parent/69/oss-parent-69.pom -Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/com/github/ferstl/depgraph-maven-plugin/4.0.3-CodeQL-2/depgraph-maven-plugin-4.0.3-CodeQL-2.jar -Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/com/github/ferstl/depgraph-maven-plugin/4.0.3-CodeQL-2/depgraph-maven-plugin-4.0.3-CodeQL-2.pom +Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/com/github/ferstl/depgraph-maven-plugin/4.0.3-CodeQL-3/depgraph-maven-plugin-4.0.3-CodeQL-3.jar +Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/com/github/ferstl/depgraph-maven-plugin/4.0.3-CodeQL-3/depgraph-maven-plugin-4.0.3-CodeQL-3.pom Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/com/google/code/findbugs/jsr305/3.0.2/jsr305-3.0.2.jar Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/com/google/code/findbugs/jsr305/3.0.2/jsr305-3.0.2.pom Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/com/google/errorprone/error_prone_annotations/2.36.0/error_prone_annotations-2.36.0.jar @@ -28,12 +28,12 @@ Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferst Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/javax/annotation/javax.annotation-api/1.2/javax.annotation-api-1.2.jar Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/javax/annotation/javax.annotation-api/1.2/javax.annotation-api-1.2.pom Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/net/java/jvnet-parent/3/jvnet-parent-3.pom -Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/apache/apache/19/apache-19.pom Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/apache/apache/25/apache-25.pom Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/apache/apache/27/apache-27.pom -Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/apache/commons/commons-lang3/3.8.1/commons-lang3-3.8.1.jar -Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/apache/commons/commons-lang3/3.8.1/commons-lang3-3.8.1.pom -Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/apache/commons/commons-parent/47/commons-parent-47.pom +Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/apache/apache/35/apache-35.pom +Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/apache/commons/commons-lang3/3.18.0/commons-lang3-3.18.0.jar +Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/apache/commons/commons-lang3/3.18.0/commons-lang3-3.18.0.pom +Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/apache/commons/commons-parent/85/commons-parent-85.pom Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/apache/maven/maven-artifact/3.8.6/maven-artifact-3.8.6.jar Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/apache/maven/maven-artifact/3.8.6/maven-artifact-3.8.6.pom Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/apache/maven/maven-model/3.8.6/maven-model-3.8.6.jar @@ -54,12 +54,11 @@ Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferst Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/codehaus/plexus/plexus-component-annotations/1.5.5/plexus-component-annotations-1.5.5.jar Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/codehaus/plexus/plexus-component-annotations/1.5.5/plexus-component-annotations-1.5.5.pom Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/codehaus/plexus/plexus-containers/1.5.5/plexus-containers-1.5.5.pom -Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/codehaus/plexus/plexus-utils/3.0.24/plexus-utils-3.0.24.pom -Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/codehaus/plexus/plexus-utils/3.3.1/plexus-utils-3.3.1.jar -Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/codehaus/plexus/plexus-utils/3.3.1/plexus-utils-3.3.1.pom +Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/codehaus/plexus/plexus-utils/3.6.1/plexus-utils-3.6.1.jar +Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/codehaus/plexus/plexus-utils/3.6.1/plexus-utils-3.6.1.pom Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/codehaus/plexus/plexus/2.0.7/plexus-2.0.7.pom +Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/codehaus/plexus/plexus/25/plexus-25.pom Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/codehaus/plexus/plexus/3.3.1/plexus-3.3.1.pom -Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/codehaus/plexus/plexus/4.0/plexus-4.0.pom Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/codehaus/plexus/plexus/5.1/plexus-5.1.pom Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/eclipse/sisu/org.eclipse.sisu.inject/0.3.5/org.eclipse.sisu.inject-0.3.5.jar Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/eclipse/sisu/org.eclipse.sisu.inject/0.3.5/org.eclipse.sisu.inject-0.3.5.pom @@ -67,11 +66,13 @@ Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferst Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/eclipse/sisu/org.eclipse.sisu.plexus/0.3.5/org.eclipse.sisu.plexus-0.3.5.pom Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/eclipse/sisu/sisu-inject/0.3.5/sisu-inject-0.3.5.pom Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/eclipse/sisu/sisu-plexus/0.3.5/sisu-plexus-0.3.5.pom +Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/junit/junit-bom/5.13.1/junit-bom-5.13.1.pom +Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/junit/junit-bom/5.14.1/junit-bom-5.14.1.pom Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/junit/junit-bom/5.9.1/junit-bom-5.9.1.pom Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/sonatype/forge/forge-parent/10/forge-parent-10.pom Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/sonatype/oss/oss-parent/7/oss-parent-7.pom Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/sonatype/oss/oss-parent/9/oss-parent-9.pom Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/sonatype/spice/spice-parent/17/spice-parent-17.pom -Downloaded from mirror-force-central: https://repo1.maven.org/maven2/junit/junit/4.11/junit-4.11.pom -Downloaded from mirror-force-central: https://repo1.maven.org/maven2/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.pom -Downloaded from mirror-force-central: https://repo1.maven.org/maven2/org/hamcrest/hamcrest-parent/1.3/hamcrest-parent-1.3.pom +Downloaded from google-maven-central: https://maven-central.storage-download.googleapis.com/maven2/junit/junit/4.11/junit-4.11.pom +Downloaded from google-maven-central: https://maven-central.storage-download.googleapis.com/maven2/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.pom +Downloaded from google-maven-central: https://maven-central.storage-download.googleapis.com/maven2/org/hamcrest/hamcrest-parent/1.3/hamcrest-parent-1.3.pom diff --git a/java/ql/integration-tests/java/buildless-maven-mirrorof/pom.xml b/java/ql/integration-tests/java/buildless-maven-mirrorof/pom.xml index ec4aaf128c1..debe59e6c03 100644 --- a/java/ql/integration-tests/java/buildless-maven-mirrorof/pom.xml +++ b/java/ql/integration-tests/java/buildless-maven-mirrorof/pom.xml @@ -111,4 +111,30 @@ + + + + + central + https://maven-central.storage-download.googleapis.com/maven2/ + + true + + + true + + + + + + central + https://maven-central.storage-download.googleapis.com/maven2/ + + true + + + true + + + \ No newline at end of file diff --git a/java/ql/integration-tests/java/buildless-maven-mirrorof/settings-xml.expected b/java/ql/integration-tests/java/buildless-maven-mirrorof/settings-xml.expected index 6a01b100b30..9b5afd40d09 100644 --- a/java/ql/integration-tests/java/buildless-maven-mirrorof/settings-xml.expected +++ b/java/ql/integration-tests/java/buildless-maven-mirrorof/settings-xml.expected @@ -5,11 +5,11 @@ - mirror-force-central + google-maven-central - Mirror Repository + GCS Maven Central mirror - https://repo1.maven.org/maven2 + https://maven-central.storage-download.googleapis.com/maven2/ *,!codeql-depgraph-plugin-repo diff --git a/java/ql/integration-tests/java/buildless-maven-mirrorof/settings.xml b/java/ql/integration-tests/java/buildless-maven-mirrorof/settings.xml index 8c4268224d4..c5d5204d1f1 100644 --- a/java/ql/integration-tests/java/buildless-maven-mirrorof/settings.xml +++ b/java/ql/integration-tests/java/buildless-maven-mirrorof/settings.xml @@ -1,9 +1,9 @@ - mirror-force-central - Mirror Repository - https://repo1.maven.org/maven2 + google-maven-central + GCS Maven Central mirror + https://maven-central.storage-download.googleapis.com/maven2/ * diff --git a/java/ql/integration-tests/java/buildless-maven-multimodule/buildless-fetches.expected b/java/ql/integration-tests/java/buildless-maven-multimodule/buildless-fetches.expected index e4a95afc713..a005078e06e 100644 --- a/java/ql/integration-tests/java/buildless-maven-multimodule/buildless-fetches.expected +++ b/java/ql/integration-tests/java/buildless-maven-multimodule/buildless-fetches.expected @@ -1,3 +1,6 @@ +https://maven-central.storage-download.googleapis.com/maven2/junit/junit/4.11/junit-4.11.jar +https://maven-central.storage-download.googleapis.com/maven2/org/apache/commons/commons-lang3/3.14.0/commons-lang3-3.14.0.jar +https://maven-central.storage-download.googleapis.com/maven2/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar https://repo.maven.apache.org/maven2/com/feiniaojin/naaf/naaf-graceful-response-example/1.0/naaf-graceful-response-example-1.0.jar https://repo.maven.apache.org/maven2/com/github/MoebiusSolutions/avro-registry-in-source/avro-registry-in-source-tests/1.8/avro-registry-in-source-tests-1.8.jar https://repo.maven.apache.org/maven2/com/github/MoebiusSolutions/avro-registry-in-source/example-project/1.5/example-project-1.5.jar @@ -9,10 +12,7 @@ https://repo.maven.apache.org/maven2/de/knutwalker/rx-redis-example_2.11/0.1.2/r https://repo.maven.apache.org/maven2/de/knutwalker/rx-redis-java-example_2.11/0.1.2/rx-redis-java-example_2.11-0.1.2.jar https://repo.maven.apache.org/maven2/io/github/scrollsyou/example-spring-boot-starter/1.0.0/example-spring-boot-starter-1.0.0.jar https://repo.maven.apache.org/maven2/io/streamnative/com/example/maven-central-template/server/3.0.0/server-3.0.0.jar -https://repo.maven.apache.org/maven2/junit/junit/4.11/junit-4.11.jar https://repo.maven.apache.org/maven2/no/nav/security/token-validation-ktor-demo/3.1.0/token-validation-ktor-demo-3.1.0.jar -https://repo.maven.apache.org/maven2/org/apache/commons/commons-lang3/3.14.0/commons-lang3-3.14.0.jar -https://repo.maven.apache.org/maven2/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar https://repo.maven.apache.org/maven2/org/minijax/minijax-example-fileupload/0.5.10/minijax-example-fileupload-0.5.10.jar https://repo.maven.apache.org/maven2/org/minijax/minijax-example-inject/0.5.10/minijax-example-inject-0.5.10.jar https://repo.maven.apache.org/maven2/org/minijax/minijax-example-json/0.5.10/minijax-example-json-0.5.10.jar diff --git a/java/ql/integration-tests/java/buildless-maven-multimodule/diagnostics.expected b/java/ql/integration-tests/java/buildless-maven-multimodule/diagnostics.expected index 1058e1528f9..cc4731ad9c2 100644 --- a/java/ql/integration-tests/java/buildless-maven-multimodule/diagnostics.expected +++ b/java/ql/integration-tests/java/buildless-maven-multimodule/diagnostics.expected @@ -1,3 +1,18 @@ +{ + "attributes": {}, + "markdownMessage": "Internal telemetry for the Java extractor.\n\nNo action needed.", + "severity": "note", + "source": { + "extractorName": "java", + "id": "java/extractor/summary", + "name": "Java extractor telemetry" + }, + "visibility": { + "cliSummaryTable": false, + "statusPage": false, + "telemetry": true + } +} { "markdownMessage": "Java analysis used build tool Maven to pick a JDK version and/or to recommend external dependencies.", "severity": "unknown", diff --git a/java/ql/integration-tests/java/buildless-maven-multimodule/settings.xml b/java/ql/integration-tests/java/buildless-maven-multimodule/settings.xml new file mode 100644 index 00000000000..a40670670a6 --- /dev/null +++ b/java/ql/integration-tests/java/buildless-maven-multimodule/settings.xml @@ -0,0 +1,10 @@ + + + + google-maven-central + GCS Maven Central mirror + https://maven-central.storage-download.googleapis.com/maven2/ + central + + + diff --git a/java/ql/integration-tests/java/buildless-maven-multimodule/source_archive.expected b/java/ql/integration-tests/java/buildless-maven-multimodule/source_archive.expected index 1e19d984019..db2c37d5ccd 100644 --- a/java/ql/integration-tests/java/buildless-maven-multimodule/source_archive.expected +++ b/java/ql/integration-tests/java/buildless-maven-multimodule/source_archive.expected @@ -1,4 +1,5 @@ pom.xml +settings.xml submod1/pom.xml submod1/src/main/java/com/example/App.java submod1/src/main/resources/my-app.properties diff --git a/java/ql/integration-tests/java/buildless-maven-multimodule/test.py b/java/ql/integration-tests/java/buildless-maven-multimodule/test.py index 2a839a0c294..04ce2aac710 100644 --- a/java/ql/integration-tests/java/buildless-maven-multimodule/test.py +++ b/java/ql/integration-tests/java/buildless-maven-multimodule/test.py @@ -1,7 +1,10 @@ +import os + def test(codeql, java, check_diagnostics_java): codeql.database.create( _env={ "CODEQL_EXTRACTOR_JAVA_OPTION_BUILDLESS": "true", "CODEQL_EXTRACTOR_JAVA_OPTION_BUILDLESS_CLASSPATH_FROM_BUILD_FILES": "true", + "LGTM_INDEX_MAVEN_SETTINGS_FILE": os.path.join(os.path.dirname(os.path.realpath(__file__)), "settings.xml"), } ) diff --git a/java/ql/integration-tests/java/buildless-maven-timeout/diagnostics.expected b/java/ql/integration-tests/java/buildless-maven-timeout/diagnostics.expected index 5a30189b5e3..db71cb39532 100644 --- a/java/ql/integration-tests/java/buildless-maven-timeout/diagnostics.expected +++ b/java/ql/integration-tests/java/buildless-maven-timeout/diagnostics.expected @@ -1,3 +1,18 @@ +{ + "attributes": {}, + "markdownMessage": "Internal telemetry for the Java extractor.\n\nNo action needed.", + "severity": "note", + "source": { + "extractorName": "java", + "id": "java/extractor/summary", + "name": "Java extractor telemetry" + }, + "visibility": { + "cliSummaryTable": false, + "statusPage": false, + "telemetry": true + } +} { "markdownMessage": "A Maven process was aborted because it didn't write to the console for 5 seconds. Consider either lenghtening the timeout if appropriate by setting CODEQL_EXTRACTOR_JAVA_BUILDLESS_CHILD_PROCESS_IDLE_TIMEOUT to a higher value or zero for no timeout, or else investigate why Maven timed out. Java analysis will continue, but the analysis may be of reduced quality.", "severity": "note", @@ -83,7 +98,7 @@ } } { - "markdownMessage": "Running the Maven plugin `com.github.ferstl:depgraph-maven-plugin:4.0.3-CodeQL-2:graph` failed. This means precise dependency information will be unavailable, and so dependencies will be guessed based on Java package names. Consider investigating why this plugin fails to run.", + "markdownMessage": "Running the Maven plugin `com.github.ferstl:depgraph-maven-plugin:4.0.3-CodeQL-3:graph` failed. This means precise dependency information will be unavailable, and so dependencies will be guessed based on Java package names. Consider investigating why this plugin fails to run.", "severity": "note", "source": { "extractorName": "java", diff --git a/java/ql/integration-tests/java/buildless-maven-timeout/settings.xml b/java/ql/integration-tests/java/buildless-maven-timeout/settings.xml new file mode 100644 index 00000000000..a40670670a6 --- /dev/null +++ b/java/ql/integration-tests/java/buildless-maven-timeout/settings.xml @@ -0,0 +1,10 @@ + + + + google-maven-central + GCS Maven Central mirror + https://maven-central.storage-download.googleapis.com/maven2/ + central + + + diff --git a/java/ql/integration-tests/java/buildless-maven-timeout/source_archive.expected b/java/ql/integration-tests/java/buildless-maven-timeout/source_archive.expected index 0f7ecaa2630..38a7383604a 100644 --- a/java/ql/integration-tests/java/buildless-maven-timeout/source_archive.expected +++ b/java/ql/integration-tests/java/buildless-maven-timeout/source_archive.expected @@ -1,5 +1,6 @@ .mvn/wrapper/maven-wrapper.properties pom.xml +settings.xml src/main/java/com/example/App.java src/main/resources/my-app.properties src/main/resources/page.xml diff --git a/java/ql/integration-tests/java/buildless-maven-timeout/test.py b/java/ql/integration-tests/java/buildless-maven-timeout/test.py index 7bf7e25357f..2e409457c54 100644 --- a/java/ql/integration-tests/java/buildless-maven-timeout/test.py +++ b/java/ql/integration-tests/java/buildless-maven-timeout/test.py @@ -1,6 +1,11 @@ +import os + def test(codeql, java, check_diagnostics_java): # mvnw has been rigged to stall for a long time by trying to fetch from a black-hole IP. We should find the timeout logic fires and buildless aborts the Maven run quickly. codeql.database.create( build_mode="none", - _env={"CODEQL_EXTRACTOR_JAVA_BUILDLESS_CHILD_PROCESS_IDLE_TIMEOUT": "5"}, + _env={ + "CODEQL_EXTRACTOR_JAVA_BUILDLESS_CHILD_PROCESS_IDLE_TIMEOUT": "5", + "LGTM_INDEX_MAVEN_SETTINGS_FILE": os.path.join(os.path.dirname(os.path.realpath(__file__)), "settings.xml"), + }, ) diff --git a/java/ql/integration-tests/java/buildless-maven-tolerate-unavailable-dependency/diagnostics.expected b/java/ql/integration-tests/java/buildless-maven-tolerate-unavailable-dependency/diagnostics.expected index 0ef924eb7c1..0b6f182e818 100644 --- a/java/ql/integration-tests/java/buildless-maven-tolerate-unavailable-dependency/diagnostics.expected +++ b/java/ql/integration-tests/java/buildless-maven-tolerate-unavailable-dependency/diagnostics.expected @@ -1,3 +1,18 @@ +{ + "attributes": {}, + "markdownMessage": "Internal telemetry for the Java extractor.\n\nNo action needed.", + "severity": "note", + "source": { + "extractorName": "java", + "id": "java/extractor/summary", + "name": "Java extractor telemetry" + }, + "visibility": { + "cliSummaryTable": false, + "statusPage": false, + "telemetry": true + } +} { "markdownMessage": "At least one dependency JAR suggested by the build system could not be downloaded. This means the analysis will try to satisfy the dependency with its default choice for the required external package name, which may be the wrong version or the wrong package entirely. This may lead to partial analysis of code using this dependency. See the extraction log for full details. If the cause appears to be a temporary outage, consider retrying the analysis.", "severity": "note", @@ -97,7 +112,7 @@ } } { - "markdownMessage": "Running the Maven plugin `com.github.ferstl:depgraph-maven-plugin:4.0.3-CodeQL-2:graph` yielded an artifact transfer exception. This means some dependency information will be unavailable, and so some dependencies will be guessed based on Java package names. Consider investigating why this plugin encountered errors retrieving dependencies.", + "markdownMessage": "Running the Maven plugin `com.github.ferstl:depgraph-maven-plugin:4.0.3-CodeQL-3:graph` yielded an artifact transfer exception. This means some dependency information will be unavailable, and so some dependencies will be guessed based on Java package names. Consider investigating why this plugin encountered errors retrieving dependencies.", "severity": "note", "source": { "extractorName": "java", diff --git a/java/ql/integration-tests/java/buildless-maven-tolerate-unavailable-dependency/settings.xml b/java/ql/integration-tests/java/buildless-maven-tolerate-unavailable-dependency/settings.xml new file mode 100644 index 00000000000..a40670670a6 --- /dev/null +++ b/java/ql/integration-tests/java/buildless-maven-tolerate-unavailable-dependency/settings.xml @@ -0,0 +1,10 @@ + + + + google-maven-central + GCS Maven Central mirror + https://maven-central.storage-download.googleapis.com/maven2/ + central + + + diff --git a/java/ql/integration-tests/java/buildless-maven-tolerate-unavailable-dependency/test.py b/java/ql/integration-tests/java/buildless-maven-tolerate-unavailable-dependency/test.py index f7673ce3ad1..1d2b6c06b3f 100644 --- a/java/ql/integration-tests/java/buildless-maven-tolerate-unavailable-dependency/test.py +++ b/java/ql/integration-tests/java/buildless-maven-tolerate-unavailable-dependency/test.py @@ -1,4 +1,9 @@ -def test(codeql, java): +import os + +def test(codeql, java, check_diagnostics_java): codeql.database.create( build_mode="none", + _env={ + "LGTM_INDEX_MAVEN_SETTINGS_FILE": os.path.join(os.path.dirname(os.path.realpath(__file__)), "settings.xml"), + } ) diff --git a/java/ql/integration-tests/java/buildless-maven/buildless-fetches.expected b/java/ql/integration-tests/java/buildless-maven/buildless-fetches.expected index 49120865e8d..a4bfbc7a97b 100644 --- a/java/ql/integration-tests/java/buildless-maven/buildless-fetches.expected +++ b/java/ql/integration-tests/java/buildless-maven/buildless-fetches.expected @@ -1,3 +1,5 @@ +https://maven-central.storage-download.googleapis.com/maven2/junit/junit/4.11/junit-4.11.jar +https://maven-central.storage-download.googleapis.com/maven2/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar https://repo.maven.apache.org/maven2/com/feiniaojin/naaf/naaf-graceful-response-example/1.0/naaf-graceful-response-example-1.0.jar https://repo.maven.apache.org/maven2/com/github/MoebiusSolutions/avro-registry-in-source/avro-registry-in-source-tests/1.8/avro-registry-in-source-tests-1.8.jar https://repo.maven.apache.org/maven2/com/github/MoebiusSolutions/avro-registry-in-source/example-project/1.5/example-project-1.5.jar @@ -9,9 +11,7 @@ https://repo.maven.apache.org/maven2/de/knutwalker/rx-redis-example_2.11/0.1.2/r https://repo.maven.apache.org/maven2/de/knutwalker/rx-redis-java-example_2.11/0.1.2/rx-redis-java-example_2.11-0.1.2.jar https://repo.maven.apache.org/maven2/io/github/scrollsyou/example-spring-boot-starter/1.0.0/example-spring-boot-starter-1.0.0.jar https://repo.maven.apache.org/maven2/io/streamnative/com/example/maven-central-template/server/3.0.0/server-3.0.0.jar -https://repo.maven.apache.org/maven2/junit/junit/4.11/junit-4.11.jar https://repo.maven.apache.org/maven2/no/nav/security/token-validation-ktor-demo/3.1.0/token-validation-ktor-demo-3.1.0.jar -https://repo.maven.apache.org/maven2/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar https://repo.maven.apache.org/maven2/org/minijax/minijax-example-fileupload/0.5.10/minijax-example-fileupload-0.5.10.jar https://repo.maven.apache.org/maven2/org/minijax/minijax-example-inject/0.5.10/minijax-example-inject-0.5.10.jar https://repo.maven.apache.org/maven2/org/minijax/minijax-example-json/0.5.10/minijax-example-json-0.5.10.jar diff --git a/java/ql/integration-tests/java/buildless-maven/diagnostics.expected b/java/ql/integration-tests/java/buildless-maven/diagnostics.expected index f3c89bb842a..fdef7e871f5 100644 --- a/java/ql/integration-tests/java/buildless-maven/diagnostics.expected +++ b/java/ql/integration-tests/java/buildless-maven/diagnostics.expected @@ -1,3 +1,18 @@ +{ + "attributes": {}, + "markdownMessage": "Internal telemetry for the Java extractor.\n\nNo action needed.", + "severity": "note", + "source": { + "extractorName": "java", + "id": "java/extractor/summary", + "name": "Java extractor telemetry" + }, + "visibility": { + "cliSummaryTable": false, + "statusPage": false, + "telemetry": true + } +} { "markdownMessage": "Java analysis used build tool Maven to pick a JDK version and/or to recommend external dependencies.", "severity": "unknown", diff --git a/java/ql/integration-tests/java/buildless-maven/maven-fetches.expected b/java/ql/integration-tests/java/buildless-maven/maven-fetches.expected index 208ca501487..bf66bd15f01 100644 --- a/java/ql/integration-tests/java/buildless-maven/maven-fetches.expected +++ b/java/ql/integration-tests/java/buildless-maven/maven-fetches.expected @@ -1,6 +1,6 @@ -Downloaded from central: https://repo.maven.apache.org/maven2/junit/junit/4.11/junit-4.11.pom -Downloaded from central: https://repo.maven.apache.org/maven2/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.pom -Downloaded from central: https://repo.maven.apache.org/maven2/org/hamcrest/hamcrest-parent/1.3/hamcrest-parent-1.3.pom +Downloaded from central: https://maven-central.storage-download.googleapis.com/maven2/junit/junit/4.11/junit-4.11.pom +Downloaded from central: https://maven-central.storage-download.googleapis.com/maven2/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.pom +Downloaded from central: https://maven-central.storage-download.googleapis.com/maven2/org/hamcrest/hamcrest-parent/1.3/hamcrest-parent-1.3.pom Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/com/fasterxml/jackson/core/jackson-annotations/2.18.6/jackson-annotations-2.18.6.jar Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/com/fasterxml/jackson/core/jackson-annotations/2.18.6/jackson-annotations-2.18.6.pom Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/com/fasterxml/jackson/core/jackson-core/2.18.6/jackson-core-2.18.6.jar @@ -11,8 +11,8 @@ Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferst Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/com/fasterxml/jackson/jackson-bom/2.18.6/jackson-bom-2.18.6.pom Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/com/fasterxml/jackson/jackson-parent/2.18.4/jackson-parent-2.18.4.pom Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/com/fasterxml/oss-parent/69/oss-parent-69.pom -Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/com/github/ferstl/depgraph-maven-plugin/4.0.3-CodeQL-2/depgraph-maven-plugin-4.0.3-CodeQL-2.jar -Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/com/github/ferstl/depgraph-maven-plugin/4.0.3-CodeQL-2/depgraph-maven-plugin-4.0.3-CodeQL-2.pom +Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/com/github/ferstl/depgraph-maven-plugin/4.0.3-CodeQL-3/depgraph-maven-plugin-4.0.3-CodeQL-3.jar +Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/com/github/ferstl/depgraph-maven-plugin/4.0.3-CodeQL-3/depgraph-maven-plugin-4.0.3-CodeQL-3.pom Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/com/google/code/findbugs/jsr305/3.0.2/jsr305-3.0.2.jar Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/com/google/code/findbugs/jsr305/3.0.2/jsr305-3.0.2.pom Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/com/google/errorprone/error_prone_annotations/2.36.0/error_prone_annotations-2.36.0.jar @@ -31,12 +31,12 @@ Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferst Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/javax/annotation/javax.annotation-api/1.2/javax.annotation-api-1.2.jar Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/javax/annotation/javax.annotation-api/1.2/javax.annotation-api-1.2.pom Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/net/java/jvnet-parent/3/jvnet-parent-3.pom -Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/apache/apache/19/apache-19.pom Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/apache/apache/25/apache-25.pom Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/apache/apache/27/apache-27.pom -Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/apache/commons/commons-lang3/3.8.1/commons-lang3-3.8.1.jar -Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/apache/commons/commons-lang3/3.8.1/commons-lang3-3.8.1.pom -Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/apache/commons/commons-parent/47/commons-parent-47.pom +Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/apache/apache/35/apache-35.pom +Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/apache/commons/commons-lang3/3.18.0/commons-lang3-3.18.0.jar +Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/apache/commons/commons-lang3/3.18.0/commons-lang3-3.18.0.pom +Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/apache/commons/commons-parent/85/commons-parent-85.pom Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/apache/maven/maven-artifact/3.8.6/maven-artifact-3.8.6.jar Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/apache/maven/maven-artifact/3.8.6/maven-artifact-3.8.6.pom Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/apache/maven/maven-model/3.8.6/maven-model-3.8.6.jar @@ -57,12 +57,11 @@ Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferst Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/codehaus/plexus/plexus-component-annotations/1.5.5/plexus-component-annotations-1.5.5.jar Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/codehaus/plexus/plexus-component-annotations/1.5.5/plexus-component-annotations-1.5.5.pom Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/codehaus/plexus/plexus-containers/1.5.5/plexus-containers-1.5.5.pom -Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/codehaus/plexus/plexus-utils/3.0.24/plexus-utils-3.0.24.pom -Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/codehaus/plexus/plexus-utils/3.3.1/plexus-utils-3.3.1.jar -Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/codehaus/plexus/plexus-utils/3.3.1/plexus-utils-3.3.1.pom +Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/codehaus/plexus/plexus-utils/3.6.1/plexus-utils-3.6.1.jar +Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/codehaus/plexus/plexus-utils/3.6.1/plexus-utils-3.6.1.pom Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/codehaus/plexus/plexus/2.0.7/plexus-2.0.7.pom +Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/codehaus/plexus/plexus/25/plexus-25.pom Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/codehaus/plexus/plexus/3.3.1/plexus-3.3.1.pom -Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/codehaus/plexus/plexus/4.0/plexus-4.0.pom Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/codehaus/plexus/plexus/5.1/plexus-5.1.pom Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/eclipse/sisu/org.eclipse.sisu.inject/0.3.5/org.eclipse.sisu.inject-0.3.5.jar Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/eclipse/sisu/org.eclipse.sisu.inject/0.3.5/org.eclipse.sisu.inject-0.3.5.pom @@ -70,6 +69,8 @@ Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferst Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/eclipse/sisu/org.eclipse.sisu.plexus/0.3.5/org.eclipse.sisu.plexus-0.3.5.pom Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/eclipse/sisu/sisu-inject/0.3.5/sisu-inject-0.3.5.pom Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/eclipse/sisu/sisu-plexus/0.3.5/sisu-plexus-0.3.5.pom +Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/junit/junit-bom/5.13.1/junit-bom-5.13.1.pom +Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/junit/junit-bom/5.14.1/junit-bom-5.14.1.pom Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/junit/junit-bom/5.9.1/junit-bom-5.9.1.pom Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/sonatype/forge/forge-parent/10/forge-parent-10.pom Downloaded from codeql-depgraph-plugin-repo: file://[dist-root]/java/tools/ferstl-depgraph-dependencies/org/sonatype/oss/oss-parent/7/oss-parent-7.pom diff --git a/java/ql/integration-tests/java/buildless-maven/pom.xml b/java/ql/integration-tests/java/buildless-maven/pom.xml index ec4aaf128c1..debe59e6c03 100644 --- a/java/ql/integration-tests/java/buildless-maven/pom.xml +++ b/java/ql/integration-tests/java/buildless-maven/pom.xml @@ -111,4 +111,30 @@ + + + + + central + https://maven-central.storage-download.googleapis.com/maven2/ + + true + + + true + + + + + + central + https://maven-central.storage-download.googleapis.com/maven2/ + + true + + + true + + + \ No newline at end of file diff --git a/java/ql/integration-tests/java/buildless-proxy-gradle/build.gradle b/java/ql/integration-tests/java/buildless-proxy-gradle/build.gradle index 98833538000..ae557cf3afa 100644 --- a/java/ql/integration-tests/java/buildless-proxy-gradle/build.gradle +++ b/java/ql/integration-tests/java/buildless-proxy-gradle/build.gradle @@ -8,7 +8,9 @@ apply plugin: 'java-library' repositories { - mavenCentral() + maven { + url = 'https://maven-central.storage-download.googleapis.com/maven2/' + } } dependencies { diff --git a/java/ql/integration-tests/java/buildless-proxy-gradle/buildless-fetches.expected b/java/ql/integration-tests/java/buildless-proxy-gradle/buildless-fetches.expected index 631cb23bade..397d226299f 100644 --- a/java/ql/integration-tests/java/buildless-proxy-gradle/buildless-fetches.expected +++ b/java/ql/integration-tests/java/buildless-proxy-gradle/buildless-fetches.expected @@ -1 +1 @@ -https://repo.maven.apache.org/maven2/org/apache/commons/commons-math3/3.6.1/commons-math3-3.6.1.jar +https://maven-central.storage-download.googleapis.com/maven2/org/apache/commons/commons-math3/3.6.1/commons-math3-3.6.1.jar diff --git a/java/ql/integration-tests/java/buildless-proxy-gradle/diagnostics.expected b/java/ql/integration-tests/java/buildless-proxy-gradle/diagnostics.expected index 337fa933808..abe6bfaa24c 100644 --- a/java/ql/integration-tests/java/buildless-proxy-gradle/diagnostics.expected +++ b/java/ql/integration-tests/java/buildless-proxy-gradle/diagnostics.expected @@ -1,3 +1,18 @@ +{ + "attributes": {}, + "markdownMessage": "Internal telemetry for the Java extractor.\n\nNo action needed.", + "severity": "note", + "source": { + "extractorName": "java", + "id": "java/extractor/summary", + "name": "Java extractor telemetry" + }, + "visibility": { + "cliSummaryTable": false, + "statusPage": false, + "telemetry": true + } +} { "markdownMessage": "Java analysis used build tool Gradle to pick a JDK version and/or to recommend external dependencies.", "severity": "unknown", diff --git a/java/ql/integration-tests/java/buildless-proxy-maven/buildless-fetches.expected b/java/ql/integration-tests/java/buildless-proxy-maven/buildless-fetches.expected index 49120865e8d..a4bfbc7a97b 100644 --- a/java/ql/integration-tests/java/buildless-proxy-maven/buildless-fetches.expected +++ b/java/ql/integration-tests/java/buildless-proxy-maven/buildless-fetches.expected @@ -1,3 +1,5 @@ +https://maven-central.storage-download.googleapis.com/maven2/junit/junit/4.11/junit-4.11.jar +https://maven-central.storage-download.googleapis.com/maven2/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar https://repo.maven.apache.org/maven2/com/feiniaojin/naaf/naaf-graceful-response-example/1.0/naaf-graceful-response-example-1.0.jar https://repo.maven.apache.org/maven2/com/github/MoebiusSolutions/avro-registry-in-source/avro-registry-in-source-tests/1.8/avro-registry-in-source-tests-1.8.jar https://repo.maven.apache.org/maven2/com/github/MoebiusSolutions/avro-registry-in-source/example-project/1.5/example-project-1.5.jar @@ -9,9 +11,7 @@ https://repo.maven.apache.org/maven2/de/knutwalker/rx-redis-example_2.11/0.1.2/r https://repo.maven.apache.org/maven2/de/knutwalker/rx-redis-java-example_2.11/0.1.2/rx-redis-java-example_2.11-0.1.2.jar https://repo.maven.apache.org/maven2/io/github/scrollsyou/example-spring-boot-starter/1.0.0/example-spring-boot-starter-1.0.0.jar https://repo.maven.apache.org/maven2/io/streamnative/com/example/maven-central-template/server/3.0.0/server-3.0.0.jar -https://repo.maven.apache.org/maven2/junit/junit/4.11/junit-4.11.jar https://repo.maven.apache.org/maven2/no/nav/security/token-validation-ktor-demo/3.1.0/token-validation-ktor-demo-3.1.0.jar -https://repo.maven.apache.org/maven2/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar https://repo.maven.apache.org/maven2/org/minijax/minijax-example-fileupload/0.5.10/minijax-example-fileupload-0.5.10.jar https://repo.maven.apache.org/maven2/org/minijax/minijax-example-inject/0.5.10/minijax-example-inject-0.5.10.jar https://repo.maven.apache.org/maven2/org/minijax/minijax-example-json/0.5.10/minijax-example-json-0.5.10.jar diff --git a/java/ql/integration-tests/java/buildless-proxy-maven/diagnostics.expected b/java/ql/integration-tests/java/buildless-proxy-maven/diagnostics.expected index f3c89bb842a..fdef7e871f5 100644 --- a/java/ql/integration-tests/java/buildless-proxy-maven/diagnostics.expected +++ b/java/ql/integration-tests/java/buildless-proxy-maven/diagnostics.expected @@ -1,3 +1,18 @@ +{ + "attributes": {}, + "markdownMessage": "Internal telemetry for the Java extractor.\n\nNo action needed.", + "severity": "note", + "source": { + "extractorName": "java", + "id": "java/extractor/summary", + "name": "Java extractor telemetry" + }, + "visibility": { + "cliSummaryTable": false, + "statusPage": false, + "telemetry": true + } +} { "markdownMessage": "Java analysis used build tool Maven to pick a JDK version and/or to recommend external dependencies.", "severity": "unknown", diff --git a/java/ql/integration-tests/java/buildless-proxy-maven/settings.xml b/java/ql/integration-tests/java/buildless-proxy-maven/settings.xml new file mode 100644 index 00000000000..a40670670a6 --- /dev/null +++ b/java/ql/integration-tests/java/buildless-proxy-maven/settings.xml @@ -0,0 +1,10 @@ + + + + google-maven-central + GCS Maven Central mirror + https://maven-central.storage-download.googleapis.com/maven2/ + central + + + diff --git a/java/ql/integration-tests/java/buildless-proxy-maven/source_archive.expected b/java/ql/integration-tests/java/buildless-proxy-maven/source_archive.expected index 0a86ff54645..ac35d94be39 100644 --- a/java/ql/integration-tests/java/buildless-proxy-maven/source_archive.expected +++ b/java/ql/integration-tests/java/buildless-proxy-maven/source_archive.expected @@ -1,4 +1,5 @@ pom.xml +settings.xml src/main/java/com/example/App.java src/main/resources/my-app.properties src/main/resources/page.xml diff --git a/java/ql/integration-tests/java/buildless-proxy-maven/test.py b/java/ql/integration-tests/java/buildless-proxy-maven/test.py index 879a1b3a80a..4b9c2c2d9f8 100644 --- a/java/ql/integration-tests/java/buildless-proxy-maven/test.py +++ b/java/ql/integration-tests/java/buildless-proxy-maven/test.py @@ -1,7 +1,10 @@ +import os + def test(codeql, java, codeql_mitm_proxy, check_diagnostics_java): codeql.database.create( _env={ "CODEQL_EXTRACTOR_JAVA_OPTION_BUILDLESS": "true", "CODEQL_EXTRACTOR_JAVA_OPTION_BUILDLESS_CLASSPATH_FROM_BUILD_FILES": "true", + "LGTM_INDEX_MAVEN_SETTINGS_FILE": os.path.join(os.path.dirname(os.path.realpath(__file__)), "settings.xml"), } ) diff --git a/java/ql/integration-tests/java/buildless-sibling-projects/buildless-fetches.expected b/java/ql/integration-tests/java/buildless-sibling-projects/buildless-fetches.expected index 79b12c2919e..c09259a9cb9 100644 --- a/java/ql/integration-tests/java/buildless-sibling-projects/buildless-fetches.expected +++ b/java/ql/integration-tests/java/buildless-sibling-projects/buildless-fetches.expected @@ -1,6 +1,7 @@ -https://jcenter.bintray.com/junit/junit/4.12/junit-4.12.jar -https://jcenter.bintray.com/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar -https://jcenter.bintray.com/org/slf4j/slf4j-api/1.7.21/slf4j-api-1.7.21.jar +https://maven-central.storage-download.googleapis.com/maven2/junit/junit/4.11/junit-4.11.jar +https://maven-central.storage-download.googleapis.com/maven2/junit/junit/4.12/junit-4.12.jar +https://maven-central.storage-download.googleapis.com/maven2/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar +https://maven-central.storage-download.googleapis.com/maven2/org/slf4j/slf4j-api/1.7.21/slf4j-api-1.7.21.jar https://repo.maven.apache.org/maven2/com/feiniaojin/naaf/naaf-graceful-response-example/1.0/naaf-graceful-response-example-1.0.jar https://repo.maven.apache.org/maven2/com/github/MoebiusSolutions/avro-registry-in-source/avro-registry-in-source-tests/1.8/avro-registry-in-source-tests-1.8.jar https://repo.maven.apache.org/maven2/com/github/MoebiusSolutions/avro-registry-in-source/example-project/1.5/example-project-1.5.jar @@ -12,7 +13,6 @@ https://repo.maven.apache.org/maven2/de/knutwalker/rx-redis-example_2.11/0.1.2/r https://repo.maven.apache.org/maven2/de/knutwalker/rx-redis-java-example_2.11/0.1.2/rx-redis-java-example_2.11-0.1.2.jar https://repo.maven.apache.org/maven2/io/github/scrollsyou/example-spring-boot-starter/1.0.0/example-spring-boot-starter-1.0.0.jar https://repo.maven.apache.org/maven2/io/streamnative/com/example/maven-central-template/server/3.0.0/server-3.0.0.jar -https://repo.maven.apache.org/maven2/junit/junit/4.11/junit-4.11.jar https://repo.maven.apache.org/maven2/no/nav/security/token-validation-ktor-demo/3.1.0/token-validation-ktor-demo-3.1.0.jar https://repo.maven.apache.org/maven2/org/minijax/minijax-example-fileupload/0.5.10/minijax-example-fileupload-0.5.10.jar https://repo.maven.apache.org/maven2/org/minijax/minijax-example-inject/0.5.10/minijax-example-inject-0.5.10.jar diff --git a/java/ql/integration-tests/java/buildless-sibling-projects/diagnostics.expected b/java/ql/integration-tests/java/buildless-sibling-projects/diagnostics.expected index b3df8a700c3..b821d41e600 100644 --- a/java/ql/integration-tests/java/buildless-sibling-projects/diagnostics.expected +++ b/java/ql/integration-tests/java/buildless-sibling-projects/diagnostics.expected @@ -1,3 +1,18 @@ +{ + "attributes": {}, + "markdownMessage": "Internal telemetry for the Java extractor.\n\nNo action needed.", + "severity": "note", + "source": { + "extractorName": "java", + "id": "java/extractor/summary", + "name": "Java extractor telemetry" + }, + "visibility": { + "cliSummaryTable": false, + "statusPage": false, + "telemetry": true + } +} { "markdownMessage": "Java analysis dropped the following dependencies because a sibling project depends on a higher version:\n\n* `junit/junit-4.11`", "severity": "unknown", diff --git a/java/ql/integration-tests/java/buildless-sibling-projects/gradle-sample/build.gradle b/java/ql/integration-tests/java/buildless-sibling-projects/gradle-sample/build.gradle index 3da556a7939..c8a167ad540 100644 --- a/java/ql/integration-tests/java/buildless-sibling-projects/gradle-sample/build.gradle +++ b/java/ql/integration-tests/java/buildless-sibling-projects/gradle-sample/build.gradle @@ -12,9 +12,9 @@ apply plugin: 'java' // In this section you declare where to find the dependencies of your project repositories { - // Use 'jcenter' for resolving your dependencies. - // You can declare any Maven/Ivy/file repository here. - jcenter() + maven { + url = 'https://maven-central.storage-download.googleapis.com/maven2/' + } } // In this section you declare the dependencies for your production and test code diff --git a/java/ql/integration-tests/java/buildless-sibling-projects/gradle-sample2/build.gradle b/java/ql/integration-tests/java/buildless-sibling-projects/gradle-sample2/build.gradle index c3b774e3d50..53f732218ac 100644 --- a/java/ql/integration-tests/java/buildless-sibling-projects/gradle-sample2/build.gradle +++ b/java/ql/integration-tests/java/buildless-sibling-projects/gradle-sample2/build.gradle @@ -12,9 +12,9 @@ apply plugin: 'java' // In this section you declare where to find the dependencies of your project repositories { - // Use 'jcenter' for resolving your dependencies. - // You can declare any Maven/Ivy/file repository here. - jcenter() + maven { + url = 'https://maven-central.storage-download.googleapis.com/maven2/' + } } // In this section you declare the dependencies for your production and test code diff --git a/java/ql/integration-tests/java/buildless-sibling-projects/settings.xml b/java/ql/integration-tests/java/buildless-sibling-projects/settings.xml new file mode 100644 index 00000000000..a40670670a6 --- /dev/null +++ b/java/ql/integration-tests/java/buildless-sibling-projects/settings.xml @@ -0,0 +1,10 @@ + + + + google-maven-central + GCS Maven Central mirror + https://maven-central.storage-download.googleapis.com/maven2/ + central + + + diff --git a/java/ql/integration-tests/java/buildless-sibling-projects/source_archive.expected b/java/ql/integration-tests/java/buildless-sibling-projects/source_archive.expected index 3369d78d4af..5c26b296ddd 100644 --- a/java/ql/integration-tests/java/buildless-sibling-projects/source_archive.expected +++ b/java/ql/integration-tests/java/buildless-sibling-projects/source_archive.expected @@ -26,4 +26,5 @@ maven-project-2/src/main/resources/my-app.properties maven-project-2/src/main/resources/page.xml maven-project-2/src/main/resources/struts.xml maven-project-2/src/test/java/com/example/AppTest4.java +settings.xml test-db/working/settings.xml diff --git a/java/ql/integration-tests/java/buildless-sibling-projects/test.py b/java/ql/integration-tests/java/buildless-sibling-projects/test.py index 65ae24ed441..9a6144c62c3 100644 --- a/java/ql/integration-tests/java/buildless-sibling-projects/test.py +++ b/java/ql/integration-tests/java/buildless-sibling-projects/test.py @@ -1,3 +1,5 @@ +import os + def test(codeql, use_java_11, java, actions_toolchains_file, check_diagnostics_java): # The version of gradle used doesn't work on java 17 codeql.database.create( @@ -5,5 +7,6 @@ def test(codeql, use_java_11, java, actions_toolchains_file, check_diagnostics_j "CODEQL_EXTRACTOR_JAVA_OPTION_BUILDLESS": "true", "CODEQL_EXTRACTOR_JAVA_OPTION_BUILDLESS_CLASSPATH_FROM_BUILD_FILES": "true", "LGTM_INDEX_MAVEN_TOOLCHAINS_FILE": str(actions_toolchains_file), + "LGTM_INDEX_MAVEN_SETTINGS_FILE": os.path.join(os.path.dirname(os.path.realpath(__file__)), "settings.xml"), } ) diff --git a/java/ql/integration-tests/java/buildless-snapshot-repository/settings.xml b/java/ql/integration-tests/java/buildless-snapshot-repository/settings.xml new file mode 100644 index 00000000000..a40670670a6 --- /dev/null +++ b/java/ql/integration-tests/java/buildless-snapshot-repository/settings.xml @@ -0,0 +1,10 @@ + + + + google-maven-central + GCS Maven Central mirror + https://maven-central.storage-download.googleapis.com/maven2/ + central + + + diff --git a/java/ql/integration-tests/java/buildless-snapshot-repository/test.py b/java/ql/integration-tests/java/buildless-snapshot-repository/test.py index a4814e1f8a1..7aebc44fcc1 100644 --- a/java/ql/integration-tests/java/buildless-snapshot-repository/test.py +++ b/java/ql/integration-tests/java/buildless-snapshot-repository/test.py @@ -1,3 +1,4 @@ +import os import subprocess import runs_on @@ -15,7 +16,10 @@ def test(codeql, java): try: codeql.database.create( extractor_option="buildless=true", - _env={"CODEQL_EXTRACTOR_JAVA_OPTION_BUILDLESS_CLASSPATH_FROM_BUILD_FILES": "true"}, + _env={ + "CODEQL_EXTRACTOR_JAVA_OPTION_BUILDLESS_CLASSPATH_FROM_BUILD_FILES": "true", + "LGTM_INDEX_MAVEN_SETTINGS_FILE": os.path.join(os.path.dirname(os.path.realpath(__file__)), "settings.xml"), + }, ) finally: repo_server_process.kill() diff --git a/java/ql/integration-tests/java/buildless/diagnostics.expected b/java/ql/integration-tests/java/buildless/diagnostics.expected index 90aa56bf3f6..ee1b8835665 100644 --- a/java/ql/integration-tests/java/buildless/diagnostics.expected +++ b/java/ql/integration-tests/java/buildless/diagnostics.expected @@ -1,3 +1,18 @@ +{ + "attributes": {}, + "markdownMessage": "Internal telemetry for the Java extractor.\n\nNo action needed.", + "severity": "note", + "source": { + "extractorName": "java", + "id": "java/extractor/summary", + "name": "Java extractor telemetry" + }, + "visibility": { + "cliSummaryTable": false, + "statusPage": false, + "telemetry": true + } +} { "markdownMessage": "Because no usable build tool (Gradle, Maven, etc) was found, build scripts could not be queried for guidance about the appropriate JDK version for the code being extracted, or precise dependency information. The default JDK will be used, and external dependencies will be inferred from the Java package names used.", "severity": "unknown", diff --git a/java/ql/integration-tests/java/diagnostics/android-gradle-incompatibility/settings.gradle b/java/ql/integration-tests/java/diagnostics/android-gradle-incompatibility/settings.gradle index 1fa19406e1a..86c0d338f97 100644 --- a/java/ql/integration-tests/java/diagnostics/android-gradle-incompatibility/settings.gradle +++ b/java/ql/integration-tests/java/diagnostics/android-gradle-incompatibility/settings.gradle @@ -14,7 +14,9 @@ pluginManagement { repositories { gradlePluginPortal() google() - mavenCentral() + maven { + url = 'https://maven-central.storage-download.googleapis.com/maven2/' + } } } dependencyResolutionManagement { @@ -33,7 +35,9 @@ dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { google() - mavenCentral() + maven { + url = 'https://maven-central.storage-download.googleapis.com/maven2/' + } } } rootProject.name = "Android Sample" diff --git a/java/ql/integration-tests/java/diagnostics/java-version-too-old/build.gradle b/java/ql/integration-tests/java/diagnostics/java-version-too-old/build.gradle index c3b774e3d50..53f732218ac 100644 --- a/java/ql/integration-tests/java/diagnostics/java-version-too-old/build.gradle +++ b/java/ql/integration-tests/java/diagnostics/java-version-too-old/build.gradle @@ -12,9 +12,9 @@ apply plugin: 'java' // In this section you declare where to find the dependencies of your project repositories { - // Use 'jcenter' for resolving your dependencies. - // You can declare any Maven/Ivy/file repository here. - jcenter() + maven { + url = 'https://maven-central.storage-download.googleapis.com/maven2/' + } } // In this section you declare the dependencies for your production and test code diff --git a/java/ql/integration-tests/java/diagnostics/no-gradle-wrapper/build.gradle b/java/ql/integration-tests/java/diagnostics/no-gradle-wrapper/build.gradle index 071a12b7691..0fc1d500219 100644 --- a/java/ql/integration-tests/java/diagnostics/no-gradle-wrapper/build.gradle +++ b/java/ql/integration-tests/java/diagnostics/no-gradle-wrapper/build.gradle @@ -12,9 +12,9 @@ apply plugin: 'java' // In this section you declare where to find the dependencies of your project repositories { - // Use 'jcenter' for resolving your dependencies. - // You can declare any Maven/Ivy/file repository here. - jcenter() + maven { + url = 'https://maven-central.storage-download.googleapis.com/maven2/' + } } // In this section you declare the dependencies for your production and test code diff --git a/java/ql/integration-tests/java/gradle-sample-kotlin-script/app/build.gradle.kts b/java/ql/integration-tests/java/gradle-sample-kotlin-script/app/build.gradle.kts index bd48ad3b33a..dc42ddf372c 100644 --- a/java/ql/integration-tests/java/gradle-sample-kotlin-script/app/build.gradle.kts +++ b/java/ql/integration-tests/java/gradle-sample-kotlin-script/app/build.gradle.kts @@ -12,8 +12,9 @@ plugins { } repositories { - // Use Maven Central for resolving dependencies. - mavenCentral() + maven { + url = uri("https://maven-central.storage-download.googleapis.com/maven2/") + } } dependencies { diff --git a/java/ql/integration-tests/java/gradle-sample-without-wrapper-or-gradle-buildless/build.gradle b/java/ql/integration-tests/java/gradle-sample-without-wrapper-or-gradle-buildless/build.gradle index 071a12b7691..0fc1d500219 100644 --- a/java/ql/integration-tests/java/gradle-sample-without-wrapper-or-gradle-buildless/build.gradle +++ b/java/ql/integration-tests/java/gradle-sample-without-wrapper-or-gradle-buildless/build.gradle @@ -12,9 +12,9 @@ apply plugin: 'java' // In this section you declare where to find the dependencies of your project repositories { - // Use 'jcenter' for resolving your dependencies. - // You can declare any Maven/Ivy/file repository here. - jcenter() + maven { + url = 'https://maven-central.storage-download.googleapis.com/maven2/' + } } // In this section you declare the dependencies for your production and test code diff --git a/java/ql/integration-tests/java/gradle-sample-without-wrapper-or-gradle-buildless/diagnostics.expected b/java/ql/integration-tests/java/gradle-sample-without-wrapper-or-gradle-buildless/diagnostics.expected index f40920e10d6..b23aa85f254 100644 --- a/java/ql/integration-tests/java/gradle-sample-without-wrapper-or-gradle-buildless/diagnostics.expected +++ b/java/ql/integration-tests/java/gradle-sample-without-wrapper-or-gradle-buildless/diagnostics.expected @@ -1,3 +1,21 @@ +{ + "attributes": { + "java_vendor": "__REDACTED__", + "java_version": "11.0.31" + }, + "markdownMessage": "Internal telemetry for the Java extractor.\n\nNo action needed.", + "severity": "note", + "source": { + "extractorName": "java", + "id": "java/extractor/summary", + "name": "Java extractor telemetry" + }, + "visibility": { + "cliSummaryTable": false, + "statusPage": false, + "telemetry": true + } +} { "markdownMessage": "Analyzed a Gradle project without the [Gradle wrapper](https://docs.gradle.org/current/userguide/gradle_wrapper.html). This may use an incompatible version of Gradle.", "severity": "warning", diff --git a/java/ql/integration-tests/java/gradle-sample-without-wrapper-or-gradle-buildless/test.py b/java/ql/integration-tests/java/gradle-sample-without-wrapper-or-gradle-buildless/test.py index e59277f3ea3..92aedd825ef 100644 --- a/java/ql/integration-tests/java/gradle-sample-without-wrapper-or-gradle-buildless/test.py +++ b/java/ql/integration-tests/java/gradle-sample-without-wrapper-or-gradle-buildless/test.py @@ -4,7 +4,8 @@ import pathlib # The version of gradle used doesn't work on java 17 -def test(codeql, use_java_11, java, environment): +def test(codeql, use_java_11, java, environment, check_diagnostics): + check_diagnostics.redact += ["attributes.java_vendor"] gradle_override_dir = pathlib.Path(tempfile.mkdtemp()) if runs_on.windows: (gradle_override_dir / "gradle.bat").write_text("@echo off\nexit /b 2\n") diff --git a/java/ql/integration-tests/java/gradle-sample/build.gradle b/java/ql/integration-tests/java/gradle-sample/build.gradle index 071a12b7691..0fc1d500219 100644 --- a/java/ql/integration-tests/java/gradle-sample/build.gradle +++ b/java/ql/integration-tests/java/gradle-sample/build.gradle @@ -12,9 +12,9 @@ apply plugin: 'java' // In this section you declare where to find the dependencies of your project repositories { - // Use 'jcenter' for resolving your dependencies. - // You can declare any Maven/Ivy/file repository here. - jcenter() + maven { + url = 'https://maven-central.storage-download.googleapis.com/maven2/' + } } // In this section you declare the dependencies for your production and test code diff --git a/java/ql/integration-tests/java/maven-add-exports-module-flags/settings.xml b/java/ql/integration-tests/java/maven-add-exports-module-flags/settings.xml new file mode 100644 index 00000000000..a40670670a6 --- /dev/null +++ b/java/ql/integration-tests/java/maven-add-exports-module-flags/settings.xml @@ -0,0 +1,10 @@ + + + + google-maven-central + GCS Maven Central mirror + https://maven-central.storage-download.googleapis.com/maven2/ + central + + + diff --git a/java/ql/integration-tests/java/maven-add-exports-module-flags/source_archive.expected b/java/ql/integration-tests/java/maven-add-exports-module-flags/source_archive.expected index 3d84bfa09ab..e9d047b9742 100644 --- a/java/ql/integration-tests/java/maven-add-exports-module-flags/source_archive.expected +++ b/java/ql/integration-tests/java/maven-add-exports-module-flags/source_archive.expected @@ -1,3 +1,4 @@ pom.xml +settings.xml src/main/java/com/example/CompilerUser.java target/maven-archiver/pom.properties diff --git a/java/ql/integration-tests/java/maven-add-exports-module-flags/test.py b/java/ql/integration-tests/java/maven-add-exports-module-flags/test.py index 73c4b1415a1..ffa89ccab41 100644 --- a/java/ql/integration-tests/java/maven-add-exports-module-flags/test.py +++ b/java/ql/integration-tests/java/maven-add-exports-module-flags/test.py @@ -1,2 +1,9 @@ +import os + def test(codeql, java, actions_toolchains_file): - codeql.database.create(_env={"LGTM_INDEX_MAVEN_TOOLCHAINS_FILE": str(actions_toolchains_file)}) + codeql.database.create( + _env={ + "LGTM_INDEX_MAVEN_TOOLCHAINS_FILE": str(actions_toolchains_file), + "LGTM_INDEX_MAVEN_SETTINGS_FILE": os.path.join(os.path.dirname(os.path.realpath(__file__)), "settings.xml"), + } + ) diff --git a/java/ql/integration-tests/java/maven-download-failure/diagnostics.expected b/java/ql/integration-tests/java/maven-download-failure/diagnostics.expected index daabe47a9e9..c3e812b3616 100644 --- a/java/ql/integration-tests/java/maven-download-failure/diagnostics.expected +++ b/java/ql/integration-tests/java/maven-download-failure/diagnostics.expected @@ -1,3 +1,18 @@ +{ + "attributes": {}, + "markdownMessage": "Internal telemetry for the Java extractor.\n\nNo action needed.", + "severity": "note", + "source": { + "extractorName": "java", + "id": "java/extractor/summary", + "name": "Java extractor telemetry" + }, + "visibility": { + "cliSummaryTable": false, + "statusPage": false, + "telemetry": true + } +} { "markdownMessage": "Java analysis used build tool Maven to pick a JDK version and/or to recommend external dependencies.", "severity": "unknown", diff --git a/java/ql/integration-tests/java/maven-download-failure/settings.xml b/java/ql/integration-tests/java/maven-download-failure/settings.xml new file mode 100644 index 00000000000..a40670670a6 --- /dev/null +++ b/java/ql/integration-tests/java/maven-download-failure/settings.xml @@ -0,0 +1,10 @@ + + + + google-maven-central + GCS Maven Central mirror + https://maven-central.storage-download.googleapis.com/maven2/ + central + + + diff --git a/java/ql/integration-tests/java/maven-download-failure/source_archive.expected b/java/ql/integration-tests/java/maven-download-failure/source_archive.expected index 0a86ff54645..ac35d94be39 100644 --- a/java/ql/integration-tests/java/maven-download-failure/source_archive.expected +++ b/java/ql/integration-tests/java/maven-download-failure/source_archive.expected @@ -1,4 +1,5 @@ pom.xml +settings.xml src/main/java/com/example/App.java src/main/resources/my-app.properties src/main/resources/page.xml diff --git a/java/ql/integration-tests/java/maven-download-failure/test.py b/java/ql/integration-tests/java/maven-download-failure/test.py index a86d970e3fe..48bf3b41c21 100644 --- a/java/ql/integration-tests/java/maven-download-failure/test.py +++ b/java/ql/integration-tests/java/maven-download-failure/test.py @@ -2,13 +2,14 @@ import os import os.path import shutil -def test(codeql, java, check_diagnostics): +def test(codeql, java, check_diagnostics_java): # Avoid shutil resolving mvn to the wrapper script in the test dir: os.environ["NoDefaultCurrentDirectoryInExePath"] = "0" runenv = { "PATH": os.path.realpath(os.path.dirname(__file__)) + os.pathsep + os.getenv("PATH"), "REAL_MVN_PATH": shutil.which("mvn"), + "LGTM_INDEX_MAVEN_SETTINGS_FILE": os.path.join(os.path.dirname(os.path.realpath(__file__)), "settings.xml"), } del os.environ["NoDefaultCurrentDirectoryInExePath"] codeql.database.create(build_mode = "none", _env = runenv) diff --git a/java/ql/integration-tests/java/maven-enforcer-multiple-versions/settings.xml b/java/ql/integration-tests/java/maven-enforcer-multiple-versions/settings.xml new file mode 100644 index 00000000000..a40670670a6 --- /dev/null +++ b/java/ql/integration-tests/java/maven-enforcer-multiple-versions/settings.xml @@ -0,0 +1,10 @@ + + + + google-maven-central + GCS Maven Central mirror + https://maven-central.storage-download.googleapis.com/maven2/ + central + + + diff --git a/java/ql/integration-tests/java/maven-enforcer-multiple-versions/source_archive.expected b/java/ql/integration-tests/java/maven-enforcer-multiple-versions/source_archive.expected index 59a81a01481..d86dae4531f 100644 --- a/java/ql/integration-tests/java/maven-enforcer-multiple-versions/source_archive.expected +++ b/java/ql/integration-tests/java/maven-enforcer-multiple-versions/source_archive.expected @@ -1,4 +1,5 @@ pom.xml +settings.xml src/main/java/com/example/App.java src/main/resources/my-app.properties src/main/resources/page.xml diff --git a/java/ql/integration-tests/java/maven-enforcer-multiple-versions/test.py b/java/ql/integration-tests/java/maven-enforcer-multiple-versions/test.py index eb49efe6a2a..a71c8821d5e 100644 --- a/java/ql/integration-tests/java/maven-enforcer-multiple-versions/test.py +++ b/java/ql/integration-tests/java/maven-enforcer-multiple-versions/test.py @@ -1,2 +1,8 @@ +import os + def test(codeql, java): - codeql.database.create() + codeql.database.create( + _env={ + "LGTM_INDEX_MAVEN_SETTINGS_FILE": os.path.join(os.path.dirname(os.path.realpath(__file__)), "settings.xml"), + }, + ) diff --git a/java/ql/integration-tests/java/maven-enforcer-single-version/settings.xml b/java/ql/integration-tests/java/maven-enforcer-single-version/settings.xml new file mode 100644 index 00000000000..a40670670a6 --- /dev/null +++ b/java/ql/integration-tests/java/maven-enforcer-single-version/settings.xml @@ -0,0 +1,10 @@ + + + + google-maven-central + GCS Maven Central mirror + https://maven-central.storage-download.googleapis.com/maven2/ + central + + + diff --git a/java/ql/integration-tests/java/maven-enforcer-single-version/source_archive.expected b/java/ql/integration-tests/java/maven-enforcer-single-version/source_archive.expected index 59a81a01481..d86dae4531f 100644 --- a/java/ql/integration-tests/java/maven-enforcer-single-version/source_archive.expected +++ b/java/ql/integration-tests/java/maven-enforcer-single-version/source_archive.expected @@ -1,4 +1,5 @@ pom.xml +settings.xml src/main/java/com/example/App.java src/main/resources/my-app.properties src/main/resources/page.xml diff --git a/java/ql/integration-tests/java/maven-enforcer-single-version/test.py b/java/ql/integration-tests/java/maven-enforcer-single-version/test.py index eb49efe6a2a..a71c8821d5e 100644 --- a/java/ql/integration-tests/java/maven-enforcer-single-version/test.py +++ b/java/ql/integration-tests/java/maven-enforcer-single-version/test.py @@ -1,2 +1,8 @@ +import os + def test(codeql, java): - codeql.database.create() + codeql.database.create( + _env={ + "LGTM_INDEX_MAVEN_SETTINGS_FILE": os.path.join(os.path.dirname(os.path.realpath(__file__)), "settings.xml"), + }, + ) diff --git a/java/ql/integration-tests/java/maven-enforcer/settings.xml b/java/ql/integration-tests/java/maven-enforcer/settings.xml new file mode 100644 index 00000000000..a40670670a6 --- /dev/null +++ b/java/ql/integration-tests/java/maven-enforcer/settings.xml @@ -0,0 +1,10 @@ + + + + google-maven-central + GCS Maven Central mirror + https://maven-central.storage-download.googleapis.com/maven2/ + central + + + diff --git a/java/ql/integration-tests/java/maven-enforcer/source_archive.expected b/java/ql/integration-tests/java/maven-enforcer/source_archive.expected index 59a81a01481..d86dae4531f 100644 --- a/java/ql/integration-tests/java/maven-enforcer/source_archive.expected +++ b/java/ql/integration-tests/java/maven-enforcer/source_archive.expected @@ -1,4 +1,5 @@ pom.xml +settings.xml src/main/java/com/example/App.java src/main/resources/my-app.properties src/main/resources/page.xml diff --git a/java/ql/integration-tests/java/maven-enforcer/test.py b/java/ql/integration-tests/java/maven-enforcer/test.py index eb49efe6a2a..a71c8821d5e 100644 --- a/java/ql/integration-tests/java/maven-enforcer/test.py +++ b/java/ql/integration-tests/java/maven-enforcer/test.py @@ -1,2 +1,8 @@ +import os + def test(codeql, java): - codeql.database.create() + codeql.database.create( + _env={ + "LGTM_INDEX_MAVEN_SETTINGS_FILE": os.path.join(os.path.dirname(os.path.realpath(__file__)), "settings.xml"), + }, + ) diff --git a/java/ql/integration-tests/java/maven-execution-specific-java-version/settings.xml b/java/ql/integration-tests/java/maven-execution-specific-java-version/settings.xml new file mode 100644 index 00000000000..a40670670a6 --- /dev/null +++ b/java/ql/integration-tests/java/maven-execution-specific-java-version/settings.xml @@ -0,0 +1,10 @@ + + + + google-maven-central + GCS Maven Central mirror + https://maven-central.storage-download.googleapis.com/maven2/ + central + + + diff --git a/java/ql/integration-tests/java/maven-execution-specific-java-version/source_archive.expected b/java/ql/integration-tests/java/maven-execution-specific-java-version/source_archive.expected index 16e83f3a7f6..a603ae78ec4 100644 --- a/java/ql/integration-tests/java/maven-execution-specific-java-version/source_archive.expected +++ b/java/ql/integration-tests/java/maven-execution-specific-java-version/source_archive.expected @@ -1,4 +1,5 @@ pom.xml +settings.xml src/main/java/com/example/App.java src/test/java/com/example/AppTest.java target/maven-archiver/pom.properties diff --git a/java/ql/integration-tests/java/maven-execution-specific-java-version/test.py b/java/ql/integration-tests/java/maven-execution-specific-java-version/test.py index 73c4b1415a1..ffa89ccab41 100644 --- a/java/ql/integration-tests/java/maven-execution-specific-java-version/test.py +++ b/java/ql/integration-tests/java/maven-execution-specific-java-version/test.py @@ -1,2 +1,9 @@ +import os + def test(codeql, java, actions_toolchains_file): - codeql.database.create(_env={"LGTM_INDEX_MAVEN_TOOLCHAINS_FILE": str(actions_toolchains_file)}) + codeql.database.create( + _env={ + "LGTM_INDEX_MAVEN_TOOLCHAINS_FILE": str(actions_toolchains_file), + "LGTM_INDEX_MAVEN_SETTINGS_FILE": os.path.join(os.path.dirname(os.path.realpath(__file__)), "settings.xml"), + } + ) diff --git a/java/ql/integration-tests/java/maven-java16-with-higher-jdk/settings.xml b/java/ql/integration-tests/java/maven-java16-with-higher-jdk/settings.xml new file mode 100644 index 00000000000..a40670670a6 --- /dev/null +++ b/java/ql/integration-tests/java/maven-java16-with-higher-jdk/settings.xml @@ -0,0 +1,10 @@ + + + + google-maven-central + GCS Maven Central mirror + https://maven-central.storage-download.googleapis.com/maven2/ + central + + + diff --git a/java/ql/integration-tests/java/maven-java16-with-higher-jdk/source_archive.expected b/java/ql/integration-tests/java/maven-java16-with-higher-jdk/source_archive.expected index eb5dbc368ee..7fb96566709 100644 --- a/java/ql/integration-tests/java/maven-java16-with-higher-jdk/source_archive.expected +++ b/java/ql/integration-tests/java/maven-java16-with-higher-jdk/source_archive.expected @@ -1,3 +1,4 @@ pom.xml +settings.xml src/main/java/com/example/App.java target/maven-archiver/pom.properties diff --git a/java/ql/integration-tests/java/maven-java16-with-higher-jdk/test.py b/java/ql/integration-tests/java/maven-java16-with-higher-jdk/test.py index 73c4b1415a1..ffa89ccab41 100644 --- a/java/ql/integration-tests/java/maven-java16-with-higher-jdk/test.py +++ b/java/ql/integration-tests/java/maven-java16-with-higher-jdk/test.py @@ -1,2 +1,9 @@ +import os + def test(codeql, java, actions_toolchains_file): - codeql.database.create(_env={"LGTM_INDEX_MAVEN_TOOLCHAINS_FILE": str(actions_toolchains_file)}) + codeql.database.create( + _env={ + "LGTM_INDEX_MAVEN_TOOLCHAINS_FILE": str(actions_toolchains_file), + "LGTM_INDEX_MAVEN_SETTINGS_FILE": os.path.join(os.path.dirname(os.path.realpath(__file__)), "settings.xml"), + } + ) diff --git a/java/ql/integration-tests/java/maven-java8-java11-dependency/settings.xml b/java/ql/integration-tests/java/maven-java8-java11-dependency/settings.xml new file mode 100644 index 00000000000..a40670670a6 --- /dev/null +++ b/java/ql/integration-tests/java/maven-java8-java11-dependency/settings.xml @@ -0,0 +1,10 @@ + + + + google-maven-central + GCS Maven Central mirror + https://maven-central.storage-download.googleapis.com/maven2/ + central + + + diff --git a/java/ql/integration-tests/java/maven-java8-java11-dependency/source_archive.expected b/java/ql/integration-tests/java/maven-java8-java11-dependency/source_archive.expected index 5088f76cc38..51c47ade3d0 100644 --- a/java/ql/integration-tests/java/maven-java8-java11-dependency/source_archive.expected +++ b/java/ql/integration-tests/java/maven-java8-java11-dependency/source_archive.expected @@ -1,4 +1,5 @@ pom.xml +settings.xml src/main/java/com/example/Calculator.java src/test/java/com/example/CalculatorTest.java target/maven-archiver/pom.properties diff --git a/java/ql/integration-tests/java/maven-java8-java11-dependency/test.py b/java/ql/integration-tests/java/maven-java8-java11-dependency/test.py index 73c4b1415a1..ffa89ccab41 100644 --- a/java/ql/integration-tests/java/maven-java8-java11-dependency/test.py +++ b/java/ql/integration-tests/java/maven-java8-java11-dependency/test.py @@ -1,2 +1,9 @@ +import os + def test(codeql, java, actions_toolchains_file): - codeql.database.create(_env={"LGTM_INDEX_MAVEN_TOOLCHAINS_FILE": str(actions_toolchains_file)}) + codeql.database.create( + _env={ + "LGTM_INDEX_MAVEN_TOOLCHAINS_FILE": str(actions_toolchains_file), + "LGTM_INDEX_MAVEN_SETTINGS_FILE": os.path.join(os.path.dirname(os.path.realpath(__file__)), "settings.xml"), + } + ) diff --git a/java/ql/integration-tests/java/maven-multimodule-test-java-version/settings.xml b/java/ql/integration-tests/java/maven-multimodule-test-java-version/settings.xml new file mode 100644 index 00000000000..a40670670a6 --- /dev/null +++ b/java/ql/integration-tests/java/maven-multimodule-test-java-version/settings.xml @@ -0,0 +1,10 @@ + + + + google-maven-central + GCS Maven Central mirror + https://maven-central.storage-download.googleapis.com/maven2/ + central + + + diff --git a/java/ql/integration-tests/java/maven-multimodule-test-java-version/source_archive.expected b/java/ql/integration-tests/java/maven-multimodule-test-java-version/source_archive.expected index 08385ca91a0..a83b2775f38 100644 --- a/java/ql/integration-tests/java/maven-multimodule-test-java-version/source_archive.expected +++ b/java/ql/integration-tests/java/maven-multimodule-test-java-version/source_archive.expected @@ -2,6 +2,7 @@ main-module/pom.xml main-module/src/main/java/com/example/App.java main-module/target/maven-archiver/pom.properties pom.xml +settings.xml test-module/pom.xml test-module/src/main/java/com/example/tests/TestUtils.java test-module/target/maven-archiver/pom.properties diff --git a/java/ql/integration-tests/java/maven-sample-extract-properties/settings.xml b/java/ql/integration-tests/java/maven-sample-extract-properties/settings.xml new file mode 100644 index 00000000000..a40670670a6 --- /dev/null +++ b/java/ql/integration-tests/java/maven-sample-extract-properties/settings.xml @@ -0,0 +1,10 @@ + + + + google-maven-central + GCS Maven Central mirror + https://maven-central.storage-download.googleapis.com/maven2/ + central + + + diff --git a/java/ql/integration-tests/java/maven-sample-extract-properties/source_archive.expected b/java/ql/integration-tests/java/maven-sample-extract-properties/source_archive.expected index 59a81a01481..d86dae4531f 100644 --- a/java/ql/integration-tests/java/maven-sample-extract-properties/source_archive.expected +++ b/java/ql/integration-tests/java/maven-sample-extract-properties/source_archive.expected @@ -1,4 +1,5 @@ pom.xml +settings.xml src/main/java/com/example/App.java src/main/resources/my-app.properties src/main/resources/page.xml diff --git a/java/ql/integration-tests/java/maven-sample-extract-properties/test.py b/java/ql/integration-tests/java/maven-sample-extract-properties/test.py index a12444ef170..a6b6cad52d3 100644 --- a/java/ql/integration-tests/java/maven-sample-extract-properties/test.py +++ b/java/ql/integration-tests/java/maven-sample-extract-properties/test.py @@ -1,2 +1,8 @@ +import os + def test(codeql, java): - codeql.database.create(_env={"LGTM_INDEX_PROPERTIES_FILES": "true"}) + codeql.database.create( + _env={ + "LGTM_INDEX_PROPERTIES_FILES": "true", + "LGTM_INDEX_MAVEN_SETTINGS_FILE": os.path.join(os.path.dirname(os.path.realpath(__file__)), "settings.xml") + }) diff --git a/java/ql/integration-tests/java/maven-sample-large-xml-files/settings.xml b/java/ql/integration-tests/java/maven-sample-large-xml-files/settings.xml new file mode 100644 index 00000000000..a40670670a6 --- /dev/null +++ b/java/ql/integration-tests/java/maven-sample-large-xml-files/settings.xml @@ -0,0 +1,10 @@ + + + + google-maven-central + GCS Maven Central mirror + https://maven-central.storage-download.googleapis.com/maven2/ + central + + + diff --git a/java/ql/integration-tests/java/maven-sample-large-xml-files/test.py b/java/ql/integration-tests/java/maven-sample-large-xml-files/test.py index 08a582b9d42..ff1cc6faad4 100644 --- a/java/ql/integration-tests/java/maven-sample-large-xml-files/test.py +++ b/java/ql/integration-tests/java/maven-sample-large-xml-files/test.py @@ -1,6 +1,12 @@ +import os + def test(codeql, java): # Test that a build with 60 ~1MB XML docs extracts does not extract them, but we fall back to by-name mode instead: for i in range(60): with open(f"generated-{i}.xml", "w") as f: f.write("" + ("a" * 1000000) + "") - codeql.database.create() + codeql.database.create( + _env={ + "LGTM_INDEX_MAVEN_SETTINGS_FILE": os.path.join(os.path.dirname(os.path.realpath(__file__)), "settings.xml") + }, + ) diff --git a/java/ql/integration-tests/java/maven-sample-small-xml-files/settings.xml b/java/ql/integration-tests/java/maven-sample-small-xml-files/settings.xml new file mode 100644 index 00000000000..a40670670a6 --- /dev/null +++ b/java/ql/integration-tests/java/maven-sample-small-xml-files/settings.xml @@ -0,0 +1,10 @@ + + + + google-maven-central + GCS Maven Central mirror + https://maven-central.storage-download.googleapis.com/maven2/ + central + + + diff --git a/java/ql/integration-tests/java/maven-sample-small-xml-files/source_archive.expected b/java/ql/integration-tests/java/maven-sample-small-xml-files/source_archive.expected index 83f376944a7..68569a23577 100644 --- a/java/ql/integration-tests/java/maven-sample-small-xml-files/source_archive.expected +++ b/java/ql/integration-tests/java/maven-sample-small-xml-files/source_archive.expected @@ -4,6 +4,7 @@ generated-2.xml generated-3.xml generated-4.xml pom.xml +settings.xml src/main/java/com/example/App.java src/main/resources/my-app.properties src/main/resources/page.xml diff --git a/java/ql/integration-tests/java/maven-sample-small-xml-files/test.py b/java/ql/integration-tests/java/maven-sample-small-xml-files/test.py index 8795cbbaa09..e7ee32a5443 100644 --- a/java/ql/integration-tests/java/maven-sample-small-xml-files/test.py +++ b/java/ql/integration-tests/java/maven-sample-small-xml-files/test.py @@ -1,6 +1,12 @@ +import os + def test(codeql, java): # Test that a build with 5 ~1MB XML docs extracts them: for i in range(5): with open(f"generated-{i}.xml", "w") as f: f.write("" + ("a" * 1000000) + "") - codeql.database.create() + codeql.database.create( + _env={ + "LGTM_INDEX_MAVEN_SETTINGS_FILE": os.path.join(os.path.dirname(os.path.realpath(__file__)), "settings.xml") + }, + ) diff --git a/java/ql/integration-tests/java/maven-sample-xml-mode-all-gbk-encoding/settings.xml b/java/ql/integration-tests/java/maven-sample-xml-mode-all-gbk-encoding/settings.xml new file mode 100644 index 00000000000..a40670670a6 --- /dev/null +++ b/java/ql/integration-tests/java/maven-sample-xml-mode-all-gbk-encoding/settings.xml @@ -0,0 +1,10 @@ + + + + google-maven-central + GCS Maven Central mirror + https://maven-central.storage-download.googleapis.com/maven2/ + central + + + diff --git a/java/ql/integration-tests/java/maven-sample-xml-mode-all-gbk-encoding/source_archive.expected b/java/ql/integration-tests/java/maven-sample-xml-mode-all-gbk-encoding/source_archive.expected index 535084ac188..04218439bf1 100644 --- a/java/ql/integration-tests/java/maven-sample-xml-mode-all-gbk-encoding/source_archive.expected +++ b/java/ql/integration-tests/java/maven-sample-xml-mode-all-gbk-encoding/source_archive.expected @@ -1,4 +1,5 @@ pom.xml +settings.xml src/main/java/com/example/App.java src/main/resources/my-app.properties src/main/resources/page.xml diff --git a/java/ql/integration-tests/java/maven-sample-xml-mode-all-gbk-encoding/test.py b/java/ql/integration-tests/java/maven-sample-xml-mode-all-gbk-encoding/test.py index 93ac0300499..3ee198cfd67 100644 --- a/java/ql/integration-tests/java/maven-sample-xml-mode-all-gbk-encoding/test.py +++ b/java/ql/integration-tests/java/maven-sample-xml-mode-all-gbk-encoding/test.py @@ -1,2 +1,9 @@ +import os + def test(codeql, java): - codeql.database.create(_env={"LGTM_INDEX_XML_MODE": "all"}) + codeql.database.create( + _env={ + "LGTM_INDEX_XML_MODE": "all", + "LGTM_INDEX_MAVEN_SETTINGS_FILE": os.path.join(os.path.dirname(os.path.realpath(__file__)), "settings.xml"), + }, + ) diff --git a/java/ql/integration-tests/java/maven-sample-xml-mode-all/settings.xml b/java/ql/integration-tests/java/maven-sample-xml-mode-all/settings.xml new file mode 100644 index 00000000000..a40670670a6 --- /dev/null +++ b/java/ql/integration-tests/java/maven-sample-xml-mode-all/settings.xml @@ -0,0 +1,10 @@ + + + + google-maven-central + GCS Maven Central mirror + https://maven-central.storage-download.googleapis.com/maven2/ + central + + + diff --git a/java/ql/integration-tests/java/maven-sample-xml-mode-all/source_archive.expected b/java/ql/integration-tests/java/maven-sample-xml-mode-all/source_archive.expected index 59a81a01481..d86dae4531f 100644 --- a/java/ql/integration-tests/java/maven-sample-xml-mode-all/source_archive.expected +++ b/java/ql/integration-tests/java/maven-sample-xml-mode-all/source_archive.expected @@ -1,4 +1,5 @@ pom.xml +settings.xml src/main/java/com/example/App.java src/main/resources/my-app.properties src/main/resources/page.xml diff --git a/java/ql/integration-tests/java/maven-sample-xml-mode-all/test.py b/java/ql/integration-tests/java/maven-sample-xml-mode-all/test.py index 93ac0300499..5eeece7c91b 100644 --- a/java/ql/integration-tests/java/maven-sample-xml-mode-all/test.py +++ b/java/ql/integration-tests/java/maven-sample-xml-mode-all/test.py @@ -1,2 +1,9 @@ +import os + def test(codeql, java): - codeql.database.create(_env={"LGTM_INDEX_XML_MODE": "all"}) + codeql.database.create( + _env={ + "LGTM_INDEX_XML_MODE": "all", + "LGTM_INDEX_MAVEN_SETTINGS_FILE": os.path.join(os.path.dirname(os.path.realpath(__file__)), "settings.xml") + }, + ) diff --git a/java/ql/integration-tests/java/maven-sample-xml-mode-byname/settings.xml b/java/ql/integration-tests/java/maven-sample-xml-mode-byname/settings.xml new file mode 100644 index 00000000000..a40670670a6 --- /dev/null +++ b/java/ql/integration-tests/java/maven-sample-xml-mode-byname/settings.xml @@ -0,0 +1,10 @@ + + + + google-maven-central + GCS Maven Central mirror + https://maven-central.storage-download.googleapis.com/maven2/ + central + + + diff --git a/java/ql/integration-tests/java/maven-sample-xml-mode-byname/test.py b/java/ql/integration-tests/java/maven-sample-xml-mode-byname/test.py index 64e5f7ba05a..f5123e4a245 100644 --- a/java/ql/integration-tests/java/maven-sample-xml-mode-byname/test.py +++ b/java/ql/integration-tests/java/maven-sample-xml-mode-byname/test.py @@ -1,2 +1,9 @@ +import os + def test(codeql, java): - codeql.database.create(_env={"LGTM_INDEX_XML_MODE": "byname"}) + codeql.database.create( + _env={ + "LGTM_INDEX_XML_MODE": "byname", + "LGTM_INDEX_MAVEN_SETTINGS_FILE": os.path.join(os.path.dirname(os.path.realpath(__file__)), "settings.xml"), + }, + ) diff --git a/java/ql/integration-tests/java/maven-sample-xml-mode-disabled/settings.xml b/java/ql/integration-tests/java/maven-sample-xml-mode-disabled/settings.xml new file mode 100644 index 00000000000..a40670670a6 --- /dev/null +++ b/java/ql/integration-tests/java/maven-sample-xml-mode-disabled/settings.xml @@ -0,0 +1,10 @@ + + + + google-maven-central + GCS Maven Central mirror + https://maven-central.storage-download.googleapis.com/maven2/ + central + + + diff --git a/java/ql/integration-tests/java/maven-sample-xml-mode-disabled/test.py b/java/ql/integration-tests/java/maven-sample-xml-mode-disabled/test.py index aa6c911f94d..8039a1d5c9f 100644 --- a/java/ql/integration-tests/java/maven-sample-xml-mode-disabled/test.py +++ b/java/ql/integration-tests/java/maven-sample-xml-mode-disabled/test.py @@ -1,2 +1,9 @@ +import os + def test(codeql, java): - codeql.database.create(_env={"LGTM_INDEX_XML_MODE": "disabled"}) + codeql.database.create( + _env={ + "LGTM_INDEX_XML_MODE": "disabled", + "LGTM_INDEX_MAVEN_SETTINGS_FILE": os.path.join(os.path.dirname(os.path.realpath(__file__)), "settings.xml"), + }, + ) diff --git a/java/ql/integration-tests/java/maven-sample-xml-mode-smart/settings.xml b/java/ql/integration-tests/java/maven-sample-xml-mode-smart/settings.xml new file mode 100644 index 00000000000..a40670670a6 --- /dev/null +++ b/java/ql/integration-tests/java/maven-sample-xml-mode-smart/settings.xml @@ -0,0 +1,10 @@ + + + + google-maven-central + GCS Maven Central mirror + https://maven-central.storage-download.googleapis.com/maven2/ + central + + + diff --git a/java/ql/integration-tests/java/maven-sample-xml-mode-smart/test.py b/java/ql/integration-tests/java/maven-sample-xml-mode-smart/test.py index 7736927eb8a..59d649ad707 100644 --- a/java/ql/integration-tests/java/maven-sample-xml-mode-smart/test.py +++ b/java/ql/integration-tests/java/maven-sample-xml-mode-smart/test.py @@ -1,2 +1,9 @@ +import os + def test(codeql, java): - codeql.database.create(_env={"LGTM_INDEX_XML_MODE": "smart"}) + codeql.database.create( + _env={ + "LGTM_INDEX_XML_MODE": "smart", + "LGTM_INDEX_MAVEN_SETTINGS_FILE": os.path.join(os.path.dirname(os.path.realpath(__file__)), "settings.xml"), + }, + ) diff --git a/java/ql/integration-tests/java/maven-sample/settings.xml b/java/ql/integration-tests/java/maven-sample/settings.xml new file mode 100644 index 00000000000..a40670670a6 --- /dev/null +++ b/java/ql/integration-tests/java/maven-sample/settings.xml @@ -0,0 +1,10 @@ + + + + google-maven-central + GCS Maven Central mirror + https://maven-central.storage-download.googleapis.com/maven2/ + central + + + diff --git a/java/ql/integration-tests/java/maven-sample/source_archive.expected b/java/ql/integration-tests/java/maven-sample/source_archive.expected index 59a81a01481..d86dae4531f 100644 --- a/java/ql/integration-tests/java/maven-sample/source_archive.expected +++ b/java/ql/integration-tests/java/maven-sample/source_archive.expected @@ -1,4 +1,5 @@ pom.xml +settings.xml src/main/java/com/example/App.java src/main/resources/my-app.properties src/main/resources/page.xml diff --git a/java/ql/integration-tests/java/maven-sample/test.py b/java/ql/integration-tests/java/maven-sample/test.py index eb49efe6a2a..14d7fc40b8f 100644 --- a/java/ql/integration-tests/java/maven-sample/test.py +++ b/java/ql/integration-tests/java/maven-sample/test.py @@ -1,2 +1,8 @@ +import os + def test(codeql, java): - codeql.database.create() + codeql.database.create( + _env={ + "LGTM_INDEX_MAVEN_SETTINGS_FILE": os.path.join(os.path.dirname(os.path.realpath(__file__)), "settings.xml") + }, + ) diff --git a/java/ql/integration-tests/java/maven-wrapper-missing-properties/settings.xml b/java/ql/integration-tests/java/maven-wrapper-missing-properties/settings.xml new file mode 100644 index 00000000000..a40670670a6 --- /dev/null +++ b/java/ql/integration-tests/java/maven-wrapper-missing-properties/settings.xml @@ -0,0 +1,10 @@ + + + + google-maven-central + GCS Maven Central mirror + https://maven-central.storage-download.googleapis.com/maven2/ + central + + + diff --git a/java/ql/integration-tests/java/maven-wrapper-missing-properties/source_archive.expected b/java/ql/integration-tests/java/maven-wrapper-missing-properties/source_archive.expected index 6ea990c4d1b..e2e6f04afd5 100644 --- a/java/ql/integration-tests/java/maven-wrapper-missing-properties/source_archive.expected +++ b/java/ql/integration-tests/java/maven-wrapper-missing-properties/source_archive.expected @@ -1,4 +1,5 @@ .mvn/wrapper/maven-wrapper.properties pom.xml +settings.xml src/main/java/com/example/Hello.java target/maven-archiver/pom.properties diff --git a/java/ql/integration-tests/java/maven-wrapper-missing-properties/test.py b/java/ql/integration-tests/java/maven-wrapper-missing-properties/test.py index ef93712d879..9d08d3360d0 100644 --- a/java/ql/integration-tests/java/maven-wrapper-missing-properties/test.py +++ b/java/ql/integration-tests/java/maven-wrapper-missing-properties/test.py @@ -1,2 +1,9 @@ +import os + def test(codeql, java): - codeql.database.create(build_mode="autobuild") + codeql.database.create( + build_mode="autobuild", + _env={ + "LGTM_INDEX_MAVEN_SETTINGS_FILE": os.path.join(os.path.dirname(os.path.realpath(__file__)), "settings.xml"), + }, + ) diff --git a/java/ql/integration-tests/java/maven-wrapper-script-only/settings.xml b/java/ql/integration-tests/java/maven-wrapper-script-only/settings.xml new file mode 100644 index 00000000000..a40670670a6 --- /dev/null +++ b/java/ql/integration-tests/java/maven-wrapper-script-only/settings.xml @@ -0,0 +1,10 @@ + + + + google-maven-central + GCS Maven Central mirror + https://maven-central.storage-download.googleapis.com/maven2/ + central + + + diff --git a/java/ql/integration-tests/java/maven-wrapper-script-only/source_archive.expected b/java/ql/integration-tests/java/maven-wrapper-script-only/source_archive.expected index 1e05b6ef3ee..df2451d695c 100644 --- a/java/ql/integration-tests/java/maven-wrapper-script-only/source_archive.expected +++ b/java/ql/integration-tests/java/maven-wrapper-script-only/source_archive.expected @@ -1,5 +1,6 @@ .mvn/wrapper/maven-wrapper.properties pom.xml +settings.xml src/main/java/com/example/App.java src/main/resources/my-app.properties src/main/resources/page.xml diff --git a/java/ql/integration-tests/java/maven-wrapper-script-only/test.py b/java/ql/integration-tests/java/maven-wrapper-script-only/test.py index eb49efe6a2a..a71c8821d5e 100644 --- a/java/ql/integration-tests/java/maven-wrapper-script-only/test.py +++ b/java/ql/integration-tests/java/maven-wrapper-script-only/test.py @@ -1,2 +1,8 @@ +import os + def test(codeql, java): - codeql.database.create() + codeql.database.create( + _env={ + "LGTM_INDEX_MAVEN_SETTINGS_FILE": os.path.join(os.path.dirname(os.path.realpath(__file__)), "settings.xml"), + }, + ) diff --git a/java/ql/integration-tests/java/maven-wrapper-source-only/settings.xml b/java/ql/integration-tests/java/maven-wrapper-source-only/settings.xml new file mode 100644 index 00000000000..a40670670a6 --- /dev/null +++ b/java/ql/integration-tests/java/maven-wrapper-source-only/settings.xml @@ -0,0 +1,10 @@ + + + + google-maven-central + GCS Maven Central mirror + https://maven-central.storage-download.googleapis.com/maven2/ + central + + + diff --git a/java/ql/integration-tests/java/maven-wrapper-source-only/source_archive.expected b/java/ql/integration-tests/java/maven-wrapper-source-only/source_archive.expected index 1e05b6ef3ee..df2451d695c 100644 --- a/java/ql/integration-tests/java/maven-wrapper-source-only/source_archive.expected +++ b/java/ql/integration-tests/java/maven-wrapper-source-only/source_archive.expected @@ -1,5 +1,6 @@ .mvn/wrapper/maven-wrapper.properties pom.xml +settings.xml src/main/java/com/example/App.java src/main/resources/my-app.properties src/main/resources/page.xml diff --git a/java/ql/integration-tests/java/maven-wrapper-source-only/test.py b/java/ql/integration-tests/java/maven-wrapper-source-only/test.py index eb49efe6a2a..a71c8821d5e 100644 --- a/java/ql/integration-tests/java/maven-wrapper-source-only/test.py +++ b/java/ql/integration-tests/java/maven-wrapper-source-only/test.py @@ -1,2 +1,8 @@ +import os + def test(codeql, java): - codeql.database.create() + codeql.database.create( + _env={ + "LGTM_INDEX_MAVEN_SETTINGS_FILE": os.path.join(os.path.dirname(os.path.realpath(__file__)), "settings.xml"), + }, + ) diff --git a/java/ql/integration-tests/java/maven-wrapper/settings.xml b/java/ql/integration-tests/java/maven-wrapper/settings.xml new file mode 100644 index 00000000000..a40670670a6 --- /dev/null +++ b/java/ql/integration-tests/java/maven-wrapper/settings.xml @@ -0,0 +1,10 @@ + + + + google-maven-central + GCS Maven Central mirror + https://maven-central.storage-download.googleapis.com/maven2/ + central + + + diff --git a/java/ql/integration-tests/java/maven-wrapper/source_archive.expected b/java/ql/integration-tests/java/maven-wrapper/source_archive.expected index 1e05b6ef3ee..df2451d695c 100644 --- a/java/ql/integration-tests/java/maven-wrapper/source_archive.expected +++ b/java/ql/integration-tests/java/maven-wrapper/source_archive.expected @@ -1,5 +1,6 @@ .mvn/wrapper/maven-wrapper.properties pom.xml +settings.xml src/main/java/com/example/App.java src/main/resources/my-app.properties src/main/resources/page.xml diff --git a/java/ql/integration-tests/java/maven-wrapper/test.py b/java/ql/integration-tests/java/maven-wrapper/test.py index eb49efe6a2a..a71c8821d5e 100644 --- a/java/ql/integration-tests/java/maven-wrapper/test.py +++ b/java/ql/integration-tests/java/maven-wrapper/test.py @@ -1,2 +1,8 @@ +import os + def test(codeql, java): - codeql.database.create() + codeql.database.create( + _env={ + "LGTM_INDEX_MAVEN_SETTINGS_FILE": os.path.join(os.path.dirname(os.path.realpath(__file__)), "settings.xml"), + }, + ) diff --git a/java/ql/integration-tests/java/partial-gradle-sample-without-gradle/build.gradle b/java/ql/integration-tests/java/partial-gradle-sample-without-gradle/build.gradle index 071a12b7691..0fc1d500219 100644 --- a/java/ql/integration-tests/java/partial-gradle-sample-without-gradle/build.gradle +++ b/java/ql/integration-tests/java/partial-gradle-sample-without-gradle/build.gradle @@ -12,9 +12,9 @@ apply plugin: 'java' // In this section you declare where to find the dependencies of your project repositories { - // Use 'jcenter' for resolving your dependencies. - // You can declare any Maven/Ivy/file repository here. - jcenter() + maven { + url = 'https://maven-central.storage-download.googleapis.com/maven2/' + } } // In this section you declare the dependencies for your production and test code diff --git a/java/ql/integration-tests/java/partial-gradle-sample/build.gradle b/java/ql/integration-tests/java/partial-gradle-sample/build.gradle index 071a12b7691..0fc1d500219 100644 --- a/java/ql/integration-tests/java/partial-gradle-sample/build.gradle +++ b/java/ql/integration-tests/java/partial-gradle-sample/build.gradle @@ -12,9 +12,9 @@ apply plugin: 'java' // In this section you declare where to find the dependencies of your project repositories { - // Use 'jcenter' for resolving your dependencies. - // You can declare any Maven/Ivy/file repository here. - jcenter() + maven { + url = 'https://maven-central.storage-download.googleapis.com/maven2/' + } } // In this section you declare the dependencies for your production and test code diff --git a/java/ql/integration-tests/java/spring-boot-sample/build.gradle b/java/ql/integration-tests/java/spring-boot-sample/build.gradle index 6c918f95048..3a810b7ae15 100644 --- a/java/ql/integration-tests/java/spring-boot-sample/build.gradle +++ b/java/ql/integration-tests/java/spring-boot-sample/build.gradle @@ -11,7 +11,9 @@ version = '0.0.1-SNAPSHOT' // but I omit it to test we recognise the Spring Boot plugin version. repositories { - mavenCentral() + maven { + url = 'https://maven-central.storage-download.googleapis.com/maven2/' + } } dependencies { diff --git a/java/ql/integration-tests/kotlin/all-platforms/compiler_arguments/app/build.gradle b/java/ql/integration-tests/kotlin/all-platforms/compiler_arguments/app/build.gradle index 8b91012467e..aee3a05f24a 100644 --- a/java/ql/integration-tests/kotlin/all-platforms/compiler_arguments/app/build.gradle +++ b/java/ql/integration-tests/kotlin/all-platforms/compiler_arguments/app/build.gradle @@ -15,8 +15,9 @@ plugins { } repositories { - // Use Maven Central for resolving dependencies. - mavenCentral() + maven { + url = 'https://maven-central.storage-download.googleapis.com/maven2/' + } } application { diff --git a/java/ql/integration-tests/kotlin/all-platforms/diagnostics/kotlin-version-too-new/diagnostics.expected b/java/ql/integration-tests/kotlin/all-platforms/diagnostics/kotlin-version-too-new/diagnostics.expected index 2720daff0b2..33ef093cb9a 100644 --- a/java/ql/integration-tests/kotlin/all-platforms/diagnostics/kotlin-version-too-new/diagnostics.expected +++ b/java/ql/integration-tests/kotlin/all-platforms/diagnostics/kotlin-version-too-new/diagnostics.expected @@ -1,5 +1,5 @@ { - "markdownMessage": "The Kotlin version installed (`999.999.999`) is too recent for this version of CodeQL. Install a version lower than 2.3.30.", + "markdownMessage": "The Kotlin version installed (`999.999.999`) is too recent for this version of CodeQL. Install a version lower than 2.4.10.", "severity": "error", "source": { "extractorName": "java", diff --git a/java/ql/integration-tests/kotlin/all-platforms/enhanced-nullability/test.py b/java/ql/integration-tests/kotlin/all-platforms/enhanced-nullability/test.py index e030b51db8f..e6aa92cfc29 100644 --- a/java/ql/integration-tests/kotlin/all-platforms/enhanced-nullability/test.py +++ b/java/ql/integration-tests/kotlin/all-platforms/enhanced-nullability/test.py @@ -1,7 +1,7 @@ import pathlib -def test(codeql, java_full): +def test(codeql, java_full, kotlinc_2_3_20): java_srcs = " ".join([str(s) for s in pathlib.Path().glob("*.java")]) codeql.database.create( command=[ diff --git a/java/ql/integration-tests/kotlin/all-platforms/external-property-overloads/test.py b/java/ql/integration-tests/kotlin/all-platforms/external-property-overloads/test.py index 403f3729d06..d21c0541cf4 100644 --- a/java/ql/integration-tests/kotlin/all-platforms/external-property-overloads/test.py +++ b/java/ql/integration-tests/kotlin/all-platforms/external-property-overloads/test.py @@ -1,6 +1,6 @@ import commands -def test(codeql, java_full): +def test(codeql, java_full, kotlinc_2_3_20): commands.run("kotlinc -language-version 1.9 test.kt -d lib") codeql.database.create(command="kotlinc -language-version 1.9 user.kt -cp lib") diff --git a/java/ql/integration-tests/kotlin/all-platforms/extractor_information_kotlin1/test.py b/java/ql/integration-tests/kotlin/all-platforms/extractor_information_kotlin1/test.py index 5a0dc9e072b..eea3fcbf549 100755 --- a/java/ql/integration-tests/kotlin/all-platforms/extractor_information_kotlin1/test.py +++ b/java/ql/integration-tests/kotlin/all-platforms/extractor_information_kotlin1/test.py @@ -1,2 +1,2 @@ -def test(codeql, java_full): - codeql.database.create(command="kotlinc -J-Xmx2G -language-version 1.9 SomeClass.kt") +def test(codeql, java_full, kotlinc_2_3_20): + codeql.database.create(command=f"kotlinc -J-Xmx2G -language-version 1.9 SomeClass.kt") diff --git a/java/ql/integration-tests/kotlin/all-platforms/file_classes/test.py b/java/ql/integration-tests/kotlin/all-platforms/file_classes/test.py index 99c21ceb0b8..baf7556962d 100644 --- a/java/ql/integration-tests/kotlin/all-platforms/file_classes/test.py +++ b/java/ql/integration-tests/kotlin/all-platforms/file_classes/test.py @@ -1,6 +1,6 @@ import commands -def test(codeql, java_full): +def test(codeql, java_full, kotlinc_2_3_20): commands.run("kotlinc -language-version 1.9 A.kt") codeql.database.create(command="kotlinc -cp . -language-version 1.9 B.kt C.kt") diff --git a/java/ql/integration-tests/kotlin/all-platforms/gradle_groovy_app/app/build.gradle b/java/ql/integration-tests/kotlin/all-platforms/gradle_groovy_app/app/build.gradle index 8b91012467e..aee3a05f24a 100644 --- a/java/ql/integration-tests/kotlin/all-platforms/gradle_groovy_app/app/build.gradle +++ b/java/ql/integration-tests/kotlin/all-platforms/gradle_groovy_app/app/build.gradle @@ -15,8 +15,9 @@ plugins { } repositories { - // Use Maven Central for resolving dependencies. - mavenCentral() + maven { + url = 'https://maven-central.storage-download.googleapis.com/maven2/' + } } application { diff --git a/java/ql/integration-tests/kotlin/all-platforms/gradle_kotlinx_serialization/app/build.gradle b/java/ql/integration-tests/kotlin/all-platforms/gradle_kotlinx_serialization/app/build.gradle index 2b13663941d..554228cffad 100644 --- a/java/ql/integration-tests/kotlin/all-platforms/gradle_kotlinx_serialization/app/build.gradle +++ b/java/ql/integration-tests/kotlin/all-platforms/gradle_kotlinx_serialization/app/build.gradle @@ -4,7 +4,9 @@ plugins { } repositories { - mavenCentral() + maven { + url = 'https://maven-central.storage-download.googleapis.com/maven2/' + } } dependencies { diff --git a/java/ql/integration-tests/kotlin/all-platforms/java-interface-redeclares-tostring/test.py b/java/ql/integration-tests/kotlin/all-platforms/java-interface-redeclares-tostring/test.py index 3db804c83be..57b0b660561 100644 --- a/java/ql/integration-tests/kotlin/all-platforms/java-interface-redeclares-tostring/test.py +++ b/java/ql/integration-tests/kotlin/all-platforms/java-interface-redeclares-tostring/test.py @@ -1,6 +1,6 @@ import commands -def test(codeql, java_full): +def test(codeql, java_full, kotlinc_2_3_20): commands.run(["javac", "Test.java", "-d", "bin"]) codeql.database.create(command="kotlinc -language-version 1.9 user.kt -cp bin") diff --git a/java/ql/integration-tests/kotlin/all-platforms/kotlin_java_lowering_wildcards/test.py b/java/ql/integration-tests/kotlin/all-platforms/kotlin_java_lowering_wildcards/test.py index d1c4948dfe7..6346892aaa7 100644 --- a/java/ql/integration-tests/kotlin/all-platforms/kotlin_java_lowering_wildcards/test.py +++ b/java/ql/integration-tests/kotlin/all-platforms/kotlin_java_lowering_wildcards/test.py @@ -1,7 +1,7 @@ import commands -def test(codeql, java_full): +def test(codeql, java_full, kotlinc_2_3_20): # Compile the JavaDefns2 copy outside tracing, to make sure the Kotlin view of it matches the Java view seen by the traced javac compilation of JavaDefns.java below. commands.run(["javac", "JavaDefns2.java"]) codeql.database.create( diff --git a/java/ql/integration-tests/kotlin/all-platforms/kotlin_kfunction/app/build.gradle b/java/ql/integration-tests/kotlin/all-platforms/kotlin_kfunction/app/build.gradle index 8b91012467e..aee3a05f24a 100644 --- a/java/ql/integration-tests/kotlin/all-platforms/kotlin_kfunction/app/build.gradle +++ b/java/ql/integration-tests/kotlin/all-platforms/kotlin_kfunction/app/build.gradle @@ -15,8 +15,9 @@ plugins { } repositories { - // Use Maven Central for resolving dependencies. - mavenCentral() + maven { + url = 'https://maven-central.storage-download.googleapis.com/maven2/' + } } application { diff --git a/java/ql/integration-tests/update-ferstl-depgraph-dependencies.sh b/java/ql/integration-tests/update-ferstl-depgraph-dependencies.sh index 19d8167be74..d8093a48b17 100755 --- a/java/ql/integration-tests/update-ferstl-depgraph-dependencies.sh +++ b/java/ql/integration-tests/update-ferstl-depgraph-dependencies.sh @@ -35,7 +35,7 @@ JACKSON_VERSION="${1:-2.18.6}" GUAVA_VERSION="${2:-33.4.0-jre}" PLUGIN_UPSTREAM_VERSION="4.0.3" -PLUGIN_CODEQL_VERSION="${PLUGIN_UPSTREAM_VERSION}-CodeQL-2" +PLUGIN_CODEQL_VERSION="${PLUGIN_UPSTREAM_VERSION}-CodeQL-3" UPSTREAM_TAG="depgraph-maven-plugin-${PLUGIN_UPSTREAM_VERSION}" UPSTREAM_REPO="https://github.com/ferstl/depgraph-maven-plugin.git" @@ -76,9 +76,19 @@ pom_path, old_version, new_version, new_guava, new_jackson = sys.argv[1:] with open(pom_path) as f: content = f.read() -# 1. Version suffix: 4.0.3 -> 4.0.3-CodeQL-2 (first occurrence only — the element) +# 1. Version suffix: 4.0.3 -> 4.0.3-CodeQL-3 (first occurrence only — the element) content = content.replace(f'{old_version}', f'{new_version}', 1) +# 1b. Pin patched plexus-utils / commons-lang3 (transitive via maven-core) to +# clear CVEs in the vendored bundle. Inserted into . +content = content.replace( + ' import\n \n \n ', + ' import\n \n' + ' \n org.codehaus.plexus\n plexus-utils\n 3.6.1\n \n' + ' \n org.apache.commons\n commons-lang3\n 3.18.0\n \n' + ' \n ', + 1) + # 2. Guava content = content.replace('31.1-jre', f'{new_guava}') diff --git a/java/ql/lib/CHANGELOG.md b/java/ql/lib/CHANGELOG.md index 2e702064d7f..9a60d9f070e 100644 --- a/java/ql/lib/CHANGELOG.md +++ b/java/ql/lib/CHANGELOG.md @@ -1,3 +1,13 @@ +## 9.2.0 + +### New Features + +* Kotlin 2.4.0 can now be analysed. + +### Minor Analysis Improvements + +* Improved modeling of Apache HttpClient `execute` method sinks for `java/ssrf` and `java/non-https-url`. + ## 9.1.2 ### Minor Analysis Improvements diff --git a/java/ql/lib/change-notes/2026-05-07-apache-httpclient-ssrf-sinks.md b/java/ql/lib/change-notes/released/9.2.0.md similarity index 51% rename from java/ql/lib/change-notes/2026-05-07-apache-httpclient-ssrf-sinks.md rename to java/ql/lib/change-notes/released/9.2.0.md index d51f4897486..3df26b56dca 100644 --- a/java/ql/lib/change-notes/2026-05-07-apache-httpclient-ssrf-sinks.md +++ b/java/ql/lib/change-notes/released/9.2.0.md @@ -1,4 +1,9 @@ ---- -category: minorAnalysis ---- +## 9.2.0 + +### New Features + +* Kotlin 2.4.0 can now be analysed. + +### Minor Analysis Improvements + * Improved modeling of Apache HttpClient `execute` method sinks for `java/ssrf` and `java/non-https-url`. diff --git a/java/ql/lib/codeql-pack.release.yml b/java/ql/lib/codeql-pack.release.yml index 1fd7d868f4e..8bc32f3e62a 100644 --- a/java/ql/lib/codeql-pack.release.yml +++ b/java/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 9.1.2 +lastReleaseVersion: 9.2.0 diff --git a/java/ql/lib/qlpack.yml b/java/ql/lib/qlpack.yml index 18948bf45f5..a847cb88c63 100644 --- a/java/ql/lib/qlpack.yml +++ b/java/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/java-all -version: 9.1.3-dev +version: 9.2.1-dev groups: java dbscheme: config/semmlecode.dbscheme extractor: java diff --git a/java/ql/lib/semmle/code/java/ControlFlowGraph.qll b/java/ql/lib/semmle/code/java/ControlFlowGraph.qll index 51f3046e1bf..7390be9cb3c 100644 --- a/java/ql/lib/semmle/code/java/ControlFlowGraph.qll +++ b/java/ql/lib/semmle/code/java/ControlFlowGraph.qll @@ -61,6 +61,8 @@ private module Ast implements AstSig { class Parameter extends AstNode { Parameter() { none() } + AstNode getPattern() { none() } + Expr getDefaultValue() { none() } } @@ -136,7 +138,9 @@ private module Ast implements AstSig { final private class FinalCatchClause = J::CatchClause; class CatchClause extends FinalCatchClause { - AstNode getVariable() { result = super.getVariable() } + AstNode getPattern() { result = super.getVariable() } + + AstNode getVariable() { none() } Expr getCondition() { none() } diff --git a/java/ql/src/CHANGELOG.md b/java/ql/src/CHANGELOG.md index e013e79ce9e..4e7c1a329c2 100644 --- a/java/ql/src/CHANGELOG.md +++ b/java/ql/src/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.11.5 + +No user-facing changes. + ## 1.11.4 No user-facing changes. diff --git a/java/ql/src/change-notes/released/1.11.5.md b/java/ql/src/change-notes/released/1.11.5.md new file mode 100644 index 00000000000..bc8ea1d7829 --- /dev/null +++ b/java/ql/src/change-notes/released/1.11.5.md @@ -0,0 +1,3 @@ +## 1.11.5 + +No user-facing changes. diff --git a/java/ql/src/codeql-pack.release.yml b/java/ql/src/codeql-pack.release.yml index 813a925461f..d3dd29373b1 100644 --- a/java/ql/src/codeql-pack.release.yml +++ b/java/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.11.4 +lastReleaseVersion: 1.11.5 diff --git a/java/ql/src/qlpack.yml b/java/ql/src/qlpack.yml index ac519484225..6f9c819f109 100644 --- a/java/ql/src/qlpack.yml +++ b/java/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/java-queries -version: 1.11.5-dev +version: 1.11.6-dev groups: - java - queries diff --git a/java/ql/test-kotlin1/library-tests/controlflow/basic/bbStmts.expected b/java/ql/test-kotlin1/library-tests/controlflow/basic/bbStmts.expected index 484fb5ea042..a3c7b11eb21 100644 --- a/java/ql/test-kotlin1/library-tests/controlflow/basic/bbStmts.expected +++ b/java/ql/test-kotlin1/library-tests/controlflow/basic/bbStmts.expected @@ -235,15 +235,16 @@ | Test.kt:84:11:84:18 | After (...)... | 4 | Test.kt:85:3:85:10 | Before return ... | | Test.kt:84:11:84:18 | After (...)... | 5 | Test.kt:85:10:85:10 | 1 | | Test.kt:84:11:84:18 | After (...)... | 6 | Test.kt:85:3:85:10 | return ... | -| Test.kt:86:4:88:2 | After catch (...) [match] | 0 | Test.kt:86:4:88:2 | After catch (...) [match] | -| Test.kt:86:4:88:2 | After catch (...) [match] | 1 | Test.kt:86:11:86:31 | e | -| Test.kt:86:4:88:2 | After catch (...) [match] | 2 | Test.kt:86:34:88:2 | { ... } | -| Test.kt:86:4:88:2 | After catch (...) [match] | 3 | Test.kt:87:3:87:10 | Before return ... | -| Test.kt:86:4:88:2 | After catch (...) [match] | 4 | Test.kt:87:10:87:10 | 2 | -| Test.kt:86:4:88:2 | After catch (...) [match] | 5 | Test.kt:87:3:87:10 | return ... | -| Test.kt:86:4:88:2 | After catch (...) [no-match] | 0 | Test.kt:86:4:88:2 | After catch (...) [no-match] | -| Test.kt:86:4:88:2 | After catch (...) [no-match] | 1 | Test.kt:82:1:89:1 | Exceptional Exit | | Test.kt:86:4:88:2 | catch (...) | 0 | Test.kt:86:4:88:2 | catch (...) | +| Test.kt:86:4:88:2 | catch (...) | 1 | Test.kt:86:11:86:31 | e | +| Test.kt:86:11:86:31 | After e [match] | 0 | Test.kt:86:11:86:31 | After e [match] | +| Test.kt:86:11:86:31 | After e [match] | 1 | Test.kt:86:34:88:2 | { ... } | +| Test.kt:86:11:86:31 | After e [match] | 2 | Test.kt:87:3:87:10 | Before return ... | +| Test.kt:86:11:86:31 | After e [match] | 3 | Test.kt:87:10:87:10 | 2 | +| Test.kt:86:11:86:31 | After e [match] | 4 | Test.kt:87:3:87:10 | return ... | +| Test.kt:86:11:86:31 | After e [no-match] | 0 | Test.kt:86:11:86:31 | After e [no-match] | +| Test.kt:86:11:86:31 | After e [no-match] | 1 | Test.kt:86:4:88:2 | After catch (...) [no-match] | +| Test.kt:86:11:86:31 | After e [no-match] | 2 | Test.kt:82:1:89:1 | Exceptional Exit | | Test.kt:91:1:98:1 | Entry | 0 | Test.kt:91:1:98:1 | Entry | | Test.kt:91:1:98:1 | Entry | 1 | Test.kt:91:22:98:1 | { ... } | | Test.kt:91:1:98:1 | Entry | 2 | Test.kt:92:2:97:2 | try ... | @@ -262,15 +263,16 @@ | Test.kt:93:12:93:13 | After ...!! | 4 | Test.kt:94:3:94:10 | Before return ... | | Test.kt:93:12:93:13 | After ...!! | 5 | Test.kt:94:10:94:10 | 1 | | Test.kt:93:12:93:13 | After ...!! | 6 | Test.kt:94:3:94:10 | return ... | -| Test.kt:95:4:97:2 | After catch (...) [match] | 0 | Test.kt:95:4:97:2 | After catch (...) [match] | -| Test.kt:95:4:97:2 | After catch (...) [match] | 1 | Test.kt:95:11:95:33 | e | -| Test.kt:95:4:97:2 | After catch (...) [match] | 2 | Test.kt:95:36:97:2 | { ... } | -| Test.kt:95:4:97:2 | After catch (...) [match] | 3 | Test.kt:96:3:96:10 | Before return ... | -| Test.kt:95:4:97:2 | After catch (...) [match] | 4 | Test.kt:96:10:96:10 | 2 | -| Test.kt:95:4:97:2 | After catch (...) [match] | 5 | Test.kt:96:3:96:10 | return ... | -| Test.kt:95:4:97:2 | After catch (...) [no-match] | 0 | Test.kt:95:4:97:2 | After catch (...) [no-match] | -| Test.kt:95:4:97:2 | After catch (...) [no-match] | 1 | Test.kt:91:1:98:1 | Exceptional Exit | | Test.kt:95:4:97:2 | catch (...) | 0 | Test.kt:95:4:97:2 | catch (...) | +| Test.kt:95:4:97:2 | catch (...) | 1 | Test.kt:95:11:95:33 | e | +| Test.kt:95:11:95:33 | After e [match] | 0 | Test.kt:95:11:95:33 | After e [match] | +| Test.kt:95:11:95:33 | After e [match] | 1 | Test.kt:95:36:97:2 | { ... } | +| Test.kt:95:11:95:33 | After e [match] | 2 | Test.kt:96:3:96:10 | Before return ... | +| Test.kt:95:11:95:33 | After e [match] | 3 | Test.kt:96:10:96:10 | 2 | +| Test.kt:95:11:95:33 | After e [match] | 4 | Test.kt:96:3:96:10 | return ... | +| Test.kt:95:11:95:33 | After e [no-match] | 0 | Test.kt:95:11:95:33 | After e [no-match] | +| Test.kt:95:11:95:33 | After e [no-match] | 1 | Test.kt:95:4:97:2 | After catch (...) [no-match] | +| Test.kt:95:11:95:33 | After e [no-match] | 2 | Test.kt:91:1:98:1 | Exceptional Exit | | Test.kt:100:1:110:1 | Entry | 0 | Test.kt:100:1:110:1 | Entry | | Test.kt:100:1:110:1 | Entry | 1 | Test.kt:100:25:110:1 | { ... } | | Test.kt:100:1:110:1 | Entry | 2 | Test.kt:101:5:103:5 | ; | diff --git a/java/ql/test-kotlin1/library-tests/controlflow/basic/bbStrictDominance.expected b/java/ql/test-kotlin1/library-tests/controlflow/basic/bbStrictDominance.expected index bac6b722447..4e66ae0cd04 100644 --- a/java/ql/test-kotlin1/library-tests/controlflow/basic/bbStrictDominance.expected +++ b/java/ql/test-kotlin1/library-tests/controlflow/basic/bbStrictDominance.expected @@ -32,17 +32,17 @@ | Test.kt:82:21:89:1 | { ... } | Test.kt:82:1:89:1 | Normal Exit | | Test.kt:82:21:89:1 | { ... } | Test.kt:84:7:84:7 | x | | Test.kt:82:21:89:1 | { ... } | Test.kt:86:4:88:2 | catch (...) | -| Test.kt:82:21:89:1 | { ... } | Test.kt:86:11:86:31 | e | +| Test.kt:82:21:89:1 | { ... } | Test.kt:86:34:88:2 | { ... } | | Test.kt:86:4:88:2 | catch (...) | Test.kt:82:1:89:1 | Exceptional Exit | -| Test.kt:86:4:88:2 | catch (...) | Test.kt:86:11:86:31 | e | +| Test.kt:86:4:88:2 | catch (...) | Test.kt:86:34:88:2 | { ... } | | Test.kt:91:22:98:1 | { ... } | Test.kt:91:1:98:1 | Exceptional Exit | | Test.kt:91:22:98:1 | { ... } | Test.kt:91:1:98:1 | Exit | | Test.kt:91:22:98:1 | { ... } | Test.kt:91:1:98:1 | Normal Exit | | Test.kt:91:22:98:1 | { ... } | Test.kt:93:7:93:7 | x | | Test.kt:91:22:98:1 | { ... } | Test.kt:95:4:97:2 | catch (...) | -| Test.kt:91:22:98:1 | { ... } | Test.kt:95:11:95:33 | e | +| Test.kt:91:22:98:1 | { ... } | Test.kt:95:36:97:2 | { ... } | | Test.kt:95:4:97:2 | catch (...) | Test.kt:91:1:98:1 | Exceptional Exit | -| Test.kt:95:4:97:2 | catch (...) | Test.kt:95:11:95:33 | e | +| Test.kt:95:4:97:2 | catch (...) | Test.kt:95:36:97:2 | { ... } | | Test.kt:100:25:110:1 | { ... } | Test.kt:100:1:110:1 | Exit | | Test.kt:100:25:110:1 | { ... } | Test.kt:100:1:110:1 | Normal Exit | | Test.kt:100:25:110:1 | { ... } | Test.kt:101:22:101:22 | y | diff --git a/java/ql/test-kotlin1/library-tests/controlflow/basic/bbSuccessor.expected b/java/ql/test-kotlin1/library-tests/controlflow/basic/bbSuccessor.expected index 0596f159e22..25b51acefc4 100644 --- a/java/ql/test-kotlin1/library-tests/controlflow/basic/bbSuccessor.expected +++ b/java/ql/test-kotlin1/library-tests/controlflow/basic/bbSuccessor.expected @@ -20,16 +20,16 @@ | Test.kt:82:21:89:1 | { ... } | Test.kt:86:4:88:2 | catch (...) | | Test.kt:84:7:84:7 | x | Test.kt:82:1:89:1 | Normal Exit | | Test.kt:86:4:88:2 | catch (...) | Test.kt:82:1:89:1 | Exceptional Exit | -| Test.kt:86:4:88:2 | catch (...) | Test.kt:86:11:86:31 | e | -| Test.kt:86:11:86:31 | e | Test.kt:82:1:89:1 | Normal Exit | +| Test.kt:86:4:88:2 | catch (...) | Test.kt:86:34:88:2 | { ... } | +| Test.kt:86:34:88:2 | { ... } | Test.kt:82:1:89:1 | Normal Exit | | Test.kt:91:1:98:1 | Exceptional Exit | Test.kt:91:1:98:1 | Exit | | Test.kt:91:1:98:1 | Normal Exit | Test.kt:91:1:98:1 | Exit | | Test.kt:91:22:98:1 | { ... } | Test.kt:93:7:93:7 | x | | Test.kt:91:22:98:1 | { ... } | Test.kt:95:4:97:2 | catch (...) | | Test.kt:93:7:93:7 | x | Test.kt:91:1:98:1 | Normal Exit | | Test.kt:95:4:97:2 | catch (...) | Test.kt:91:1:98:1 | Exceptional Exit | -| Test.kt:95:4:97:2 | catch (...) | Test.kt:95:11:95:33 | e | -| Test.kt:95:11:95:33 | e | Test.kt:91:1:98:1 | Normal Exit | +| Test.kt:95:4:97:2 | catch (...) | Test.kt:95:36:97:2 | { ... } | +| Test.kt:95:36:97:2 | { ... } | Test.kt:91:1:98:1 | Normal Exit | | Test.kt:100:1:110:1 | Normal Exit | Test.kt:100:1:110:1 | Exit | | Test.kt:100:25:110:1 | { ... } | Test.kt:101:9:101:17 | After ... (value equals) ... [false] | | Test.kt:100:25:110:1 | { ... } | Test.kt:101:22:101:22 | y | diff --git a/java/ql/test-kotlin1/library-tests/controlflow/basic/getASuccessor.expected b/java/ql/test-kotlin1/library-tests/controlflow/basic/getASuccessor.expected index 8f9cce28160..291c07f6857 100644 --- a/java/ql/test-kotlin1/library-tests/controlflow/basic/getASuccessor.expected +++ b/java/ql/test-kotlin1/library-tests/controlflow/basic/getASuccessor.expected @@ -136,8 +136,8 @@ | Test.kt:84:11:84:18 | (...)... | CastExpr | Test.kt:86:4:88:2 | catch (...) | CatchClause | | Test.kt:85:3:85:10 | return ... | ReturnStmt | Test.kt:82:1:89:1 | Normal Exit | Method | | Test.kt:85:10:85:10 | 1 | IntegerLiteral | Test.kt:85:3:85:10 | return ... | ReturnStmt | -| Test.kt:86:4:88:2 | catch (...) | CatchClause | Test.kt:82:1:89:1 | Exceptional Exit | Method | | Test.kt:86:4:88:2 | catch (...) | CatchClause | Test.kt:86:11:86:31 | e | LocalVariableDeclExpr | +| Test.kt:86:11:86:31 | e | LocalVariableDeclExpr | Test.kt:82:1:89:1 | Exceptional Exit | Method | | Test.kt:86:11:86:31 | e | LocalVariableDeclExpr | Test.kt:86:34:88:2 | { ... } | BlockStmt | | Test.kt:86:34:88:2 | { ... } | BlockStmt | Test.kt:87:10:87:10 | 2 | IntegerLiteral | | Test.kt:87:3:87:10 | return ... | ReturnStmt | Test.kt:82:1:89:1 | Normal Exit | Method | @@ -155,8 +155,8 @@ | Test.kt:93:12:93:13 | ...!! | NotNullExpr | Test.kt:95:4:97:2 | catch (...) | CatchClause | | Test.kt:94:3:94:10 | return ... | ReturnStmt | Test.kt:91:1:98:1 | Normal Exit | Method | | Test.kt:94:10:94:10 | 1 | IntegerLiteral | Test.kt:94:3:94:10 | return ... | ReturnStmt | -| Test.kt:95:4:97:2 | catch (...) | CatchClause | Test.kt:91:1:98:1 | Exceptional Exit | Method | | Test.kt:95:4:97:2 | catch (...) | CatchClause | Test.kt:95:11:95:33 | e | LocalVariableDeclExpr | +| Test.kt:95:11:95:33 | e | LocalVariableDeclExpr | Test.kt:91:1:98:1 | Exceptional Exit | Method | | Test.kt:95:11:95:33 | e | LocalVariableDeclExpr | Test.kt:95:36:97:2 | { ... } | BlockStmt | | Test.kt:95:36:97:2 | { ... } | BlockStmt | Test.kt:96:10:96:10 | 2 | IntegerLiteral | | Test.kt:96:3:96:10 | return ... | ReturnStmt | Test.kt:91:1:98:1 | Normal Exit | Method | diff --git a/java/ql/test-kotlin2/library-tests/controlflow/basic/bbStmts.expected b/java/ql/test-kotlin2/library-tests/controlflow/basic/bbStmts.expected index 6a1994921f4..429d8f7eb7f 100644 --- a/java/ql/test-kotlin2/library-tests/controlflow/basic/bbStmts.expected +++ b/java/ql/test-kotlin2/library-tests/controlflow/basic/bbStmts.expected @@ -235,15 +235,16 @@ | Test.kt:84:11:84:18 | After (...)... | 4 | Test.kt:85:3:85:10 | Before return ... | | Test.kt:84:11:84:18 | After (...)... | 5 | Test.kt:85:10:85:10 | 1 | | Test.kt:84:11:84:18 | After (...)... | 6 | Test.kt:85:3:85:10 | return ... | -| Test.kt:86:4:88:2 | After catch (...) [match] | 0 | Test.kt:86:4:88:2 | After catch (...) [match] | -| Test.kt:86:4:88:2 | After catch (...) [match] | 1 | Test.kt:86:11:86:31 | e | -| Test.kt:86:4:88:2 | After catch (...) [match] | 2 | Test.kt:86:34:88:2 | { ... } | -| Test.kt:86:4:88:2 | After catch (...) [match] | 3 | Test.kt:87:3:87:10 | Before return ... | -| Test.kt:86:4:88:2 | After catch (...) [match] | 4 | Test.kt:87:10:87:10 | 2 | -| Test.kt:86:4:88:2 | After catch (...) [match] | 5 | Test.kt:87:3:87:10 | return ... | -| Test.kt:86:4:88:2 | After catch (...) [no-match] | 0 | Test.kt:86:4:88:2 | After catch (...) [no-match] | -| Test.kt:86:4:88:2 | After catch (...) [no-match] | 1 | Test.kt:82:1:89:1 | Exceptional Exit | | Test.kt:86:4:88:2 | catch (...) | 0 | Test.kt:86:4:88:2 | catch (...) | +| Test.kt:86:4:88:2 | catch (...) | 1 | Test.kt:86:11:86:31 | e | +| Test.kt:86:11:86:31 | After e [match] | 0 | Test.kt:86:11:86:31 | After e [match] | +| Test.kt:86:11:86:31 | After e [match] | 1 | Test.kt:86:34:88:2 | { ... } | +| Test.kt:86:11:86:31 | After e [match] | 2 | Test.kt:87:3:87:10 | Before return ... | +| Test.kt:86:11:86:31 | After e [match] | 3 | Test.kt:87:10:87:10 | 2 | +| Test.kt:86:11:86:31 | After e [match] | 4 | Test.kt:87:3:87:10 | return ... | +| Test.kt:86:11:86:31 | After e [no-match] | 0 | Test.kt:86:11:86:31 | After e [no-match] | +| Test.kt:86:11:86:31 | After e [no-match] | 1 | Test.kt:86:4:88:2 | After catch (...) [no-match] | +| Test.kt:86:11:86:31 | After e [no-match] | 2 | Test.kt:82:1:89:1 | Exceptional Exit | | Test.kt:91:1:98:1 | Entry | 0 | Test.kt:91:1:98:1 | Entry | | Test.kt:91:1:98:1 | Entry | 1 | Test.kt:91:22:98:1 | { ... } | | Test.kt:91:1:98:1 | Entry | 2 | Test.kt:92:2:97:2 | try ... | @@ -262,15 +263,16 @@ | Test.kt:93:11:93:13 | After ...!! | 4 | Test.kt:94:3:94:10 | Before return ... | | Test.kt:93:11:93:13 | After ...!! | 5 | Test.kt:94:10:94:10 | 1 | | Test.kt:93:11:93:13 | After ...!! | 6 | Test.kt:94:3:94:10 | return ... | -| Test.kt:95:4:97:2 | After catch (...) [match] | 0 | Test.kt:95:4:97:2 | After catch (...) [match] | -| Test.kt:95:4:97:2 | After catch (...) [match] | 1 | Test.kt:95:11:95:33 | e | -| Test.kt:95:4:97:2 | After catch (...) [match] | 2 | Test.kt:95:36:97:2 | { ... } | -| Test.kt:95:4:97:2 | After catch (...) [match] | 3 | Test.kt:96:3:96:10 | Before return ... | -| Test.kt:95:4:97:2 | After catch (...) [match] | 4 | Test.kt:96:10:96:10 | 2 | -| Test.kt:95:4:97:2 | After catch (...) [match] | 5 | Test.kt:96:3:96:10 | return ... | -| Test.kt:95:4:97:2 | After catch (...) [no-match] | 0 | Test.kt:95:4:97:2 | After catch (...) [no-match] | -| Test.kt:95:4:97:2 | After catch (...) [no-match] | 1 | Test.kt:91:1:98:1 | Exceptional Exit | | Test.kt:95:4:97:2 | catch (...) | 0 | Test.kt:95:4:97:2 | catch (...) | +| Test.kt:95:4:97:2 | catch (...) | 1 | Test.kt:95:11:95:33 | e | +| Test.kt:95:11:95:33 | After e [match] | 0 | Test.kt:95:11:95:33 | After e [match] | +| Test.kt:95:11:95:33 | After e [match] | 1 | Test.kt:95:36:97:2 | { ... } | +| Test.kt:95:11:95:33 | After e [match] | 2 | Test.kt:96:3:96:10 | Before return ... | +| Test.kt:95:11:95:33 | After e [match] | 3 | Test.kt:96:10:96:10 | 2 | +| Test.kt:95:11:95:33 | After e [match] | 4 | Test.kt:96:3:96:10 | return ... | +| Test.kt:95:11:95:33 | After e [no-match] | 0 | Test.kt:95:11:95:33 | After e [no-match] | +| Test.kt:95:11:95:33 | After e [no-match] | 1 | Test.kt:95:4:97:2 | After catch (...) [no-match] | +| Test.kt:95:11:95:33 | After e [no-match] | 2 | Test.kt:91:1:98:1 | Exceptional Exit | | Test.kt:100:1:110:1 | Entry | 0 | Test.kt:100:1:110:1 | Entry | | Test.kt:100:1:110:1 | Entry | 1 | Test.kt:100:25:110:1 | { ... } | | Test.kt:100:1:110:1 | Entry | 2 | Test.kt:101:5:103:5 | ; | diff --git a/java/ql/test-kotlin2/library-tests/controlflow/basic/bbStrictDominance.expected b/java/ql/test-kotlin2/library-tests/controlflow/basic/bbStrictDominance.expected index a4a9b68d404..8f4e5c19ebb 100644 --- a/java/ql/test-kotlin2/library-tests/controlflow/basic/bbStrictDominance.expected +++ b/java/ql/test-kotlin2/library-tests/controlflow/basic/bbStrictDominance.expected @@ -32,17 +32,17 @@ | Test.kt:82:21:89:1 | { ... } | Test.kt:82:1:89:1 | Normal Exit | | Test.kt:82:21:89:1 | { ... } | Test.kt:84:3:84:18 | x | | Test.kt:82:21:89:1 | { ... } | Test.kt:86:4:88:2 | catch (...) | -| Test.kt:82:21:89:1 | { ... } | Test.kt:86:11:86:31 | e | +| Test.kt:82:21:89:1 | { ... } | Test.kt:86:34:88:2 | { ... } | | Test.kt:86:4:88:2 | catch (...) | Test.kt:82:1:89:1 | Exceptional Exit | -| Test.kt:86:4:88:2 | catch (...) | Test.kt:86:11:86:31 | e | +| Test.kt:86:4:88:2 | catch (...) | Test.kt:86:34:88:2 | { ... } | | Test.kt:91:22:98:1 | { ... } | Test.kt:91:1:98:1 | Exceptional Exit | | Test.kt:91:22:98:1 | { ... } | Test.kt:91:1:98:1 | Exit | | Test.kt:91:22:98:1 | { ... } | Test.kt:91:1:98:1 | Normal Exit | | Test.kt:91:22:98:1 | { ... } | Test.kt:93:3:93:13 | x | | Test.kt:91:22:98:1 | { ... } | Test.kt:95:4:97:2 | catch (...) | -| Test.kt:91:22:98:1 | { ... } | Test.kt:95:11:95:33 | e | +| Test.kt:91:22:98:1 | { ... } | Test.kt:95:36:97:2 | { ... } | | Test.kt:95:4:97:2 | catch (...) | Test.kt:91:1:98:1 | Exceptional Exit | -| Test.kt:95:4:97:2 | catch (...) | Test.kt:95:11:95:33 | e | +| Test.kt:95:4:97:2 | catch (...) | Test.kt:95:36:97:2 | { ... } | | Test.kt:100:25:110:1 | { ... } | Test.kt:100:1:110:1 | Exit | | Test.kt:100:25:110:1 | { ... } | Test.kt:100:1:110:1 | Normal Exit | | Test.kt:100:25:110:1 | { ... } | Test.kt:101:22:101:22 | y | diff --git a/java/ql/test-kotlin2/library-tests/controlflow/basic/bbSuccessor.expected b/java/ql/test-kotlin2/library-tests/controlflow/basic/bbSuccessor.expected index 060e3fcae70..97d8600b09d 100644 --- a/java/ql/test-kotlin2/library-tests/controlflow/basic/bbSuccessor.expected +++ b/java/ql/test-kotlin2/library-tests/controlflow/basic/bbSuccessor.expected @@ -20,16 +20,16 @@ | Test.kt:82:21:89:1 | { ... } | Test.kt:86:4:88:2 | catch (...) | | Test.kt:84:3:84:18 | x | Test.kt:82:1:89:1 | Normal Exit | | Test.kt:86:4:88:2 | catch (...) | Test.kt:82:1:89:1 | Exceptional Exit | -| Test.kt:86:4:88:2 | catch (...) | Test.kt:86:11:86:31 | e | -| Test.kt:86:11:86:31 | e | Test.kt:82:1:89:1 | Normal Exit | +| Test.kt:86:4:88:2 | catch (...) | Test.kt:86:34:88:2 | { ... } | +| Test.kt:86:34:88:2 | { ... } | Test.kt:82:1:89:1 | Normal Exit | | Test.kt:91:1:98:1 | Exceptional Exit | Test.kt:91:1:98:1 | Exit | | Test.kt:91:1:98:1 | Normal Exit | Test.kt:91:1:98:1 | Exit | | Test.kt:91:22:98:1 | { ... } | Test.kt:93:3:93:13 | x | | Test.kt:91:22:98:1 | { ... } | Test.kt:95:4:97:2 | catch (...) | | Test.kt:93:3:93:13 | x | Test.kt:91:1:98:1 | Normal Exit | | Test.kt:95:4:97:2 | catch (...) | Test.kt:91:1:98:1 | Exceptional Exit | -| Test.kt:95:4:97:2 | catch (...) | Test.kt:95:11:95:33 | e | -| Test.kt:95:11:95:33 | e | Test.kt:91:1:98:1 | Normal Exit | +| Test.kt:95:4:97:2 | catch (...) | Test.kt:95:36:97:2 | { ... } | +| Test.kt:95:36:97:2 | { ... } | Test.kt:91:1:98:1 | Normal Exit | | Test.kt:100:1:110:1 | Normal Exit | Test.kt:100:1:110:1 | Exit | | Test.kt:100:25:110:1 | { ... } | Test.kt:101:9:101:17 | After ... (value equals) ... [false] | | Test.kt:100:25:110:1 | { ... } | Test.kt:101:22:101:22 | y | diff --git a/java/ql/test-kotlin2/library-tests/controlflow/basic/getASuccessor.expected b/java/ql/test-kotlin2/library-tests/controlflow/basic/getASuccessor.expected index d5483586e0b..0d913d2448a 100644 --- a/java/ql/test-kotlin2/library-tests/controlflow/basic/getASuccessor.expected +++ b/java/ql/test-kotlin2/library-tests/controlflow/basic/getASuccessor.expected @@ -136,8 +136,8 @@ | Test.kt:84:11:84:18 | (...)... | CastExpr | Test.kt:86:4:88:2 | catch (...) | CatchClause | | Test.kt:85:3:85:10 | return ... | ReturnStmt | Test.kt:82:1:89:1 | Normal Exit | Method | | Test.kt:85:10:85:10 | 1 | IntegerLiteral | Test.kt:85:3:85:10 | return ... | ReturnStmt | -| Test.kt:86:4:88:2 | catch (...) | CatchClause | Test.kt:82:1:89:1 | Exceptional Exit | Method | | Test.kt:86:4:88:2 | catch (...) | CatchClause | Test.kt:86:11:86:31 | e | LocalVariableDeclExpr | +| Test.kt:86:11:86:31 | e | LocalVariableDeclExpr | Test.kt:82:1:89:1 | Exceptional Exit | Method | | Test.kt:86:11:86:31 | e | LocalVariableDeclExpr | Test.kt:86:34:88:2 | { ... } | BlockStmt | | Test.kt:86:34:88:2 | { ... } | BlockStmt | Test.kt:87:10:87:10 | 2 | IntegerLiteral | | Test.kt:87:3:87:10 | return ... | ReturnStmt | Test.kt:82:1:89:1 | Normal Exit | Method | @@ -155,8 +155,8 @@ | Test.kt:93:11:93:13 | ...!! | NotNullExpr | Test.kt:95:4:97:2 | catch (...) | CatchClause | | Test.kt:94:3:94:10 | return ... | ReturnStmt | Test.kt:91:1:98:1 | Normal Exit | Method | | Test.kt:94:10:94:10 | 1 | IntegerLiteral | Test.kt:94:3:94:10 | return ... | ReturnStmt | -| Test.kt:95:4:97:2 | catch (...) | CatchClause | Test.kt:91:1:98:1 | Exceptional Exit | Method | | Test.kt:95:4:97:2 | catch (...) | CatchClause | Test.kt:95:11:95:33 | e | LocalVariableDeclExpr | +| Test.kt:95:11:95:33 | e | LocalVariableDeclExpr | Test.kt:91:1:98:1 | Exceptional Exit | Method | | Test.kt:95:11:95:33 | e | LocalVariableDeclExpr | Test.kt:95:36:97:2 | { ... } | BlockStmt | | Test.kt:95:36:97:2 | { ... } | BlockStmt | Test.kt:96:10:96:10 | 2 | IntegerLiteral | | Test.kt:96:3:96:10 | return ... | ReturnStmt | Test.kt:91:1:98:1 | Normal Exit | Method | diff --git a/java/ql/test/library-tests/java7/MultiCatch/MultiCatchControlFlow.expected b/java/ql/test/library-tests/java7/MultiCatch/MultiCatchControlFlow.expected index 54bd6b9388f..de98d238e40 100644 --- a/java/ql/test/library-tests/java7/MultiCatch/MultiCatchControlFlow.expected +++ b/java/ql/test/library-tests/java7/MultiCatch/MultiCatchControlFlow.expected @@ -14,8 +14,8 @@ | MultiCatch.java:12:11:12:27 | new IOException(...) | MultiCatch.java:12:5:12:28 | throw ... | | MultiCatch.java:14:5:14:29 | throw ... | MultiCatch.java:15:5:15:37 | catch (...) | | MultiCatch.java:14:11:14:28 | new SQLException(...) | MultiCatch.java:14:5:14:29 | throw ... | -| MultiCatch.java:15:5:15:37 | catch (...) | MultiCatch.java:7:14:7:23 | Exceptional Exit | | MultiCatch.java:15:5:15:37 | catch (...) | MultiCatch.java:15:36:15:36 | e | +| MultiCatch.java:15:36:15:36 | e | MultiCatch.java:7:14:7:23 | Exceptional Exit | | MultiCatch.java:15:36:15:36 | e | MultiCatch.java:16:3:19:3 | { ... } | | MultiCatch.java:16:3:19:3 | { ... } | MultiCatch.java:17:4:17:23 | ; | | MultiCatch.java:17:4:17:4 | e | MultiCatch.java:17:4:17:22 | printStackTrace(...) | @@ -41,8 +41,8 @@ | MultiCatch.java:29:11:29:28 | new SQLException(...) | MultiCatch.java:29:5:29:29 | throw ... | | MultiCatch.java:30:4:30:25 | throw ... | MultiCatch.java:31:5:31:37 | catch (...) | | MultiCatch.java:30:10:30:24 | new Exception(...) | MultiCatch.java:30:4:30:25 | throw ... | -| MultiCatch.java:31:5:31:37 | catch (...) | MultiCatch.java:22:14:22:24 | Exceptional Exit | | MultiCatch.java:31:5:31:37 | catch (...) | MultiCatch.java:31:36:31:36 | e | +| MultiCatch.java:31:36:31:36 | e | MultiCatch.java:22:14:22:24 | Exceptional Exit | | MultiCatch.java:31:36:31:36 | e | MultiCatch.java:32:3:32:4 | { ... } | | MultiCatch.java:32:3:32:4 | { ... } | MultiCatch.java:22:14:22:24 | Normal Exit | | MultiCatch.java:35:14:35:26 | Entry | MultiCatch.java:36:2:42:2 | { ... } | diff --git a/java/ql/test/library-tests/successors/CloseReaderTest/TestSucc.expected b/java/ql/test/library-tests/successors/CloseReaderTest/TestSucc.expected index 6889eb8da32..3151eb07f7c 100644 --- a/java/ql/test/library-tests/successors/CloseReaderTest/TestSucc.expected +++ b/java/ql/test/library-tests/successors/CloseReaderTest/TestSucc.expected @@ -28,8 +28,8 @@ | CloseReaderTest.java:19:11:19:15 | stdin | CloseReaderTest.java:19:11:19:26 | readLine(...) | | CloseReaderTest.java:19:11:19:26 | readLine(...) | CloseReaderTest.java:19:4:19:27 | return ... | | CloseReaderTest.java:19:11:19:26 | readLine(...) | CloseReaderTest.java:20:5:20:26 | catch (...) | -| CloseReaderTest.java:20:5:20:26 | catch (...) | CloseReaderTest.java:9:23:9:34 | Exceptional Exit | | CloseReaderTest.java:20:5:20:26 | catch (...) | CloseReaderTest.java:20:24:20:25 | ex | +| CloseReaderTest.java:20:24:20:25 | ex | CloseReaderTest.java:9:23:9:34 | Exceptional Exit | | CloseReaderTest.java:20:24:20:25 | ex | CloseReaderTest.java:21:3:23:3 | { ... } | | CloseReaderTest.java:21:3:23:3 | { ... } | CloseReaderTest.java:22:11:22:14 | null | | CloseReaderTest.java:22:4:22:15 | return ... | CloseReaderTest.java:9:23:9:34 | Normal Exit | diff --git a/java/ql/test/library-tests/successors/SchackTest/TestSucc.expected b/java/ql/test/library-tests/successors/SchackTest/TestSucc.expected index 19fef193edb..574837742c0 100644 --- a/java/ql/test/library-tests/successors/SchackTest/TestSucc.expected +++ b/java/ql/test/library-tests/successors/SchackTest/TestSucc.expected @@ -50,16 +50,16 @@ | SchackTest.java:16:4:16:41 | ; | SchackTest.java:16:4:16:13 | System.out | | SchackTest.java:16:23:16:39 | "false successor" | SchackTest.java:16:4:16:40 | println(...) | | SchackTest.java:17:5:17:17 | catch (...) | SchackTest.java:17:16:17:16 | e | -| SchackTest.java:17:5:17:17 | catch (...) | SchackTest.java:19:5:19:17 | catch (...) | | SchackTest.java:17:16:17:16 | e | SchackTest.java:17:19:19:3 | { ... } | +| SchackTest.java:17:16:17:16 | e | SchackTest.java:19:5:19:17 | catch (...) | | SchackTest.java:17:19:19:3 | { ... } | SchackTest.java:18:4:18:41 | ; | | SchackTest.java:18:4:18:13 | System.out | SchackTest.java:18:23:18:39 | "false successor" | | SchackTest.java:18:4:18:40 | println(...) | SchackTest.java:21:13:23:3 | { ... } | | SchackTest.java:18:4:18:41 | ; | SchackTest.java:18:4:18:13 | System.out | | SchackTest.java:18:23:18:39 | "false successor" | SchackTest.java:18:4:18:40 | println(...) | | SchackTest.java:19:5:19:17 | catch (...) | SchackTest.java:19:16:19:16 | e | -| SchackTest.java:19:5:19:17 | catch (...) | SchackTest.java:21:13:23:3 | { ... } | | SchackTest.java:19:16:19:16 | e | SchackTest.java:19:19:21:3 | { ... } | +| SchackTest.java:19:16:19:16 | e | SchackTest.java:21:13:23:3 | { ... } | | SchackTest.java:19:19:21:3 | { ... } | SchackTest.java:20:4:20:74 | ; | | SchackTest.java:20:4:20:13 | System.out | SchackTest.java:20:23:20:72 | "successor (but neither true nor false successor)" | | SchackTest.java:20:4:20:73 | println(...) | SchackTest.java:21:13:23:3 | { ... } | diff --git a/java/ql/test/library-tests/successors/TestThrow/TestSucc.expected b/java/ql/test/library-tests/successors/TestThrow/TestSucc.expected index 3ed406a0a71..e673cf0bcbe 100644 --- a/java/ql/test/library-tests/successors/TestThrow/TestSucc.expected +++ b/java/ql/test/library-tests/successors/TestThrow/TestSucc.expected @@ -18,8 +18,8 @@ | TestThrow.java:20:10:20:31 | new RuntimeException(...) | TestThrow.java:20:4:20:32 | throw ... | | TestThrow.java:20:10:20:31 | new RuntimeException(...) | TestThrow.java:21:5:21:30 | catch (...) | | TestThrow.java:21:5:21:30 | catch (...) | TestThrow.java:21:29:21:29 | e | -| TestThrow.java:21:5:21:30 | catch (...) | TestThrow.java:24:5:24:23 | catch (...) | | TestThrow.java:21:29:21:29 | e | TestThrow.java:22:3:24:3 | { ... } | +| TestThrow.java:21:29:21:29 | e | TestThrow.java:24:5:24:23 | catch (...) | | TestThrow.java:22:3:24:3 | { ... } | TestThrow.java:23:4:23:9 | ; | | TestThrow.java:23:4:23:4 | z | TestThrow.java:23:8:23:8 | 1 | | TestThrow.java:23:4:23:8 | ...=... | TestThrow.java:29:3:29:9 | ; | @@ -71,8 +71,8 @@ | TestThrow.java:44:5:44:13 | thrower(...) | TestThrow.java:50:3:52:3 | { ... } | | TestThrow.java:44:5:44:14 | ; | TestThrow.java:44:5:44:13 | thrower(...) | | TestThrow.java:46:5:46:30 | catch (...) | TestThrow.java:46:29:46:29 | e | -| TestThrow.java:46:5:46:30 | catch (...) | TestThrow.java:50:3:52:3 | { ... } | | TestThrow.java:46:29:46:29 | e | TestThrow.java:47:3:49:3 | { ... } | +| TestThrow.java:46:29:46:29 | e | TestThrow.java:50:3:52:3 | { ... } | | TestThrow.java:47:3:49:3 | { ... } | TestThrow.java:48:4:48:9 | ; | | TestThrow.java:48:4:48:4 | z | TestThrow.java:48:8:48:8 | 1 | | TestThrow.java:48:4:48:8 | ...=... | TestThrow.java:50:3:52:3 | { ... } | @@ -113,8 +113,8 @@ | TestThrow.java:67:5:67:13 | thrower(...) | TestThrow.java:69:5:69:30 | catch (...) | | TestThrow.java:67:5:67:13 | thrower(...) | TestThrow.java:74:3:74:9 | ; | | TestThrow.java:67:5:67:14 | ; | TestThrow.java:67:5:67:13 | thrower(...) | -| TestThrow.java:69:5:69:30 | catch (...) | TestThrow.java:15:14:15:14 | Exceptional Exit | | TestThrow.java:69:5:69:30 | catch (...) | TestThrow.java:69:29:69:29 | e | +| TestThrow.java:69:29:69:29 | e | TestThrow.java:15:14:15:14 | Exceptional Exit | | TestThrow.java:69:29:69:29 | e | TestThrow.java:70:3:72:3 | { ... } | | TestThrow.java:70:3:72:3 | { ... } | TestThrow.java:71:4:71:9 | ; | | TestThrow.java:71:4:71:4 | z | TestThrow.java:71:8:71:8 | 1 | @@ -171,8 +171,8 @@ | TestThrow.java:97:28:97:36 | "Foo bar" | TestThrow.java:97:39:97:42 | null | | TestThrow.java:97:39:97:42 | null | TestThrow.java:97:12:97:43 | new IOException(...) | | TestThrow.java:99:6:99:31 | catch (...) | TestThrow.java:99:30:99:30 | e | -| TestThrow.java:99:6:99:31 | catch (...) | TestThrow.java:119:5:119:25 | catch (...) | | TestThrow.java:99:30:99:30 | e | TestThrow.java:100:4:102:4 | { ... } | +| TestThrow.java:99:30:99:30 | e | TestThrow.java:119:5:119:25 | catch (...) | | TestThrow.java:100:4:102:4 | { ... } | TestThrow.java:101:5:101:10 | ; | | TestThrow.java:101:5:101:5 | z | TestThrow.java:101:9:101:9 | 1 | | TestThrow.java:101:5:101:9 | ...=... | TestThrow.java:103:4:118:4 | try ... | @@ -216,8 +216,8 @@ | TestThrow.java:116:28:116:36 | "Foo bar" | TestThrow.java:116:39:116:42 | null | | TestThrow.java:116:39:116:42 | null | TestThrow.java:116:12:116:43 | new IOException(...) | | TestThrow.java:119:5:119:25 | catch (...) | TestThrow.java:119:24:119:24 | e | -| TestThrow.java:119:5:119:25 | catch (...) | TestThrow.java:124:3:126:3 | { ... } | | TestThrow.java:119:24:119:24 | e | TestThrow.java:120:3:122:3 | { ... } | +| TestThrow.java:119:24:119:24 | e | TestThrow.java:124:3:126:3 | { ... } | | TestThrow.java:120:3:122:3 | { ... } | TestThrow.java:121:4:121:9 | ; | | TestThrow.java:121:4:121:4 | z | TestThrow.java:121:8:121:8 | 2 | | TestThrow.java:121:4:121:8 | ...=... | TestThrow.java:124:3:126:3 | { ... } | diff --git a/java/ql/test/library-tests/successors/TestTryCatch/TestSucc.expected b/java/ql/test/library-tests/successors/TestTryCatch/TestSucc.expected index 7769fd9d5b3..f3759792eac 100644 --- a/java/ql/test/library-tests/successors/TestTryCatch/TestSucc.expected +++ b/java/ql/test/library-tests/successors/TestTryCatch/TestSucc.expected @@ -105,8 +105,8 @@ | TestTryCatch.java:34:9:34:9 | y | TestTryCatch.java:34:13:34:13 | 1 | | TestTryCatch.java:34:9:34:13 | ... + ... | TestTryCatch.java:34:5:34:13 | ...=... | | TestTryCatch.java:34:13:34:13 | 1 | TestTryCatch.java:34:9:34:13 | ... + ... | -| TestTryCatch.java:35:6:35:31 | catch (...) | TestTryCatch.java:4:14:4:14 | Exceptional Exit | | TestTryCatch.java:35:6:35:31 | catch (...) | TestTryCatch.java:35:30:35:30 | e | +| TestTryCatch.java:35:30:35:30 | e | TestTryCatch.java:4:14:4:14 | Exceptional Exit | | TestTryCatch.java:35:30:35:30 | e | TestTryCatch.java:36:4:40:4 | { ... } | | TestTryCatch.java:36:4:40:4 | { ... } | TestTryCatch.java:37:5:37:14 | var ...; | | TestTryCatch.java:37:5:37:14 | var ...; | TestTryCatch.java:37:13:37:13 | 1 | diff --git a/java/ql/test/library-tests/successors/TestTryWithResources/TestSucc.expected b/java/ql/test/library-tests/successors/TestTryWithResources/TestSucc.expected index e9dabd746f1..f8fe1c798db 100644 --- a/java/ql/test/library-tests/successors/TestTryWithResources/TestSucc.expected +++ b/java/ql/test/library-tests/successors/TestTryWithResources/TestSucc.expected @@ -28,8 +28,8 @@ | TestTryWithResources.java:10:4:10:32 | ; | TestTryWithResources.java:10:4:10:13 | System.out | | TestTryWithResources.java:10:23:10:30 | "worked" | TestTryWithResources.java:10:4:10:31 | println(...) | | TestTryWithResources.java:11:5:11:35 | catch (...) | TestTryWithResources.java:11:34:11:34 | e | -| TestTryWithResources.java:11:5:11:35 | catch (...) | TestTryWithResources.java:13:13:15:3 | { ... } | | TestTryWithResources.java:11:34:11:34 | e | TestTryWithResources.java:11:37:13:3 | { ... } | +| TestTryWithResources.java:11:34:11:34 | e | TestTryWithResources.java:13:13:15:3 | { ... } | | TestTryWithResources.java:11:37:13:3 | { ... } | TestTryWithResources.java:12:4:12:40 | ; | | TestTryWithResources.java:12:4:12:13 | System.out | TestTryWithResources.java:12:23:12:38 | "file not found" | | TestTryWithResources.java:12:4:12:39 | println(...) | TestTryWithResources.java:13:13:15:3 | { ... } | diff --git a/javascript/ql/lib/CHANGELOG.md b/javascript/ql/lib/CHANGELOG.md index 6471aa3fe68..e3802a7686e 100644 --- a/javascript/ql/lib/CHANGELOG.md +++ b/javascript/ql/lib/CHANGELOG.md @@ -1,3 +1,14 @@ +## 2.8.0 + +### New Features + +* Added `UseMemoDirective` and `UseNoMemoDirective` classes to model the React compiler directives `"use memo"` and `"use no memo"`. + +### Minor Analysis Improvements + +* Added more prompt-injection sinks for the OpenAI, Anthropic, and Google GenAI SDKs: OpenAI `videos.create`/`edit`/`extend`/`remix` (Sora) prompts and `beta.realtime.sessions.create` instructions, Anthropic legacy `completions.create` prompts, and Google GenAI `caches.create` cached contents and system instructions. +* The OpenAI legacy `completions.create` prompt is now treated as a user-prompt-injection sink instead of a system-prompt-injection sink, since the legacy `/v1/completions` endpoint takes a single free-form prompt with no role separation. + ## 2.7.2 ### Minor Analysis Improvements diff --git a/javascript/ql/lib/change-notes/2026-05-05-use-memo-directive.md b/javascript/ql/lib/change-notes/2026-05-05-use-memo-directive.md deleted file mode 100644 index be95205c9ab..00000000000 --- a/javascript/ql/lib/change-notes/2026-05-05-use-memo-directive.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: feature ---- -* Added `UseMemoDirective` and `UseNoMemoDirective` classes to model the React compiler directives `"use memo"` and `"use no memo"`. diff --git a/javascript/ql/lib/change-notes/2026-06-22-angular-hostlistener-postmessage.md b/javascript/ql/lib/change-notes/2026-06-22-angular-hostlistener-postmessage.md new file mode 100644 index 00000000000..686e8ae96da --- /dev/null +++ b/javascript/ql/lib/change-notes/2026-06-22-angular-hostlistener-postmessage.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Added support for Angular's `@HostListener('window:message', ...)` and `@HostListener('document:message', ...)` decorators as `postMessage` event handlers. The decorated method's event parameter is now recognized as a client-side remote flow source, and is considered by the `js/missing-origin-check` query. diff --git a/javascript/ql/lib/change-notes/released/2.8.0.md b/javascript/ql/lib/change-notes/released/2.8.0.md new file mode 100644 index 00000000000..4060343bf0a --- /dev/null +++ b/javascript/ql/lib/change-notes/released/2.8.0.md @@ -0,0 +1,10 @@ +## 2.8.0 + +### New Features + +* Added `UseMemoDirective` and `UseNoMemoDirective` classes to model the React compiler directives `"use memo"` and `"use no memo"`. + +### Minor Analysis Improvements + +* Added more prompt-injection sinks for the OpenAI, Anthropic, and Google GenAI SDKs: OpenAI `videos.create`/`edit`/`extend`/`remix` (Sora) prompts and `beta.realtime.sessions.create` instructions, Anthropic legacy `completions.create` prompts, and Google GenAI `caches.create` cached contents and system instructions. +* The OpenAI legacy `completions.create` prompt is now treated as a user-prompt-injection sink instead of a system-prompt-injection sink, since the legacy `/v1/completions` endpoint takes a single free-form prompt with no role separation. diff --git a/javascript/ql/lib/codeql-pack.release.yml b/javascript/ql/lib/codeql-pack.release.yml index 5160df7b1b7..8e0a6e07a08 100644 --- a/javascript/ql/lib/codeql-pack.release.yml +++ b/javascript/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 2.7.2 +lastReleaseVersion: 2.8.0 diff --git a/javascript/ql/lib/ext/anthropic.model.yml b/javascript/ql/lib/ext/anthropic.model.yml index bf0c953e07f..80e82925697 100644 --- a/javascript/ql/lib/ext/anthropic.model.yml +++ b/javascript/ql/lib/ext/anthropic.model.yml @@ -10,6 +10,7 @@ extensions: extensible: sinkModel data: - ["anthropic.Client", "Member[messages].Member[create].Argument[0].Member[system]", "system-prompt-injection"] + - ["anthropic.Client", "Member[completions].Member[create].Argument[0].Member[prompt]", "user-prompt-injection"] - ["anthropic.Client", "Member[messages].Member[create].Argument[0].Member[system].ArrayElement.Member[text]", "system-prompt-injection"] - ["anthropic.Client", "Member[beta].Member[messages].Member[create].Argument[0].Member[system]", "system-prompt-injection"] - ["anthropic.Client", "Member[beta].Member[messages].Member[create].Argument[0].Member[system].ArrayElement.Member[text]", "system-prompt-injection"] diff --git a/javascript/ql/lib/ext/google-genai.model.yml b/javascript/ql/lib/ext/google-genai.model.yml index 9ff8fd44e4b..9b9796d4fa9 100644 --- a/javascript/ql/lib/ext/google-genai.model.yml +++ b/javascript/ql/lib/ext/google-genai.model.yml @@ -13,6 +13,7 @@ extensions: - ["google-genai.Client", "Member[chats].Member[create].Argument[0].Member[config].Member[systemInstruction]", "system-prompt-injection"] - ["google-genai.Client", "Member[chats].Member[create].ReturnValue.Member[sendMessage].Argument[0].Member[config].Member[systemInstruction]", "system-prompt-injection"] - ["google-genai.Client", "Member[live].Member[connect].Argument[0].Member[config].Member[systemInstruction]", "system-prompt-injection"] + - ["google-genai.Client", "Member[caches].Member[create].Argument[0].Member[config].Member[systemInstruction]", "system-prompt-injection"] - ["google-genai.Client", "Member[models].Member[generateContent,generateContentStream].Argument[0].Member[contents]", "user-prompt-injection"] - ["google-genai.Client", "Member[models].Member[generateImages].Argument[0].Member[prompt]", "user-prompt-injection"] - ["google-genai.Client", "Member[models].Member[editImage].Argument[0].Member[prompt]", "user-prompt-injection"] @@ -20,3 +21,4 @@ extensions: - ["google-genai.Client", "Member[chats].Member[create].ReturnValue.Member[sendMessage,sendMessageStream].Argument[0].Member[message]", "user-prompt-injection"] - ["google-genai.Client", "Member[chats].Member[create].ReturnValue.Member[sendMessage,sendMessageStream].Argument[0].Member[content]", "user-prompt-injection"] - ["google-genai.Client", "Member[interactions].Member[create].Argument[0].Member[input]", "user-prompt-injection"] + - ["google-genai.Client", "Member[caches].Member[create].Argument[0].Member[config].Member[contents]", "user-prompt-injection"] diff --git a/javascript/ql/lib/ext/openai.model.yml b/javascript/ql/lib/ext/openai.model.yml index a979842e926..bbccbe5a802 100644 --- a/javascript/ql/lib/ext/openai.model.yml +++ b/javascript/ql/lib/ext/openai.model.yml @@ -12,7 +12,7 @@ extensions: extensible: sinkModel data: - ["openai.Client", "Member[responses].Member[create].Argument[0].Member[instructions]", "system-prompt-injection"] - - ["openai.Client", "Member[completions].Member[create].Argument[0].Member[prompt]", "system-prompt-injection"] + - ["openai.Client", "Member[beta].Member[realtime].Member[sessions].Member[create].Argument[0].Member[instructions]", "system-prompt-injection"] - ["openai.Client", "Member[beta].Member[assistants].Member[create].Argument[0].Member[instructions]", "system-prompt-injection"] - ["openai.Client", "Member[beta].Member[assistants].Member[update].Argument[1].Member[instructions]", "system-prompt-injection"] - ["openai.Client", "Member[beta].Member[threads].Member[runs].Member[create].Argument[1].Member[instructions,additional_instructions]", "system-prompt-injection"] @@ -25,3 +25,5 @@ extensions: - ["@openai/guardrails", "Member[GuardrailAgent].Member[create].Argument[2]", "system-prompt-injection"] - ["@openai/agents", "Member[run].Argument[1]", "user-prompt-injection"] - ["@openai/agents", "Member[Runner].Instance.Member[run].Argument[1]", "user-prompt-injection"] + - ["openai.Client", "Member[videos].Member[create,edit,extend].Argument[0].Member[prompt]", "user-prompt-injection"] + - ["openai.Client", "Member[videos].Member[remix].Argument[1].Member[prompt]", "user-prompt-injection"] diff --git a/javascript/ql/lib/qlpack.yml b/javascript/ql/lib/qlpack.yml index 870ad58a1b8..584f2e135f7 100644 --- a/javascript/ql/lib/qlpack.yml +++ b/javascript/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/javascript-all -version: 2.7.3-dev +version: 2.8.1-dev groups: javascript dbscheme: semmlecode.javascript.dbscheme extractor: javascript diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/DOM.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/DOM.qll index f959de6c0b5..3d371c47318 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/DOM.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/DOM.qll @@ -195,6 +195,18 @@ class PostMessageEventHandler extends Function { rhs = DataFlow::globalObjectRef().getAPropertyWrite("onmessage").getRhs() and rhs.getABoundFunctionValue(paramIndex).getFunction() = this ) + or + // Angular's `@HostListener('window:message', ['$event'])` decorator registers + // a method as a `message` event handler on the global `window` or `document` + // target. The decorated method receives the `MessageEvent` as its first + // parameter, so it is equivalent to `window.addEventListener('message', ...)`. + exists(MethodDefinition method, DataFlow::CallNode decorator | + decorator = DataFlow::moduleMember("@angular/core", "HostListener").getACall() and + decorator = method.getADecorator().getExpression().flow() and + decorator.getArgument(0).mayHaveStringValue(["window:message", "document:message"]) and + method.getBody() = this and + paramIndex = 0 + ) } /** diff --git a/javascript/ql/src/CHANGELOG.md b/javascript/ql/src/CHANGELOG.md index b3a62befc5e..3da6a12390e 100644 --- a/javascript/ql/src/CHANGELOG.md +++ b/javascript/ql/src/CHANGELOG.md @@ -1,3 +1,10 @@ +## 2.4.0 + +### New Queries + +* Added a new query, `js/system-prompt-injection`, to detect cases where untrusted, user-provided values flow into the system prompt of an AI model, allowing an attacker to manipulate the model's behavior. +* Added a new experimental query, `javascript/ssrf-ipv6-transition-incomplete-guard`, to detect SSRF host-validation guards that reject private IPv4 ranges but fail to unwrap IPv6-transition forms (IPv4-mapped `::ffff:`, NAT64 `64:ff9b::`, 6to4 `2002::`), allowing the guard to be bypassed by wrapping an internal IPv4 address in a transition literal. + ## 2.3.11 No user-facing changes. diff --git a/javascript/ql/src/change-notes/2026-06-08-new-system-prompt-injection-query.md b/javascript/ql/src/change-notes/2026-06-08-new-system-prompt-injection-query.md deleted file mode 100644 index 1764a7cbc1a..00000000000 --- a/javascript/ql/src/change-notes/2026-06-08-new-system-prompt-injection-query.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -category: newQuery ---- - -* Added a new query, `js/system-prompt-injection`, to detect cases where untrusted, user-provided values flow into the system prompt of an AI model, allowing an attacker to manipulate the model's behavior. diff --git a/javascript/ql/src/change-notes/2026-06-06-ssrf-ipv6-transition-incomplete-guard.md b/javascript/ql/src/change-notes/released/2.4.0.md similarity index 60% rename from javascript/ql/src/change-notes/2026-06-06-ssrf-ipv6-transition-incomplete-guard.md rename to javascript/ql/src/change-notes/released/2.4.0.md index 35bd19acf46..21d82834f92 100644 --- a/javascript/ql/src/change-notes/2026-06-06-ssrf-ipv6-transition-incomplete-guard.md +++ b/javascript/ql/src/change-notes/released/2.4.0.md @@ -1,4 +1,6 @@ ---- -category: newQuery ---- +## 2.4.0 + +### New Queries + +* Added a new query, `js/system-prompt-injection`, to detect cases where untrusted, user-provided values flow into the system prompt of an AI model, allowing an attacker to manipulate the model's behavior. * Added a new experimental query, `javascript/ssrf-ipv6-transition-incomplete-guard`, to detect SSRF host-validation guards that reject private IPv4 ranges but fail to unwrap IPv6-transition forms (IPv4-mapped `::ffff:`, NAT64 `64:ff9b::`, 6to4 `2002::`), allowing the guard to be bypassed by wrapping an internal IPv4 address in a transition literal. diff --git a/javascript/ql/src/codeql-pack.release.yml b/javascript/ql/src/codeql-pack.release.yml index 5ac091006e8..cb0ea3a249a 100644 --- a/javascript/ql/src/codeql-pack.release.yml +++ b/javascript/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 2.3.11 +lastReleaseVersion: 2.4.0 diff --git a/javascript/ql/src/qlpack.yml b/javascript/ql/src/qlpack.yml index 09303bab573..b608077e3e0 100644 --- a/javascript/ql/src/qlpack.yml +++ b/javascript/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/javascript-queries -version: 2.3.12-dev +version: 2.4.1-dev groups: - javascript - queries diff --git a/javascript/ql/test/Security/CWE-1427/SystemPromptInjection/SystemPromptInjection.expected b/javascript/ql/test/Security/CWE-1427/SystemPromptInjection/SystemPromptInjection.expected index d6594252a7e..d9b7e43a33a 100644 --- a/javascript/ql/test/Security/CWE-1427/SystemPromptInjection/SystemPromptInjection.expected +++ b/javascript/ql/test/Security/CWE-1427/SystemPromptInjection/SystemPromptInjection.expected @@ -23,6 +23,7 @@ | gemini_test.js:85:26:85:49 | "Talk l ... persona | gemini_test.js:8:19:8:35 | req.query.persona | gemini_test.js:85:26:85:49 | "Talk l ... persona | This system prompt depends on a $@. | gemini_test.js:8:19:8:35 | req.query.persona | user-provided value | | gemini_test.js:95:26:95:49 | "Talk l ... persona | gemini_test.js:8:19:8:35 | req.query.persona | gemini_test.js:95:26:95:49 | "Talk l ... persona | This system prompt depends on a $@. | gemini_test.js:8:19:8:35 | req.query.persona | user-provided value | | gemini_test.js:105:26:105:49 | "Talk l ... persona | gemini_test.js:8:19:8:35 | req.query.persona | gemini_test.js:105:26:105:49 | "Talk l ... persona | This system prompt depends on a $@. | gemini_test.js:8:19:8:35 | req.query.persona | user-provided value | +| gemini_test.js:119:26:119:49 | "Talk l ... persona | gemini_test.js:8:19:8:35 | req.query.persona | gemini_test.js:119:26:119:49 | "Talk l ... persona | This system prompt depends on a $@. | gemini_test.js:8:19:8:35 | req.query.persona | user-provided value | | langchain_test.js:16:37:16:60 | "Talk l ... persona | langchain_test.js:9:19:9:35 | req.query.persona | langchain_test.js:16:37:16:60 | "Talk l ... persona | This system prompt depends on a $@. | langchain_test.js:9:19:9:35 | req.query.persona | user-provided value | | langchain_test.js:19:14:19:37 | "Talk l ... persona | langchain_test.js:9:19:9:35 | req.query.persona | langchain_test.js:19:14:19:37 | "Talk l ... persona | This system prompt depends on a $@. | langchain_test.js:9:19:9:35 | req.query.persona | user-provided value | | langchain_test.js:25:19:25:42 | "Talk l ... persona | langchain_test.js:9:19:9:35 | req.query.persona | langchain_test.js:25:19:25:42 | "Talk l ... persona | This system prompt depends on a $@. | langchain_test.js:9:19:9:35 | req.query.persona | user-provided value | @@ -33,13 +34,13 @@ | openai_test.js:83:18:83:41 | "Talk l ... persona | openai_test.js:11:19:11:35 | req.query.persona | openai_test.js:83:18:83:41 | "Talk l ... persona | This system prompt depends on a $@. | openai_test.js:11:19:11:35 | req.query.persona | user-provided value | | openai_test.js:97:19:97:42 | "Talk l ... persona | openai_test.js:11:19:11:35 | req.query.persona | openai_test.js:97:19:97:42 | "Talk l ... persona | This system prompt depends on a $@. | openai_test.js:11:19:11:35 | req.query.persona | user-provided value | | openai_test.js:110:18:110:41 | "Talk l ... persona | openai_test.js:11:19:11:35 | req.query.persona | openai_test.js:110:18:110:41 | "Talk l ... persona | This system prompt depends on a $@. | openai_test.js:11:19:11:35 | req.query.persona | user-provided value | -| openai_test.js:120:13:120:36 | "Talk l ... persona | openai_test.js:11:19:11:35 | req.query.persona | openai_test.js:120:13:120:36 | "Talk l ... persona | This system prompt depends on a $@. | openai_test.js:11:19:11:35 | req.query.persona | user-provided value | -| openai_test.js:129:19:129:42 | "Talk l ... persona | openai_test.js:11:19:11:35 | req.query.persona | openai_test.js:129:19:129:42 | "Talk l ... persona | This system prompt depends on a $@. | openai_test.js:11:19:11:35 | req.query.persona | user-provided value | -| openai_test.js:134:19:134:42 | "Talk l ... persona | openai_test.js:11:19:11:35 | req.query.persona | openai_test.js:134:19:134:42 | "Talk l ... persona | This system prompt depends on a $@. | openai_test.js:11:19:11:35 | req.query.persona | user-provided value | -| openai_test.js:140:19:140:42 | "Talk l ... persona | openai_test.js:11:19:11:35 | req.query.persona | openai_test.js:140:19:140:42 | "Talk l ... persona | This system prompt depends on a $@. | openai_test.js:11:19:11:35 | req.query.persona | user-provided value | -| openai_test.js:146:30:146:58 | "Also t ... persona | openai_test.js:11:19:11:35 | req.query.persona | openai_test.js:146:30:146:58 | "Also t ... persona | This system prompt depends on a $@. | openai_test.js:11:19:11:35 | req.query.persona | user-provided value | -| openai_test.js:152:14:152:37 | "Talk l ... persona | openai_test.js:11:19:11:35 | req.query.persona | openai_test.js:152:14:152:37 | "Talk l ... persona | This system prompt depends on a $@. | openai_test.js:11:19:11:35 | req.query.persona | user-provided value | -| openai_test.js:164:32:164:55 | "Talk l ... persona | openai_test.js:11:19:11:35 | req.query.persona | openai_test.js:164:32:164:55 | "Talk l ... persona | This system prompt depends on a $@. | openai_test.js:11:19:11:35 | req.query.persona | user-provided value | +| openai_test.js:128:19:128:42 | "Talk l ... persona | openai_test.js:11:19:11:35 | req.query.persona | openai_test.js:128:19:128:42 | "Talk l ... persona | This system prompt depends on a $@. | openai_test.js:11:19:11:35 | req.query.persona | user-provided value | +| openai_test.js:137:19:137:42 | "Talk l ... persona | openai_test.js:11:19:11:35 | req.query.persona | openai_test.js:137:19:137:42 | "Talk l ... persona | This system prompt depends on a $@. | openai_test.js:11:19:11:35 | req.query.persona | user-provided value | +| openai_test.js:142:19:142:42 | "Talk l ... persona | openai_test.js:11:19:11:35 | req.query.persona | openai_test.js:142:19:142:42 | "Talk l ... persona | This system prompt depends on a $@. | openai_test.js:11:19:11:35 | req.query.persona | user-provided value | +| openai_test.js:148:19:148:42 | "Talk l ... persona | openai_test.js:11:19:11:35 | req.query.persona | openai_test.js:148:19:148:42 | "Talk l ... persona | This system prompt depends on a $@. | openai_test.js:11:19:11:35 | req.query.persona | user-provided value | +| openai_test.js:154:30:154:58 | "Also t ... persona | openai_test.js:11:19:11:35 | req.query.persona | openai_test.js:154:30:154:58 | "Also t ... persona | This system prompt depends on a $@. | openai_test.js:11:19:11:35 | req.query.persona | user-provided value | +| openai_test.js:160:14:160:37 | "Talk l ... persona | openai_test.js:11:19:11:35 | req.query.persona | openai_test.js:160:14:160:37 | "Talk l ... persona | This system prompt depends on a $@. | openai_test.js:11:19:11:35 | req.query.persona | user-provided value | +| openai_test.js:172:32:172:55 | "Talk l ... persona | openai_test.js:11:19:11:35 | req.query.persona | openai_test.js:172:32:172:55 | "Talk l ... persona | This system prompt depends on a $@. | openai_test.js:11:19:11:35 | req.query.persona | user-provided value | | openrouter_test.js:23:18:23:41 | "Talk l ... persona | openrouter_test.js:12:19:12:35 | req.query.persona | openrouter_test.js:23:18:23:41 | "Talk l ... persona | This system prompt depends on a $@. | openrouter_test.js:12:19:12:35 | req.query.persona | user-provided value | | openrouter_test.js:38:18:38:41 | "Talk l ... persona | openrouter_test.js:12:19:12:35 | req.query.persona | openrouter_test.js:38:18:38:41 | "Talk l ... persona | This system prompt depends on a $@. | openrouter_test.js:12:19:12:35 | req.query.persona | user-provided value | | openrouter_test.js:52:19:52:42 | "Talk l ... persona | openrouter_test.js:12:19:12:35 | req.query.persona | openrouter_test.js:52:19:52:42 | "Talk l ... persona | This system prompt depends on a $@. | openrouter_test.js:12:19:12:35 | req.query.persona | user-provided value | @@ -109,6 +110,7 @@ edges | gemini_test.js:8:9:8:15 | persona | gemini_test.js:85:43:85:49 | persona | provenance | | | gemini_test.js:8:9:8:15 | persona | gemini_test.js:95:43:95:49 | persona | provenance | | | gemini_test.js:8:9:8:15 | persona | gemini_test.js:105:43:105:49 | persona | provenance | | +| gemini_test.js:8:9:8:15 | persona | gemini_test.js:119:43:119:49 | persona | provenance | | | gemini_test.js:8:19:8:35 | req.query.persona | gemini_test.js:8:9:8:15 | persona | provenance | | | gemini_test.js:18:43:18:49 | persona | gemini_test.js:18:26:18:49 | "Talk l ... persona | provenance | | | gemini_test.js:30:42:30:48 | persona | gemini_test.js:30:25:30:48 | "Talk l ... persona | provenance | | @@ -116,6 +118,7 @@ edges | gemini_test.js:85:43:85:49 | persona | gemini_test.js:85:26:85:49 | "Talk l ... persona | provenance | | | gemini_test.js:95:43:95:49 | persona | gemini_test.js:95:26:95:49 | "Talk l ... persona | provenance | | | gemini_test.js:105:43:105:49 | persona | gemini_test.js:105:26:105:49 | "Talk l ... persona | provenance | | +| gemini_test.js:119:43:119:49 | persona | gemini_test.js:119:26:119:49 | "Talk l ... persona | provenance | | | langchain_test.js:9:9:9:15 | persona | langchain_test.js:16:54:16:60 | persona | provenance | | | langchain_test.js:9:9:9:15 | persona | langchain_test.js:19:31:19:37 | persona | provenance | | | langchain_test.js:9:9:9:15 | persona | langchain_test.js:25:36:25:42 | persona | provenance | | @@ -130,13 +133,13 @@ edges | openai_test.js:11:9:11:15 | persona | openai_test.js:83:35:83:41 | persona | provenance | | | openai_test.js:11:9:11:15 | persona | openai_test.js:97:36:97:42 | persona | provenance | | | openai_test.js:11:9:11:15 | persona | openai_test.js:110:35:110:41 | persona | provenance | | -| openai_test.js:11:9:11:15 | persona | openai_test.js:120:30:120:36 | persona | provenance | | -| openai_test.js:11:9:11:15 | persona | openai_test.js:129:36:129:42 | persona | provenance | | -| openai_test.js:11:9:11:15 | persona | openai_test.js:134:36:134:42 | persona | provenance | | -| openai_test.js:11:9:11:15 | persona | openai_test.js:140:36:140:42 | persona | provenance | | -| openai_test.js:11:9:11:15 | persona | openai_test.js:146:52:146:58 | persona | provenance | | -| openai_test.js:11:9:11:15 | persona | openai_test.js:152:31:152:37 | persona | provenance | | -| openai_test.js:11:9:11:15 | persona | openai_test.js:164:49:164:55 | persona | provenance | | +| openai_test.js:11:9:11:15 | persona | openai_test.js:128:36:128:42 | persona | provenance | | +| openai_test.js:11:9:11:15 | persona | openai_test.js:137:36:137:42 | persona | provenance | | +| openai_test.js:11:9:11:15 | persona | openai_test.js:142:36:142:42 | persona | provenance | | +| openai_test.js:11:9:11:15 | persona | openai_test.js:148:36:148:42 | persona | provenance | | +| openai_test.js:11:9:11:15 | persona | openai_test.js:154:52:154:58 | persona | provenance | | +| openai_test.js:11:9:11:15 | persona | openai_test.js:160:31:160:37 | persona | provenance | | +| openai_test.js:11:9:11:15 | persona | openai_test.js:172:49:172:55 | persona | provenance | | | openai_test.js:11:19:11:35 | req.query.persona | openai_test.js:11:9:11:15 | persona | provenance | | | openai_test.js:19:36:19:42 | persona | openai_test.js:19:19:19:42 | "Talk l ... persona | provenance | | | openai_test.js:29:35:29:41 | persona | openai_test.js:29:18:29:41 | "Talk l ... persona | provenance | | @@ -145,13 +148,13 @@ edges | openai_test.js:83:35:83:41 | persona | openai_test.js:83:18:83:41 | "Talk l ... persona | provenance | | | openai_test.js:97:36:97:42 | persona | openai_test.js:97:19:97:42 | "Talk l ... persona | provenance | | | openai_test.js:110:35:110:41 | persona | openai_test.js:110:18:110:41 | "Talk l ... persona | provenance | | -| openai_test.js:120:30:120:36 | persona | openai_test.js:120:13:120:36 | "Talk l ... persona | provenance | | -| openai_test.js:129:36:129:42 | persona | openai_test.js:129:19:129:42 | "Talk l ... persona | provenance | | -| openai_test.js:134:36:134:42 | persona | openai_test.js:134:19:134:42 | "Talk l ... persona | provenance | | -| openai_test.js:140:36:140:42 | persona | openai_test.js:140:19:140:42 | "Talk l ... persona | provenance | | -| openai_test.js:146:52:146:58 | persona | openai_test.js:146:30:146:58 | "Also t ... persona | provenance | | -| openai_test.js:152:31:152:37 | persona | openai_test.js:152:14:152:37 | "Talk l ... persona | provenance | | -| openai_test.js:164:49:164:55 | persona | openai_test.js:164:32:164:55 | "Talk l ... persona | provenance | | +| openai_test.js:128:36:128:42 | persona | openai_test.js:128:19:128:42 | "Talk l ... persona | provenance | | +| openai_test.js:137:36:137:42 | persona | openai_test.js:137:19:137:42 | "Talk l ... persona | provenance | | +| openai_test.js:142:36:142:42 | persona | openai_test.js:142:19:142:42 | "Talk l ... persona | provenance | | +| openai_test.js:148:36:148:42 | persona | openai_test.js:148:19:148:42 | "Talk l ... persona | provenance | | +| openai_test.js:154:52:154:58 | persona | openai_test.js:154:30:154:58 | "Also t ... persona | provenance | | +| openai_test.js:160:31:160:37 | persona | openai_test.js:160:14:160:37 | "Talk l ... persona | provenance | | +| openai_test.js:172:49:172:55 | persona | openai_test.js:172:32:172:55 | "Talk l ... persona | provenance | | | openrouter_test.js:12:9:12:15 | persona | openrouter_test.js:23:35:23:41 | persona | provenance | | | openrouter_test.js:12:9:12:15 | persona | openrouter_test.js:38:35:38:41 | persona | provenance | | | openrouter_test.js:12:9:12:15 | persona | openrouter_test.js:52:36:52:42 | persona | provenance | | @@ -235,6 +238,8 @@ nodes | gemini_test.js:95:43:95:49 | persona | semmle.label | persona | | gemini_test.js:105:26:105:49 | "Talk l ... persona | semmle.label | "Talk l ... persona | | gemini_test.js:105:43:105:49 | persona | semmle.label | persona | +| gemini_test.js:119:26:119:49 | "Talk l ... persona | semmle.label | "Talk l ... persona | +| gemini_test.js:119:43:119:49 | persona | semmle.label | persona | | langchain_test.js:9:9:9:15 | persona | semmle.label | persona | | langchain_test.js:9:19:9:35 | req.query.persona | semmle.label | req.query.persona | | langchain_test.js:16:37:16:60 | "Talk l ... persona | semmle.label | "Talk l ... persona | @@ -259,20 +264,20 @@ nodes | openai_test.js:97:36:97:42 | persona | semmle.label | persona | | openai_test.js:110:18:110:41 | "Talk l ... persona | semmle.label | "Talk l ... persona | | openai_test.js:110:35:110:41 | persona | semmle.label | persona | -| openai_test.js:120:13:120:36 | "Talk l ... persona | semmle.label | "Talk l ... persona | -| openai_test.js:120:30:120:36 | persona | semmle.label | persona | -| openai_test.js:129:19:129:42 | "Talk l ... persona | semmle.label | "Talk l ... persona | -| openai_test.js:129:36:129:42 | persona | semmle.label | persona | -| openai_test.js:134:19:134:42 | "Talk l ... persona | semmle.label | "Talk l ... persona | -| openai_test.js:134:36:134:42 | persona | semmle.label | persona | -| openai_test.js:140:19:140:42 | "Talk l ... persona | semmle.label | "Talk l ... persona | -| openai_test.js:140:36:140:42 | persona | semmle.label | persona | -| openai_test.js:146:30:146:58 | "Also t ... persona | semmle.label | "Also t ... persona | -| openai_test.js:146:52:146:58 | persona | semmle.label | persona | -| openai_test.js:152:14:152:37 | "Talk l ... persona | semmle.label | "Talk l ... persona | -| openai_test.js:152:31:152:37 | persona | semmle.label | persona | -| openai_test.js:164:32:164:55 | "Talk l ... persona | semmle.label | "Talk l ... persona | -| openai_test.js:164:49:164:55 | persona | semmle.label | persona | +| openai_test.js:128:19:128:42 | "Talk l ... persona | semmle.label | "Talk l ... persona | +| openai_test.js:128:36:128:42 | persona | semmle.label | persona | +| openai_test.js:137:19:137:42 | "Talk l ... persona | semmle.label | "Talk l ... persona | +| openai_test.js:137:36:137:42 | persona | semmle.label | persona | +| openai_test.js:142:19:142:42 | "Talk l ... persona | semmle.label | "Talk l ... persona | +| openai_test.js:142:36:142:42 | persona | semmle.label | persona | +| openai_test.js:148:19:148:42 | "Talk l ... persona | semmle.label | "Talk l ... persona | +| openai_test.js:148:36:148:42 | persona | semmle.label | persona | +| openai_test.js:154:30:154:58 | "Also t ... persona | semmle.label | "Also t ... persona | +| openai_test.js:154:52:154:58 | persona | semmle.label | persona | +| openai_test.js:160:14:160:37 | "Talk l ... persona | semmle.label | "Talk l ... persona | +| openai_test.js:160:31:160:37 | persona | semmle.label | persona | +| openai_test.js:172:32:172:55 | "Talk l ... persona | semmle.label | "Talk l ... persona | +| openai_test.js:172:49:172:55 | persona | semmle.label | persona | | openrouter_test.js:12:9:12:15 | persona | semmle.label | persona | | openrouter_test.js:12:19:12:35 | req.query.persona | semmle.label | req.query.persona | | openrouter_test.js:23:18:23:41 | "Talk l ... persona | semmle.label | "Talk l ... persona | diff --git a/javascript/ql/test/Security/CWE-1427/SystemPromptInjection/gemini_test.js b/javascript/ql/test/Security/CWE-1427/SystemPromptInjection/gemini_test.js index f4b0a69820b..ce046d29ac6 100644 --- a/javascript/ql/test/Security/CWE-1427/SystemPromptInjection/gemini_test.js +++ b/javascript/ql/test/Security/CWE-1427/SystemPromptInjection/gemini_test.js @@ -109,6 +109,17 @@ app.get("/test", async (req, res) => { }, }); + // === caches.create: config.systemInstruction === + + // SHOULD ALERT + const cache = await ai.caches.create({ + model: "gemini-2.0-flash", + config: { + contents: "Some document to cache", + systemInstruction: "Talk like a " + persona, // $ Alert[js/system-prompt-injection] + }, + }); + // === Sanitizer: constant comparison === // SHOULD NOT ALERT diff --git a/javascript/ql/test/Security/CWE-1427/SystemPromptInjection/openai_test.js b/javascript/ql/test/Security/CWE-1427/SystemPromptInjection/openai_test.js index de872e0aa92..d8f524771bc 100644 --- a/javascript/ql/test/Security/CWE-1427/SystemPromptInjection/openai_test.js +++ b/javascript/ql/test/Security/CWE-1427/SystemPromptInjection/openai_test.js @@ -114,10 +114,18 @@ app.get("/test", async (req, res) => { // === Legacy Completions API === - // prompt (SHOULD ALERT) + // prompt (SHOULD NOT ALERT for system - reclassified as user-prompt-injection) const l1 = await client.completions.create({ model: "gpt-3.5-turbo-instruct", - prompt: "Talk like a " + persona, // $ Alert[js/system-prompt-injection] + prompt: "Talk like a " + persona, // OK - legacy completions prompt is a user-prompt-injection sink + }); + + // === Realtime API (beta) === + + // beta.realtime.sessions.create instructions (SHOULD ALERT) + const rt1 = await client.beta.realtime.sessions.create({ + model: "gpt-4o-realtime-preview", + instructions: "Talk like a " + persona, // $ Alert[js/system-prompt-injection] }); // === Assistants API (beta) === diff --git a/javascript/ql/test/Security/CWE-1427/UserPromptInjection/UserPromptInjection.expected b/javascript/ql/test/Security/CWE-1427/UserPromptInjection/UserPromptInjection.expected index d243ea58d81..e3adc857a8e 100644 --- a/javascript/ql/test/Security/CWE-1427/UserPromptInjection/UserPromptInjection.expected +++ b/javascript/ql/test/Security/CWE-1427/UserPromptInjection/UserPromptInjection.expected @@ -1,12 +1,14 @@ #select | anthropic_user_test.js:18:18:18:26 | userInput | anthropic_user_test.js:8:21:8:39 | req.query.userInput | anthropic_user_test.js:18:18:18:26 | userInput | This prompt construction depends on a $@. | anthropic_user_test.js:8:21:8:39 | req.query.userInput | user-provided value | | anthropic_user_test.js:31:18:31:26 | userInput | anthropic_user_test.js:8:21:8:39 | req.query.userInput | anthropic_user_test.js:31:18:31:26 | userInput | This prompt construction depends on a $@. | anthropic_user_test.js:8:21:8:39 | req.query.userInput | user-provided value | +| anthropic_user_test.js:41:13:41:51 | `\\n\\nHu ... stant:` | anthropic_user_test.js:8:21:8:39 | req.query.userInput | anthropic_user_test.js:41:13:41:51 | `\\n\\nHu ... stant:` | This prompt construction depends on a $@. | anthropic_user_test.js:8:21:8:39 | req.query.userInput | user-provided value | | gemini_user_test.js:14:15:14:23 | userInput | gemini_user_test.js:8:21:8:39 | req.query.userInput | gemini_user_test.js:14:15:14:23 | userInput | This prompt construction depends on a $@. | gemini_user_test.js:8:21:8:39 | req.query.userInput | user-provided value | | gemini_user_test.js:26:19:26:27 | userInput | gemini_user_test.js:8:21:8:39 | req.query.userInput | gemini_user_test.js:26:19:26:27 | userInput | This prompt construction depends on a $@. | gemini_user_test.js:8:21:8:39 | req.query.userInput | user-provided value | | gemini_user_test.js:37:15:37:23 | userInput | gemini_user_test.js:8:21:8:39 | req.query.userInput | gemini_user_test.js:37:15:37:23 | userInput | This prompt construction depends on a $@. | gemini_user_test.js:8:21:8:39 | req.query.userInput | user-provided value | | gemini_user_test.js:44:13:44:21 | userInput | gemini_user_test.js:8:21:8:39 | req.query.userInput | gemini_user_test.js:44:13:44:21 | userInput | This prompt construction depends on a $@. | gemini_user_test.js:8:21:8:39 | req.query.userInput | user-provided value | | gemini_user_test.js:51:13:51:21 | userInput | gemini_user_test.js:8:21:8:39 | req.query.userInput | gemini_user_test.js:51:13:51:21 | userInput | This prompt construction depends on a $@. | gemini_user_test.js:8:21:8:39 | req.query.userInput | user-provided value | | gemini_user_test.js:58:13:58:21 | userInput | gemini_user_test.js:8:21:8:39 | req.query.userInput | gemini_user_test.js:58:13:58:21 | userInput | This prompt construction depends on a $@. | gemini_user_test.js:8:21:8:39 | req.query.userInput | user-provided value | +| gemini_user_test.js:66:17:66:25 | userInput | gemini_user_test.js:8:21:8:39 | req.query.userInput | gemini_user_test.js:66:17:66:25 | userInput | This prompt construction depends on a $@. | gemini_user_test.js:8:21:8:39 | req.query.userInput | user-provided value | | langchain_user_test.js:18:26:18:34 | userInput | langchain_user_test.js:13:21:13:39 | req.query.userInput | langchain_user_test.js:18:26:18:34 | userInput | This prompt construction depends on a $@. | langchain_user_test.js:13:21:13:39 | req.query.userInput | user-provided value | | langchain_user_test.js:22:26:22:34 | userInput | langchain_user_test.js:13:21:13:39 | req.query.userInput | langchain_user_test.js:22:26:22:34 | userInput | This prompt construction depends on a $@. | langchain_user_test.js:13:21:13:39 | req.query.userInput | user-provided value | | langchain_user_test.js:26:24:26:32 | userInput | langchain_user_test.js:13:21:13:39 | req.query.userInput | langchain_user_test.js:26:24:26:32 | userInput | This prompt construction depends on a $@. | langchain_user_test.js:13:21:13:39 | req.query.userInput | user-provided value | @@ -31,15 +33,19 @@ | openai_user_test.js:67:13:67:21 | userInput | openai_user_test.js:15:21:15:39 | req.query.userInput | openai_user_test.js:67:13:67:21 | userInput | This prompt construction depends on a $@. | openai_user_test.js:15:21:15:39 | req.query.userInput | user-provided value | | openai_user_test.js:72:13:72:21 | userInput | openai_user_test.js:15:21:15:39 | req.query.userInput | openai_user_test.js:72:13:72:21 | userInput | This prompt construction depends on a $@. | openai_user_test.js:15:21:15:39 | req.query.userInput | user-provided value | | openai_user_test.js:76:13:76:21 | userInput | openai_user_test.js:15:21:15:39 | req.query.userInput | openai_user_test.js:76:13:76:21 | userInput | This prompt construction depends on a $@. | openai_user_test.js:15:21:15:39 | req.query.userInput | user-provided value | -| openai_user_test.js:83:13:83:21 | userInput | openai_user_test.js:15:21:15:39 | req.query.userInput | openai_user_test.js:83:13:83:21 | userInput | This prompt construction depends on a $@. | openai_user_test.js:15:21:15:39 | req.query.userInput | user-provided value | -| openai_user_test.js:89:13:89:21 | userInput | openai_user_test.js:15:21:15:39 | req.query.userInput | openai_user_test.js:89:13:89:21 | userInput | This prompt construction depends on a $@. | openai_user_test.js:15:21:15:39 | req.query.userInput | user-provided value | -| openai_user_test.js:95:14:95:22 | userInput | openai_user_test.js:15:21:15:39 | req.query.userInput | openai_user_test.js:95:14:95:22 | userInput | This prompt construction depends on a $@. | openai_user_test.js:15:21:15:39 | req.query.userInput | user-provided value | -| openai_user_test.js:101:12:101:20 | userInput | openai_user_test.js:15:21:15:39 | req.query.userInput | openai_user_test.js:101:12:101:20 | userInput | This prompt construction depends on a $@. | openai_user_test.js:15:21:15:39 | req.query.userInput | user-provided value | -| openai_user_test.js:148:12:148:20 | userInput | openai_user_test.js:15:21:15:39 | req.query.userInput | openai_user_test.js:148:12:148:20 | userInput | This prompt construction depends on a $@. | openai_user_test.js:15:21:15:39 | req.query.userInput | user-provided value | -| openai_user_test.js:192:20:192:28 | userInput | openai_user_test.js:15:21:15:39 | req.query.userInput | openai_user_test.js:192:20:192:28 | userInput | This prompt construction depends on a $@. | openai_user_test.js:15:21:15:39 | req.query.userInput | user-provided value | -| openai_user_test.js:196:30:196:38 | userInput | openai_user_test.js:15:21:15:39 | req.query.userInput | openai_user_test.js:196:30:196:38 | userInput | This prompt construction depends on a $@. | openai_user_test.js:15:21:15:39 | req.query.userInput | user-provided value | -| openai_user_test.js:201:27:201:35 | userInput | openai_user_test.js:15:21:15:39 | req.query.userInput | openai_user_test.js:201:27:201:35 | userInput | This prompt construction depends on a $@. | openai_user_test.js:15:21:15:39 | req.query.userInput | user-provided value | -| openai_user_test.js:205:30:205:38 | userInput | openai_user_test.js:15:21:15:39 | req.query.userInput | openai_user_test.js:205:30:205:38 | userInput | This prompt construction depends on a $@. | openai_user_test.js:15:21:15:39 | req.query.userInput | user-provided value | +| openai_user_test.js:82:13:82:21 | userInput | openai_user_test.js:15:21:15:39 | req.query.userInput | openai_user_test.js:82:13:82:21 | userInput | This prompt construction depends on a $@. | openai_user_test.js:15:21:15:39 | req.query.userInput | user-provided value | +| openai_user_test.js:86:13:86:21 | userInput | openai_user_test.js:15:21:15:39 | req.query.userInput | openai_user_test.js:86:13:86:21 | userInput | This prompt construction depends on a $@. | openai_user_test.js:15:21:15:39 | req.query.userInput | user-provided value | +| openai_user_test.js:90:13:90:21 | userInput | openai_user_test.js:15:21:15:39 | req.query.userInput | openai_user_test.js:90:13:90:21 | userInput | This prompt construction depends on a $@. | openai_user_test.js:15:21:15:39 | req.query.userInput | user-provided value | +| openai_user_test.js:96:13:96:21 | userInput | openai_user_test.js:15:21:15:39 | req.query.userInput | openai_user_test.js:96:13:96:21 | userInput | This prompt construction depends on a $@. | openai_user_test.js:15:21:15:39 | req.query.userInput | user-provided value | +| openai_user_test.js:103:13:103:21 | userInput | openai_user_test.js:15:21:15:39 | req.query.userInput | openai_user_test.js:103:13:103:21 | userInput | This prompt construction depends on a $@. | openai_user_test.js:15:21:15:39 | req.query.userInput | user-provided value | +| openai_user_test.js:109:13:109:21 | userInput | openai_user_test.js:15:21:15:39 | req.query.userInput | openai_user_test.js:109:13:109:21 | userInput | This prompt construction depends on a $@. | openai_user_test.js:15:21:15:39 | req.query.userInput | user-provided value | +| openai_user_test.js:115:14:115:22 | userInput | openai_user_test.js:15:21:15:39 | req.query.userInput | openai_user_test.js:115:14:115:22 | userInput | This prompt construction depends on a $@. | openai_user_test.js:15:21:15:39 | req.query.userInput | user-provided value | +| openai_user_test.js:121:12:121:20 | userInput | openai_user_test.js:15:21:15:39 | req.query.userInput | openai_user_test.js:121:12:121:20 | userInput | This prompt construction depends on a $@. | openai_user_test.js:15:21:15:39 | req.query.userInput | user-provided value | +| openai_user_test.js:168:12:168:20 | userInput | openai_user_test.js:15:21:15:39 | req.query.userInput | openai_user_test.js:168:12:168:20 | userInput | This prompt construction depends on a $@. | openai_user_test.js:15:21:15:39 | req.query.userInput | user-provided value | +| openai_user_test.js:212:20:212:28 | userInput | openai_user_test.js:15:21:15:39 | req.query.userInput | openai_user_test.js:212:20:212:28 | userInput | This prompt construction depends on a $@. | openai_user_test.js:15:21:15:39 | req.query.userInput | user-provided value | +| openai_user_test.js:216:30:216:38 | userInput | openai_user_test.js:15:21:15:39 | req.query.userInput | openai_user_test.js:216:30:216:38 | userInput | This prompt construction depends on a $@. | openai_user_test.js:15:21:15:39 | req.query.userInput | user-provided value | +| openai_user_test.js:221:27:221:35 | userInput | openai_user_test.js:15:21:15:39 | req.query.userInput | openai_user_test.js:221:27:221:35 | userInput | This prompt construction depends on a $@. | openai_user_test.js:15:21:15:39 | req.query.userInput | user-provided value | +| openai_user_test.js:225:30:225:38 | userInput | openai_user_test.js:15:21:15:39 | req.query.userInput | openai_user_test.js:225:30:225:38 | userInput | This prompt construction depends on a $@. | openai_user_test.js:15:21:15:39 | req.query.userInput | user-provided value | | openrouter_user_test.js:22:18:22:26 | userInput | openrouter_user_test.js:12:21:12:39 | req.query.userInput | openrouter_user_test.js:22:18:22:26 | userInput | This prompt construction depends on a $@. | openrouter_user_test.js:12:21:12:39 | req.query.userInput | user-provided value | | openrouter_user_test.js:36:19:36:27 | userInput | openrouter_user_test.js:12:21:12:39 | req.query.userInput | openrouter_user_test.js:36:19:36:27 | userInput | This prompt construction depends on a $@. | openrouter_user_test.js:12:21:12:39 | req.query.userInput | user-provided value | | openrouter_user_test.js:50:18:50:26 | userInput | openrouter_user_test.js:12:21:12:39 | req.query.userInput | openrouter_user_test.js:50:18:50:26 | userInput | This prompt construction depends on a $@. | openrouter_user_test.js:12:21:12:39 | req.query.userInput | user-provided value | @@ -51,13 +57,16 @@ edges | anthropic_user_test.js:8:9:8:17 | userInput | anthropic_user_test.js:18:18:18:26 | userInput | provenance | | | anthropic_user_test.js:8:9:8:17 | userInput | anthropic_user_test.js:31:18:31:26 | userInput | provenance | | +| anthropic_user_test.js:8:9:8:17 | userInput | anthropic_user_test.js:41:27:41:35 | userInput | provenance | | | anthropic_user_test.js:8:21:8:39 | req.query.userInput | anthropic_user_test.js:8:9:8:17 | userInput | provenance | | +| anthropic_user_test.js:41:27:41:35 | userInput | anthropic_user_test.js:41:13:41:51 | `\\n\\nHu ... stant:` | provenance | | | gemini_user_test.js:8:9:8:17 | userInput | gemini_user_test.js:14:15:14:23 | userInput | provenance | | | gemini_user_test.js:8:9:8:17 | userInput | gemini_user_test.js:26:19:26:27 | userInput | provenance | | | gemini_user_test.js:8:9:8:17 | userInput | gemini_user_test.js:37:15:37:23 | userInput | provenance | | | gemini_user_test.js:8:9:8:17 | userInput | gemini_user_test.js:44:13:44:21 | userInput | provenance | | | gemini_user_test.js:8:9:8:17 | userInput | gemini_user_test.js:51:13:51:21 | userInput | provenance | | | gemini_user_test.js:8:9:8:17 | userInput | gemini_user_test.js:58:13:58:21 | userInput | provenance | | +| gemini_user_test.js:8:9:8:17 | userInput | gemini_user_test.js:66:17:66:25 | userInput | provenance | | | gemini_user_test.js:8:21:8:39 | req.query.userInput | gemini_user_test.js:8:9:8:17 | userInput | provenance | | | langchain_user_test.js:13:9:13:17 | userInput | langchain_user_test.js:18:26:18:34 | userInput | provenance | | | langchain_user_test.js:13:9:13:17 | userInput | langchain_user_test.js:22:26:22:34 | userInput | provenance | | @@ -84,15 +93,19 @@ edges | openai_user_test.js:15:9:15:17 | userInput | openai_user_test.js:67:13:67:21 | userInput | provenance | | | openai_user_test.js:15:9:15:17 | userInput | openai_user_test.js:72:13:72:21 | userInput | provenance | | | openai_user_test.js:15:9:15:17 | userInput | openai_user_test.js:76:13:76:21 | userInput | provenance | | -| openai_user_test.js:15:9:15:17 | userInput | openai_user_test.js:83:13:83:21 | userInput | provenance | | -| openai_user_test.js:15:9:15:17 | userInput | openai_user_test.js:89:13:89:21 | userInput | provenance | | -| openai_user_test.js:15:9:15:17 | userInput | openai_user_test.js:95:14:95:22 | userInput | provenance | | -| openai_user_test.js:15:9:15:17 | userInput | openai_user_test.js:101:12:101:20 | userInput | provenance | | -| openai_user_test.js:15:9:15:17 | userInput | openai_user_test.js:148:12:148:20 | userInput | provenance | | -| openai_user_test.js:15:9:15:17 | userInput | openai_user_test.js:192:20:192:28 | userInput | provenance | | -| openai_user_test.js:15:9:15:17 | userInput | openai_user_test.js:196:30:196:38 | userInput | provenance | | -| openai_user_test.js:15:9:15:17 | userInput | openai_user_test.js:201:27:201:35 | userInput | provenance | | -| openai_user_test.js:15:9:15:17 | userInput | openai_user_test.js:205:30:205:38 | userInput | provenance | | +| openai_user_test.js:15:9:15:17 | userInput | openai_user_test.js:82:13:82:21 | userInput | provenance | | +| openai_user_test.js:15:9:15:17 | userInput | openai_user_test.js:86:13:86:21 | userInput | provenance | | +| openai_user_test.js:15:9:15:17 | userInput | openai_user_test.js:90:13:90:21 | userInput | provenance | | +| openai_user_test.js:15:9:15:17 | userInput | openai_user_test.js:96:13:96:21 | userInput | provenance | | +| openai_user_test.js:15:9:15:17 | userInput | openai_user_test.js:103:13:103:21 | userInput | provenance | | +| openai_user_test.js:15:9:15:17 | userInput | openai_user_test.js:109:13:109:21 | userInput | provenance | | +| openai_user_test.js:15:9:15:17 | userInput | openai_user_test.js:115:14:115:22 | userInput | provenance | | +| openai_user_test.js:15:9:15:17 | userInput | openai_user_test.js:121:12:121:20 | userInput | provenance | | +| openai_user_test.js:15:9:15:17 | userInput | openai_user_test.js:168:12:168:20 | userInput | provenance | | +| openai_user_test.js:15:9:15:17 | userInput | openai_user_test.js:212:20:212:28 | userInput | provenance | | +| openai_user_test.js:15:9:15:17 | userInput | openai_user_test.js:216:30:216:38 | userInput | provenance | | +| openai_user_test.js:15:9:15:17 | userInput | openai_user_test.js:221:27:221:35 | userInput | provenance | | +| openai_user_test.js:15:9:15:17 | userInput | openai_user_test.js:225:30:225:38 | userInput | provenance | | | openai_user_test.js:15:21:15:39 | req.query.userInput | openai_user_test.js:15:9:15:17 | userInput | provenance | | | openrouter_user_test.js:12:9:12:17 | userInput | openrouter_user_test.js:22:18:22:26 | userInput | provenance | | | openrouter_user_test.js:12:9:12:17 | userInput | openrouter_user_test.js:36:19:36:27 | userInput | provenance | | @@ -108,6 +121,8 @@ nodes | anthropic_user_test.js:8:21:8:39 | req.query.userInput | semmle.label | req.query.userInput | | anthropic_user_test.js:18:18:18:26 | userInput | semmle.label | userInput | | anthropic_user_test.js:31:18:31:26 | userInput | semmle.label | userInput | +| anthropic_user_test.js:41:13:41:51 | `\\n\\nHu ... stant:` | semmle.label | `\\n\\nHu ... stant:` | +| anthropic_user_test.js:41:27:41:35 | userInput | semmle.label | userInput | | gemini_user_test.js:8:9:8:17 | userInput | semmle.label | userInput | | gemini_user_test.js:8:21:8:39 | req.query.userInput | semmle.label | req.query.userInput | | gemini_user_test.js:14:15:14:23 | userInput | semmle.label | userInput | @@ -116,6 +131,7 @@ nodes | gemini_user_test.js:44:13:44:21 | userInput | semmle.label | userInput | | gemini_user_test.js:51:13:51:21 | userInput | semmle.label | userInput | | gemini_user_test.js:58:13:58:21 | userInput | semmle.label | userInput | +| gemini_user_test.js:66:17:66:25 | userInput | semmle.label | userInput | | langchain_user_test.js:13:9:13:17 | userInput | semmle.label | userInput | | langchain_user_test.js:13:21:13:39 | req.query.userInput | semmle.label | req.query.userInput | | langchain_user_test.js:18:26:18:34 | userInput | semmle.label | userInput | @@ -144,15 +160,19 @@ nodes | openai_user_test.js:67:13:67:21 | userInput | semmle.label | userInput | | openai_user_test.js:72:13:72:21 | userInput | semmle.label | userInput | | openai_user_test.js:76:13:76:21 | userInput | semmle.label | userInput | -| openai_user_test.js:83:13:83:21 | userInput | semmle.label | userInput | -| openai_user_test.js:89:13:89:21 | userInput | semmle.label | userInput | -| openai_user_test.js:95:14:95:22 | userInput | semmle.label | userInput | -| openai_user_test.js:101:12:101:20 | userInput | semmle.label | userInput | -| openai_user_test.js:148:12:148:20 | userInput | semmle.label | userInput | -| openai_user_test.js:192:20:192:28 | userInput | semmle.label | userInput | -| openai_user_test.js:196:30:196:38 | userInput | semmle.label | userInput | -| openai_user_test.js:201:27:201:35 | userInput | semmle.label | userInput | -| openai_user_test.js:205:30:205:38 | userInput | semmle.label | userInput | +| openai_user_test.js:82:13:82:21 | userInput | semmle.label | userInput | +| openai_user_test.js:86:13:86:21 | userInput | semmle.label | userInput | +| openai_user_test.js:90:13:90:21 | userInput | semmle.label | userInput | +| openai_user_test.js:96:13:96:21 | userInput | semmle.label | userInput | +| openai_user_test.js:103:13:103:21 | userInput | semmle.label | userInput | +| openai_user_test.js:109:13:109:21 | userInput | semmle.label | userInput | +| openai_user_test.js:115:14:115:22 | userInput | semmle.label | userInput | +| openai_user_test.js:121:12:121:20 | userInput | semmle.label | userInput | +| openai_user_test.js:168:12:168:20 | userInput | semmle.label | userInput | +| openai_user_test.js:212:20:212:28 | userInput | semmle.label | userInput | +| openai_user_test.js:216:30:216:38 | userInput | semmle.label | userInput | +| openai_user_test.js:221:27:221:35 | userInput | semmle.label | userInput | +| openai_user_test.js:225:30:225:38 | userInput | semmle.label | userInput | | openrouter_user_test.js:12:9:12:17 | userInput | semmle.label | userInput | | openrouter_user_test.js:12:21:12:39 | req.query.userInput | semmle.label | req.query.userInput | | openrouter_user_test.js:22:18:22:26 | userInput | semmle.label | userInput | diff --git a/javascript/ql/test/Security/CWE-1427/UserPromptInjection/anthropic_user_test.js b/javascript/ql/test/Security/CWE-1427/UserPromptInjection/anthropic_user_test.js index 1c269b650be..a0c9514aa0e 100644 --- a/javascript/ql/test/Security/CWE-1427/UserPromptInjection/anthropic_user_test.js +++ b/javascript/ql/test/Security/CWE-1427/UserPromptInjection/anthropic_user_test.js @@ -33,6 +33,14 @@ app.get("/test", async (req, res) => { ], }); + // === Legacy Text Completions API (SHOULD ALERT) === + + await client.completions.create({ + model: "claude-2.1", + max_tokens_to_sample: 1024, + prompt: `\n\nHuman: ${userInput}\n\nAssistant:`, // $ Alert[js/user-prompt-injection] + }); + // === Constant comparison sanitizer (SHOULD NOT ALERT) === const userInput2 = req.query.userInput2; diff --git a/javascript/ql/test/Security/CWE-1427/UserPromptInjection/gemini_user_test.js b/javascript/ql/test/Security/CWE-1427/UserPromptInjection/gemini_user_test.js index f38da3a418c..32ed4299575 100644 --- a/javascript/ql/test/Security/CWE-1427/UserPromptInjection/gemini_user_test.js +++ b/javascript/ql/test/Security/CWE-1427/UserPromptInjection/gemini_user_test.js @@ -58,6 +58,15 @@ app.get("/test", async (req, res) => { prompt: userInput, // $ Alert[js/user-prompt-injection] }); + // === caches.create: config.contents (SHOULD ALERT) === + + await ai.caches.create({ + model: "gemini-2.0-flash", + config: { + contents: userInput, // $ Alert[js/user-prompt-injection] + }, + }); + // === Constant comparison sanitizer (SHOULD NOT ALERT) === const userInput2 = req.query.userInput2; diff --git a/javascript/ql/test/Security/CWE-1427/UserPromptInjection/openai_user_test.js b/javascript/ql/test/Security/CWE-1427/UserPromptInjection/openai_user_test.js index 98e9dfcf6dc..f4240679d7d 100644 --- a/javascript/ql/test/Security/CWE-1427/UserPromptInjection/openai_user_test.js +++ b/javascript/ql/test/Security/CWE-1427/UserPromptInjection/openai_user_test.js @@ -76,6 +76,26 @@ app.get("/test", async (req, res) => { prompt: userInput, // $ Alert[js/user-prompt-injection] }); + // Videos API (Sora) + await client.videos.create({ + model: "sora-2", + prompt: userInput, // $ Alert[js/user-prompt-injection] + }); + + await client.videos.edit({ + prompt: userInput, // $ Alert[js/user-prompt-injection] + }); + + await client.videos.remix("video_123", { + prompt: userInput, // $ Alert[js/user-prompt-injection] + }); + + await client.videos.extend({ + video: { id: "video_123" }, + seconds: 4, + prompt: userInput, // $ Alert[js/user-prompt-injection] + }); + // Audio API await client.audio.transcriptions.create({ file: "audio.mp3", diff --git a/javascript/ql/test/query-tests/Security/CWE-020/MissingOriginCheck/Angular.ts b/javascript/ql/test/query-tests/Security/CWE-020/MissingOriginCheck/Angular.ts new file mode 100644 index 00000000000..3a6695a0f65 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-020/MissingOriginCheck/Angular.ts @@ -0,0 +1,29 @@ +import { Component, HostListener } from '@angular/core'; + +@Component({ selector: 'app-root' }) +class AngularComponent { + // Angular registers this as a `window` message handler via the decorator, + // equivalent to `window.addEventListener('message', ...)`. + @HostListener('window:message', ['$event']) + onWindowMessage(event: MessageEvent): void { // $ Alert - no origin check + eval(event.data); + } + + @HostListener('document:message', ['$event']) + onDocumentMessage(event: MessageEvent): void { // $ Alert - no origin check + eval(event.data); + } + + @HostListener('window:message', ['$event']) + onCheckedMessage(event: MessageEvent): void { // OK - has an origin check + if (event.origin === 'https://www.example.com') { + eval(event.data); + } + } + + // Not a message event, so it is not a postMessage handler. + @HostListener('window:resize', ['$event']) + onResize(event: MessageEvent): void { // OK - not a message handler + eval(event.data); + } +} diff --git a/javascript/ql/test/query-tests/Security/CWE-020/MissingOriginCheck/MissingOriginCheck.expected b/javascript/ql/test/query-tests/Security/CWE-020/MissingOriginCheck/MissingOriginCheck.expected index 58fb6ce7997..718826f8225 100644 --- a/javascript/ql/test/query-tests/Security/CWE-020/MissingOriginCheck/MissingOriginCheck.expected +++ b/javascript/ql/test/query-tests/Security/CWE-020/MissingOriginCheck/MissingOriginCheck.expected @@ -1,3 +1,5 @@ +| Angular.ts:8:19:8:23 | event | Postmessage handler has no origin check. | +| Angular.ts:13:21:13:25 | event | Postmessage handler has no origin check. | | tst.js:11:20:11:24 | event | Postmessage handler has no origin check. | | tst.js:24:27:24:27 | e | Postmessage handler has no origin check. | | tst.js:40:27:40:27 | e | Postmessage handler has no origin check. | diff --git a/misc/suite-helpers/CHANGELOG.md b/misc/suite-helpers/CHANGELOG.md index 8f96c9ba8dd..b73e8234a5b 100644 --- a/misc/suite-helpers/CHANGELOG.md +++ b/misc/suite-helpers/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.52 + +No user-facing changes. + ## 1.0.51 No user-facing changes. diff --git a/misc/suite-helpers/change-notes/released/1.0.52.md b/misc/suite-helpers/change-notes/released/1.0.52.md new file mode 100644 index 00000000000..a91f5a8025d --- /dev/null +++ b/misc/suite-helpers/change-notes/released/1.0.52.md @@ -0,0 +1,3 @@ +## 1.0.52 + +No user-facing changes. diff --git a/misc/suite-helpers/codeql-pack.release.yml b/misc/suite-helpers/codeql-pack.release.yml index 232dbe38ec8..ea1d2eed4d2 100644 --- a/misc/suite-helpers/codeql-pack.release.yml +++ b/misc/suite-helpers/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.0.51 +lastReleaseVersion: 1.0.52 diff --git a/misc/suite-helpers/qlpack.yml b/misc/suite-helpers/qlpack.yml index 7ac4b0e1dc3..0dafb086b74 100644 --- a/misc/suite-helpers/qlpack.yml +++ b/misc/suite-helpers/qlpack.yml @@ -1,4 +1,4 @@ name: codeql/suite-helpers -version: 1.0.52-dev +version: 1.0.53-dev groups: shared warnOnImplicitThis: true diff --git a/python/ql/lib/CHANGELOG.md b/python/ql/lib/CHANGELOG.md index 99e46d2808a..7d4f024be7a 100644 --- a/python/ql/lib/CHANGELOG.md +++ b/python/ql/lib/CHANGELOG.md @@ -1,3 +1,16 @@ +## 7.2.0 + +### Deprecated APIs + +* The `Function.getAReturnValueFlowNode()` predicate has been deprecated. Bind a `Return` node explicitly instead — `exists(Return ret | ret.getScope() = f and n.getNode() = ret.getValue())`. This is a preparatory step towards migrating the dataflow library off the legacy CFG; it has no semantic effect. +* The `AstNode.getAFlowNode()` predicate has been deprecated. Use `ControlFlowNode.getNode()` from the other direction instead: replace `e.getAFlowNode() = n` with `n.getNode() = e`. This is a preparatory step towards migrating the dataflow library off the legacy CFG; it has no semantic effect. + +### Minor Analysis Improvements + +* Python type tracking now follows values stored in instance attributes such as `self.attr` across instance methods, including across a class hierarchy (for example, a value stored on `self.attr` in a base class and read in a subclass, or vice versa). As a result, analysis is more likely to recognize user-defined objects that are stored on `self` and used later in other methods, which may produce additional results. +* Simplified the internal predicates that detect `@staticmethod`, `@classmethod` and `@property` decorators to match the decorator's AST `Name` directly, rather than going through the CFG and requiring the name to resolve globally. Code that shadows these three builtin decorators at the module-scope will now be classified by the decorator name alone; in practice, shadowing these names is extremely rare and the call-graph results are unchanged. +* Python taint tracking is now more precise for values flowing through container contents, such as list, set, tuple, and dictionary elements. This may remove some false positive alerts. + ## 7.1.2 ### Minor Analysis Improvements diff --git a/python/ql/lib/LegacyPointsTo.qll b/python/ql/lib/LegacyPointsTo.qll index ffea2d93b66..f5ad67a3c55 100644 --- a/python/ql/lib/LegacyPointsTo.qll +++ b/python/ql/lib/LegacyPointsTo.qll @@ -213,9 +213,11 @@ class ExprWithPointsTo extends Expr { * Gets what this expression might "refer-to" in the given `context`. */ predicate refersTo(Context context, Object obj, ClassObject cls, AstNode origin) { - this.getAFlowNode() - .(ControlFlowNodeWithPointsTo) - .refersTo(context, obj, cls, origin.getAFlowNode()) + exists(ControlFlowNode this_, ControlFlowNode origin_ | + this_.getNode() = this and origin_.getNode() = origin + | + this_.(ControlFlowNodeWithPointsTo).refersTo(context, obj, cls, origin_) + ) } /** @@ -226,7 +228,11 @@ class ExprWithPointsTo extends Expr { */ pragma[nomagic] predicate refersTo(Object obj, AstNode origin) { - this.getAFlowNode().(ControlFlowNodeWithPointsTo).refersTo(obj, origin.getAFlowNode()) + exists(ControlFlowNode this_, ControlFlowNode origin_ | + this_.getNode() = this and origin_.getNode() = origin + | + this_.(ControlFlowNodeWithPointsTo).refersTo(obj, origin_) + ) } /** @@ -240,16 +246,22 @@ class ExprWithPointsTo extends Expr { * in the given `context`. */ predicate pointsTo(Context context, Value value, AstNode origin) { - this.getAFlowNode() - .(ControlFlowNodeWithPointsTo) - .pointsTo(context, value, origin.getAFlowNode()) + exists(ControlFlowNode this_, ControlFlowNode origin_ | + this_.getNode() = this and origin_.getNode() = origin + | + this_.(ControlFlowNodeWithPointsTo).pointsTo(context, value, origin_) + ) } /** * Holds if this expression might "point-to" to `value` which is from `origin`. */ predicate pointsTo(Value value, AstNode origin) { - this.getAFlowNode().(ControlFlowNodeWithPointsTo).pointsTo(value, origin.getAFlowNode()) + exists(ControlFlowNode this_, ControlFlowNode origin_ | + this_.getNode() = this and origin_.getNode() = origin + | + this_.(ControlFlowNodeWithPointsTo).pointsTo(value, origin_) + ) } /** @@ -475,7 +487,10 @@ class FunctionMetricsWithPointsTo extends FunctionMetrics { not non_coupling_method(result) and exists(Call call | call.getScope() = this | exists(FunctionObject callee | callee.getFunction() = result | - call.getAFlowNode().getFunction().(ControlFlowNodeWithPointsTo).refersTo(callee) + exists(CallNode call_ | + call_.getNode() = call and + call_.getFunction().(ControlFlowNodeWithPointsTo).refersTo(callee) + ) ) or exists(Attribute a | call.getFunc() = a | diff --git a/python/ql/lib/analysis/DefinitionTracking.qll b/python/ql/lib/analysis/DefinitionTracking.qll index 21155970375..583a7807ff2 100644 --- a/python/ql/lib/analysis/DefinitionTracking.qll +++ b/python/ql/lib/analysis/DefinitionTracking.qll @@ -64,7 +64,7 @@ private predicate jump_to_defn(ControlFlowNode use, Definition defn) { private predicate preferred_jump_to_defn(Expr use, Definition def) { not use instanceof ClassExpr and not use instanceof FunctionExpr and - jump_to_defn(use.getAFlowNode(), def) + exists(ControlFlowNode useNode | useNode.getNode() = use | jump_to_defn(useNode, def)) } private predicate unique_jump_to_defn(Expr use, Definition def) { @@ -452,7 +452,7 @@ private predicate self_parameter_jump_to_defn_attribute( * This exists primarily for testing use `getPreferredDefinition()` instead. */ Definition getADefinition(Expr use) { - jump_to_defn(use.getAFlowNode(), result) and + exists(ControlFlowNode useNode | useNode.getNode() = use | jump_to_defn(useNode, result)) and not use instanceof Call and not use.isArtificial() and // Not the use itself diff --git a/python/ql/lib/change-notes/2026-05-19-flask-subclasses.md b/python/ql/lib/change-notes/2026-05-19-flask-subclasses.md new file mode 100644 index 00000000000..e0288351ddc --- /dev/null +++ b/python/ql/lib/change-notes/2026-05-19-flask-subclasses.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* `Flask::FlaskApp::instance()` will now also return instances of subclasses defined in the source tree. Previously, these were filtered out. `Flask::FlaskApp::classRef()` has been deprecated in favor of `Flask::FlaskApp::subclassRef()` since it already returned some subclasses. \ No newline at end of file diff --git a/python/ql/lib/change-notes/2026-05-28-remove-imprecise-containter-steps.md b/python/ql/lib/change-notes/2026-05-28-remove-imprecise-containter-steps.md deleted file mode 100644 index 25c664d6c05..00000000000 --- a/python/ql/lib/change-notes/2026-05-28-remove-imprecise-containter-steps.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: minorAnalysis ---- -* Python taint tracking is now more precise for values flowing through container contents, such as list, set, tuple, and dictionary elements. This may remove some false positive alerts. diff --git a/python/ql/lib/change-notes/2026-06-01-decorator-predicate-simplification.md b/python/ql/lib/change-notes/2026-06-01-decorator-predicate-simplification.md deleted file mode 100644 index 44ee5b5ff80..00000000000 --- a/python/ql/lib/change-notes/2026-06-01-decorator-predicate-simplification.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: minorAnalysis ---- -* Simplified the internal predicates that detect `@staticmethod`, `@classmethod` and `@property` decorators to match the decorator's AST `Name` directly, rather than going through the CFG and requiring the name to resolve globally. Code that shadows these three builtin decorators at the module-scope will now be classified by the decorator name alone; in practice, shadowing these names is extremely rare and the call-graph results are unchanged. diff --git a/python/ql/lib/change-notes/2026-06-11-fix-type-tracking-instance-attributes.md b/python/ql/lib/change-notes/2026-06-11-fix-type-tracking-instance-attributes.md deleted file mode 100644 index da7b752ad67..00000000000 --- a/python/ql/lib/change-notes/2026-06-11-fix-type-tracking-instance-attributes.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: minorAnalysis ---- -* Python type tracking now follows values stored in instance attributes such as `self.attr` across instance methods, including across a class hierarchy (for example, a value stored on `self.attr` in a base class and read in a subclass, or vice versa). As a result, analysis is more likely to recognize user-defined objects that are stored on `self` and used later in other methods, which may produce additional results. diff --git a/python/ql/lib/change-notes/released/7.2.0.md b/python/ql/lib/change-notes/released/7.2.0.md new file mode 100644 index 00000000000..93c31d28ab1 --- /dev/null +++ b/python/ql/lib/change-notes/released/7.2.0.md @@ -0,0 +1,12 @@ +## 7.2.0 + +### Deprecated APIs + +* The `Function.getAReturnValueFlowNode()` predicate has been deprecated. Bind a `Return` node explicitly instead — `exists(Return ret | ret.getScope() = f and n.getNode() = ret.getValue())`. This is a preparatory step towards migrating the dataflow library off the legacy CFG; it has no semantic effect. +* The `AstNode.getAFlowNode()` predicate has been deprecated. Use `ControlFlowNode.getNode()` from the other direction instead: replace `e.getAFlowNode() = n` with `n.getNode() = e`. This is a preparatory step towards migrating the dataflow library off the legacy CFG; it has no semantic effect. + +### Minor Analysis Improvements + +* Python type tracking now follows values stored in instance attributes such as `self.attr` across instance methods, including across a class hierarchy (for example, a value stored on `self.attr` in a base class and read in a subclass, or vice versa). As a result, analysis is more likely to recognize user-defined objects that are stored on `self` and used later in other methods, which may produce additional results. +* Simplified the internal predicates that detect `@staticmethod`, `@classmethod` and `@property` decorators to match the decorator's AST `Name` directly, rather than going through the CFG and requiring the name to resolve globally. Code that shadows these three builtin decorators at the module-scope will now be classified by the decorator name alone; in practice, shadowing these names is extremely rare and the call-graph results are unchanged. +* Python taint tracking is now more precise for values flowing through container contents, such as list, set, tuple, and dictionary elements. This may remove some false positive alerts. diff --git a/python/ql/lib/codeql-pack.release.yml b/python/ql/lib/codeql-pack.release.yml index 547681cc440..fda9ea165fc 100644 --- a/python/ql/lib/codeql-pack.release.yml +++ b/python/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 7.1.2 +lastReleaseVersion: 7.2.0 diff --git a/python/ql/lib/qlpack.yml b/python/ql/lib/qlpack.yml index 210e683a54f..506fd493c79 100644 --- a/python/ql/lib/qlpack.yml +++ b/python/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/python-all -version: 7.1.3-dev +version: 7.2.1-dev groups: python dbscheme: semmlecode.python.dbscheme extractor: python diff --git a/python/ql/lib/semmle/python/AstExtended.qll b/python/ql/lib/semmle/python/AstExtended.qll index 13da4e899a7..2adad68f0b4 100644 --- a/python/ql/lib/semmle/python/AstExtended.qll +++ b/python/ql/lib/semmle/python/AstExtended.qll @@ -17,12 +17,17 @@ abstract class AstNode extends AstNode_ { abstract Scope getScope(); /** + * DEPRECATED: use `ControlFlowNode.getNode()` from the other direction instead; + * that is, replace `e.getAFlowNode() = n` with `n.getNode() = e`. This API is + * being removed to untangle the AST and CFG hierarchies in preparation for + * migrating the dataflow library off the legacy CFG. + * * Gets a flow node corresponding directly to this node. * NOTE: For some statements and other purely syntactic elements, - * there may not be a `ControlFlowNode` + * there may not be a `ControlFlowNode`. */ cached - ControlFlowNode getAFlowNode() { + deprecated ControlFlowNode getAFlowNode() { Stages::AST::ref() and py_flow_bb_node(result, this, _, _) } diff --git a/python/ql/lib/semmle/python/Exprs.qll b/python/ql/lib/semmle/python/Exprs.qll index 6ab9f8d8340..937c9e5ffd7 100644 --- a/python/ql/lib/semmle/python/Exprs.qll +++ b/python/ql/lib/semmle/python/Exprs.qll @@ -28,7 +28,9 @@ class Expr extends Expr_, AstNode { /** Whether this expression may have a side effect (as determined purely from its syntax) */ predicate hasSideEffects() { /* If an exception raised by this expression handled, count that as a side effect */ - this.getAFlowNode().getASuccessor().getNode() instanceof ExceptStmt + exists(ControlFlowNode n | n.getNode() = this | + n.getASuccessor().getNode() instanceof ExceptStmt + ) or this.getASubExpression().hasSideEffects() } @@ -68,7 +70,7 @@ class Attribute extends Attribute_ { /* syntax: Expr.name */ override Expr getASubExpression() { result = this.getObject() } - override AttrNode getAFlowNode() { result = super.getAFlowNode() } + deprecated override AttrNode getAFlowNode() { result = super.getAFlowNode() } /** Gets the name of this attribute. That is the `name` in `obj.name` */ string getName() { result = Attribute_.super.getAttr() } @@ -97,7 +99,7 @@ class Subscript extends Subscript_ { Expr getObject() { result = Subscript_.super.getValue() } - override SubscriptNode getAFlowNode() { result = super.getAFlowNode() } + deprecated override SubscriptNode getAFlowNode() { result = super.getAFlowNode() } } /** A call expression, such as `func(...)` */ @@ -113,7 +115,7 @@ class Call extends Call_ { override string toString() { result = this.getFunc().toString() + "()" } - override CallNode getAFlowNode() { result = super.getAFlowNode() } + deprecated override CallNode getAFlowNode() { result = super.getAFlowNode() } /** Gets a tuple (*) argument of this call. */ Expr getStarargs() { result = this.getAPositionalArg().(Starred).getValue() } @@ -201,7 +203,7 @@ class IfExp extends IfExp_ { result = this.getTest() or result = this.getBody() or result = this.getOrelse() } - override IfExprNode getAFlowNode() { result = super.getAFlowNode() } + deprecated override IfExprNode getAFlowNode() { result = super.getAFlowNode() } } /** A starred expression, such as the `*rest` in the assignment `first, *rest = seq` */ @@ -411,7 +413,7 @@ class PlaceHolder extends PlaceHolder_ { override string toString() { result = "$" + this.getId() } - override NameNode getAFlowNode() { result = super.getAFlowNode() } + deprecated override NameNode getAFlowNode() { result = super.getAFlowNode() } } /** A tuple expression such as `( 1, 3, 5, 7, 9 )` */ @@ -478,7 +480,7 @@ class Name extends Name_ { override string toString() { result = this.getId() } - override NameNode getAFlowNode() { result = super.getAFlowNode() } + deprecated override NameNode getAFlowNode() { result = super.getAFlowNode() } override predicate isArtificial() { /* Artificial variable names in comprehensions all start with "." */ @@ -585,7 +587,7 @@ abstract class NameConstant extends Name, ImmutableLiteral { override predicate isConstant() { any() } - override NameConstantNode getAFlowNode() { result = Name.super.getAFlowNode() } + deprecated override NameConstantNode getAFlowNode() { result = Name.super.getAFlowNode() } override predicate isArtificial() { none() } } diff --git a/python/ql/lib/semmle/python/Flow.qll b/python/ql/lib/semmle/python/Flow.qll index 94caf513aa9..76a1f21af15 100644 --- a/python/ql/lib/semmle/python/Flow.qll +++ b/python/ql/lib/semmle/python/Flow.qll @@ -1,7 +1,7 @@ overlay[local] module; -import python +import python as Py private import semmle.python.internal.CachedStages private import codeql.controlflow.BasicBlock as BB @@ -17,7 +17,7 @@ private import codeql.controlflow.BasicBlock as BB */ private predicate augstore(ControlFlowNode load, ControlFlowNode store) { - exists(Expr load_store | exists(AugAssign aa | aa.getTarget() = load_store) | + exists(Py::Expr load_store | exists(Py::AugAssign aa | aa.getTarget() = load_store) | toAst(load) = load_store and toAst(store) = load_store and load.strictlyDominates(store) @@ -25,7 +25,7 @@ private predicate augstore(ControlFlowNode load, ControlFlowNode store) { } /** A non-dispatched getNode() to avoid negative recursion issues */ -private AstNode toAst(ControlFlowNode n) { py_flow_bb_node(n, result, _, _) } +private Py::AstNode toAst(ControlFlowNode n) { py_flow_bb_node(n, result, _, _) } /** * A control flow node. Control flow nodes have a many-to-one relation with syntactic nodes, @@ -35,19 +35,19 @@ private AstNode toAst(ControlFlowNode n) { py_flow_bb_node(n, result, _, _) } class ControlFlowNode extends @py_flow_node { /** Whether this control flow node is a load (including those in augmented assignments) */ predicate isLoad() { - exists(Expr e | e = toAst(this) | py_expr_contexts(_, 3, e) and not augstore(_, this)) + exists(Py::Expr e | e = toAst(this) | py_expr_contexts(_, 3, e) and not augstore(_, this)) } /** Whether this control flow node is a store (including those in augmented assignments) */ predicate isStore() { - exists(Expr e | e = toAst(this) | py_expr_contexts(_, 5, e) or augstore(_, this)) + exists(Py::Expr e | e = toAst(this) | py_expr_contexts(_, 5, e) or augstore(_, this)) } /** Whether this control flow node is a delete */ - predicate isDelete() { exists(Expr e | e = toAst(this) | py_expr_contexts(_, 2, e)) } + predicate isDelete() { exists(Py::Expr e | e = toAst(this) | py_expr_contexts(_, 2, e)) } /** Whether this control flow node is a parameter */ - predicate isParameter() { exists(Expr e | e = toAst(this) | py_expr_contexts(_, 4, e)) } + predicate isParameter() { exists(Py::Expr e | e = toAst(this) | py_expr_contexts(_, 4, e)) } /** Whether this control flow node is a store in an augmented assignment */ predicate isAugStore() { augstore(_, this) } @@ -57,61 +57,61 @@ class ControlFlowNode extends @py_flow_node { /** Whether this flow node corresponds to a literal */ predicate isLiteral() { - toAst(this) instanceof Bytes + toAst(this) instanceof Py::Bytes or - toAst(this) instanceof Dict + toAst(this) instanceof Py::Dict or - toAst(this) instanceof DictComp + toAst(this) instanceof Py::DictComp or - toAst(this) instanceof Set + toAst(this) instanceof Py::Set or - toAst(this) instanceof SetComp + toAst(this) instanceof Py::SetComp or - toAst(this) instanceof Ellipsis + toAst(this) instanceof Py::Ellipsis or - toAst(this) instanceof GeneratorExp + toAst(this) instanceof Py::GeneratorExp or - toAst(this) instanceof Lambda + toAst(this) instanceof Py::Lambda or - toAst(this) instanceof ListComp + toAst(this) instanceof Py::ListComp or - toAst(this) instanceof List + toAst(this) instanceof Py::List or - toAst(this) instanceof Num + toAst(this) instanceof Py::Num or - toAst(this) instanceof Tuple + toAst(this) instanceof Py::Tuple or - toAst(this) instanceof Unicode + toAst(this) instanceof Py::Unicode or - toAst(this) instanceof NameConstant + toAst(this) instanceof Py::NameConstant } /** Whether this flow node corresponds to an attribute expression */ - predicate isAttribute() { toAst(this) instanceof Attribute } + predicate isAttribute() { toAst(this) instanceof Py::Attribute } /** Whether this flow node corresponds to an subscript expression */ - predicate isSubscript() { toAst(this) instanceof Subscript } + predicate isSubscript() { toAst(this) instanceof Py::Subscript } /** Whether this flow node corresponds to an import member */ - predicate isImportMember() { toAst(this) instanceof ImportMember } + predicate isImportMember() { toAst(this) instanceof Py::ImportMember } /** Whether this flow node corresponds to a call */ - predicate isCall() { toAst(this) instanceof Call } + predicate isCall() { toAst(this) instanceof Py::Call } /** Whether this flow node is the first in a module */ - predicate isModuleEntry() { this.isEntryNode() and toAst(this) instanceof Module } + predicate isModuleEntry() { this.isEntryNode() and toAst(this) instanceof Py::Module } /** Whether this flow node corresponds to an import */ - predicate isImport() { toAst(this) instanceof ImportExpr } + predicate isImport() { toAst(this) instanceof Py::ImportExpr } /** Whether this flow node corresponds to a conditional expression */ - predicate isIfExp() { toAst(this) instanceof IfExp } + predicate isIfExp() { toAst(this) instanceof Py::IfExp } /** Whether this flow node corresponds to a function definition expression */ - predicate isFunction() { toAst(this) instanceof FunctionExpr } + predicate isFunction() { toAst(this) instanceof Py::FunctionExpr } /** Whether this flow node corresponds to a class definition expression */ - predicate isClass() { toAst(this) instanceof ClassExpr } + predicate isClass() { toAst(this) instanceof Py::ClassExpr } /** Gets a predecessor of this flow node */ ControlFlowNode getAPredecessor() { this = result.getASuccessor() } @@ -123,25 +123,25 @@ class ControlFlowNode extends @py_flow_node { ControlFlowNode getImmediateDominator() { py_idoms(this, result) } /** Gets the syntactic element corresponding to this flow node */ - AstNode getNode() { py_flow_bb_node(this, result, _, _) } + Py::AstNode getNode() { py_flow_bb_node(this, result, _, _) } /** Gets a textual representation of this element. */ cached string toString() { Stages::AST::ref() and // Since modules can have ambigous names, entry nodes can too, if we do not collate them. - exists(Scope s | s.getEntryNode() = this | + exists(Py::Scope s | s.getEntryNode() = this | result = "Entry node for " + concat( | | s.toString(), ",") ) or - exists(Scope s | s.getANormalExit() = this | result = "Exit node for " + s.toString()) + exists(Py::Scope s | s.getANormalExit() = this | result = "Exit node for " + s.toString()) or - not exists(Scope s | s.getEntryNode() = this or s.getANormalExit() = this) and + not exists(Py::Scope s | s.getEntryNode() = this or s.getANormalExit() = this) and result = "ControlFlowNode for " + this.getNode().toString() } /** Gets the location of this ControlFlowNode */ - Location getLocation() { result = this.getNode().getLocation() } + Py::Location getLocation() { result = this.getNode().getLocation() } /** Whether this flow node is the first in its scope */ predicate isEntryNode() { py_scope_flow(this, _, -1) } @@ -151,9 +151,9 @@ class ControlFlowNode extends @py_flow_node { /** Gets the scope containing this flow node */ cached - Scope getScope() { + Py::Scope getScope() { Stages::AST::ref() and - if this.getNode() instanceof Scope + if this.getNode() instanceof Py::Scope then /* Entry or exit node */ result = this.getNode() @@ -161,7 +161,7 @@ class ControlFlowNode extends @py_flow_node { } /** Gets the enclosing module */ - Module getEnclosingModule() { result = this.getScope().getEnclosingModule() } + Py::Module getEnclosingModule() { result = this.getScope().getEnclosingModule() } /** Gets a successor for this node if the relevant condition is True. */ ControlFlowNode getATrueSuccessor() { @@ -188,7 +188,7 @@ class ControlFlowNode extends @py_flow_node { } /** Whether the scope may be exited as a result of this node raising an exception */ - predicate isExceptionalExit(Scope s) { py_scope_flow(this, s, 1) } + predicate isExceptionalExit(Py::Scope s) { py_scope_flow(this, s, 1) } /** Whether this node is a normal (non-exceptional) exit */ predicate isNormalExit() { py_scope_flow(this, _, 0) or py_scope_flow(this, _, 2) } @@ -236,7 +236,7 @@ class ControlFlowNode extends @py_flow_node { /* join-ordering helper for `getAChild() */ pragma[noinline] private ControlFlowNode getExprChild(BasicBlock dom) { - this.getNode().(Expr).getAChildNode() = result.getNode() and + this.getNode().(Py::Expr).getAChildNode() = result.getNode() and result.getBasicBlock().dominates(dom) and not this instanceof UnaryExprNode } @@ -249,16 +249,16 @@ class ControlFlowNode extends @py_flow_node { */ private class AnyNode extends ControlFlowNode { - override AstNode getNode() { result = super.getNode() } + override Py::AstNode getNode() { result = super.getNode() } } /** A control flow node corresponding to a call expression, such as `func(...)` */ class CallNode extends ControlFlowNode { - CallNode() { toAst(this) instanceof Call } + CallNode() { toAst(this) instanceof Py::Call } /** Gets the flow node corresponding to the function expression for the call corresponding to this flow node */ ControlFlowNode getFunction() { - exists(Call c | + exists(Py::Call c | this.getNode() = c and c.getFunc() = result.getNode() and result.getBasicBlock().dominates(this.getBasicBlock()) @@ -267,7 +267,7 @@ class CallNode extends ControlFlowNode { /** Gets the flow node corresponding to the n'th positional argument of the call corresponding to this flow node */ ControlFlowNode getArg(int n) { - exists(Call c | + exists(Py::Call c | this.getNode() = c and c.getArg(n) = result.getNode() and result.getBasicBlock().dominates(this.getBasicBlock()) @@ -276,7 +276,7 @@ class CallNode extends ControlFlowNode { /** Gets the flow node corresponding to the named argument of the call corresponding to this flow node */ ControlFlowNode getArgByName(string name) { - exists(Call c, Keyword k | + exists(Py::Call c, Py::Keyword k | this.getNode() = c and k = c.getANamedArg() and k.getValue() = result.getNode() and @@ -292,7 +292,7 @@ class CallNode extends ControlFlowNode { result = this.getArgByName(_) } - override Call getNode() { result = super.getNode() } + override Py::Call getNode() { result = super.getNode() } predicate isDecoratorCall() { this.isClassDecoratorCall() @@ -301,11 +301,11 @@ class CallNode extends ControlFlowNode { } predicate isClassDecoratorCall() { - exists(ClassExpr cls | this.getNode() = cls.getADecoratorCall()) + exists(Py::ClassExpr cls | this.getNode() = cls.getADecoratorCall()) } predicate isFunctionDecoratorCall() { - exists(FunctionExpr func | this.getNode() = func.getADecoratorCall()) + exists(Py::FunctionExpr func | this.getNode() = func.getADecoratorCall()) } /** Gets the first tuple (*) argument of this call, if any. */ @@ -323,11 +323,11 @@ class CallNode extends ControlFlowNode { /** A control flow corresponding to an attribute expression, such as `value.attr` */ class AttrNode extends ControlFlowNode { - AttrNode() { toAst(this) instanceof Attribute } + AttrNode() { toAst(this) instanceof Py::Attribute } /** Gets the flow node corresponding to the object of the attribute expression corresponding to this flow node */ ControlFlowNode getObject() { - exists(Attribute a | + exists(Py::Attribute a | this.getNode() = a and a.getObject() = result.getNode() and result.getBasicBlock().dominates(this.getBasicBlock()) @@ -339,7 +339,7 @@ class AttrNode extends ControlFlowNode { * with the matching name */ ControlFlowNode getObject(string name) { - exists(Attribute a | + exists(Py::Attribute a | this.getNode() = a and a.getObject() = result.getNode() and a.getName() = name and @@ -348,57 +348,57 @@ class AttrNode extends ControlFlowNode { } /** Gets the attribute name of the attribute expression corresponding to this flow node */ - string getName() { exists(Attribute a | this.getNode() = a and a.getName() = result) } + string getName() { exists(Py::Attribute a | this.getNode() = a and a.getName() = result) } - override Attribute getNode() { result = super.getNode() } + override Py::Attribute getNode() { result = super.getNode() } } /** A control flow node corresponding to a `from ... import ...` expression */ class ImportMemberNode extends ControlFlowNode { - ImportMemberNode() { toAst(this) instanceof ImportMember } + ImportMemberNode() { toAst(this) instanceof Py::ImportMember } /** * Gets the flow node corresponding to the module in the import-member expression corresponding to this flow node, * with the matching name */ ControlFlowNode getModule(string name) { - exists(ImportMember i | this.getNode() = i and i.getModule() = result.getNode() | + exists(Py::ImportMember i | this.getNode() = i and i.getModule() = result.getNode() | i.getName() = name and result.getBasicBlock().dominates(this.getBasicBlock()) ) } - override ImportMember getNode() { result = super.getNode() } + override Py::ImportMember getNode() { result = super.getNode() } } /** A control flow node corresponding to an artificial expression representing an import */ class ImportExprNode extends ControlFlowNode { - ImportExprNode() { toAst(this) instanceof ImportExpr } + ImportExprNode() { toAst(this) instanceof Py::ImportExpr } - override ImportExpr getNode() { result = super.getNode() } + override Py::ImportExpr getNode() { result = super.getNode() } } /** A control flow node corresponding to a `from ... import *` statement */ class ImportStarNode extends ControlFlowNode { - ImportStarNode() { toAst(this) instanceof ImportStar } + ImportStarNode() { toAst(this) instanceof Py::ImportStar } /** Gets the flow node corresponding to the module in the import-star corresponding to this flow node */ ControlFlowNode getModule() { - exists(ImportStar i | this.getNode() = i and i.getModuleExpr() = result.getNode() | + exists(Py::ImportStar i | this.getNode() = i and i.getModuleExpr() = result.getNode() | result.getBasicBlock().dominates(this.getBasicBlock()) ) } - override ImportStar getNode() { result = super.getNode() } + override Py::ImportStar getNode() { result = super.getNode() } } /** A control flow node corresponding to a subscript expression, such as `value[slice]` */ class SubscriptNode extends ControlFlowNode { - SubscriptNode() { toAst(this) instanceof Subscript } + SubscriptNode() { toAst(this) instanceof Py::Subscript } /** flow node corresponding to the value of the sequence in a subscript operation */ ControlFlowNode getObject() { - exists(Subscript s | + exists(Py::Subscript s | this.getNode() = s and s.getObject() = result.getNode() and result.getBasicBlock().dominates(this.getBasicBlock()) @@ -407,23 +407,23 @@ class SubscriptNode extends ControlFlowNode { /** flow node corresponding to the index in a subscript operation */ ControlFlowNode getIndex() { - exists(Subscript s | + exists(Py::Subscript s | this.getNode() = s and s.getIndex() = result.getNode() and result.getBasicBlock().dominates(this.getBasicBlock()) ) } - override Subscript getNode() { result = super.getNode() } + override Py::Subscript getNode() { result = super.getNode() } } /** A control flow node corresponding to a comparison operation, such as `x DeletionNode -> NameNode('b') -> AttrNode('y') -> DeletionNode`. */ class DeletionNode extends ControlFlowNode { - DeletionNode() { toAst(this) instanceof Delete } + DeletionNode() { toAst(this) instanceof Py::Delete } /** Gets the unique target of this deletion node. */ ControlFlowNode getTarget() { result.getASuccessor() = this } @@ -617,9 +617,9 @@ class DeletionNode extends ControlFlowNode { /** A control flow node corresponding to a sequence (tuple or list) literal */ abstract class SequenceNode extends ControlFlowNode { SequenceNode() { - toAst(this) instanceof Tuple + toAst(this) instanceof Py::Tuple or - toAst(this) instanceof List + toAst(this) instanceof Py::List } /** Gets the control flow node for an element of this sequence */ @@ -632,11 +632,11 @@ abstract class SequenceNode extends ControlFlowNode { /** A control flow node corresponding to a tuple expression such as `( 1, 3, 5, 7, 9 )` */ class TupleNode extends SequenceNode { - TupleNode() { toAst(this) instanceof Tuple } + TupleNode() { toAst(this) instanceof Py::Tuple } override ControlFlowNode getElement(int n) { Stages::AST::ref() and - exists(Tuple t | this.getNode() = t and result.getNode() = t.getElt(n)) and + exists(Py::Tuple t | this.getNode() = t and result.getNode() = t.getElt(n)) and ( result.getBasicBlock().dominates(this.getBasicBlock()) or @@ -647,10 +647,10 @@ class TupleNode extends SequenceNode { /** A control flow node corresponding to a list expression, such as `[ 1, 3, 5, 7, 9 ]` */ class ListNode extends SequenceNode { - ListNode() { toAst(this) instanceof List } + ListNode() { toAst(this) instanceof Py::List } override ControlFlowNode getElement(int n) { - exists(List l | this.getNode() = l and result.getNode() = l.getElt(n)) and + exists(Py::List l | this.getNode() = l and result.getNode() = l.getElt(n)) and ( result.getBasicBlock().dominates(this.getBasicBlock()) or @@ -661,10 +661,10 @@ class ListNode extends SequenceNode { /** A control flow node corresponding to a set expression, such as `{ 1, 3, 5, 7, 9 }` */ class SetNode extends ControlFlowNode { - SetNode() { toAst(this) instanceof Set } + SetNode() { toAst(this) instanceof Py::Set } ControlFlowNode getAnElement() { - exists(Set s | this.getNode() = s and result.getNode() = s.getElt(_)) and + exists(Py::Set s | this.getNode() = s and result.getNode() = s.getElt(_)) and ( result.getBasicBlock().dominates(this.getBasicBlock()) or @@ -675,20 +675,20 @@ class SetNode extends ControlFlowNode { /** A control flow node corresponding to a dictionary literal, such as `{ 'a': 1, 'b': 2 }` */ class DictNode extends ControlFlowNode { - DictNode() { toAst(this) instanceof Dict } + DictNode() { toAst(this) instanceof Py::Dict } /** * Gets a key of this dictionary literal node, for those items that have keys * E.g, in {'a':1, **b} this returns only 'a' */ ControlFlowNode getAKey() { - exists(Dict d | this.getNode() = d and result.getNode() = d.getAKey()) and + exists(Py::Dict d | this.getNode() = d and result.getNode() = d.getAKey()) and result.getBasicBlock().dominates(this.getBasicBlock()) } /** Gets a value of this dictionary literal node */ ControlFlowNode getAValue() { - exists(Dict d | this.getNode() = d and result.getNode() = d.getAValue()) and + exists(Py::Dict d | this.getNode() = d and result.getNode() = d.getAValue()) and result.getBasicBlock().dominates(this.getBasicBlock()) } } @@ -712,21 +712,23 @@ class IterableNode extends ControlFlowNode { } } -private AstNode assigned_value(Expr lhs) { +private Py::AstNode assigned_value(Py::Expr lhs) { /* lhs = result */ - exists(Assign a | a.getATarget() = lhs and result = a.getValue()) + exists(Py::Assign a | a.getATarget() = lhs and result = a.getValue()) or /* lhs := result */ - exists(AssignExpr a | a.getTarget() = lhs and result = a.getValue()) + exists(Py::AssignExpr a | a.getTarget() = lhs and result = a.getValue()) or /* lhs : annotation = result */ - exists(AnnAssign a | a.getTarget() = lhs and result = a.getValue()) + exists(Py::AnnAssign a | a.getTarget() = lhs and result = a.getValue()) or /* import result as lhs */ - exists(Alias a | a.getAsname() = lhs and result = a.getValue()) + exists(Py::Alias a | a.getAsname() = lhs and result = a.getValue()) or /* lhs += x => result = (lhs + x) */ - exists(AugAssign a, BinaryExpr b | b = a.getOperation() and result = b and lhs = b.getLeft()) + exists(Py::AugAssign a, Py::BinaryExpr b | + b = a.getOperation() and result = b and lhs = b.getLeft() + ) or /* * ..., lhs, ... = ..., result, ... @@ -734,31 +736,31 @@ private AstNode assigned_value(Expr lhs) { * ..., (..., lhs, ...), ... = ..., (..., result, ...), ... */ - exists(Assign a | nested_sequence_assign(a.getATarget(), a.getValue(), lhs, result)) + exists(Py::Assign a | nested_sequence_assign(a.getATarget(), a.getValue(), lhs, result)) or /* for lhs in seq: => `result` is the `for` node, representing the `iter(next(seq))` operation. */ - result.(For).getTarget() = lhs + result.(Py::For).getTarget() = lhs or - exists(Parameter param | lhs = param.asName() and result = param.getDefault()) + exists(Py::Parameter param | lhs = param.asName() and result = param.getDefault()) } predicate nested_sequence_assign( - Expr left_parent, Expr right_parent, Expr left_result, Expr right_result + Py::Expr left_parent, Py::Expr right_parent, Py::Expr left_result, Py::Expr right_result ) { - exists(Assign a | + exists(Py::Assign a | a.getATarget().getASubExpression*() = left_parent and a.getValue().getASubExpression*() = right_parent ) and - exists(int i, Expr left_elem, Expr right_elem | + exists(int i, Py::Expr left_elem, Py::Expr right_elem | ( - left_elem = left_parent.(Tuple).getElt(i) + left_elem = left_parent.(Py::Tuple).getElt(i) or - left_elem = left_parent.(List).getElt(i) + left_elem = left_parent.(Py::List).getElt(i) ) and ( - right_elem = right_parent.(Tuple).getElt(i) + right_elem = right_parent.(Py::Tuple).getElt(i) or - right_elem = right_parent.(List).getElt(i) + right_elem = right_parent.(Py::List).getElt(i) ) | left_result = left_elem and right_result = right_elem @@ -769,9 +771,9 @@ predicate nested_sequence_assign( /** A flow node for a `for` statement. */ class ForNode extends ControlFlowNode { - ForNode() { toAst(this) instanceof For } + ForNode() { toAst(this) instanceof Py::For } - override For getNode() { result = super.getNode() } + override Py::For getNode() { result = super.getNode() } /** Holds if this `for` statement causes iteration over `sequence` storing each step of the iteration in `target` */ predicate iterates(ControlFlowNode target, ControlFlowNode sequence) { @@ -782,7 +784,7 @@ class ForNode extends ControlFlowNode { /** Gets the sequence node for this `for` statement. */ ControlFlowNode getSequence() { - exists(For for | + exists(Py::For for | toAst(this) = for and for.getIter() = result.getNode() | @@ -792,7 +794,7 @@ class ForNode extends ControlFlowNode { /** A possible `target` for this `for` statement, not accounting for loop unrolling */ private ControlFlowNode possibleTarget() { - exists(For for | + exists(Py::For for | toAst(this) = for and for.getTarget() = result.getNode() and this.getBasicBlock().dominates(result.getBasicBlock()) @@ -809,11 +811,11 @@ class ForNode extends ControlFlowNode { /** A flow node for a `raise` statement */ class RaiseStmtNode extends ControlFlowNode { - RaiseStmtNode() { toAst(this) instanceof Raise } + RaiseStmtNode() { toAst(this) instanceof Py::Raise } /** Gets the control flow node for the exception raised by this raise statement */ ControlFlowNode getException() { - exists(Raise r | + exists(Py::Raise r | r = toAst(this) and r.getException() = toAst(result) and result.getBasicBlock().dominates(this.getBasicBlock()) @@ -827,36 +829,36 @@ class RaiseStmtNode extends ControlFlowNode { */ class NameNode extends ControlFlowNode { NameNode() { - exists(Name n | py_flow_bb_node(this, n, _, _)) + exists(Py::Name n | py_flow_bb_node(this, n, _, _)) or - exists(PlaceHolder p | py_flow_bb_node(this, p, _, _)) + exists(Py::PlaceHolder p | py_flow_bb_node(this, p, _, _)) } /** Whether this flow node defines the variable `v`. */ - predicate defines(Variable v) { - exists(Name d | this.getNode() = d and d.defines(v)) and + predicate defines(Py::Variable v) { + exists(Py::Name d | this.getNode() = d and d.defines(v)) and not this.isLoad() } /** Whether this flow node deletes the variable `v`. */ - predicate deletes(Variable v) { exists(Name d | this.getNode() = d and d.deletes(v)) } + predicate deletes(Py::Variable v) { exists(Py::Name d | this.getNode() = d and d.deletes(v)) } /** Whether this flow node uses the variable `v`. */ - predicate uses(Variable v) { + predicate uses(Py::Variable v) { this.isLoad() and - exists(Name u | this.getNode() = u and u.uses(v)) + exists(Py::Name u | this.getNode() = u and u.uses(v)) or - exists(PlaceHolder u | - this.getNode() = u and u.getVariable() = v and u.getCtx() instanceof Load + exists(Py::PlaceHolder u | + this.getNode() = u and u.getVariable() = v and u.getCtx() instanceof Py::Load ) or Scopes::use_of_global_variable(this, v.getScope(), v.getId()) } string getId() { - result = this.getNode().(Name).getId() + result = this.getNode().(Py::Name).getId() or - result = this.getNode().(PlaceHolder).getId() + result = this.getNode().(Py::PlaceHolder).getId() } /** Whether this is a use of a local variable. */ @@ -868,82 +870,84 @@ class NameNode extends ControlFlowNode { /** Whether this is a use of a global (including builtin) variable. */ predicate isGlobal() { Scopes::use_of_global_variable(this, _, _) } - predicate isSelf() { exists(SsaVariable selfvar | selfvar.isSelf() and selfvar.getAUse() = this) } + predicate isSelf() { + exists(Py::SsaVariable selfvar | selfvar.isSelf() and selfvar.getAUse() = this) + } } /** A control flow node corresponding to a named constant, one of `None`, `True` or `False`. */ class NameConstantNode extends NameNode { - NameConstantNode() { exists(NameConstant n | py_flow_bb_node(this, n, _, _)) } + NameConstantNode() { exists(Py::NameConstant n | py_flow_bb_node(this, n, _, _)) } /* * We ought to override uses as well, but that has * a serious performance impact. - * deprecated predicate uses(Variable v) { none() } + * deprecated predicate uses(Py::Variable v) { none() } */ } /** A control flow node corresponding to a starred expression, `*a`. */ class StarredNode extends ControlFlowNode { - StarredNode() { toAst(this) instanceof Starred } + StarredNode() { toAst(this) instanceof Py::Starred } - ControlFlowNode getValue() { toAst(result) = toAst(this).(Starred).getValue() } + ControlFlowNode getValue() { toAst(result) = toAst(this).(Py::Starred).getValue() } } /** The ControlFlowNode for an 'except' statement. */ class ExceptFlowNode extends ControlFlowNode { - ExceptFlowNode() { this.getNode() instanceof ExceptStmt } + ExceptFlowNode() { this.getNode() instanceof Py::ExceptStmt } /** * Gets the type handled by this exception handler. - * `ExceptionType` in `except ExceptionType as e:` + * `Py::ExceptionType` in `except Py::ExceptionType as e:` */ ControlFlowNode getType() { - exists(ExceptStmt ex | + exists(Py::ExceptStmt ex | this.getBasicBlock().dominates(result.getBasicBlock()) and ex = this.getNode() and - result = ex.getType().getAFlowNode() + result.getNode() = ex.getType() ) } /** * Gets the name assigned to the handled exception, if any. - * `e` in `except ExceptionType as e:` + * `e` in `except Py::ExceptionType as e:` */ ControlFlowNode getName() { - exists(ExceptStmt ex | + exists(Py::ExceptStmt ex | this.getBasicBlock().dominates(result.getBasicBlock()) and ex = this.getNode() and - result = ex.getName().getAFlowNode() + result.getNode() = ex.getName() ) } } /** The ControlFlowNode for an 'except*' statement. */ class ExceptGroupFlowNode extends ControlFlowNode { - ExceptGroupFlowNode() { this.getNode() instanceof ExceptGroupStmt } + ExceptGroupFlowNode() { this.getNode() instanceof Py::ExceptGroupStmt } /** * Gets the type handled by this exception handler. - * `ExceptionType` in `except* ExceptionType as e:` + * `Py::ExceptionType` in `except* Py::ExceptionType as e:` */ ControlFlowNode getType() { this.getBasicBlock().dominates(result.getBasicBlock()) and - result = this.getNode().(ExceptGroupStmt).getType().getAFlowNode() + result.getNode() = this.getNode().(Py::ExceptGroupStmt).getType() } /** * Gets the name assigned to the handled exception, if any. - * `e` in `except* ExceptionType as e:` + * `e` in `except* Py::ExceptionType as e:` */ ControlFlowNode getName() { this.getBasicBlock().dominates(result.getBasicBlock()) and - result = this.getNode().(ExceptGroupStmt).getName().getAFlowNode() + result.getNode() = this.getNode().(Py::ExceptGroupStmt).getName() } } private module Scopes { private predicate fast_local(NameNode n) { - exists(FastLocalVariable v | + exists(Py::FastLocalVariable v | n.uses(v) and v.getScope() = n.getScope() ) @@ -952,15 +956,15 @@ private module Scopes { predicate local(NameNode n) { fast_local(n) or - exists(SsaVariable var | + exists(Py::SsaVariable var | var.getAUse() = n and - n.getScope() instanceof Class and + n.getScope() instanceof Py::Class and exists(var.getDefinition()) ) } predicate non_local(NameNode n) { - exists(FastLocalVariable flv | + exists(Py::FastLocalVariable flv | flv.getALoad() = n.getNode() and not flv.getScope() = n.getScope() ) @@ -968,20 +972,20 @@ private module Scopes { // magic is fine, but we get questionable join-ordering of it pragma[nomagic] - predicate use_of_global_variable(NameNode n, Module scope, string name) { + predicate use_of_global_variable(NameNode n, Py::Module scope, string name) { n.isLoad() and not non_local(n) and - not exists(SsaVariable var | var.getAUse() = n | - var.getVariable() instanceof FastLocalVariable + not exists(Py::SsaVariable var | var.getAUse() = n | + var.getVariable() instanceof Py::FastLocalVariable or - n.getScope() instanceof Class and + n.getScope() instanceof Py::Class and not maybe_undefined(var) ) and name = n.getId() and scope = n.getEnclosingModule() } - private predicate maybe_undefined(SsaVariable var) { + private predicate maybe_undefined(Py::SsaVariable var) { not exists(var.getDefinition()) and not py_ssa_phi(var, _) or var.getDefinition().isDelete() @@ -1058,13 +1062,13 @@ class BasicBlock extends @py_flow_node { private predicate oneNodeBlock() { this.firstNode() = this.getLastNode() } private predicate startLocationInfo(string file, int line, int col) { - if this.firstNode().getNode() instanceof Scope + if this.firstNode().getNode() instanceof Py::Scope then this.firstNode().getASuccessor().getLocation().hasLocationInfo(file, line, col, _, _) else this.firstNode().getLocation().hasLocationInfo(file, line, col, _, _) } private predicate endLocationInfo(int endl, int endc) { - if this.getLastNode().getNode() instanceof Scope and not this.oneNodeBlock() + if this.getLastNode().getNode() instanceof Py::Scope and not this.oneNodeBlock() then this.getLastNode().getAPredecessor().getLocation().hasLocationInfo(_, _, _, endl, endc) else this.getLastNode().getLocation().hasLocationInfo(_, _, _, endl, endc) } @@ -1081,7 +1085,7 @@ class BasicBlock extends @py_flow_node { /** Whether flow from this basic block reaches a normal exit from its scope */ predicate reachesExit() { - exists(Scope s | s.getANormalExit().getBasicBlock() = this) + exists(Py::Scope s | s.getANormalExit().getBasicBlock() = this) or this.getASuccessor().reachesExit() } @@ -1122,7 +1126,7 @@ class BasicBlock extends @py_flow_node { /** Gets the scope of this block */ pragma[nomagic] - Scope getScope() { + Py::Scope getScope() { exists(ControlFlowNode n | n.getBasicBlock() = this | /* Take care not to use an entry or exit node as that node's scope will be the outer scope */ not py_scope_flow(n, _, -1) and @@ -1145,17 +1149,17 @@ class BasicBlock extends @py_flow_node { predicate reaches(BasicBlock other) { this = other or this.strictlyReaches(other) } /** - * Gets the `ConditionBlock`, if any, that controls this block and - * does not control any other `ConditionBlock`s that control this block. - * That is the `ConditionBlock` that is closest dominator. + * Gets the `Py::ConditionBlock`, if any, that controls this block and + * does not control any other `Py::ConditionBlock`s that control this block. + * That is the `Py::ConditionBlock` that is closest dominator. */ - ConditionBlock getImmediatelyControllingBlock() { + Py::ConditionBlock getImmediatelyControllingBlock() { result = this.nonControllingImmediateDominator*().getImmediateDominator() } private BasicBlock nonControllingImmediateDominator() { result = this.getImmediateDominator() and - not result.(ConditionBlock).controls(this, _) + not result.(Py::ConditionBlock).controls(this, _) } /** @@ -1175,7 +1179,7 @@ private class ControlFlowNodeAlias = ControlFlowNode; final private class FinalBasicBlock = BasicBlock; -module Cfg implements BB::CfgSig { +module Cfg implements BB::CfgSig { private import codeql.controlflow.SuccessorType class ControlFlowNode = ControlFlowNodeAlias; @@ -1186,7 +1190,7 @@ module Cfg implements BB::CfgSig { // Using the location of the first node is simple // and we just need a way to identify the basic block // during debugging, so this will be serviceable. - Location getLocation() { result = super.getNode(0).getLocation() } + Py::Location getLocation() { result = super.getNode(0).getLocation() } int length() { result = count(int i | exists(this.getNode(i))) } diff --git a/python/ql/lib/semmle/python/Function.qll b/python/ql/lib/semmle/python/Function.qll index c133275b8b7..2ef0366aa3b 100644 --- a/python/ql/lib/semmle/python/Function.qll +++ b/python/ql/lib/semmle/python/Function.qll @@ -153,8 +153,16 @@ class Function extends Function_, Scope, AstNode { override predicate contains(AstNode inner) { Scope.super.contains(inner) } - /** Gets a control flow node for a return value of this function */ - ControlFlowNode getAReturnValueFlowNode() { + /** + * DEPRECATED: bind a `Return` node explicitly instead, e.g. + * `exists(Return ret | ret.getScope() = this and n.getNode() = ret.getValue())`. + * This API is being phased out together with `AstNode.getAFlowNode()` to + * untangle the AST and CFG hierarchies in preparation for migrating the + * dataflow library off the legacy CFG. + * + * Gets a control flow node for a return value of this function. + */ + deprecated ControlFlowNode getAReturnValueFlowNode() { exists(Return ret | ret.getScope() = this and ret.getValue() = result.getNode() diff --git a/python/ql/lib/semmle/python/Import.qll b/python/ql/lib/semmle/python/Import.qll index 2f7fae95539..1e153a0de03 100644 --- a/python/ql/lib/semmle/python/Import.qll +++ b/python/ql/lib/semmle/python/Import.qll @@ -163,7 +163,7 @@ class ImportMember extends ImportMember_ { result = this.getModule().(ImportExpr).getImportedModuleName() + "." + this.getName() } - override ImportMemberNode getAFlowNode() { result = super.getAFlowNode() } + deprecated override ImportMemberNode getAFlowNode() { result = super.getAFlowNode() } } /** An import statement */ diff --git a/python/ql/lib/semmle/python/SelfAttribute.qll b/python/ql/lib/semmle/python/SelfAttribute.qll index 90ef2b38401..364e080dcdd 100644 --- a/python/ql/lib/semmle/python/SelfAttribute.qll +++ b/python/ql/lib/semmle/python/SelfAttribute.qll @@ -46,20 +46,23 @@ class SelfAttributeRead extends SelfAttribute { } predicate guardedByHasattr() { - exists(Variable var, ControlFlowNode n | - var.getAUse() = this.getObject().getAFlowNode() and + exists(Variable var, ControlFlowNode n, ControlFlowNode this_, ControlFlowNode obj_ | + this_.getNode() = this and obj_.getNode() = this.getObject() + | + var.getAUse() = obj_ and hasattr(n, var.getAUse(), this.getName()) and - n.strictlyDominates(this.getAFlowNode()) + n.strictlyDominates(this_) ) } pragma[noinline] predicate locallyDefined() { - exists(SelfAttributeStore store | - this.getName() = store.getName() and - this.getScope() = store.getScope() + exists(SelfAttributeStore store, ControlFlowNode store_, ControlFlowNode this_ | + store_.getNode() = store and this_.getNode() = this | - store.getAFlowNode().strictlyDominates(this.getAFlowNode()) + this.getName() = store.getName() and + this.getScope() = store.getScope() and + store_.strictlyDominates(this_) ) } } diff --git a/python/ql/lib/semmle/python/dataflow/new/BarrierGuards.qll b/python/ql/lib/semmle/python/dataflow/new/BarrierGuards.qll index fefa30965ce..072098991bb 100644 --- a/python/ql/lib/semmle/python/dataflow/new/BarrierGuards.qll +++ b/python/ql/lib/semmle/python/dataflow/new/BarrierGuards.qll @@ -5,24 +5,30 @@ private import semmle.python.dataflow.new.DataFlow private predicate constCompare(DataFlow::GuardNode g, ControlFlowNode node, boolean branch) { exists(CompareNode cn | cn = g | - exists(ImmutableLiteral const, Cmpop op | - op = any(Eq eq) and branch = true - or - op = any(NotEq ne) and branch = false + exists(ImmutableLiteral const, Cmpop op, ControlFlowNode c | + c.getNode() = const and + ( + op = any(Eq eq) and branch = true + or + op = any(NotEq ne) and branch = false + ) | - cn.operands(const.getAFlowNode(), op, node) + cn.operands(c, op, node) or - cn.operands(node, op, const.getAFlowNode()) + cn.operands(node, op, c) ) or - exists(NameConstant const, Cmpop op | - op = any(Is is_) and branch = true - or - op = any(IsNot isn) and branch = false + exists(NameConstant const, Cmpop op, ControlFlowNode c | + c.getNode() = const and + ( + op = any(Is is_) and branch = true + or + op = any(IsNot isn) and branch = false + ) | - cn.operands(const.getAFlowNode(), op, node) + cn.operands(c, op, node) or - cn.operands(node, op, const.getAFlowNode()) + cn.operands(node, op, c) ) or exists(IterableNode const_iterable, Cmpop op | diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/Attributes.qll b/python/ql/lib/semmle/python/dataflow/new/internal/Attributes.qll index 8778ae28866..76d2cb11e14 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/Attributes.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/Attributes.qll @@ -228,7 +228,7 @@ private class ClassDefinitionAsAttrWrite extends AttrWrite, CfgNode { override Node getValue() { result.asCfgNode() = node.getValue() } - override Node getObject() { result.asCfgNode() = cls.getAFlowNode() } + override Node getObject() { result.asCfgNode().getNode() = cls } override ExprNode getAttributeNameExpr() { none() } diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll index 4e3a011e8d1..23b49882445 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll @@ -1913,8 +1913,8 @@ abstract class ReturnNode extends Node { class ExtractedReturnNode extends ReturnNode, CfgNode { // See `TaintTrackingImplementation::returnFlowStep` ExtractedReturnNode() { - node = any(Return ret).getValue().getAFlowNode() or - node = any(Yield yield).getAFlowNode() + node.getNode() = any(Return ret).getValue() or + node.getNode() = any(Yield yield) } override ReturnKind getKind() { any() } @@ -1932,7 +1932,7 @@ class ExtractedReturnNode extends ReturnNode, CfgNode { class YieldNodeInContextManagerFunction extends ReturnNode, CfgNode { YieldNodeInContextManagerFunction() { hasContextmanagerDecorator(node.getScope()) and - node = any(Yield yield).getValue().getAFlowNode() + node.getNode() = any(Yield yield).getValue() } override ReturnKind getKind() { any() } diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll index 897248d0a5d..04e8ad0587f 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll @@ -185,8 +185,8 @@ private predicate synthDictSplatArgumentNodeStoreStep( */ predicate yieldStoreStep(Node nodeFrom, Content c, Node nodeTo) { exists(Yield yield | - nodeTo.asCfgNode() = yield.getAFlowNode() and - nodeFrom.asCfgNode() = yield.getValue().getAFlowNode() and + nodeTo.asCfgNode().getNode() = yield and + nodeFrom.asCfgNode().getNode() = yield.getValue() and // TODO: Consider if this will also need to transfer dictionary content // once dictionary comprehensions are supported. c instanceof ListElementContent diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll index bb393630463..8ee269cab34 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll @@ -485,7 +485,7 @@ class ModuleVariableNode extends Node, TModuleVariableNode { /** Gets a node that reads this variable, excluding reads that happen through `from ... import *`. */ Node getALocalRead() { - result.asCfgNode() = var.getALoad().getAFlowNode() and + result.asCfgNode().getNode() = var.getALoad() and not result.getScope() = mod } diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/ImportResolution.qll b/python/ql/lib/semmle/python/dataflow/new/internal/ImportResolution.qll index f3943f53f86..f62c4efcac8 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/ImportResolution.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/ImportResolution.qll @@ -9,7 +9,19 @@ private import semmle.python.dataflow.new.DataFlow private import semmle.python.dataflow.new.internal.ImportStar private import semmle.python.dataflow.new.TypeTracking private import semmle.python.dataflow.new.internal.DataFlowPrivate -private import semmle.python.essa.SsaDefinitions + +/** + * Holds if `init` is a package's `__init__.py` and `var` is a global variable in + * `init` whose name matches a submodule of the package. + * + * Inlined from `SsaSource::init_module_submodule_defn` to avoid pulling + * `semmle.python.essa.SsaDefinitions` into the new dataflow stack. + */ +private predicate initModuleSubmoduleDefn(GlobalVariable var, Module init) { + init.isPackageInit() and + exists(init.getPackage().getSubModule(var.getId())) and + var.getScope() = init +} /** * Python modules and the way imports are resolved are... complicated. Here's a crash course in how @@ -326,7 +338,7 @@ module ImportResolution { // imported yet. exists(string submodule, Module package, EssaVariable var | submodule = var.getName() and - SsaSource::init_module_submodule_defn(var.getSourceVariable(), package.getEntryNode()) and + initModuleSubmoduleDefn(var.getSourceVariable(), package) and m = getModuleFromName(package.getPackageName() + "." + submodule) and result.asCfgNode() = var.getDefinition().(EssaNodeDefinition).getDefiningNode() ) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackingImpl.qll b/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackingImpl.qll index 4d9e95b4c7a..13afd6a4276 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackingImpl.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackingImpl.qll @@ -94,8 +94,10 @@ private module SummaryTypeTrackerInput implements SummaryTypeTracker::Input { Node returnOf(Node callable, SummaryComponent return) { return = FlowSummaryImpl::Private::SummaryComponent::return() and // `result` should be the return value of a callable expression (lambda or function) referenced by `callable` - result.asCfgNode() = - callable.getALocalSource().asExpr().(CallableExpr).getInnerScope().getAReturnValueFlowNode() + exists(Return ret | + ret.getScope() = callable.getALocalSource().asExpr().(CallableExpr).getInnerScope() and + result.asCfgNode().getNode() = ret.getValue() + ) } // Relating callables to nodes diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/VariableCapture.qll b/python/ql/lib/semmle/python/dataflow/new/internal/VariableCapture.qll index fbe05979328..b170f7d95d7 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/VariableCapture.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/VariableCapture.qll @@ -61,7 +61,7 @@ private module CaptureInput implements Shared::InputSig limit @@ -211,7 +215,7 @@ predicate too_many_args(Call call, Value callable, int limit) { call = func.getAMethodCall().getNode() and limit = func.maxParameters() - 1 or callable instanceof ClassValue and - call.getAFlowNode() = get_a_call(callable) and + exists(ControlFlowNode callCfg | callCfg.getNode() = call | callCfg = get_a_call(callable)) and limit = func.maxParameters() - 1 ) and positional_arg_count_for_call(call, callable) > limit diff --git a/python/ql/src/Expressions/DuplicateKeyInDictionaryLiteral.ql b/python/ql/src/Expressions/DuplicateKeyInDictionaryLiteral.ql index 166eae635fa..0c55a2ece58 100644 --- a/python/ql/src/Expressions/DuplicateKeyInDictionaryLiteral.ql +++ b/python/ql/src/Expressions/DuplicateKeyInDictionaryLiteral.ql @@ -36,11 +36,15 @@ where exists(string s | dict_key(d, k1, s) and dict_key(d, k2, s) and k1 != k2) and ( exists(BasicBlock b, int i1, int i2 | - k1.getAFlowNode() = b.getNode(i1) and - k2.getAFlowNode() = b.getNode(i2) and + b.getNode(i1).getNode() = k1 and + b.getNode(i2).getNode() = k2 and i1 < i2 ) or - k1.getAFlowNode().getBasicBlock().strictlyDominates(k2.getAFlowNode().getBasicBlock()) + exists(ControlFlowNode k1Cfg, ControlFlowNode k2Cfg | + k1Cfg.getNode() = k1 and k2Cfg.getNode() = k2 + | + k1Cfg.getBasicBlock().strictlyDominates(k2Cfg.getBasicBlock()) + ) ) select k1, "Dictionary key " + repr(k1) + " is subsequently $@.", k2, "overwritten" diff --git a/python/ql/src/Expressions/Formatting/AdvancedFormatting.qll b/python/ql/src/Expressions/Formatting/AdvancedFormatting.qll index d98286d85fa..a5e0379685a 100644 --- a/python/ql/src/Expressions/Formatting/AdvancedFormatting.qll +++ b/python/ql/src/Expressions/Formatting/AdvancedFormatting.qll @@ -98,16 +98,18 @@ private predicate brace_pair(PossibleAdvancedFormatString fmt, int start, int en } private predicate advanced_format_call(Call format_expr, PossibleAdvancedFormatString fmt, int args) { - exists(CallNode call | call = format_expr.getAFlowNode() | + exists(CallNode call, ControlFlowNode fmtCfg | + call.getNode() = format_expr and fmtCfg.getNode() = fmt + | call.getFunction().(ControlFlowNodeWithPointsTo).pointsTo(Value::named("format")) and - call.getArg(0).(ControlFlowNodeWithPointsTo).pointsTo(_, fmt.getAFlowNode()) and + call.getArg(0).(ControlFlowNodeWithPointsTo).pointsTo(_, fmtCfg) and args = count(format_expr.getAnArg()) - 1 or call.getFunction() .(AttrNode) .getObject("format") .(ControlFlowNodeWithPointsTo) - .pointsTo(_, fmt.getAFlowNode()) and + .pointsTo(_, fmtCfg) and args = count(format_expr.getAnArg()) ) } diff --git a/python/ql/src/Expressions/IncorrectComparisonUsingIs.ql b/python/ql/src/Expressions/IncorrectComparisonUsingIs.ql index fa0ca14669f..a7336c62547 100644 --- a/python/ql/src/Expressions/IncorrectComparisonUsingIs.ql +++ b/python/ql/src/Expressions/IncorrectComparisonUsingIs.ql @@ -15,7 +15,7 @@ import python /** Holds if the comparison `comp` uses `is` or `is not` (represented as `op`) to compare its `left` and `right` arguments. */ predicate comparison_using_is(Compare comp, ControlFlowNode left, Cmpop op, ControlFlowNode right) { - exists(CompareNode fcomp | fcomp = comp.getAFlowNode() | + exists(CompareNode fcomp | fcomp.getNode() = comp | fcomp.operands(left, op, right) and (op instanceof Is or op instanceof IsNot) ) diff --git a/python/ql/src/Expressions/IsComparisons.qll b/python/ql/src/Expressions/IsComparisons.qll index cb052ceca76..ee49f6c3337 100644 --- a/python/ql/src/Expressions/IsComparisons.qll +++ b/python/ql/src/Expressions/IsComparisons.qll @@ -5,7 +5,7 @@ private import LegacyPointsTo /** Holds if the comparison `comp` uses `is` or `is not` (represented as `op`) to compare its `left` and `right` arguments. */ predicate comparison_using_is(Compare comp, ControlFlowNode left, Cmpop op, ControlFlowNode right) { - exists(CompareNode fcomp | fcomp = comp.getAFlowNode() | + exists(CompareNode fcomp | fcomp.getNode() = comp | fcomp.operands(left, op, right) and (op instanceof Is or op instanceof IsNot) ) diff --git a/python/ql/src/Expressions/TruncatedDivision.ql b/python/ql/src/Expressions/TruncatedDivision.ql index c731a21f7d2..d63ac056d3c 100644 --- a/python/ql/src/Expressions/TruncatedDivision.ql +++ b/python/ql/src/Expressions/TruncatedDivision.ql @@ -19,7 +19,7 @@ where // Only relevant for Python 2, as all later versions implement true division major_version() = 2 and exists(BinaryExprNode bin, Value lval, Value rval | - bin = div.getAFlowNode() and + bin.getNode() = div and bin.getNode().getOp() instanceof Div and bin.getLeft().(ControlFlowNodeWithPointsTo).pointsTo(lval, left) and lval.getClass() = ClassValue::int_() and diff --git a/python/ql/src/Functions/ExplicitReturnInInit.ql b/python/ql/src/Functions/ExplicitReturnInInit.ql index f1300afbfd0..25fc799fafa 100644 --- a/python/ql/src/Functions/ExplicitReturnInInit.ql +++ b/python/ql/src/Functions/ExplicitReturnInInit.ql @@ -19,7 +19,9 @@ where exists(Function init | init.isInitMethod() and r.getScope() = init) and r.getValue() = rv and not rv.pointsTo(Value::none_()) and - not exists(FunctionValue f | f.getACall() = rv.getAFlowNode() | f.neverReturns()) and + not exists(FunctionValue f, ControlFlowNode rvCfg | rvCfg.getNode() = rv | + f.getACall() = rvCfg and f.neverReturns() + ) and // to avoid double reporting, don't trigger if returning result from other __init__ function not exists(Attribute meth | meth = rv.(Call).getFunc() | meth.getName() = "__init__") select r, "Explicit return in __init__ method." diff --git a/python/ql/src/Functions/ReturnValueIgnored.ql b/python/ql/src/Functions/ReturnValueIgnored.ql index 3716b989d89..83af6304cb3 100644 --- a/python/ql/src/Functions/ReturnValueIgnored.ql +++ b/python/ql/src/Functions/ReturnValueIgnored.ql @@ -69,7 +69,12 @@ where returns_meaningful_value(callee) and not wrapped_in_try_except(call) and exists(int unused | - unused = count(ExprStmt e | e.getValue().getAFlowNode() = callee.getACall()) and + unused = + count(ExprStmt e | + exists(ControlFlowNode eValCfg | eValCfg.getNode() = e.getValue() | + eValCfg = callee.getACall() + ) + ) and total = count(callee.getACall()) | percentage_used = (100.0 * (total - unused) / total).floor() diff --git a/python/ql/src/Resources/FileOpen.qll b/python/ql/src/Resources/FileOpen.qll index dd952e732d4..1daecb6d033 100644 --- a/python/ql/src/Resources/FileOpen.qll +++ b/python/ql/src/Resources/FileOpen.qll @@ -138,12 +138,12 @@ predicate function_opens_file(FunctionValue f) { f = Value::named("open") or exists(EssaVariable v, Return ret | ret.getScope() = f.getScope() | - ret.getValue().getAFlowNode() = v.getAUse() and + v.getNode() = ret.getValue().getAUse() and var_is_open(v, _) ) or exists(Return ret, FunctionValue callee | ret.getScope() = f.getScope() | - ret.getValue().getAFlowNode() = callee.getACall() and + callee.getNode() = ret.getValue().getACall() and function_opens_file(callee) ) } diff --git a/python/ql/src/Security/CWE-798/HardcodedCredentials.ql b/python/ql/src/Security/CWE-798/HardcodedCredentials.ql index 1e7b4452a9a..baeaf26514c 100644 --- a/python/ql/src/Security/CWE-798/HardcodedCredentials.ql +++ b/python/ql/src/Security/CWE-798/HardcodedCredentials.ql @@ -94,7 +94,7 @@ class CredentialSink extends DataFlow::Node { this.(DataFlow::ArgumentNode).argumentOf(_, pos) ) or - exists(Keyword k | k.getArg() = name and k.getValue().getAFlowNode() = this.asCfgNode()) + exists(Keyword k | k.getArg() = name and this.asCfgNode().getNode() = k.getValue()) or exists(CompareNode cmp, NameNode n | n.getId() = name | cmp.operands(this.asCfgNode(), any(Eq eq), n) diff --git a/python/ql/src/Statements/IterableStringOrSequence.ql b/python/ql/src/Statements/IterableStringOrSequence.ql index d1c4a507f0d..ad8b6beab29 100644 --- a/python/ql/src/Statements/IterableStringOrSequence.ql +++ b/python/ql/src/Statements/IterableStringOrSequence.ql @@ -25,7 +25,7 @@ from For loop, ControlFlowNodeWithPointsTo iter, Value str, Value seq, ControlFlowNode seq_origin, ControlFlowNode str_origin where - loop.getIter().getAFlowNode() = iter and + iter.getNode() = loop.getIter() and iter.pointsTo(str, str_origin) and iter.pointsTo(seq, seq_origin) and has_string_type(str) and diff --git a/python/ql/src/Statements/NestedLoopsSameVariableWithReuse.ql b/python/ql/src/Statements/NestedLoopsSameVariableWithReuse.ql index c4deb4e6427..a9c5a5fbbd9 100644 --- a/python/ql/src/Statements/NestedLoopsSameVariableWithReuse.ql +++ b/python/ql/src/Statements/NestedLoopsSameVariableWithReuse.ql @@ -15,7 +15,7 @@ import python predicate loop_variable_ssa(For f, Variable v, SsaVariable s) { - f.getTarget().getAFlowNode() = s.getDefinition() and v = s.getVariable() + s.getDefinition().getNode() = f.getTarget() and v = s.getVariable() } predicate variableUsedInNestedLoops(For inner, For outer, Variable v, Name n) { diff --git a/python/ql/src/Statements/NonIteratorInForLoop.ql b/python/ql/src/Statements/NonIteratorInForLoop.ql index f8e6e51b55f..b0cbc71130d 100644 --- a/python/ql/src/Statements/NonIteratorInForLoop.ql +++ b/python/ql/src/Statements/NonIteratorInForLoop.ql @@ -16,7 +16,7 @@ private import LegacyPointsTo from For loop, ControlFlowNodeWithPointsTo iter, Value v, ClassValue t, ControlFlowNode origin where - loop.getIter().getAFlowNode() = iter and + iter.getNode() = loop.getIter() and iter.pointsTo(_, v, origin) and v.getClass() = t and not t.isIterable() and diff --git a/python/ql/src/Statements/SideEffectInAssert.ql b/python/ql/src/Statements/SideEffectInAssert.ql index 7ac96030c04..55c34144dce 100644 --- a/python/ql/src/Statements/SideEffectInAssert.ql +++ b/python/ql/src/Statements/SideEffectInAssert.ql @@ -24,11 +24,13 @@ predicate func_with_side_effects(Expr e) { } predicate call_with_side_effect(Call e) { - e.getAFlowNode() = - API::moduleImport("subprocess") - .getMember(["call", "check_call", "check_output"]) - .getACall() - .asCfgNode() + exists(ControlFlowNode eCfg | eCfg.getNode() = e | + eCfg = + API::moduleImport("subprocess") + .getMember(["call", "check_call", "check_output"]) + .getACall() + .asCfgNode() + ) } predicate probable_side_effect(Expr e) { diff --git a/python/ql/src/Variables/Definition.qll b/python/ql/src/Variables/Definition.qll index be8c9490788..9bd7130957b 100644 --- a/python/ql/src/Variables/Definition.qll +++ b/python/ql/src/Variables/Definition.qll @@ -133,7 +133,11 @@ class ListComprehensionDeclaration extends ListComp { major_version() = 2 and this.getIterationVariable(_).getId() = result.getId() and result.getScope() = this.getScope() and - this.getAFlowNode().strictlyReaches(result.getAFlowNode()) and + exists(ControlFlowNode thisCfg, ControlFlowNode resultCfg | + thisCfg.getNode() = this and resultCfg.getNode() = result + | + thisCfg.strictlyReaches(resultCfg) + ) and result.isUse() } diff --git a/python/ql/src/Variables/LeakingListComprehension.ql b/python/ql/src/Variables/LeakingListComprehension.ql index 9b98fb43a31..a9baa21661d 100644 --- a/python/ql/src/Variables/LeakingListComprehension.ql +++ b/python/ql/src/Variables/LeakingListComprehension.ql @@ -13,18 +13,21 @@ import python import Definition -from ListComprehensionDeclaration l, Name use, Name defn +from + ListComprehensionDeclaration l, Name use, Name defn, ControlFlowNode lCfg, ControlFlowNode useCfg where use = l.getALeakedVariableUse() and defn = l.getDefinition() and - l.getAFlowNode().strictlyReaches(use.getAFlowNode()) and + lCfg.getNode() = l and + useCfg.getNode() = use and + lCfg.strictlyReaches(useCfg) and /* Make sure we aren't in a loop, as the variable may be redefined */ - not use.getAFlowNode().strictlyReaches(l.getAFlowNode()) and + not useCfg.strictlyReaches(lCfg) and not l.contains(use) and not use.deletes(_) and not exists(SsaVariable v | - v.getAUse() = use.getAFlowNode() and - not v.getDefinition().strictlyDominates(l.getAFlowNode()) + v.getAUse() = useCfg and + not v.getDefinition().strictlyDominates(lCfg) ) select use, use.getId() + " may have a different value in Python 3, as the $@ will not be in scope.", defn, diff --git a/python/ql/src/Variables/Loop.qll b/python/ql/src/Variables/Loop.qll index c7749fe476b..e7c189cac35 100644 --- a/python/ql/src/Variables/Loop.qll +++ b/python/ql/src/Variables/Loop.qll @@ -26,8 +26,11 @@ private Stmt loop_probably_defines(Variable v) { /** Holds if the variable used by `use` is probably defined in a loop */ predicate probably_defined_in_loop(Name use) { - exists(Stmt loop | loop = loop_probably_defines(use.getVariable()) | - loop.getAFlowNode().strictlyReaches(use.getAFlowNode()) + exists(Stmt loop, ControlFlowNode loopCfg, ControlFlowNode useCfg | + loop = loop_probably_defines(use.getVariable()) and + loopCfg.getNode() = loop and + useCfg.getNode() = use and + loopCfg.strictlyReaches(useCfg) ) } diff --git a/python/ql/src/Variables/MultiplyDefined.ql b/python/ql/src/Variables/MultiplyDefined.ql index 3c26ff0b1eb..ce8b5b316c2 100644 --- a/python/ql/src/Variables/MultiplyDefined.ql +++ b/python/ql/src/Variables/MultiplyDefined.ql @@ -24,8 +24,8 @@ predicate multiply_defined(AstNode asgn1, AstNode asgn2, Variable v) { forex(Definition def, Definition redef | def.getVariable() = v and - def = asgn1.getAFlowNode() and - redef = asgn2.getAFlowNode() + def.getNode() = asgn1 and + redef.getNode() = asgn2 | def.isUnused() and def.getARedef() = redef and diff --git a/python/ql/src/Variables/SuspiciousUnusedLoopIterationVariable.ql b/python/ql/src/Variables/SuspiciousUnusedLoopIterationVariable.ql index d252742d67c..f74fd4970ee 100644 --- a/python/ql/src/Variables/SuspiciousUnusedLoopIterationVariable.ql +++ b/python/ql/src/Variables/SuspiciousUnusedLoopIterationVariable.ql @@ -88,7 +88,9 @@ predicate implicit_repeat(For f) { * E.g. gets `x` from `{ y for y in x }`. */ ControlFlowNode get_comp_iterable(For f) { - exists(Comp c | c.getFunction().getStmt(0) = f | c.getAFlowNode().getAPredecessor() = result) + exists(Comp c, ControlFlowNode cCfg | + c.getFunction().getStmt(0) = f and cCfg.getNode() = c and cCfg.getAPredecessor() = result + ) } from For f, Variable v, string msg diff --git a/python/ql/src/Variables/Undefined.qll b/python/ql/src/Variables/Undefined.qll index 42437a81340..b320c2040b2 100644 --- a/python/ql/src/Variables/Undefined.qll +++ b/python/ql/src/Variables/Undefined.qll @@ -19,9 +19,10 @@ private predicate loop_entry_variables(EssaVariable pred, EssaVariable succ) { private predicate loop_entry_edge(BasicBlock pred, BasicBlock loop) { pred = loop.getAPredecessor() and pred = loop.getImmediateDominator() and - exists(Stmt s | + exists(Stmt s, ControlFlowNode sCfg | loop_probably_executes_at_least_once(s) and - s.getAFlowNode().getBasicBlock() = loop + sCfg.getNode() = s and + sCfg.getBasicBlock() = loop ) } diff --git a/python/ql/src/Variables/UndefinedGlobal.ql b/python/ql/src/Variables/UndefinedGlobal.ql index 404ac64aa5a..0c54b444ce3 100644 --- a/python/ql/src/Variables/UndefinedGlobal.ql +++ b/python/ql/src/Variables/UndefinedGlobal.ql @@ -27,7 +27,7 @@ predicate guarded_against_name_error(Name u) { | globals.getFunc().(Name).getId() = "globals" and guard.controls(controlled, _) and - controlled.contains(u.getAFlowNode()) + exists(ControlFlowNode uCfg | uCfg.getNode() = u | controlled.contains(uCfg)) ) } @@ -101,18 +101,18 @@ predicate undefined_use(Name u) { } private predicate first_use_in_a_block(Name use) { - exists(GlobalVariable v, BasicBlock b, int i | - i = min(int j | b.getNode(j).getNode() = v.getALoad()) and b.getNode(i) = use.getAFlowNode() + exists(GlobalVariable v, BasicBlock b, int i, ControlFlowNode useCfg | useCfg.getNode() = use | + i = min(int j | b.getNode(j).getNode() = v.getALoad()) and b.getNode(i) = useCfg ) } predicate first_undefined_use(Name use) { undefined_use(use) and - exists(GlobalVariable v | v.getALoad() = use | + exists(GlobalVariable v, ControlFlowNode useCfg | v.getALoad() = use and useCfg.getNode() = use | first_use_in_a_block(use) and not exists(ControlFlowNode other | other.getNode() = v.getALoad() and - other.getBasicBlock().strictlyDominates(use.getAFlowNode().getBasicBlock()) + other.getBasicBlock().strictlyDominates(useCfg.getBasicBlock()) ) ) } diff --git a/python/ql/src/Variables/UndefinedPlaceHolder.ql b/python/ql/src/Variables/UndefinedPlaceHolder.ql index 29f9b3a1a51..9fa0cc7eaaa 100644 --- a/python/ql/src/Variables/UndefinedPlaceHolder.ql +++ b/python/ql/src/Variables/UndefinedPlaceHolder.ql @@ -18,8 +18,8 @@ private import semmle.python.types.ImportTime /* Local variable part */ predicate initialized_as_local(PlaceHolder use) { - exists(SsaVariableWithPointsTo l, Function f | - f = use.getScope() and l.getAUse() = use.getAFlowNode() + exists(SsaVariableWithPointsTo l, Function f, ControlFlowNode useCfg | + f = use.getScope() and useCfg.getNode() = use and l.getAUse() = useCfg | l.getVariable() instanceof LocalVariable and not l.maybeUndefined() diff --git a/python/ql/src/Variables/UnusedModuleVariable.ql b/python/ql/src/Variables/UnusedModuleVariable.ql index 24d6559d6fe..0443c3388c8 100644 --- a/python/ql/src/Variables/UnusedModuleVariable.ql +++ b/python/ql/src/Variables/UnusedModuleVariable.ql @@ -54,7 +54,7 @@ predicate unused_global(Name unused, GlobalVariable v) { u.uses(v) | // That is reachable from this definition, directly - defn.strictlyReaches(u.getAFlowNode()) + exists(ControlFlowNode uCfg | uCfg.getNode() = u | defn.strictlyReaches(uCfg)) or // indirectly defn.getBasicBlock().reachesExit() and u.getScope() != unused.getScope() diff --git a/python/ql/src/analysis/CrossProjectDefinitions.qll b/python/ql/src/analysis/CrossProjectDefinitions.qll index 64b30f566f1..61e12a09ec6 100644 --- a/python/ql/src/analysis/CrossProjectDefinitions.qll +++ b/python/ql/src/analysis/CrossProjectDefinitions.qll @@ -48,15 +48,17 @@ class Symbol extends TSymbol { AstNode find() { this = TModule(result) or - exists(Symbol s, string name | this = TMember(s, name) | + exists(Symbol s, string name, ControlFlowNode resultCfg | + this = TMember(s, name) and resultCfg.getNode() = result + | exists(ClassObject cls | s.resolvesTo() = cls and - cls.attributeRefersTo(name, _, result.getAFlowNode()) + cls.attributeRefersTo(name, _, resultCfg) ) or exists(ModuleObject m | s.resolvesTo() = m and - m.attributeRefersTo(name, _, result.getAFlowNode()) + m.attributeRefersTo(name, _, resultCfg) ) ) } diff --git a/python/ql/src/analysis/ImportFailure.ql b/python/ql/src/analysis/ImportFailure.ql index 71967e6e04f..760a3693d6e 100644 --- a/python/ql/src/analysis/ImportFailure.ql +++ b/python/ql/src/analysis/ImportFailure.ql @@ -80,10 +80,11 @@ class VersionGuard extends ConditionBlock { VersionGuard() { this.getLastNode() instanceof VersionTest } } -from ImportExpr ie +from ImportExpr ie, ControlFlowNode ieCfg where + ieCfg.getNode() = ie and not ie.(ExprWithPointsTo).refersTo(_) and - exists(Context c | c.appliesTo(ie.getAFlowNode())) and + exists(Context c | c.appliesTo(ieCfg)) and not ok_to_fail(ie) and - not exists(VersionGuard guard | guard.controls(ie.getAFlowNode().getBasicBlock(), _)) + not exists(VersionGuard guard | guard.controls(ieCfg.getBasicBlock(), _)) select ie, "Unable to resolve import of '" + ie.getImportedModuleName() + "'." diff --git a/python/ql/src/analysis/KeyPointsToFailure.ql b/python/ql/src/analysis/KeyPointsToFailure.ql index f07e8638f38..e42e5ac0bdd 100644 --- a/python/ql/src/analysis/KeyPointsToFailure.ql +++ b/python/ql/src/analysis/KeyPointsToFailure.ql @@ -11,13 +11,13 @@ import python import semmle.python.pointsto.PointsTo predicate points_to_failure(Expr e) { - exists(ControlFlowNode f | f = e.getAFlowNode() | not PointsTo::pointsTo(f, _, _, _)) + exists(ControlFlowNode f | f.getNode() = e | not PointsTo::pointsTo(f, _, _, _)) } predicate key_points_to_failure(Expr e) { points_to_failure(e) and not points_to_failure(e.getASubExpression()) and - not exists(SsaVariable ssa | ssa.getAUse() = e.getAFlowNode() | + not exists(SsaVariable ssa, ControlFlowNode eCfg | eCfg.getNode() = e and ssa.getAUse() = eCfg | points_to_failure(ssa.getAnUltimateDefinition().getDefinition().getNode()) ) and not exists(Assign a | a.getATarget() = e) diff --git a/python/ql/src/analysis/PointsToFailure.ql b/python/ql/src/analysis/PointsToFailure.ql index fee1e80d2f7..8d46cbd9095 100644 --- a/python/ql/src/analysis/PointsToFailure.ql +++ b/python/ql/src/analysis/PointsToFailure.ql @@ -12,5 +12,5 @@ import python private import LegacyPointsTo from Expr e -where exists(ControlFlowNodeWithPointsTo f | f = e.getAFlowNode() | not f.refersTo(_)) +where exists(ControlFlowNodeWithPointsTo f | f.getNode() = e | not f.refersTo(_)) select e, "Expression does not 'point-to' any object." diff --git a/python/ql/src/change-notes/2026-06-17-modification-of-locals-cross-scope.md b/python/ql/src/change-notes/released/1.8.5.md similarity index 92% rename from python/ql/src/change-notes/2026-06-17-modification-of-locals-cross-scope.md rename to python/ql/src/change-notes/released/1.8.5.md index 5a625a95511..1b8e94d2a5c 100644 --- a/python/ql/src/change-notes/2026-06-17-modification-of-locals-cross-scope.md +++ b/python/ql/src/change-notes/released/1.8.5.md @@ -1,4 +1,5 @@ ---- -category: minorAnalysis ---- +## 1.8.5 + +### Minor Analysis Improvements + * The `py/modification-of-locals` query no longer flags modifications of a `locals()` dictionary that has been passed out of the scope in which `locals()` was called (for example, by passing it to another function or storing it in an instance attribute). In such cases the dictionary is used as an ordinary mapping and modifying it is meaningful, so these were false positives. The "modification has no effect" claim only applies within the scope that called `locals()`, which is now the only case reported. diff --git a/python/ql/src/codeql-pack.release.yml b/python/ql/src/codeql-pack.release.yml index f2a60cd1327..75869ad94ec 100644 --- a/python/ql/src/codeql-pack.release.yml +++ b/python/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.8.4 +lastReleaseVersion: 1.8.5 diff --git a/python/ql/src/meta/ClassHierarchy/Find.ql b/python/ql/src/meta/ClassHierarchy/Find.ql index 2c474cb2102..e13c683b6f1 100644 --- a/python/ql/src/meta/ClassHierarchy/Find.ql +++ b/python/ql/src/meta/ClassHierarchy/Find.ql @@ -351,7 +351,7 @@ class DjangoHttpRequest extends FindSubclassesSpec { class FlaskClass extends FindSubclassesSpec { FlaskClass() { this = "flask.Flask~Subclass" } - override API::Node getAlreadyModeledClass() { result = Flask::FlaskApp::classRef() } + override API::Node getAlreadyModeledClass() { result = Flask::FlaskApp::subclassRef() } } class FlaskBlueprint extends FindSubclassesSpec { diff --git a/python/ql/src/qlpack.yml b/python/ql/src/qlpack.yml index 0eba954079e..a4a2db0e660 100644 --- a/python/ql/src/qlpack.yml +++ b/python/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/python-queries -version: 1.8.5-dev +version: 1.8.6-dev groups: - python - queries diff --git a/python/ql/src/semmle/python/functions/ModificationOfParameterWithDefaultCustomizations.qll b/python/ql/src/semmle/python/functions/ModificationOfParameterWithDefaultCustomizations.qll index c7aef20c09d..83ba4df4e29 100644 --- a/python/ql/src/semmle/python/functions/ModificationOfParameterWithDefaultCustomizations.qll +++ b/python/ql/src/semmle/python/functions/ModificationOfParameterWithDefaultCustomizations.qll @@ -131,7 +131,7 @@ module ModificationOfParameterWithDefault { exists(DeletionNode d | d.getTarget().(SubscriptNode).getObject() = this.asCfgNode()) or // augmented assignment to the value - exists(AugAssign a | a.getTarget().getAFlowNode() = this.asCfgNode()) + exists(AugAssign a | this.asCfgNode().getNode() = a.getTarget()) or // modifying function call exists(DataFlow::CallCfgNode c, DataFlow::AttrRead a | c.getFunction() = a | diff --git a/python/ql/test/2/library-tests/comprehensions/ConsistencyCheck.ql b/python/ql/test/2/library-tests/comprehensions/ConsistencyCheck.ql index 2f5191fb547..c1a214e40c7 100644 --- a/python/ql/test/2/library-tests/comprehensions/ConsistencyCheck.ql +++ b/python/ql/test/2/library-tests/comprehensions/ConsistencyCheck.ql @@ -5,5 +5,7 @@ import python select count(Comprehension c | - count(c.toString()) != 1 or count(c.getLocation()) != 1 or not exists(c.getAFlowNode()) + count(c.toString()) != 1 or + count(c.getLocation()) != 1 or + not exists(ControlFlowNode n | n.getNode() = c) ) diff --git a/python/ql/test/2/query-tests/Classes/new-style/PropertyInOldStyleClass.qlref b/python/ql/test/2/query-tests/Classes/new-style/PropertyInOldStyleClass.qlref index 297295c006e..fa194766511 100644 --- a/python/ql/test/2/query-tests/Classes/new-style/PropertyInOldStyleClass.qlref +++ b/python/ql/test/2/query-tests/Classes/new-style/PropertyInOldStyleClass.qlref @@ -1 +1,2 @@ -Classes/PropertyInOldStyleClass.ql +query: Classes/PropertyInOldStyleClass.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/2/query-tests/Classes/new-style/SlotsInOldStyleClass.qlref b/python/ql/test/2/query-tests/Classes/new-style/SlotsInOldStyleClass.qlref index 62fb3202a16..688f31402ad 100644 --- a/python/ql/test/2/query-tests/Classes/new-style/SlotsInOldStyleClass.qlref +++ b/python/ql/test/2/query-tests/Classes/new-style/SlotsInOldStyleClass.qlref @@ -1 +1,2 @@ -Classes/SlotsInOldStyleClass.ql \ No newline at end of file +query: Classes/SlotsInOldStyleClass.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/2/query-tests/Classes/new-style/SuperInOldStyleClass.qlref b/python/ql/test/2/query-tests/Classes/new-style/SuperInOldStyleClass.qlref index 08f737893ef..293fc72d86c 100644 --- a/python/ql/test/2/query-tests/Classes/new-style/SuperInOldStyleClass.qlref +++ b/python/ql/test/2/query-tests/Classes/new-style/SuperInOldStyleClass.qlref @@ -1 +1,2 @@ -Classes/SuperInOldStyleClass.ql \ No newline at end of file +query: Classes/SuperInOldStyleClass.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/2/query-tests/Classes/new-style/newstyle_test.py b/python/ql/test/2/query-tests/Classes/new-style/newstyle_test.py index f1e3ea8e42c..44dce333ef9 100644 --- a/python/ql/test/2/query-tests/Classes/new-style/newstyle_test.py +++ b/python/ql/test/2/query-tests/Classes/new-style/newstyle_test.py @@ -1,7 +1,7 @@ #Only works for Python2 -class OldStyle1: +class OldStyle1: # $ Alert[py/slots-in-old-style-class] __slots__ = [ 'a', 'b' ] @@ -12,7 +12,7 @@ class OldStyle1: class OldStyle2: def __init__(self, x): - super().__init__(x) + super().__init__(x) # $ Alert[py/super-in-old-style] class NewStyle1(object): diff --git a/python/ql/test/2/query-tests/Classes/new-style/property_old_style.py b/python/ql/test/2/query-tests/Classes/new-style/property_old_style.py index 8291feab26c..0b529d9edb7 100644 --- a/python/ql/test/2/query-tests/Classes/new-style/property_old_style.py +++ b/python/ql/test/2/query-tests/Classes/new-style/property_old_style.py @@ -5,6 +5,6 @@ class OldStyle: def __init__(self, x): self._x = x - @property + @property # $ Alert[py/property-in-old-style-class] def piosc(self): return self._x \ No newline at end of file diff --git a/python/ql/test/2/query-tests/Exceptions/general/CatchingBaseException.qlref b/python/ql/test/2/query-tests/Exceptions/general/CatchingBaseException.qlref index 5588dbf2c7b..33b4697e7ef 100644 --- a/python/ql/test/2/query-tests/Exceptions/general/CatchingBaseException.qlref +++ b/python/ql/test/2/query-tests/Exceptions/general/CatchingBaseException.qlref @@ -1 +1,2 @@ -Exceptions/CatchingBaseException.ql \ No newline at end of file +query: Exceptions/CatchingBaseException.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/2/query-tests/Exceptions/general/EmptyExcept.qlref b/python/ql/test/2/query-tests/Exceptions/general/EmptyExcept.qlref index 3f4987046b1..7a046d008cd 100644 --- a/python/ql/test/2/query-tests/Exceptions/general/EmptyExcept.qlref +++ b/python/ql/test/2/query-tests/Exceptions/general/EmptyExcept.qlref @@ -1 +1,2 @@ -Exceptions/EmptyExcept.ql \ No newline at end of file +query: Exceptions/EmptyExcept.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/2/query-tests/Exceptions/general/IncorrectExceptOrder.qlref b/python/ql/test/2/query-tests/Exceptions/general/IncorrectExceptOrder.qlref index bc4c3a07081..f4278558baa 100644 --- a/python/ql/test/2/query-tests/Exceptions/general/IncorrectExceptOrder.qlref +++ b/python/ql/test/2/query-tests/Exceptions/general/IncorrectExceptOrder.qlref @@ -1 +1,2 @@ -Exceptions/IncorrectExceptOrder.ql +query: Exceptions/IncorrectExceptOrder.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/2/query-tests/Exceptions/generators/UnguardedNextInGenerator.qlref b/python/ql/test/2/query-tests/Exceptions/generators/UnguardedNextInGenerator.qlref index 7fe5d609705..f174a4a96f5 100644 --- a/python/ql/test/2/query-tests/Exceptions/generators/UnguardedNextInGenerator.qlref +++ b/python/ql/test/2/query-tests/Exceptions/generators/UnguardedNextInGenerator.qlref @@ -1 +1,2 @@ -Exceptions/UnguardedNextInGenerator.ql \ No newline at end of file +query: Exceptions/UnguardedNextInGenerator.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/2/query-tests/Exceptions/generators/test.py b/python/ql/test/2/query-tests/Exceptions/generators/test.py index e8b3f0b2b34..0c5ca29f798 100644 --- a/python/ql/test/2/query-tests/Exceptions/generators/test.py +++ b/python/ql/test/2/query-tests/Exceptions/generators/test.py @@ -2,12 +2,12 @@ def bad1(it): while True: - yield next(it) + yield next(it) # $ Alert def bad2(seq): it = iter(seq) #Not OK as seq may be empty - raise KeyError(next(it)) + raise KeyError(next(it)) # $ Alert yield 0 def ok1(seq): diff --git a/python/ql/test/2/query-tests/Exceptions/raising/RaisingTuple.qlref b/python/ql/test/2/query-tests/Exceptions/raising/RaisingTuple.qlref index 55d1f5e1d4f..1cefef85d8a 100644 --- a/python/ql/test/2/query-tests/Exceptions/raising/RaisingTuple.qlref +++ b/python/ql/test/2/query-tests/Exceptions/raising/RaisingTuple.qlref @@ -1 +1,2 @@ -Exceptions/RaisingTuple.ql +query: Exceptions/RaisingTuple.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/2/query-tests/Exceptions/raising/test.py b/python/ql/test/2/query-tests/Exceptions/raising/test.py index ff991f642e2..1e5f3cb35fc 100644 --- a/python/ql/test/2/query-tests/Exceptions/raising/test.py +++ b/python/ql/test/2/query-tests/Exceptions/raising/test.py @@ -5,11 +5,11 @@ def ok(): def bad1(): ex = Exception, "message" - raise ex + raise ex # $ Alert def bad2(): - raise (Exception, "message") + raise (Exception, "message") # $ Alert def bad3(): ex = Exception, - raise ex, "message" + raise ex, "message" # $ Alert diff --git a/python/ql/test/2/query-tests/Expressions/UseofApply.py b/python/ql/test/2/query-tests/Expressions/UseofApply.py index 9109636f99e..6c2255012e6 100644 --- a/python/ql/test/2/query-tests/Expressions/UseofApply.py +++ b/python/ql/test/2/query-tests/Expressions/UseofApply.py @@ -16,7 +16,7 @@ def useofapply(): # This use of `apply` is a reference to the builtin function and so SHOULD be # caught by the query. - apply(foo, [1]) + apply(foo, [1]) # $ Alert[py/use-of-apply] diff --git a/python/ql/test/2/query-tests/Expressions/UseofApply.qlref b/python/ql/test/2/query-tests/Expressions/UseofApply.qlref index abf684e3918..4add79acdb3 100644 --- a/python/ql/test/2/query-tests/Expressions/UseofApply.qlref +++ b/python/ql/test/2/query-tests/Expressions/UseofApply.qlref @@ -1 +1,2 @@ -Expressions/UseofApply.ql +query: Expressions/UseofApply.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/2/query-tests/Expressions/UseofInput.qlref b/python/ql/test/2/query-tests/Expressions/UseofInput.qlref index 3f9590f48b2..2684126de5e 100644 --- a/python/ql/test/2/query-tests/Expressions/UseofInput.qlref +++ b/python/ql/test/2/query-tests/Expressions/UseofInput.qlref @@ -1 +1,2 @@ -Expressions/UseofInput.ql \ No newline at end of file +query: Expressions/UseofInput.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/2/query-tests/Expressions/expressions_test.py b/python/ql/test/2/query-tests/Expressions/expressions_test.py index c31681e3535..6889822b791 100644 --- a/python/ql/test/2/query-tests/Expressions/expressions_test.py +++ b/python/ql/test/2/query-tests/Expressions/expressions_test.py @@ -1,9 +1,9 @@ def use_of_apply(func, args): - apply(func, args) + apply(func, args) # $ Alert[py/use-of-apply] def use_of_input(): - return input() # NOT OK + return input() # $ Alert[py/use-of-input] # NOT OK def not_use_of_input(): diff --git a/python/ql/test/2/query-tests/Functions/DeprecatedSliceMethod.qlref b/python/ql/test/2/query-tests/Functions/DeprecatedSliceMethod.qlref index c38b8d1f761..3043411c1ce 100644 --- a/python/ql/test/2/query-tests/Functions/DeprecatedSliceMethod.qlref +++ b/python/ql/test/2/query-tests/Functions/DeprecatedSliceMethod.qlref @@ -1 +1,2 @@ -Functions/DeprecatedSliceMethod.ql \ No newline at end of file +query: Functions/DeprecatedSliceMethod.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/2/query-tests/Imports/encoding_error/EncodingError.qlref b/python/ql/test/2/query-tests/Imports/encoding_error/EncodingError.qlref index a7e91769ded..bc78d28db32 100644 --- a/python/ql/test/2/query-tests/Imports/encoding_error/EncodingError.qlref +++ b/python/ql/test/2/query-tests/Imports/encoding_error/EncodingError.qlref @@ -1 +1,2 @@ -Imports/EncodingError.ql +query: Imports/EncodingError.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/2/query-tests/Imports/syntax_error/EncodingError.qlref b/python/ql/test/2/query-tests/Imports/syntax_error/EncodingError.qlref index e742356f865..bc78d28db32 100644 --- a/python/ql/test/2/query-tests/Imports/syntax_error/EncodingError.qlref +++ b/python/ql/test/2/query-tests/Imports/syntax_error/EncodingError.qlref @@ -1 +1,2 @@ -Imports/EncodingError.ql \ No newline at end of file +query: Imports/EncodingError.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/2/query-tests/Imports/syntax_error/SyntaxError.qlref b/python/ql/test/2/query-tests/Imports/syntax_error/SyntaxError.qlref index c143a01fe8b..5d0698be3de 100644 --- a/python/ql/test/2/query-tests/Imports/syntax_error/SyntaxError.qlref +++ b/python/ql/test/2/query-tests/Imports/syntax_error/SyntaxError.qlref @@ -1 +1,2 @@ -Imports/SyntaxError.ql \ No newline at end of file +query: Imports/SyntaxError.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/2/query-tests/Imports/syntax_error/bad_encoding.py b/python/ql/test/2/query-tests/Imports/syntax_error/bad_encoding.py index 9c61b1e1b11..5e3308df0f5 100644 --- a/python/ql/test/2/query-tests/Imports/syntax_error/bad_encoding.py +++ b/python/ql/test/2/query-tests/Imports/syntax_error/bad_encoding.py @@ -8,5 +8,5 @@ # encoding:shift-jis def f(): - print "Python ‚ÌŠJ”­‚ÍA1990 ”N‚²‚ë‚©‚çŠJŽn‚³‚ê‚Ä‚¢‚Ü‚·" + print "Python ‚ÌŠJ”­‚ÍA1990 ”N‚²‚ë‚©‚çŠJŽn‚³‚ê‚Ä‚¢‚Ü‚·" # $ Alert[py/encoding-error] """ diff --git a/python/ql/test/2/query-tests/Imports/syntax_error/nonsense.py b/python/ql/test/2/query-tests/Imports/syntax_error/nonsense.py index e413967af41..f5cd27b313b 100644 --- a/python/ql/test/2/query-tests/Imports/syntax_error/nonsense.py +++ b/python/ql/test/2/query-tests/Imports/syntax_error/nonsense.py @@ -1,4 +1,4 @@ -`Twas brillig, and the slithy toves +`Twas brillig, and the slithy toves # $ Alert[py/syntax-error] Did gyre and gimble in the wabe: All mimsy were the borogoves, And the mome raths outgrabe. diff --git a/python/ql/test/2/query-tests/Lexical/OldOctalLiteral.qlref b/python/ql/test/2/query-tests/Lexical/OldOctalLiteral.qlref index 40040c873d6..e5b4fdfec57 100644 --- a/python/ql/test/2/query-tests/Lexical/OldOctalLiteral.qlref +++ b/python/ql/test/2/query-tests/Lexical/OldOctalLiteral.qlref @@ -1 +1,2 @@ -Lexical/OldOctalLiteral.ql \ No newline at end of file +query: Lexical/OldOctalLiteral.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/2/query-tests/Lexical/lexical_test.py b/python/ql/test/2/query-tests/Lexical/lexical_test.py index 4b82b17cc65..412c24683d1 100644 --- a/python/ql/test/2/query-tests/Lexical/lexical_test.py +++ b/python/ql/test/2/query-tests/Lexical/lexical_test.py @@ -1,6 +1,6 @@ #Bad Octal literal -017 +017 # $ Alert #Good Octal literal 0o17 #Special case file permissions diff --git a/python/ql/test/2/query-tests/Statements/ExecUsed.qlref b/python/ql/test/2/query-tests/Statements/ExecUsed.qlref index ccff89d6815..286996305ed 100644 --- a/python/ql/test/2/query-tests/Statements/ExecUsed.qlref +++ b/python/ql/test/2/query-tests/Statements/ExecUsed.qlref @@ -1 +1,2 @@ -Statements/ExecUsed.ql \ No newline at end of file +query: Statements/ExecUsed.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/2/query-tests/Statements/TopLevelPrint.qlref b/python/ql/test/2/query-tests/Statements/TopLevelPrint.qlref index 8271065261d..e91717901f3 100644 --- a/python/ql/test/2/query-tests/Statements/TopLevelPrint.qlref +++ b/python/ql/test/2/query-tests/Statements/TopLevelPrint.qlref @@ -1 +1,2 @@ -Statements/TopLevelPrint.ql \ No newline at end of file +query: Statements/TopLevelPrint.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/2/query-tests/Statements/module.py b/python/ql/test/2/query-tests/Statements/module.py index 0b1f4d26546..af34eedf0dc 100644 --- a/python/ql/test/2/query-tests/Statements/module.py +++ b/python/ql/test/2/query-tests/Statements/module.py @@ -1,2 +1,2 @@ #Top level prints in modules are bad -print ("Side effect on import") \ No newline at end of file +print ("Side effect on import") # $ Alert[py/print-during-import] \ No newline at end of file diff --git a/python/ql/test/2/query-tests/Statements/statements_test.py b/python/ql/test/2/query-tests/Statements/statements_test.py index e540608964d..46e91c25c31 100644 --- a/python/ql/test/2/query-tests/Statements/statements_test.py +++ b/python/ql/test/2/query-tests/Statements/statements_test.py @@ -2,7 +2,7 @@ def exec_used(val): - exec (val) + exec (val) # $ Alert[py/use-of-exec] #Top level print import module diff --git a/python/ql/test/2/query-tests/Variables/LeakyComp/LeakyComp.qlref b/python/ql/test/2/query-tests/Variables/LeakyComp/LeakyComp.qlref index 0f6dd50a281..6b4ece7f127 100644 --- a/python/ql/test/2/query-tests/Variables/LeakyComp/LeakyComp.qlref +++ b/python/ql/test/2/query-tests/Variables/LeakyComp/LeakyComp.qlref @@ -1 +1,2 @@ -Variables/LeakingListComprehension.ql \ No newline at end of file +query: Variables/LeakingListComprehension.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/2/query-tests/Variables/LeakyComp/test.py b/python/ql/test/2/query-tests/Variables/LeakyComp/test.py index 0cd6a0d2520..bbb5d33328f 100644 --- a/python/ql/test/2/query-tests/Variables/LeakyComp/test.py +++ b/python/ql/test/2/query-tests/Variables/LeakyComp/test.py @@ -2,12 +2,12 @@ from __future__ import print_function def undefined_in_3(): [x for x in range(3)] - print(x) + print(x) # $ Alert def different_in_3(): y = 10 [y for y in range(3)] - print(y) + print(y) # $ Alert def ok(): [z for z in range(4)] diff --git a/python/ql/test/3/query-tests/Expressions/UseofApply/UseofApply.qlref b/python/ql/test/3/query-tests/Expressions/UseofApply/UseofApply.qlref index abf684e3918..4add79acdb3 100644 --- a/python/ql/test/3/query-tests/Expressions/UseofApply/UseofApply.qlref +++ b/python/ql/test/3/query-tests/Expressions/UseofApply/UseofApply.qlref @@ -1 +1,2 @@ -Expressions/UseofApply.ql +query: Expressions/UseofApply.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/3/query-tests/Imports/encoding_error/EncodingError.qlref b/python/ql/test/3/query-tests/Imports/encoding_error/EncodingError.qlref index a7e91769ded..bc78d28db32 100644 --- a/python/ql/test/3/query-tests/Imports/encoding_error/EncodingError.qlref +++ b/python/ql/test/3/query-tests/Imports/encoding_error/EncodingError.qlref @@ -1 +1,2 @@ -Imports/EncodingError.ql +query: Imports/EncodingError.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/3/query-tests/Imports/syntax_error/EncodingError.qlref b/python/ql/test/3/query-tests/Imports/syntax_error/EncodingError.qlref index e742356f865..bc78d28db32 100644 --- a/python/ql/test/3/query-tests/Imports/syntax_error/EncodingError.qlref +++ b/python/ql/test/3/query-tests/Imports/syntax_error/EncodingError.qlref @@ -1 +1,2 @@ -Imports/EncodingError.ql \ No newline at end of file +query: Imports/EncodingError.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/3/query-tests/Imports/syntax_error/SyntaxError.qlref b/python/ql/test/3/query-tests/Imports/syntax_error/SyntaxError.qlref index c143a01fe8b..5d0698be3de 100644 --- a/python/ql/test/3/query-tests/Imports/syntax_error/SyntaxError.qlref +++ b/python/ql/test/3/query-tests/Imports/syntax_error/SyntaxError.qlref @@ -1 +1,2 @@ -Imports/SyntaxError.ql \ No newline at end of file +query: Imports/SyntaxError.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/3/query-tests/Imports/syntax_error/bad_encoding.py b/python/ql/test/3/query-tests/Imports/syntax_error/bad_encoding.py index 9c61b1e1b11..5e3308df0f5 100644 --- a/python/ql/test/3/query-tests/Imports/syntax_error/bad_encoding.py +++ b/python/ql/test/3/query-tests/Imports/syntax_error/bad_encoding.py @@ -8,5 +8,5 @@ # encoding:shift-jis def f(): - print "Python ‚ÌŠJ”­‚ÍA1990 ”N‚²‚ë‚©‚çŠJŽn‚³‚ê‚Ä‚¢‚Ü‚·" + print "Python ‚ÌŠJ”­‚ÍA1990 ”N‚²‚ë‚©‚çŠJŽn‚³‚ê‚Ä‚¢‚Ü‚·" # $ Alert[py/encoding-error] """ diff --git a/python/ql/test/3/query-tests/Imports/syntax_error/nonsense.py b/python/ql/test/3/query-tests/Imports/syntax_error/nonsense.py index 66cdd526fba..e0819afbc5e 100644 --- a/python/ql/test/3/query-tests/Imports/syntax_error/nonsense.py +++ b/python/ql/test/3/query-tests/Imports/syntax_error/nonsense.py @@ -1,4 +1,4 @@ - `Twas brillig, and the slithy toves + `Twas brillig, and the slithy toves # $ Alert[py/syntax-error] Did gyre and gimble in the wabe: All mimsy were the borogoves, And the mome raths outgrabe. diff --git a/python/ql/test/3/query-tests/Statements/general/ExecUsed.qlref b/python/ql/test/3/query-tests/Statements/general/ExecUsed.qlref index ccff89d6815..286996305ed 100644 --- a/python/ql/test/3/query-tests/Statements/general/ExecUsed.qlref +++ b/python/ql/test/3/query-tests/Statements/general/ExecUsed.qlref @@ -1 +1,2 @@ -Statements/ExecUsed.ql \ No newline at end of file +query: Statements/ExecUsed.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/3/query-tests/Statements/general/TopLevelPrint.qlref b/python/ql/test/3/query-tests/Statements/general/TopLevelPrint.qlref index 8271065261d..e91717901f3 100644 --- a/python/ql/test/3/query-tests/Statements/general/TopLevelPrint.qlref +++ b/python/ql/test/3/query-tests/Statements/general/TopLevelPrint.qlref @@ -1 +1,2 @@ -Statements/TopLevelPrint.ql \ No newline at end of file +query: Statements/TopLevelPrint.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/3/query-tests/Statements/general/module.py b/python/ql/test/3/query-tests/Statements/general/module.py index 0b1f4d26546..af34eedf0dc 100644 --- a/python/ql/test/3/query-tests/Statements/general/module.py +++ b/python/ql/test/3/query-tests/Statements/general/module.py @@ -1,2 +1,2 @@ #Top level prints in modules are bad -print ("Side effect on import") \ No newline at end of file +print ("Side effect on import") # $ Alert[py/print-during-import] \ No newline at end of file diff --git a/python/ql/test/3/query-tests/Statements/general/statements_test.py b/python/ql/test/3/query-tests/Statements/general/statements_test.py index 2baee458c04..a4414a40f80 100644 --- a/python/ql/test/3/query-tests/Statements/general/statements_test.py +++ b/python/ql/test/3/query-tests/Statements/general/statements_test.py @@ -2,7 +2,7 @@ def exec_used(val): - exec(val) + exec(val) # $ Alert[py/use-of-exec] #Top level print import module diff --git a/python/ql/test/3/query-tests/Statements/unreachable/UnreachableCode.qlref b/python/ql/test/3/query-tests/Statements/unreachable/UnreachableCode.qlref index 5b7891f0026..b95a67d2494 100644 --- a/python/ql/test/3/query-tests/Statements/unreachable/UnreachableCode.qlref +++ b/python/ql/test/3/query-tests/Statements/unreachable/UnreachableCode.qlref @@ -1 +1,2 @@ -Statements/UnreachableCode.ql +query: Statements/UnreachableCode.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/3/query-tests/Statements/unreachable_suppressed/UnreachableCode.qlref b/python/ql/test/3/query-tests/Statements/unreachable_suppressed/UnreachableCode.qlref index 5b7891f0026..b95a67d2494 100644 --- a/python/ql/test/3/query-tests/Statements/unreachable_suppressed/UnreachableCode.qlref +++ b/python/ql/test/3/query-tests/Statements/unreachable_suppressed/UnreachableCode.qlref @@ -1 +1,2 @@ -Statements/UnreachableCode.ql +query: Statements/UnreachableCode.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/experimental/import-resolution/importflow.ql b/python/ql/test/experimental/import-resolution/importflow.ql index a3e20123fc7..15a4498aa11 100644 --- a/python/ql/test/experimental/import-resolution/importflow.ql +++ b/python/ql/test/experimental/import-resolution/importflow.ql @@ -45,13 +45,15 @@ private class VersionGuardedNode extends DataFlow::Node { VersionGuardedNode() { version in [2, 3] and - exists(If parent, CompareNode c | parent.getBody().contains(this.asExpr()) | + exists(If parent, CompareNode c, ControlFlowNode litCfg | + parent.getBody().contains(this.asExpr()) and + litCfg.getNode() = any(IntegerLiteral lit | lit.getValue() = version) + | c.operands(API::moduleImport("sys") .getMember("version_info") .getASubscript() .asSource() - .asCfgNode(), any(Eq eq), - any(IntegerLiteral lit | lit.getValue() = version).getAFlowNode()) + .asCfgNode(), any(Eq eq), litCfg) ) } diff --git a/python/ql/test/experimental/meta/InlineInstanceTest.qll b/python/ql/test/experimental/meta/InlineInstanceTest.qll new file mode 100644 index 00000000000..c4ef66e3510 --- /dev/null +++ b/python/ql/test/experimental/meta/InlineInstanceTest.qll @@ -0,0 +1,29 @@ +/** + * Defines an InlineExpectationsTest for class instances, that is, + * for any API::Node that is an instance of a class (e.g. `Flask`). + */ + +import python +import semmle.python.ApiGraphs +import utils.test.InlineExpectationsTest +private import semmle.python.dataflow.new.internal.PrintNode + +signature API::Node getInstanceSig(); + +module MakeInlineInstanceTest { + private module InlineInstanceTest implements TestSig { + string getARelevantTag() { result = "instance" } + + predicate hasActualResult(Location location, string element, string tag, string value) { + exists(location.getFile().getRelativePath()) and + exists(API::Node instance | instance = getInstance() | + location = instance.getLocation() and + element = prettyNode(instance.asSource()) and + value = "" and + tag = "instance" + ) + } + } + + import MakeTest +} diff --git a/python/ql/test/experimental/query-tests/Classes/Naming/NamingConventionsClasses.py b/python/ql/test/experimental/query-tests/Classes/Naming/NamingConventionsClasses.py index c07bdb57234..46633a009f7 100644 --- a/python/ql/test/experimental/query-tests/Classes/Naming/NamingConventionsClasses.py +++ b/python/ql/test/experimental/query-tests/Classes/Naming/NamingConventionsClasses.py @@ -1,5 +1,5 @@ # BAD, do not start class or interface name with lowercase letter -class badName: +class badName: # $ Alert def hello(self): print("hello") diff --git a/python/ql/test/experimental/query-tests/Classes/Naming/NamingConventionsClasses.qlref b/python/ql/test/experimental/query-tests/Classes/Naming/NamingConventionsClasses.qlref index 7ed945d782c..b5b73c19bf8 100644 --- a/python/ql/test/experimental/query-tests/Classes/Naming/NamingConventionsClasses.qlref +++ b/python/ql/test/experimental/query-tests/Classes/Naming/NamingConventionsClasses.qlref @@ -1 +1,2 @@ -experimental/Classes/NamingConventionsClasses.ql \ No newline at end of file +query: experimental/Classes/NamingConventionsClasses.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/experimental/query-tests/Functions/general/NamingConventionsFunctions.py b/python/ql/test/experimental/query-tests/Functions/general/NamingConventionsFunctions.py index fb3e89ab8e9..5923ce5919f 100644 --- a/python/ql/test/experimental/query-tests/Functions/general/NamingConventionsFunctions.py +++ b/python/ql/test/experimental/query-tests/Functions/general/NamingConventionsFunctions.py @@ -1,7 +1,7 @@ class Test: # BAD, do not start function name with uppercase letter - def HelloWorld(self): + def HelloWorld(self): # $ Alert print("hello world") # GOOD, function name starts with lowercase letter diff --git a/python/ql/test/experimental/query-tests/Functions/general/NamingConventionsFunctions.qlref b/python/ql/test/experimental/query-tests/Functions/general/NamingConventionsFunctions.qlref index 0204694de0a..21d3e5fe135 100644 --- a/python/ql/test/experimental/query-tests/Functions/general/NamingConventionsFunctions.qlref +++ b/python/ql/test/experimental/query-tests/Functions/general/NamingConventionsFunctions.qlref @@ -1 +1,2 @@ -experimental/Functions/NamingConventionsFunctions.ql \ No newline at end of file +query: experimental/Functions/NamingConventionsFunctions.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/experimental/query-tests/Security/CWE-022-TarSlip/TarSlip.qlref b/python/ql/test/experimental/query-tests/Security/CWE-022-TarSlip/TarSlip.qlref index a518196b698..2842a87d080 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-022-TarSlip/TarSlip.qlref +++ b/python/ql/test/experimental/query-tests/Security/CWE-022-TarSlip/TarSlip.qlref @@ -1 +1,2 @@ -experimental/Security/CWE-022bis/TarSlipImprov.ql +query: experimental/Security/CWE-022bis/TarSlipImprov.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/experimental/query-tests/Security/CWE-022-TarSlip/TarSlipImprov.py b/python/ql/test/experimental/query-tests/Security/CWE-022-TarSlip/TarSlipImprov.py index 15bc66b4aea..3b59f24e402 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-022-TarSlip/TarSlipImprov.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-022-TarSlip/TarSlipImprov.py @@ -12,14 +12,14 @@ import os.path unsafe_filename_tar = sys.argv[2] safe_filename_tar = "safe_path.tar" -tar = tarfile.open(unsafe_filename_tar) +tar = tarfile.open(unsafe_filename_tar) # $ Source[py/tarslip-extended] result = [] for member in tar: if ".." in member.name: raise ValueError("Path in member name !!!") result.append(member) path = unsafe_filename_tar -tar.extractall(path=path, members=result) +tar.extractall(path=path, members=result) # $ Alert[py/tarslip-extended] tar.close() @@ -35,27 +35,27 @@ def members_filter1(tarfile): result.append(member) return result -tar = tarfile.open(unsafe_filename_tar) -tar.extractall(path=tempfile.mkdtemp(), members=members_filter1(tar)) +tar = tarfile.open(unsafe_filename_tar) # $ Source[py/tarslip-extended] +tar.extractall(path=tempfile.mkdtemp(), members=members_filter1(tar)) # $ Alert[py/tarslip-extended] tar.close() -with tarfile.open(unsafe_filename_tar) as tar: +with tarfile.open(unsafe_filename_tar) as tar: # $ Source[py/tarslip-extended] for entry in tar: if ".." in entry.name: raise ValueError("Illegal tar archive entry") - tar.extract(entry, "/tmp/unpack/") + tar.extract(entry, "/tmp/unpack/") # $ Alert[py/tarslip-extended] def _validate_archive_name(name, target): if not os.path.abspath(os.path.join(target, name)).startswith(target + os.path.sep): raise ValueError(f"Provided language pack contains invalid name {name}") -with tarfile.open(unsafe_filename_tar) as tar: +with tarfile.open(unsafe_filename_tar) as tar: # $ Source[py/tarslip-extended] target = "/tmp/unpack" for entry in tar: _validate_archive_name(entry.name, target) - tar.extract(entry, target) + tar.extract(entry, target) # $ Alert[py/tarslip-extended] def members_filter2(tarfile): @@ -85,10 +85,10 @@ def _validate_archive_name(name, target): raise ValueError(f"Provided language pack contains invalid name {name}") target = "/tmp/unpack" -with tarfile.open(unsafe_filename_tar, "r") as tar: +with tarfile.open(unsafe_filename_tar, "r") as tar: # $ Source[py/tarslip-extended] for info in tar.getmembers(): _validate_tar_info(info, target) - tar.extractall(target) + tar.extractall(target) # $ Alert[py/tarslip-extended] def members_filter3(tarfile): @@ -108,11 +108,11 @@ tar.extractall(path=tempfile.mkdtemp(), members=members_filter3(tar)) tar.close() -tar = tarfile.open(unsafe_filename_tar) +tar = tarfile.open(unsafe_filename_tar) # $ Source[py/tarslip-extended] tarf = tar.getmembers() for f in tarf: if not f.issym(): - tar.extractall(path=tempfile.mkdtemp(), members=[f]) + tar.extractall(path=tempfile.mkdtemp(), members=[f]) # $ Alert[py/tarslip-extended] tar.close() @@ -120,27 +120,27 @@ class MKTar(TarFile): pass tarball = unsafe_filename_tar -with MKTar.open(name=tarball) as tar: +with MKTar.open(name=tarball) as tar: # $ Source[py/tarslip-extended] for entry in tar: - tar._extract_member(entry, entry.name) + tar._extract_member(entry, entry.name) # $ Alert[py/tarslip-extended] tarball = unsafe_filename_tar -with tarfile.open(tarball) as tar: - tar.extractall() +with tarfile.open(tarball) as tar: # $ Source[py/tarslip-extended] + tar.extractall() # $ Alert[py/tarslip-extended] -tar = tarfile.open(unsafe_filename_tar) -tar.extractall(path=tempfile.mkdtemp(), members=None) +tar = tarfile.open(unsafe_filename_tar) # $ Source[py/tarslip-extended] +tar.extractall(path=tempfile.mkdtemp(), members=None) # $ Alert[py/tarslip-extended] class MKTar(tarfile.TarFile): pass tarball = unsafe_filename_tar -with MKTar.open(name=tarball) as tar: +with MKTar.open(name=tarball) as tar: # $ Source[py/tarslip-extended] for entry in tar: - tar._extract_member(entry, entry.name) + tar._extract_member(entry, entry.name) # $ Alert[py/tarslip-extended] @contextmanager @@ -148,7 +148,7 @@ def py2_tarxz(filename): with tempfile.TemporaryFile() as tmp: subprocess.check_call(["xz", "-dc", filename], stdout=tmp.fileno()) tmp.seek(0) - with closing(tarfile.TarFile(fileobj=tmp)) as tf: + with closing(tarfile.TarFile(fileobj=tmp)) as tf: # $ Source[py/tarslip-extended] yield tf def unpack_tarball(tar_filename, dest): @@ -156,7 +156,7 @@ def unpack_tarball(tar_filename, dest): # Py 2.7 lacks lzma support tar_cm = py2_tarxz(tar_filename) else: - tar_cm = closing(tarfile.open(tar_filename)) + tar_cm = closing(tarfile.open(tar_filename)) # $ Source[py/tarslip-extended] base_dir = None with tar_cm as tarc: @@ -166,32 +166,32 @@ def unpack_tarball(tar_filename, dest): base_dir = base_name elif base_dir != base_name: print('Unexpected path in %s: %s' % (tar_filename, base_name)) - tarc.extractall(dest) + tarc.extractall(dest) # $ Alert[py/tarslip-extended] return os.path.join(dest, base_dir) unpack_tarball(unsafe_filename_tar, "/tmp/unpack") tarball = unsafe_filename_tar -with tarfile.open(name=tarball) as tar: +with tarfile.open(name=tarball) as tar: # $ Source[py/tarslip-extended] for entry in tar: - tar._extract_member(entry, entry.name) + tar._extract_member(entry, entry.name) # $ Alert[py/tarslip-extended] tarball = unsafe_filename_tar -with tarfile.open(name=tarball) as tar: +with tarfile.open(name=tarball) as tar: # $ Source[py/tarslip-extended] for entry in tar: - tar.extract(entry, "/tmp/unpack/") + tar.extract(entry, "/tmp/unpack/") # $ Alert[py/tarslip-extended] tarball = unsafe_filename_tar -tar = tarfile.open(tarball) -tar.extractall("/tmp/unpack/") +tar = tarfile.open(tarball) # $ Source[py/tarslip-extended] +tar.extractall("/tmp/unpack/") # $ Alert[py/tarslip-extended] tarball = unsafe_filename_tar -with tarfile.open(tarball, "r") as tar: - tar.extractall(path="/tmp/unpack/", members=tar) +with tarfile.open(tarball, "r") as tar: # $ Source[py/tarslip-extended] + tar.extractall(path="/tmp/unpack/", members=tar) # $ Alert[py/tarslip-extended] def members_filter4(tarfile): @@ -207,8 +207,8 @@ tar.extractall(path=tempfile.mkdtemp(), members=members_filter4(tar)) tar.close() -with tarfile.open(unsafe_filename_tar, "r") as tar: - tar.extractall(path="/tmp/unpack") +with tarfile.open(unsafe_filename_tar, "r") as tar: # $ Source[py/tarslip-extended] + tar.extractall(path="/tmp/unpack") # $ Alert[py/tarslip-extended] def members_filter5(tarfile): @@ -228,12 +228,12 @@ filename = unsafe_filename_tar tmp_dir = "/tmp/" read_type = "r:gz" if filename.endswith("tgz") else "r" -with tarfile.open(filename, read_type) as corpus_tar: +with tarfile.open(filename, read_type) as corpus_tar: # $ Source[py/tarslip-extended] members = [] for f in corpus_tar: if not os.path.isfile(os.path.join(tmp_dir, f.name)): members.append(f) - corpus_tar.extractall(tmp_dir, members=members) + corpus_tar.extractall(tmp_dir, members=members) # $ Alert[py/tarslip-extended] def members_filter6(tarfile): @@ -251,66 +251,66 @@ tar.close() archive_path = unsafe_filename_tar target_dir = "/tmp/unpack" -tarfile.open(archive_path, "r").extractall(path=target_dir) +tarfile.open(archive_path, "r").extractall(path=target_dir) # $ Alert[py/tarslip-extended] tarball = unsafe_filename_tar -with tarfile.open(tarball) as tar: +with tarfile.open(tarball) as tar: # $ Source[py/tarslip-extended] for entry in tar: if entry.isfile(): - tar.extract(entry, "/tmp/unpack/") + tar.extract(entry, "/tmp/unpack/") # $ Alert[py/tarslip-extended] -with tarfile.open(unsafe_filename_tar) as tar: +with tarfile.open(unsafe_filename_tar) as tar: # $ Source[py/tarslip-extended] for entry in tar: if entry.name.startswith("/"): raise ValueError("Illegal tar archive entry") - tar.extract(entry, "/tmp/unpack/") + tar.extract(entry, "/tmp/unpack/") # $ Alert[py/tarslip-extended] tarball = unsafe_filename_tar -with tarfile.TarFile(tarball, mode="r") as tar: +with tarfile.TarFile(tarball, mode="r") as tar: # $ Source[py/tarslip-extended] for entry in tar: if entry.isfile(): - tar.extract(entry, "/tmp/unpack/") + tar.extract(entry, "/tmp/unpack/") # $ Alert[py/tarslip-extended] -with tarfile.open(unsafe_filename_tar) as tar: +with tarfile.open(unsafe_filename_tar) as tar: # $ Source[py/tarslip-extended] for entry in tar: if os.path.isabs(entry.name): raise ValueError("Illegal tar archive entry") - tar.extract(entry, "/tmp/unpack/") + tar.extract(entry, "/tmp/unpack/") # $ Alert[py/tarslip-extended] -with tarfile.TarFile(unsafe_filename_tar, mode="r") as tar: - tar.extractall(path="/tmp/unpack") +with tarfile.TarFile(unsafe_filename_tar, mode="r") as tar: # $ Source[py/tarslip-extended] + tar.extractall(path="/tmp/unpack") # $ Alert[py/tarslip-extended] -tar = tarfile.open(filename) -tar.extractall(path=tempfile.mkdtemp(), members=tar.getmembers()) +tar = tarfile.open(filename) # $ Source[py/tarslip-extended] +tar.extractall(path=tempfile.mkdtemp(), members=tar.getmembers()) # $ Alert[py/tarslip-extended] tar.close() -tar = tarfile.open(unsafe_filename_tar) -tar.extractall(path=tempfile.mkdtemp(), members=None) +tar = tarfile.open(unsafe_filename_tar) # $ Source[py/tarslip-extended] +tar.extractall(path=tempfile.mkdtemp(), members=None) # $ Alert[py/tarslip-extended] tar.extractall(path=tempfile.mkdtemp(), members=members_filter4(tar)) tar.close() -with tarfile.TarFile(unsafe_filename_tar, mode="r") as tar: - tar.extractall(path="/tmp/unpack/", members=tar) +with tarfile.TarFile(unsafe_filename_tar, mode="r") as tar: # $ Source[py/tarslip-extended] + tar.extractall(path="/tmp/unpack/", members=tar) # $ Alert[py/tarslip-extended] -tar = tarfile.open(unsafe_filename_tar) +tar = tarfile.open(unsafe_filename_tar) # $ Source[py/tarslip-extended] result = [] for member in tar: if member.issym(): raise ValueError("But it is a symlink") result.append(member) -tar.extractall(path=tempfile.mkdtemp(), members=result) +tar.extractall(path=tempfile.mkdtemp(), members=result) # $ Alert[py/tarslip-extended] tar.close() archive_path = unsafe_filename_tar target_dir = "/tmp/unpack" -tarfile.TarFile(unsafe_filename_tar, mode="r").extractall(path=target_dir) \ No newline at end of file +tarfile.TarFile(unsafe_filename_tar, mode="r").extractall(path=target_dir) # $ Alert[py/tarslip-extended] \ No newline at end of file diff --git a/python/ql/test/experimental/query-tests/Security/CWE-022-TarSlip/ZipSlip.qlref b/python/ql/test/experimental/query-tests/Security/CWE-022-TarSlip/ZipSlip.qlref index 717dc9d0f10..177a74d6bd7 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-022-TarSlip/ZipSlip.qlref +++ b/python/ql/test/experimental/query-tests/Security/CWE-022-TarSlip/ZipSlip.qlref @@ -1 +1,2 @@ -experimental/Security/CWE-022/ZipSlip.ql +query: experimental/Security/CWE-022/ZipSlip.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/experimental/query-tests/Security/CWE-022-TarSlip/zipslip_bad.py b/python/ql/test/experimental/query-tests/Security/CWE-022-TarSlip/zipslip_bad.py index c622ead874c..4e7195cf856 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-022-TarSlip/zipslip_bad.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-022-TarSlip/zipslip_bad.py @@ -5,35 +5,35 @@ import gzip import zipfile def unzip(filename): - with tarfile.open(filename) as zipf: + with tarfile.open(filename) as zipf: # $ Alert[py/zipslip] #BAD : This could write any file on the filesystem. for entry in zipf: - shutil.move(entry, "/tmp/unpack/") + shutil.move(entry, "/tmp/unpack/") # $ Sink[py/zipslip] def unzip1(filename): - with gzip.open(filename) as zipf: + with gzip.open(filename) as zipf: # $ Alert[py/zipslip] #BAD : This could write any file on the filesystem. for entry in zipf: - shutil.copy2(entry, "/tmp/unpack/") + shutil.copy2(entry, "/tmp/unpack/") # $ Sink[py/zipslip] def unzip2(filename): - with bz2.open(filename) as zipf: + with bz2.open(filename) as zipf: # $ Alert[py/zipslip] #BAD : This could write any file on the filesystem. for entry in zipf: - shutil.copyfile(entry, "/tmp/unpack/") + shutil.copyfile(entry, "/tmp/unpack/") # $ Sink[py/zipslip] def unzip3(filename): zf = zipfile.ZipFile(filename) - with zf.namelist() as filelist: + with zf.namelist() as filelist: # $ Alert[py/zipslip] #BAD : This could write any file on the filesystem. for x in filelist: - shutil.copy(x, "/tmp/unpack/") + shutil.copy(x, "/tmp/unpack/") # $ Sink[py/zipslip] def unzip4(filename): zf = zipfile.ZipFile(filename) - filelist = zf.namelist() + filelist = zf.namelist() # $ Alert[py/zipslip] for x in filelist: with zf.open(x) as srcf: - shutil.copyfileobj(x, "/tmp/unpack/") + shutil.copyfileobj(x, "/tmp/unpack/") # $ Sink[py/zipslip] import tty # to set the import root so we can identify the standard library diff --git a/python/ql/test/experimental/query-tests/Security/CWE-074-RemoteCommandExecution/AsyncSsh.py b/python/ql/test/experimental/query-tests/Security/CWE-074-RemoteCommandExecution/AsyncSsh.py index 492c8a0f1de..fe41e75e064 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-074-RemoteCommandExecution/AsyncSsh.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-074-RemoteCommandExecution/AsyncSsh.py @@ -12,8 +12,8 @@ session.handshake(sock) session.userauth_password("user", "password") @app.get("/bad1") -async def bad1(cmd: str): +async def bad1(cmd: str): # $ Source async with asyncssh.connect('localhost') as conn: - result = await conn.run(cmd, check=True) # $ result=BAD getRemoteCommand=cmd + result = await conn.run(cmd, check=True) # $ Alert result=BAD getRemoteCommand=cmd print(result.stdout, end='') return {"success": "Dangerous"} diff --git a/python/ql/test/experimental/query-tests/Security/CWE-074-RemoteCommandExecution/Netmiko.py b/python/ql/test/experimental/query-tests/Security/CWE-074-RemoteCommandExecution/Netmiko.py index dd12357214d..75b6be33baa 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-074-RemoteCommandExecution/Netmiko.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-074-RemoteCommandExecution/Netmiko.py @@ -15,11 +15,11 @@ cisco_881 = { } @app.get("/bad1") -async def bad1(cmd: str): +async def bad1(cmd: str): # $ Source net_connect = ConnectHandler(**cisco_881) - net_connect.send_command(command_string=cmd) # $ result=BAD getRemoteCommand=cmd - net_connect.send_command_expect(command_string=cmd) # $ result=BAD getRemoteCommand=cmd - net_connect.send_command_timing(command_string=cmd) # $ result=BAD getRemoteCommand=cmd - net_connect.send_multiline(commands=[[cmd, "expect"]]) # $ result=BAD getRemoteCommand=List - net_connect.send_multiline_timing(commands=cmd) # $ result=BAD getRemoteCommand=cmd + net_connect.send_command(command_string=cmd) # $ Alert result=BAD getRemoteCommand=cmd + net_connect.send_command_expect(command_string=cmd) # $ Alert result=BAD getRemoteCommand=cmd + net_connect.send_command_timing(command_string=cmd) # $ Alert result=BAD getRemoteCommand=cmd + net_connect.send_multiline(commands=[[cmd, "expect"]]) # $ Alert result=BAD getRemoteCommand=List + net_connect.send_multiline_timing(commands=cmd) # $ Alert result=BAD getRemoteCommand=cmd return {"success": "Dangerous"} diff --git a/python/ql/test/experimental/query-tests/Security/CWE-074-RemoteCommandExecution/Pexpect.py b/python/ql/test/experimental/query-tests/Security/CWE-074-RemoteCommandExecution/Pexpect.py index f2b05a075c9..4615bbc0246 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-074-RemoteCommandExecution/Pexpect.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-074-RemoteCommandExecution/Pexpect.py @@ -12,10 +12,10 @@ ssh.login(hostname, username, password) app = FastAPI() @app.get("/bad1") -async def bad1(cmd: str): - ssh.send(cmd) # $ result=BAD getRemoteCommand=cmd +async def bad1(cmd: str): # $ Source + ssh.send(cmd) # $ Alert result=BAD getRemoteCommand=cmd ssh.prompt() - ssh.sendline(cmd) # $ result=BAD getRemoteCommand=cmd + ssh.sendline(cmd) # $ Alert result=BAD getRemoteCommand=cmd ssh.prompt() ssh.logout() return {"success": stdout} \ No newline at end of file diff --git a/python/ql/test/experimental/query-tests/Security/CWE-074-RemoteCommandExecution/RemoteCommandExecution.qlref b/python/ql/test/experimental/query-tests/Security/CWE-074-RemoteCommandExecution/RemoteCommandExecution.qlref index dc5c7028f32..b95082533a7 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-074-RemoteCommandExecution/RemoteCommandExecution.qlref +++ b/python/ql/test/experimental/query-tests/Security/CWE-074-RemoteCommandExecution/RemoteCommandExecution.qlref @@ -1 +1,2 @@ -experimental/Security/CWE-074/remoteCommandExecution/RemoteCommandExecution.ql \ No newline at end of file +query: experimental/Security/CWE-074/remoteCommandExecution/RemoteCommandExecution.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/experimental/query-tests/Security/CWE-074-RemoteCommandExecution/Scrapli.py b/python/ql/test/experimental/query-tests/Security/CWE-074-RemoteCommandExecution/Scrapli.py index 47abfb2f669..985028aebec 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-074-RemoteCommandExecution/Scrapli.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-074-RemoteCommandExecution/Scrapli.py @@ -10,7 +10,7 @@ from scrapli.driver import GenericDriver app = FastAPI() @app.get("/bad1") -async def bad1(cmd: str): +async def bad1(cmd: str): # $ Source dev_connect = { "host": host, "auth_username": user, @@ -21,23 +21,23 @@ async def bad1(cmd: str): } driver = AsyncIOSXEDriver async with driver(**dev_connect) as conn: - output = await conn.send_command(cmd) # $ result=BAD getRemoteCommand=cmd + output = await conn.send_command(cmd) # $ Alert result=BAD getRemoteCommand=cmd driver = AsyncIOSXRDriver async with driver(**dev_connect) as conn: - output = await conn.send_command(cmd) # $ result=BAD getRemoteCommand=cmd + output = await conn.send_command(cmd) # $ Alert result=BAD getRemoteCommand=cmd driver = AsyncNXOSDriver async with driver(**dev_connect) as conn: - output = await conn.send_command(cmd) # $ result=BAD getRemoteCommand=cmd + output = await conn.send_command(cmd) # $ Alert result=BAD getRemoteCommand=cmd driver = AsyncEOSDriver async with driver(**dev_connect) as conn: - output = await conn.send_command(cmd) # $ result=BAD getRemoteCommand=cmd + output = await conn.send_command(cmd) # $ Alert result=BAD getRemoteCommand=cmd driver = AsyncJunosDriver async with driver(**dev_connect) as conn: - output = await conn.send_command(cmd) # $ result=BAD getRemoteCommand=cmd + output = await conn.send_command(cmd) # $ Alert result=BAD getRemoteCommand=cmd return {"success": "Dangerous"} @app.get("/bad1") -def bad2(cmd: str): +def bad2(cmd: str): # $ Source dev_connect = { "host": host, "auth_username": user, @@ -48,19 +48,19 @@ def bad2(cmd: str): } driver = NXOSDriver with driver(**dev_connect) as conn: - output = conn.send_command(cmd) # $ result=BAD getRemoteCommand=cmd + output = conn.send_command(cmd) # $ Alert result=BAD getRemoteCommand=cmd driver = IOSXRDriver with driver(**dev_connect) as conn: - output = conn.send_command(cmd) # $ result=BAD getRemoteCommand=cmd + output = conn.send_command(cmd) # $ Alert result=BAD getRemoteCommand=cmd driver = IOSXEDriver with driver(**dev_connect) as conn: - output = conn.send_command(cmd) # $ result=BAD getRemoteCommand=cmd + output = conn.send_command(cmd) # $ Alert result=BAD getRemoteCommand=cmd driver = EOSDriver with driver(**dev_connect) as conn: - output = conn.send_command(cmd) # $ result=BAD getRemoteCommand=cmd + output = conn.send_command(cmd) # $ Alert result=BAD getRemoteCommand=cmd driver = JunosDriver with driver(**dev_connect) as conn: - output = conn.send_command(cmd) # $ result=BAD getRemoteCommand=cmd + output = conn.send_command(cmd) # $ Alert result=BAD getRemoteCommand=cmd dev_connect = { "host": "65.65.65.65", @@ -71,7 +71,7 @@ def bad2(cmd: str): "platform": "cisco_iosxe", } with Scrapli(**dev_connect) as conn: - result = conn.send_command(cmd) # $ result=BAD getRemoteCommand=cmd + result = conn.send_command(cmd) # $ Alert result=BAD getRemoteCommand=cmd dev_connect = { "host": "65.65.65.65", @@ -81,5 +81,5 @@ def bad2(cmd: str): "transport": "ssh2", } with GenericDriver(**dev_connect) as conn: - result = conn.send_command(cmd) # $ result=BAD getRemoteCommand=cmd + result = conn.send_command(cmd) # $ Alert result=BAD getRemoteCommand=cmd return {"success": "Dangerous"} diff --git a/python/ql/test/experimental/query-tests/Security/CWE-074-RemoteCommandExecution/Twisted.py b/python/ql/test/experimental/query-tests/Security/CWE-074-RemoteCommandExecution/Twisted.py index 016745e9e02..c9718853b4e 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-074-RemoteCommandExecution/Twisted.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-074-RemoteCommandExecution/Twisted.py @@ -10,10 +10,10 @@ app = FastAPI() @app.get("/bad1") -async def bad1(cmd: bytes): +async def bad1(cmd: bytes): # $ Source endpoint = SSHCommandClientEndpoint.newConnection( reactor, - cmd, # $ result=BAD getRemoteCommand=cmd + cmd, # $ Alert result=BAD getRemoteCommand=cmd b"username", b"ssh.example.com", 22, @@ -21,7 +21,7 @@ async def bad1(cmd: bytes): SSHCommandClientEndpoint.existingConnection( endpoint, - cmd) # $ result=BAD getRemoteCommand=cmd + cmd) # $ Alert result=BAD getRemoteCommand=cmd factory = Factory() d = endpoint.connect(factory) diff --git a/python/ql/test/experimental/query-tests/Security/CWE-074-RemoteCommandExecution/paramiko.py b/python/ql/test/experimental/query-tests/Security/CWE-074-RemoteCommandExecution/paramiko.py index e1c17362beb..f4997f90116 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-074-RemoteCommandExecution/paramiko.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-074-RemoteCommandExecution/paramiko.py @@ -12,11 +12,11 @@ app = FastAPI() @app.get("/bad1") -async def bad1(cmd: str): - stdin, stdout, stderr = paramiko_ssh_client.exec_command(cmd) # $ result=BAD getRemoteCommand=cmd +async def bad1(cmd: str): # $ Source + stdin, stdout, stderr = paramiko_ssh_client.exec_command(cmd) # $ Alert result=BAD getRemoteCommand=cmd return {"success": "Dangerous"} @app.get("/bad2") -async def bad2(cmd: str): - stdin, stdout, stderr = paramiko_ssh_client.exec_command(command=cmd) # $ result=BAD getRemoteCommand=cmd +async def bad2(cmd: str): # $ Source + stdin, stdout, stderr = paramiko_ssh_client.exec_command(command=cmd) # $ Alert result=BAD getRemoteCommand=cmd return {"success": "Dangerous"} diff --git a/python/ql/test/experimental/query-tests/Security/CWE-074-RemoteCommandExecution/ssh2.py b/python/ql/test/experimental/query-tests/Security/CWE-074-RemoteCommandExecution/ssh2.py index 312aaadb5ae..e1c4d31ca22 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-074-RemoteCommandExecution/ssh2.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-074-RemoteCommandExecution/ssh2.py @@ -12,9 +12,9 @@ session.handshake(sock) session.userauth_password("user", "password") @app.get("/bad1") -async def bad1(cmd: str): +async def bad1(cmd: str): # $ Source channel = session.open_session() - channel.execute(cmd) # $ result=BAD getRemoteCommand=cmd + channel.execute(cmd) # $ Alert result=BAD getRemoteCommand=cmd channel.wait_eof() channel.close() channel.wait_closed() diff --git a/python/ql/test/experimental/query-tests/Security/CWE-079/EmailXss.qlref b/python/ql/test/experimental/query-tests/Security/CWE-079/EmailXss.qlref index fcc132dd66c..c141aa6746b 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-079/EmailXss.qlref +++ b/python/ql/test/experimental/query-tests/Security/CWE-079/EmailXss.qlref @@ -1 +1,2 @@ -experimental/Security/CWE-079/EmailXss.ql +query: experimental/Security/CWE-079/EmailXss.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/experimental/query-tests/Security/CWE-079/django_mail.py b/python/ql/test/experimental/query-tests/Security/CWE-079/django_mail.py index 178e8decc79..fb42c22f02e 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-079/django_mail.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-079/django_mail.py @@ -11,7 +11,7 @@ def django_response(request): https://github.com/django/django/blob/ca9872905559026af82000e46cde6f7dedc897b6/django/core/mail/__init__.py#L64 """ send_mail("Subject", "plain-text body", "from@example.com", - ["to@example.com"], html_message=django.http.request.GET.get("html")) + ["to@example.com"], html_message=django.http.request.GET.get("html")) # $ Alert def django_response(request): @@ -20,6 +20,6 @@ def django_response(request): https://github.com/django/django/blob/ca9872905559026af82000e46cde6f7dedc897b6/django/core/mail/__init__.py#L90-L121 """ mail_admins("Subject", "plain-text body", - html_message=django.http.request.GET.get("html")) + html_message=django.http.request.GET.get("html")) # $ Alert mail_managers("Subject", "plain-text body", - html_message=django.http.request.GET.get("html")) + html_message=django.http.request.GET.get("html")) # $ Alert diff --git a/python/ql/test/experimental/query-tests/Security/CWE-079/flask_mail.py b/python/ql/test/experimental/query-tests/Security/CWE-079/flask_mail.py index e8bdcc93634..6978ad741f6 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-079/flask_mail.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-079/flask_mail.py @@ -1,4 +1,4 @@ -from flask import request, Flask +from flask import request, Flask # $ Source from flask_mail import Mail, Message app = Flask(__name__) @@ -10,12 +10,12 @@ def send(): sender="from@example.com", recipients=["to@example.com"], body="plain-text body", - html=request.args["html"]) + html=request.args["html"]) # $ Alert # The message can contain a body and/or HTML: msg.body = "plain-text body" # The email's HTML can be set via msg.html or as an initialize argument when creating a Message object. - msg.html = request.args["html"] + msg.html = request.args["html"] # $ Alert mail.send(msg) @@ -28,5 +28,5 @@ def connect(): msg = Message(subject="Subject", sender="from@example.com", recipients=["to@example.com"], - html=request.args["html"]) + html=request.args["html"]) # $ Alert conn.send(msg) diff --git a/python/ql/test/experimental/query-tests/Security/CWE-079/sendgrid_mail.py b/python/ql/test/experimental/query-tests/Security/CWE-079/sendgrid_mail.py index e10e8a030a8..4d89056f3fe 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-079/sendgrid_mail.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-079/sendgrid_mail.py @@ -1,4 +1,4 @@ -from flask import request, Flask +from flask import request, Flask # $ Source from sendgrid import SendGridAPIClient from sendgrid.helpers.mail import Mail, Email, To, Content, MimeType, HtmlContent @@ -11,7 +11,7 @@ def send(): from_email='from_email@example.com', to_emails='to@example.com', subject='Sending with Twilio SendGrid is Fun', - html_content=request.args["html_content"]) + html_content=request.args["html_content"]) # $ Alert sg = SendGridAPIClient('SENDGRID_API_KEY') sg.send(message) @@ -23,7 +23,7 @@ def send(): from_email='from_email@example.com', to_emails='to@example.com', subject='Sending with Twilio SendGrid is Fun', - html_content=HtmlContent(request.args["html_content"])) + html_content=HtmlContent(request.args["html_content"])) # $ Alert sg = SendGridAPIClient('SENDGRID_API_KEY') sg.send(message) @@ -34,7 +34,7 @@ def send_post(): from_email = Email("test@example.com") to_email = To("test@example.com") subject = "Sending with SendGrid is Fun" - html_content = Content("text/html", request.args["html_content"]) + html_content = Content("text/html", request.args["html_content"]) # $ Alert plain_content = Content("text/plain", request.args["plain_content"]) mail = Mail(from_email, to_email, subject, plain_content, html_content) diff --git a/python/ql/test/experimental/query-tests/Security/CWE-079/sendgrid_via_mail_send_post_request_body_bad.py b/python/ql/test/experimental/query-tests/Security/CWE-079/sendgrid_via_mail_send_post_request_body_bad.py index fca641057da..30a67213b48 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-079/sendgrid_via_mail_send_post_request_body_bad.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-079/sendgrid_via_mail_send_post_request_body_bad.py @@ -1,6 +1,6 @@ import sendgrid import os -from flask import request, Flask +from flask import request, Flask # $ Source app = Flask(__name__) @@ -13,7 +13,7 @@ def send(): "content": [ { "type": "text/html", - "value": "{}".format(request.args["html_content"]) + "value": "{}".format(request.args["html_content"]) # $ Alert } ], "from": { @@ -24,7 +24,7 @@ def send(): "mail_settings": { "footer": { "enable": True, - "html": "{}".format(request.args["html_footer"]), + "html": "{}".format(request.args["html_footer"]), # $ Alert "text": "Thanks,/n The SendGrid Team" }, }, @@ -38,7 +38,7 @@ def send(): "tracking_settings": { "subscription_tracking": { "enable": True, - "html": "{}".format(request.args["html_tracking"]), + "html": "{}".format(request.args["html_tracking"]), # $ Alert "substitution_tag": "<%click here%>", "text": "If you would like to unsubscribe and stop receiving these emails <% click here %>." } diff --git a/python/ql/test/experimental/query-tests/Security/CWE-079/smtplib_bad_subparts.py b/python/ql/test/experimental/query-tests/Security/CWE-079/smtplib_bad_subparts.py index 209bd889393..20c8e3466ae 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-079/smtplib_bad_subparts.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-079/smtplib_bad_subparts.py @@ -1,5 +1,5 @@ # This test checks that the developer doesn't pass a MIMEText instance to a MIMEMultipart initializer via the subparts parameter. -from flask import Flask, request +from flask import Flask, request # $ Source import json import smtplib import ssl @@ -21,7 +21,7 @@ def email_person(): # Turn these into plain/html MIMEText objects part1 = MIMEText(text, "plain") - part2 = MIMEText(html, "html") + part2 = MIMEText(html, "html") # $ Alert message = MIMEMultipart(_subparts=(part1, part2)) message["Subject"] = "multipart test" diff --git a/python/ql/test/experimental/query-tests/Security/CWE-079/smtplib_bad_via_attach.py b/python/ql/test/experimental/query-tests/Security/CWE-079/smtplib_bad_via_attach.py index 48a228b0bc6..d50ab028087 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-079/smtplib_bad_via_attach.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-079/smtplib_bad_via_attach.py @@ -1,5 +1,5 @@ # This test checks that the developer doesn't pass a MIMEText instance to a MIMEMultipart message. -from flask import Flask, request +from flask import Flask, request # $ Source import json import smtplib, ssl from email.mime.text import MIMEText @@ -24,7 +24,7 @@ def email_person(): # Turn these into plain/html MIMEText objects part1 = MIMEText(text, "plain") - part2 = MIMEText(html, "html") + part2 = MIMEText(html, "html") # $ Alert # Add HTML/plain-text parts to MIMEMultipart message # The email client will try to render the last part first diff --git a/python/ql/test/experimental/query-tests/Security/CWE-091-XsltInjection/XsltInjection.expected b/python/ql/test/experimental/query-tests/Security/CWE-091-XsltInjection/XsltInjection.expected index 8d960a22dfd..28c85388a97 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-091-XsltInjection/XsltInjection.expected +++ b/python/ql/test/experimental/query-tests/Security/CWE-091-XsltInjection/XsltInjection.expected @@ -1,3 +1,10 @@ +#select +| xslt.py:14:29:14:37 | ControlFlowNode for xslt_root | xslt.py:3:26:3:32 | ControlFlowNode for ImportMember | xslt.py:14:29:14:37 | ControlFlowNode for xslt_root | This XSLT query depends on $@. | xslt.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value | +| xsltInjection.py:12:28:12:36 | ControlFlowNode for xslt_root | xsltInjection.py:3:26:3:32 | ControlFlowNode for ImportMember | xsltInjection.py:12:28:12:36 | ControlFlowNode for xslt_root | This XSLT query depends on $@. | xsltInjection.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value | +| xsltInjection.py:21:29:21:37 | ControlFlowNode for xslt_root | xsltInjection.py:3:26:3:32 | ControlFlowNode for ImportMember | xsltInjection.py:21:29:21:37 | ControlFlowNode for xslt_root | This XSLT query depends on $@. | xsltInjection.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value | +| xsltInjection.py:31:24:31:32 | ControlFlowNode for xslt_root | xsltInjection.py:3:26:3:32 | ControlFlowNode for ImportMember | xsltInjection.py:31:24:31:32 | ControlFlowNode for xslt_root | This XSLT query depends on $@. | xsltInjection.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value | +| xsltInjection.py:40:24:40:32 | ControlFlowNode for xslt_root | xsltInjection.py:3:26:3:32 | ControlFlowNode for ImportMember | xsltInjection.py:40:24:40:32 | ControlFlowNode for xslt_root | This XSLT query depends on $@. | xsltInjection.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value | +| xsltInjection.py:50:24:50:32 | ControlFlowNode for xslt_root | xsltInjection.py:3:26:3:32 | ControlFlowNode for ImportMember | xsltInjection.py:50:24:50:32 | ControlFlowNode for xslt_root | This XSLT query depends on $@. | xsltInjection.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value | edges | xslt.py:3:26:3:32 | ControlFlowNode for ImportMember | xslt.py:3:26:3:32 | ControlFlowNode for request | provenance | | | xslt.py:3:26:3:32 | ControlFlowNode for request | xslt.py:10:17:10:23 | ControlFlowNode for request | provenance | | @@ -122,10 +129,3 @@ nodes | xsltInjection.py:46:38:46:48 | ControlFlowNode for xsltStrings [List element] | semmle.label | ControlFlowNode for xsltStrings [List element] | | xsltInjection.py:50:24:50:32 | ControlFlowNode for xslt_root | semmle.label | ControlFlowNode for xslt_root | subpaths -#select -| xslt.py:14:29:14:37 | ControlFlowNode for xslt_root | xslt.py:3:26:3:32 | ControlFlowNode for ImportMember | xslt.py:14:29:14:37 | ControlFlowNode for xslt_root | This XSLT query depends on $@. | xslt.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value | -| xsltInjection.py:12:28:12:36 | ControlFlowNode for xslt_root | xsltInjection.py:3:26:3:32 | ControlFlowNode for ImportMember | xsltInjection.py:12:28:12:36 | ControlFlowNode for xslt_root | This XSLT query depends on $@. | xsltInjection.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value | -| xsltInjection.py:21:29:21:37 | ControlFlowNode for xslt_root | xsltInjection.py:3:26:3:32 | ControlFlowNode for ImportMember | xsltInjection.py:21:29:21:37 | ControlFlowNode for xslt_root | This XSLT query depends on $@. | xsltInjection.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value | -| xsltInjection.py:31:24:31:32 | ControlFlowNode for xslt_root | xsltInjection.py:3:26:3:32 | ControlFlowNode for ImportMember | xsltInjection.py:31:24:31:32 | ControlFlowNode for xslt_root | This XSLT query depends on $@. | xsltInjection.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value | -| xsltInjection.py:40:24:40:32 | ControlFlowNode for xslt_root | xsltInjection.py:3:26:3:32 | ControlFlowNode for ImportMember | xsltInjection.py:40:24:40:32 | ControlFlowNode for xslt_root | This XSLT query depends on $@. | xsltInjection.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value | -| xsltInjection.py:50:24:50:32 | ControlFlowNode for xslt_root | xsltInjection.py:3:26:3:32 | ControlFlowNode for ImportMember | xsltInjection.py:50:24:50:32 | ControlFlowNode for xslt_root | This XSLT query depends on $@. | xsltInjection.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value | diff --git a/python/ql/test/experimental/query-tests/Security/CWE-091-XsltInjection/XsltInjection.qlref b/python/ql/test/experimental/query-tests/Security/CWE-091-XsltInjection/XsltInjection.qlref index 4d432d461ca..5bde608133c 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-091-XsltInjection/XsltInjection.qlref +++ b/python/ql/test/experimental/query-tests/Security/CWE-091-XsltInjection/XsltInjection.qlref @@ -1 +1,2 @@ -experimental/Security/CWE-091/XsltInjection.ql +query: experimental/Security/CWE-091/XsltInjection.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/experimental/query-tests/Security/CWE-091-XsltInjection/xslt.py b/python/ql/test/experimental/query-tests/Security/CWE-091-XsltInjection/xslt.py index 1655916c7e0..b589f453a9b 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-091-XsltInjection/xslt.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-091-XsltInjection/xslt.py @@ -1,6 +1,6 @@ from lxml import etree from io import StringIO -from flask import Flask, request +from flask import Flask, request # $ Source app = Flask(__name__) @@ -11,4 +11,4 @@ def bad(): xslt_root = etree.XML(xsltQuery) f = StringIO('') tree = etree.parse(f) - result_tree = tree.xslt(xslt_root) # Not OK + result_tree = tree.xslt(xslt_root) # $ Alert # Not OK diff --git a/python/ql/test/experimental/query-tests/Security/CWE-091-XsltInjection/xsltInjection.py b/python/ql/test/experimental/query-tests/Security/CWE-091-XsltInjection/xsltInjection.py index ddab954bbff..2e56ff487ca 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-091-XsltInjection/xsltInjection.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-091-XsltInjection/xsltInjection.py @@ -1,6 +1,6 @@ from lxml import etree from io import StringIO -from flask import Flask, request +from flask import Flask, request # $ Source app = Flask(__name__) @@ -9,7 +9,7 @@ app = Flask(__name__) def a(): xsltQuery = request.args.get('xml', '') xslt_root = etree.XML(xsltQuery) - transform = etree.XSLT(xslt_root) # Not OK + transform = etree.XSLT(xslt_root) # $ Alert # Not OK @app.route("/xslt2") @@ -18,7 +18,7 @@ def b(): xslt_root = etree.XML(xsltQuery) f = StringIO('') tree = etree.parse(f) - result_tree = tree.xslt(xslt_root) # Not OK + result_tree = tree.xslt(xslt_root) # $ Alert # Not OK @app.route("/xslt3") @@ -28,7 +28,7 @@ def c(): f = StringIO('') tree = etree.parse(f) - result = tree.xslt(xslt_root, a="'A'") # Not OK + result = tree.xslt(xslt_root, a="'A'") # $ Alert # Not OK @app.route("/xslt4") def d(): @@ -37,7 +37,7 @@ def d(): f = StringIO('') tree = etree.parse(f) - result = tree.xslt(xslt_root, a="'A'") # Not OK + result = tree.xslt(xslt_root, a="'A'") # $ Alert # Not OK @app.route("/xslt5") def e(): @@ -47,7 +47,7 @@ def e(): f = StringIO('') tree = etree.parse(f) - result = tree.xslt(xslt_root, a="'A'") # Not OK + result = tree.xslt(xslt_root, a="'A'") # $ Alert # Not OK @app.route("/xslt6") @@ -76,4 +76,4 @@ def h(): f = StringIO('') tree = etree.parse(f) - result = tree.xslt(xslt_root, a="'A'") # OK \ No newline at end of file + result = tree.xslt(xslt_root, a="'A'") # OK diff --git a/python/ql/test/experimental/query-tests/Security/CWE-094/Js2Py.qlref b/python/ql/test/experimental/query-tests/Security/CWE-094/Js2Py.qlref index 457bfe2aacc..b88e9d7f392 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-094/Js2Py.qlref +++ b/python/ql/test/experimental/query-tests/Security/CWE-094/Js2Py.qlref @@ -1 +1,2 @@ -experimental/Security/CWE-094/Js2Py.ql +query: experimental/Security/CWE-094/Js2Py.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/experimental/query-tests/Security/CWE-094/Js2PyTest.py b/python/ql/test/experimental/query-tests/Security/CWE-094/Js2PyTest.py index f7aae16a9ee..d62cabef965 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-094/Js2PyTest.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-094/Js2PyTest.py @@ -6,5 +6,5 @@ bp = flask.Blueprint("app", __name__, url_prefix="/") @bp.route("/bad") def bad(): - jk = flask.request.form["jk"] - jk = eval_js(f"{jk} f()") \ No newline at end of file + jk = flask.request.form["jk"] # $ Source + jk = eval_js(f"{jk} f()") # $ Alert \ No newline at end of file diff --git a/python/ql/test/experimental/query-tests/Security/CWE-1236/CsvInjection.expected b/python/ql/test/experimental/query-tests/Security/CWE-1236/CsvInjection.expected index 5152f7353f2..aa90dfaeea0 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-1236/CsvInjection.expected +++ b/python/ql/test/experimental/query-tests/Security/CWE-1236/CsvInjection.expected @@ -1,3 +1,7 @@ +#select +| csv_bad.py:18:24:18:31 | ControlFlowNode for csv_data | csv_bad.py:9:19:9:25 | ControlFlowNode for ImportMember | csv_bad.py:18:24:18:31 | ControlFlowNode for csv_data | Csv injection might include code from $@. | csv_bad.py:9:19:9:25 | ControlFlowNode for ImportMember | this user input | +| csv_bad.py:19:25:19:32 | ControlFlowNode for csv_data | csv_bad.py:9:19:9:25 | ControlFlowNode for ImportMember | csv_bad.py:19:25:19:32 | ControlFlowNode for csv_data | Csv injection might include code from $@. | csv_bad.py:9:19:9:25 | ControlFlowNode for ImportMember | this user input | +| csv_bad.py:25:46:25:53 | ControlFlowNode for csv_data | csv_bad.py:9:19:9:25 | ControlFlowNode for ImportMember | csv_bad.py:25:46:25:53 | ControlFlowNode for csv_data | Csv injection might include code from $@. | csv_bad.py:9:19:9:25 | ControlFlowNode for ImportMember | this user input | edges | csv_bad.py:9:19:9:25 | ControlFlowNode for ImportMember | csv_bad.py:9:19:9:25 | ControlFlowNode for request | provenance | | | csv_bad.py:9:19:9:25 | ControlFlowNode for request | csv_bad.py:16:16:16:22 | ControlFlowNode for request | provenance | | @@ -26,7 +30,3 @@ nodes | csv_bad.py:24:16:24:38 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | | csv_bad.py:25:46:25:53 | ControlFlowNode for csv_data | semmle.label | ControlFlowNode for csv_data | subpaths -#select -| csv_bad.py:18:24:18:31 | ControlFlowNode for csv_data | csv_bad.py:9:19:9:25 | ControlFlowNode for ImportMember | csv_bad.py:18:24:18:31 | ControlFlowNode for csv_data | Csv injection might include code from $@. | csv_bad.py:9:19:9:25 | ControlFlowNode for ImportMember | this user input | -| csv_bad.py:19:25:19:32 | ControlFlowNode for csv_data | csv_bad.py:9:19:9:25 | ControlFlowNode for ImportMember | csv_bad.py:19:25:19:32 | ControlFlowNode for csv_data | Csv injection might include code from $@. | csv_bad.py:9:19:9:25 | ControlFlowNode for ImportMember | this user input | -| csv_bad.py:25:46:25:53 | ControlFlowNode for csv_data | csv_bad.py:9:19:9:25 | ControlFlowNode for ImportMember | csv_bad.py:25:46:25:53 | ControlFlowNode for csv_data | Csv injection might include code from $@. | csv_bad.py:9:19:9:25 | ControlFlowNode for ImportMember | this user input | diff --git a/python/ql/test/experimental/query-tests/Security/CWE-1236/CsvInjection.qlref b/python/ql/test/experimental/query-tests/Security/CWE-1236/CsvInjection.qlref index d9cd7e9ca51..6fe779d1b36 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-1236/CsvInjection.qlref +++ b/python/ql/test/experimental/query-tests/Security/CWE-1236/CsvInjection.qlref @@ -1 +1,2 @@ -experimental/Security/CWE-1236/CsvInjection.ql \ No newline at end of file +query: experimental/Security/CWE-1236/CsvInjection.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/experimental/query-tests/Security/CWE-1236/csv_bad.py b/python/ql/test/experimental/query-tests/Security/CWE-1236/csv_bad.py index 6e204d1f3c5..199f96912b5 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-1236/csv_bad.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-1236/csv_bad.py @@ -6,7 +6,7 @@ import copy import csv from flask import Flask -from flask import request +from flask import request # $ Source from typing import List app = Flask(__name__) @@ -15,17 +15,17 @@ app = Flask(__name__) def bad1(): csv_data = request.args.get('csv') csvWriter = csv.writer(open("test.csv", "wt")) - csvWriter.writerow(csv_data) # bad - csvWriter.writerows(csv_data) # bad + csvWriter.writerow(csv_data) # $ Alert # bad + csvWriter.writerows(csv_data) # $ Alert # bad return "bad1" @app.route('/bad2') def bad2(): csv_data = request.args.get('csv') - csvWriter = csv.DictWriter(f, fieldnames=csv_data) # bad + csvWriter = csv.DictWriter(f, fieldnames=csv_data) # $ Alert # bad csvWriter.writeheader() return "bad2" if __name__ == '__main__': app.debug = True - app.run() \ No newline at end of file + app.run() diff --git a/python/ql/test/experimental/query-tests/Security/CWE-176/UnicodeBypassValidation.qlref b/python/ql/test/experimental/query-tests/Security/CWE-176/UnicodeBypassValidation.qlref index ee372b36840..0cb6079b74a 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-176/UnicodeBypassValidation.qlref +++ b/python/ql/test/experimental/query-tests/Security/CWE-176/UnicodeBypassValidation.qlref @@ -1 +1,2 @@ -experimental/Security/CWE-176/UnicodeBypassValidation.ql +query: experimental/Security/CWE-176/UnicodeBypassValidation.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/experimental/query-tests/Security/CWE-176/samples.py b/python/ql/test/experimental/query-tests/Security/CWE-176/samples.py index 37ebfd25d41..5d0962e0c50 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-176/samples.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-176/samples.py @@ -1,5 +1,5 @@ import unicodedata -from flask import Flask, request, escape, render_template +from flask import Flask, request, escape, render_template # $ Source app = Flask(__name__) @@ -7,7 +7,7 @@ app = Flask(__name__) @app.route("/unsafe1") def unsafe1(): user_input = escape(request.args.get("ui")) - normalized_user_input = unicodedata.normalize("NFKC", user_input) # $ result=BAD + normalized_user_input = unicodedata.normalize("NFKC", user_input) # $ Alert result=BAD return render_template("result.html", normalized_user_input=normalized_user_input) @@ -17,7 +17,7 @@ def unsafe1bis(): if user_input.isascii(): normalized_user_input = user_input else: - normalized_user_input = unicodedata.normalize("NFC", user_input) # $ result=BAD + normalized_user_input = unicodedata.normalize("NFC", user_input) # $ Alert result=BAD return render_template("result.html", normalized_user_input=normalized_user_input) diff --git a/python/ql/test/experimental/query-tests/Security/CWE-208/TimingAttackAgainstHash/PossibleTimingAttackAgainstHash.expected b/python/ql/test/experimental/query-tests/Security/CWE-208/TimingAttackAgainstHash/PossibleTimingAttackAgainstHash.expected index 1577182b2dc..bd32259294e 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-208/TimingAttackAgainstHash/PossibleTimingAttackAgainstHash.expected +++ b/python/ql/test/experimental/query-tests/Security/CWE-208/TimingAttackAgainstHash/PossibleTimingAttackAgainstHash.expected @@ -1,3 +1,6 @@ +#select +| TimingAttackAgainstHash.py:27:24:27:32 | ControlFlowNode for signature | TimingAttackAgainstHash.py:26:17:26:41 | ControlFlowNode for Attribute() | TimingAttackAgainstHash.py:27:24:27:32 | ControlFlowNode for signature | Possible Timing attack against $@ validation. | TimingAttackAgainstHash.py:26:17:26:41 | ControlFlowNode for Attribute() | signature message | +| TimingAttackAgainstHash.py:37:19:37:48 | ControlFlowNode for sign() | TimingAttackAgainstHash.py:30:12:30:47 | ControlFlowNode for Attribute() | TimingAttackAgainstHash.py:37:19:37:48 | ControlFlowNode for sign() | Possible Timing attack against $@ validation. | TimingAttackAgainstHash.py:30:12:30:47 | ControlFlowNode for Attribute() | MAC message | edges | TimingAttackAgainstHash.py:26:5:26:13 | ControlFlowNode for signature | TimingAttackAgainstHash.py:27:24:27:32 | ControlFlowNode for signature | provenance | | | TimingAttackAgainstHash.py:26:17:26:41 | ControlFlowNode for Attribute() | TimingAttackAgainstHash.py:26:5:26:13 | ControlFlowNode for signature | provenance | | @@ -9,6 +12,3 @@ nodes | TimingAttackAgainstHash.py:30:12:30:47 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | | TimingAttackAgainstHash.py:37:19:37:48 | ControlFlowNode for sign() | semmle.label | ControlFlowNode for sign() | subpaths -#select -| TimingAttackAgainstHash.py:27:24:27:32 | ControlFlowNode for signature | TimingAttackAgainstHash.py:26:17:26:41 | ControlFlowNode for Attribute() | TimingAttackAgainstHash.py:27:24:27:32 | ControlFlowNode for signature | Possible Timing attack against $@ validation. | TimingAttackAgainstHash.py:26:17:26:41 | ControlFlowNode for Attribute() | signature message | -| TimingAttackAgainstHash.py:37:19:37:48 | ControlFlowNode for sign() | TimingAttackAgainstHash.py:30:12:30:47 | ControlFlowNode for Attribute() | TimingAttackAgainstHash.py:37:19:37:48 | ControlFlowNode for sign() | Possible Timing attack against $@ validation. | TimingAttackAgainstHash.py:30:12:30:47 | ControlFlowNode for Attribute() | MAC message | diff --git a/python/ql/test/experimental/query-tests/Security/CWE-208/TimingAttackAgainstHash/PossibleTimingAttackAgainstHash.qlref b/python/ql/test/experimental/query-tests/Security/CWE-208/TimingAttackAgainstHash/PossibleTimingAttackAgainstHash.qlref index 73a8e6960ef..5ac00932072 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-208/TimingAttackAgainstHash/PossibleTimingAttackAgainstHash.qlref +++ b/python/ql/test/experimental/query-tests/Security/CWE-208/TimingAttackAgainstHash/PossibleTimingAttackAgainstHash.qlref @@ -1 +1,2 @@ -experimental/Security/CWE-208/TimingAttackAgainstHash/PossibleTimingAttackAgainstHash.ql +query: experimental/Security/CWE-208/TimingAttackAgainstHash/PossibleTimingAttackAgainstHash.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/experimental/query-tests/Security/CWE-208/TimingAttackAgainstHash/TimingAttackAgainstHash.py b/python/ql/test/experimental/query-tests/Security/CWE-208/TimingAttackAgainstHash/TimingAttackAgainstHash.py index 1d312f028eb..e9b5be0eb36 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-208/TimingAttackAgainstHash/TimingAttackAgainstHash.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-208/TimingAttackAgainstHash/TimingAttackAgainstHash.py @@ -16,25 +16,25 @@ def UnsafeCmacCheck(actualCmac): expected = cmac.CMAC(algorithms.AES(key)) expected.update(b"message to authenticate") expected.finalize() - return actualCmac == expected + return actualCmac == expected def UnsafeCheckSignature(expected): message = b'To be signed' key = RSA.import_key(open('private_key.der').read()) h = SHA256.new(message) - signature = pkcs1_15.new(key).sign(h) - return expected == signature + signature = pkcs1_15.new(key).sign(h) # $ Source[py/possible-timing-attack-against-hash] + return expected == signature # $ Alert[py/possible-timing-attack-against-hash] def sign(pre_key, msg, alg): - return hmac.new(pre_key, msg, alg).digest() + return hmac.new(pre_key, msg, alg).digest() # $ Source[py/possible-timing-attack-against-hash] def verifyGood(msg, sig): return constant_time_string_compare(sig, sign(key, msg, hashlib.sha256)) #good - + def verifyBad(msg, sig): key = "e179017a-62b0-4996-8a38-e91aa9f1" - return sig == sign(key, msg, hashlib.sha256) #bad + return sig == sign(key, msg, hashlib.sha256) # $ Alert[py/possible-timing-attack-against-hash] #bad def constant_time_string_compare(a, b): if len(a) != len(b): diff --git a/python/ql/test/experimental/query-tests/Security/CWE-208/TimingAttackAgainstHash/TimingAttackAgainstHash.qlref b/python/ql/test/experimental/query-tests/Security/CWE-208/TimingAttackAgainstHash/TimingAttackAgainstHash.qlref index 50c9d84b1f9..2829d76e85d 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-208/TimingAttackAgainstHash/TimingAttackAgainstHash.qlref +++ b/python/ql/test/experimental/query-tests/Security/CWE-208/TimingAttackAgainstHash/TimingAttackAgainstHash.qlref @@ -1 +1,2 @@ -experimental/Security/CWE-208/TimingAttackAgainstHash/TimingAttackAgainstHash.ql +query: experimental/Security/CWE-208/TimingAttackAgainstHash/TimingAttackAgainstHash.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/experimental/query-tests/Security/CWE-208/TimingAttackAgainstHeaderValue/TimingAttackAgainstHeader.py b/python/ql/test/experimental/query-tests/Security/CWE-208/TimingAttackAgainstHeaderValue/TimingAttackAgainstHeader.py index 211c36274d7..591764ed4f8 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-208/TimingAttackAgainstHeaderValue/TimingAttackAgainstHeader.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-208/TimingAttackAgainstHeaderValue/TimingAttackAgainstHeader.py @@ -11,7 +11,7 @@ app = Flask(__name__) @app.route('/bad') def bad(): - if not request.headers.get('X-Auth-Token') == "token": + if not request.headers.get('X-Auth-Token') == "token": # $ Alert raise Exception('bad token') return 'bad' diff --git a/python/ql/test/experimental/query-tests/Security/CWE-208/TimingAttackAgainstHeaderValue/TimingAttackAgainstHeaderValue.qlref b/python/ql/test/experimental/query-tests/Security/CWE-208/TimingAttackAgainstHeaderValue/TimingAttackAgainstHeaderValue.qlref index 9da35da9d6d..0d31d85dc3f 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-208/TimingAttackAgainstHeaderValue/TimingAttackAgainstHeaderValue.qlref +++ b/python/ql/test/experimental/query-tests/Security/CWE-208/TimingAttackAgainstHeaderValue/TimingAttackAgainstHeaderValue.qlref @@ -1 +1,2 @@ -experimental/Security/CWE-208/TimingAttackAgainstHeaderValue/TimingAttackAgainstHeaderValue.ql +query: experimental/Security/CWE-208/TimingAttackAgainstHeaderValue/TimingAttackAgainstHeaderValue.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/experimental/query-tests/Security/CWE-208/TimingAttackAgainstSensitiveInfo/PossibleTimingAttackAgainstSensitiveInfo.qlref b/python/ql/test/experimental/query-tests/Security/CWE-208/TimingAttackAgainstSensitiveInfo/PossibleTimingAttackAgainstSensitiveInfo.qlref index acfe13f6aad..bd9d8272f98 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-208/TimingAttackAgainstSensitiveInfo/PossibleTimingAttackAgainstSensitiveInfo.qlref +++ b/python/ql/test/experimental/query-tests/Security/CWE-208/TimingAttackAgainstSensitiveInfo/PossibleTimingAttackAgainstSensitiveInfo.qlref @@ -1 +1,2 @@ -experimental/Security/CWE-208/TimingAttackAgainstSensitiveInfo/PossibleTimingAttackAgainstSensitiveInfo.ql +query: experimental/Security/CWE-208/TimingAttackAgainstSensitiveInfo/PossibleTimingAttackAgainstSensitiveInfo.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/experimental/query-tests/Security/CWE-208/TimingAttackAgainstSensitiveInfo/TimingAttackAgainstSensitiveInfo.py b/python/ql/test/experimental/query-tests/Security/CWE-208/TimingAttackAgainstSensitiveInfo/TimingAttackAgainstSensitiveInfo.py index a34b3b7c5ae..4619821174e 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-208/TimingAttackAgainstSensitiveInfo/TimingAttackAgainstSensitiveInfo.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-208/TimingAttackAgainstSensitiveInfo/TimingAttackAgainstSensitiveInfo.py @@ -12,8 +12,8 @@ app = Flask(__name__) @app.route('/bad', methods = ['POST', 'GET']) def bad(): if request.method == 'POST': - password = request.form['pwd'] - return password == "1234" + password = request.form['pwd'] # $ Source + return password == "1234" # $ Alert @app.route('/good', methods = ['POST', 'GET']) def good(): diff --git a/python/ql/test/experimental/query-tests/Security/CWE-287-ConstantSecretKey/ConstantSecretKey.qlref b/python/ql/test/experimental/query-tests/Security/CWE-287-ConstantSecretKey/ConstantSecretKey.qlref index e77b304f62c..535dfacbac4 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-287-ConstantSecretKey/ConstantSecretKey.qlref +++ b/python/ql/test/experimental/query-tests/Security/CWE-287-ConstantSecretKey/ConstantSecretKey.qlref @@ -1 +1,2 @@ -experimental/Security/CWE-287-ConstantSecretKey/WebAppConstantSecretKey.ql +query: experimental/Security/CWE-287-ConstantSecretKey/WebAppConstantSecretKey.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/experimental/query-tests/Security/CWE-287-ConstantSecretKey/app_safe.py b/python/ql/test/experimental/query-tests/Security/CWE-287-ConstantSecretKey/app_safe.py index 442a23e2c3a..3fcb38acbf9 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-287-ConstantSecretKey/app_safe.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-287-ConstantSecretKey/app_safe.py @@ -2,7 +2,7 @@ from flask import Flask, session from flask_session import Session app = Flask(__name__) -app.config['SECRET_KEY'] = 'CHANGEME' +app.config['SECRET_KEY'] = 'CHANGEME' # $ Alert Session(app) diff --git a/python/ql/test/experimental/query-tests/Security/CWE-287-ConstantSecretKey/app_unsafe.py b/python/ql/test/experimental/query-tests/Security/CWE-287-ConstantSecretKey/app_unsafe.py index 5aeeb6f7003..c108dfd4561 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-287-ConstantSecretKey/app_unsafe.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-287-ConstantSecretKey/app_unsafe.py @@ -1,11 +1,11 @@ from flask import Flask, session app = Flask(__name__) -aConstant = 'CHANGEME1' -app.config['SECRET_KEY'] = aConstant -app.secret_key = aConstant -app.config.update(SECRET_KEY=aConstant) -app.config.from_mapping(SECRET_KEY=aConstant) +aConstant = 'CHANGEME1' # $ Source +app.config['SECRET_KEY'] = aConstant # $ Alert +app.secret_key = aConstant # $ Alert +app.config.update(SECRET_KEY=aConstant) # $ Alert +app.config.from_mapping(SECRET_KEY=aConstant) # $ Alert app.config.from_pyfile("config.py") app.config.from_object('config.Config') diff --git a/python/ql/test/experimental/query-tests/Security/CWE-287-ConstantSecretKey/config.py b/python/ql/test/experimental/query-tests/Security/CWE-287-ConstantSecretKey/config.py index 1a512c0d9f0..12dacb516e6 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-287-ConstantSecretKey/config.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-287-ConstantSecretKey/config.py @@ -4,16 +4,16 @@ import os import random FLASK_DEBUG = True -aConstant = 'CHANGEME2' +aConstant = 'CHANGEME2' # $ Source class Config: SECRET_KEY = environ.get("envKey") - SECRET_KEY = aConstant + SECRET_KEY = aConstant # $ Alert SECRET_KEY = os.getenv('envKey') SECRET_KEY = os.environ.get('envKey') SECRET_KEY = os.environ.get('envKey', random.randint) SECRET_KEY = os.getenv('envKey', random.randint) - SECRET_KEY = os.getenv('envKey', aConstant) - SECRET_KEY = os.environ.get('envKey', aConstant) + SECRET_KEY = os.getenv('envKey', aConstant) # $ Alert + SECRET_KEY = os.environ.get('envKey', aConstant) # $ Alert SECRET_KEY = os.environ['envKey'] diff --git a/python/ql/test/experimental/query-tests/Security/CWE-287-ConstantSecretKey/config2.py b/python/ql/test/experimental/query-tests/Security/CWE-287-ConstantSecretKey/config2.py index dc3508783e2..96b08fead12 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-287-ConstantSecretKey/config2.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-287-ConstantSecretKey/config2.py @@ -2,4 +2,4 @@ # General Config FLASK_DEBUG = True -SECRET_KEY = "CHANGEME5" +SECRET_KEY = "CHANGEME5" # $ Alert diff --git a/python/ql/test/experimental/query-tests/Security/CWE-287/ImproperLdapAuth.qlref b/python/ql/test/experimental/query-tests/Security/CWE-287/ImproperLdapAuth.qlref index 9f5c6e4c43f..edd5c17e2b1 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-287/ImproperLdapAuth.qlref +++ b/python/ql/test/experimental/query-tests/Security/CWE-287/ImproperLdapAuth.qlref @@ -1 +1,2 @@ -experimental/Security/CWE-287/ImproperLdapAuth.ql +query: experimental/Security/CWE-287/ImproperLdapAuth.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/experimental/query-tests/Security/CWE-287/auth_bad_2.py b/python/ql/test/experimental/query-tests/Security/CWE-287/auth_bad_2.py index d37cc09cfd0..ef274090f91 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-287/auth_bad_2.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-287/auth_bad_2.py @@ -16,7 +16,7 @@ def simple_bind_example(): search_filter = "(user={})".format(ldap.filter.escape_filter_chars(request.args['search'])) ldap_connection = ldap.initialize("ldap://127.0.0.1:1337") - ldap_connection.simple_bind('cn=root') + ldap_connection.simple_bind('cn=root') # $ Alert user = ldap_connection.search_s(dn, ldap.SCOPE_SUBTREE, search_filter) @@ -30,7 +30,7 @@ def simple_bind_s_example(): search_filter = "(user={})".format(ldap.filter.escape_filter_chars(request.args['search'])) ldap_connection = ldap.initialize("ldap://127.0.0.1:1337") - ldap_connection.simple_bind_s('cn=root') + ldap_connection.simple_bind_s('cn=root') # $ Alert user = ldap_connection.search_s(dn, ldap.SCOPE_SUBTREE, search_filter) @@ -44,7 +44,7 @@ def bind_s_example(): search_filter = "(user={})".format(ldap.filter.escape_filter_chars(request.args['search'])) ldap_connection = ldap.initialize("ldap://127.0.0.1:1337") - ldap_connection.bind_s('cn=root', None) + ldap_connection.bind_s('cn=root', None) # $ Alert user = ldap_connection.search_s(dn, ldap.SCOPE_SUBTREE, search_filter) @app.route("/bind_s_example") @@ -57,7 +57,7 @@ def bind_s_example_kwargs(): search_filter = "(user={})".format(ldap.filter.escape_filter_chars(request.args['search'])) ldap_connection = ldap.initialize("ldap://127.0.0.1:1337") - ldap_connection.bind_s(who='cn=root', cred=None) + ldap_connection.bind_s(who='cn=root', cred=None) # $ Alert user = ldap_connection.search_s(dn, ldap.SCOPE_SUBTREE, search_filter) @app.route("/bind_example") @@ -70,7 +70,7 @@ def bind_example(): search_filter = "(user={})".format(ldap.filter.escape_filter_chars(request.args['search'])) ldap_connection = ldap.initialize("ldap://127.0.0.1:1337") - ldap_connection.bind('cn=root', "") + ldap_connection.bind('cn=root', "") # $ Alert user = ldap_connection.search_s(dn, ldap.SCOPE_SUBTREE, search_filter) @@ -84,7 +84,7 @@ def bind_example(): search_filter = "(user={})".format(ldap.filter.escape_filter_chars(request.args['search'])) ldap_connection = ldap.initialize("ldap://127.0.0.1:1337") - ldap_connection.bind(who='cn=root', cred="") + ldap_connection.bind(who='cn=root', cred="") # $ Alert user = ldap_connection.search_s(dn, ldap.SCOPE_SUBTREE, search_filter) diff --git a/python/ql/test/experimental/query-tests/Security/CWE-287/auth_bad_3.py b/python/ql/test/experimental/query-tests/Security/CWE-287/auth_bad_3.py index 2500b4cadb6..3b99754ec40 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-287/auth_bad_3.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-287/auth_bad_3.py @@ -16,7 +16,7 @@ def passwordNone(): search_filter = "(user={})".format(escape_filter_chars(request.args['search'])) srv = Server('servername', get_info=ALL) - conn = Connection(srv, 'user_dn', None) + conn = Connection(srv, 'user_dn', None) # $ Alert status, result, response, _ = conn.search(dn, search_filter) @@ -30,7 +30,7 @@ def passwordNoneKwargs(): search_filter = "(user={})".format(escape_filter_chars(request.args['search'])) srv = Server('servername', get_info=ALL) - conn = Connection(srv, user='user_dn', password=None) + conn = Connection(srv, user='user_dn', password=None) # $ Alert status, result, response, _ = conn.search(dn, search_filter) @app.route("/passwordEmpty") @@ -43,7 +43,7 @@ def passwordEmpty(): search_filter = "(user={})".format(escape_filter_chars(request.args['search'])) srv = Server('servername', get_info=ALL) - conn = Connection(srv, user='user_dn', password="") + conn = Connection(srv, user='user_dn', password="") # $ Alert status, result, response, _ = conn.search(dn, search_filter) @@ -57,7 +57,7 @@ def notPassword(): search_filter = "(user={})".format(escape_filter_chars(request.args['search'])) srv = Server('servername', get_info=ALL) - conn = Connection(srv, user='user_dn') + conn = Connection(srv, user='user_dn') # $ Alert status, result, response, _ = conn.search(dn, search_filter) diff --git a/python/ql/test/experimental/query-tests/Security/CWE-327-UnsafeUsageOfClientSideEncryptionVersion/UnsafeUsageOfClientSideEncryptionVersion.expected b/python/ql/test/experimental/query-tests/Security/CWE-327-UnsafeUsageOfClientSideEncryptionVersion/UnsafeUsageOfClientSideEncryptionVersion.expected index 097e3580fb1..8ffc7ac31d9 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-327-UnsafeUsageOfClientSideEncryptionVersion/UnsafeUsageOfClientSideEncryptionVersion.expected +++ b/python/ql/test/experimental/query-tests/Security/CWE-327-UnsafeUsageOfClientSideEncryptionVersion/UnsafeUsageOfClientSideEncryptionVersion.expected @@ -1,3 +1,9 @@ +#select +| test.py:11:9:11:19 | ControlFlowNode for blob_client | test.py:3:7:3:51 | ControlFlowNode for Attribute() | test.py:11:9:11:19 | ControlFlowNode for blob_client | Unsafe usage of v1 version of Azure Storage client-side encryption | +| test.py:21:9:21:19 | ControlFlowNode for blob_client | test.py:15:27:15:71 | ControlFlowNode for Attribute() | test.py:21:9:21:19 | ControlFlowNode for blob_client | Unsafe usage of v1 version of Azure Storage client-side encryption | +| test.py:31:9:31:19 | ControlFlowNode for blob_client | test.py:25:24:25:66 | ControlFlowNode for Attribute() | test.py:31:9:31:19 | ControlFlowNode for blob_client | Unsafe usage of v1 version of Azure Storage client-side encryption | +| test.py:43:9:43:19 | ControlFlowNode for blob_client | test.py:3:7:3:51 | ControlFlowNode for Attribute() | test.py:43:9:43:19 | ControlFlowNode for blob_client | Unsafe usage of v1 version of Azure Storage client-side encryption | +| test.py:75:9:75:10 | ControlFlowNode for bc | test.py:3:7:3:51 | ControlFlowNode for Attribute() | test.py:75:9:75:10 | ControlFlowNode for bc | Unsafe usage of v1 version of Azure Storage client-side encryption | edges | test.py:3:1:3:3 | ControlFlowNode for BSC | test.py:7:19:7:21 | ControlFlowNode for BSC | provenance | | | test.py:3:1:3:3 | ControlFlowNode for BSC | test.py:35:19:35:21 | ControlFlowNode for BSC | provenance | | @@ -86,9 +92,3 @@ nodes | test.py:73:10:73:33 | ControlFlowNode for get_unsafe_blob_client() | semmle.label | ControlFlowNode for get_unsafe_blob_client() | | test.py:75:9:75:10 | ControlFlowNode for bc | semmle.label | ControlFlowNode for bc | subpaths -#select -| test.py:11:9:11:19 | ControlFlowNode for blob_client | test.py:3:7:3:51 | ControlFlowNode for Attribute() | test.py:11:9:11:19 | ControlFlowNode for blob_client | Unsafe usage of v1 version of Azure Storage client-side encryption | -| test.py:21:9:21:19 | ControlFlowNode for blob_client | test.py:15:27:15:71 | ControlFlowNode for Attribute() | test.py:21:9:21:19 | ControlFlowNode for blob_client | Unsafe usage of v1 version of Azure Storage client-side encryption | -| test.py:31:9:31:19 | ControlFlowNode for blob_client | test.py:25:24:25:66 | ControlFlowNode for Attribute() | test.py:31:9:31:19 | ControlFlowNode for blob_client | Unsafe usage of v1 version of Azure Storage client-side encryption | -| test.py:43:9:43:19 | ControlFlowNode for blob_client | test.py:3:7:3:51 | ControlFlowNode for Attribute() | test.py:43:9:43:19 | ControlFlowNode for blob_client | Unsafe usage of v1 version of Azure Storage client-side encryption | -| test.py:75:9:75:10 | ControlFlowNode for bc | test.py:3:7:3:51 | ControlFlowNode for Attribute() | test.py:75:9:75:10 | ControlFlowNode for bc | Unsafe usage of v1 version of Azure Storage client-side encryption | diff --git a/python/ql/test/experimental/query-tests/Security/CWE-327-UnsafeUsageOfClientSideEncryptionVersion/UnsafeUsageOfClientSideEncryptionVersion.qlref b/python/ql/test/experimental/query-tests/Security/CWE-327-UnsafeUsageOfClientSideEncryptionVersion/UnsafeUsageOfClientSideEncryptionVersion.qlref index b737b32c815..b5ed8a0d636 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-327-UnsafeUsageOfClientSideEncryptionVersion/UnsafeUsageOfClientSideEncryptionVersion.qlref +++ b/python/ql/test/experimental/query-tests/Security/CWE-327-UnsafeUsageOfClientSideEncryptionVersion/UnsafeUsageOfClientSideEncryptionVersion.qlref @@ -1 +1,2 @@ -experimental/Security/CWE-327/Azure/UnsafeUsageOfClientSideEncryptionVersion.ql +query: experimental/Security/CWE-327/Azure/UnsafeUsageOfClientSideEncryptionVersion.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/experimental/query-tests/Security/CWE-327-UnsafeUsageOfClientSideEncryptionVersion/test.py b/python/ql/test/experimental/query-tests/Security/CWE-327-UnsafeUsageOfClientSideEncryptionVersion/test.py index 32fa60c6193..de1d6a3f5c6 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-327-UnsafeUsageOfClientSideEncryptionVersion/test.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-327-UnsafeUsageOfClientSideEncryptionVersion/test.py @@ -1,6 +1,6 @@ from azure.storage.blob import BlobServiceClient, ContainerClient, BlobClient -BSC = BlobServiceClient.from_connection_string(...) +BSC = BlobServiceClient.from_connection_string(...) # $ Source def unsafe(): # does not set encryption_version to 2.0, default is unsafe @@ -8,27 +8,27 @@ def unsafe(): blob_client.require_encryption = True blob_client.key_encryption_key = ... with open("decryptedcontentfile.txt", "rb") as stream: - blob_client.upload_blob(stream) # BAD + blob_client.upload_blob(stream) # $ Alert # BAD def unsafe_setting_on_blob_service_client(): - blob_service_client = BlobServiceClient.from_connection_string(...) + blob_service_client = BlobServiceClient.from_connection_string(...) # $ Source blob_service_client.require_encryption = True blob_service_client.key_encryption_key = ... blob_client = blob_service_client.get_blob_client(...) with open("decryptedcontentfile.txt", "rb") as stream: - blob_client.upload_blob(stream) + blob_client.upload_blob(stream) # $ Alert def unsafe_setting_on_container_client(): - container_client = ContainerClient.from_connection_string(...) + container_client = ContainerClient.from_connection_string(...) # $ Source container_client.require_encryption = True container_client.key_encryption_key = ... blob_client = container_client.get_blob_client(...) with open("decryptedcontentfile.txt", "rb") as stream: - blob_client.upload_blob(stream) + blob_client.upload_blob(stream) # $ Alert def potentially_unsafe(use_new_version=False): @@ -40,7 +40,7 @@ def potentially_unsafe(use_new_version=False): blob_client.encryption_version = '2.0' with open("decryptedcontentfile.txt", "rb") as stream: - blob_client.upload_blob(stream) # BAD + blob_client.upload_blob(stream) # $ Alert # BAD def safe(): @@ -72,7 +72,7 @@ def get_unsafe_blob_client(): def unsafe_with_calls(): bc = get_unsafe_blob_client() with open("decryptedcontentfile.txt", "rb") as stream: - bc.upload_blob(stream) # BAD + bc.upload_blob(stream) # $ Alert # BAD def get_safe_blob_client(): diff --git a/python/ql/test/experimental/query-tests/Security/CWE-338/InsecureRandomness.py b/python/ql/test/experimental/query-tests/Security/CWE-338/InsecureRandomness.py index 9f043954967..ee94baf9eee 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-338/InsecureRandomness.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-338/InsecureRandomness.py @@ -2,4 +2,4 @@ import random def generatePassword(): # BAD: the random is not cryptographically secure - return random.random() + return random.random() # $ Alert diff --git a/python/ql/test/experimental/query-tests/Security/CWE-338/InsecureRandomness.qlref b/python/ql/test/experimental/query-tests/Security/CWE-338/InsecureRandomness.qlref index 447fc2cf6b2..84cbc2412d9 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-338/InsecureRandomness.qlref +++ b/python/ql/test/experimental/query-tests/Security/CWE-338/InsecureRandomness.qlref @@ -1 +1,2 @@ -experimental/Security/CWE-338/InsecureRandomness.ql \ No newline at end of file +query: experimental/Security/CWE-338/InsecureRandomness.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/experimental/query-tests/Security/CWE-346/Cors.py b/python/ql/test/experimental/query-tests/Security/CWE-346/Cors.py index cc12e1273fb..e01d99bde75 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-346/Cors.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-346/Cors.py @@ -4,8 +4,8 @@ def bad(): request = cherrypy.request validCors = "domain.com" if request.method in ['POST', 'PUT', 'PATCH', 'DELETE']: - origin = request.headers.get('Origin', None) - if origin.startswith(validCors): + origin = request.headers.get('Origin', None) # $ Source + if origin.startswith(validCors): # $ Alert print("Origin Valid") def good(): diff --git a/python/ql/test/experimental/query-tests/Security/CWE-346/CorsBypass.qlref b/python/ql/test/experimental/query-tests/Security/CWE-346/CorsBypass.qlref index b652fd93088..35c42c39e85 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-346/CorsBypass.qlref +++ b/python/ql/test/experimental/query-tests/Security/CWE-346/CorsBypass.qlref @@ -1 +1,2 @@ -experimental/Security/CWE-346/CorsBypass.ql \ No newline at end of file +query: experimental/Security/CWE-346/CorsBypass.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/experimental/query-tests/Security/CWE-347/JWTEmptyKeyOrAlgorithm.qlref b/python/ql/test/experimental/query-tests/Security/CWE-347/JWTEmptyKeyOrAlgorithm.qlref index fe0d2ea0004..d225e37a0d3 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-347/JWTEmptyKeyOrAlgorithm.qlref +++ b/python/ql/test/experimental/query-tests/Security/CWE-347/JWTEmptyKeyOrAlgorithm.qlref @@ -1 +1,2 @@ -experimental/Security/CWE-347/JWTEmptyKeyOrAlgorithm.ql +query: experimental/Security/CWE-347/JWTEmptyKeyOrAlgorithm.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/experimental/query-tests/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.qlref b/python/ql/test/experimental/query-tests/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.qlref index d289ff151f4..38402ddd457 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.qlref +++ b/python/ql/test/experimental/query-tests/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.qlref @@ -1 +1,2 @@ -experimental/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.ql +query: experimental/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/experimental/query-tests/Security/CWE-347/authlib.py b/python/ql/test/experimental/query-tests/Security/CWE-347/authlib.py index 2f736789703..94eb4a38c87 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-347/authlib.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-347/authlib.py @@ -8,8 +8,8 @@ jwt.encode({"alg": "HS256"}, token, "key") JsonWebToken().encode({"alg": "HS256"}, token, "key") # bad - empty key -jwt.encode({"alg": "HS256"}, token, "") -JsonWebToken().encode({"alg": "HS256"}, token, "") +jwt.encode({"alg": "HS256"}, token, "") # $ Alert[py/jwt-empty-secret-or-algorithm] +JsonWebToken().encode({"alg": "HS256"}, token, "") # $ Alert[py/jwt-empty-secret-or-algorithm] # Decoding diff --git a/python/ql/test/experimental/query-tests/Security/CWE-347/pyjwt.py b/python/ql/test/experimental/query-tests/Security/CWE-347/pyjwt.py index 39892b33dcb..c08375ef9f4 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-347/pyjwt.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-347/pyjwt.py @@ -7,11 +7,11 @@ jwt.encode(token, "key", "HS256") jwt.encode(token, key="key", algorithm="HS256") # bad - both key and algorithm set to None -jwt.encode(token, None, None) +jwt.encode(token, None, None) # $ Alert[py/jwt-empty-secret-or-algorithm] # bad - empty key -jwt.encode(token, "", algorithm="HS256") -jwt.encode(token, key="", algorithm="HS256") +jwt.encode(token, "", algorithm="HS256") # $ Alert[py/jwt-empty-secret-or-algorithm] +jwt.encode(token, key="", algorithm="HS256") # $ Alert[py/jwt-empty-secret-or-algorithm] # Decoding @@ -19,8 +19,8 @@ jwt.encode(token, key="", algorithm="HS256") jwt.decode(token, "key", "HS256") # bad - unverified decoding -jwt.decode(token, verify=False) -jwt.decode(token, key, options={"verify_signature": False}) +jwt.decode(token, verify=False) # $ Alert[py/jwt-missing-verification] +jwt.decode(token, key, options={"verify_signature": False}) # $ Alert[py/jwt-missing-verification] # good - verified decoding jwt.decode(token, verify=True) diff --git a/python/ql/test/experimental/query-tests/Security/CWE-347/python_jose.py b/python/ql/test/experimental/query-tests/Security/CWE-347/python_jose.py index eeb050184d8..8c2bfe90879 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-347/python_jose.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-347/python_jose.py @@ -7,8 +7,8 @@ jwt.encode(token, "key", "HS256") jwt.encode(token, key="key", algorithm="HS256") # bad - empty key -jwt.encode(token, "", algorithm="HS256") -jwt.encode(token, key="", algorithm="HS256") +jwt.encode(token, "", algorithm="HS256") # $ Alert[py/jwt-empty-secret-or-algorithm] +jwt.encode(token, key="", algorithm="HS256") # $ Alert[py/jwt-empty-secret-or-algorithm] # Decoding @@ -16,7 +16,7 @@ jwt.encode(token, key="", algorithm="HS256") jwt.decode(token, "key", "HS256") # bad - unverified decoding -jwt.decode(token, key, options={"verify_signature": False}) +jwt.decode(token, key, options={"verify_signature": False}) # $ Alert[py/jwt-missing-verification] # good - verified decoding jwt.decode(token, key, options={"verify_signature": True}) diff --git a/python/ql/test/experimental/query-tests/Security/CWE-347/python_jwt.py b/python/ql/test/experimental/query-tests/Security/CWE-347/python_jwt.py index 42a3fc35f07..77e67b2dd90 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-347/python_jwt.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-347/python_jwt.py @@ -11,4 +11,4 @@ def good(token): def bad(token): - python_jwt.process_jwt(token) + python_jwt.process_jwt(token) # $ Alert[py/jwt-missing-verification] diff --git a/python/ql/test/experimental/query-tests/Security/CWE-348/ClientSuppliedIpUsedInSecurityCheck.qlref b/python/ql/test/experimental/query-tests/Security/CWE-348/ClientSuppliedIpUsedInSecurityCheck.qlref index 2a1775fe06a..51f11c6dfcd 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-348/ClientSuppliedIpUsedInSecurityCheck.qlref +++ b/python/ql/test/experimental/query-tests/Security/CWE-348/ClientSuppliedIpUsedInSecurityCheck.qlref @@ -1 +1,2 @@ -experimental/Security/CWE-348/ClientSuppliedIpUsedInSecurityCheck.ql \ No newline at end of file +query: experimental/Security/CWE-348/ClientSuppliedIpUsedInSecurityCheck.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/experimental/query-tests/Security/CWE-348/flask_bad.py b/python/ql/test/experimental/query-tests/Security/CWE-348/flask_bad.py index b357a9316fd..491a1339970 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-348/flask_bad.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-348/flask_bad.py @@ -10,15 +10,15 @@ app = Flask(__name__) @app.route('/bad1') def bad1(): - client_ip = request.headers.get('x-forwarded-for') - if not client_ip.startswith('192.168.'): + client_ip = request.headers.get('x-forwarded-for') # $ Source + if not client_ip.startswith('192.168.'): # $ Alert raise Exception('ip illegal') return 'bad1' @app.route('/bad2') def bad2(): - client_ip = request.headers.get('x-forwarded-for') - if not client_ip == '127.0.0.1': + client_ip = request.headers.get('x-forwarded-for') # $ Source + if not client_ip == '127.0.0.1': # $ Alert raise Exception('ip illegal') return 'bad2' diff --git a/python/ql/test/experimental/query-tests/Security/CWE-348/tornado_bad.py b/python/ql/test/experimental/query-tests/Security/CWE-348/tornado_bad.py index 23ad29d8b09..9899922d019 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-348/tornado_bad.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-348/tornado_bad.py @@ -19,8 +19,8 @@ class IndexHandler(tornado.web.RequestHandler): if client_ip: client_ip = client_ip.split(',')[len(client_ip.split(',')) - 1] else: - client_ip = self.request.headers.get('REMOTE_ADDR', None) - if not client_ip == '127.0.0.1': + client_ip = self.request.headers.get('REMOTE_ADDR', None) # $ Source + if not client_ip == '127.0.0.1': # $ Alert raise Exception('ip illegal') self.write("hello.") diff --git a/python/ql/test/experimental/query-tests/Security/CWE-522-global-option/LdapInsecureAuth.qlref b/python/ql/test/experimental/query-tests/Security/CWE-522-global-option/LdapInsecureAuth.qlref index 7b867cb3186..cd63387a1a7 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-522-global-option/LdapInsecureAuth.qlref +++ b/python/ql/test/experimental/query-tests/Security/CWE-522-global-option/LdapInsecureAuth.qlref @@ -1 +1,2 @@ -experimental/Security/CWE-522/LdapInsecureAuth.ql +query: experimental/Security/CWE-522/LdapInsecureAuth.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/experimental/query-tests/Security/CWE-522/LdapInsecureAuth.qlref b/python/ql/test/experimental/query-tests/Security/CWE-522/LdapInsecureAuth.qlref index 7b867cb3186..cd63387a1a7 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-522/LdapInsecureAuth.qlref +++ b/python/ql/test/experimental/query-tests/Security/CWE-522/LdapInsecureAuth.qlref @@ -1 +1,2 @@ -experimental/Security/CWE-522/LdapInsecureAuth.ql +query: experimental/Security/CWE-522/LdapInsecureAuth.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/experimental/query-tests/Security/CWE-522/ldap2_remote.py b/python/ql/test/experimental/query-tests/Security/CWE-522/ldap2_remote.py index 3119ca2d28a..75f5b0b0ea3 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-522/ldap2_remote.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-522/ldap2_remote.py @@ -42,7 +42,7 @@ def two(): @app.route("/one_bad") def one_bad(): - ldap_connection_7 = ldap.initialize(schema + remote_host) + ldap_connection_7 = ldap.initialize(schema + remote_host) # $ Alert ldap_connection_7.set_option(ldap.OPT_X_TLS_DEMAND, False) ldap_connection_7.simple_bind_s('', '') user = ldap_connection_7.search_s( @@ -53,7 +53,7 @@ def one_bad(): @app.route("/one_bad_2") def one_bad_2(): - ldap_connection_8 = ldap.initialize(schema + remote_host) + ldap_connection_8 = ldap.initialize(schema + remote_host) # $ Alert ldap_connection_8.set_option(ldap.OPT_X_TLS_NEVER, True) ldap_connection_8.simple_bind_s('', '') user = ldap_connection_8.search_s( diff --git a/python/ql/test/experimental/query-tests/Security/CWE-522/ldap3_remote.py b/python/ql/test/experimental/query-tests/Security/CWE-522/ldap3_remote.py index 269e03e41fe..ff5c5998ec2 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-522/ldap3_remote.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-522/ldap3_remote.py @@ -1,5 +1,5 @@ from ldap3 import Server, Connection, ALL -from flask import request, Flask +from flask import request, Flask # $ Source app = Flask(__name__) @@ -98,8 +98,8 @@ def seven(): @app.route("/eight") def eight(): - host = schema + "somethingon.theinternet.com" - srv = Server(host, port=1337) + host = schema + "somethingon.theinternet.com" # $ Source + srv = Server(host, port=1337) # $ Alert conn = Connection(srv, "dn", "password") conn.start_tls() conn.search("dn", "search_filter") @@ -111,8 +111,8 @@ def eight(): @app.route("/nine") def nine(): - host = schema + "somethingon.theinternet.com" - srv = Server(host, 1337, False) + host = schema + "somethingon.theinternet.com" # $ Source + srv = Server(host, 1337, False) # $ Alert conn = Connection(srv, "dn", "password") conn.search("dn", "search_filter") return conn.response @@ -123,8 +123,8 @@ def nine(): @app.route("/ten") def ten(): - host = schema + remote_host - srv = Server(host, port=1337, use_ssl=False) + host = schema + remote_host # $ Source + srv = Server(host, port=1337, use_ssl=False) # $ Alert conn = Connection(srv, "dn", "password") conn.search("dn", "search_filter") return conn.response @@ -136,7 +136,7 @@ def ten(): @app.route("/eleven") def eleven(): host = schema + request.args['host'] - srv = Server(host, port=1337) + srv = Server(host, port=1337) # $ Alert conn = Connection(srv, "dn", "password") conn.search("dn", "search_filter") return conn.response diff --git a/python/ql/test/experimental/query-tests/Security/CWE-611-SimpleXmlRpcServer/SimpleXmlRpcServer.qlref b/python/ql/test/experimental/query-tests/Security/CWE-611-SimpleXmlRpcServer/SimpleXmlRpcServer.qlref index a0b30e6d69b..f9b2ebd0390 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-611-SimpleXmlRpcServer/SimpleXmlRpcServer.qlref +++ b/python/ql/test/experimental/query-tests/Security/CWE-611-SimpleXmlRpcServer/SimpleXmlRpcServer.qlref @@ -1 +1,2 @@ -experimental/Security/CWE-611/SimpleXmlRpcServer.ql +query: experimental/Security/CWE-611/SimpleXmlRpcServer.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/experimental/query-tests/Security/CWE-611-SimpleXmlRpcServer/xmlrpc_server.py b/python/ql/test/experimental/query-tests/Security/CWE-611-SimpleXmlRpcServer/xmlrpc_server.py index 83c18b549b3..f2463a752bc 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-611-SimpleXmlRpcServer/xmlrpc_server.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-611-SimpleXmlRpcServer/xmlrpc_server.py @@ -4,7 +4,7 @@ def foo(n: str): print("foo called with arg:", n, type(n)) return "ok" -server = SimpleXMLRPCServer(("127.0.0.1", 8000)) +server = SimpleXMLRPCServer(("127.0.0.1", 8000)) # $ Alert server.register_function(foo, "foo") server.serve_forever() diff --git a/python/ql/test/experimental/query-tests/Security/CWE-770/UnicodeDoS.qlref b/python/ql/test/experimental/query-tests/Security/CWE-770/UnicodeDoS.qlref index aff380880ea..1124c168344 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-770/UnicodeDoS.qlref +++ b/python/ql/test/experimental/query-tests/Security/CWE-770/UnicodeDoS.qlref @@ -1 +1,2 @@ -experimental/Security/CWE-770/UnicodeDoS.ql \ No newline at end of file +query: experimental/Security/CWE-770/UnicodeDoS.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/experimental/query-tests/Security/CWE-770/tests.py b/python/ql/test/experimental/query-tests/Security/CWE-770/tests.py index 1007bcc8985..f359cdaca1c 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-770/tests.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-770/tests.py @@ -1,4 +1,4 @@ -from flask import Flask, jsonify, request +from flask import Flask, jsonify, request # $ Source import unicodedata app = Flask(__name__) @@ -13,7 +13,7 @@ def bad_1(): # Normalize the file path using NFKC Unicode normalization return ( - unicodedata.normalize("NFKC", file_path), + unicodedata.normalize("NFKC", file_path), # $ Alert 200, {"Content-Type": "application/octet-stream"}, ) @@ -25,7 +25,7 @@ def bad_2(): if len(r) >= 10: # Normalize the r using NFKD Unicode normalization - r = unicodedata.normalize("NFKD", r) + r = unicodedata.normalize("NFKD", r) # $ Alert return r, 200, {"Content-Type": "application/octet-stream"} else: return jsonify({"error": "File not found"}), 404 @@ -37,7 +37,7 @@ def bad_3(): length = len(r) if length >= 1_000: # Normalize the r using NFKD Unicode normalization - r = unicodedata.normalize("NFKD", r) + r = unicodedata.normalize("NFKD", r) # $ Alert return r, 200, {"Content-Type": "application/octet-stream"} else: return jsonify({"error": "File not found"}), 404 @@ -49,7 +49,7 @@ def bad_4(): length = len(r) if 1_000 <= length: # Normalize the r using NFKD Unicode normalization - r = unicodedata.normalize("NFKD", r) + r = unicodedata.normalize("NFKD", r) # $ Alert return r, 200, {"Content-Type": "application/octet-stream"} else: return jsonify({"error": "File not found"}), 404 @@ -61,7 +61,7 @@ def bad_5(): length = len(r) if not length < 1_000: # Normalize the r using NFKD Unicode normalization - r = unicodedata.normalize("NFKD", r) + r = unicodedata.normalize("NFKD", r) # $ Alert return r, 200, {"Content-Type": "application/octet-stream"} else: return jsonify({"error": "File not found"}), 404 @@ -73,7 +73,7 @@ def bad_6(): length = len(r) if not 1_000 > length: # Normalize the r using NFKD Unicode normalization - r = unicodedata.normalize("NFKD", r) + r = unicodedata.normalize("NFKD", r) # $ Alert return r, 200, {"Content-Type": "application/octet-stream"} else: return jsonify({"error": "File not found"}), 404 diff --git a/python/ql/test/library-tests/ControlFlow/PointsToSupport/UseFromDefinition.ql b/python/ql/test/library-tests/ControlFlow/PointsToSupport/UseFromDefinition.ql index 8b52244478f..6173331a2dd 100644 --- a/python/ql/test/library-tests/ControlFlow/PointsToSupport/UseFromDefinition.ql +++ b/python/ql/test/library-tests/ControlFlow/PointsToSupport/UseFromDefinition.ql @@ -9,7 +9,7 @@ Expr assignedValue(Name n) { from Name def, DefinitionNode d where - d = def.getAFlowNode() and + d.getNode() = def and exists(assignedValue(def)) and not d.getValue().getNode() = assignedValue(def) select def.toString(), assignedValue(def) diff --git a/python/ql/test/library-tests/ControlFlow/splitting/NodeCount.ql b/python/ql/test/library-tests/ControlFlow/splitting/NodeCount.ql index c51707a65ff..e41f73f5b88 100644 --- a/python/ql/test/library-tests/ControlFlow/splitting/NodeCount.ql +++ b/python/ql/test/library-tests/ControlFlow/splitting/NodeCount.ql @@ -8,4 +8,4 @@ where not a instanceof ExprStmt and a.getScope() = s and s instanceof Function -select a.getLocation().getStartLine(), s.getName(), a, count(a.getAFlowNode()) +select a.getLocation().getStartLine(), s.getName(), a, count(ControlFlowNode n | n.getNode() = a) diff --git a/python/ql/test/library-tests/PointsTo/global/Global.ql b/python/ql/test/library-tests/PointsTo/global/Global.ql index 4dc6d16d379..9887b79fbfc 100644 --- a/python/ql/test/library-tests/PointsTo/global/Global.ql +++ b/python/ql/test/library-tests/PointsTo/global/Global.ql @@ -3,6 +3,6 @@ private import LegacyPointsTo from ControlFlowNode f, PointsToContext ctx, Value obj, ControlFlowNode orig where - exists(ExprStmt s | s.getValue().getAFlowNode() = f) and + exists(ExprStmt s | f.getNode() = s.getValue()) and PointsTo::pointsTo(f, ctx, obj, orig) select ctx, f, obj.toString(), orig diff --git a/python/ql/test/library-tests/PointsTo/local/LocalPointsTo.ql b/python/ql/test/library-tests/PointsTo/local/LocalPointsTo.ql index c81bd0ed3de..ecf67aa7b33 100644 --- a/python/ql/test/library-tests/PointsTo/local/LocalPointsTo.ql +++ b/python/ql/test/library-tests/PointsTo/local/LocalPointsTo.ql @@ -4,6 +4,6 @@ import semmle.python.objects.ObjectInternal from ControlFlowNode f, ObjectInternal obj, ControlFlowNode orig where - exists(ExprStmt s | s.getValue().getAFlowNode() = f) and + exists(ExprStmt s | f.getNode() = s.getValue()) and PointsTo::pointsTo(f, _, obj, orig) select f, obj.toString(), orig diff --git a/python/ql/test/library-tests/dataflow/tainttracking/TestTaintLib.qll b/python/ql/test/library-tests/dataflow/tainttracking/TestTaintLib.qll index 67a9f576cc7..4d7d9201e3e 100644 --- a/python/ql/test/library-tests/dataflow/tainttracking/TestTaintLib.qll +++ b/python/ql/test/library-tests/dataflow/tainttracking/TestTaintLib.qll @@ -43,7 +43,7 @@ query predicate test_taint(string arg_location, string test_res, string scope_na // TODO: Replace with `hasFlowToExpr` once that is working if TestTaintTrackingFlow::flowTo(any(DataFlow::Node n | - n.(DataFlow::CfgNode).getNode() = arg.getAFlowNode() + n.(DataFlow::CfgNode).getNode().getNode() = arg )) then has_taint = true else has_taint = false diff --git a/python/ql/test/library-tests/frameworks/django-orm/ReflectedXss.qlref b/python/ql/test/library-tests/frameworks/django-orm/ReflectedXss.qlref index e0efe102416..9cd0122e556 100644 --- a/python/ql/test/library-tests/frameworks/django-orm/ReflectedXss.qlref +++ b/python/ql/test/library-tests/frameworks/django-orm/ReflectedXss.qlref @@ -1 +1,2 @@ -Security/CWE-079/ReflectedXss.ql +query: Security/CWE-079/ReflectedXss.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/library-tests/frameworks/django-orm/testapp/orm_security_tests.py b/python/ql/test/library-tests/frameworks/django-orm/testapp/orm_security_tests.py index 74d23d95009..86c8dc80418 100644 --- a/python/ql/test/library-tests/frameworks/django-orm/testapp/orm_security_tests.py +++ b/python/ql/test/library-tests/frameworks/django-orm/testapp/orm_security_tests.py @@ -16,7 +16,7 @@ class Person(models.Model): name = models.CharField(max_length=256) age = models.IntegerField() -def person(request): +def person(request): # $ Source if request.method == "POST": person = Person() person.name = request.POST["name"] @@ -41,18 +41,18 @@ def person(request): resp_text = "

Persons:

" for person in Person.objects.all(): resp_text += "\n{} (age {})".format(person.name, person.age) - return HttpResponse(resp_text) # NOT OK + return HttpResponse(resp_text) # $ Alert // NOT OK def show_name(request): person = Person.objects.get(id=request.GET["id"]) - return HttpResponse("Name is: {}".format(person.name)) # NOT OK + return HttpResponse("Name is: {}".format(person.name)) # $ Alert // NOT OK def show_age(request): person = Person.objects.get(id=request.GET["id"]) assert isinstance(person.age, int) # Since the age is an integer, there is not actually XSS in the line below - return HttpResponse("Age is: {}".format(person.age)) # OK + return HttpResponse("Age is: {}".format(person.age)) # $ SPURIOUS: Alert // OK # look at the log after doing """ @@ -92,14 +92,14 @@ def only_az(value): class CommentValidatorNotUsed(models.Model): text = models.CharField(max_length=256, validators=[only_az]) -def save_comment_validator_not_used(request): # $ requestHandler +def save_comment_validator_not_used(request): # $ Source requestHandler comment = CommentValidatorNotUsed(text=request.POST["text"]) comment.save() return HttpResponse("ok") def display_comment_validator_not_used(request): # $ requestHandler comment = CommentValidatorNotUsed.objects.last() - return HttpResponse(comment.text) # NOT OK + return HttpResponse(comment.text) # $ Alert // NOT OK # To test this """ @@ -111,14 +111,14 @@ http http://127.0.0.1:8000/display_comment_validator_not_used/ class CommentValidatorUsed(models.Model): text = models.CharField(max_length=256, validators=[only_az]) -def save_comment_validator_used(request): # $ requestHandler +def save_comment_validator_used(request): # $ Source requestHandler comment = CommentValidatorUsed(text=request.POST["text"]) comment.full_clean() comment.save() def display_comment_validator_used(request): # $ requestHandler comment = CommentValidatorUsed.objects.last() - return HttpResponse(comment.text) # sort of OK + return HttpResponse(comment.text) # $ Alert // sort of OK # Doing the following will raise a ValidationError """ diff --git a/python/ql/test/library-tests/frameworks/flask/InlineInstanceTest.expected b/python/ql/test/library-tests/frameworks/flask/InlineInstanceTest.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/python/ql/test/library-tests/frameworks/flask/InlineInstanceTest.ql b/python/ql/test/library-tests/frameworks/flask/InlineInstanceTest.ql new file mode 100644 index 00000000000..10dff72385a --- /dev/null +++ b/python/ql/test/library-tests/frameworks/flask/InlineInstanceTest.ql @@ -0,0 +1,8 @@ +import python +import semmle.python.frameworks.Flask +import semmle.python.ApiGraphs +import experimental.meta.InlineInstanceTest + +API::Node getInstance() { result = Flask::FlaskApp::instance() } + +import MakeInlineInstanceTest diff --git a/python/ql/test/library-tests/frameworks/flask/flask_subclass.py b/python/ql/test/library-tests/frameworks/flask/flask_subclass.py new file mode 100644 index 00000000000..145adada0ae --- /dev/null +++ b/python/ql/test/library-tests/frameworks/flask/flask_subclass.py @@ -0,0 +1,14 @@ +from flask import Flask + + +class Sub(Flask): + def __init__(self, *args, **kwargs): + Flask.__init__(self, *args, **kwargs) + + +app = Sub(__name__) # $ instance + + +@app.route("/") # $ routeSetup="/" +def hello(): # $ requestHandler + return "world" # $ HttpResponse \ No newline at end of file diff --git a/python/ql/test/library-tests/frameworks/flask/old_test.py b/python/ql/test/library-tests/frameworks/flask/old_test.py index 4c1ee89b530..48b3b7c7f29 100644 --- a/python/ql/test/library-tests/frameworks/flask/old_test.py +++ b/python/ql/test/library-tests/frameworks/flask/old_test.py @@ -1,7 +1,7 @@ import flask from flask import Flask, request, make_response -app = Flask(__name__) +app = Flask(__name__) # $ instance @app.route("/") # $ routeSetup="/" def hello_world(): # $ requestHandler diff --git a/python/ql/test/library-tests/frameworks/flask/response_test.py b/python/ql/test/library-tests/frameworks/flask/response_test.py index e775239d642..7491c6d3e9c 100644 --- a/python/ql/test/library-tests/frameworks/flask/response_test.py +++ b/python/ql/test/library-tests/frameworks/flask/response_test.py @@ -3,7 +3,7 @@ import json from flask import Flask, make_response, jsonify, Response, request, redirect from werkzeug.datastructures import Headers -app = Flask(__name__) +app = Flask(__name__) # $ instance @app.route("/html1") # $ routeSetup="/html1" diff --git a/python/ql/test/library-tests/frameworks/flask/routing_test.py b/python/ql/test/library-tests/frameworks/flask/routing_test.py index 1bd8de5e7de..837cb34d293 100644 --- a/python/ql/test/library-tests/frameworks/flask/routing_test.py +++ b/python/ql/test/library-tests/frameworks/flask/routing_test.py @@ -1,7 +1,7 @@ import flask from flask import Flask, make_response -app = Flask(__name__) +app = Flask(__name__) # $ instance SOME_ROUTE = "/some/route" diff --git a/python/ql/test/library-tests/frameworks/flask/save_uploaded_file.py b/python/ql/test/library-tests/frameworks/flask/save_uploaded_file.py index 502d4cdcbc2..691029844d0 100644 --- a/python/ql/test/library-tests/frameworks/flask/save_uploaded_file.py +++ b/python/ql/test/library-tests/frameworks/flask/save_uploaded_file.py @@ -1,5 +1,5 @@ from flask import Flask, request -app = Flask(__name__) +app = Flask(__name__) # $ instance @app.route("/save-uploaded-file") # $ routeSetup="/save-uploaded-file" def test_taint(): # $ requestHandler diff --git a/python/ql/test/library-tests/frameworks/flask/taint_test.py b/python/ql/test/library-tests/frameworks/flask/taint_test.py index 85637d60f42..9cdee60ef58 100644 --- a/python/ql/test/library-tests/frameworks/flask/taint_test.py +++ b/python/ql/test/library-tests/frameworks/flask/taint_test.py @@ -1,5 +1,5 @@ from flask import Flask, request, render_template_string, stream_template_string -app = Flask(__name__) +app = Flask(__name__) # $ instance @app.route("/test_taint//") # $ routeSetup="/test_taint//" def test_taint(name = "World!", number="0", foo="foo"): # $ requestHandler routedParameter=name routedParameter=number diff --git a/python/ql/test/library-tests/frameworks/flask/template_test.py b/python/ql/test/library-tests/frameworks/flask/template_test.py index b10dd3e6645..2c482e9cb82 100644 --- a/python/ql/test/library-tests/frameworks/flask/template_test.py +++ b/python/ql/test/library-tests/frameworks/flask/template_test.py @@ -1,5 +1,5 @@ from flask import Flask, Response, stream_with_context, render_template_string, stream_template_string -app = Flask(__name__) +app = Flask(__name__) # $ instance @app.route("/a") # $ routeSetup="/a" def a(): # $ requestHandler diff --git a/python/ql/test/library-tests/frameworks/gradio/taint_step_test.py b/python/ql/test/library-tests/frameworks/gradio/taint_step_test.py index eb1614e99b0..c599420f4c8 100644 --- a/python/ql/test/library-tests/frameworks/gradio/taint_step_test.py +++ b/python/ql/test/library-tests/frameworks/gradio/taint_step_test.py @@ -2,15 +2,15 @@ import gradio as gr import os with gr.Blocks() as demo: - path = gr.Textbox(label="Path") # $ source=gr.Textbox(..) - file = gr.Textbox(label="File") # $ source=gr.Textbox(..) + path = gr.Textbox(label="Path") # $ Source source=gr.Textbox(..) + file = gr.Textbox(label="File") # $ Source source=gr.Textbox(..) output = gr.Textbox(label="Output Box") # path injection sink def fileread(path, file): filepath = os.path.join(path, file) - with open(filepath, "r") as f: + with open(filepath, "r") as f: # $ Alert return f.read() diff --git a/python/ql/test/library-tests/frameworks/gradio/taint_step_test.qlref b/python/ql/test/library-tests/frameworks/gradio/taint_step_test.qlref index d43482cc509..6a680f6d5ff 100644 --- a/python/ql/test/library-tests/frameworks/gradio/taint_step_test.qlref +++ b/python/ql/test/library-tests/frameworks/gradio/taint_step_test.qlref @@ -1 +1,2 @@ -Security/CWE-022/PathInjection.ql +query: Security/CWE-022/PathInjection.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Classes/init-calls-subclass-method/InitCallsSubclassMethod.qlref b/python/ql/test/query-tests/Classes/init-calls-subclass-method/InitCallsSubclassMethod.qlref index 6530409f90a..c396a4dbc3d 100644 --- a/python/ql/test/query-tests/Classes/init-calls-subclass-method/InitCallsSubclassMethod.qlref +++ b/python/ql/test/query-tests/Classes/init-calls-subclass-method/InitCallsSubclassMethod.qlref @@ -1 +1,2 @@ -Classes/InitCallsSubclass/InitCallsSubclassMethod.ql +query: Classes/InitCallsSubclass/InitCallsSubclassMethod.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Classes/init-calls-subclass-method/init_calls_subclass.py b/python/ql/test/query-tests/Classes/init-calls-subclass-method/init_calls_subclass.py index ef944a9c7ef..626f11b1f22 100644 --- a/python/ql/test/query-tests/Classes/init-calls-subclass-method/init_calls_subclass.py +++ b/python/ql/test/query-tests/Classes/init-calls-subclass-method/init_calls_subclass.py @@ -5,7 +5,7 @@ def bad1(): def __init__(self, arg): self._state = "Not OK" - self.set_up(arg) # BAD: set_up is overriden. + self.set_up(arg) # $ Alert # BAD: set_up is overriden. self._state = "OK" def set_up(self, arg): @@ -29,7 +29,7 @@ def bad2(): self.a = arg # BAD: postproc is called after initialization. This is still an issue # since it may still occur before all initialization on a subclass is complete. - self.postproc() + self.postproc() # $ Alert def postproc(self): if self.a == 1: @@ -72,4 +72,4 @@ def good4(): class Sub(Super): def _set_b(self): - self.b = self.a+1 \ No newline at end of file + self.b = self.a+1 diff --git a/python/ql/test/query-tests/Classes/should-be-context-manager/ShouldBeContextManager.qlref b/python/ql/test/query-tests/Classes/should-be-context-manager/ShouldBeContextManager.qlref index f555b0af07a..b13b7d8b7b9 100644 --- a/python/ql/test/query-tests/Classes/should-be-context-manager/ShouldBeContextManager.qlref +++ b/python/ql/test/query-tests/Classes/should-be-context-manager/ShouldBeContextManager.qlref @@ -1 +1,2 @@ -Classes/ShouldBeContextManager.ql \ No newline at end of file +query: Classes/ShouldBeContextManager.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Classes/should-be-context-manager/should_be_context_manager.py b/python/ql/test/query-tests/Classes/should-be-context-manager/should_be_context_manager.py index 68fc81206a3..869d19f3d86 100644 --- a/python/ql/test/query-tests/Classes/should-be-context-manager/should_be_context_manager.py +++ b/python/ql/test/query-tests/Classes/should-be-context-manager/should_be_context_manager.py @@ -1,6 +1,6 @@ #Should be context manager -class MegaDel(object): +class MegaDel(object): # $ Alert def __del__(self): a = self.x + self.y @@ -13,7 +13,7 @@ class MegaDel(object): sum += a print(sum) -class MiniDel(object): +class MiniDel(object): # $ Alert def close(self): pass diff --git a/python/ql/test/query-tests/Classes/useless/UselessClass.qlref b/python/ql/test/query-tests/Classes/useless/UselessClass.qlref index 9c8e87e962c..6dac346e62b 100644 --- a/python/ql/test/query-tests/Classes/useless/UselessClass.qlref +++ b/python/ql/test/query-tests/Classes/useless/UselessClass.qlref @@ -1 +1,2 @@ -Classes/UselessClass.ql +query: Classes/UselessClass.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Classes/useless/test.py b/python/ql/test/query-tests/Classes/useless/test.py index 40c9e56e117..063da81c172 100644 --- a/python/ql/test/query-tests/Classes/useless/test.py +++ b/python/ql/test/query-tests/Classes/useless/test.py @@ -25,7 +25,7 @@ class Useful2(object): pass -class Useless1(object): +class Useless1(object): # $ Alert def __init__(self): pass @@ -34,7 +34,7 @@ class Useless1(object): pass -class Useless2(object): +class Useless2(object): # $ Alert def do_something(self): pass diff --git a/python/ql/test/query-tests/Exceptions/general/NotImplementedIsNotAnException.qlref b/python/ql/test/query-tests/Exceptions/general/NotImplementedIsNotAnException.qlref index 61ac527ffb9..a5e0761210e 100644 --- a/python/ql/test/query-tests/Exceptions/general/NotImplementedIsNotAnException.qlref +++ b/python/ql/test/query-tests/Exceptions/general/NotImplementedIsNotAnException.qlref @@ -1 +1,2 @@ -Exceptions/NotImplementedIsNotAnException.ql \ No newline at end of file +query: Exceptions/NotImplementedIsNotAnException.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Exceptions/general/exceptions_test.py b/python/ql/test/query-tests/Exceptions/general/exceptions_test.py index e5e9ea67a6e..81ec5b52302 100644 --- a/python/ql/test/query-tests/Exceptions/general/exceptions_test.py +++ b/python/ql/test/query-tests/Exceptions/general/exceptions_test.py @@ -193,7 +193,7 @@ def ee8(x): #These are so common, we give warnings not errors. def foo(): - raise NotImplemented + raise NotImplemented # $ Alert[py/raise-not-implemented] def bar(): - raise NotImplemented() + raise NotImplemented() # $ Alert[py/raise-not-implemented] diff --git a/python/ql/test/query-tests/Expressions/Formatting/MixedExplicitImplicitIn3101Format.qlref b/python/ql/test/query-tests/Expressions/Formatting/MixedExplicitImplicitIn3101Format.qlref index 3b9a8dc0ccf..044e500615f 100644 --- a/python/ql/test/query-tests/Expressions/Formatting/MixedExplicitImplicitIn3101Format.qlref +++ b/python/ql/test/query-tests/Expressions/Formatting/MixedExplicitImplicitIn3101Format.qlref @@ -1 +1,2 @@ -Expressions/Formatting/MixedExplicitImplicitIn3101Format.ql \ No newline at end of file +query: Expressions/Formatting/MixedExplicitImplicitIn3101Format.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Expressions/Formatting/UnusedArgumentIn3101Format.qlref b/python/ql/test/query-tests/Expressions/Formatting/UnusedArgumentIn3101Format.qlref index b3e654ad052..8de137448b6 100644 --- a/python/ql/test/query-tests/Expressions/Formatting/UnusedArgumentIn3101Format.qlref +++ b/python/ql/test/query-tests/Expressions/Formatting/UnusedArgumentIn3101Format.qlref @@ -1 +1,2 @@ -Expressions/Formatting/UnusedArgumentIn3101Format.ql \ No newline at end of file +query: Expressions/Formatting/UnusedArgumentIn3101Format.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Expressions/Formatting/UnusedNamedArgumentIn3101Format.qlref b/python/ql/test/query-tests/Expressions/Formatting/UnusedNamedArgumentIn3101Format.qlref index 6a77d891079..a1e71b6cd8b 100644 --- a/python/ql/test/query-tests/Expressions/Formatting/UnusedNamedArgumentIn3101Format.qlref +++ b/python/ql/test/query-tests/Expressions/Formatting/UnusedNamedArgumentIn3101Format.qlref @@ -1 +1,2 @@ -Expressions/Formatting/UnusedNamedArgumentIn3101Format.ql \ No newline at end of file +query: Expressions/Formatting/UnusedNamedArgumentIn3101Format.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Expressions/Formatting/WrongNameInArgumentsFor3101Format.qlref b/python/ql/test/query-tests/Expressions/Formatting/WrongNameInArgumentsFor3101Format.qlref index e0b30887034..6bd5b9c75da 100644 --- a/python/ql/test/query-tests/Expressions/Formatting/WrongNameInArgumentsFor3101Format.qlref +++ b/python/ql/test/query-tests/Expressions/Formatting/WrongNameInArgumentsFor3101Format.qlref @@ -1 +1,2 @@ -Expressions/Formatting/WrongNameInArgumentsFor3101Format.ql \ No newline at end of file +query: Expressions/Formatting/WrongNameInArgumentsFor3101Format.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Expressions/Formatting/WrongNumberArgumentsFor3101Format.qlref b/python/ql/test/query-tests/Expressions/Formatting/WrongNumberArgumentsFor3101Format.qlref index 130a6525a90..02168e01c64 100644 --- a/python/ql/test/query-tests/Expressions/Formatting/WrongNumberArgumentsFor3101Format.qlref +++ b/python/ql/test/query-tests/Expressions/Formatting/WrongNumberArgumentsFor3101Format.qlref @@ -1 +1,2 @@ -Expressions/Formatting/WrongNumberArgumentsFor3101Format.ql \ No newline at end of file +query: Expressions/Formatting/WrongNumberArgumentsFor3101Format.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Expressions/Formatting/test.py b/python/ql/test/query-tests/Expressions/Formatting/test.py index e9fd23c8aad..3117a9de2a4 100755 --- a/python/ql/test/query-tests/Expressions/Formatting/test.py +++ b/python/ql/test/query-tests/Expressions/Formatting/test.py @@ -1,11 +1,11 @@ from __future__ import unicode_literals -mixed_format1 = "{}{1}" +mixed_format1 = "{}{1}" # $ Alert[py/str-format/mixed-fields] named_format1 = "{name!r}, {0}" explicit_format1 = "{0}, {1}" implicit_format1 = "{}, {}" -mixed_format2 = "{}{1}" +mixed_format2 = "{}{1}" # $ Alert[py/str-format/mixed-fields] named_format2 = "{name!r}, {0}" explicit_format2 = "{0}, {1}" implicit_format2 = "{}, {}" @@ -14,23 +14,23 @@ implicit_format2 = "{}, {}" mixed_format1.format("Hello", "World") format(mixed_format2, "Hello", "World") -named_format1.format("Hello", world="World") -format(named_format2, "Hello", world="World") +named_format1.format("Hello", world="World") # $ Alert[py/str-format/missing-named-argument] Alert[py/str-format/surplus-named-argument] +format(named_format2, "Hello", world="World") # $ Alert[py/str-format/missing-named-argument] Alert[py/str-format/surplus-named-argument] -named_format1.format(name="Hello", world="World") -format(named_format2, name="Hello", world="World") +named_format1.format(name="Hello", world="World") # $ Alert[py/str-format/missing-argument] Alert[py/str-format/surplus-named-argument] +format(named_format2, name="Hello", world="World") # $ Alert[py/str-format/missing-argument] Alert[py/str-format/surplus-named-argument] -explicit_format1.format("Hello") -format(explicit_format2, "Hello") +explicit_format1.format("Hello") # $ Alert[py/str-format/missing-argument] +format(explicit_format2, "Hello") # $ Alert[py/str-format/missing-argument] -implicit_format1.format("Hello") -format(implicit_format2, "Hello") +implicit_format1.format("Hello") # $ Alert[py/str-format/missing-argument] +format(implicit_format2, "Hello") # $ Alert[py/str-format/missing-argument] -explicit_format1.format("Hello", "World", "Extra") -format(explicit_format2, "Hello", "World", "Extra") +explicit_format1.format("Hello", "World", "Extra") # $ Alert[py/str-format/surplus-argument] +format(explicit_format2, "Hello", "World", "Extra") # $ Alert[py/str-format/surplus-argument] -implicit_format1.format("Hello", "World", "Extra") -format(implicit_format2, "Hello", "World", "Extra") +implicit_format1.format("Hello", "World", "Extra") # $ Alert[py/str-format/surplus-argument] +format(implicit_format2, "Hello", "World", "Extra") # $ Alert[py/str-format/surplus-argument] #OK ODASA-3197 if cond: @@ -42,8 +42,8 @@ format(x_or_y, x="x", y="y") x_or_y.format(x="x", y="y") #Still fail for multiple formats -format(x_or_y, x="x", y="y", z="z") -x_or_y.format(x="x", y="y", z="z") +format(x_or_y, x="x", y="y", z="z") # $ Alert[py/str-format/surplus-named-argument] +x_or_y.format(x="x", y="y", z="z") # $ Alert[py/str-format/surplus-named-argument] #False positive reported by customer. -- Verify fix. "{{}}>".format(html_class) diff --git a/python/ql/test/query-tests/Expressions/Formatting/unknown_format_string.py b/python/ql/test/query-tests/Expressions/Formatting/unknown_format_string.py index a3b32a504db..690716e20b2 100644 --- a/python/ql/test/query-tests/Expressions/Formatting/unknown_format_string.py +++ b/python/ql/test/query-tests/Expressions/Formatting/unknown_format_string.py @@ -6,7 +6,7 @@ def possibly_unknown_format_string1(x): fmt = user_specified else: fmt = "{a}" - return fmt.format(a=1,b=2) + return fmt.format(a=1,b=2) # $ Alert[py/str-format/surplus-named-argument] def possibly_unknown_format_string2(x): user_specified = input() @@ -14,7 +14,7 @@ def possibly_unknown_format_string2(x): fmt = user_specified else: fmt = "{a}" - return fmt.format(a=1,b=2) + return fmt.format(a=1,b=2) # $ Alert[py/str-format/surplus-named-argument] def possibly_unknown_format_string3(x): @@ -22,4 +22,4 @@ def possibly_unknown_format_string3(x): fmt = input() else: fmt = "{a}" - return fmt.format(a=1,b=2) + return fmt.format(a=1,b=2) # $ Alert[py/str-format/surplus-named-argument] diff --git a/python/ql/test/query-tests/Expressions/Regex/BackspaceEscape.qlref b/python/ql/test/query-tests/Expressions/Regex/BackspaceEscape.qlref index 2bf85f8a45a..25a46ec7b29 100644 --- a/python/ql/test/query-tests/Expressions/Regex/BackspaceEscape.qlref +++ b/python/ql/test/query-tests/Expressions/Regex/BackspaceEscape.qlref @@ -1 +1,2 @@ -Expressions/Regex/BackspaceEscape.ql +query: Expressions/Regex/BackspaceEscape.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Expressions/Regex/DuplicateCharacterInSet.qlref b/python/ql/test/query-tests/Expressions/Regex/DuplicateCharacterInSet.qlref index f0fc83c214e..358d546ce8a 100644 --- a/python/ql/test/query-tests/Expressions/Regex/DuplicateCharacterInSet.qlref +++ b/python/ql/test/query-tests/Expressions/Regex/DuplicateCharacterInSet.qlref @@ -1 +1,2 @@ -Expressions/Regex/DuplicateCharacterInSet.ql +query: Expressions/Regex/DuplicateCharacterInSet.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Expressions/Regex/MissingPartSpecialGroup.qlref b/python/ql/test/query-tests/Expressions/Regex/MissingPartSpecialGroup.qlref index faf8f31ad4d..215e7874972 100644 --- a/python/ql/test/query-tests/Expressions/Regex/MissingPartSpecialGroup.qlref +++ b/python/ql/test/query-tests/Expressions/Regex/MissingPartSpecialGroup.qlref @@ -1 +1,2 @@ -Expressions/Regex/MissingPartSpecialGroup.ql +query: Expressions/Regex/MissingPartSpecialGroup.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Expressions/Regex/UnmatchableCaret.qlref b/python/ql/test/query-tests/Expressions/Regex/UnmatchableCaret.qlref index 161fd59f7f2..218dcb02198 100644 --- a/python/ql/test/query-tests/Expressions/Regex/UnmatchableCaret.qlref +++ b/python/ql/test/query-tests/Expressions/Regex/UnmatchableCaret.qlref @@ -1 +1,2 @@ -Expressions/Regex/UnmatchableCaret.ql +query: Expressions/Regex/UnmatchableCaret.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Expressions/Regex/UnmatchableDollar.qlref b/python/ql/test/query-tests/Expressions/Regex/UnmatchableDollar.qlref index b162342922c..cabb436241c 100644 --- a/python/ql/test/query-tests/Expressions/Regex/UnmatchableDollar.qlref +++ b/python/ql/test/query-tests/Expressions/Regex/UnmatchableDollar.qlref @@ -1 +1,2 @@ -Expressions/Regex/UnmatchableDollar.ql +query: Expressions/Regex/UnmatchableDollar.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Expressions/Regex/test.py b/python/ql/test/query-tests/Expressions/Regex/test.py index 717663e335c..ebc1ae1368b 100644 --- a/python/ql/test/query-tests/Expressions/Regex/test.py +++ b/python/ql/test/query-tests/Expressions/Regex/test.py @@ -1,9 +1,9 @@ import re #Unmatchable caret -re.compile(b' ^abc') -re.compile(b"(?s) ^abc") -re.compile(b"\[^123]") +re.compile(b' ^abc') # $ Alert[py/regex/unmatchable-caret] +re.compile(b"(?s) ^abc") # $ Alert[py/regex/unmatchable-caret] +re.compile(b"\[^123]") # $ Alert[py/regex/unmatchable-caret] #Likely false positives for unmatchable caret re.compile(b"[^123]") @@ -14,21 +14,21 @@ re.compile(b"(?:(?:\n\r?)|^)( *)\S") re.compile(b"^diff (?:-r [0-9a-f]+ ){1,2}(.*)$") #Backspace escape -re.compile(br"[\b\t ]") # Should warn +re.compile(br"[\b\t ]") # $ Alert[py/regex/backspace-escape] # Should warn re.compile(br"E\d+\b.*") # Fine -re.compile(br"E\d+\b[ \b\t]") #Both +re.compile(br"E\d+\b[ \b\t]") # $ Alert[py/regex/backspace-escape] #Both #Missing part in named group -re.compile(br'(P[\w]+)') -re.compile(br'(_(P[\w]+)|)') +re.compile(br'(P[\w]+)') # $ Alert[py/regex/incomplete-special-group] +re.compile(br'(_(P[\w]+)|)') # $ Alert[py/regex/incomplete-special-group] #This is OK... re.compile(br'(?P\w+)') #Unmatchable dollar -re.compile(b"abc$ ") -re.compile(b"abc$ (?s)") -re.compile(b"\[$] ") +re.compile(b"abc$ ") # $ Alert[py/regex/unmatchable-dollar] +re.compile(b"abc$ (?s)") # $ Alert[py/regex/unmatchable-dollar] +re.compile(b"\[$] ") # $ Alert[py/regex/unmatchable-dollar] #Not unmatchable dollar re.match(b"[$] ", b"$ ") @@ -43,9 +43,9 @@ re.match(b"((a$\Z)|b){4}", b"bbba") re.match(b"(a){00}b", b"b") #Duplicate character in set -re.compile(b"[AA]") -re.compile(b"[000]") -re.compile(b"[-0-9-]") +re.compile(b"[AA]") # $ Alert[py/regex/duplicate-in-character-class] +re.compile(b"[000]") # $ Alert[py/regex/duplicate-in-character-class] +re.compile(b"[-0-9-]") # $ Alert[py/regex/duplicate-in-character-class] #Possible false positives re.compile(b"[S\S]") @@ -76,8 +76,8 @@ re.compile(br'\w+$(?<=foo)') #Not OK -re.compile(br'(?<=foo)^\w+') -re.compile(br'\w+$(?=foo)') +re.compile(br'(?<=foo)^\w+') # $ Alert[py/regex/unmatchable-caret] +re.compile(br'\w+$(?=foo)') # $ Alert[py/regex/unmatchable-dollar] #OK -- ODASA-ODASA-3968 @@ -134,7 +134,7 @@ VERBOSE_REGEX = r""" \[ # [ (?P
[^]]+) # very permissive! \] # ] - """ + """ # $ Alert[py/regex/duplicate-in-character-class] # Compiled regular expression marking it as verbose ODASA_6786 = re.compile(VERBOSE_REGEX, re.VERBOSE) diff --git a/python/ql/test/query-tests/Expressions/comparisons/UselessComparisonTest.qlref b/python/ql/test/query-tests/Expressions/comparisons/UselessComparisonTest.qlref index fb7f75f9f61..e022932acda 100644 --- a/python/ql/test/query-tests/Expressions/comparisons/UselessComparisonTest.qlref +++ b/python/ql/test/query-tests/Expressions/comparisons/UselessComparisonTest.qlref @@ -1 +1,2 @@ -Expressions/Comparisons/UselessComparisonTest.ql \ No newline at end of file +query: Expressions/Comparisons/UselessComparisonTest.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Expressions/comparisons/test.py b/python/ql/test/query-tests/Expressions/comparisons/test.py index aac73f4932e..17266714493 100644 --- a/python/ql/test/query-tests/Expressions/comparisons/test.py +++ b/python/ql/test/query-tests/Expressions/comparisons/test.py @@ -3,16 +3,16 @@ def f(w, x, y, z): if x < 0 or z < 0: raise Exception() - if x >= 0: # Useless test due to x < 0 being false + if x >= 0: # $ Alert # Useless test due to x < 0 being false y += 1 - if z >= 0: # Useless test due to z < 0 being false + if z >= 0: # $ Alert # Useless test due to z < 0 being false y += 1 while w >= 0: if y < 10: z += 1 - if y == 15: # Useless test due to y < 10 being true + if y == 15: # $ Alert # Useless test due to y < 10 being true z += 1 - elif y > 7: # Useless test + elif y > 7: # $ Alert # Useless test y -= 1 if y < 10: y += 1 @@ -24,10 +24,10 @@ def f(w, x, y, z): def g(w, x, y, z): if w < x or y < z+2: raise Exception() - if w >= x: # Useless test due to w < x being false + if w >= x: # $ Alert # Useless test due to w < x being false pass if cond: - if z > y-2: # Useless test due to y < z+2 being false + if z > y-2: # $ Alert # Useless test due to y < z+2 being false y += 1 else: if z >= y-2: # Not a useless test. @@ -46,7 +46,7 @@ def validate_series(start, end): def medium1(x, y): if x + 1000000000000000 > y + 1000000000000000: return - if x > y: # Redundant + if x > y: # $ Alert # Redundant pass def medium2(x, y): @@ -70,19 +70,19 @@ def big2(x, y): def odasa6782_v1(protocol): if protocol < 0: protocol = HIGHEST_PROTOCOL - elif not 0 <= protocol: + elif not 0 <= protocol: # $ Alert raise ValueError() def odasa6782_v2(protocol): if protocol < 0: protocol = HIGHEST_PROTOCOL - elif not 0 <= protocol <= HIGHEST_PROTOCOL: + elif not 0 <= protocol <= HIGHEST_PROTOCOL: # $ Alert raise ValueError() def odasa6782_v3(protocol): if protocol < 0: protocol = HIGHEST_PROTOCOL - elif 0 <= protocol <= HIGHEST_PROTOCOL: + elif 0 <= protocol <= HIGHEST_PROTOCOL: # $ Alert pass else: raise ValueError() diff --git a/python/ql/test/query-tests/Expressions/eq/IncorrectComparisonUsingIs.qlref b/python/ql/test/query-tests/Expressions/eq/IncorrectComparisonUsingIs.qlref index 73123cf7628..df847ee2b1b 100644 --- a/python/ql/test/query-tests/Expressions/eq/IncorrectComparisonUsingIs.qlref +++ b/python/ql/test/query-tests/Expressions/eq/IncorrectComparisonUsingIs.qlref @@ -1 +1,2 @@ -Expressions/IncorrectComparisonUsingIs.ql +query: Expressions/IncorrectComparisonUsingIs.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Expressions/eq/expressions_test.py b/python/ql/test/query-tests/Expressions/eq/expressions_test.py index 3489bf3a1a9..7c02b1fbc48 100644 --- a/python/ql/test/query-tests/Expressions/eq/expressions_test.py +++ b/python/ql/test/query-tests/Expressions/eq/expressions_test.py @@ -43,7 +43,7 @@ class C: #Using 'is' when should be using '==' s = "Hello " + "World" -if "Hello World" is s: +if "Hello World" is s: # $ Alert[py/comparison-using-is] print ("OK") #This is OK in CPython, but may not be portable diff --git a/python/ql/test/query-tests/Expressions/general/CompareConstants.qlref b/python/ql/test/query-tests/Expressions/general/CompareConstants.qlref index 0e2ab115eee..5b5160d860d 100644 --- a/python/ql/test/query-tests/Expressions/general/CompareConstants.qlref +++ b/python/ql/test/query-tests/Expressions/general/CompareConstants.qlref @@ -1 +1,2 @@ -Expressions/CompareConstants.ql +query: Expressions/CompareConstants.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Expressions/general/CompareIdenticalValues.qlref b/python/ql/test/query-tests/Expressions/general/CompareIdenticalValues.qlref index 4bc0ec69fc0..ad4cbb7600e 100644 --- a/python/ql/test/query-tests/Expressions/general/CompareIdenticalValues.qlref +++ b/python/ql/test/query-tests/Expressions/general/CompareIdenticalValues.qlref @@ -1 +1,2 @@ -Expressions/CompareIdenticalValues.ql +query: Expressions/CompareIdenticalValues.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Expressions/general/CompareIdenticalValuesMissingSelf.qlref b/python/ql/test/query-tests/Expressions/general/CompareIdenticalValuesMissingSelf.qlref index f19a0dee436..48f4d302afb 100644 --- a/python/ql/test/query-tests/Expressions/general/CompareIdenticalValuesMissingSelf.qlref +++ b/python/ql/test/query-tests/Expressions/general/CompareIdenticalValuesMissingSelf.qlref @@ -1 +1,2 @@ -Expressions/CompareIdenticalValuesMissingSelf.ql \ No newline at end of file +query: Expressions/CompareIdenticalValuesMissingSelf.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Expressions/general/DuplicateKeyInDictionaryLiteral.qlref b/python/ql/test/query-tests/Expressions/general/DuplicateKeyInDictionaryLiteral.qlref index a1bb7109882..23123f18749 100644 --- a/python/ql/test/query-tests/Expressions/general/DuplicateKeyInDictionaryLiteral.qlref +++ b/python/ql/test/query-tests/Expressions/general/DuplicateKeyInDictionaryLiteral.qlref @@ -1 +1,2 @@ -Expressions/DuplicateKeyInDictionaryLiteral.ql \ No newline at end of file +query: Expressions/DuplicateKeyInDictionaryLiteral.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Expressions/general/EqualsNone.qlref b/python/ql/test/query-tests/Expressions/general/EqualsNone.qlref index 8d9699258e2..026a3f5bbc2 100644 --- a/python/ql/test/query-tests/Expressions/general/EqualsNone.qlref +++ b/python/ql/test/query-tests/Expressions/general/EqualsNone.qlref @@ -1 +1,2 @@ -Expressions/EqualsNone.ql \ No newline at end of file +query: Expressions/EqualsNone.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Expressions/general/ExplicitCallToDel.qlref b/python/ql/test/query-tests/Expressions/general/ExplicitCallToDel.qlref index 932f1a3d366..451bd74eee0 100644 --- a/python/ql/test/query-tests/Expressions/general/ExplicitCallToDel.qlref +++ b/python/ql/test/query-tests/Expressions/general/ExplicitCallToDel.qlref @@ -1 +1,2 @@ -Expressions/ExplicitCallToDel.ql \ No newline at end of file +query: Expressions/ExplicitCallToDel.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Expressions/general/UnsupportedFormatCharacter.qlref b/python/ql/test/query-tests/Expressions/general/UnsupportedFormatCharacter.qlref index 3cb459229e4..8e50b947401 100644 --- a/python/ql/test/query-tests/Expressions/general/UnsupportedFormatCharacter.qlref +++ b/python/ql/test/query-tests/Expressions/general/UnsupportedFormatCharacter.qlref @@ -1 +1,2 @@ -Expressions/UnsupportedFormatCharacter.ql \ No newline at end of file +query: Expressions/UnsupportedFormatCharacter.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Expressions/general/compare.py b/python/ql/test/query-tests/Expressions/general/compare.py index 141b5e6a028..c48e06f4b1c 100644 --- a/python/ql/test/query-tests/Expressions/general/compare.py +++ b/python/ql/test/query-tests/Expressions/general/compare.py @@ -5,12 +5,12 @@ a == b a.x == b.x #Same variables -a == a -a.x == a.x +a == a # $ Alert[py/comparison-of-identical-expressions] +a.x == a.x # $ Alert[py/comparison-of-identical-expressions] #Compare constants -1 == 1 -1 == 2 +1 == 1 # $ Alert[py/comparison-of-constants] +1 == 2 # $ Alert[py/comparison-of-constants] #Maybe missing self class X(object): @@ -19,7 +19,7 @@ class X(object): self.x = x def missing_self(self, x): - if x == x: + if x == x: # $ Alert[py/comparison-missing-self] print ("Yes") #Compare constants in assert -- ok diff --git a/python/ql/test/query-tests/Expressions/general/expressions_test.py b/python/ql/test/query-tests/Expressions/general/expressions_test.py index 5e07b58e204..7be69bb7f98 100644 --- a/python/ql/test/query-tests/Expressions/general/expressions_test.py +++ b/python/ql/test/query-tests/Expressions/general/expressions_test.py @@ -1,8 +1,8 @@ #encoding: utf-8 def dup_key(): - return { 1: -1, + return { 1: -1, # $ Alert[py/duplicate-key-dict-literal] 1: -2, - u'a' : u'A', + u'a' : u'A', # $ Alert[py/duplicate-key-dict-literal] u'a' : u'B' } @@ -34,7 +34,7 @@ def call_non_callable(arg): dont_know() # Not a violation #Explicit call to __del__ -x.__del__() +x.__del__() # $ Alert[py/explicit-call-to-delete] #Unhashable object def func(): @@ -112,7 +112,7 @@ def is_container(): #Equals none def x(arg): - return arg == None + return arg == None # $ Alert[py/test-equals-none] class NotMyDict(object): @@ -130,7 +130,7 @@ class SubTest(Test): # This is permitted and required. Test.__del__(self) # This is a violation. - self.__del__() + self.__del__() # $ Alert[py/explicit-call-to-delete] # This is an alternate syntax for the super() call, and hence OK. super(SubTest, self).__del__() # This is the Python 3 spelling of the same. diff --git a/python/ql/test/query-tests/Expressions/general/str_fmt_test.py b/python/ql/test/query-tests/Expressions/general/str_fmt_test.py index e941b842c31..2bccc2253cc 100644 --- a/python/ql/test/query-tests/Expressions/general/str_fmt_test.py +++ b/python/ql/test/query-tests/Expressions/general/str_fmt_test.py @@ -5,7 +5,7 @@ def expected_mapping_for_fmt_string(): print (u"%(name)s" % x) def unsupported_format_char(arg): - print (u"%Z" % arg) + print (u"%Z" % arg) # $ Alert[py/percent-format/unsupported-character] def wrong_arg_count_format(arg): print(u"%s %s" % (arg, arg, 0)) diff --git a/python/ql/test/query-tests/Expressions/strings/UnintentionalImplicitStringConcatenation.qlref b/python/ql/test/query-tests/Expressions/strings/UnintentionalImplicitStringConcatenation.qlref index c305fd129f8..7159e5c7972 100644 --- a/python/ql/test/query-tests/Expressions/strings/UnintentionalImplicitStringConcatenation.qlref +++ b/python/ql/test/query-tests/Expressions/strings/UnintentionalImplicitStringConcatenation.qlref @@ -1 +1,2 @@ -Expressions/UnintentionalImplicitStringConcatenation.ql \ No newline at end of file +query: Expressions/UnintentionalImplicitStringConcatenation.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Expressions/strings/test.py b/python/ql/test/query-tests/Expressions/strings/test.py index 15b3c9216e3..1767a2d109b 100644 --- a/python/ql/test/query-tests/Expressions/strings/test.py +++ b/python/ql/test/query-tests/Expressions/strings/test.py @@ -15,13 +15,13 @@ def test(): error1 = [ "foo", "/usr/local" - "/usr/bin" + "/usr/bin" # $ Alert ] error2 = [ "foo" + "bar", "/usr/local" - "/usr/bin" + "/usr/bin" # $ Alert ] #Examples from documentation @@ -31,9 +31,9 @@ def unclear(): return [ "first part of long string" - " and the second part", + " and the second part", # $ Alert "/usr/local" - "/usr/bin" + "/usr/bin" # $ Alert ] def clarified(): diff --git a/python/ql/test/query-tests/Expressions/super/CallToSuperWrongClass.qlref b/python/ql/test/query-tests/Expressions/super/CallToSuperWrongClass.qlref index c3beeaede04..e1ed0c122be 100644 --- a/python/ql/test/query-tests/Expressions/super/CallToSuperWrongClass.qlref +++ b/python/ql/test/query-tests/Expressions/super/CallToSuperWrongClass.qlref @@ -1 +1,2 @@ -Expressions/CallToSuperWrongClass.ql \ No newline at end of file +query: Expressions/CallToSuperWrongClass.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Expressions/super/test.py b/python/ql/test/query-tests/Expressions/super/test.py index e2e667cd25d..947bc3814b2 100644 --- a/python/ql/test/query-tests/Expressions/super/test.py +++ b/python/ql/test/query-tests/Expressions/super/test.py @@ -7,7 +7,7 @@ class MyDict(dict): class NotMyDict(object): def f(self): - super(MyDict, self).f() + super(MyDict, self).f() # $ Alert #Splitting PY2 = sys.version_info[0] == 2 diff --git a/python/ql/test/query-tests/Functions/ModificationOfParameterWithDefault/ModificationOfParameterWithDefault.qlref b/python/ql/test/query-tests/Functions/ModificationOfParameterWithDefault/ModificationOfParameterWithDefault.qlref index 8c4044e8fee..3871382349a 100644 --- a/python/ql/test/query-tests/Functions/ModificationOfParameterWithDefault/ModificationOfParameterWithDefault.qlref +++ b/python/ql/test/query-tests/Functions/ModificationOfParameterWithDefault/ModificationOfParameterWithDefault.qlref @@ -1 +1,2 @@ -Functions/ModificationOfParameterWithDefault.ql +query: Functions/ModificationOfParameterWithDefault.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Functions/ModificationOfParameterWithDefault/test.py b/python/ql/test/query-tests/Functions/ModificationOfParameterWithDefault/test.py index b047f4ddc64..d1e5b8d810f 100644 --- a/python/ql/test/query-tests/Functions/ModificationOfParameterWithDefault/test.py +++ b/python/ql/test/query-tests/Functions/ModificationOfParameterWithDefault/test.py @@ -1,31 +1,31 @@ # Not OK -def simple(l = [0]): - l[0] = 1 # $ modification=l +def simple(l = [0]): # $ Source + l[0] = 1 # $ Alert modification=l return l # Not OK -def slice(l = [0]): - l[0:1] = 1 # $ modification=l +def slice(l = [0]): # $ Source + l[0:1] = 1 # $ Alert modification=l return l # Not OK -def list_del(l = [0]): - del l[0] # $ modification=l +def list_del(l = [0]): # $ Source + del l[0] # $ Alert modification=l return l # Not OK -def append_op(l = []): - l += [1, 2, 3] # $ modification=l +def append_op(l = []): # $ Source + l += [1, 2, 3] # $ Alert modification=l return l # Not OK -def repeat_op(l = [0]): - l *= 3 # $ modification=l +def repeat_op(l = [0]): # $ Source + l *= 3 # $ Alert modification=l return l # Not OK -def append(l = []): - l.append(1) # $ modification=l +def append(l = []): # $ Source + l.append(1) # $ Alert modification=l return l # OK @@ -36,64 +36,64 @@ def includes(l = []): return x def extends(l): - l.extend([1]) # $ modification=l + l.extend([1]) # $ Alert modification=l return l # Not OK -def deferred(l = []): +def deferred(l = []): # $ Source extends(l) return l # Not OK -def nonempty(l = [5]): - l.append(1) # $ modification=l +def nonempty(l = [5]): # $ Source + l.append(1) # $ Alert modification=l return l # Not OK -def dict(d = {}): - d['a'] = 1 # $ modification=d +def dict(d = {}): # $ Source + d['a'] = 1 # $ Alert modification=d return d # Not OK -def dict_nonempty(d = {'a': 1}): - d['a'] = 2 # $ modification=d +def dict_nonempty(d = {'a': 1}): # $ Source + d['a'] = 2 # $ Alert modification=d return d # OK -def dict_nonempty_nochange(d = {'a': 1}): - d['a'] = 1 # $ SPURIOUS: modification=d +def dict_nonempty_nochange(d = {'a': 1}): # $ Source + d['a'] = 1 # $ SPURIOUS: Alert modification=d return d def modifies(d): - d['a'] = 1 # $ modification=d + d['a'] = 1 # $ Alert modification=d return d # Not OK -def dict_deferred(d = {}): +def dict_deferred(d = {}): # $ Source modifies(d) return d # Not OK -def dict_method(d = {}): - d.update({'a': 1}) # $ modification=d +def dict_method(d = {}): # $ Source + d.update({'a': 1}) # $ Alert modification=d return d # Not OK -def dict_method_nonempty(d = {'a': 1}): - d.update({'a': 2}) # $ modification=d +def dict_method_nonempty(d = {'a': 1}): # $ Source + d.update({'a': 2}) # $ Alert modification=d return d # OK -def dict_method_nonempty_nochange(d = {'a': 1}): - d.update({'a': 1}) # $ SPURIOUS:modification=d +def dict_method_nonempty_nochange(d = {'a': 1}): # $ Source + d.update({'a': 1}) # $ SPURIOUS: Alert modification=d return d def modifies_method(d): - d.update({'a': 1}) # $ modification=d + d.update({'a': 1}) # $ Alert modification=d return d # Not OK -def dict_deferred_method(d = {}): +def dict_deferred_method(d = {}): # $ Source modifies_method(d) return d @@ -105,58 +105,58 @@ def dict_includes(d = {}): return x # Not OK -def dict_del(d = {'a': 1}): - del d['a'] # $ modification=d +def dict_del(d = {'a': 1}): # $ Source + del d['a'] # $ Alert modification=d return d # Not OK -def dict_update_op(d = {}): +def dict_update_op(d = {}): # $ Source x = {'a': 1} - d |= x # $ modification=d + d |= x # $ Alert modification=d return d # OK -def dict_update_op_nochange(d = {}): +def dict_update_op_nochange(d = {}): # $ Source x = {} - d |= x # $ SPURIOUS: modification=d + d |= x # $ SPURIOUS: Alert modification=d return d -def sanitizer(l = []): +def sanitizer(l = []): # $ Source if l: l.append(1) else: - l.append(1) # $ modification=l + l.append(1) # $ Alert modification=l return l -def sanitizer_negated(l = [1]): +def sanitizer_negated(l = [1]): # $ Source if not l: l.append(1) else: - l.append(1) # $ modification=l + l.append(1) # $ Alert modification=l return l -def sanitizer(l = []): +def sanitizer(l = []): # $ Source if not l: - l.append(1) # $ modification=l + l.append(1) # $ Alert modification=l else: l.append(1) return l -def sanitizer_negated(l = [1]): +def sanitizer_negated(l = [1]): # $ Source if l: - l.append(1) # $ modification=l + l.append(1) # $ Alert modification=l else: l.append(1) return l # indirect modification of parameter with default def aug_assign_argument(x): - x += ['x'] # $ modification=x + x += ['x'] # $ Alert modification=x def mutate_argument(x): - x.append('x') # $ modification=x + x.append('x') # $ Alert modification=x -def indirect_modification(y = []): +def indirect_modification(y = []): # $ Source aug_assign_argument(y) mutate_argument(y) @@ -182,19 +182,19 @@ def do_stuff_based_on_type(x): if isinstance(x, str): x = x.split() elif isinstance(x, dict): - x.setdefault('foo', 'bar') # $ modification=x + x.setdefault('foo', 'bar') # $ Alert modification=x elif isinstance(x, list): - x.append(5) # $ modification=x + x.append(5) # $ Alert modification=x elif isinstance(x, tuple): x = x.unknown_method() def str_default(x="hello world"): do_stuff_based_on_type(x) -def dict_default(x={'baz':'quux'}): +def dict_default(x={'baz':'quux'}): # $ Source do_stuff_based_on_type(x) -def list_default(x=[1,2,3,4]): +def list_default(x=[1,2,3,4]): # $ Source do_stuff_based_on_type(x) def tuple_default(x=(1,2)): diff --git a/python/ql/test/query-tests/Functions/general/DeprecatedSliceMethod.qlref b/python/ql/test/query-tests/Functions/general/DeprecatedSliceMethod.qlref index c38b8d1f761..3043411c1ce 100644 --- a/python/ql/test/query-tests/Functions/general/DeprecatedSliceMethod.qlref +++ b/python/ql/test/query-tests/Functions/general/DeprecatedSliceMethod.qlref @@ -1 +1,2 @@ -Functions/DeprecatedSliceMethod.ql \ No newline at end of file +query: Functions/DeprecatedSliceMethod.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Functions/general/InitIsGenerator.qlref b/python/ql/test/query-tests/Functions/general/InitIsGenerator.qlref index a3df140ff1e..2662a7ca03a 100644 --- a/python/ql/test/query-tests/Functions/general/InitIsGenerator.qlref +++ b/python/ql/test/query-tests/Functions/general/InitIsGenerator.qlref @@ -1 +1,2 @@ -Functions/InitIsGenerator.ql \ No newline at end of file +query: Functions/InitIsGenerator.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Functions/general/SignatureOverriddenMethod.qlref b/python/ql/test/query-tests/Functions/general/SignatureOverriddenMethod.qlref index a306477b3b4..5470a05e0e4 100644 --- a/python/ql/test/query-tests/Functions/general/SignatureOverriddenMethod.qlref +++ b/python/ql/test/query-tests/Functions/general/SignatureOverriddenMethod.qlref @@ -1 +1,2 @@ -Functions/SignatureOverriddenMethod.ql +query: Functions/SignatureOverriddenMethod.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Functions/general/SignatureSpecialMethods.qlref b/python/ql/test/query-tests/Functions/general/SignatureSpecialMethods.qlref index bc1b29b6c0d..ab188ef5bc2 100644 --- a/python/ql/test/query-tests/Functions/general/SignatureSpecialMethods.qlref +++ b/python/ql/test/query-tests/Functions/general/SignatureSpecialMethods.qlref @@ -1 +1,2 @@ -Functions/SignatureSpecialMethods.ql \ No newline at end of file +query: Functions/SignatureSpecialMethods.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Functions/general/explicit_return_in_init.py b/python/ql/test/query-tests/Functions/general/explicit_return_in_init.py index 47a2933ad6e..1c26e5f31e5 100644 --- a/python/ql/test/query-tests/Functions/general/explicit_return_in_init.py +++ b/python/ql/test/query-tests/Functions/general/explicit_return_in_init.py @@ -29,7 +29,7 @@ class InitCallsInit(InitCallsError): class InitIsGenerator(object): - def __init__(self): + def __init__(self): # $ Alert[py/init-method-is-generator] yield self # OK as it returns result of a call to super().__init__() diff --git a/python/ql/test/query-tests/Functions/general/functions_test.py b/python/ql/test/query-tests/Functions/general/functions_test.py index 741599abd5b..a306ef8ccc8 100644 --- a/python/ql/test/query-tests/Functions/general/functions_test.py +++ b/python/ql/test/query-tests/Functions/general/functions_test.py @@ -92,13 +92,13 @@ def ok_to_ignore(): class DeprecatedSliceMethods(object): - def __getslice__(self, start, stop): + def __getslice__(self, start, stop): # $ Alert[py/deprecated-slice-method] pass - def __setslice__(self, start, stop, value): + def __setslice__(self, start, stop, value): # $ Alert[py/deprecated-slice-method] pass - def __delslice__(self, start, stop): + def __delslice__(self, start, stop): # $ Alert[py/deprecated-slice-method] pass diff --git a/python/ql/test/query-tests/Functions/general/om_test.py b/python/ql/test/query-tests/Functions/general/om_test.py index 959ed6bfe34..edaa81bd062 100644 --- a/python/ql/test/query-tests/Functions/general/om_test.py +++ b/python/ql/test/query-tests/Functions/general/om_test.py @@ -29,10 +29,10 @@ class Derived(Base): def ok2(self, arg1, arg2 = 2, arg3 = 3): return arg1, arg2, arg3 - def grossly_wrong1(self, arg1): + def grossly_wrong1(self, arg1): # $ Alert[py/inheritance/signature-mismatch] return arg1 - def grossly_wrong2(self, arg1, arg2, arg3): + def grossly_wrong2(self, arg1, arg2, arg3): # $ Alert[py/inheritance/signature-mismatch] return arg1, arg2, arg3 def strictly_wrong1(self, arg1): @@ -56,19 +56,19 @@ class Special(object): class WrongSpecials(object): - def __div__(self, x, y): + def __div__(self, x, y): # $ Alert[py/special-method-wrong-signature] return self, x, y - def __mul__(self): + def __mul__(self): # $ Alert[py/special-method-wrong-signature] return self - def __neg__(self, other): + def __neg__(self, other): # $ Alert[py/special-method-wrong-signature] return self, other - def __exit__(self, arg0, arg1): + def __exit__(self, arg0, arg1): # $ Alert[py/special-method-wrong-signature] return arg0 == arg1 - def __repr__(): + def __repr__(): # $ Alert[py/special-method-wrong-signature] return "" def __add__(self, other="Unused default"): @@ -80,7 +80,7 @@ class WrongSpecials(object): class OKSpecials(object): - def __del__(): + def __del__(): # $ Alert[py/special-method-wrong-signature] state = some_state() def __del__(self): diff --git a/python/ql/test/query-tests/Functions/iterators/IterReturnsNonSelf.qlref b/python/ql/test/query-tests/Functions/iterators/IterReturnsNonSelf.qlref index b806215d26c..828fca864da 100644 --- a/python/ql/test/query-tests/Functions/iterators/IterReturnsNonSelf.qlref +++ b/python/ql/test/query-tests/Functions/iterators/IterReturnsNonSelf.qlref @@ -1 +1,2 @@ -Functions/IterReturnsNonSelf.ql \ No newline at end of file +query: Functions/IterReturnsNonSelf.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Functions/iterators/test.py b/python/ql/test/query-tests/Functions/iterators/test.py index ced389967e4..860d199dae8 100644 --- a/python/ql/test/query-tests/Functions/iterators/test.py +++ b/python/ql/test/query-tests/Functions/iterators/test.py @@ -2,7 +2,7 @@ class Bad1: def __next__(self): return 0 - def __iter__(self): # BAD: Iter does not return self + def __iter__(self): # $ Alert # BAD: Iter does not return self yield 0 class Good1: @@ -48,6 +48,6 @@ class FalsePositive1: self._it = iter(self) return next(self._it) - def __iter__(self): # SPURIOUS, GOOD: implementation of next ensures the iterator is equivalent to the one returned by iter, but this is not detected. + def __iter__(self): # $ Alert # SPURIOUS, GOOD: implementation of next ensures the iterator is equivalent to the one returned by iter, but this is not detected. yield 0 - yield 0 \ No newline at end of file + yield 0 diff --git a/python/ql/test/query-tests/Functions/return_values/ReturnConsistentTupleSizes.qlref b/python/ql/test/query-tests/Functions/return_values/ReturnConsistentTupleSizes.qlref index c91661b33cf..c7eaa3205b2 100644 --- a/python/ql/test/query-tests/Functions/return_values/ReturnConsistentTupleSizes.qlref +++ b/python/ql/test/query-tests/Functions/return_values/ReturnConsistentTupleSizes.qlref @@ -1 +1,2 @@ -Functions/ReturnConsistentTupleSizes.ql +query: Functions/ReturnConsistentTupleSizes.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Functions/return_values/functions_test.py b/python/ql/test/query-tests/Functions/return_values/functions_test.py index 9f72a7fec60..fdd89275761 100644 --- a/python/ql/test/query-tests/Functions/return_values/functions_test.py +++ b/python/ql/test/query-tests/Functions/return_values/functions_test.py @@ -303,7 +303,7 @@ y = foo() # Returning tuples with different sizes -def returning_different_tuple_sizes(x): +def returning_different_tuple_sizes(x): # $ Alert[py/mixed-tuple-returns] if x: return 1,2 else: @@ -326,7 +326,7 @@ def indirectly_returning_different_tuple_sizes(x): # OK, since we only look at l return function_returning_2_tuple() else: return function_returning_3_tuple() - + def mismatched_multi_assign(x): a,b = returning_different_tuple_sizes(x) diff --git a/python/ql/test/query-tests/Imports/PyCheckerTests/ImportandImportFrom.qlref b/python/ql/test/query-tests/Imports/PyCheckerTests/ImportandImportFrom.qlref index 3d50843db7e..ed5a37e9d47 100644 --- a/python/ql/test/query-tests/Imports/PyCheckerTests/ImportandImportFrom.qlref +++ b/python/ql/test/query-tests/Imports/PyCheckerTests/ImportandImportFrom.qlref @@ -1 +1,2 @@ -Imports/ImportandImportFrom.ql +query: Imports/ImportandImportFrom.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Imports/PyCheckerTests/imports_test.py b/python/ql/test/query-tests/Imports/PyCheckerTests/imports_test.py index 6224c788c5e..f8a4a4b139e 100644 --- a/python/ql/test/query-tests/Imports/PyCheckerTests/imports_test.py +++ b/python/ql/test/query-tests/Imports/PyCheckerTests/imports_test.py @@ -1,7 +1,7 @@ #Import and import from -import test_module2 +import test_module2 # $ Alert[py/import-and-import-from] from test_module2 import func #Module imports itself diff --git a/python/ql/test/query-tests/Imports/PyCheckerTests/pkg_notok/__init__.py b/python/ql/test/query-tests/Imports/PyCheckerTests/pkg_notok/__init__.py index b0e269d67a5..3c7abf44e5e 100644 --- a/python/ql/test/query-tests/Imports/PyCheckerTests/pkg_notok/__init__.py +++ b/python/ql/test/query-tests/Imports/PyCheckerTests/pkg_notok/__init__.py @@ -1,7 +1,7 @@ class Foo(object): pass -import pkg_notok +import pkg_notok # $ Alert[py/import-and-import-from] # This import is a bit tricky. It will make `bar` available in as `pkg_notok.bar` as a # side effect (see https://docs.python.org/3/reference/import.html#submodules), but the diff --git a/python/ql/test/query-tests/Imports/deprecated/DeprecatedModule.qlref b/python/ql/test/query-tests/Imports/deprecated/DeprecatedModule.qlref index 9f87b11d807..93ed1e7b4be 100644 --- a/python/ql/test/query-tests/Imports/deprecated/DeprecatedModule.qlref +++ b/python/ql/test/query-tests/Imports/deprecated/DeprecatedModule.qlref @@ -1 +1,2 @@ -Imports/DeprecatedModule.ql +query: Imports/DeprecatedModule.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Imports/deprecated/test.py b/python/ql/test/query-tests/Imports/deprecated/test.py index ce70d29794e..6cf11feb782 100644 --- a/python/ql/test/query-tests/Imports/deprecated/test.py +++ b/python/ql/test/query-tests/Imports/deprecated/test.py @@ -1,11 +1,11 @@ # Some deprecated modules -import rfc822 -import posixfile +import rfc822 # $ Alert +import posixfile # $ Alert # We should only report a bad import once class Foo(object): def foo(self): - import md5 + import md5 # $ Alert # Backwards compatible code, should not report try: diff --git a/python/ql/test/query-tests/Imports/general/ImportShadowedByLoopVar.qlref b/python/ql/test/query-tests/Imports/general/ImportShadowedByLoopVar.qlref index 3844f21922f..d5b4aaa1693 100644 --- a/python/ql/test/query-tests/Imports/general/ImportShadowedByLoopVar.qlref +++ b/python/ql/test/query-tests/Imports/general/ImportShadowedByLoopVar.qlref @@ -1 +1,2 @@ -Imports/ImportShadowedByLoopVar.ql \ No newline at end of file +query: Imports/ImportShadowedByLoopVar.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Imports/general/ImportStarUsed.qlref b/python/ql/test/query-tests/Imports/general/ImportStarUsed.qlref index 35f8bff3e5f..099627be88c 100644 --- a/python/ql/test/query-tests/Imports/general/ImportStarUsed.qlref +++ b/python/ql/test/query-tests/Imports/general/ImportStarUsed.qlref @@ -1 +1,2 @@ -Imports/ImportStarUsed.ql \ No newline at end of file +query: Imports/ImportStarUsed.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Imports/general/Imports.qlref b/python/ql/test/query-tests/Imports/general/Imports.qlref index 6bcdb2d9b5f..926c62f0a41 100644 --- a/python/ql/test/query-tests/Imports/general/Imports.qlref +++ b/python/ql/test/query-tests/Imports/general/Imports.qlref @@ -1 +1,2 @@ -Imports/Imports.ql +query: Imports/Imports.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Imports/general/MultipleImport.qlref b/python/ql/test/query-tests/Imports/general/MultipleImport.qlref index a4d2195b688..7826fb7e33c 100644 --- a/python/ql/test/query-tests/Imports/general/MultipleImport.qlref +++ b/python/ql/test/query-tests/Imports/general/MultipleImport.qlref @@ -1 +1,2 @@ -Imports/MultipleImports.ql +query: Imports/MultipleImports.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Imports/general/imports_test.py b/python/ql/test/query-tests/Imports/general/imports_test.py index 4b51f8254fc..f0f881ffb53 100644 --- a/python/ql/test/query-tests/Imports/general/imports_test.py +++ b/python/ql/test/query-tests/Imports/general/imports_test.py @@ -1,5 +1,5 @@ #Multiple imports on a single line -import module1, module2 +import module1, module2 # $ Alert[py/multiple-imports-on-line] #Cyclic import @@ -13,13 +13,13 @@ import top_level_cycle import module -for module in range(10): +for module in range(10): # $ Alert[py/import-shadowed-loop-variable] print(module) #Import * used -from module import * -from module_without_all import * +from module import * # $ Alert[py/import-star-used] +from module_without_all import * # $ Alert[py/import-star-used] #Unused import @@ -30,8 +30,8 @@ module1.func func1 #Duplicate import -import module1 -import module2 +import module1 # $ Alert[py/repeated-import] +import module2 # $ Alert[py/repeated-import] #OK -- Import used in epytext documentation. import used_in_docs @@ -62,4 +62,4 @@ import module1 as different different # FP reported in https://github.com/github/codeql/issues/4003 -from module_that_does_not_exist import * +from module_that_does_not_exist import * # $ Alert[py/import-star-used] diff --git a/python/ql/test/query-tests/Lexical/ToDoComment/ToDoComment.qlref b/python/ql/test/query-tests/Lexical/ToDoComment/ToDoComment.qlref index 4568a99f388..2915fa8c366 100644 --- a/python/ql/test/query-tests/Lexical/ToDoComment/ToDoComment.qlref +++ b/python/ql/test/query-tests/Lexical/ToDoComment/ToDoComment.qlref @@ -1 +1 @@ -Lexical/ToDoComment.ql \ No newline at end of file +Lexical/ToDoComment.ql diff --git a/python/ql/test/query-tests/Lexical/commented_out_code/test.py b/python/ql/test/query-tests/Lexical/commented_out_code/test.py index 067855b6744..2502799cca7 100644 --- a/python/ql/test/query-tests/Lexical/commented_out_code/test.py +++ b/python/ql/test/query-tests/Lexical/commented_out_code/test.py @@ -14,56 +14,56 @@ def f(x): do_something() #else: # do_something_else() - -# Some non-code comments. + +# Some non-code comments. # Space immediately after scope start and between functions. -# +# #class CommentedOut: -# +# # def __init__(self): # pass -# +# # def method(self): # # pass -# +# #def g(y): -# assert y +# assert y # with y: # # Commented out comment # if y: # do_something() # else: # do_something_else() -# +# #def h(z): # '''Doc string # ''' # # Commented out comment -# +# # followed_by_space() -# +# # more_code() - + #def j(): # """ Doc string """ # pass - + #def k(): # # """ Doc string """ # pass - + #def l(): # -# """ -# Doc string +# """ +# Doc string # """ # # pass - + # # # @@ -72,7 +72,7 @@ def f(x): # pass # # -# +# some_code_to_break_up_comments() #with x: @@ -88,7 +88,7 @@ def a_function_to_break_up_comments(): pass # An example explaining -# something which contains +# something which contains # the following code: # # def f(): @@ -96,5 +96,3 @@ def a_function_to_break_up_comments(): # x.y = z # return x # - - \ No newline at end of file diff --git a/python/ql/test/query-tests/Security/CWE-020-CookieInjection/CookieInjection.expected b/python/ql/test/query-tests/Security/CWE-020-CookieInjection/CookieInjection.expected index cf3a06ac7c8..6e9c8ff47dc 100644 --- a/python/ql/test/query-tests/Security/CWE-020-CookieInjection/CookieInjection.expected +++ b/python/ql/test/query-tests/Security/CWE-020-CookieInjection/CookieInjection.expected @@ -1,3 +1,7 @@ +#select +| django_tests.py:6:21:6:43 | ControlFlowNode for Attribute() | django_tests.py:4:25:4:31 | ControlFlowNode for request | django_tests.py:6:21:6:43 | ControlFlowNode for Attribute() | Cookie is constructed from a $@. | django_tests.py:4:25:4:31 | ControlFlowNode for request | user-supplied input | +| django_tests.py:7:21:7:44 | ControlFlowNode for Attribute() | django_tests.py:4:25:4:31 | ControlFlowNode for request | django_tests.py:7:21:7:44 | ControlFlowNode for Attribute() | Cookie is constructed from a $@. | django_tests.py:4:25:4:31 | ControlFlowNode for request | user-supplied input | +| django_tests.py:13:30:13:100 | ControlFlowNode for Fstring | django_tests.py:11:26:11:32 | ControlFlowNode for request | django_tests.py:13:30:13:100 | ControlFlowNode for Fstring | Cookie is constructed from a $@. | django_tests.py:11:26:11:32 | ControlFlowNode for request | user-supplied input | edges | django_tests.py:4:25:4:31 | ControlFlowNode for request | django_tests.py:6:21:6:31 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | | django_tests.py:4:25:4:31 | ControlFlowNode for request | django_tests.py:7:21:7:31 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | @@ -22,7 +26,3 @@ nodes | django_tests.py:13:59:13:69 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | | django_tests.py:13:59:13:82 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | subpaths -#select -| django_tests.py:6:21:6:43 | ControlFlowNode for Attribute() | django_tests.py:4:25:4:31 | ControlFlowNode for request | django_tests.py:6:21:6:43 | ControlFlowNode for Attribute() | Cookie is constructed from a $@. | django_tests.py:4:25:4:31 | ControlFlowNode for request | user-supplied input | -| django_tests.py:7:21:7:44 | ControlFlowNode for Attribute() | django_tests.py:4:25:4:31 | ControlFlowNode for request | django_tests.py:7:21:7:44 | ControlFlowNode for Attribute() | Cookie is constructed from a $@. | django_tests.py:4:25:4:31 | ControlFlowNode for request | user-supplied input | -| django_tests.py:13:30:13:100 | ControlFlowNode for Fstring | django_tests.py:11:26:11:32 | ControlFlowNode for request | django_tests.py:13:30:13:100 | ControlFlowNode for Fstring | Cookie is constructed from a $@. | django_tests.py:11:26:11:32 | ControlFlowNode for request | user-supplied input | diff --git a/python/ql/test/query-tests/Security/CWE-020-CookieInjection/CookieInjection.qlref b/python/ql/test/query-tests/Security/CWE-020-CookieInjection/CookieInjection.qlref index a405c564b1b..788c1b424ff 100644 --- a/python/ql/test/query-tests/Security/CWE-020-CookieInjection/CookieInjection.qlref +++ b/python/ql/test/query-tests/Security/CWE-020-CookieInjection/CookieInjection.qlref @@ -1 +1,2 @@ -Security/CWE-020/CookieInjection.ql \ No newline at end of file +query: Security/CWE-020/CookieInjection.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Security/CWE-020-CookieInjection/django_tests.py b/python/ql/test/query-tests/Security/CWE-020-CookieInjection/django_tests.py index e070f5cab82..f77e8f20ea2 100644 --- a/python/ql/test/query-tests/Security/CWE-020-CookieInjection/django_tests.py +++ b/python/ql/test/query-tests/Security/CWE-020-CookieInjection/django_tests.py @@ -1,20 +1,20 @@ import django.http from django.urls import path -def django_response_bad(request): +def django_response_bad(request): # $ Source resp = django.http.HttpResponse() - resp.set_cookie(request.GET.get("name"), # BAD: Cookie is constructed from user input - request.GET.get("value")) + resp.set_cookie(request.GET.get("name"), # $ Alert # BAD: Cookie is constructed from user input + request.GET.get("value")) # $ Alert return resp -def django_response_bad2(request): +def django_response_bad2(request): # $ Source response = django.http.HttpResponse() - response['Set-Cookie'] = f"{request.GET.get('name')}={request.GET.get('value')}; SameSite=None;" # BAD: Cookie header is constructed from user input. + response['Set-Cookie'] = f"{request.GET.get('name')}={request.GET.get('value')}; SameSite=None;" # $ Alert # BAD: Cookie header is constructed from user input. return response # fake setup, you can't actually run this urlpatterns = [ path("response_bad", django_response_bad), path("response_bd2", django_response_bad2) -] \ No newline at end of file +] diff --git a/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.qlref b/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.qlref index 03c06feeec8..fbacbf2a07a 100644 --- a/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.qlref +++ b/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.qlref @@ -1 +1,2 @@ -Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.ql +query: Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/test.py b/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/test.py index 18b46298d8a..f2857914c03 100644 --- a/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/test.py +++ b/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/test.py @@ -2,7 +2,7 @@ import hashlib import hmac import base64 -from flask import Flask, request, make_response +from flask import Flask, request, make_response # $ Source app = Flask(__name__) SECRET_KEY = b"SECRET_KEY" @@ -12,7 +12,7 @@ SECRET_KEY = b"SECRET_KEY" def hmac_example(): data_raw = request.args.get("data").encode('utf-8') data = base64.decodebytes(data_raw) - my_hmac = hmac.new(SECRET_KEY, data, hashlib.sha256) + my_hmac = hmac.new(SECRET_KEY, data, hashlib.sha256) # $ Alert digest = my_hmac.digest() print(digest) return "ok" @@ -22,7 +22,7 @@ def hmac_example(): def hmac_example2(): data_raw = request.args.get("data").encode('utf-8') data = base64.decodebytes(data_raw) - my_hmac = hmac.new(key=SECRET_KEY, msg=data, digestmod=hashlib.sha256) + my_hmac = hmac.new(key=SECRET_KEY, msg=data, digestmod=hashlib.sha256) # $ Alert digest = my_hmac.digest() print(digest) return "ok" @@ -32,16 +32,16 @@ def hmac_example2(): def unknown_lib_1(): from unknown.lib import func data = request.args.get("data") - func(data) - func(kw=data) + func(data) # $ Alert + func(kw=data) # $ Alert @app.route("/unknown-lib-2") def unknown_lib_2(): import unknown.lib data = request.args.get("data") - unknown.lib.func(data) - unknown.lib.func(kw=data) + unknown.lib.func(data) # $ Alert + unknown.lib.func(kw=data) # $ Alert def handle_this(arg, application = None): diff --git a/python/ql/test/query-tests/Security/CWE-020-IncompleteHostnameRegExp/IncompleteHostnameRegExp.qlref b/python/ql/test/query-tests/Security/CWE-020-IncompleteHostnameRegExp/IncompleteHostnameRegExp.qlref index e818d947252..d1afa385825 100644 --- a/python/ql/test/query-tests/Security/CWE-020-IncompleteHostnameRegExp/IncompleteHostnameRegExp.qlref +++ b/python/ql/test/query-tests/Security/CWE-020-IncompleteHostnameRegExp/IncompleteHostnameRegExp.qlref @@ -1 +1,2 @@ -Security/CWE-020/IncompleteHostnameRegExp.ql \ No newline at end of file +query: Security/CWE-020/IncompleteHostnameRegExp.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Security/CWE-020-IncompleteHostnameRegExp/hosttest.py b/python/ql/test/query-tests/Security/CWE-020-IncompleteHostnameRegExp/hosttest.py index ca7f7094a8c..e2e90e65142 100644 --- a/python/ql/test/query-tests/Security/CWE-020-IncompleteHostnameRegExp/hosttest.py +++ b/python/ql/test/query-tests/Security/CWE-020-IncompleteHostnameRegExp/hosttest.py @@ -3,7 +3,7 @@ import re app = Flask(__name__) -UNSAFE_REGEX = re.compile("(www|beta).example.com/") +UNSAFE_REGEX = re.compile("(www|beta).example.com/") # $ Alert SAFE_REGEX = re.compile(r"(www|beta)\.example\.com/") @app.route('/some/path/bad') diff --git a/python/ql/test/query-tests/Security/CWE-020-IncompleteUrlSubstringSanitization/IncompleteUrlSubstringSanitization.qlref b/python/ql/test/query-tests/Security/CWE-020-IncompleteUrlSubstringSanitization/IncompleteUrlSubstringSanitization.qlref index 3fa6794419d..1c4c2382153 100644 --- a/python/ql/test/query-tests/Security/CWE-020-IncompleteUrlSubstringSanitization/IncompleteUrlSubstringSanitization.qlref +++ b/python/ql/test/query-tests/Security/CWE-020-IncompleteUrlSubstringSanitization/IncompleteUrlSubstringSanitization.qlref @@ -1 +1,2 @@ -Security/CWE-020/IncompleteUrlSubstringSanitization.ql \ No newline at end of file +query: Security/CWE-020/IncompleteUrlSubstringSanitization.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Security/CWE-020-IncompleteUrlSubstringSanitization/urltest.py b/python/ql/test/query-tests/Security/CWE-020-IncompleteUrlSubstringSanitization/urltest.py index 308b946603b..bc59d83819a 100644 --- a/python/ql/test/query-tests/Security/CWE-020-IncompleteUrlSubstringSanitization/urltest.py +++ b/python/ql/test/query-tests/Security/CWE-020-IncompleteUrlSubstringSanitization/urltest.py @@ -6,13 +6,13 @@ app = Flask(__name__) @app.route('/some/path/bad1') def unsafe1(request): target = request.args.get('target', '') - if "example.com" in target: + if "example.com" in target: # $ Alert return redirect(target) @app.route('/some/path/bad2') def unsafe2(request): target = request.args.get('target', '') - if target.endswith("example.com"): + if target.endswith("example.com"): # $ Alert return redirect(target) diff --git a/python/ql/test/query-tests/Security/CWE-020-SuspiciousRegexpRange/OverlyLargeRangeQuery.qlref b/python/ql/test/query-tests/Security/CWE-020-SuspiciousRegexpRange/OverlyLargeRangeQuery.qlref index 77b5c92707f..c42315c4550 100644 --- a/python/ql/test/query-tests/Security/CWE-020-SuspiciousRegexpRange/OverlyLargeRangeQuery.qlref +++ b/python/ql/test/query-tests/Security/CWE-020-SuspiciousRegexpRange/OverlyLargeRangeQuery.qlref @@ -1 +1,2 @@ -Security/CWE-020/OverlyLargeRange.ql +query: Security/CWE-020/OverlyLargeRange.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Security/CWE-020-SuspiciousRegexpRange/test.py b/python/ql/test/query-tests/Security/CWE-020-SuspiciousRegexpRange/test.py index 43380ccef0d..ca3cfd99190 100644 --- a/python/ql/test/query-tests/Security/CWE-020-SuspiciousRegexpRange/test.py +++ b/python/ql/test/query-tests/Security/CWE-020-SuspiciousRegexpRange/test.py @@ -1,10 +1,10 @@ import re -overlap1 = re.compile(r'^[0-93-5]$') # NOT OK +overlap1 = re.compile(r'^[0-93-5]$') # $ Alert # NOT OK -overlap2 = re.compile(r'[A-ZA-z]') # NOT OK +overlap2 = re.compile(r'[A-ZA-z]') # $ Alert # NOT OK -isEmpty = re.compile(r'^[z-a]$') # NOT OK +isEmpty = re.compile(r'^[z-a]$') # $ Alert # NOT OK isAscii = re.compile(r'^[\x00-\x7F]*$') # OK @@ -14,18 +14,18 @@ codePoints = re.compile(r'[^\x21-\x7E]|[[\](){}<>/%]') # OK NON_ALPHANUMERIC_REGEXP = re.compile(r'([^\#-~| |!])') # OK -smallOverlap = re.compile(r'[0-9a-fA-f]') # NOT OK +smallOverlap = re.compile(r'[0-9a-fA-f]') # $ Alert # NOT OK -weirdRange = re.compile(r'[$-`]') # NOT OK +weirdRange = re.compile(r'[$-`]') # $ Alert # NOT OK -keywordOperator = re.compile(r'[!\~\*\/%+-<>\^|=&]') # NOT OK +keywordOperator = re.compile(r'[!\~\*\/%+-<>\^|=&]') # $ Alert # NOT OK -notYoutube = re.compile(r'youtu\.be\/[a-z1-9.-_]+') # NOT OK +notYoutube = re.compile(r'youtu\.be\/[a-z1-9.-_]+') # $ Alert # NOT OK -numberToLetter = re.compile(r'[7-F]') # NOT OK +numberToLetter = re.compile(r'[7-F]') # $ Alert # NOT OK -overlapsWithClass1 = re.compile(r'[0-9\d]') # NOT OK +overlapsWithClass1 = re.compile(r'[0-9\d]') # $ Alert # NOT OK -overlapsWithClass2 = re.compile(r'[\w,.-?:*+]') # NOT OK +overlapsWithClass2 = re.compile(r'[\w,.-?:*+]') # $ Alert # NOT OK -unicodeStuff = re.compile('[\U0001D173-\U0001D17A\U000E0020-\U000E007F\U000e0001]') # NOT OK \ No newline at end of file +unicodeStuff = re.compile('[\U0001D173-\U0001D17A\U000E0020-\U000E007F\U000e0001]') # $ Alert # NOT OK diff --git a/python/ql/test/query-tests/Security/CWE-022-TarSlip/TarSlip.expected b/python/ql/test/query-tests/Security/CWE-022-TarSlip/TarSlip.expected index 6f98ea1aae2..abdccddd631 100644 --- a/python/ql/test/query-tests/Security/CWE-022-TarSlip/TarSlip.expected +++ b/python/ql/test/query-tests/Security/CWE-022-TarSlip/TarSlip.expected @@ -1,3 +1,13 @@ +#select +| tarslip.py:15:1:15:3 | ControlFlowNode for tar | tarslip.py:14:7:14:39 | ControlFlowNode for Attribute() | tarslip.py:15:1:15:3 | ControlFlowNode for tar | This file extraction depends on a $@. | tarslip.py:14:7:14:39 | ControlFlowNode for Attribute() | potentially untrusted source | +| tarslip.py:20:17:20:21 | ControlFlowNode for entry | tarslip.py:18:7:18:39 | ControlFlowNode for Attribute() | tarslip.py:20:17:20:21 | ControlFlowNode for entry | This file extraction depends on a $@. | tarslip.py:18:7:18:39 | ControlFlowNode for Attribute() | potentially untrusted source | +| tarslip.py:39:17:39:21 | ControlFlowNode for entry | tarslip.py:35:7:35:39 | ControlFlowNode for Attribute() | tarslip.py:39:17:39:21 | ControlFlowNode for entry | This file extraction depends on a $@. | tarslip.py:35:7:35:39 | ControlFlowNode for Attribute() | potentially untrusted source | +| tarslip.py:43:24:43:26 | ControlFlowNode for tar | tarslip.py:42:7:42:39 | ControlFlowNode for Attribute() | tarslip.py:43:24:43:26 | ControlFlowNode for tar | This file extraction depends on a $@. | tarslip.py:42:7:42:39 | ControlFlowNode for Attribute() | potentially untrusted source | +| tarslip.py:61:21:61:25 | ControlFlowNode for entry | tarslip.py:58:7:58:39 | ControlFlowNode for Attribute() | tarslip.py:61:21:61:25 | ControlFlowNode for entry | This file extraction depends on a $@. | tarslip.py:58:7:58:39 | ControlFlowNode for Attribute() | potentially untrusted source | +| tarslip.py:91:1:91:3 | ControlFlowNode for tar | tarslip.py:90:7:90:39 | ControlFlowNode for Attribute() | tarslip.py:91:1:91:3 | ControlFlowNode for tar | This file extraction depends on a $@. | tarslip.py:90:7:90:39 | ControlFlowNode for Attribute() | potentially untrusted source | +| tarslip.py:96:17:96:21 | ControlFlowNode for entry | tarslip.py:94:7:94:39 | ControlFlowNode for Attribute() | tarslip.py:96:17:96:21 | ControlFlowNode for entry | This file extraction depends on a $@. | tarslip.py:94:7:94:39 | ControlFlowNode for Attribute() | potentially untrusted source | +| tarslip.py:110:1:110:3 | ControlFlowNode for tar | tarslip.py:109:7:109:39 | ControlFlowNode for Attribute() | tarslip.py:110:1:110:3 | ControlFlowNode for tar | This file extraction depends on a $@. | tarslip.py:109:7:109:39 | ControlFlowNode for Attribute() | potentially untrusted source | +| tarslip.py:113:24:113:26 | ControlFlowNode for tar | tarslip.py:112:7:112:39 | ControlFlowNode for Attribute() | tarslip.py:113:24:113:26 | ControlFlowNode for tar | This file extraction depends on a $@. | tarslip.py:112:7:112:39 | ControlFlowNode for Attribute() | potentially untrusted source | edges | tarslip.py:14:1:14:3 | ControlFlowNode for tar | tarslip.py:15:1:15:3 | ControlFlowNode for tar | provenance | | | tarslip.py:14:7:14:39 | ControlFlowNode for Attribute() | tarslip.py:14:1:14:3 | ControlFlowNode for tar | provenance | | @@ -54,13 +64,3 @@ nodes | tarslip.py:112:7:112:39 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | | tarslip.py:113:24:113:26 | ControlFlowNode for tar | semmle.label | ControlFlowNode for tar | subpaths -#select -| tarslip.py:15:1:15:3 | ControlFlowNode for tar | tarslip.py:14:7:14:39 | ControlFlowNode for Attribute() | tarslip.py:15:1:15:3 | ControlFlowNode for tar | This file extraction depends on a $@. | tarslip.py:14:7:14:39 | ControlFlowNode for Attribute() | potentially untrusted source | -| tarslip.py:20:17:20:21 | ControlFlowNode for entry | tarslip.py:18:7:18:39 | ControlFlowNode for Attribute() | tarslip.py:20:17:20:21 | ControlFlowNode for entry | This file extraction depends on a $@. | tarslip.py:18:7:18:39 | ControlFlowNode for Attribute() | potentially untrusted source | -| tarslip.py:39:17:39:21 | ControlFlowNode for entry | tarslip.py:35:7:35:39 | ControlFlowNode for Attribute() | tarslip.py:39:17:39:21 | ControlFlowNode for entry | This file extraction depends on a $@. | tarslip.py:35:7:35:39 | ControlFlowNode for Attribute() | potentially untrusted source | -| tarslip.py:43:24:43:26 | ControlFlowNode for tar | tarslip.py:42:7:42:39 | ControlFlowNode for Attribute() | tarslip.py:43:24:43:26 | ControlFlowNode for tar | This file extraction depends on a $@. | tarslip.py:42:7:42:39 | ControlFlowNode for Attribute() | potentially untrusted source | -| tarslip.py:61:21:61:25 | ControlFlowNode for entry | tarslip.py:58:7:58:39 | ControlFlowNode for Attribute() | tarslip.py:61:21:61:25 | ControlFlowNode for entry | This file extraction depends on a $@. | tarslip.py:58:7:58:39 | ControlFlowNode for Attribute() | potentially untrusted source | -| tarslip.py:91:1:91:3 | ControlFlowNode for tar | tarslip.py:90:7:90:39 | ControlFlowNode for Attribute() | tarslip.py:91:1:91:3 | ControlFlowNode for tar | This file extraction depends on a $@. | tarslip.py:90:7:90:39 | ControlFlowNode for Attribute() | potentially untrusted source | -| tarslip.py:96:17:96:21 | ControlFlowNode for entry | tarslip.py:94:7:94:39 | ControlFlowNode for Attribute() | tarslip.py:96:17:96:21 | ControlFlowNode for entry | This file extraction depends on a $@. | tarslip.py:94:7:94:39 | ControlFlowNode for Attribute() | potentially untrusted source | -| tarslip.py:110:1:110:3 | ControlFlowNode for tar | tarslip.py:109:7:109:39 | ControlFlowNode for Attribute() | tarslip.py:110:1:110:3 | ControlFlowNode for tar | This file extraction depends on a $@. | tarslip.py:109:7:109:39 | ControlFlowNode for Attribute() | potentially untrusted source | -| tarslip.py:113:24:113:26 | ControlFlowNode for tar | tarslip.py:112:7:112:39 | ControlFlowNode for Attribute() | tarslip.py:113:24:113:26 | ControlFlowNode for tar | This file extraction depends on a $@. | tarslip.py:112:7:112:39 | ControlFlowNode for Attribute() | potentially untrusted source | diff --git a/python/ql/test/query-tests/Security/CWE-022-TarSlip/TarSlip.qlref b/python/ql/test/query-tests/Security/CWE-022-TarSlip/TarSlip.qlref index cfede0c92b2..c9b6b9f4f06 100644 --- a/python/ql/test/query-tests/Security/CWE-022-TarSlip/TarSlip.qlref +++ b/python/ql/test/query-tests/Security/CWE-022-TarSlip/TarSlip.qlref @@ -1 +1,2 @@ -Security/CWE-022/TarSlip.ql +query: Security/CWE-022/TarSlip.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Security/CWE-022-TarSlip/tarslip.py b/python/ql/test/query-tests/Security/CWE-022-TarSlip/tarslip.py index 2c06d01adfd..b2614b8a6d1 100644 --- a/python/ql/test/query-tests/Security/CWE-022-TarSlip/tarslip.py +++ b/python/ql/test/query-tests/Security/CWE-022-TarSlip/tarslip.py @@ -11,13 +11,13 @@ tar = tarfile.open(safe_filename_tar) for entry in tar: tar.extract(entry) -tar = tarfile.open(unsafe_filename_tar) -tar.extractall() +tar = tarfile.open(unsafe_filename_tar) # $ Source +tar.extractall() # $ Alert tar.close() -tar = tarfile.open(unsafe_filename_tar) +tar = tarfile.open(unsafe_filename_tar) # $ Source for entry in tar: - tar.extract(entry) + tar.extract(entry) # $ Alert tar = tarfile.open(safe_filename_tar) tar.extractall() @@ -32,15 +32,15 @@ for entry in tar: tar.extract(entry, "/tmp/unpack/") #Part Sanitized -tar = tarfile.open(unsafe_filename_tar) +tar = tarfile.open(unsafe_filename_tar) # $ Source for entry in tar: if ".." in entry.name: raise ValueError("Illegal tar archive entry") - tar.extract(entry, "/tmp/unpack/") + tar.extract(entry, "/tmp/unpack/") # $ Alert #Unsanitized members -tar = tarfile.open(unsafe_filename_tar) -tar.extractall(members=tar) +tar = tarfile.open(unsafe_filename_tar) # $ Source +tar.extractall(members=tar) # $ Alert #Sanitize members @@ -55,10 +55,10 @@ tar.extractall(members=safemembers(tar)) # Wrong sanitizer (is missing not) -tar = tarfile.open(unsafe_filename_tar) +tar = tarfile.open(unsafe_filename_tar) # $ Source for entry in tar: if os.path.isabs(entry.name) or ".." in entry.name: - tar.extract(entry, "/tmp/unpack/") + tar.extract(entry, "/tmp/unpack/") # $ Alert # OK Sanitized using not @@ -87,13 +87,13 @@ for entry in tar: extraction_filter = "fully_trusted" -tar = tarfile.open(unsafe_filename_tar) -tar.extractall(filter=extraction_filter) # unsafe +tar = tarfile.open(unsafe_filename_tar) # $ Source +tar.extractall(filter=extraction_filter) # $ Alert # unsafe tar.close() -tar = tarfile.open(unsafe_filename_tar) +tar = tarfile.open(unsafe_filename_tar) # $ Source for entry in tar: - tar.extract(entry, filter=extraction_filter) # unsafe + tar.extract(entry, filter=extraction_filter) # $ Alert # unsafe extraction_filter = "data" @@ -106,11 +106,11 @@ for entry in tar: tar.extract(entry, filter=extraction_filter) # safe extraction_filter = None -tar = tarfile.open(unsafe_filename_tar) -tar.extractall(filter=extraction_filter) # unsafe +tar = tarfile.open(unsafe_filename_tar) # $ Source +tar.extractall(filter=extraction_filter) # $ Alert # unsafe -tar = tarfile.open(unsafe_filename_tar) -tar.extractall(members=tar, filter=extraction_filter) # unsafe +tar = tarfile.open(unsafe_filename_tar) # $ Source +tar.extractall(members=tar, filter=extraction_filter) # $ Alert # unsafe tar = tarfile.open(unsafe_filename_tar) tar.extractall(members=safemembers(tar), filter=extraction_filter) # safe -- we assume `safemembers` makes up for the unsafe filter diff --git a/python/ql/test/query-tests/Security/CWE-074-TemplateInjection/JinjaSsti.py b/python/ql/test/query-tests/Security/CWE-074-TemplateInjection/JinjaSsti.py index f1fe834e493..432286eeb6d 100644 --- a/python/ql/test/query-tests/Security/CWE-074-TemplateInjection/JinjaSsti.py +++ b/python/ql/test/query-tests/Security/CWE-074-TemplateInjection/JinjaSsti.py @@ -4,21 +4,21 @@ from jinja2 import Template from jinja2 import Environment, DictLoader, escape -def a(request): +def a(request): # $ Source # Load the template template = request.GET['template'] - t = Template(template) # BAD: Template constructed from user input + t = Template(template) # $ Alert # BAD: Template constructed from user input name = request.GET['name'] # Render the template with the context data html = t.render(name=escape(name)) return HttpResponse(html) -def b(request): +def b(request): # $ Source import jinja2 # Load the template template = request.GET['template'] env = Environment() - t = env.from_string(template) # BAD: Template constructed from user input + t = env.from_string(template) # $ Alert # BAD: Template constructed from user input name = request.GET['name'] # Render the template with the context data html = t.render(name=escape(name)) diff --git a/python/ql/test/query-tests/Security/CWE-074-TemplateInjection/TemplateInjection.expected b/python/ql/test/query-tests/Security/CWE-074-TemplateInjection/TemplateInjection.expected index f9210772839..a4bf57e174c 100644 --- a/python/ql/test/query-tests/Security/CWE-074-TemplateInjection/TemplateInjection.expected +++ b/python/ql/test/query-tests/Security/CWE-074-TemplateInjection/TemplateInjection.expected @@ -1,3 +1,6 @@ +#select +| JinjaSsti.py:10:18:10:25 | ControlFlowNode for template | JinjaSsti.py:7:7:7:13 | ControlFlowNode for request | JinjaSsti.py:10:18:10:25 | ControlFlowNode for template | This template construction depends on a $@. | JinjaSsti.py:7:7:7:13 | ControlFlowNode for request | user-provided value | +| JinjaSsti.py:21:25:21:32 | ControlFlowNode for template | JinjaSsti.py:16:7:16:13 | ControlFlowNode for request | JinjaSsti.py:21:25:21:32 | ControlFlowNode for template | This template construction depends on a $@. | JinjaSsti.py:16:7:16:13 | ControlFlowNode for request | user-provided value | edges | JinjaSsti.py:7:7:7:13 | ControlFlowNode for request | JinjaSsti.py:9:5:9:12 | ControlFlowNode for template | provenance | AdditionalTaintStep | | JinjaSsti.py:9:5:9:12 | ControlFlowNode for template | JinjaSsti.py:10:18:10:25 | ControlFlowNode for template | provenance | | @@ -11,6 +14,3 @@ nodes | JinjaSsti.py:19:5:19:12 | ControlFlowNode for template | semmle.label | ControlFlowNode for template | | JinjaSsti.py:21:25:21:32 | ControlFlowNode for template | semmle.label | ControlFlowNode for template | subpaths -#select -| JinjaSsti.py:10:18:10:25 | ControlFlowNode for template | JinjaSsti.py:7:7:7:13 | ControlFlowNode for request | JinjaSsti.py:10:18:10:25 | ControlFlowNode for template | This template construction depends on a $@. | JinjaSsti.py:7:7:7:13 | ControlFlowNode for request | user-provided value | -| JinjaSsti.py:21:25:21:32 | ControlFlowNode for template | JinjaSsti.py:16:7:16:13 | ControlFlowNode for request | JinjaSsti.py:21:25:21:32 | ControlFlowNode for template | This template construction depends on a $@. | JinjaSsti.py:16:7:16:13 | ControlFlowNode for request | user-provided value | diff --git a/python/ql/test/query-tests/Security/CWE-074-TemplateInjection/TemplateInjection.qlref b/python/ql/test/query-tests/Security/CWE-074-TemplateInjection/TemplateInjection.qlref index ead6bb469c6..818407e3eb8 100644 --- a/python/ql/test/query-tests/Security/CWE-074-TemplateInjection/TemplateInjection.qlref +++ b/python/ql/test/query-tests/Security/CWE-074-TemplateInjection/TemplateInjection.qlref @@ -1 +1,2 @@ -Security/CWE-074/TemplateInjection.ql \ No newline at end of file +query: Security/CWE-074/TemplateInjection.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Security/CWE-078-CommandInjection-py2/CommandInjection.qlref b/python/ql/test/query-tests/Security/CWE-078-CommandInjection-py2/CommandInjection.qlref index e38b88f2919..8d677af3571 100644 --- a/python/ql/test/query-tests/Security/CWE-078-CommandInjection-py2/CommandInjection.qlref +++ b/python/ql/test/query-tests/Security/CWE-078-CommandInjection-py2/CommandInjection.qlref @@ -1 +1,2 @@ -Security/CWE-078/CommandInjection.ql +query: Security/CWE-078/CommandInjection.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Security/CWE-078-CommandInjection-py2/command_injection.py b/python/ql/test/query-tests/Security/CWE-078-CommandInjection-py2/command_injection.py index 09dd2bf9716..676215f29d1 100644 --- a/python/ql/test/query-tests/Security/CWE-078-CommandInjection-py2/command_injection.py +++ b/python/ql/test/query-tests/Security/CWE-078-CommandInjection-py2/command_injection.py @@ -2,7 +2,7 @@ import os import platform import popen2 -from flask import Flask, request +from flask import Flask, request # $ Source app = Flask(__name__) @@ -16,14 +16,14 @@ def python2_specific(): """ files = request.args.get("files", "") - os.popen2("ls " + files) - os.popen3("ls " + files) - os.popen4("ls " + files) + os.popen2("ls " + files) # $ Alert + os.popen3("ls " + files) # $ Alert + os.popen4("ls " + files) # $ Alert - platform.popen("ls " + files) + platform.popen("ls " + files) # $ Alert - popen2.popen2("ls " + files) - popen2.popen3("ls " + files) - popen2.popen4("ls " + files) - popen2.Popen3("ls " + files) - popen2.Popen4("ls " + files) + popen2.popen2("ls " + files) # $ Alert + popen2.popen3("ls " + files) # $ Alert + popen2.popen4("ls " + files) # $ Alert + popen2.Popen3("ls " + files) # $ Alert + popen2.Popen4("ls " + files) # $ Alert diff --git a/python/ql/test/query-tests/Security/CWE-078-CommandInjection/CommandInjection.qlref b/python/ql/test/query-tests/Security/CWE-078-CommandInjection/CommandInjection.qlref index e38b88f2919..8d677af3571 100644 --- a/python/ql/test/query-tests/Security/CWE-078-CommandInjection/CommandInjection.qlref +++ b/python/ql/test/query-tests/Security/CWE-078-CommandInjection/CommandInjection.qlref @@ -1 +1,2 @@ -Security/CWE-078/CommandInjection.ql +query: Security/CWE-078/CommandInjection.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Security/CWE-078-CommandInjection/command_injection.py b/python/ql/test/query-tests/Security/CWE-078-CommandInjection/command_injection.py index 3ba50c25480..fb4f09c1c2a 100644 --- a/python/ql/test/query-tests/Security/CWE-078-CommandInjection/command_injection.py +++ b/python/ql/test/query-tests/Security/CWE-078-CommandInjection/command_injection.py @@ -2,7 +2,7 @@ import re import os import subprocess -from flask import Flask, request +from flask import Flask, request # $ Source app = Flask(__name__) @@ -10,27 +10,27 @@ app = Flask(__name__) def command_injection1(): files = request.args.get('files', '') # Don't let files be `; rm -rf /` - os.system("ls " + files) # $ result=BAD + os.system("ls " + files) # $ Alert result=BAD @app.route("/command2") def command_injection2(): files = request.args.get('files', '') # Don't let files be `; rm -rf /` - subprocess.Popen("ls " + files, shell=True) # $ result=BAD + subprocess.Popen("ls " + files, shell=True) # $ Alert result=BAD @app.route("/command3") def first_arg_injection(): cmd = request.args.get('cmd', '') - subprocess.Popen([cmd, "param1"]) # $ result=BAD + subprocess.Popen([cmd, "param1"]) # $ Alert result=BAD @app.route("/other_cases") def others(): files = request.args.get('files', '') # Don't let files be `; rm -rf /` - os.popen("ls " + files) # $ result=BAD + os.popen("ls " + files) # $ Alert result=BAD @app.route("/multiple") @@ -38,8 +38,8 @@ def multiple(): command = request.args.get('command', '') # We should mark flow to both calls here, which conflicts with removing flow out of # a sink due to use-use flow. - os.system(command) # $ result=BAD - os.system(command) # $ result=BAD + os.system(command) # $ Alert result=BAD + os.system(command) # $ Alert result=BAD @app.route("/not-into-sink-impl") @@ -52,11 +52,11 @@ def not_into_sink_impl(): subprocess.call implementation: https://github.com/python/cpython/blob/fa7ce080175f65d678a7d5756c94f82887fc9803/Lib/subprocess.py#L341 """ command = request.args.get('command', '') - os.system(command) # $ result=BAD - os.popen(command) # $ result=BAD - subprocess.call(command) # $ result=BAD - subprocess.check_call(command) # $ result=BAD - subprocess.run(command) # $ result=BAD + os.system(command) # $ Alert result=BAD + os.popen(command) # $ Alert result=BAD + subprocess.call(command) # $ Alert result=BAD + subprocess.check_call(command) # $ Alert result=BAD + subprocess.run(command) # $ Alert result=BAD @app.route("/path-exists-not-sanitizer") @@ -70,11 +70,11 @@ def path_exists_not_sanitizer(): """ path = request.args.get('path', '') if os.path.exists(path): - os.system("ls " + path) # $ result=BAD + os.system("ls " + path) # $ Alert result=BAD @app.route("/restricted-characters") def restricted_characters(): path = request.args.get('path', '') if re.match(r'^[a-zA-Z0-9_-]+$', path): - os.system("ls " + path) # $ SPURIOUS: result=BAD + os.system("ls " + path) # $ Alert SPURIOUS: result=BAD diff --git a/python/ql/test/query-tests/Security/CWE-078-UnsafeShellCommandConstruction/UnsafeShellCommandConstruction.qlref b/python/ql/test/query-tests/Security/CWE-078-UnsafeShellCommandConstruction/UnsafeShellCommandConstruction.qlref index fdc01b9ecbf..26c43ff16ca 100644 --- a/python/ql/test/query-tests/Security/CWE-078-UnsafeShellCommandConstruction/UnsafeShellCommandConstruction.qlref +++ b/python/ql/test/query-tests/Security/CWE-078-UnsafeShellCommandConstruction/UnsafeShellCommandConstruction.qlref @@ -1 +1,2 @@ -Security/CWE-078/UnsafeShellCommandConstruction.ql +query: Security/CWE-078/UnsafeShellCommandConstruction.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Security/CWE-078-UnsafeShellCommandConstruction/src/unsafe_shell_test.py b/python/ql/test/query-tests/Security/CWE-078-UnsafeShellCommandConstruction/src/unsafe_shell_test.py index 95d05bbfaf0..22c7513f02d 100644 --- a/python/ql/test/query-tests/Security/CWE-078-UnsafeShellCommandConstruction/src/unsafe_shell_test.py +++ b/python/ql/test/query-tests/Security/CWE-078-UnsafeShellCommandConstruction/src/unsafe_shell_test.py @@ -1,45 +1,45 @@ import os import subprocess -def unsafe_shell_one(name): - os.system("ping " + name) # $ result=BAD +def unsafe_shell_one(name): # $ Source + os.system("ping " + name) # $ Alert result=BAD # f-strings - os.system(f"ping {name}") # $ result=BAD + os.system(f"ping {name}") # $ Alert result=BAD # array.join - os.system("ping " + " ".join(name)) # $ result=BAD + os.system("ping " + " ".join(name)) # $ Alert result=BAD # array.join, with a list - os.system("ping " + " ".join([name])) # $ result=BAD + os.system("ping " + " ".join([name])) # $ Alert result=BAD # format, using .format - os.system("ping {}".format(name)) # $ result=BAD + os.system("ping {}".format(name)) # $ Alert result=BAD # format, using % - os.system("ping %s" % name) # $ result=BAD + os.system("ping %s" % name) # $ Alert result=BAD os.system(name) # OK - seems intentional. import fabric -def facbric_stuff (name): +def facbric_stuff (name): # $ Source fabric.api.run("ping " + name, shell=False) # OK - fabric.api.run("ping " + name, shell=True) # $ result=BAD + fabric.api.run("ping " + name, shell=True) # $ Alert result=BAD def indirect(flag): fabric.api.run("ping " + name, shell=flag) # OK indirect(False) -def subprocess_flag (name): +def subprocess_flag (name): # $ Source subprocess.run("ping " + name, shell=False) # OK - and nonsensical - subprocess.run("ping " + name, shell=True) # $ result=BAD + subprocess.run("ping " + name, shell=True) # $ Alert result=BAD def indirect(flag, x): - subprocess.run("ping " + x, shell=flag) # $ result=BAD + subprocess.run("ping " + x, shell=flag) # $ Alert result=BAD indirect(True, name) diff --git a/python/ql/test/query-tests/Security/CWE-079-Jinja2WithoutEscaping/Jinja2WithoutEscaping.qlref b/python/ql/test/query-tests/Security/CWE-079-Jinja2WithoutEscaping/Jinja2WithoutEscaping.qlref index 9fefcf4a030..d63a6068dc2 100644 --- a/python/ql/test/query-tests/Security/CWE-079-Jinja2WithoutEscaping/Jinja2WithoutEscaping.qlref +++ b/python/ql/test/query-tests/Security/CWE-079-Jinja2WithoutEscaping/Jinja2WithoutEscaping.qlref @@ -1 +1,2 @@ -Security/CWE-079/Jinja2WithoutEscaping.ql +query: Security/CWE-079/Jinja2WithoutEscaping.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Security/CWE-079-Jinja2WithoutEscaping/jinja2_escaping.py b/python/ql/test/query-tests/Security/CWE-079-Jinja2WithoutEscaping/jinja2_escaping.py index aed840ce886..f3d1150df9a 100644 --- a/python/ql/test/query-tests/Security/CWE-079-Jinja2WithoutEscaping/jinja2_escaping.py +++ b/python/ql/test/query-tests/Security/CWE-079-Jinja2WithoutEscaping/jinja2_escaping.py @@ -6,7 +6,7 @@ from jinja2 import Environment, select_autoescape, FileSystemLoader, Template app = Flask(__name__) loader = FileSystemLoader( searchpath="templates/" ) -unsafe_env = Environment(loader=loader) +unsafe_env = Environment(loader=loader) # $ Alert safe1_env = Environment(loader=loader, autoescape=True) safe2_env = Environment(loader=loader, autoescape=select_autoescape()) @@ -38,18 +38,18 @@ e = Environment( auto = select_autoescape e = Environment(autoescape=auto) # GOOD z = 0 -e = Environment(autoescape=z) # BAD +e = Environment(autoescape=z) # $ Alert # BAD E = Environment -E() # BAD -E(autoescape=z) # BAD +E() # $ Alert # BAD +E(autoescape=z) # $ Alert # BAD E(autoescape=auto) # GOOD E(autoescape=0+1) # GOOD def checked(cond=False): if cond: - e = Environment(autoescape=cond) # GOOD + e = Environment(autoescape=cond) # $ Alert # GOOD -unsafe_tmpl = Template('Hello {{ name }}!') +unsafe_tmpl = Template('Hello {{ name }}!') # $ Alert safe1_tmpl = Template('Hello {{ name }}!', autoescape=True) safe2_tmpl = Template('Hello {{ name }}!', autoescape=select_autoescape()) diff --git a/python/ql/test/query-tests/Security/CWE-079-ReflectedXss/ReflectedXss.expected b/python/ql/test/query-tests/Security/CWE-079-ReflectedXss/ReflectedXss.expected index d332231e0c9..bf4f584c815 100644 --- a/python/ql/test/query-tests/Security/CWE-079-ReflectedXss/ReflectedXss.expected +++ b/python/ql/test/query-tests/Security/CWE-079-ReflectedXss/ReflectedXss.expected @@ -1,3 +1,7 @@ +#select +| reflected_xss.py:10:26:10:53 | ControlFlowNode for BinaryExpr | reflected_xss.py:2:26:2:32 | ControlFlowNode for ImportMember | reflected_xss.py:10:26:10:53 | ControlFlowNode for BinaryExpr | Cross-site scripting vulnerability due to a $@. | reflected_xss.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | +| reflected_xss.py:22:26:22:41 | ControlFlowNode for Attribute() | reflected_xss.py:2:26:2:32 | ControlFlowNode for ImportMember | reflected_xss.py:22:26:22:41 | ControlFlowNode for Attribute() | Cross-site scripting vulnerability due to a $@. | reflected_xss.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | +| reflected_xss.py:28:26:28:41 | ControlFlowNode for Attribute() | reflected_xss.py:2:26:2:32 | ControlFlowNode for ImportMember | reflected_xss.py:28:26:28:41 | ControlFlowNode for Attribute() | Cross-site scripting vulnerability due to a $@. | reflected_xss.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | edges | reflected_xss.py:2:26:2:32 | ControlFlowNode for ImportMember | reflected_xss.py:2:26:2:32 | ControlFlowNode for request | provenance | | | reflected_xss.py:2:26:2:32 | ControlFlowNode for request | reflected_xss.py:9:18:9:24 | ControlFlowNode for request | provenance | | @@ -28,7 +32,3 @@ nodes | reflected_xss.py:27:23:27:29 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | | reflected_xss.py:28:26:28:41 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | subpaths -#select -| reflected_xss.py:10:26:10:53 | ControlFlowNode for BinaryExpr | reflected_xss.py:2:26:2:32 | ControlFlowNode for ImportMember | reflected_xss.py:10:26:10:53 | ControlFlowNode for BinaryExpr | Cross-site scripting vulnerability due to a $@. | reflected_xss.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | -| reflected_xss.py:22:26:22:41 | ControlFlowNode for Attribute() | reflected_xss.py:2:26:2:32 | ControlFlowNode for ImportMember | reflected_xss.py:22:26:22:41 | ControlFlowNode for Attribute() | Cross-site scripting vulnerability due to a $@. | reflected_xss.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | -| reflected_xss.py:28:26:28:41 | ControlFlowNode for Attribute() | reflected_xss.py:2:26:2:32 | ControlFlowNode for ImportMember | reflected_xss.py:28:26:28:41 | ControlFlowNode for Attribute() | Cross-site scripting vulnerability due to a $@. | reflected_xss.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | diff --git a/python/ql/test/query-tests/Security/CWE-079-ReflectedXss/ReflectedXss.qlref b/python/ql/test/query-tests/Security/CWE-079-ReflectedXss/ReflectedXss.qlref index e0efe102416..9cd0122e556 100644 --- a/python/ql/test/query-tests/Security/CWE-079-ReflectedXss/ReflectedXss.qlref +++ b/python/ql/test/query-tests/Security/CWE-079-ReflectedXss/ReflectedXss.qlref @@ -1 +1,2 @@ -Security/CWE-079/ReflectedXss.ql +query: Security/CWE-079/ReflectedXss.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Security/CWE-079-ReflectedXss/reflected_xss.py b/python/ql/test/query-tests/Security/CWE-079-ReflectedXss/reflected_xss.py index 98682f04f3c..67fcf0bf9ff 100644 --- a/python/ql/test/query-tests/Security/CWE-079-ReflectedXss/reflected_xss.py +++ b/python/ql/test/query-tests/Security/CWE-079-ReflectedXss/reflected_xss.py @@ -1,5 +1,5 @@ import json -from flask import Flask, request, make_response, escape, jsonify +from flask import Flask, request, make_response, escape, jsonify # $ Source app = Flask(__name__) @@ -7,7 +7,7 @@ app = Flask(__name__) @app.route("/unsafe") def unsafe(): first_name = request.args.get("name", "") - return make_response("Your name is " + first_name) # NOT OK + return make_response("Your name is " + first_name) # $ Alert # NOT OK @app.route("/safe") @@ -19,13 +19,13 @@ def safe(): @app.route("/unsafe/json") def unsafe_json(): data = json.loads(request.data) - return make_response(json.dumps(data)) # NOT OK + return make_response(json.dumps(data)) # $ Alert # NOT OK @app.route("/safe/json") def safe_json(): data = json.loads(request.data) - return make_response(json.dumps(data), 200, {'Content-Type': 'application/json'}) # OK, FP + return make_response(json.dumps(data), 200, {'Content-Type': 'application/json'}) # $ SPURIOUS: Alert # OK, FP @app.route("/jsonify") diff --git a/python/ql/test/query-tests/Security/CWE-089-SqlInjection-local-threat-model/SqlInjection.qlref b/python/ql/test/query-tests/Security/CWE-089-SqlInjection-local-threat-model/SqlInjection.qlref index b6916bd2cd4..e1918157744 100644 --- a/python/ql/test/query-tests/Security/CWE-089-SqlInjection-local-threat-model/SqlInjection.qlref +++ b/python/ql/test/query-tests/Security/CWE-089-SqlInjection-local-threat-model/SqlInjection.qlref @@ -1,2 +1,4 @@ query: Security/CWE-089/SqlInjection.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Security/CWE-089-SqlInjection-local-threat-model/test.py b/python/ql/test/query-tests/Security/CWE-089-SqlInjection-local-threat-model/test.py index 97bfa393ced..70959d0bff0 100644 --- a/python/ql/test/query-tests/Security/CWE-089-SqlInjection-local-threat-model/test.py +++ b/python/ql/test/query-tests/Security/CWE-089-SqlInjection-local-threat-model/test.py @@ -3,4 +3,4 @@ import sys import psycopg conn = psycopg.connect(...) -conn.execute(sys.argv[1]) +conn.execute(sys.argv[1]) # $ Alert diff --git a/python/ql/test/query-tests/Security/CWE-090-LdapInjection/LdapInjection.qlref b/python/ql/test/query-tests/Security/CWE-090-LdapInjection/LdapInjection.qlref index 19112f987ad..87db0e58f84 100644 --- a/python/ql/test/query-tests/Security/CWE-090-LdapInjection/LdapInjection.qlref +++ b/python/ql/test/query-tests/Security/CWE-090-LdapInjection/LdapInjection.qlref @@ -1 +1,2 @@ -Security/CWE-090/LdapInjection.ql +query: Security/CWE-090/LdapInjection.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Security/CWE-090-LdapInjection/ldap3_bad.py b/python/ql/test/query-tests/Security/CWE-090-LdapInjection/ldap3_bad.py index 2edb986fccf..a69aef9ad3d 100644 --- a/python/ql/test/query-tests/Security/CWE-090-LdapInjection/ldap3_bad.py +++ b/python/ql/test/query-tests/Security/CWE-090-LdapInjection/ldap3_bad.py @@ -1,4 +1,4 @@ -from flask import request, Flask +from flask import request, Flask # $ Source import ldap3 app = Flask(__name__) @@ -18,7 +18,7 @@ def normal(): srv = ldap3.Server('ldap://127.0.0.1') conn = ldap3.Connection(srv, user=dn, auto_bind=True) - conn.search(dn, search_filter) + conn.search(dn, search_filter) # $ Alert @app.route("/direct") @@ -35,7 +35,7 @@ def direct(): srv = ldap3.Server('ldap://127.0.0.1') conn = ldap3.Connection(srv, user=dn, auto_bind=True).search( - dn, search_filter) + dn, search_filter) # $ Alert # if __name__ == "__main__": # app.run(debug=True) diff --git a/python/ql/test/query-tests/Security/CWE-090-LdapInjection/ldap_bad.py b/python/ql/test/query-tests/Security/CWE-090-LdapInjection/ldap_bad.py index 133b0baaf9c..8fd38f52f57 100644 --- a/python/ql/test/query-tests/Security/CWE-090-LdapInjection/ldap_bad.py +++ b/python/ql/test/query-tests/Security/CWE-090-LdapInjection/ldap_bad.py @@ -1,4 +1,4 @@ -from flask import request, Flask +from flask import request, Flask # $ Source import ldap app = Flask(__name__) @@ -18,7 +18,7 @@ def normal(): ldap_connection = ldap.initialize("ldap://127.0.0.1") user = ldap_connection.search_s( - dn, ldap.SCOPE_SUBTREE, search_filter) + dn, ldap.SCOPE_SUBTREE, search_filter) # $ Alert @app.route("/direct") @@ -34,7 +34,7 @@ def direct(): search_filter = "(user={})".format(unsafe_filter) user = ldap.initialize("ldap://127.0.0.1").search_s( - dn, ldap.SCOPE_SUBTREE, search_filter) + dn, ldap.SCOPE_SUBTREE, search_filter) # $ Alert @app.route("/normal_argbyname") @@ -52,7 +52,7 @@ def normal_argbyname(): ldap_connection = ldap.initialize("ldap://127.0.0.1") user = ldap_connection.search_s( - dn, ldap.SCOPE_SUBTREE, filterstr=search_filter) + dn, ldap.SCOPE_SUBTREE, filterstr=search_filter) # $ Alert # if __name__ == "__main__": diff --git a/python/ql/test/query-tests/Security/CWE-113-HeaderInjection/Tests2-with-wsgi-validator/HeaderInjection.qlref b/python/ql/test/query-tests/Security/CWE-113-HeaderInjection/Tests2-with-wsgi-validator/HeaderInjection.qlref index 7dbe28e4b59..4379f3d416b 100644 --- a/python/ql/test/query-tests/Security/CWE-113-HeaderInjection/Tests2-with-wsgi-validator/HeaderInjection.qlref +++ b/python/ql/test/query-tests/Security/CWE-113-HeaderInjection/Tests2-with-wsgi-validator/HeaderInjection.qlref @@ -1 +1,2 @@ -Security/CWE-113/HeaderInjection.ql \ No newline at end of file +query: Security/CWE-113/HeaderInjection.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Security/CWE-116-BadTagFilter/BadTagFilter.qlref b/python/ql/test/query-tests/Security/CWE-116-BadTagFilter/BadTagFilter.qlref index e5fc84fd48a..443c007de0c 100644 --- a/python/ql/test/query-tests/Security/CWE-116-BadTagFilter/BadTagFilter.qlref +++ b/python/ql/test/query-tests/Security/CWE-116-BadTagFilter/BadTagFilter.qlref @@ -1 +1,2 @@ -Security/CWE-116/BadTagFilter.ql +query: Security/CWE-116/BadTagFilter.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Security/CWE-116-BadTagFilter/tst.py b/python/ql/test/query-tests/Security/CWE-116-BadTagFilter/tst.py index 2c3ec0667e3..04b81be29e6 100644 --- a/python/ql/test/query-tests/Security/CWE-116-BadTagFilter/tst.py +++ b/python/ql/test/query-tests/Security/CWE-116-BadTagFilter/tst.py @@ -1,28 +1,28 @@ import re filters = [ - re.compile(r""".*?<\/script>""", re.IGNORECASE), # NOT OK - doesn't match newlines or `` - re.compile(r""".*?<\/script>""", re.IGNORECASE | re.DOTALL), # NOT OK - doesn't match `` + re.compile(r""".*?<\/script>""", re.IGNORECASE), # $ Alert # NOT OK - doesn't match newlines or `` + re.compile(r""".*?<\/script>""", re.IGNORECASE | re.DOTALL), # $ Alert # NOT OK - doesn't match `` re.compile(r""".*?<\/script[^>]*>""", re.IGNORECASE | re.DOTALL), # OK re.compile(r"""""", re.IGNORECASE | re.DOTALL), # OK - we don't care regexps that only match comments re.compile(r""")|([^\/\s>]+)[\S\s]*?>"""), #// NOT OK - doesn't match comments with the right capture groups - re.compile(r"""<(?:(?:\/([^>]+)>)|(?:!--([\S|\s]*?)-->)|(?:([^\/\s>]+)((?:\s+[\w\-:.]+(?:\s*=\s*?(?:(?:"[^"]*")|(?:'[^']*')|[^\s"'\/>]+))?)*)[\S\s]*?(\/?)>))"""), # NOT OK - capture groups - re.compile(r"""(<[a-z\/!$]("[^"]*"|'[^']*'|[^'">])*>|)""", re.IGNORECASE), # NOT OK - capture groups - re.compile(r"""<(?:(?:!--([\w\W]*?)-->)|(?:!\[CDATA\[([\w\W]*?)\]\]>)|(?:!DOCTYPE([\w\W]*?)>)|(?:\?([^\s\/<>]+) ?([\w\W]*?)[?/]>)|(?:\/([A-Za-z][A-Za-z0-9\-_\:\.]*)>)|(?:([A-Za-z][A-Za-z0-9\-_\:\.]*)((?:\s+[^"'>]+(?:(?:"[^"]*")|(?:'[^']*')|[^>]*))*|\/|\s+)>))"""), # NOT OK - capture groups + re.compile(r"""]*>([\s\S]*?)<\/script>""", re.IGNORECASE | re.DOTALL), # $ Alert # NOT OK - too strict matching on the end tag + re.compile(r"""<(?:!--([\S|\s]*?)-->)|([^\/\s>]+)[\S\s]*?>"""), # $ Alert #// NOT OK - doesn't match comments with the right capture groups + re.compile(r"""<(?:(?:\/([^>]+)>)|(?:!--([\S|\s]*?)-->)|(?:([^\/\s>]+)((?:\s+[\w\-:.]+(?:\s*=\s*?(?:(?:"[^"]*")|(?:'[^']*')|[^\s"'\/>]+))?)*)[\S\s]*?(\/?)>))"""), # $ Alert # NOT OK - capture groups + re.compile(r"""(<[a-z\/!$]("[^"]*"|'[^']*'|[^'">])*>|)""", re.IGNORECASE), # $ Alert # NOT OK - capture groups + re.compile(r"""<(?:(?:!--([\w\W]*?)-->)|(?:!\[CDATA\[([\w\W]*?)\]\]>)|(?:!DOCTYPE([\w\W]*?)>)|(?:\?([^\s\/<>]+) ?([\w\W]*?)[?/]>)|(?:\/([A-Za-z][A-Za-z0-9\-_\:\.]*)>)|(?:([A-Za-z][A-Za-z0-9\-_\:\.]*)((?:\s+[^"'>]+(?:(?:"[^"]*")|(?:'[^']*')|[^>]*))*|\/|\s+)>))"""), # $ Alert # NOT OK - capture groups ] doFilters(filters) diff --git a/python/ql/test/query-tests/Security/CWE-117-LogInjection/LogInjection.expected b/python/ql/test/query-tests/Security/CWE-117-LogInjection/LogInjection.expected index fd9b5fe6bb6..67274311bf4 100644 --- a/python/ql/test/query-tests/Security/CWE-117-LogInjection/LogInjection.expected +++ b/python/ql/test/query-tests/Security/CWE-117-LogInjection/LogInjection.expected @@ -1,3 +1,8 @@ +#select +| LogInjectionBad.py:18:21:18:40 | ControlFlowNode for BinaryExpr | LogInjectionBad.py:7:19:7:25 | ControlFlowNode for ImportMember | LogInjectionBad.py:18:21:18:40 | ControlFlowNode for BinaryExpr | This log entry depends on a $@. | LogInjectionBad.py:7:19:7:25 | ControlFlowNode for ImportMember | user-provided value | +| LogInjectionBad.py:24:18:24:37 | ControlFlowNode for BinaryExpr | LogInjectionBad.py:7:19:7:25 | ControlFlowNode for ImportMember | LogInjectionBad.py:24:18:24:37 | ControlFlowNode for BinaryExpr | This log entry depends on a $@. | LogInjectionBad.py:7:19:7:25 | ControlFlowNode for ImportMember | user-provided value | +| LogInjectionBad.py:30:25:30:44 | ControlFlowNode for BinaryExpr | LogInjectionBad.py:7:19:7:25 | ControlFlowNode for ImportMember | LogInjectionBad.py:30:25:30:44 | ControlFlowNode for BinaryExpr | This log entry depends on a $@. | LogInjectionBad.py:7:19:7:25 | ControlFlowNode for ImportMember | user-provided value | +| LogInjectionBad.py:37:19:37:38 | ControlFlowNode for BinaryExpr | LogInjectionBad.py:7:19:7:25 | ControlFlowNode for ImportMember | LogInjectionBad.py:37:19:37:38 | ControlFlowNode for BinaryExpr | This log entry depends on a $@. | LogInjectionBad.py:7:19:7:25 | ControlFlowNode for ImportMember | user-provided value | edges | LogInjectionBad.py:7:19:7:25 | ControlFlowNode for ImportMember | LogInjectionBad.py:7:19:7:25 | ControlFlowNode for request | provenance | | | LogInjectionBad.py:7:19:7:25 | ControlFlowNode for request | LogInjectionBad.py:17:12:17:18 | ControlFlowNode for request | provenance | | @@ -44,8 +49,3 @@ nodes | LogInjectionBad.py:35:12:35:35 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | | LogInjectionBad.py:37:19:37:38 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | subpaths -#select -| LogInjectionBad.py:18:21:18:40 | ControlFlowNode for BinaryExpr | LogInjectionBad.py:7:19:7:25 | ControlFlowNode for ImportMember | LogInjectionBad.py:18:21:18:40 | ControlFlowNode for BinaryExpr | This log entry depends on a $@. | LogInjectionBad.py:7:19:7:25 | ControlFlowNode for ImportMember | user-provided value | -| LogInjectionBad.py:24:18:24:37 | ControlFlowNode for BinaryExpr | LogInjectionBad.py:7:19:7:25 | ControlFlowNode for ImportMember | LogInjectionBad.py:24:18:24:37 | ControlFlowNode for BinaryExpr | This log entry depends on a $@. | LogInjectionBad.py:7:19:7:25 | ControlFlowNode for ImportMember | user-provided value | -| LogInjectionBad.py:30:25:30:44 | ControlFlowNode for BinaryExpr | LogInjectionBad.py:7:19:7:25 | ControlFlowNode for ImportMember | LogInjectionBad.py:30:25:30:44 | ControlFlowNode for BinaryExpr | This log entry depends on a $@. | LogInjectionBad.py:7:19:7:25 | ControlFlowNode for ImportMember | user-provided value | -| LogInjectionBad.py:37:19:37:38 | ControlFlowNode for BinaryExpr | LogInjectionBad.py:7:19:7:25 | ControlFlowNode for ImportMember | LogInjectionBad.py:37:19:37:38 | ControlFlowNode for BinaryExpr | This log entry depends on a $@. | LogInjectionBad.py:7:19:7:25 | ControlFlowNode for ImportMember | user-provided value | diff --git a/python/ql/test/query-tests/Security/CWE-117-LogInjection/LogInjection.qlref b/python/ql/test/query-tests/Security/CWE-117-LogInjection/LogInjection.qlref index 1837c628c33..fc8a61c453d 100644 --- a/python/ql/test/query-tests/Security/CWE-117-LogInjection/LogInjection.qlref +++ b/python/ql/test/query-tests/Security/CWE-117-LogInjection/LogInjection.qlref @@ -1 +1,2 @@ -Security/CWE-117/LogInjection.ql +query: Security/CWE-117/LogInjection.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Security/CWE-117-LogInjection/LogInjectionBad.py b/python/ql/test/query-tests/Security/CWE-117-LogInjection/LogInjectionBad.py index 0c0cbe1a8fe..e8b4837a4bd 100644 --- a/python/ql/test/query-tests/Security/CWE-117-LogInjection/LogInjectionBad.py +++ b/python/ql/test/query-tests/Security/CWE-117-LogInjection/LogInjectionBad.py @@ -4,7 +4,7 @@ @Desc :Log Injection """ from flask import Flask -from flask import request +from flask import request # $ Source from django.utils.log import request_logger import logging @@ -15,26 +15,26 @@ app = Flask(__name__) @app.route('/bad1') def bad1(): name = request.args.get('name') - app.logger.info('User name: ' + name) # Bad + app.logger.info('User name: ' + name) # $ Alert # Bad return 'bad1' @app.route('/bad2') def bad2(): name = request.args.get('name') - logging.info('User name: ' + name) # Bad + logging.info('User name: ' + name) # $ Alert # Bad return 'bad2' @app.route('/bad3') def bad3(): name = request.args.get('name') - request_logger.warn('User name: ' + name) # Bad + request_logger.warn('User name: ' + name) # $ Alert # Bad return 'bad3' @app.route('/bad4') def bad4(): name = request.args.get('name') logtest = logging.getLogger('test') - logtest.debug('User name: ' + name) # Bad + logtest.debug('User name: ' + name) # $ Alert # Bad return 'bad4' if __name__ == '__main__': diff --git a/python/ql/test/query-tests/Security/CWE-209-StackTraceExposure/StackTraceExposure.qlref b/python/ql/test/query-tests/Security/CWE-209-StackTraceExposure/StackTraceExposure.qlref index 18cf2d49a1a..420481918d1 100644 --- a/python/ql/test/query-tests/Security/CWE-209-StackTraceExposure/StackTraceExposure.qlref +++ b/python/ql/test/query-tests/Security/CWE-209-StackTraceExposure/StackTraceExposure.qlref @@ -1 +1,2 @@ -Security/CWE-209/StackTraceExposure.ql +query: Security/CWE-209/StackTraceExposure.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Security/CWE-209-StackTraceExposure/test.py b/python/ql/test/query-tests/Security/CWE-209-StackTraceExposure/test.py index 96bfba9cf57..dce8d355e20 100644 --- a/python/ql/test/query-tests/Security/CWE-209-StackTraceExposure/test.py +++ b/python/ql/test/query-tests/Security/CWE-209-StackTraceExposure/test.py @@ -13,23 +13,23 @@ def server_bad(): try: do_computation() except Exception: - return traceback.format_exc() # $ exceptionInfo + return traceback.format_exc() # $ Alert exceptionInfo # BAD @app.route('/bad/direct') def server_bad_direct(): try: do_computation() - except Exception as e: # $ exceptionInfo - return e + except Exception as e: # $ Source exceptionInfo + return e # $ Alert # BAD @app.route('/bad/traceback') def server_bad_traceback(): try: do_computation() - except Exception as e: # $ exceptionInfo - return e.__traceback__ + except Exception as e: # $ Source exceptionInfo + return e.__traceback__ # $ Alert # GOOD @app.route('/good') @@ -46,8 +46,8 @@ def server_bad_flow(): try: do_computation() except Exception: - err = traceback.format_exc() # $ exceptionInfo - return format_error(err) + err = traceback.format_exc() # $ Source exceptionInfo + return format_error(err) # $ Alert def format_error(msg): return "[ERROR] " + msg @@ -62,8 +62,8 @@ def maybe_xss(): def bad_jsonify(): try: do_computation() - except Exception as e: # $ exceptionInfo - return jsonify({"error": str(e)}) + except Exception as e: # $ Source exceptionInfo + return jsonify({"error": str(e)}) # $ Alert if __name__ == "__main__": diff --git a/python/ql/test/query-tests/Security/CWE-215-FlaskDebug/FlaskDebug.qlref b/python/ql/test/query-tests/Security/CWE-215-FlaskDebug/FlaskDebug.qlref index 0e21a3ac14f..0fad5641329 100644 --- a/python/ql/test/query-tests/Security/CWE-215-FlaskDebug/FlaskDebug.qlref +++ b/python/ql/test/query-tests/Security/CWE-215-FlaskDebug/FlaskDebug.qlref @@ -1 +1,2 @@ -Security/CWE-215/FlaskDebug.ql +query: Security/CWE-215/FlaskDebug.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Security/CWE-215-FlaskDebug/test.py b/python/ql/test/query-tests/Security/CWE-215-FlaskDebug/test.py index c1d653aab93..b828784994a 100644 --- a/python/ql/test/query-tests/Security/CWE-215-FlaskDebug/test.py +++ b/python/ql/test/query-tests/Security/CWE-215-FlaskDebug/test.py @@ -7,8 +7,8 @@ def main(): raise Exception() # bad -app.run(debug=True) -app.run('host', 8080, True) +app.run(debug=True) # $ Alert +app.run('host', 8080, True) # $ Alert # okay app.run() @@ -23,11 +23,11 @@ app.notrun(debug=True) DEBUG = True -app.run(debug=DEBUG) # NOT OK +app.run(debug=DEBUG) # $ Alert # NOT OK DEBUG = 1 -app.run(debug=DEBUG) # NOT OK +app.run(debug=DEBUG) # $ Alert # NOT OK if False: app.run(debug=True) @@ -35,12 +35,12 @@ if False: runapp = app.run -runapp(debug=True) # NOT OK +runapp(debug=True) # $ Alert # NOT OK # imports from other module import settings -app.run(debug=settings.ALWAYS_TRUE) # NOT OK +app.run(debug=settings.ALWAYS_TRUE) # $ Alert # NOT OK # depending on environment values diff --git a/python/ql/test/query-tests/Security/CWE-285-PamAuthorization/PamAuthorization.qlref b/python/ql/test/query-tests/Security/CWE-285-PamAuthorization/PamAuthorization.qlref index 81915461d7a..de31c362b6c 100644 --- a/python/ql/test/query-tests/Security/CWE-285-PamAuthorization/PamAuthorization.qlref +++ b/python/ql/test/query-tests/Security/CWE-285-PamAuthorization/PamAuthorization.qlref @@ -1 +1,2 @@ -Security/CWE-285/PamAuthorization.ql +query: Security/CWE-285/PamAuthorization.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Security/CWE-285-PamAuthorization/pam_test.py b/python/ql/test/query-tests/Security/CWE-285-PamAuthorization/pam_test.py index f16e3c9941e..364b2a64f7d 100644 --- a/python/ql/test/query-tests/Security/CWE-285-PamAuthorization/pam_test.py +++ b/python/ql/test/query-tests/Security/CWE-285-PamAuthorization/pam_test.py @@ -1,7 +1,7 @@ from ctypes import CDLL, POINTER, Structure, byref from ctypes import c_char_p, c_int from ctypes.util import find_library -from flask import Flask, request, redirect +from flask import Flask, request, redirect # $ Source class PamHandle(Structure): @@ -73,7 +73,7 @@ def bad(): conv = PamConv(None, 0) retval = pam_start(service, username, byref(conv), byref(handle)) - retval = pam_authenticate(handle, 0) + retval = pam_authenticate(handle, 0) # $ Alert # NOT OK: no call to `pam_acct_mgmt` auth_success = retval == 0 diff --git a/python/ql/test/query-tests/Security/CWE-295-MissingHostKeyValidation/MissingHostKeyValidation.qlref b/python/ql/test/query-tests/Security/CWE-295-MissingHostKeyValidation/MissingHostKeyValidation.qlref index c366095516a..5b75b5eea10 100644 --- a/python/ql/test/query-tests/Security/CWE-295-MissingHostKeyValidation/MissingHostKeyValidation.qlref +++ b/python/ql/test/query-tests/Security/CWE-295-MissingHostKeyValidation/MissingHostKeyValidation.qlref @@ -1 +1,2 @@ -Security/CWE-295/MissingHostKeyValidation.ql +query: Security/CWE-295/MissingHostKeyValidation.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Security/CWE-295-MissingHostKeyValidation/paramiko_host_key.py b/python/ql/test/query-tests/Security/CWE-295-MissingHostKeyValidation/paramiko_host_key.py index 3d0a59dcd8f..d41d5e18098 100644 --- a/python/ql/test/query-tests/Security/CWE-295-MissingHostKeyValidation/paramiko_host_key.py +++ b/python/ql/test/query-tests/Security/CWE-295-MissingHostKeyValidation/paramiko_host_key.py @@ -2,19 +2,19 @@ from paramiko.client import AutoAddPolicy, WarningPolicy, RejectPolicy, SSHClien client = SSHClient() -client.set_missing_host_key_policy(AutoAddPolicy) # bad +client.set_missing_host_key_policy(AutoAddPolicy) # $ Alert # bad client.set_missing_host_key_policy(RejectPolicy) # good -client.set_missing_host_key_policy(WarningPolicy) # bad +client.set_missing_host_key_policy(WarningPolicy) # $ Alert # bad # Using instances -client.set_missing_host_key_policy(AutoAddPolicy()) # bad +client.set_missing_host_key_policy(AutoAddPolicy()) # $ Alert # bad client.set_missing_host_key_policy(RejectPolicy()) # good -client.set_missing_host_key_policy(WarningPolicy()) # bad +client.set_missing_host_key_policy(WarningPolicy()) # $ Alert # bad # different import import paramiko client = paramiko.SSHClient() -client.set_missing_host_key_policy(paramiko.AutoAddPolicy) # bad +client.set_missing_host_key_policy(paramiko.AutoAddPolicy) # $ Alert # bad diff --git a/python/ql/test/query-tests/Security/CWE-295-RequestWithoutValidation/RequestWithoutValidation.qlref b/python/ql/test/query-tests/Security/CWE-295-RequestWithoutValidation/RequestWithoutValidation.qlref index 7ad4d4d2ae3..cda6ce83c83 100644 --- a/python/ql/test/query-tests/Security/CWE-295-RequestWithoutValidation/RequestWithoutValidation.qlref +++ b/python/ql/test/query-tests/Security/CWE-295-RequestWithoutValidation/RequestWithoutValidation.qlref @@ -1 +1,2 @@ -Security/CWE-295/RequestWithoutValidation.ql +query: Security/CWE-295/RequestWithoutValidation.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Security/CWE-295-RequestWithoutValidation/make_request.py b/python/ql/test/query-tests/Security/CWE-295-RequestWithoutValidation/make_request.py index 29e857e07b1..8c355cd206e 100644 --- a/python/ql/test/query-tests/Security/CWE-295-RequestWithoutValidation/make_request.py +++ b/python/ql/test/query-tests/Security/CWE-295-RequestWithoutValidation/make_request.py @@ -2,14 +2,14 @@ import requests #Simple cases requests.get('https://semmle.com', verify=True) # GOOD -requests.get('https://semmle.com', verify=False) # BAD +requests.get('https://semmle.com', verify=False) # $ Alert # BAD requests.post('https://semmle.com', verify=True) # GOOD -requests.post('https://semmle.com', verify=False) # BAD +requests.post('https://semmle.com', verify=False) # $ Alert # BAD # Simple flow put = requests.put put('https://semmle.com', verify="/path/to/cert/") # GOOD -put('https://semmle.com', verify=False) # BAD +put('https://semmle.com', verify=False) # $ Alert # BAD #Other flow delete = requests.delete @@ -25,17 +25,17 @@ def req1(verify=False): patch = requests.patch def req2(verify): - patch('https://semmle.com', verify=verify) # BAD (from line 30) + patch('https://semmle.com', verify=verify) # $ Alert # BAD (from line 30) req2(False) # BAD (at line 28) req2("/path/to/cert/") # GOOD #Falsey value -requests.post('https://semmle.com', verify=0) # BAD +requests.post('https://semmle.com', verify=0) # $ Alert # BAD # requests treat `None` as default value, which means it is turned on requests.get('https://semmle.com') # OK requests.get('https://semmle.com', verify=None) # OK s = requests.Session() -s.get("url", verify=False) # BAD +s.get("url", verify=False) # $ Alert # BAD diff --git a/python/ql/test/query-tests/Security/CWE-312-CleartextLogging/CleartextLogging.expected b/python/ql/test/query-tests/Security/CWE-312-CleartextLogging/CleartextLogging.expected index 5da1b60eee1..47f27dbc5f2 100644 --- a/python/ql/test/query-tests/Security/CWE-312-CleartextLogging/CleartextLogging.expected +++ b/python/ql/test/query-tests/Security/CWE-312-CleartextLogging/CleartextLogging.expected @@ -1,3 +1,28 @@ +#select +| test.py:20:48:20:55 | ControlFlowNode for password | test.py:19:16:19:29 | ControlFlowNode for get_password() | test.py:20:48:20:55 | ControlFlowNode for password | This expression logs $@ as clear text. | test.py:19:16:19:29 | ControlFlowNode for get_password() | sensitive data (password) | +| test.py:22:58:22:65 | ControlFlowNode for password | test.py:19:16:19:29 | ControlFlowNode for get_password() | test.py:22:58:22:65 | ControlFlowNode for password | This expression logs $@ as clear text. | test.py:19:16:19:29 | ControlFlowNode for get_password() | sensitive data (password) | +| test.py:23:58:23:65 | ControlFlowNode for password | test.py:19:16:19:29 | ControlFlowNode for get_password() | test.py:23:58:23:65 | ControlFlowNode for password | This expression logs $@ as clear text. | test.py:19:16:19:29 | ControlFlowNode for get_password() | sensitive data (password) | +| test.py:27:40:27:47 | ControlFlowNode for password | test.py:19:16:19:29 | ControlFlowNode for get_password() | test.py:27:40:27:47 | ControlFlowNode for password | This expression logs $@ as clear text. | test.py:19:16:19:29 | ControlFlowNode for get_password() | sensitive data (password) | +| test.py:30:58:30:65 | ControlFlowNode for password | test.py:19:16:19:29 | ControlFlowNode for get_password() | test.py:30:58:30:65 | ControlFlowNode for password | This expression logs $@ as clear text. | test.py:19:16:19:29 | ControlFlowNode for get_password() | sensitive data (password) | +| test.py:37:11:37:24 | ControlFlowNode for get_password() | test.py:37:11:37:24 | ControlFlowNode for get_password() | test.py:37:11:37:24 | ControlFlowNode for get_password() | This expression logs $@ as clear text. | test.py:37:11:37:24 | ControlFlowNode for get_password() | sensitive data (password) | +| test.py:39:22:39:35 | ControlFlowNode for get_password() | test.py:39:22:39:35 | ControlFlowNode for get_password() | test.py:39:22:39:35 | ControlFlowNode for get_password() | This expression logs $@ as clear text. | test.py:39:22:39:35 | ControlFlowNode for get_password() | sensitive data (password) | +| test.py:40:22:40:35 | ControlFlowNode for get_password() | test.py:40:22:40:35 | ControlFlowNode for get_password() | test.py:40:22:40:35 | ControlFlowNode for get_password() | This expression logs $@ as clear text. | test.py:40:22:40:35 | ControlFlowNode for get_password() | sensitive data (password) | +| test.py:45:11:45:11 | ControlFlowNode for x | test.py:44:9:44:25 | ControlFlowNode for Attribute() | test.py:45:11:45:11 | ControlFlowNode for x | This expression logs $@ as clear text. | test.py:44:9:44:25 | ControlFlowNode for Attribute() | sensitive data (password) | +| test.py:49:15:49:36 | ControlFlowNode for social_security_number | test.py:48:14:48:35 | ControlFlowNode for social_security_number | test.py:49:15:49:36 | ControlFlowNode for social_security_number | This expression logs $@ as clear text. | test.py:48:14:48:35 | ControlFlowNode for social_security_number | sensitive data (private) | +| test.py:50:15:50:17 | ControlFlowNode for ssn | test.py:48:38:48:40 | ControlFlowNode for ssn | test.py:50:15:50:17 | ControlFlowNode for ssn | This expression logs $@ as clear text. | test.py:48:38:48:40 | ControlFlowNode for ssn | sensitive data (private) | +| test.py:52:15:52:24 | ControlFlowNode for passportNo | test.py:48:54:48:63 | ControlFlowNode for passportNo | test.py:52:15:52:24 | ControlFlowNode for passportNo | This expression logs $@ as clear text. | test.py:48:54:48:63 | ControlFlowNode for passportNo | sensitive data (private) | +| test.py:55:15:55:23 | ControlFlowNode for post_code | test.py:54:14:54:22 | ControlFlowNode for post_code | test.py:55:15:55:23 | ControlFlowNode for post_code | This expression logs $@ as clear text. | test.py:54:14:54:22 | ControlFlowNode for post_code | sensitive data (private) | +| test.py:56:15:56:21 | ControlFlowNode for zipCode | test.py:54:25:54:31 | ControlFlowNode for zipCode | test.py:56:15:56:21 | ControlFlowNode for zipCode | This expression logs $@ as clear text. | test.py:54:25:54:31 | ControlFlowNode for zipCode | sensitive data (private) | +| test.py:57:15:57:26 | ControlFlowNode for home_address | test.py:54:34:54:45 | ControlFlowNode for home_address | test.py:57:15:57:26 | ControlFlowNode for home_address | This expression logs $@ as clear text. | test.py:54:34:54:45 | ControlFlowNode for home_address | sensitive data (private) | +| test.py:60:15:60:27 | ControlFlowNode for user_latitude | test.py:59:14:59:26 | ControlFlowNode for user_latitude | test.py:60:15:60:27 | ControlFlowNode for user_latitude | This expression logs $@ as clear text. | test.py:59:14:59:26 | ControlFlowNode for user_latitude | sensitive data (private) | +| test.py:61:15:61:28 | ControlFlowNode for user_longitude | test.py:59:29:59:42 | ControlFlowNode for user_longitude | test.py:61:15:61:28 | ControlFlowNode for user_longitude | This expression logs $@ as clear text. | test.py:59:29:59:42 | ControlFlowNode for user_longitude | sensitive data (private) | +| test.py:64:15:64:27 | ControlFlowNode for mobile_number | test.py:63:14:63:26 | ControlFlowNode for mobile_number | test.py:64:15:64:27 | ControlFlowNode for mobile_number | This expression logs $@ as clear text. | test.py:63:14:63:26 | ControlFlowNode for mobile_number | sensitive data (private) | +| test.py:65:15:65:21 | ControlFlowNode for phoneNo | test.py:63:29:63:35 | ControlFlowNode for phoneNo | test.py:65:15:65:21 | ControlFlowNode for phoneNo | This expression logs $@ as clear text. | test.py:63:29:63:35 | ControlFlowNode for phoneNo | sensitive data (private) | +| test.py:68:15:68:24 | ControlFlowNode for creditcard | test.py:67:14:67:23 | ControlFlowNode for creditcard | test.py:68:15:68:24 | ControlFlowNode for creditcard | This expression logs $@ as clear text. | test.py:67:14:67:23 | ControlFlowNode for creditcard | sensitive data (private) | +| test.py:69:15:69:24 | ControlFlowNode for debit_card | test.py:67:26:67:35 | ControlFlowNode for debit_card | test.py:69:15:69:24 | ControlFlowNode for debit_card | This expression logs $@ as clear text. | test.py:67:26:67:35 | ControlFlowNode for debit_card | sensitive data (private) | +| test.py:70:15:70:25 | ControlFlowNode for bank_number | test.py:67:38:67:48 | ControlFlowNode for bank_number | test.py:70:15:70:25 | ControlFlowNode for bank_number | This expression logs $@ as clear text. | test.py:67:38:67:48 | ControlFlowNode for bank_number | sensitive data (private) | +| test.py:73:15:73:17 | ControlFlowNode for ccn | test.py:67:76:67:78 | ControlFlowNode for ccn | test.py:73:15:73:17 | ControlFlowNode for ccn | This expression logs $@ as clear text. | test.py:67:76:67:78 | ControlFlowNode for ccn | sensitive data (private) | +| test.py:74:15:74:22 | ControlFlowNode for user_ccn | test.py:67:81:67:88 | ControlFlowNode for user_ccn | test.py:74:15:74:22 | ControlFlowNode for user_ccn | This expression logs $@ as clear text. | test.py:67:81:67:88 | ControlFlowNode for user_ccn | sensitive data (private) | edges | test.py:19:5:19:12 | ControlFlowNode for password | test.py:20:48:20:55 | ControlFlowNode for password | provenance | | | test.py:19:5:19:12 | ControlFlowNode for password | test.py:22:58:22:65 | ControlFlowNode for password | provenance | | @@ -67,28 +92,3 @@ nodes | test.py:73:15:73:17 | ControlFlowNode for ccn | semmle.label | ControlFlowNode for ccn | | test.py:74:15:74:22 | ControlFlowNode for user_ccn | semmle.label | ControlFlowNode for user_ccn | subpaths -#select -| test.py:20:48:20:55 | ControlFlowNode for password | test.py:19:16:19:29 | ControlFlowNode for get_password() | test.py:20:48:20:55 | ControlFlowNode for password | This expression logs $@ as clear text. | test.py:19:16:19:29 | ControlFlowNode for get_password() | sensitive data (password) | -| test.py:22:58:22:65 | ControlFlowNode for password | test.py:19:16:19:29 | ControlFlowNode for get_password() | test.py:22:58:22:65 | ControlFlowNode for password | This expression logs $@ as clear text. | test.py:19:16:19:29 | ControlFlowNode for get_password() | sensitive data (password) | -| test.py:23:58:23:65 | ControlFlowNode for password | test.py:19:16:19:29 | ControlFlowNode for get_password() | test.py:23:58:23:65 | ControlFlowNode for password | This expression logs $@ as clear text. | test.py:19:16:19:29 | ControlFlowNode for get_password() | sensitive data (password) | -| test.py:27:40:27:47 | ControlFlowNode for password | test.py:19:16:19:29 | ControlFlowNode for get_password() | test.py:27:40:27:47 | ControlFlowNode for password | This expression logs $@ as clear text. | test.py:19:16:19:29 | ControlFlowNode for get_password() | sensitive data (password) | -| test.py:30:58:30:65 | ControlFlowNode for password | test.py:19:16:19:29 | ControlFlowNode for get_password() | test.py:30:58:30:65 | ControlFlowNode for password | This expression logs $@ as clear text. | test.py:19:16:19:29 | ControlFlowNode for get_password() | sensitive data (password) | -| test.py:37:11:37:24 | ControlFlowNode for get_password() | test.py:37:11:37:24 | ControlFlowNode for get_password() | test.py:37:11:37:24 | ControlFlowNode for get_password() | This expression logs $@ as clear text. | test.py:37:11:37:24 | ControlFlowNode for get_password() | sensitive data (password) | -| test.py:39:22:39:35 | ControlFlowNode for get_password() | test.py:39:22:39:35 | ControlFlowNode for get_password() | test.py:39:22:39:35 | ControlFlowNode for get_password() | This expression logs $@ as clear text. | test.py:39:22:39:35 | ControlFlowNode for get_password() | sensitive data (password) | -| test.py:40:22:40:35 | ControlFlowNode for get_password() | test.py:40:22:40:35 | ControlFlowNode for get_password() | test.py:40:22:40:35 | ControlFlowNode for get_password() | This expression logs $@ as clear text. | test.py:40:22:40:35 | ControlFlowNode for get_password() | sensitive data (password) | -| test.py:45:11:45:11 | ControlFlowNode for x | test.py:44:9:44:25 | ControlFlowNode for Attribute() | test.py:45:11:45:11 | ControlFlowNode for x | This expression logs $@ as clear text. | test.py:44:9:44:25 | ControlFlowNode for Attribute() | sensitive data (password) | -| test.py:49:15:49:36 | ControlFlowNode for social_security_number | test.py:48:14:48:35 | ControlFlowNode for social_security_number | test.py:49:15:49:36 | ControlFlowNode for social_security_number | This expression logs $@ as clear text. | test.py:48:14:48:35 | ControlFlowNode for social_security_number | sensitive data (private) | -| test.py:50:15:50:17 | ControlFlowNode for ssn | test.py:48:38:48:40 | ControlFlowNode for ssn | test.py:50:15:50:17 | ControlFlowNode for ssn | This expression logs $@ as clear text. | test.py:48:38:48:40 | ControlFlowNode for ssn | sensitive data (private) | -| test.py:52:15:52:24 | ControlFlowNode for passportNo | test.py:48:54:48:63 | ControlFlowNode for passportNo | test.py:52:15:52:24 | ControlFlowNode for passportNo | This expression logs $@ as clear text. | test.py:48:54:48:63 | ControlFlowNode for passportNo | sensitive data (private) | -| test.py:55:15:55:23 | ControlFlowNode for post_code | test.py:54:14:54:22 | ControlFlowNode for post_code | test.py:55:15:55:23 | ControlFlowNode for post_code | This expression logs $@ as clear text. | test.py:54:14:54:22 | ControlFlowNode for post_code | sensitive data (private) | -| test.py:56:15:56:21 | ControlFlowNode for zipCode | test.py:54:25:54:31 | ControlFlowNode for zipCode | test.py:56:15:56:21 | ControlFlowNode for zipCode | This expression logs $@ as clear text. | test.py:54:25:54:31 | ControlFlowNode for zipCode | sensitive data (private) | -| test.py:57:15:57:26 | ControlFlowNode for home_address | test.py:54:34:54:45 | ControlFlowNode for home_address | test.py:57:15:57:26 | ControlFlowNode for home_address | This expression logs $@ as clear text. | test.py:54:34:54:45 | ControlFlowNode for home_address | sensitive data (private) | -| test.py:60:15:60:27 | ControlFlowNode for user_latitude | test.py:59:14:59:26 | ControlFlowNode for user_latitude | test.py:60:15:60:27 | ControlFlowNode for user_latitude | This expression logs $@ as clear text. | test.py:59:14:59:26 | ControlFlowNode for user_latitude | sensitive data (private) | -| test.py:61:15:61:28 | ControlFlowNode for user_longitude | test.py:59:29:59:42 | ControlFlowNode for user_longitude | test.py:61:15:61:28 | ControlFlowNode for user_longitude | This expression logs $@ as clear text. | test.py:59:29:59:42 | ControlFlowNode for user_longitude | sensitive data (private) | -| test.py:64:15:64:27 | ControlFlowNode for mobile_number | test.py:63:14:63:26 | ControlFlowNode for mobile_number | test.py:64:15:64:27 | ControlFlowNode for mobile_number | This expression logs $@ as clear text. | test.py:63:14:63:26 | ControlFlowNode for mobile_number | sensitive data (private) | -| test.py:65:15:65:21 | ControlFlowNode for phoneNo | test.py:63:29:63:35 | ControlFlowNode for phoneNo | test.py:65:15:65:21 | ControlFlowNode for phoneNo | This expression logs $@ as clear text. | test.py:63:29:63:35 | ControlFlowNode for phoneNo | sensitive data (private) | -| test.py:68:15:68:24 | ControlFlowNode for creditcard | test.py:67:14:67:23 | ControlFlowNode for creditcard | test.py:68:15:68:24 | ControlFlowNode for creditcard | This expression logs $@ as clear text. | test.py:67:14:67:23 | ControlFlowNode for creditcard | sensitive data (private) | -| test.py:69:15:69:24 | ControlFlowNode for debit_card | test.py:67:26:67:35 | ControlFlowNode for debit_card | test.py:69:15:69:24 | ControlFlowNode for debit_card | This expression logs $@ as clear text. | test.py:67:26:67:35 | ControlFlowNode for debit_card | sensitive data (private) | -| test.py:70:15:70:25 | ControlFlowNode for bank_number | test.py:67:38:67:48 | ControlFlowNode for bank_number | test.py:70:15:70:25 | ControlFlowNode for bank_number | This expression logs $@ as clear text. | test.py:67:38:67:48 | ControlFlowNode for bank_number | sensitive data (private) | -| test.py:73:15:73:17 | ControlFlowNode for ccn | test.py:67:76:67:78 | ControlFlowNode for ccn | test.py:73:15:73:17 | ControlFlowNode for ccn | This expression logs $@ as clear text. | test.py:67:76:67:78 | ControlFlowNode for ccn | sensitive data (private) | -| test.py:74:15:74:22 | ControlFlowNode for user_ccn | test.py:67:81:67:88 | ControlFlowNode for user_ccn | test.py:74:15:74:22 | ControlFlowNode for user_ccn | This expression logs $@ as clear text. | test.py:67:81:67:88 | ControlFlowNode for user_ccn | sensitive data (private) | diff --git a/python/ql/test/query-tests/Security/CWE-312-CleartextLogging/CleartextLogging.qlref b/python/ql/test/query-tests/Security/CWE-312-CleartextLogging/CleartextLogging.qlref index de9273391c8..2309f8c643a 100644 --- a/python/ql/test/query-tests/Security/CWE-312-CleartextLogging/CleartextLogging.qlref +++ b/python/ql/test/query-tests/Security/CWE-312-CleartextLogging/CleartextLogging.qlref @@ -1 +1,2 @@ -Security/CWE-312/CleartextLogging.ql \ No newline at end of file +query: Security/CWE-312/CleartextLogging.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Security/CWE-312-CleartextLogging/test.py b/python/ql/test/query-tests/Security/CWE-312-CleartextLogging/test.py index ff01680ed81..a4c595fbaf9 100644 --- a/python/ql/test/query-tests/Security/CWE-312-CleartextLogging/test.py +++ b/python/ql/test/query-tests/Security/CWE-312-CleartextLogging/test.py @@ -16,62 +16,62 @@ def get_cert(): def log_password(): - password = get_password() - logging.info("logging.info Password '%s'", password) # NOT OK + password = get_password() # $ Source + logging.info("logging.info Password '%s'", password) # $ Alert # NOT OK - LOGGER.log(logging.INFO, "LOGGER.log Password '%s'", password) # NOT OK - logging.root.info("logging.root.info Password '%s'", password) # NOT OK + LOGGER.log(logging.INFO, "LOGGER.log Password '%s'", password) # $ Alert # NOT OK + logging.root.info("logging.root.info Password '%s'", password) # $ Alert # NOT OK # name of logger variable should not matter foo = LOGGER - foo.info("foo.info Password '%s'", password) # NOT OK + foo.info("foo.info Password '%s'", password) # $ Alert # NOT OK # return value from function - get_logger().info("get_logger().info Password '%s'", password) # NOT OK + get_logger().info("get_logger().info Password '%s'", password) # $ Alert # NOT OK def log_cert(): logging.debug("Cert=%s", get_cert()) # OK def print_password(): - print(get_password()) # NOT OK + print(get_password()) # $ Alert # NOT OK - sys.stdout.write(get_password()) # NOT OK - sys.stderr.write(get_password()) # NOT OK + sys.stdout.write(get_password()) # $ Alert # NOT OK + sys.stderr.write(get_password()) # $ Alert # NOT OK import getpass - x = getpass.getpass() - print(x) # NOT OK + x = getpass.getpass() # $ Source + print(x) # $ Alert # NOT OK def log_private(): - def log1(social_security_number, ssn, className, passportNo): - print(social_security_number) # NOT OK - print(ssn) # NOT OK + def log1(social_security_number, ssn, className, passportNo): # $ Source + print(social_security_number) # $ Alert # NOT OK + print(ssn) # $ Alert # NOT OK print(className) # OK - print(passportNo) # NOT OK + print(passportNo) # $ Alert # NOT OK - def log2(post_code, zipCode, home_address): - print(post_code) # NOT OK - print(zipCode) # NOT OK - print(home_address) # NOT OK + def log2(post_code, zipCode, home_address): # $ Source + print(post_code) # $ Alert # NOT OK + print(zipCode) # $ Alert # NOT OK + print(home_address) # $ Alert # NOT OK - def log3(user_latitude, user_longitude): - print(user_latitude) # NOT OK - print(user_longitude) # NOT OK + def log3(user_latitude, user_longitude): # $ Source + print(user_latitude) # $ Alert # NOT OK + print(user_longitude) # $ Alert # NOT OK - def log4(mobile_number, phoneNo): - print(mobile_number) # NOT OK - print(phoneNo) # NOT OK + def log4(mobile_number, phoneNo): # $ Source + print(mobile_number) # $ Alert # NOT OK + print(phoneNo) # $ Alert # NOT OK - def log5(creditcard, debit_card, bank_number, bank_account, accountNo, ccn, user_ccn, succNode): - print(creditcard) # NOT OK - print(debit_card) # NOT OK - print(bank_number) # NOT OK - print(bank_account) # NOT OK, but NOT FOUND - "account" is treated as having the "id" classification and thus excluded. - print(accountNo) # NOT OK, but NOT FOUND - "account" is treated as having the "id" classification and thus excluded. - print(ccn) # NOT OK - print(user_ccn) # NOT OK + def log5(creditcard, debit_card, bank_number, bank_account, accountNo, ccn, user_ccn, succNode): # $ Source + print(creditcard) # $ Alert # NOT OK + print(debit_card) # $ Alert # NOT OK + print(bank_number) # $ Alert # NOT OK + print(bank_account) # $ MISSING: Alert # NOT OK, but NOT FOUND - "account" is treated as having the "id" classification and thus excluded. + print(accountNo) # $ MISSING: Alert # NOT OK, but NOT FOUND - "account" is treated as having the "id" classification and thus excluded. + print(ccn) # $ Alert # NOT OK + print(user_ccn) # $ Alert # NOT OK print(succNode) # OK diff --git a/python/ql/test/query-tests/Security/CWE-312-CleartextStorage-py3/CleartextStorage.expected b/python/ql/test/query-tests/Security/CWE-312-CleartextStorage-py3/CleartextStorage.expected index 588cfae32ef..66c192b89e0 100644 --- a/python/ql/test/query-tests/Security/CWE-312-CleartextStorage-py3/CleartextStorage.expected +++ b/python/ql/test/query-tests/Security/CWE-312-CleartextStorage-py3/CleartextStorage.expected @@ -1,3 +1,7 @@ +#select +| test.py:12:21:12:28 | ControlFlowNode for password | test.py:9:16:9:29 | ControlFlowNode for get_password() | test.py:12:21:12:28 | ControlFlowNode for password | This expression stores $@ as clear text. | test.py:9:16:9:29 | ControlFlowNode for get_password() | sensitive data (password) | +| test.py:13:22:13:45 | ControlFlowNode for Attribute() | test.py:9:16:9:29 | ControlFlowNode for get_password() | test.py:13:22:13:45 | ControlFlowNode for Attribute() | This expression stores $@ as clear text. | test.py:9:16:9:29 | ControlFlowNode for get_password() | sensitive data (password) | +| test.py:15:26:15:33 | ControlFlowNode for password | test.py:9:16:9:29 | ControlFlowNode for get_password() | test.py:15:26:15:33 | ControlFlowNode for password | This expression stores $@ as clear text. | test.py:9:16:9:29 | ControlFlowNode for get_password() | sensitive data (password) | edges | test.py:9:5:9:12 | ControlFlowNode for password | test.py:12:21:12:28 | ControlFlowNode for password | provenance | | | test.py:9:5:9:12 | ControlFlowNode for password | test.py:13:22:13:45 | ControlFlowNode for Attribute() | provenance | | @@ -10,7 +14,3 @@ nodes | test.py:13:22:13:45 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | | test.py:15:26:15:33 | ControlFlowNode for password | semmle.label | ControlFlowNode for password | subpaths -#select -| test.py:12:21:12:28 | ControlFlowNode for password | test.py:9:16:9:29 | ControlFlowNode for get_password() | test.py:12:21:12:28 | ControlFlowNode for password | This expression stores $@ as clear text. | test.py:9:16:9:29 | ControlFlowNode for get_password() | sensitive data (password) | -| test.py:13:22:13:45 | ControlFlowNode for Attribute() | test.py:9:16:9:29 | ControlFlowNode for get_password() | test.py:13:22:13:45 | ControlFlowNode for Attribute() | This expression stores $@ as clear text. | test.py:9:16:9:29 | ControlFlowNode for get_password() | sensitive data (password) | -| test.py:15:26:15:33 | ControlFlowNode for password | test.py:9:16:9:29 | ControlFlowNode for get_password() | test.py:15:26:15:33 | ControlFlowNode for password | This expression stores $@ as clear text. | test.py:9:16:9:29 | ControlFlowNode for get_password() | sensitive data (password) | diff --git a/python/ql/test/query-tests/Security/CWE-312-CleartextStorage-py3/CleartextStorage.qlref b/python/ql/test/query-tests/Security/CWE-312-CleartextStorage-py3/CleartextStorage.qlref index a32206e8d6a..a39c1b1c4ef 100644 --- a/python/ql/test/query-tests/Security/CWE-312-CleartextStorage-py3/CleartextStorage.qlref +++ b/python/ql/test/query-tests/Security/CWE-312-CleartextStorage-py3/CleartextStorage.qlref @@ -1 +1,2 @@ -Security/CWE-312/CleartextStorage.ql \ No newline at end of file +query: Security/CWE-312/CleartextStorage.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Security/CWE-312-CleartextStorage-py3/test.py b/python/ql/test/query-tests/Security/CWE-312-CleartextStorage-py3/test.py index 91b7fb7e6c2..a433f7dc85c 100644 --- a/python/ql/test/query-tests/Security/CWE-312-CleartextStorage-py3/test.py +++ b/python/ql/test/query-tests/Security/CWE-312-CleartextStorage-py3/test.py @@ -6,10 +6,10 @@ def get_password(): def write_password(filename): - password = get_password() + password = get_password() # $ Source path = pathlib.Path(filename) - path.write_text(password) # NOT OK - path.write_bytes(password.encode("utf-8")) # NOT OK + path.write_text(password) # $ Alert # NOT OK + path.write_bytes(password.encode("utf-8")) # $ Alert # NOT OK - path.open("w").write(password) # NOT OK + path.open("w").write(password) # $ Alert # NOT OK diff --git a/python/ql/test/query-tests/Security/CWE-312-CleartextStorage/CleartextStorage.expected b/python/ql/test/query-tests/Security/CWE-312-CleartextStorage/CleartextStorage.expected index ea41c1ba651..ed748c70df3 100644 --- a/python/ql/test/query-tests/Security/CWE-312-CleartextStorage/CleartextStorage.expected +++ b/python/ql/test/query-tests/Security/CWE-312-CleartextStorage/CleartextStorage.expected @@ -1,3 +1,8 @@ +#select +| password_in_cookie.py:9:33:9:40 | ControlFlowNode for password | password_in_cookie.py:7:16:7:43 | ControlFlowNode for Attribute() | password_in_cookie.py:9:33:9:40 | ControlFlowNode for password | This expression stores $@ as clear text. | password_in_cookie.py:7:16:7:43 | ControlFlowNode for Attribute() | sensitive data (password) | +| password_in_cookie.py:16:33:16:40 | ControlFlowNode for password | password_in_cookie.py:14:16:14:43 | ControlFlowNode for Attribute() | password_in_cookie.py:16:33:16:40 | ControlFlowNode for password | This expression stores $@ as clear text. | password_in_cookie.py:14:16:14:43 | ControlFlowNode for Attribute() | sensitive data (password) | +| test.py:17:20:17:27 | ControlFlowNode for password | test.py:15:16:15:29 | ControlFlowNode for get_password() | test.py:17:20:17:27 | ControlFlowNode for password | This expression stores $@ as clear text. | test.py:15:16:15:29 | ControlFlowNode for get_password() | sensitive data (password) | +| test.py:19:25:19:29 | ControlFlowNode for lines | test.py:15:16:15:29 | ControlFlowNode for get_password() | test.py:19:25:19:29 | ControlFlowNode for lines | This expression stores $@ as clear text. | test.py:15:16:15:29 | ControlFlowNode for get_password() | sensitive data (password) | edges | password_in_cookie.py:7:5:7:12 | ControlFlowNode for password | password_in_cookie.py:9:33:9:40 | ControlFlowNode for password | provenance | | | password_in_cookie.py:7:16:7:43 | ControlFlowNode for Attribute() | password_in_cookie.py:7:5:7:12 | ControlFlowNode for password | provenance | | @@ -24,8 +29,3 @@ nodes | test.py:18:18:18:32 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | | test.py:19:25:19:29 | ControlFlowNode for lines | semmle.label | ControlFlowNode for lines | subpaths -#select -| password_in_cookie.py:9:33:9:40 | ControlFlowNode for password | password_in_cookie.py:7:16:7:43 | ControlFlowNode for Attribute() | password_in_cookie.py:9:33:9:40 | ControlFlowNode for password | This expression stores $@ as clear text. | password_in_cookie.py:7:16:7:43 | ControlFlowNode for Attribute() | sensitive data (password) | -| password_in_cookie.py:16:33:16:40 | ControlFlowNode for password | password_in_cookie.py:14:16:14:43 | ControlFlowNode for Attribute() | password_in_cookie.py:16:33:16:40 | ControlFlowNode for password | This expression stores $@ as clear text. | password_in_cookie.py:14:16:14:43 | ControlFlowNode for Attribute() | sensitive data (password) | -| test.py:17:20:17:27 | ControlFlowNode for password | test.py:15:16:15:29 | ControlFlowNode for get_password() | test.py:17:20:17:27 | ControlFlowNode for password | This expression stores $@ as clear text. | test.py:15:16:15:29 | ControlFlowNode for get_password() | sensitive data (password) | -| test.py:19:25:19:29 | ControlFlowNode for lines | test.py:15:16:15:29 | ControlFlowNode for get_password() | test.py:19:25:19:29 | ControlFlowNode for lines | This expression stores $@ as clear text. | test.py:15:16:15:29 | ControlFlowNode for get_password() | sensitive data (password) | diff --git a/python/ql/test/query-tests/Security/CWE-312-CleartextStorage/CleartextStorage.qlref b/python/ql/test/query-tests/Security/CWE-312-CleartextStorage/CleartextStorage.qlref index a32206e8d6a..a39c1b1c4ef 100644 --- a/python/ql/test/query-tests/Security/CWE-312-CleartextStorage/CleartextStorage.qlref +++ b/python/ql/test/query-tests/Security/CWE-312-CleartextStorage/CleartextStorage.qlref @@ -1 +1,2 @@ -Security/CWE-312/CleartextStorage.ql \ No newline at end of file +query: Security/CWE-312/CleartextStorage.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Security/CWE-312-CleartextStorage/password_in_cookie.py b/python/ql/test/query-tests/Security/CWE-312-CleartextStorage/password_in_cookie.py index 2688c13dace..c85405f3860 100644 --- a/python/ql/test/query-tests/Security/CWE-312-CleartextStorage/password_in_cookie.py +++ b/python/ql/test/query-tests/Security/CWE-312-CleartextStorage/password_in_cookie.py @@ -4,14 +4,14 @@ app = Flask("Leak password") @app.route('/') def index(): - password = request.args.get("password") + password = request.args.get("password") # $ Source resp = make_response(render_template(...)) - resp.set_cookie("password", password) # NOT OK + resp.set_cookie("password", password) # $ Alert # NOT OK return resp @app.route('/') def index2(): - password = request.args.get("password") + password = request.args.get("password") # $ Source resp = Response(...) - resp.set_cookie("password", password) # NOT OK + resp.set_cookie("password", password) # $ Alert # NOT OK return resp diff --git a/python/ql/test/query-tests/Security/CWE-312-CleartextStorage/test.py b/python/ql/test/query-tests/Security/CWE-312-CleartextStorage/test.py index 6d04aa4b170..58613efd4b2 100644 --- a/python/ql/test/query-tests/Security/CWE-312-CleartextStorage/test.py +++ b/python/ql/test/query-tests/Security/CWE-312-CleartextStorage/test.py @@ -12,11 +12,11 @@ def write_cert(filename): file.writelines(lines) # OK def write_password(filename): - password = get_password() + password = get_password() # $ Source with open(filename, "w") as file: - file.write(password) # NOT OK + file.write(password) # $ Alert # NOT OK lines = [password + "\n"] - file.writelines(lines) # NOT OK + file.writelines(lines) # $ Alert # NOT OK def FPs(): # just like for cleartext-logging see that file for more elaborate tests diff --git a/python/ql/test/query-tests/Security/CWE-326-WeakCryptoKey/WeakCryptoKey.qlref b/python/ql/test/query-tests/Security/CWE-326-WeakCryptoKey/WeakCryptoKey.qlref index 70a66eef06e..3ee942673d3 100644 --- a/python/ql/test/query-tests/Security/CWE-326-WeakCryptoKey/WeakCryptoKey.qlref +++ b/python/ql/test/query-tests/Security/CWE-326-WeakCryptoKey/WeakCryptoKey.qlref @@ -1 +1,2 @@ -Security/CWE-326/WeakCryptoKey.ql +query: Security/CWE-326/WeakCryptoKey.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Security/CWE-326-WeakCryptoKey/weak_crypto.py b/python/ql/test/query-tests/Security/CWE-326-WeakCryptoKey/weak_crypto.py index 5ec929c7d09..87ed42d12bf 100644 --- a/python/ql/test/query-tests/Security/CWE-326-WeakCryptoKey/weak_crypto.py +++ b/python/ql/test/query-tests/Security/CWE-326-WeakCryptoKey/weak_crypto.py @@ -65,23 +65,23 @@ RSA.generate(RSA_STRONG) # Weak keys -dsa_gen_key(DSA_WEAK) -ec_gen_key(EC_WEAK) -rsa_gen_key(65537, RSA_WEAK) +dsa_gen_key(DSA_WEAK) # $ Alert +ec_gen_key(EC_WEAK) # $ Alert +rsa_gen_key(65537, RSA_WEAK) # $ Alert -dsa_gen_key(key_size=DSA_WEAK) -ec_gen_key(curve=EC_WEAK) -rsa_gen_key(65537, key_size=RSA_WEAK) +dsa_gen_key(key_size=DSA_WEAK) # $ Alert +ec_gen_key(curve=EC_WEAK) # $ Alert +rsa_gen_key(65537, key_size=RSA_WEAK) # $ Alert -DSA.generate(DSA_WEAK) -RSA.generate(RSA_WEAK) +DSA.generate(DSA_WEAK) # $ Alert +RSA.generate(RSA_WEAK) # $ Alert # ------------------------------------------------------------------------------ # Through function calls def make_new_rsa_key_weak(bits): - return RSA.generate(bits) # NOT OK + return RSA.generate(bits) # $ Alert # NOT OK make_new_rsa_key_weak(RSA_WEAK) diff --git a/python/ql/test/query-tests/Security/CWE-327-BrokenCryptoAlgorithm/BrokenCryptoAlgorithm.qlref b/python/ql/test/query-tests/Security/CWE-327-BrokenCryptoAlgorithm/BrokenCryptoAlgorithm.qlref index 3f7aff53700..81a5bd0ae94 100644 --- a/python/ql/test/query-tests/Security/CWE-327-BrokenCryptoAlgorithm/BrokenCryptoAlgorithm.qlref +++ b/python/ql/test/query-tests/Security/CWE-327-BrokenCryptoAlgorithm/BrokenCryptoAlgorithm.qlref @@ -1 +1,2 @@ -Security/CWE-327/BrokenCryptoAlgorithm.ql +query: Security/CWE-327/BrokenCryptoAlgorithm.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Security/CWE-327-BrokenCryptoAlgorithm/test_cryptodome.py b/python/ql/test/query-tests/Security/CWE-327-BrokenCryptoAlgorithm/test_cryptodome.py index 16482054eb2..6735f21ccd6 100644 --- a/python/ql/test/query-tests/Security/CWE-327-BrokenCryptoAlgorithm/test_cryptodome.py +++ b/python/ql/test/query-tests/Security/CWE-327-BrokenCryptoAlgorithm/test_cryptodome.py @@ -8,11 +8,11 @@ key = os.urandom(256//8) secret_message = b"secret message" cipher = ARC4.new(key) -encrypted = cipher.encrypt(secret_message) # NOT OK +encrypted = cipher.encrypt(secret_message) # $ Alert # NOT OK print(secret_message, encrypted) cipher = AES.new(key, AES.MODE_ECB) -encrypted = cipher.encrypt(secret_message) # NOT OK +encrypted = cipher.encrypt(secret_message) # $ Alert # NOT OK print(secret_message, encrypted) diff --git a/python/ql/test/query-tests/Security/CWE-327-BrokenCryptoAlgorithm/test_cryptography.py b/python/ql/test/query-tests/Security/CWE-327-BrokenCryptoAlgorithm/test_cryptography.py index 4c7317cdba4..076a9b4f870 100644 --- a/python/ql/test/query-tests/Security/CWE-327-BrokenCryptoAlgorithm/test_cryptography.py +++ b/python/ql/test/query-tests/Security/CWE-327-BrokenCryptoAlgorithm/test_cryptography.py @@ -10,7 +10,7 @@ cipher = Cipher(algorithm, mode=None) secret_message = b"secret message" encryptor = cipher.encryptor() -encrypted = encryptor.update(secret_message) # NOT OK +encrypted = encryptor.update(secret_message) # $ Alert # NOT OK encrypted += encryptor.finalize() print(secret_message, encrypted) @@ -19,7 +19,7 @@ algorithm = algorithms.AES(key) cipher = Cipher(algorithm, mode=modes.ECB()) encryptor = cipher.encryptor() -encrypted = encryptor.update(secret_message + b'\x80\x00') # NOT OK +encrypted = encryptor.update(secret_message + b'\x80\x00') # $ Alert # NOT OK encrypted += encryptor.finalize() print(secret_message, encrypted) diff --git a/python/ql/test/query-tests/Security/CWE-327-InsecureDefaultProtocol/InsecureDefaultProtocol.qlref b/python/ql/test/query-tests/Security/CWE-327-InsecureDefaultProtocol/InsecureDefaultProtocol.qlref index 13599b14931..64b934bc385 100644 --- a/python/ql/test/query-tests/Security/CWE-327-InsecureDefaultProtocol/InsecureDefaultProtocol.qlref +++ b/python/ql/test/query-tests/Security/CWE-327-InsecureDefaultProtocol/InsecureDefaultProtocol.qlref @@ -1 +1,2 @@ -Security/CWE-327/InsecureDefaultProtocol.ql +query: Security/CWE-327/InsecureDefaultProtocol.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Security/CWE-327-InsecureDefaultProtocol/InsecureProtocol.py b/python/ql/test/query-tests/Security/CWE-327-InsecureDefaultProtocol/InsecureProtocol.py index 1ea2a51a44e..a99bfe3005a 100644 --- a/python/ql/test/query-tests/Security/CWE-327-InsecureDefaultProtocol/InsecureProtocol.py +++ b/python/ql/test/query-tests/Security/CWE-327-InsecureDefaultProtocol/InsecureProtocol.py @@ -4,4 +4,4 @@ import ssl ssl.wrap_socket(ssl_version=ssl.PROTOCOL_TLSv1_2) # possibly insecure default -ssl.wrap_socket() +ssl.wrap_socket() # $ Alert diff --git a/python/ql/test/query-tests/Security/CWE-327-InsecureProtocol/InsecureProtocol.py b/python/ql/test/query-tests/Security/CWE-327-InsecureProtocol/InsecureProtocol.py index ab80ed47dac..80af8bbad37 100644 --- a/python/ql/test/query-tests/Security/CWE-327-InsecureProtocol/InsecureProtocol.py +++ b/python/ql/test/query-tests/Security/CWE-327-InsecureProtocol/InsecureProtocol.py @@ -3,25 +3,25 @@ from OpenSSL import SSL from ssl import SSLContext # insecure versions specified -ssl.wrap_socket(ssl_version=ssl.PROTOCOL_SSLv2) -ssl.wrap_socket(ssl_version=ssl.PROTOCOL_SSLv3) -ssl.wrap_socket(ssl_version=ssl.PROTOCOL_TLSv1) +ssl.wrap_socket(ssl_version=ssl.PROTOCOL_SSLv2) # $ Alert +ssl.wrap_socket(ssl_version=ssl.PROTOCOL_SSLv3) # $ Alert +ssl.wrap_socket(ssl_version=ssl.PROTOCOL_TLSv1) # $ Alert -SSLContext(protocol=ssl.PROTOCOL_SSLv2) -SSLContext(protocol=ssl.PROTOCOL_SSLv3) -SSLContext(protocol=ssl.PROTOCOL_TLSv1) +SSLContext(protocol=ssl.PROTOCOL_SSLv2) # $ Alert +SSLContext(protocol=ssl.PROTOCOL_SSLv3) # $ Alert +SSLContext(protocol=ssl.PROTOCOL_TLSv1) # $ Alert -SSL.Context(SSL.SSLv2_METHOD) -SSL.Context(SSL.SSLv3_METHOD) -SSL.Context(SSL.TLSv1_METHOD) +SSL.Context(SSL.SSLv2_METHOD) # $ Alert +SSL.Context(SSL.SSLv3_METHOD) # $ Alert +SSL.Context(SSL.TLSv1_METHOD) # $ Alert METHOD = SSL.SSLv2_METHOD -SSL.Context(METHOD) +SSL.Context(METHOD) # $ Alert # importing the protocol constant directly from ssl import PROTOCOL_SSLv2 -ssl.wrap_socket(ssl_version=PROTOCOL_SSLv2) -SSLContext(protocol=PROTOCOL_SSLv2) +ssl.wrap_socket(ssl_version=PROTOCOL_SSLv2) # $ Alert +SSLContext(protocol=PROTOCOL_SSLv2) # $ Alert # secure versions specified ssl.wrap_socket(ssl_version=ssl.PROTOCOL_TLSv1_2) diff --git a/python/ql/test/query-tests/Security/CWE-327-InsecureProtocol/InsecureProtocol.qlref b/python/ql/test/query-tests/Security/CWE-327-InsecureProtocol/InsecureProtocol.qlref index c06a937ff57..75ce269cc68 100644 --- a/python/ql/test/query-tests/Security/CWE-327-InsecureProtocol/InsecureProtocol.qlref +++ b/python/ql/test/query-tests/Security/CWE-327-InsecureProtocol/InsecureProtocol.qlref @@ -1 +1,2 @@ -Security/CWE-327/InsecureProtocol.ql +query: Security/CWE-327/InsecureProtocol.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Security/CWE-327-InsecureProtocol/import_all_one_file.py b/python/ql/test/query-tests/Security/CWE-327-InsecureProtocol/import_all_one_file.py index aab459ceeea..5a2f4614afa 100644 --- a/python/ql/test/query-tests/Security/CWE-327-InsecureProtocol/import_all_one_file.py +++ b/python/ql/test/query-tests/Security/CWE-327-InsecureProtocol/import_all_one_file.py @@ -22,9 +22,9 @@ with socket.create_connection((hostname, 443)) as sock: print(ssock.version()) with socket.create_connection((hostname, 443)) as sock: - with copy_completely_insecure_context.wrap_socket(sock, server_hostname=hostname) as ssock: + with copy_completely_insecure_context.wrap_socket(sock, server_hostname=hostname) as ssock: # $ Alert print(ssock.version()) with socket.create_connection((hostname, 443)) as sock: - with copy_also_insecure_context.wrap_socket(sock, server_hostname=hostname) as ssock: + with copy_also_insecure_context.wrap_socket(sock, server_hostname=hostname) as ssock: # $ Alert print(ssock.version()) diff --git a/python/ql/test/query-tests/Security/CWE-327-InsecureProtocol/import_use.py b/python/ql/test/query-tests/Security/CWE-327-InsecureProtocol/import_use.py index 3c12fd81355..390acf747ab 100644 --- a/python/ql/test/query-tests/Security/CWE-327-InsecureProtocol/import_use.py +++ b/python/ql/test/query-tests/Security/CWE-327-InsecureProtocol/import_use.py @@ -10,9 +10,9 @@ with socket.create_connection((hostname, 443)) as sock: print(ssock.version()) with socket.create_connection((hostname, 443)) as sock: - with completely_insecure_context.wrap_socket(sock, server_hostname=hostname) as ssock: + with completely_insecure_context.wrap_socket(sock, server_hostname=hostname) as ssock: # $ Alert print(ssock.version()) with socket.create_connection((hostname, 443)) as sock: - with also_insecure_context.wrap_socket(sock, server_hostname=hostname) as ssock: + with also_insecure_context.wrap_socket(sock, server_hostname=hostname) as ssock: # $ Alert print(ssock.version()) diff --git a/python/ql/test/query-tests/Security/CWE-327-InsecureProtocol/pyOpenSSL_fluent.py b/python/ql/test/query-tests/Security/CWE-327-InsecureProtocol/pyOpenSSL_fluent.py index fa771411882..729e968e5c1 100644 --- a/python/ql/test/query-tests/Security/CWE-327-InsecureProtocol/pyOpenSSL_fluent.py +++ b/python/ql/test/query-tests/Security/CWE-327-InsecureProtocol/pyOpenSSL_fluent.py @@ -5,7 +5,7 @@ def test_fluent(): hostname = 'www.python.org' context = SSL.Context(SSL.SSLv23_METHOD) - conn = SSL.Connection(context, socket.socket(socket.AF_INET, socket.SOCK_STREAM)) + conn = SSL.Connection(context, socket.socket(socket.AF_INET, socket.SOCK_STREAM)) # $ Alert r = conn.connect((hostname, 443)) print(conn.get_protocol_version_name()) @@ -15,7 +15,7 @@ def test_fluent_no_TLSv1(): context = SSL.Context(SSL.SSLv23_METHOD) context.set_options(SSL.OP_NO_TLSv1) - conn = SSL.Connection(context, socket.socket(socket.AF_INET, socket.SOCK_STREAM)) + conn = SSL.Connection(context, socket.socket(socket.AF_INET, socket.SOCK_STREAM)) # $ Alert r = conn.connect((hostname, 443)) print(conn.get_protocol_version_name()) diff --git a/python/ql/test/query-tests/Security/CWE-327-InsecureProtocol/ssl_fluent.py b/python/ql/test/query-tests/Security/CWE-327-InsecureProtocol/ssl_fluent.py index a8e491a42f1..e4d71de5695 100644 --- a/python/ql/test/query-tests/Security/CWE-327-InsecureProtocol/ssl_fluent.py +++ b/python/ql/test/query-tests/Security/CWE-327-InsecureProtocol/ssl_fluent.py @@ -6,7 +6,7 @@ def test_fluent_tls(): context = ssl.SSLContext(ssl.PROTOCOL_TLS) with socket.create_connection((hostname, 443)) as sock: - with context.wrap_socket(sock, server_hostname=hostname) as ssock: + with context.wrap_socket(sock, server_hostname=hostname) as ssock: # $ Alert print(ssock.version()) @@ -16,7 +16,7 @@ def test_fluent_tls_no_TLSv1(): context.options |= ssl.OP_NO_TLSv1 with socket.create_connection((hostname, 443)) as sock: - with context.wrap_socket(sock, server_hostname=hostname) as ssock: + with context.wrap_socket(sock, server_hostname=hostname) as ssock: # $ Alert print(ssock.version()) def test_fluent_tls_client_no_TLSv1(): @@ -25,7 +25,7 @@ def test_fluent_tls_client_no_TLSv1(): context.options |= ssl.OP_NO_TLSv1 with socket.create_connection((hostname, 443)) as sock: - with context.wrap_socket(sock, server_hostname=hostname) as ssock: + with context.wrap_socket(sock, server_hostname=hostname) as ssock: # $ Alert print(ssock.version()) def test_fluent_tls_server_no_TLSv1(): @@ -34,7 +34,7 @@ def test_fluent_tls_server_no_TLSv1(): context.options |= ssl.OP_NO_TLSv1 with socket.create_server((hostname, 443)) as sock: - with context.wrap_socket(sock, server_hostname=hostname) as ssock: + with context.wrap_socket(sock, server_hostname=hostname) as ssock: # $ Alert print(ssock.version()) def test_fluent_tls_safe(): @@ -54,7 +54,7 @@ def test_fluent_ssl(): context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) with socket.create_connection((hostname, 443)) as sock: - with context.wrap_socket(sock, server_hostname=hostname) as ssock: + with context.wrap_socket(sock, server_hostname=hostname) as ssock: # $ Alert print(ssock.version()) @@ -68,13 +68,13 @@ def create_secure_context(): def create_connection(context): with socket.create_connection(('www.python.org', 443)) as sock: - with context.wrap_socket(sock, server_hostname=hostname) as ssock: + with context.wrap_socket(sock, server_hostname=hostname) as ssock: # $ Alert print(ssock.version()) def test_delegated_context_unsafe(): context = create_relaxed_context() with socket.create_connection(('www.python.org', 443)) as sock: - with context.wrap_socket(sock, server_hostname=hostname) as ssock: + with context.wrap_socket(sock, server_hostname=hostname) as ssock: # $ Alert print(ssock.version()) def test_delegated_context_safe(): @@ -94,7 +94,7 @@ def test_delegated_context_made_unsafe(): context = create_secure_context() context.options &= ~ssl.OP_NO_TLSv1_1 with socket.create_connection(('www.python.org', 443)) as sock: - with context.wrap_socket(sock, server_hostname=hostname) as ssock: + with context.wrap_socket(sock, server_hostname=hostname) as ssock: # $ Alert print(ssock.version()) def test_delegated_connection_unsafe(): @@ -143,7 +143,7 @@ def test_fluent_ssl_unsafe_version(): context.minimum_version = ssl.TLSVersion.TLSv1_1 with socket.create_connection((hostname, 443)) as sock: - with context.wrap_socket(sock, server_hostname=hostname) as ssock: + with context.wrap_socket(sock, server_hostname=hostname) as ssock: # $ Alert print(ssock.version()) def test_fluent_ssl_safe_version(): @@ -162,5 +162,5 @@ def test_fluent_explicitly_unsafe(): context.options &= ~ssl.OP_NO_SSLv3 with socket.create_connection((hostname, 443)) as sock: - with context.wrap_socket(sock, server_hostname=hostname) as ssock: + with context.wrap_socket(sock, server_hostname=hostname) as ssock: # $ Alert print(ssock.version()) diff --git a/python/ql/test/query-tests/Security/CWE-327-WeakSensitiveDataHashing/WeakSensitiveDataHashing.expected b/python/ql/test/query-tests/Security/CWE-327-WeakSensitiveDataHashing/WeakSensitiveDataHashing.expected index 1027fbf4963..ae081dd1aa0 100644 --- a/python/ql/test/query-tests/Security/CWE-327-WeakSensitiveDataHashing/WeakSensitiveDataHashing.expected +++ b/python/ql/test/query-tests/Security/CWE-327-WeakSensitiveDataHashing/WeakSensitiveDataHashing.expected @@ -1,3 +1,16 @@ +#select +| test_cryptodome.py:8:19:8:27 | ControlFlowNode for dangerous | test_cryptodome.py:2:37:2:51 | ControlFlowNode for ImportMember | test_cryptodome.py:8:19:8:27 | ControlFlowNode for dangerous | $@ is used in a hashing algorithm (MD5) that is insecure. | test_cryptodome.py:2:37:2:51 | ControlFlowNode for ImportMember | Sensitive data (certificate) | +| test_cryptodome.py:8:19:8:27 | ControlFlowNode for dangerous | test_cryptodome.py:6:17:6:33 | ControlFlowNode for get_certificate() | test_cryptodome.py:8:19:8:27 | ControlFlowNode for dangerous | $@ is used in a hashing algorithm (MD5) that is insecure. | test_cryptodome.py:6:17:6:33 | ControlFlowNode for get_certificate() | Sensitive data (certificate) | +| test_cryptodome.py:15:19:15:27 | ControlFlowNode for dangerous | test_cryptodome.py:2:23:2:34 | ControlFlowNode for ImportMember | test_cryptodome.py:15:19:15:27 | ControlFlowNode for dangerous | $@ is used in a hashing algorithm (MD5) that is insecure for password hashing, since it is not a computationally expensive hash function. | test_cryptodome.py:2:23:2:34 | ControlFlowNode for ImportMember | Sensitive data (password) | +| test_cryptodome.py:15:19:15:27 | ControlFlowNode for dangerous | test_cryptodome.py:13:17:13:30 | ControlFlowNode for get_password() | test_cryptodome.py:15:19:15:27 | ControlFlowNode for dangerous | $@ is used in a hashing algorithm (MD5) that is insecure for password hashing, since it is not a computationally expensive hash function. | test_cryptodome.py:13:17:13:30 | ControlFlowNode for get_password() | Sensitive data (password) | +| test_cryptodome.py:24:19:24:27 | ControlFlowNode for dangerous | test_cryptodome.py:2:23:2:34 | ControlFlowNode for ImportMember | test_cryptodome.py:24:19:24:27 | ControlFlowNode for dangerous | $@ is used in a hashing algorithm (SHA256) that is insecure for password hashing, since it is not a computationally expensive hash function. | test_cryptodome.py:2:23:2:34 | ControlFlowNode for ImportMember | Sensitive data (password) | +| test_cryptodome.py:24:19:24:27 | ControlFlowNode for dangerous | test_cryptodome.py:20:17:20:30 | ControlFlowNode for get_password() | test_cryptodome.py:24:19:24:27 | ControlFlowNode for dangerous | $@ is used in a hashing algorithm (SHA256) that is insecure for password hashing, since it is not a computationally expensive hash function. | test_cryptodome.py:20:17:20:30 | ControlFlowNode for get_password() | Sensitive data (password) | +| test_cryptography.py:9:19:9:27 | ControlFlowNode for dangerous | test_cryptography.py:3:37:3:51 | ControlFlowNode for ImportMember | test_cryptography.py:9:19:9:27 | ControlFlowNode for dangerous | $@ is used in a hashing algorithm (MD5) that is insecure. | test_cryptography.py:3:37:3:51 | ControlFlowNode for ImportMember | Sensitive data (certificate) | +| test_cryptography.py:9:19:9:27 | ControlFlowNode for dangerous | test_cryptography.py:7:17:7:33 | ControlFlowNode for get_certificate() | test_cryptography.py:9:19:9:27 | ControlFlowNode for dangerous | $@ is used in a hashing algorithm (MD5) that is insecure. | test_cryptography.py:7:17:7:33 | ControlFlowNode for get_certificate() | Sensitive data (certificate) | +| test_cryptography.py:17:19:17:27 | ControlFlowNode for dangerous | test_cryptography.py:3:23:3:34 | ControlFlowNode for ImportMember | test_cryptography.py:17:19:17:27 | ControlFlowNode for dangerous | $@ is used in a hashing algorithm (MD5) that is insecure for password hashing, since it is not a computationally expensive hash function. | test_cryptography.py:3:23:3:34 | ControlFlowNode for ImportMember | Sensitive data (password) | +| test_cryptography.py:17:19:17:27 | ControlFlowNode for dangerous | test_cryptography.py:15:17:15:30 | ControlFlowNode for get_password() | test_cryptography.py:17:19:17:27 | ControlFlowNode for dangerous | $@ is used in a hashing algorithm (MD5) that is insecure for password hashing, since it is not a computationally expensive hash function. | test_cryptography.py:15:17:15:30 | ControlFlowNode for get_password() | Sensitive data (password) | +| test_cryptography.py:27:19:27:27 | ControlFlowNode for dangerous | test_cryptography.py:3:23:3:34 | ControlFlowNode for ImportMember | test_cryptography.py:27:19:27:27 | ControlFlowNode for dangerous | $@ is used in a hashing algorithm (SHA256) that is insecure for password hashing, since it is not a computationally expensive hash function. | test_cryptography.py:3:23:3:34 | ControlFlowNode for ImportMember | Sensitive data (password) | +| test_cryptography.py:27:19:27:27 | ControlFlowNode for dangerous | test_cryptography.py:23:17:23:30 | ControlFlowNode for get_password() | test_cryptography.py:27:19:27:27 | ControlFlowNode for dangerous | $@ is used in a hashing algorithm (SHA256) that is insecure for password hashing, since it is not a computationally expensive hash function. | test_cryptography.py:23:17:23:30 | ControlFlowNode for get_password() | Sensitive data (password) | edges | test_cryptodome.py:2:23:2:34 | ControlFlowNode for ImportMember | test_cryptodome.py:2:23:2:34 | ControlFlowNode for get_password | provenance | | | test_cryptodome.py:2:23:2:34 | ControlFlowNode for get_password | test_cryptodome.py:13:17:13:28 | ControlFlowNode for get_password | provenance | | @@ -61,16 +74,3 @@ nodes | test_cryptography.py:23:17:23:30 | ControlFlowNode for get_password() | semmle.label | ControlFlowNode for get_password() | | test_cryptography.py:27:19:27:27 | ControlFlowNode for dangerous | semmle.label | ControlFlowNode for dangerous | subpaths -#select -| test_cryptodome.py:8:19:8:27 | ControlFlowNode for dangerous | test_cryptodome.py:2:37:2:51 | ControlFlowNode for ImportMember | test_cryptodome.py:8:19:8:27 | ControlFlowNode for dangerous | $@ is used in a hashing algorithm (MD5) that is insecure. | test_cryptodome.py:2:37:2:51 | ControlFlowNode for ImportMember | Sensitive data (certificate) | -| test_cryptodome.py:8:19:8:27 | ControlFlowNode for dangerous | test_cryptodome.py:6:17:6:33 | ControlFlowNode for get_certificate() | test_cryptodome.py:8:19:8:27 | ControlFlowNode for dangerous | $@ is used in a hashing algorithm (MD5) that is insecure. | test_cryptodome.py:6:17:6:33 | ControlFlowNode for get_certificate() | Sensitive data (certificate) | -| test_cryptodome.py:15:19:15:27 | ControlFlowNode for dangerous | test_cryptodome.py:2:23:2:34 | ControlFlowNode for ImportMember | test_cryptodome.py:15:19:15:27 | ControlFlowNode for dangerous | $@ is used in a hashing algorithm (MD5) that is insecure for password hashing, since it is not a computationally expensive hash function. | test_cryptodome.py:2:23:2:34 | ControlFlowNode for ImportMember | Sensitive data (password) | -| test_cryptodome.py:15:19:15:27 | ControlFlowNode for dangerous | test_cryptodome.py:13:17:13:30 | ControlFlowNode for get_password() | test_cryptodome.py:15:19:15:27 | ControlFlowNode for dangerous | $@ is used in a hashing algorithm (MD5) that is insecure for password hashing, since it is not a computationally expensive hash function. | test_cryptodome.py:13:17:13:30 | ControlFlowNode for get_password() | Sensitive data (password) | -| test_cryptodome.py:24:19:24:27 | ControlFlowNode for dangerous | test_cryptodome.py:2:23:2:34 | ControlFlowNode for ImportMember | test_cryptodome.py:24:19:24:27 | ControlFlowNode for dangerous | $@ is used in a hashing algorithm (SHA256) that is insecure for password hashing, since it is not a computationally expensive hash function. | test_cryptodome.py:2:23:2:34 | ControlFlowNode for ImportMember | Sensitive data (password) | -| test_cryptodome.py:24:19:24:27 | ControlFlowNode for dangerous | test_cryptodome.py:20:17:20:30 | ControlFlowNode for get_password() | test_cryptodome.py:24:19:24:27 | ControlFlowNode for dangerous | $@ is used in a hashing algorithm (SHA256) that is insecure for password hashing, since it is not a computationally expensive hash function. | test_cryptodome.py:20:17:20:30 | ControlFlowNode for get_password() | Sensitive data (password) | -| test_cryptography.py:9:19:9:27 | ControlFlowNode for dangerous | test_cryptography.py:3:37:3:51 | ControlFlowNode for ImportMember | test_cryptography.py:9:19:9:27 | ControlFlowNode for dangerous | $@ is used in a hashing algorithm (MD5) that is insecure. | test_cryptography.py:3:37:3:51 | ControlFlowNode for ImportMember | Sensitive data (certificate) | -| test_cryptography.py:9:19:9:27 | ControlFlowNode for dangerous | test_cryptography.py:7:17:7:33 | ControlFlowNode for get_certificate() | test_cryptography.py:9:19:9:27 | ControlFlowNode for dangerous | $@ is used in a hashing algorithm (MD5) that is insecure. | test_cryptography.py:7:17:7:33 | ControlFlowNode for get_certificate() | Sensitive data (certificate) | -| test_cryptography.py:17:19:17:27 | ControlFlowNode for dangerous | test_cryptography.py:3:23:3:34 | ControlFlowNode for ImportMember | test_cryptography.py:17:19:17:27 | ControlFlowNode for dangerous | $@ is used in a hashing algorithm (MD5) that is insecure for password hashing, since it is not a computationally expensive hash function. | test_cryptography.py:3:23:3:34 | ControlFlowNode for ImportMember | Sensitive data (password) | -| test_cryptography.py:17:19:17:27 | ControlFlowNode for dangerous | test_cryptography.py:15:17:15:30 | ControlFlowNode for get_password() | test_cryptography.py:17:19:17:27 | ControlFlowNode for dangerous | $@ is used in a hashing algorithm (MD5) that is insecure for password hashing, since it is not a computationally expensive hash function. | test_cryptography.py:15:17:15:30 | ControlFlowNode for get_password() | Sensitive data (password) | -| test_cryptography.py:27:19:27:27 | ControlFlowNode for dangerous | test_cryptography.py:3:23:3:34 | ControlFlowNode for ImportMember | test_cryptography.py:27:19:27:27 | ControlFlowNode for dangerous | $@ is used in a hashing algorithm (SHA256) that is insecure for password hashing, since it is not a computationally expensive hash function. | test_cryptography.py:3:23:3:34 | ControlFlowNode for ImportMember | Sensitive data (password) | -| test_cryptography.py:27:19:27:27 | ControlFlowNode for dangerous | test_cryptography.py:23:17:23:30 | ControlFlowNode for get_password() | test_cryptography.py:27:19:27:27 | ControlFlowNode for dangerous | $@ is used in a hashing algorithm (SHA256) that is insecure for password hashing, since it is not a computationally expensive hash function. | test_cryptography.py:23:17:23:30 | ControlFlowNode for get_password() | Sensitive data (password) | diff --git a/python/ql/test/query-tests/Security/CWE-327-WeakSensitiveDataHashing/WeakSensitiveDataHashing.qlref b/python/ql/test/query-tests/Security/CWE-327-WeakSensitiveDataHashing/WeakSensitiveDataHashing.qlref index 6c8eeda7222..495cb9c979c 100644 --- a/python/ql/test/query-tests/Security/CWE-327-WeakSensitiveDataHashing/WeakSensitiveDataHashing.qlref +++ b/python/ql/test/query-tests/Security/CWE-327-WeakSensitiveDataHashing/WeakSensitiveDataHashing.qlref @@ -1 +1,2 @@ -Security/CWE-327/WeakSensitiveDataHashing.ql +query: Security/CWE-327/WeakSensitiveDataHashing.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Security/CWE-327-WeakSensitiveDataHashing/test_cryptodome.py b/python/ql/test/query-tests/Security/CWE-327-WeakSensitiveDataHashing/test_cryptodome.py index 3e196196ef9..2a8fa6522ba 100644 --- a/python/ql/test/query-tests/Security/CWE-327-WeakSensitiveDataHashing/test_cryptodome.py +++ b/python/ql/test/query-tests/Security/CWE-327-WeakSensitiveDataHashing/test_cryptodome.py @@ -1,25 +1,25 @@ from Cryptodome.Hash import MD5, SHA256 -from my_module import get_password, get_certificate +from my_module import get_password, get_certificate # $ Source def get_badly_hashed_certificate(): - dangerous = get_certificate() + dangerous = get_certificate() # $ Source hasher = MD5.new() - hasher.update(dangerous) # NOT OK + hasher.update(dangerous) # $ Alert # NOT OK return hasher.hexdigest() def get_badly_hashed_password(): - dangerous = get_password() + dangerous = get_password() # $ Source hasher = MD5.new() - hasher.update(dangerous) # NOT OK + hasher.update(dangerous) # $ Alert # NOT OK return hasher.hexdigest() def get_badly_hashed_password2(): - dangerous = get_password() + dangerous = get_password() # $ Source # Although SHA-256 is a strong cryptographic hash functions, # it is not suitable for password hashing. hasher = SHA256.new() - hasher.update(dangerous) # NOT OK + hasher.update(dangerous) # $ Alert # NOT OK return hasher.hexdigest() diff --git a/python/ql/test/query-tests/Security/CWE-327-WeakSensitiveDataHashing/test_cryptography.py b/python/ql/test/query-tests/Security/CWE-327-WeakSensitiveDataHashing/test_cryptography.py index 1090fda959c..09e58768e9f 100644 --- a/python/ql/test/query-tests/Security/CWE-327-WeakSensitiveDataHashing/test_cryptography.py +++ b/python/ql/test/query-tests/Security/CWE-327-WeakSensitiveDataHashing/test_cryptography.py @@ -1,29 +1,29 @@ from cryptography.hazmat.primitives import hashes from binascii import hexlify -from my_module import get_password, get_certificate +from my_module import get_password, get_certificate # $ Source def get_badly_hashed_certificate(): - dangerous = get_certificate() + dangerous = get_certificate() # $ Source hasher = hashes.Hash(hashes.MD5()) - hasher.update(dangerous) # NOT OK + hasher.update(dangerous) # $ Alert # NOT OK digest = hasher.finalize() return hexlify(digest).decode("utf-8") def get_badly_hashed_password(): - dangerous = get_password() + dangerous = get_password() # $ Source hasher = hashes.Hash(hashes.MD5()) - hasher.update(dangerous) # NOT OK + hasher.update(dangerous) # $ Alert # NOT OK digest = hasher.finalize() return hexlify(digest).decode("utf-8") def get_badly_hashed_password2(): - dangerous = get_password() + dangerous = get_password() # $ Source # Although SHA-256 is a strong cryptographic hash functions, # it is not suitable for password hashing. hasher = hashes.Hash(hashes.SHA256()) - hasher.update(dangerous) # NOT OK + hasher.update(dangerous) # $ Alert # NOT OK digest = hasher.finalize() return hexlify(digest).decode("utf-8") diff --git a/python/ql/test/query-tests/Security/CWE-377-InsecureTemporaryFile/InsecureTemporaryFile.py b/python/ql/test/query-tests/Security/CWE-377-InsecureTemporaryFile/InsecureTemporaryFile.py index 3c68affed8c..5b7e820706e 100644 --- a/python/ql/test/query-tests/Security/CWE-377-InsecureTemporaryFile/InsecureTemporaryFile.py +++ b/python/ql/test/query-tests/Security/CWE-377-InsecureTemporaryFile/InsecureTemporaryFile.py @@ -2,19 +2,19 @@ from tempfile import mktemp import os def write_results1(results): - filename = mktemp() + filename = mktemp() # $ Alert with open(filename, "w+") as f: f.write(results) print("Results written to", filename) def write_results2(results): - filename = os.tempnam() + filename = os.tempnam() # $ Alert with open(filename, "w+") as f: f.write(results) print("Results written to", filename) def write_results3(results): - filename = os.tmpnam() + filename = os.tmpnam() # $ Alert with open(filename, "w+") as f: f.write(results) print("Results written to", filename) diff --git a/python/ql/test/query-tests/Security/CWE-377-InsecureTemporaryFile/InsecureTemporaryFile.qlref b/python/ql/test/query-tests/Security/CWE-377-InsecureTemporaryFile/InsecureTemporaryFile.qlref index 68a27dfb269..c64f78a0103 100644 --- a/python/ql/test/query-tests/Security/CWE-377-InsecureTemporaryFile/InsecureTemporaryFile.qlref +++ b/python/ql/test/query-tests/Security/CWE-377-InsecureTemporaryFile/InsecureTemporaryFile.qlref @@ -1 +1,2 @@ -Security/CWE-377/InsecureTemporaryFile.ql +query: Security/CWE-377/InsecureTemporaryFile.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Security/CWE-502-UnsafeDeserialization/UnsafeDeserialization.expected b/python/ql/test/query-tests/Security/CWE-502-UnsafeDeserialization/UnsafeDeserialization.expected index bab1e34c912..309ef858d3b 100644 --- a/python/ql/test/query-tests/Security/CWE-502-UnsafeDeserialization/UnsafeDeserialization.expected +++ b/python/ql/test/query-tests/Security/CWE-502-UnsafeDeserialization/UnsafeDeserialization.expected @@ -1,3 +1,9 @@ +#select +| unsafe_deserialization.py:15:18:15:24 | ControlFlowNode for payload | unsafe_deserialization.py:8:26:8:32 | ControlFlowNode for ImportMember | unsafe_deserialization.py:15:18:15:24 | ControlFlowNode for payload | Unsafe deserialization depends on a $@. | unsafe_deserialization.py:8:26:8:32 | ControlFlowNode for ImportMember | user-provided value | +| unsafe_deserialization.py:16:15:16:21 | ControlFlowNode for payload | unsafe_deserialization.py:8:26:8:32 | ControlFlowNode for ImportMember | unsafe_deserialization.py:16:15:16:21 | ControlFlowNode for payload | Unsafe deserialization depends on a $@. | unsafe_deserialization.py:8:26:8:32 | ControlFlowNode for ImportMember | user-provided value | +| unsafe_deserialization.py:18:19:18:25 | ControlFlowNode for payload | unsafe_deserialization.py:8:26:8:32 | ControlFlowNode for ImportMember | unsafe_deserialization.py:18:19:18:25 | ControlFlowNode for payload | Unsafe deserialization depends on a $@. | unsafe_deserialization.py:8:26:8:32 | ControlFlowNode for ImportMember | user-provided value | +| unsafe_deserialization.py:21:16:21:22 | ControlFlowNode for payload | unsafe_deserialization.py:8:26:8:32 | ControlFlowNode for ImportMember | unsafe_deserialization.py:21:16:21:22 | ControlFlowNode for payload | Unsafe deserialization depends on a $@. | unsafe_deserialization.py:8:26:8:32 | ControlFlowNode for ImportMember | user-provided value | +| unsafe_deserialization.py:24:24:24:30 | ControlFlowNode for payload | unsafe_deserialization.py:8:26:8:32 | ControlFlowNode for ImportMember | unsafe_deserialization.py:24:24:24:30 | ControlFlowNode for payload | Unsafe deserialization depends on a $@. | unsafe_deserialization.py:8:26:8:32 | ControlFlowNode for ImportMember | user-provided value | edges | unsafe_deserialization.py:8:26:8:32 | ControlFlowNode for ImportMember | unsafe_deserialization.py:8:26:8:32 | ControlFlowNode for request | provenance | | | unsafe_deserialization.py:8:26:8:32 | ControlFlowNode for request | unsafe_deserialization.py:14:15:14:21 | ControlFlowNode for request | provenance | | @@ -22,9 +28,3 @@ nodes | unsafe_deserialization.py:21:16:21:22 | ControlFlowNode for payload | semmle.label | ControlFlowNode for payload | | unsafe_deserialization.py:24:24:24:30 | ControlFlowNode for payload | semmle.label | ControlFlowNode for payload | subpaths -#select -| unsafe_deserialization.py:15:18:15:24 | ControlFlowNode for payload | unsafe_deserialization.py:8:26:8:32 | ControlFlowNode for ImportMember | unsafe_deserialization.py:15:18:15:24 | ControlFlowNode for payload | Unsafe deserialization depends on a $@. | unsafe_deserialization.py:8:26:8:32 | ControlFlowNode for ImportMember | user-provided value | -| unsafe_deserialization.py:16:15:16:21 | ControlFlowNode for payload | unsafe_deserialization.py:8:26:8:32 | ControlFlowNode for ImportMember | unsafe_deserialization.py:16:15:16:21 | ControlFlowNode for payload | Unsafe deserialization depends on a $@. | unsafe_deserialization.py:8:26:8:32 | ControlFlowNode for ImportMember | user-provided value | -| unsafe_deserialization.py:18:19:18:25 | ControlFlowNode for payload | unsafe_deserialization.py:8:26:8:32 | ControlFlowNode for ImportMember | unsafe_deserialization.py:18:19:18:25 | ControlFlowNode for payload | Unsafe deserialization depends on a $@. | unsafe_deserialization.py:8:26:8:32 | ControlFlowNode for ImportMember | user-provided value | -| unsafe_deserialization.py:21:16:21:22 | ControlFlowNode for payload | unsafe_deserialization.py:8:26:8:32 | ControlFlowNode for ImportMember | unsafe_deserialization.py:21:16:21:22 | ControlFlowNode for payload | Unsafe deserialization depends on a $@. | unsafe_deserialization.py:8:26:8:32 | ControlFlowNode for ImportMember | user-provided value | -| unsafe_deserialization.py:24:24:24:30 | ControlFlowNode for payload | unsafe_deserialization.py:8:26:8:32 | ControlFlowNode for ImportMember | unsafe_deserialization.py:24:24:24:30 | ControlFlowNode for payload | Unsafe deserialization depends on a $@. | unsafe_deserialization.py:8:26:8:32 | ControlFlowNode for ImportMember | user-provided value | diff --git a/python/ql/test/query-tests/Security/CWE-502-UnsafeDeserialization/UnsafeDeserialization.qlref b/python/ql/test/query-tests/Security/CWE-502-UnsafeDeserialization/UnsafeDeserialization.qlref index fa9c0ceb3cb..2eba44efb96 100644 --- a/python/ql/test/query-tests/Security/CWE-502-UnsafeDeserialization/UnsafeDeserialization.qlref +++ b/python/ql/test/query-tests/Security/CWE-502-UnsafeDeserialization/UnsafeDeserialization.qlref @@ -1 +1,2 @@ -Security/CWE-502/UnsafeDeserialization.ql +query: Security/CWE-502/UnsafeDeserialization.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Security/CWE-502-UnsafeDeserialization/unsafe_deserialization.py b/python/ql/test/query-tests/Security/CWE-502-UnsafeDeserialization/unsafe_deserialization.py index d9189a92f41..81a73c23f5f 100644 --- a/python/ql/test/query-tests/Security/CWE-502-UnsafeDeserialization/unsafe_deserialization.py +++ b/python/ql/test/query-tests/Security/CWE-502-UnsafeDeserialization/unsafe_deserialization.py @@ -5,20 +5,20 @@ import marshal from yaml import SafeLoader -from flask import Flask, request +from flask import Flask, request # $ Source app = Flask(__name__) @app.route("/") def hello(): payload = request.args.get("payload") - pickle.loads(payload) # NOT OK - yaml.load(payload) # NOT OK + pickle.loads(payload) # $ Alert # NOT OK + yaml.load(payload) # $ Alert # NOT OK yaml.load(payload, Loader=SafeLoader) # OK - marshal.loads(payload) # NOT OK + marshal.loads(payload) # $ Alert # NOT OK import dill - dill.loads(payload) # NOT OK + dill.loads(payload) # $ Alert # NOT OK import pandas - pandas.read_pickle(payload) # NOT OK \ No newline at end of file + pandas.read_pickle(payload) # $ Alert # NOT OK diff --git a/python/ql/test/query-tests/Security/CWE-601-UrlRedirect/UrlRedirect.expected b/python/ql/test/query-tests/Security/CWE-601-UrlRedirect/UrlRedirect.expected index 551299a64dc..3e43c112e2a 100644 --- a/python/ql/test/query-tests/Security/CWE-601-UrlRedirect/UrlRedirect.expected +++ b/python/ql/test/query-tests/Security/CWE-601-UrlRedirect/UrlRedirect.expected @@ -1,3 +1,16 @@ +#select +| test.py:8:21:8:26 | ControlFlowNode for target | test.py:1:26:1:32 | ControlFlowNode for ImportMember | test.py:8:21:8:26 | ControlFlowNode for target | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | +| test.py:32:21:32:24 | ControlFlowNode for safe | test.py:1:26:1:32 | ControlFlowNode for ImportMember | test.py:32:21:32:24 | ControlFlowNode for safe | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | +| test.py:39:21:39:24 | ControlFlowNode for safe | test.py:1:26:1:32 | ControlFlowNode for ImportMember | test.py:39:21:39:24 | ControlFlowNode for safe | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | +| test.py:46:21:46:24 | ControlFlowNode for safe | test.py:1:26:1:32 | ControlFlowNode for ImportMember | test.py:46:21:46:24 | ControlFlowNode for safe | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | +| test.py:62:21:62:26 | ControlFlowNode for unsafe | test.py:1:26:1:32 | ControlFlowNode for ImportMember | test.py:62:21:62:26 | ControlFlowNode for unsafe | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | +| test.py:69:21:69:26 | ControlFlowNode for unsafe | test.py:1:26:1:32 | ControlFlowNode for ImportMember | test.py:69:21:69:26 | ControlFlowNode for unsafe | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | +| test.py:76:21:76:26 | ControlFlowNode for unsafe | test.py:1:26:1:32 | ControlFlowNode for ImportMember | test.py:76:21:76:26 | ControlFlowNode for unsafe | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | +| test.py:83:21:83:26 | ControlFlowNode for unsafe | test.py:1:26:1:32 | ControlFlowNode for ImportMember | test.py:83:21:83:26 | ControlFlowNode for unsafe | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | +| test.py:93:18:93:26 | ControlFlowNode for untrusted | test.py:1:26:1:32 | ControlFlowNode for ImportMember | test.py:93:18:93:26 | ControlFlowNode for untrusted | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | +| test.py:114:25:114:33 | ControlFlowNode for untrusted | test.py:1:26:1:32 | ControlFlowNode for ImportMember | test.py:114:25:114:33 | ControlFlowNode for untrusted | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | +| test.py:140:25:140:33 | ControlFlowNode for untrusted | test.py:1:26:1:32 | ControlFlowNode for ImportMember | test.py:140:25:140:33 | ControlFlowNode for untrusted | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | +| test.py:148:25:148:33 | ControlFlowNode for untrusted | test.py:1:26:1:32 | ControlFlowNode for ImportMember | test.py:148:25:148:33 | ControlFlowNode for untrusted | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | edges | test.py:1:26:1:32 | ControlFlowNode for ImportMember | test.py:1:26:1:32 | ControlFlowNode for request | provenance | | | test.py:1:26:1:32 | ControlFlowNode for request | test.py:7:14:7:20 | ControlFlowNode for request | provenance | | @@ -138,16 +151,3 @@ nodes | test.py:145:17:145:46 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | | test.py:148:25:148:33 | ControlFlowNode for untrusted | semmle.label | ControlFlowNode for untrusted | subpaths -#select -| test.py:8:21:8:26 | ControlFlowNode for target | test.py:1:26:1:32 | ControlFlowNode for ImportMember | test.py:8:21:8:26 | ControlFlowNode for target | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | -| test.py:32:21:32:24 | ControlFlowNode for safe | test.py:1:26:1:32 | ControlFlowNode for ImportMember | test.py:32:21:32:24 | ControlFlowNode for safe | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | -| test.py:39:21:39:24 | ControlFlowNode for safe | test.py:1:26:1:32 | ControlFlowNode for ImportMember | test.py:39:21:39:24 | ControlFlowNode for safe | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | -| test.py:46:21:46:24 | ControlFlowNode for safe | test.py:1:26:1:32 | ControlFlowNode for ImportMember | test.py:46:21:46:24 | ControlFlowNode for safe | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | -| test.py:62:21:62:26 | ControlFlowNode for unsafe | test.py:1:26:1:32 | ControlFlowNode for ImportMember | test.py:62:21:62:26 | ControlFlowNode for unsafe | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | -| test.py:69:21:69:26 | ControlFlowNode for unsafe | test.py:1:26:1:32 | ControlFlowNode for ImportMember | test.py:69:21:69:26 | ControlFlowNode for unsafe | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | -| test.py:76:21:76:26 | ControlFlowNode for unsafe | test.py:1:26:1:32 | ControlFlowNode for ImportMember | test.py:76:21:76:26 | ControlFlowNode for unsafe | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | -| test.py:83:21:83:26 | ControlFlowNode for unsafe | test.py:1:26:1:32 | ControlFlowNode for ImportMember | test.py:83:21:83:26 | ControlFlowNode for unsafe | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | -| test.py:93:18:93:26 | ControlFlowNode for untrusted | test.py:1:26:1:32 | ControlFlowNode for ImportMember | test.py:93:18:93:26 | ControlFlowNode for untrusted | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | -| test.py:114:25:114:33 | ControlFlowNode for untrusted | test.py:1:26:1:32 | ControlFlowNode for ImportMember | test.py:114:25:114:33 | ControlFlowNode for untrusted | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | -| test.py:140:25:140:33 | ControlFlowNode for untrusted | test.py:1:26:1:32 | ControlFlowNode for ImportMember | test.py:140:25:140:33 | ControlFlowNode for untrusted | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | -| test.py:148:25:148:33 | ControlFlowNode for untrusted | test.py:1:26:1:32 | ControlFlowNode for ImportMember | test.py:148:25:148:33 | ControlFlowNode for untrusted | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | diff --git a/python/ql/test/query-tests/Security/CWE-601-UrlRedirect/UrlRedirect.qlref b/python/ql/test/query-tests/Security/CWE-601-UrlRedirect/UrlRedirect.qlref index 8b63d80f0db..863d71f68b1 100644 --- a/python/ql/test/query-tests/Security/CWE-601-UrlRedirect/UrlRedirect.qlref +++ b/python/ql/test/query-tests/Security/CWE-601-UrlRedirect/UrlRedirect.qlref @@ -1,2 +1,2 @@ -Security/CWE-601/UrlRedirect.ql - +query: Security/CWE-601/UrlRedirect.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Security/CWE-601-UrlRedirect/test.py b/python/ql/test/query-tests/Security/CWE-601-UrlRedirect/test.py index 538e4d3910b..dd374618a9d 100644 --- a/python/ql/test/query-tests/Security/CWE-601-UrlRedirect/test.py +++ b/python/ql/test/query-tests/Security/CWE-601-UrlRedirect/test.py @@ -1,11 +1,11 @@ -from flask import Flask, request, redirect +from flask import Flask, request, redirect # $ Source app = Flask(__name__) @app.route('/') def hello(): target = request.args.get('target', '') - return redirect(target, code=302) + return redirect(target, code=302) # $ Alert # Check for safe prefixes @@ -29,21 +29,21 @@ def ok2(): def ok3(): untrusted = request.args.get('target', '') safe = "https://safe.com/{}".format(untrusted) - return redirect(safe, code=302) # FP + return redirect(safe, code=302) # $ SPURIOUS: Alert # FP @app.route('/ok4') def ok4(): untrusted = request.args.get('target', '') safe = f"https://safe.com/{untrusted}" - return redirect(safe, code=302) # FP + return redirect(safe, code=302) # $ SPURIOUS: Alert # FP @app.route('/ok5') def ok5(): untrusted = request.args.get('target', '') safe = "https://safe.com/%s" % untrusted - return redirect(safe, code=302) # FP + return redirect(safe, code=302) # $ SPURIOUS: Alert # FP @app.route('/const-str-compare') @@ -59,41 +59,41 @@ def const_str_compare(): def not_ok1(): untrusted = request.args.get('target', '') unsafe = untrusted + "?login=success" - return redirect(unsafe, code=302) + return redirect(unsafe, code=302) # $ Alert @app.route('/not_ok2') def not_ok2(): untrusted = request.args.get('target', '') unsafe = "{}?login=success".format(untrusted) - return redirect(unsafe, code=302) + return redirect(unsafe, code=302) # $ Alert @app.route('/not_ok3') def not_ok3(): untrusted = request.args.get('target', '') unsafe = f"{untrusted}?login=success" - return redirect(unsafe, code=302) + return redirect(unsafe, code=302) # $ Alert @app.route('/not_ok4') def not_ok4(): untrusted = request.args.get('target', '') unsafe = "%s?login=success" % untrusted - return redirect(unsafe, code=302) + return redirect(unsafe, code=302) # $ Alert from django.utils.http import url_has_allowed_host_and_scheme -import math +import math @app.route('/ok6') def ok6(): untrusted = request.args.get('target', '') - # random chance. + # random chance. if math.random() > 0.5: - redirect(untrusted, code=302) # NOT OK + redirect(untrusted, code=302) # $ Alert # NOT OK if url_has_allowed_host_and_scheme(untrusted, allowed_hosts=None): return redirect(untrusted, code=302) # OK - + return redirect("https://example.com", code=302) # OK import yarl @@ -111,7 +111,7 @@ def not_ok5(): untrusted = request.args.get('target', '') # no backslash replace if not yarl.URL(untrusted).is_absolute(): - return redirect(untrusted, code=302) # NOT OK + return redirect(untrusted, code=302) # $ Alert # NOT OK return redirect("/", code=302) from urllib.parse import urlparse @@ -137,7 +137,7 @@ def not_ok6(): untrusted = request.args.get('target', '') # no backslash replace if not urlparse(untrusted).netloc: - return redirect(untrusted, code=302) # NOT OK + return redirect(untrusted, code=302) # $ Alert # NOT OK return redirect("/", code=302) @app.route('/not_ok7') @@ -145,7 +145,7 @@ def not_ok7(): untrusted = request.args.get('target', '') # wrong check if urlparse(untrusted).netloc != "": - return redirect(untrusted, code=302) # NOT OK + return redirect(untrusted, code=302) # $ Alert # NOT OK return redirect("/", code=302) @app.route('/ok10') diff --git a/python/ql/test/query-tests/Security/CWE-611-Xxe/Xxe.qlref b/python/ql/test/query-tests/Security/CWE-611-Xxe/Xxe.qlref index 62a3f7f22d9..9473e862015 100644 --- a/python/ql/test/query-tests/Security/CWE-611-Xxe/Xxe.qlref +++ b/python/ql/test/query-tests/Security/CWE-611-Xxe/Xxe.qlref @@ -1 +1,2 @@ -Security/CWE-611/Xxe.ql +query: Security/CWE-611/Xxe.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Security/CWE-611-Xxe/test.py b/python/ql/test/query-tests/Security/CWE-611-Xxe/test.py index 104f2663d59..e84a05a7663 100644 --- a/python/ql/test/query-tests/Security/CWE-611-Xxe/test.py +++ b/python/ql/test/query-tests/Security/CWE-611-Xxe/test.py @@ -1,4 +1,4 @@ -from flask import Flask, request +from flask import Flask, request # $ Source import lxml.etree import markupsafe @@ -7,7 +7,7 @@ app = Flask(__name__) @app.route("/vuln-handler") def vuln_handler(): xml_content = request.args['xml_content'] - return lxml.etree.fromstring(xml_content).text + return lxml.etree.fromstring(xml_content).text # $ Alert @app.route("/safe-handler") def safe_handler(): @@ -28,7 +28,7 @@ def super_vuln_handler(): # allows DoS attacks huge_tree=True, ) - return lxml.etree.fromstring(xml_content, parser=parser).text + return lxml.etree.fromstring(xml_content, parser=parser).text # $ Alert @app.route("/sanitized-handler") def sanitized_handler(): diff --git a/python/ql/test/query-tests/Security/CWE-643-XPathInjection/XpathInjection.qlref b/python/ql/test/query-tests/Security/CWE-643-XPathInjection/XpathInjection.qlref index a61523e1767..20ce4fdfd93 100644 --- a/python/ql/test/query-tests/Security/CWE-643-XPathInjection/XpathInjection.qlref +++ b/python/ql/test/query-tests/Security/CWE-643-XPathInjection/XpathInjection.qlref @@ -1 +1,2 @@ -Security/CWE-643/XpathInjection.ql +query: Security/CWE-643/XpathInjection.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Security/CWE-643-XPathInjection/xpathBad.py b/python/ql/test/query-tests/Security/CWE-643-XPathInjection/xpathBad.py index ee836dd385e..26a2f8d0d9a 100644 --- a/python/ql/test/query-tests/Security/CWE-643-XPathInjection/xpathBad.py +++ b/python/ql/test/query-tests/Security/CWE-643-XPathInjection/xpathBad.py @@ -6,11 +6,11 @@ from django.http import HttpResponse from django.template import Template, Context, Engine, engines -def a(request): +def a(request): # $ Source value = request.GET['xpath'] f = StringIO('') tree = etree.parse(f) - r = tree.xpath("/tag[@id='%s']" % value) + r = tree.xpath("/tag[@id='%s']" % value) # $ Alert urlpatterns = [ diff --git a/python/ql/test/query-tests/Security/CWE-643-XPathInjection/xpathFlow.py b/python/ql/test/query-tests/Security/CWE-643-XPathInjection/xpathFlow.py index c2fe2ce1edb..0a4f97ce30e 100644 --- a/python/ql/test/query-tests/Security/CWE-643-XPathInjection/xpathFlow.py +++ b/python/ql/test/query-tests/Security/CWE-643-XPathInjection/xpathFlow.py @@ -1,5 +1,5 @@ from io import StringIO -from flask import Flask, request +from flask import Flask, request # $ Source app = Flask(__name__) @@ -11,7 +11,7 @@ def xpath1(): xpathQuery = request.args.get('xml', '') f = StringIO('') tree = etree.parse(f) - r = tree.xpath(xpathQuery) + r = tree.xpath(xpathQuery) # $ Alert @app.route("/xpath2") @@ -20,7 +20,7 @@ def xpath2(): xpathQuery = request.args.get('xml', '') root = etree.XML("TEXT") - find_text = etree.XPath(xpathQuery) + find_text = etree.XPath(xpathQuery) # $ Alert text = find_text(root)[0] @@ -29,7 +29,7 @@ def xpath3(): from lxml import etree xpathQuery = request.args.get('xml', '') root = etree.XML("TEXT") - find_text = etree.XPath(xpathQuery, smart_strings=False) + find_text = etree.XPath(xpathQuery, smart_strings=False) # $ Alert text = find_text(root)[0] @@ -38,7 +38,7 @@ def xpath4(): from lxml import etree xpathQuery = request.args.get('xml', '') root = etree.XML("TEXT") - find_text = etree.ETXPath(xpathQuery) + find_text = etree.ETXPath(xpathQuery) # $ Alert text = find_text(root)[0] @app.route("/xpath5") @@ -46,4 +46,4 @@ def xpath5(): import libxml2 xpathQuery = request.args.get('xml', '') doc = libxml2.parseFile('xpath_injection/credential.xml') - results = doc.xpathEval(xpathQuery) + results = doc.xpathEval(xpathQuery) # $ Alert diff --git a/python/ql/test/query-tests/Security/CWE-730-PolynomialReDoS/PolynomialReDoS.expected b/python/ql/test/query-tests/Security/CWE-730-PolynomialReDoS/PolynomialReDoS.expected index aa8cea07ed1..22fcfd05fa1 100644 --- a/python/ql/test/query-tests/Security/CWE-730-PolynomialReDoS/PolynomialReDoS.expected +++ b/python/ql/test/query-tests/Security/CWE-730-PolynomialReDoS/PolynomialReDoS.expected @@ -1,3 +1,9 @@ +#select +| test.py:8:30:8:33 | ControlFlowNode for text | test.py:2:26:2:32 | ControlFlowNode for ImportMember | test.py:8:30:8:33 | ControlFlowNode for text | This $@ that depends on a $@ may run slow on strings with many repetitions of ' '. | test.py:8:19:8:21 | \\s+ | regular expression | test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | +| test.py:9:32:9:35 | ControlFlowNode for text | test.py:2:26:2:32 | ControlFlowNode for ImportMember | test.py:9:32:9:35 | ControlFlowNode for text | This $@ that depends on a $@ may run slow on strings starting with '0.9' and with many repetitions of '99'. | test.py:9:25:9:27 | \\d+ | regular expression | test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | +| test.py:12:17:12:20 | ControlFlowNode for text | test.py:2:26:2:32 | ControlFlowNode for ImportMember | test.py:12:17:12:20 | ControlFlowNode for text | This $@ that depends on a $@ may run slow on strings with many repetitions of ' '. | test.py:11:29:11:31 | \\s+ | regular expression | test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | +| test.py:16:24:16:30 | ControlFlowNode for my_text | test.py:2:26:2:32 | ControlFlowNode for ImportMember | test.py:16:24:16:30 | ControlFlowNode for my_text | This $@ that depends on a $@ may run slow on strings with many repetitions of ' '. | test.py:18:21:18:23 | \\s+ | regular expression | test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | +| test.py:21:18:21:21 | ControlFlowNode for text | test.py:2:26:2:32 | ControlFlowNode for ImportMember | test.py:21:18:21:21 | ControlFlowNode for text | This $@ that depends on a $@ may run slow on strings starting with 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC' and with many repetitions of 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC'. | test.py:20:271:20:272 | .* | regular expression | test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | edges | test.py:2:26:2:32 | ControlFlowNode for ImportMember | test.py:2:26:2:32 | ControlFlowNode for request | provenance | | | test.py:2:26:2:32 | ControlFlowNode for request | test.py:7:12:7:18 | ControlFlowNode for request | provenance | | @@ -26,9 +32,3 @@ nodes | test.py:18:28:18:31 | ControlFlowNode for text | semmle.label | ControlFlowNode for text | | test.py:21:18:21:21 | ControlFlowNode for text | semmle.label | ControlFlowNode for text | subpaths -#select -| test.py:8:30:8:33 | ControlFlowNode for text | test.py:2:26:2:32 | ControlFlowNode for ImportMember | test.py:8:30:8:33 | ControlFlowNode for text | This $@ that depends on a $@ may run slow on strings with many repetitions of ' '. | test.py:8:19:8:21 | \\s+ | regular expression | test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | -| test.py:9:32:9:35 | ControlFlowNode for text | test.py:2:26:2:32 | ControlFlowNode for ImportMember | test.py:9:32:9:35 | ControlFlowNode for text | This $@ that depends on a $@ may run slow on strings starting with '0.9' and with many repetitions of '99'. | test.py:9:25:9:27 | \\d+ | regular expression | test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | -| test.py:12:17:12:20 | ControlFlowNode for text | test.py:2:26:2:32 | ControlFlowNode for ImportMember | test.py:12:17:12:20 | ControlFlowNode for text | This $@ that depends on a $@ may run slow on strings with many repetitions of ' '. | test.py:11:29:11:31 | \\s+ | regular expression | test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | -| test.py:16:24:16:30 | ControlFlowNode for my_text | test.py:2:26:2:32 | ControlFlowNode for ImportMember | test.py:16:24:16:30 | ControlFlowNode for my_text | This $@ that depends on a $@ may run slow on strings with many repetitions of ' '. | test.py:18:21:18:23 | \\s+ | regular expression | test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | -| test.py:21:18:21:21 | ControlFlowNode for text | test.py:2:26:2:32 | ControlFlowNode for ImportMember | test.py:21:18:21:21 | ControlFlowNode for text | This $@ that depends on a $@ may run slow on strings starting with 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC' and with many repetitions of 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC'. | test.py:20:271:20:272 | .* | regular expression | test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | diff --git a/python/ql/test/query-tests/Security/CWE-730-PolynomialReDoS/PolynomialReDoS.qlref b/python/ql/test/query-tests/Security/CWE-730-PolynomialReDoS/PolynomialReDoS.qlref index 8c457eb7467..1847f552d93 100644 --- a/python/ql/test/query-tests/Security/CWE-730-PolynomialReDoS/PolynomialReDoS.qlref +++ b/python/ql/test/query-tests/Security/CWE-730-PolynomialReDoS/PolynomialReDoS.qlref @@ -1 +1,2 @@ -Security/CWE-730/PolynomialReDoS.ql +query: Security/CWE-730/PolynomialReDoS.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Security/CWE-730-PolynomialReDoS/test.py b/python/ql/test/query-tests/Security/CWE-730-PolynomialReDoS/test.py index 622fa6803b9..60584229b91 100644 --- a/python/ql/test/query-tests/Security/CWE-730-PolynomialReDoS/test.py +++ b/python/ql/test/query-tests/Security/CWE-730-PolynomialReDoS/test.py @@ -1,22 +1,22 @@ import re -from flask import Flask, request +from flask import Flask, request # $ Source app = Flask(__name__) @app.route("/poly-redos") def code_execution(): text = request.args.get("text") - re.sub(r"^\s+|\s+$", "", text) # NOT OK - re.match(r"^0\.\d+E?\d+$", text) # NOT OK + re.sub(r"^\s+|\s+$", "", text) # $ Alert # NOT OK + re.match(r"^0\.\d+E?\d+$", text) # $ Alert # NOT OK reg = re.compile(r"^\s+|\s+$") - reg.sub("", text) # NOT OK + reg.sub("", text) # $ Alert # NOT OK def indirect(input_reg_str, my_text): my_reg = re.compile(input_reg_str) - my_reg.sub("", my_text) # NOT OK + my_reg.sub("", my_text) # $ Alert # NOT OK indirect(r"^\s+|\s+$", text) reg2 = re.compile(r"(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)C.*Y") - reg2.sub("", text) # NOT OK + reg2.sub("", text) # $ Alert # NOT OK diff --git a/python/ql/test/query-tests/Security/CWE-730-ReDoS/KnownCVEs.py b/python/ql/test/query-tests/Security/CWE-730-ReDoS/KnownCVEs.py index 14a8ff52809..6e63bf28f3c 100644 --- a/python/ql/test/query-tests/Security/CWE-730-ReDoS/KnownCVEs.py +++ b/python/ql/test/query-tests/Security/CWE-730-ReDoS/KnownCVEs.py @@ -12,7 +12,7 @@ newline = whitespace_optional + newline_only + whitespace_optional toFlag = re.compile(newline) # https://github.com/github/codeql-python-CVE-coverage/issues/400 -re.compile(r'[+-]?(\d+)*\.\d+%?') +re.compile(r'[+-]?(\d+)*\.\d+%?') # $ Alert re.compile(r'"""\s+(?:.|\n)*?\s+"""') re.compile(r'(\{\s+)(\S+)(\s+[^}]+\s+\}\s)') re.compile(r'".*``.*``.*"') @@ -27,12 +27,12 @@ re.compile(r'(\.\w+\b)(\s*=\s*)([^;]*)(\s*;)') simple_email_re = re.compile(r"^\S+@[a-zA-Z0-9._-]+\.[a-zA-Z0-9._-]+$") # https://github.com/github/codeql-python-CVE-coverage/issues/249 -rx = re.compile('(?:.*,)*[ \t]*([^ \t]+)[ \t]+' +rx = re.compile('(?:.*,)*[ \t]*([^ \t]+)[ \t]+' # $ Alert 'realm=(["\']?)([^"\']*)\\2', re.I) # https://github.com/github/codeql-python-CVE-coverage/issues/248 gauntlet = re.compile( - r"""^([-/:,#%.'"\s!\w]|\w-\w|'[\s\w]+'\s*|"[\s\w]+"|\([\d,%\.\s]+\))*$""", + r"""^([-/:,#%.'"\s!\w]|\w-\w|'[\s\w]+'\s*|"[\s\w]+"|\([\d,%\.\s]+\))*$""", # $ Alert flags=re.U ) diff --git a/python/ql/test/query-tests/Security/CWE-730-ReDoS/ReDoS.qlref b/python/ql/test/query-tests/Security/CWE-730-ReDoS/ReDoS.qlref index 4c19d395edb..2cc0b9cb67c 100644 --- a/python/ql/test/query-tests/Security/CWE-730-ReDoS/ReDoS.qlref +++ b/python/ql/test/query-tests/Security/CWE-730-ReDoS/ReDoS.qlref @@ -1 +1,2 @@ -Security/CWE-730/ReDoS.ql +query: Security/CWE-730/ReDoS.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Security/CWE-730-ReDoS/redos.py b/python/ql/test/query-tests/Security/CWE-730-ReDoS/redos.py index 4aad94021e4..736bb5a936e 100644 --- a/python/ql/test/query-tests/Security/CWE-730-ReDoS/redos.py +++ b/python/ql/test/query-tests/Security/CWE-730-ReDoS/redos.py @@ -3,7 +3,7 @@ import re # NOT GOOD; attack: "_" + "__".repeat(100) # Adapted from marked (https://github.com/markedjs/marked), which is licensed # under the MIT license; see file marked-LICENSE. -bad1 = re.compile(r'''^\b_((?:__|[\s\S])+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)''') +bad1 = re.compile(r'''^\b_((?:__|[\s\S])+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)''') # $ Alert # GOOD # Adapted from marked (https://github.com/markedjs/marked), which is licensed @@ -18,7 +18,7 @@ good2 = re.compile(r'(.*,)+.+') # NOT GOOD; attack: " '" + "\\\\".repeat(100) # Adapted from CodeMirror (https://github.com/codemirror/codemirror), # which is licensed under the MIT license; see file CodeMirror-LICENSE. -bad2 = re.compile(r'''^(?:\s+(?:"(?:[^"\\]|\\\\|\\.)+"|'(?:[^'\\]|\\\\|\\.)+'|\((?:[^)\\]|\\\\|\\.)+\)))?''') +bad2 = re.compile(r'''^(?:\s+(?:"(?:[^"\\]|\\\\|\\.)+"|'(?:[^'\\]|\\\\|\\.)+'|\((?:[^)\\]|\\\\|\\.)+\)))?''') # $ Alert # GOOD # Adapted from lulucms2 (https://github.com/yiifans/lulucms2). @@ -30,53 +30,53 @@ good2 = re.compile(r'''\(\*(?:[\s\S]*?\(\*[\s\S]*?\*\))*[\s\S]*?\*\)''') good3 = re.compile(r'''^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*''') # NOT GOOD, variant of good3; attack: "a|\n:|\n" + "||\n".repeat(100) -bad4 = re.compile(r'''^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)a''') +bad4 = re.compile(r'''^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)a''') # $ Alert # NOT GOOD; attack: "/" + "\\/a".repeat(100) # Adapted from ANodeBlog (https://github.com/gefangshuai/ANodeBlog), # which is licensed under the Apache License 2.0; see file ANodeBlog-LICENSE. -bad5 = re.compile(r'''\/(?![ *])(\\\/|.)*?\/[gim]*(?=\W|$)''') +bad5 = re.compile(r'''\/(?![ *])(\\\/|.)*?\/[gim]*(?=\W|$)''') # $ Alert # NOT GOOD; attack: "##".repeat(100) + "\na" # Adapted from CodeMirror (https://github.com/codemirror/codemirror), # which is licensed under the MIT license; see file CodeMirror-LICENSE. -bad6 = re.compile(r'''^([\s\[\{\(]|#.*)*$''') +bad6 = re.compile(r'''^([\s\[\{\(]|#.*)*$''') # $ Alert # GOOD good4 = re.compile(r'''(\r\n|\r|\n)+''') # BAD - PoC: `node -e "/((?:[^\"\']|\".*?\"|\'.*?\')*?)([(,)]|$)/.test(\"'''''''''''''''''''''''''''''''''''''''''''''\\\"\");"`. It's complicated though, because the regexp still matches something, it just matches the empty-string after the attack string. -actuallyBad = re.compile(r'''((?:[^"']|".*?"|'.*?')*?)([(,)]|$)''') +actuallyBad = re.compile(r'''((?:[^"']|".*?"|'.*?')*?)([(,)]|$)''') # $ Alert # NOT GOOD; attack: "a" + "[]".repeat(100) + ".b\n" # Adapted from Knockout (https://github.com/knockout/knockout), which is # licensed under the MIT license; see file knockout-LICENSE -bad6 = re.compile(r'''^[\_$a-z][\_$a-z0-9]*(\[.*?\])*(\.[\_$a-z][\_$a-z0-9]*(\[.*?\])*)*$''') +bad6 = re.compile(r'''^[\_$a-z][\_$a-z0-9]*(\[.*?\])*(\.[\_$a-z][\_$a-z0-9]*(\[.*?\])*)*$''') # $ Alert # GOOD good6 = re.compile(r'''(a|.)*''') # Testing the NFA - only some of the below are detected. -bad7 = re.compile(r'''^([a-z]+)+$''') -bad8 = re.compile(r'''^([a-z]*)*$''') -bad9 = re.compile(r'''^([a-zA-Z0-9])(([\\-.]|[_]+)?([a-zA-Z0-9]+))*(@){1}[a-z0-9]+[.]{1}(([a-z]{2,3})|([a-z]{2,3}[.]{1}[a-z]{2,3}))$''') -bad10 = re.compile(r'''^(([a-z])+.)+[A-Z]([a-z])+$''') +bad7 = re.compile(r'''^([a-z]+)+$''') # $ Alert +bad8 = re.compile(r'''^([a-z]*)*$''') # $ Alert +bad9 = re.compile(r'''^([a-zA-Z0-9])(([\\-.]|[_]+)?([a-zA-Z0-9]+))*(@){1}[a-z0-9]+[.]{1}(([a-z]{2,3})|([a-z]{2,3}[.]{1}[a-z]{2,3}))$''') # $ Alert +bad10 = re.compile(r'''^(([a-z])+.)+[A-Z]([a-z])+$''') # $ Alert # NOT GOOD; attack: "[" + "][".repeat(100) + "]!" # Adapted from Prototype.js (https://github.com/prototypejs/prototype), which # is licensed under the MIT license; see file Prototype.js-LICENSE. -bad11 = re.compile(r'''(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)''') +bad11 = re.compile(r'''(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)''') # $ Alert # NOT GOOD; attack: "'" + "\\a".repeat(100) + '"' # Adapted from Prism (https://github.com/PrismJS/prism), which is licensed # under the MIT license; see file Prism-LICENSE. -bad12 = re.compile(r'''("|')(\\?.)*?\1''') +bad12 = re.compile(r'''("|')(\\?.)*?\1''') # $ Alert # NOT GOOD -bad13 = re.compile(r'''(b|a?b)*c''') +bad13 = re.compile(r'''(b|a?b)*c''') # $ Alert # NOT GOOD -bad15 = re.compile(r'''(a|aa?)*b''') +bad15 = re.compile(r'''(a|aa?)*b''') # $ Alert # GOOD good7 = re.compile(r'''(.|\n)*!''') @@ -88,31 +88,31 @@ bad16 = re.compile(r'''(.|\n)*!''') good8 = re.compile(r'''([\w.]+)*''') # NOT GOOD -bad17 = re.compile(r'''(a|aa?)*b''') +bad17 = re.compile(r'''(a|aa?)*b''') # $ Alert # GOOD - not used as regexp good9 = '(a|aa?)*b' # NOT GOOD -bad18 = re.compile(r'''(([\s\S]|[^a])*)"''') +bad18 = re.compile(r'''(([\s\S]|[^a])*)"''') # $ Alert # GOOD - there is no witness in the end that could cause the regexp to not match good10 = re.compile(r'''([^"']+)*''') # NOT GOOD -bad20 = re.compile(r'''((.|[^a])*)"''') +bad20 = re.compile(r'''((.|[^a])*)"''') # $ Alert # GOOD good10 = re.compile(r'''((a|[^a])*)"''') # NOT GOOD -bad21 = re.compile(r'''((b|[^a])*)"''') +bad21 = re.compile(r'''((b|[^a])*)"''') # $ Alert # NOT GOOD -bad22 = re.compile(r'''((G|[^a])*)"''') +bad22 = re.compile(r'''((G|[^a])*)"''') # $ Alert # NOT GOOD -bad23 = re.compile(r'''(([0-9]|[^a])*)"''') +bad23 = re.compile(r'''(([0-9]|[^a])*)"''') # $ Alert # NOT GOOD bad24 = re.compile(r'''(?:=(?:([!#\$%&'\*\+\-\.\^_`\|~0-9A-Za-z]+)|"((?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"])*)"))?''') @@ -124,55 +124,55 @@ bad25 = re.compile(r'''"((?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"])*)"''') bad26 = re.compile(r'''"((?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"\\])*)"''') # NOT GOOD -bad27 = re.compile(r'''(([a-z]|[d-h])*)"''') +bad27 = re.compile(r'''(([a-z]|[d-h])*)"''') # $ Alert # NOT GOOD -bad27 = re.compile(r'''(([^a-z]|[^0-9])*)"''') +bad27 = re.compile(r'''(([^a-z]|[^0-9])*)"''') # $ Alert # NOT GOOD -bad28 = re.compile(r'''((\d|[0-9])*)"''') +bad28 = re.compile(r'''((\d|[0-9])*)"''') # $ Alert # NOT GOOD -bad29 = re.compile(r'''((\s|\s)*)"''') +bad29 = re.compile(r'''((\s|\s)*)"''') # $ Alert # NOT GOOD -bad30 = re.compile(r'''((\w|G)*)"''') +bad30 = re.compile(r'''((\w|G)*)"''') # $ Alert # GOOD good11 = re.compile(r'''((\s|\d)*)"''') # NOT GOOD -bad31 = re.compile(r'''((\d|\w)*)"''') +bad31 = re.compile(r'''((\d|\w)*)"''') # $ Alert # NOT GOOD -bad32 = re.compile(r'''((\d|5)*)"''') +bad32 = re.compile(r'''((\d|5)*)"''') # $ Alert # NOT GOOD -bad33 = re.compile(r'''((\s|[\f])*)"''') +bad33 = re.compile(r'''((\s|[\f])*)"''') # $ Alert # NOT GOOD -bad34 = re.compile(r'''((\s|[\v]|\\v)*)"''') +bad34 = re.compile(r'''((\s|[\v]|\\v)*)"''') # $ Alert # NOT GOOD -bad35 = re.compile(r'''((\f|[\f])*)"''') +bad35 = re.compile(r'''((\f|[\f])*)"''') # $ Alert # NOT GOOD -bad36 = re.compile(r'''((\W|\D)*)"''') +bad36 = re.compile(r'''((\W|\D)*)"''') # $ Alert # NOT GOOD -bad37 = re.compile(r'''((\S|\w)*)"''') +bad37 = re.compile(r'''((\S|\w)*)"''') # $ Alert # NOT GOOD -bad38 = re.compile(r'''((\S|[\w])*)"''') +bad38 = re.compile(r'''((\S|[\w])*)"''') # $ Alert # NOT GOOD -bad39 = re.compile(r'''((1s|[\da-z])*)"''') +bad39 = re.compile(r'''((1s|[\da-z])*)"''') # $ Alert # NOT GOOD -bad40 = re.compile(r'''((0|[\d])*)"''') +bad40 = re.compile(r'''((0|[\d])*)"''') # $ Alert # NOT GOOD -bad41 = re.compile(r'''(([\d]+)*)"''') +bad41 = re.compile(r'''(([\d]+)*)"''') # $ Alert # GOOD - there is no witness in the end that could cause the regexp to not match good12 = re.compile(r'''(\d+(X\d+)?)+''') @@ -184,49 +184,49 @@ good13 = re.compile(r'''([0-9]+(X[0-9]*)?)*''') good15 = re.compile(r'''^([^>]+)*(>|$)''') # NOT GOOD -bad43 = re.compile(r'''^([^>a]+)*(>|$)''') +bad43 = re.compile(r'''^([^>a]+)*(>|$)''') # $ Alert # NOT GOOD -bad44 = re.compile(r'''(\n\s*)+$''') +bad44 = re.compile(r'''(\n\s*)+$''') # $ Alert # NOT GOOD -bad45 = re.compile(r'''^(?:\s+|#.*|\(\?#[^)]*\))*(?:[?*+]|{\d+(?:,\d*)?})''') +bad45 = re.compile(r'''^(?:\s+|#.*|\(\?#[^)]*\))*(?:[?*+]|{\d+(?:,\d*)?})''') # $ Alert # NOT GOOD -bad46 = re.compile(r'''\{\[\s*([a-zA-Z]+)\(([a-zA-Z]+)\)((\s*([a-zA-Z]+)\: ?([ a-zA-Z{}]+),?)+)*\s*\]\}''') +bad46 = re.compile(r'''\{\[\s*([a-zA-Z]+)\(([a-zA-Z]+)\)((\s*([a-zA-Z]+)\: ?([ a-zA-Z{}]+),?)+)*\s*\]\}''') # $ Alert # NOT GOOD -bad47 = re.compile(r'''(a+|b+|c+)*c''') +bad47 = re.compile(r'''(a+|b+|c+)*c''') # $ Alert # NOT GOOD -bad48 = re.compile(r'''(((a+a?)*)+b+)''') +bad48 = re.compile(r'''(((a+a?)*)+b+)''') # $ Alert # NOT GOOD -bad49 = re.compile(r'''(a+)+bbbb''') +bad49 = re.compile(r'''(a+)+bbbb''') # $ Alert # GOOD good16 = re.compile(r'''(a+)+aaaaa*a+''') # NOT GOOD -bad50 = re.compile(r'''(a+)+aaaaa$''') +bad50 = re.compile(r'''(a+)+aaaaa$''') # $ Alert # GOOD good17 = re.compile(r'''(\n+)+\n\n''') # NOT GOOD -bad51 = re.compile(r'''(\n+)+\n\n$''') +bad51 = re.compile(r'''(\n+)+\n\n$''') # $ Alert # NOT GOOD -bad52 = re.compile(r'''([^X]+)*$''') +bad52 = re.compile(r'''([^X]+)*$''') # $ Alert # NOT GOOD -bad53 = re.compile(r'''(([^X]b)+)*$''') +bad53 = re.compile(r'''(([^X]b)+)*$''') # $ Alert # GOOD good18 = re.compile(r'''(([^X]b)+)*($|[^X]b)''') # NOT GOOD -bad54 = re.compile(r'''(([^X]b)+)*($|[^X]c)''') +bad54 = re.compile(r'''(([^X]b)+)*($|[^X]c)''') # $ Alert # GOOD good20 = re.compile(r'''((ab)+)*ababab''') @@ -238,13 +238,13 @@ good21 = re.compile(r'''((ab)+)*abab(ab)*(ab)+''') good22 = re.compile(r'''((ab)+)*''') # NOT GOOD -bad55 = re.compile(r'''((ab)+)*$''') +bad55 = re.compile(r'''((ab)+)*$''') # $ Alert # GOOD good23 = re.compile(r'''((ab)+)*[a1][b1][a2][b2][a3][b3]''') # NOT GOOD -bad56 = re.compile(r'''([\n\s]+)*(.)''') +bad56 = re.compile(r'''([\n\s]+)*(.)''') # $ Alert # GOOD - any witness passes through the accept state. good24 = re.compile(r'''(A*A*X)*''') @@ -253,76 +253,76 @@ good24 = re.compile(r'''(A*A*X)*''') good26 = re.compile(r'''([^\\\]]+)*''') # NOT GOOD -bad59 = re.compile(r'''(\w*foobarbaz\w*foobarbaz\w*foobarbaz\w*foobarbaz\s*foobarbaz\d*foobarbaz\w*)+-''') +bad59 = re.compile(r'''(\w*foobarbaz\w*foobarbaz\w*foobarbaz\w*foobarbaz\s*foobarbaz\d*foobarbaz\w*)+-''') # $ Alert # NOT GOOD -bad60 = re.compile(r'''(.thisisagoddamnlongstringforstresstestingthequery|\sthisisagoddamnlongstringforstresstestingthequery)*-''') +bad60 = re.compile(r'''(.thisisagoddamnlongstringforstresstestingthequery|\sthisisagoddamnlongstringforstresstestingthequery)*-''') # $ Alert # NOT GOOD -bad61 = re.compile(r'''(thisisagoddamnlongstringforstresstestingthequery|this\w+query)*-''') +bad61 = re.compile(r'''(thisisagoddamnlongstringforstresstestingthequery|this\w+query)*-''') # $ Alert # GOOD good27 = re.compile(r'''(thisisagoddamnlongstringforstresstestingthequery|imanotherbutunrelatedstringcomparedtotheotherstring)*-''') # GOOD (but false positive caused by the extractor converting all four unpaired surrogates to \uFFFD) -good28 = re.compile('''foo([\uDC66\uDC67]|[\uDC68\uDC69])*foo''') +good28 = re.compile('''foo([\uDC66\uDC67]|[\uDC68\uDC69])*foo''') # $ Alert # GOOD (but false positive caused by the extractor converting all four unpaired surrogates to \uFFFD) -good29 = re.compile('''foo((\uDC66|\uDC67)|(\uDC68|\uDC69))*foo''') +good29 = re.compile('''foo((\uDC66|\uDC67)|(\uDC68|\uDC69))*foo''') # $ Alert # NOT GOOD (but cannot currently construct a prefix) -bad62 = re.compile(r'''a{2,3}(b+)+X''') +bad62 = re.compile(r'''a{2,3}(b+)+X''') # $ Alert # NOT GOOD (and a good prefix test) -bad63 = re.compile(r'''^<(\w+)((?:\s+\w+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>''') +bad63 = re.compile(r'''^<(\w+)((?:\s+\w+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>''') # $ Alert # GOOD good30 = re.compile(r'''(a+)*[\s\S][\s\S][\s\S]?''') # GOOD - but we fail to see that repeating the attack string ends in the "accept any" state (due to not parsing the range `[\s\S]{2,3}`). -good31 = re.compile(r'''(a+)*[\s\S]{2,3}''') +good31 = re.compile(r'''(a+)*[\s\S]{2,3}''') # $ Alert # GOOD - but we spuriously conclude that a rejecting suffix exists (due to not parsing the range `[\s\S]{2,}` when constructing the NFA). -good32 = re.compile(r'''(a+)*([\s\S]{2,}|X)$''') +good32 = re.compile(r'''(a+)*([\s\S]{2,}|X)$''') # $ Alert # GOOD good33 = re.compile(r'''(a+)*([\s\S]*|X)$''') # NOT GOOD -bad64 = re.compile(r'''((a+)*$|[\s\S]+)''') +bad64 = re.compile(r'''((a+)*$|[\s\S]+)''') # $ Alert # GOOD - but still flagged. The only change compared to the above is the order of alternatives, which we don't model. -good34 = re.compile(r'''([\s\S]+|(a+)*$)''') +good34 = re.compile(r'''([\s\S]+|(a+)*$)''') # $ Alert # GOOD good35 = re.compile(r'''((;|^)a+)+$''') # NOT GOOD (a good prefix test) -bad65 = re.compile(r'''(^|;)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(e+)+f''') +bad65 = re.compile(r'''(^|;)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(e+)+f''') # $ Alert # NOT GOOD -bad66 = re.compile(r'''^ab(c+)+$''') +bad66 = re.compile(r'''^ab(c+)+$''') # $ Alert # NOT GOOD -bad67 = re.compile(r'''(\d(\s+)*){20}''') +bad67 = re.compile(r'''(\d(\s+)*){20}''') # $ Alert # GOOD - but we spuriously conclude that a rejecting suffix exists. -good36 = re.compile(r'''(([^/]|X)+)(\/[\s\S]*)*$''') +good36 = re.compile(r'''(([^/]|X)+)(\/[\s\S]*)*$''') # $ Alert # GOOD - but we spuriously conclude that a rejecting suffix exists. -good37 = re.compile(r'''^((x([^Y]+)?)*(Y|$))''') +good37 = re.compile(r'''^((x([^Y]+)?)*(Y|$))''') # $ Alert # NOT GOOD -bad68 = re.compile(r'''(a*)+b''') +bad68 = re.compile(r'''(a*)+b''') # $ Alert # NOT GOOD -bad69 = re.compile(r'''foo([\w-]*)+bar''') +bad69 = re.compile(r'''foo([\w-]*)+bar''') # $ Alert # NOT GOOD -bad70 = re.compile(r'''((ab)*)+c''') +bad70 = re.compile(r'''((ab)*)+c''') # $ Alert # NOT GOOD -bad71 = re.compile(r'''(a?a?)*b''') +bad71 = re.compile(r'''(a?a?)*b''') # $ Alert # GOOD good38 = re.compile(r'''(a?)*b''') @@ -331,44 +331,44 @@ good38 = re.compile(r'''(a?)*b''') bad72 = re.compile(r'''(c?a?)*b''') # NOT GOOD -bad73 = re.compile(r'''(?:a|a?)+b''') +bad73 = re.compile(r'''(?:a|a?)+b''') # $ Alert # NOT GOOD - but not detected. bad74 = re.compile(r'''(a?b?)*$''') # NOT GOOD -bad76 = re.compile(r'''PRE(([a-c]|[c-d])T(e?e?e?e?|X))+(cTcT|cTXcTX$)''') +bad76 = re.compile(r'''PRE(([a-c]|[c-d])T(e?e?e?e?|X))+(cTcT|cTXcTX$)''') # $ Alert # NOT GOOD - but not detected -bad77 = re.compile(r'''^((a)+\w)+$''') +bad77 = re.compile(r'''^((a)+\w)+$''') # $ Alert # NOT GOOD -bad78 = re.compile(r'''^(b+.)+$''') +bad78 = re.compile(r'''^(b+.)+$''') # $ Alert # GOOD good39 = re.compile(r'''a*b''') # All 4 bad combinations of nested * and + -bad79 = re.compile(r'''(a*)*b''') -bad80 = re.compile(r'''(a+)*b''') -bad81 = re.compile(r'''(a*)+b''') -bad82 = re.compile(r'''(a+)+b''') +bad79 = re.compile(r'''(a*)*b''') # $ Alert +bad80 = re.compile(r'''(a+)*b''') # $ Alert +bad81 = re.compile(r'''(a*)+b''') # $ Alert +bad82 = re.compile(r'''(a+)+b''') # $ Alert # GOOD good40 = re.compile(r'''(a|b)+''') good41 = re.compile(r'''(?:[\s;,"'<>(){}|[\]@=+*]|:(?![/\\]))+''') # parses wrongly, sees column 42 as a char set start # NOT GOOD -bad83 = re.compile(r'''^((?:a{|-)|\w\{)+X$''') -bad84 = re.compile(r'''^((?:a{0|-)|\w\{\d)+X$''') -bad85 = re.compile(r'''^((?:a{0,|-)|\w\{\d,)+X$''') -bad86 = re.compile(r'''^((?:a{0,2|-)|\w\{\d,\d)+X$''') +bad83 = re.compile(r'''^((?:a{|-)|\w\{)+X$''') # $ Alert +bad84 = re.compile(r'''^((?:a{0|-)|\w\{\d)+X$''') # $ Alert +bad85 = re.compile(r'''^((?:a{0,|-)|\w\{\d,)+X$''') # $ Alert +bad86 = re.compile(r'''^((?:a{0,2|-)|\w\{\d,\d)+X$''') # $ Alert # GOOD: good42 = re.compile(r'''^((?:a{0,2}|-)|\w\{\d,\d\})+X$''') # NOT GOOD -bad87 = re.compile(r'X(\u0061|a)*Y') +bad87 = re.compile(r'X(\u0061|a)*Y') # $ Alert # GOOD good43 = re.compile(r'X(\u0061|b)+Y') @@ -377,17 +377,17 @@ good43 = re.compile(r'X(\u0061|b)+Y') good44 = re.compile(r'("[^"]*?"|[^"\s]+)+(?=\s*|\s*$)') # BAD -bad88 = re.compile(r'/("[^"]*?"|[^"\s]+)+(?=\s*|\s*$)X') -bad89 = re.compile(r'/("[^"]*?"|[^"\s]+)+(?=X)') +bad88 = re.compile(r'/("[^"]*?"|[^"\s]+)+(?=\s*|\s*$)X') # $ Alert +bad89 = re.compile(r'/("[^"]*?"|[^"\s]+)+(?=X)') # $ Alert # BAD -bad90 = re.compile(r'\A(\d|0)*x') -bad91 = re.compile(r'(\d|0)*\Z') -bad92 = re.compile(r'\b(\d|0)*x') +bad90 = re.compile(r'\A(\d|0)*x') # $ Alert +bad91 = re.compile(r'(\d|0)*\Z') # $ Alert +bad92 = re.compile(r'\b(\d|0)*x') # $ Alert # GOOD stress1 = re.compile(r"(? x ) }" results = posts.map_reduce( - mapper, # $ result=BAD + mapper, # $ Alert result=BAD reducer, # $ result=OK "results") # Use `" | "a" === "a` as author diff --git a/python/ql/test/query-tests/Security/CWE-943-NoSqlInjection/flask_mongoengine_bad.py b/python/ql/test/query-tests/Security/CWE-943-NoSqlInjection/flask_mongoengine_bad.py index 098611adce4..276d2687ee3 100644 --- a/python/ql/test/query-tests/Security/CWE-943-NoSqlInjection/flask_mongoengine_bad.py +++ b/python/ql/test/query-tests/Security/CWE-943-NoSqlInjection/flask_mongoengine_bad.py @@ -1,4 +1,4 @@ -from flask import Flask, request +from flask import Flask, request # $ Source from flask_mongoengine import MongoEngine import json @@ -19,7 +19,7 @@ def subclass_objects(): unsafe_search = request.args['search'] json_search = json.loads(unsafe_search) - return Movie.objects(__raw__=json_search) # $ result=BAD + return Movie.objects(__raw__=json_search) # $ Alert result=BAD @app.route("/get_db_find") def get_db_find(): @@ -27,7 +27,7 @@ def get_db_find(): json_search = json.loads(unsafe_search) retrieved_db = db.get_db() - return retrieved_db["Movie"].find({'name': json_search}) # $ result=BAD + return retrieved_db["Movie"].find({'name': json_search}) # $ Alert result=BAD # if __name__ == "__main__": # app.run(debug=True) diff --git a/python/ql/test/query-tests/Security/CWE-943-NoSqlInjection/flask_pymongo_bad.py b/python/ql/test/query-tests/Security/CWE-943-NoSqlInjection/flask_pymongo_bad.py index e9799c055dd..f09ea224bf3 100644 --- a/python/ql/test/query-tests/Security/CWE-943-NoSqlInjection/flask_pymongo_bad.py +++ b/python/ql/test/query-tests/Security/CWE-943-NoSqlInjection/flask_pymongo_bad.py @@ -1,4 +1,4 @@ -from flask import Flask, request +from flask import Flask, request # $ Source from flask_pymongo import PyMongo import json @@ -11,7 +11,7 @@ def home_page(): unsafe_search = request.args['search'] json_search = json.loads(unsafe_search) - return mongo.db.user.find({'name': json_search}) # $ result=BAD + return mongo.db.user.find({'name': json_search}) # $ Alert result=BAD # if __name__ == "__main__": # app.run(debug=True) diff --git a/python/ql/test/query-tests/Security/CWE-943-NoSqlInjection/mongoengine_bad.py b/python/ql/test/query-tests/Security/CWE-943-NoSqlInjection/mongoengine_bad.py index 7ad4323bba9..793460b1f00 100644 --- a/python/ql/test/query-tests/Security/CWE-943-NoSqlInjection/mongoengine_bad.py +++ b/python/ql/test/query-tests/Security/CWE-943-NoSqlInjection/mongoengine_bad.py @@ -1,4 +1,4 @@ -from flask import Flask, request +from flask import Flask, request # $ Source import mongoengine as me from mongoengine.connection import get_db, connect import json @@ -19,7 +19,7 @@ def connect_find(): json_search = json.loads(unsafe_search) db = me.connect('mydb') - return db.movie.find({'name': json_search}) # $ result=BAD + return db.movie.find({'name': json_search}) # $ Alert result=BAD @app.route("/connection_connect_find") def connection_connect_find(): @@ -27,7 +27,7 @@ def connection_connect_find(): json_search = json.loads(unsafe_search) db = connect('mydb') - return db.movie.find({'name': json_search}) # $ result=BAD + return db.movie.find({'name': json_search}) # $ Alert result=BAD @app.route("/get_db_find") def get_db_find(): @@ -35,7 +35,7 @@ def get_db_find(): json_search = json.loads(unsafe_search) db = me.get_db() - return db.movie.find({'name': json_search}) # $ result=BAD + return db.movie.find({'name': json_search}) # $ Alert result=BAD @app.route("/connection_get_db_find") def connection_get_db_find(): @@ -43,14 +43,14 @@ def connection_get_db_find(): json_search = json.loads(unsafe_search) db = get_db() - return db.movie.find({'name': json_search}) # $ result=BAD + return db.movie.find({'name': json_search}) # $ Alert result=BAD @app.route("/subclass_objects") def subclass_objects(): unsafe_search = request.args['search'] json_search = json.loads(unsafe_search) - return Movie.objects(__raw__=json_search) # $ result=BAD + return Movie.objects(__raw__=json_search) # $ Alert result=BAD @app.route("/subscript_find") def subscript_find(): @@ -58,7 +58,7 @@ def subscript_find(): json_search = json.loads(unsafe_search) db = me.connect('mydb') - return db['movie'].find({'name': json_search}) # $ result=BAD + return db['movie'].find({'name': json_search}) # $ Alert result=BAD # if __name__ == "__main__": # app.run(debug=True) diff --git a/python/ql/test/query-tests/Security/CWE-943-NoSqlInjection/pymongo_test.py b/python/ql/test/query-tests/Security/CWE-943-NoSqlInjection/pymongo_test.py index 1ba7558d287..e9c2d7a1f19 100644 --- a/python/ql/test/query-tests/Security/CWE-943-NoSqlInjection/pymongo_test.py +++ b/python/ql/test/query-tests/Security/CWE-943-NoSqlInjection/pymongo_test.py @@ -1,4 +1,4 @@ -from flask import Flask, request +from flask import Flask, request # $ Source from pymongo import MongoClient from mongosanitizer.sanitizer import sanitize import json @@ -12,7 +12,7 @@ def bad(): unsafe_search = request.args['search'] json_search = json.loads(unsafe_search) - return client.db.collection.find_one({'data': json_search}) # $ result=BAD + return client.db.collection.find_one({'data': json_search}) # $ Alert result=BAD @app.route("/good") @@ -30,7 +30,7 @@ def bad2(): client = MongoClient("localhost", 27017, maxPoolSize=50) db = client.localhost collection = db['collection'] - cursor = collection.find_one({"$where": f"this._id == '${event_id}'"}) # $ result=BAD + cursor = collection.find_one({"$where": f"this._id == '${event_id}'"}) # $ Alert result=BAD @app.route("/bad3") @@ -40,7 +40,7 @@ def bad3(): client = MongoClient("localhost", 27017, maxPoolSize=50) db = client.get_database(name="localhost") collection = db.get_collection("collection") - cursor = collection.find_one({"$where": f"this._id == '${event_id}'"}) # $ result=BAD + cursor = collection.find_one({"$where": f"this._id == '${event_id}'"}) # $ Alert result=BAD @app.route("/bad4") @@ -56,11 +56,11 @@ def bad4(): "args": [ "$event_id" ], "lang": "js" } - collection.find_one({'$expr': {'$function': search}}) # $ result=BAD + collection.find_one({'$expr': {'$function': search}}) # $ Alert result=BAD - collection.find_one({'$expr': {'$function': decoded}}) # $ result=BAD - collection.find_one({'$expr': decoded}) # $ result=BAD - collection.find_one(decoded) # $ result=BAD + collection.find_one({'$expr': {'$function': decoded}}) # $ Alert result=BAD + collection.find_one({'$expr': decoded}) # $ Alert result=BAD + collection.find_one(decoded) # $ Alert result=BAD if __name__ == "__main__": app.run(debug=True) diff --git a/python/ql/test/query-tests/Statements/ReturnOrYieldOutsideFunction/ReturnOrYieldOutsideFunction.qlref b/python/ql/test/query-tests/Statements/ReturnOrYieldOutsideFunction/ReturnOrYieldOutsideFunction.qlref index d5b2e15fc7d..6368d7f0007 100644 --- a/python/ql/test/query-tests/Statements/ReturnOrYieldOutsideFunction/ReturnOrYieldOutsideFunction.qlref +++ b/python/ql/test/query-tests/Statements/ReturnOrYieldOutsideFunction/ReturnOrYieldOutsideFunction.qlref @@ -1 +1,2 @@ -Statements/ReturnOrYieldOutsideFunction.ql \ No newline at end of file +query: Statements/ReturnOrYieldOutsideFunction.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Statements/ReturnOrYieldOutsideFunction/ReturnOrYieldOutsideFunction_test.py b/python/ql/test/query-tests/Statements/ReturnOrYieldOutsideFunction/ReturnOrYieldOutsideFunction_test.py index bc7be6e3487..8c0e6fbf2fd 100644 --- a/python/ql/test/query-tests/Statements/ReturnOrYieldOutsideFunction/ReturnOrYieldOutsideFunction_test.py +++ b/python/ql/test/query-tests/Statements/ReturnOrYieldOutsideFunction/ReturnOrYieldOutsideFunction_test.py @@ -28,36 +28,36 @@ def valid_func3(): # invalid class with return outside a function class InvalidClass1(object): if [1, 2, 3]: - return "Exists" + return "Exists" # $ Alert # invalid class with yield outside a function class InvalidClass2(object): while True: - yield 1 + yield 1 # $ Alert # invalid class with yield from outside a function class InvalidClass3(object): while True: - yield from [1, 2] + yield from [1, 2] # $ Alert # invalid statement with return outside a function for i in [1, 2, 3]: - return i + return i # $ Alert # invalid statement with yield outside a function for i in [1, 2, 3]: - yield i + yield i # $ Alert # invalid statement with yield from outside a function for i in [1, 2, 3]: - yield from i + yield from i # $ Alert # invalid statement with yield from outside a function var = [1,2,3] -yield from var +yield from var # $ Alert # invalid statement with return outside a function -return False +return False # $ Alert # invalid statement with yield outside a function -yield False \ No newline at end of file +yield False # $ Alert \ No newline at end of file diff --git a/python/ql/test/query-tests/Statements/asserts/AssertLiteralConstant.qlref b/python/ql/test/query-tests/Statements/asserts/AssertLiteralConstant.qlref index 1f301867a08..d84807e177c 100644 --- a/python/ql/test/query-tests/Statements/asserts/AssertLiteralConstant.qlref +++ b/python/ql/test/query-tests/Statements/asserts/AssertLiteralConstant.qlref @@ -1 +1,2 @@ -Statements/AssertLiteralConstant.ql +query: Statements/AssertLiteralConstant.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Statements/asserts/AssertOnTuple.qlref b/python/ql/test/query-tests/Statements/asserts/AssertOnTuple.qlref index 6fe2960c1c5..6a808f08795 100644 --- a/python/ql/test/query-tests/Statements/asserts/AssertOnTuple.qlref +++ b/python/ql/test/query-tests/Statements/asserts/AssertOnTuple.qlref @@ -1 +1,2 @@ -Statements/AssertOnTuple.ql \ No newline at end of file +query: Statements/AssertOnTuple.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Statements/asserts/SideEffectInAssert.qlref b/python/ql/test/query-tests/Statements/asserts/SideEffectInAssert.qlref index 7dd70f3fed2..bf1c1279abe 100644 --- a/python/ql/test/query-tests/Statements/asserts/SideEffectInAssert.qlref +++ b/python/ql/test/query-tests/Statements/asserts/SideEffectInAssert.qlref @@ -1 +1,2 @@ -Statements/SideEffectInAssert.ql \ No newline at end of file +query: Statements/SideEffectInAssert.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Statements/asserts/assert.py b/python/ql/test/query-tests/Statements/asserts/assert.py index e4ca2bfe2bd..a96d1aaf45d 100644 --- a/python/ql/test/query-tests/Statements/asserts/assert.py +++ b/python/ql/test/query-tests/Statements/asserts/assert.py @@ -2,10 +2,10 @@ import sys import six def _f(): - assert (yield 3) + assert (yield 3) # $ Alert[py/side-effect-in-assert] x = [ 1 ] assert len(x) #Call without side-effects - assert sys.exit(1) #Call with side-effects + assert sys.exit(1) # $ Alert[py/side-effect-in-assert] #Call with side-effects expected_types = (Response, six.text_type, six.binary_type) assert isinstance(obj, expected_types), \ "obj must be %s, not %s" % ( @@ -13,8 +13,8 @@ def _f(): type(obj).__name__) def assert_tuple(x, y): - assert () - assert (x, y) + assert () # $ Alert[py/asserts-tuple] + assert (x, y) # $ Alert[py/asserts-tuple] @@ -31,31 +31,31 @@ def assert_tuple(x, y): def error_assert_true(x): if x: - assert True, "Bad" + assert True, "Bad" # $ Alert[py/assert-literal-constant] else: - assert True + assert True # $ Alert[py/assert-literal-constant] def error_assert_false(x): if x: - assert False, "Bad" + assert False, "Bad" # $ Alert[py/assert-literal-constant] def error_assert_zero(x): if x: - assert 0, "Bad" + assert 0, "Bad" # $ Alert[py/assert-literal-constant] def error_assert_one(x): if x: - assert 1, "Bad" + assert 1, "Bad" # $ Alert[py/assert-literal-constant] def error_assert_empty_string(x): if x: - assert "", "Bad" + assert "", "Bad" # $ Alert[py/assert-literal-constant] def error_assert_nonempty_string(x): if x: - assert "X", "Bad" + assert "X", "Bad" # $ Alert[py/assert-literal-constant] else: - assert "X" + assert "X" # $ Alert[py/assert-literal-constant] def ok_assert_false(x): if x: @@ -91,7 +91,7 @@ def error_assert_in_final_branch1(x): if foo(x): pass else: - assert False, "Error" + assert False, "Error" # $ Alert[py/assert-literal-constant] def error_assert_in_intermediate_branch(x): if foo(x): @@ -99,7 +99,7 @@ def error_assert_in_intermediate_branch(x): elif bar(x): pass elif quux(x): - assert False, "Error" + assert False, "Error" # $ Alert[py/assert-literal-constant] elif yks(x): pass else: diff --git a/python/ql/test/query-tests/Statements/asserts/side_effect.py b/python/ql/test/query-tests/Statements/asserts/side_effect.py index 42b9f0a16a2..0922a4385da 100644 --- a/python/ql/test/query-tests/Statements/asserts/side_effect.py +++ b/python/ql/test/query-tests/Statements/asserts/side_effect.py @@ -2,4 +2,4 @@ # messes up the results of the refers-to/points-to analysis # see /home/rasmus/code/ql/python/ql/test/library-tests/PointsTo/regressions/subprocess-assert/mwe_failure.py import subprocess -assert subprocess.call(['run-backup']) == 0 +assert subprocess.call(['run-backup']) == 0 # $ Alert[py/side-effect-in-assert] diff --git a/python/ql/test/query-tests/Statements/exit/UseOfExit.qlref b/python/ql/test/query-tests/Statements/exit/UseOfExit.qlref index 5925d933914..191e4572f18 100644 --- a/python/ql/test/query-tests/Statements/exit/UseOfExit.qlref +++ b/python/ql/test/query-tests/Statements/exit/UseOfExit.qlref @@ -1 +1,2 @@ -Statements/UseOfExit.ql +query: Statements/UseOfExit.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Statements/exit/test.py b/python/ql/test/query-tests/Statements/exit/test.py index ae03479497e..5ef557453ab 100644 --- a/python/ql/test/query-tests/Statements/exit/test.py +++ b/python/ql/test/query-tests/Statements/exit/test.py @@ -4,4 +4,4 @@ def main(): process() except Exception as ex: print(ex) - exit(1) + exit(1) # $ Alert diff --git a/python/ql/test/query-tests/Statements/general/BreakOrReturnInFinally.qlref b/python/ql/test/query-tests/Statements/general/BreakOrReturnInFinally.qlref index 0a710cdde9c..e5c72eadbba 100644 --- a/python/ql/test/query-tests/Statements/general/BreakOrReturnInFinally.qlref +++ b/python/ql/test/query-tests/Statements/general/BreakOrReturnInFinally.qlref @@ -1 +1,2 @@ -Statements/BreakOrReturnInFinally.ql \ No newline at end of file +query: Statements/BreakOrReturnInFinally.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Statements/general/C_StyleParentheses.qlref b/python/ql/test/query-tests/Statements/general/C_StyleParentheses.qlref index 6af1d43f7c6..c618ebb3c4e 100644 --- a/python/ql/test/query-tests/Statements/general/C_StyleParentheses.qlref +++ b/python/ql/test/query-tests/Statements/general/C_StyleParentheses.qlref @@ -1 +1,2 @@ -Statements/C_StyleParentheses.ql \ No newline at end of file +query: Statements/C_StyleParentheses.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Statements/general/ConstantInConditional.qlref b/python/ql/test/query-tests/Statements/general/ConstantInConditional.qlref index c4b9b9a555b..f922d141527 100644 --- a/python/ql/test/query-tests/Statements/general/ConstantInConditional.qlref +++ b/python/ql/test/query-tests/Statements/general/ConstantInConditional.qlref @@ -1 +1,2 @@ -Statements/ConstantInConditional.ql +query: Statements/ConstantInConditional.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Statements/general/ModificationOfLocals.qlref b/python/ql/test/query-tests/Statements/general/ModificationOfLocals.qlref index 88a666435e3..6069d2ec17f 100644 --- a/python/ql/test/query-tests/Statements/general/ModificationOfLocals.qlref +++ b/python/ql/test/query-tests/Statements/general/ModificationOfLocals.qlref @@ -1 +1,2 @@ -Statements/ModificationOfLocals.ql +query: Statements/ModificationOfLocals.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Statements/general/NestedLoopsSameVariable.qlref b/python/ql/test/query-tests/Statements/general/NestedLoopsSameVariable.qlref index 75a4032a05f..a8d6bf7f167 100644 --- a/python/ql/test/query-tests/Statements/general/NestedLoopsSameVariable.qlref +++ b/python/ql/test/query-tests/Statements/general/NestedLoopsSameVariable.qlref @@ -1 +1,2 @@ -Statements/NestedLoopsSameVariable.ql +query: Statements/NestedLoopsSameVariable.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Statements/general/NestedLoopsSameVariableWithReuse.qlref b/python/ql/test/query-tests/Statements/general/NestedLoopsSameVariableWithReuse.qlref index d34f2ddb21a..653624aac24 100644 --- a/python/ql/test/query-tests/Statements/general/NestedLoopsSameVariableWithReuse.qlref +++ b/python/ql/test/query-tests/Statements/general/NestedLoopsSameVariableWithReuse.qlref @@ -1 +1,2 @@ -Statements/NestedLoopsSameVariableWithReuse.ql +query: Statements/NestedLoopsSameVariableWithReuse.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Statements/general/ShouldUseWithStatement.qlref b/python/ql/test/query-tests/Statements/general/ShouldUseWithStatement.qlref index e1b3d7276ff..f918787992e 100644 --- a/python/ql/test/query-tests/Statements/general/ShouldUseWithStatement.qlref +++ b/python/ql/test/query-tests/Statements/general/ShouldUseWithStatement.qlref @@ -1 +1,2 @@ -Statements/ShouldUseWithStatement.ql +query: Statements/ShouldUseWithStatement.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Statements/general/UnnecessaryDelete.qlref b/python/ql/test/query-tests/Statements/general/UnnecessaryDelete.qlref index e97bf9a872b..50bf16971e2 100644 --- a/python/ql/test/query-tests/Statements/general/UnnecessaryDelete.qlref +++ b/python/ql/test/query-tests/Statements/general/UnnecessaryDelete.qlref @@ -1 +1,2 @@ -Statements/UnnecessaryDelete.ql \ No newline at end of file +query: Statements/UnnecessaryDelete.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Statements/general/UnnecessaryElseClause.qlref b/python/ql/test/query-tests/Statements/general/UnnecessaryElseClause.qlref index 8f92883475c..5f26a74f227 100644 --- a/python/ql/test/query-tests/Statements/general/UnnecessaryElseClause.qlref +++ b/python/ql/test/query-tests/Statements/general/UnnecessaryElseClause.qlref @@ -1 +1,2 @@ -Statements/UnnecessaryElseClause.ql \ No newline at end of file +query: Statements/UnnecessaryElseClause.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Statements/general/UnnecessaryPass.qlref b/python/ql/test/query-tests/Statements/general/UnnecessaryPass.qlref index 259ad4df638..da0a6bfd4e1 100644 --- a/python/ql/test/query-tests/Statements/general/UnnecessaryPass.qlref +++ b/python/ql/test/query-tests/Statements/general/UnnecessaryPass.qlref @@ -1 +1,2 @@ -Statements/UnnecessaryPass.ql \ No newline at end of file +query: Statements/UnnecessaryPass.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Statements/general/nested.py b/python/ql/test/query-tests/Statements/general/nested.py index ac06f2974aa..57591d76c87 100644 --- a/python/ql/test/query-tests/Statements/general/nested.py +++ b/python/ql/test/query-tests/Statements/general/nested.py @@ -1,6 +1,6 @@ def f1(): for repeated_var in range(10): - for repeated_var in range(10): + for repeated_var in range(10): # $ Alert[py/nested-loops-with-same-variable-reused] Alert[py/nested-loops-with-same-variable] pass do_something(repeated_var) @@ -16,7 +16,7 @@ def f2(): def f3(y,p): for x in y: if p(y): - for x in y: + for x in y: # $ Alert[py/nested-loops-with-same-variable] good1(x) else: good2(x) @@ -24,7 +24,7 @@ def f3(y,p): def f4(y): for x in y: good1(x) - for x in y: + for x in y: # $ Alert[py/nested-loops-with-same-variable-reused] Alert[py/nested-loops-with-same-variable] good2(x) bad(x) @@ -32,14 +32,14 @@ def f5(y): for x in y: good1(x) temp = x - for x in y: + for x in y: # $ Alert[py/nested-loops-with-same-variable] good2(x) x = temp good3(x) def f6(y, f): for x in y: - for x in y: + for x in y: # $ Alert[py/nested-loops-with-same-variable] good(x) x = f(x) bad(x) @@ -47,7 +47,7 @@ def f6(y, f): def f7(y,p): for x in y: good(x) - for x in y: + for x in y: # $ Alert[py/nested-loops-with-same-variable-reused] Alert[py/nested-loops-with-same-variable] if p(x): x = 1 break diff --git a/python/ql/test/query-tests/Statements/general/statements_test.py b/python/ql/test/query-tests/Statements/general/statements_test.py index 0a74bb31c10..dd2a49abd16 100644 --- a/python/ql/test/query-tests/Statements/general/statements_test.py +++ b/python/ql/test/query-tests/Statements/general/statements_test.py @@ -2,11 +2,11 @@ #Constant in conditional def cc1(): - if True: + if True: # $ Alert[py/constant-conditional-expression] print("Hi") def cc2(): - if 3: + if 3: # $ Alert[py/constant-conditional-expression] print("Hi") def not_cc(): @@ -62,12 +62,12 @@ else: bytes = bytes # Should not be flagged #Pointless else clauses -for x in range(10): +for x in range(10): # $ Alert[py/redundant-else] func(x) else: do_something() -while x < 10: +while x < 10: # $ Alert[py/redundant-else] func(x) else: do_something() @@ -184,7 +184,7 @@ def error_indirect_mismatched_multi_assign(x): #ODASA-6754 def error_unnecessary_delete(): x = big_object() - del x + del x # $ Alert[py/unnecessary-delete] def ok_delete_in_loop(): y = 0 diff --git a/python/ql/test/query-tests/Statements/general/test.py b/python/ql/test/query-tests/Statements/general/test.py index eb38acd89b1..013f3eabc90 100644 --- a/python/ql/test/query-tests/Statements/general/test.py +++ b/python/ql/test/query-tests/Statements/general/test.py @@ -8,7 +8,7 @@ def break_in_finally(seq, x): try: x() finally: - break + break # $ Alert[py/exit-from-finally] return 0 def return_in_finally(seq, x): @@ -16,7 +16,7 @@ def return_in_finally(seq, x): try: x() finally: - return 1 + return 1 # $ Alert[py/exit-from-finally] return 0 #Break in loop in finally @@ -34,11 +34,11 @@ def return_in_loop_in_finally(f, seq): f() finally: for i in seq: - return + return # $ Alert[py/exit-from-finally] def unnecessary_pass(arg): print (arg) - pass + pass # $ Alert[py/unnecessary-pass] #Non-iterator in for loop @@ -95,12 +95,12 @@ for z in D(): def modification_of_locals(): x = 0 - locals()['x'] = 1 + locals()['x'] = 1 # $ Alert[py/modification-of-locals] l = locals() - l.update({'x':1, 'y':2}) - l.pop('y') - del l['x'] - l.clear() + l.update({'x':1, 'y':2}) # $ Alert[py/modification-of-locals] + l.pop('y') # $ Alert[py/modification-of-locals] + del l['x'] # $ Alert[py/modification-of-locals] + l.clear() # $ Alert[py/modification-of-locals] return x @@ -112,16 +112,16 @@ locals()['foo'] = 43 # technically OK #C-style things -if (cond): +if (cond): # $ Alert[py/c-style-parentheses] pass -while (cond): +while (cond): # $ Alert[py/c-style-parentheses] pass -assert (test) +assert (test) # $ Alert[py/c-style-parentheses] def parens(x): - return (x) + return (x) # $ Alert[py/c-style-parentheses] #ODASA-2038 @@ -165,7 +165,7 @@ def no_with(): f.write("Hello ") f.write(" World\n") finally: - f.close() + f.close() # $ Alert[py/should-use-with] # Should not use a 'with' statement here: the resource is held in an instance # attribute, so its lifetime spans the enclosing instance and cannot be expressed diff --git a/python/ql/test/query-tests/Statements/no_effect/UnusedExceptionObject.qlref b/python/ql/test/query-tests/Statements/no_effect/UnusedExceptionObject.qlref index ae7783be6af..84c58c0aaf0 100644 --- a/python/ql/test/query-tests/Statements/no_effect/UnusedExceptionObject.qlref +++ b/python/ql/test/query-tests/Statements/no_effect/UnusedExceptionObject.qlref @@ -1 +1,2 @@ -Statements/UnusedExceptionObject.ql +query: Statements/UnusedExceptionObject.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Statements/no_effect/test.py b/python/ql/test/query-tests/Statements/no_effect/test.py index c37c3a5a79a..45286aaea9f 100644 --- a/python/ql/test/query-tests/Statements/no_effect/test.py +++ b/python/ql/test/query-tests/Statements/no_effect/test.py @@ -124,7 +124,7 @@ def do_action_forgotten_raise(action): elif action == "stop": stop() else: - ValueError(action) + ValueError(action) # $ Alert[py/unused-exception-object] def do_action(action): if action == "go": diff --git a/python/ql/test/query-tests/Statements/unreachable/UnreachableCode.qlref b/python/ql/test/query-tests/Statements/unreachable/UnreachableCode.qlref index 5b7891f0026..b95a67d2494 100644 --- a/python/ql/test/query-tests/Statements/unreachable/UnreachableCode.qlref +++ b/python/ql/test/query-tests/Statements/unreachable/UnreachableCode.qlref @@ -1 +1,2 @@ -Statements/UnreachableCode.ql +query: Statements/UnreachableCode.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Statements/unreachable/test.py b/python/ql/test/query-tests/Statements/unreachable/test.py index 71f27798895..8ec902e002a 100755 --- a/python/ql/test/query-tests/Statements/unreachable/test.py +++ b/python/ql/test/query-tests/Statements/unreachable/test.py @@ -5,27 +5,27 @@ def f(x): while x: print (x) while 0: - asgn = unreachable() + asgn = unreachable() # $ Alert while False: - return unreachable() + return unreachable() # $ Alert while 7: print(x) def g(x): if False: - unreachable() + unreachable() # $ Alert else: reachable() print(x) return 5 - for x in first_unreachable_stmt(): + for x in first_unreachable_stmt(): # $ Alert raise more_unreachable() def h(a,b): if True: reachable() else: - unreachable() + unreachable() # $ Alert def intish(n): """"Regression test - the 'except' statement is reachable""" @@ -81,7 +81,7 @@ class Odasa3686(object): def odasa5387(): try: str - except NameError: # Unreachable 'str' is always defined + except NameError: # $ Alert # Unreachable 'str' is always defined pass try: unicode diff --git a/python/ql/test/query-tests/Statements/unreachable_nonlocal/UnreachableCode.qlref b/python/ql/test/query-tests/Statements/unreachable_nonlocal/UnreachableCode.qlref index 5b7891f0026..b95a67d2494 100644 --- a/python/ql/test/query-tests/Statements/unreachable_nonlocal/UnreachableCode.qlref +++ b/python/ql/test/query-tests/Statements/unreachable_nonlocal/UnreachableCode.qlref @@ -1 +1,2 @@ -Statements/UnreachableCode.ql +query: Statements/UnreachableCode.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Testing/ImpreciseAssert.qlref b/python/ql/test/query-tests/Testing/ImpreciseAssert.qlref index 79dc019fe79..b5172adc2c3 100644 --- a/python/ql/test/query-tests/Testing/ImpreciseAssert.qlref +++ b/python/ql/test/query-tests/Testing/ImpreciseAssert.qlref @@ -1 +1,2 @@ -Testing/ImpreciseAssert.ql +query: Testing/ImpreciseAssert.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Testing/test.py b/python/ql/test/query-tests/Testing/test.py index 1c79f177ac6..a521d0ab209 100644 --- a/python/ql/test/query-tests/Testing/test.py +++ b/python/ql/test/query-tests/Testing/test.py @@ -3,7 +3,7 @@ from unittest import TestCase class MyTest(TestCase): def test1(self): - self.assertTrue(1 == 1) - self.assertFalse(1 > 2) - self.assertTrue(1 in [1]) - self.assertFalse(0 is "") + self.assertTrue(1 == 1) # $ Alert + self.assertFalse(1 > 2) # $ Alert + self.assertTrue(1 in [1]) # $ Alert + self.assertFalse(0 is "") # $ Alert diff --git a/python/ql/test/query-tests/Variables/general/Global.qlref b/python/ql/test/query-tests/Variables/general/Global.qlref index c20333a006e..9b2b8470e10 100644 --- a/python/ql/test/query-tests/Variables/general/Global.qlref +++ b/python/ql/test/query-tests/Variables/general/Global.qlref @@ -1 +1,2 @@ -Variables/Global.ql \ No newline at end of file +query: Variables/Global.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Variables/general/GlobalAtModuleLevel.qlref b/python/ql/test/query-tests/Variables/general/GlobalAtModuleLevel.qlref index f12469499b7..9c4da1043fd 100644 --- a/python/ql/test/query-tests/Variables/general/GlobalAtModuleLevel.qlref +++ b/python/ql/test/query-tests/Variables/general/GlobalAtModuleLevel.qlref @@ -1 +1,2 @@ -Variables/GlobalAtModuleLevel.ql \ No newline at end of file +query: Variables/GlobalAtModuleLevel.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Variables/general/ShadowBuiltin.qlref b/python/ql/test/query-tests/Variables/general/ShadowBuiltin.qlref index d732a539e5f..83d2543e747 100644 --- a/python/ql/test/query-tests/Variables/general/ShadowBuiltin.qlref +++ b/python/ql/test/query-tests/Variables/general/ShadowBuiltin.qlref @@ -1 +1,2 @@ -Variables/ShadowBuiltin.ql +query: Variables/ShadowBuiltin.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Variables/general/variables_test.py b/python/ql/test/query-tests/Variables/general/variables_test.py index e623ee5244d..add95766b13 100644 --- a/python/ql/test/query-tests/Variables/general/variables_test.py +++ b/python/ql/test/query-tests/Variables/general/variables_test.py @@ -4,7 +4,7 @@ __all__ = [ 'is_used_var1' ] #Shadow Builtin def sh1(x): - len = x + 2 #Shadows + len = x + 2 # $ Alert[py/local-shadows-builtin] #Shadows len = x + 0 # no shadowing warning for 2nd def return len @@ -54,14 +54,14 @@ def func(): return is_used_var2 #Redundant global declaration -global g_x +global g_x # $ Alert[py/redundant-global-declaration] g_x = 0 #Use global def uses_global(arg): - global g_x + global g_x # $ Alert[py/use-of-global] g_x = arg use(g_x) diff --git a/python/ql/test/query-tests/Variables/multiple/MultiplyDefined.qlref b/python/ql/test/query-tests/Variables/multiple/MultiplyDefined.qlref index 293098be566..406acf779df 100644 --- a/python/ql/test/query-tests/Variables/multiple/MultiplyDefined.qlref +++ b/python/ql/test/query-tests/Variables/multiple/MultiplyDefined.qlref @@ -1 +1,2 @@ -Variables/MultiplyDefined.ql +query: Variables/MultiplyDefined.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Variables/multiple/uselesscode_test.py b/python/ql/test/query-tests/Variables/multiple/uselesscode_test.py index 49f367d6db3..4a73d87c7b0 100644 --- a/python/ql/test/query-tests/Variables/multiple/uselesscode_test.py +++ b/python/ql/test/query-tests/Variables/multiple/uselesscode_test.py @@ -1,8 +1,8 @@ #Multiple declarations -def mult(a): - x = 1 +def mult(a): # $ Alert + x = 1 # $ Alert y = a x = 2 #Need to use x, otherwise it is ignored @@ -25,7 +25,7 @@ def _double_loop(seq): for i in seq: pass -class Mult(object): +class Mult(object): # $ Alert pass @@ -49,7 +49,7 @@ def isStr(s): # 'bad' actually *is* always redefined before being read. def have_nosmp(): try: - bad = os.environ['NPY_NOSMP'] + bad = os.environ['NPY_NOSMP'] # $ Alert bad = 1 except KeyError: bad = 0 @@ -64,7 +64,7 @@ def simple_try(foo): def try_with_else(foo): try: - bad = foo.bar + bad = foo.bar # $ Alert except AttributeError: raise else: @@ -114,7 +114,7 @@ def odasa4166(cond): def odasa5315(): x, y = foo() # OK as y is used use(y) - x, y = bar() # Not OK as neither x nor y are used. + x, y = bar() # $ Alert # Not OK as neither x nor y are used. x, y = baz() # OK as both used return x + y diff --git a/python/ql/test/query-tests/Variables/unused/SuspiciousUnusedLoopIterationVariable.qlref b/python/ql/test/query-tests/Variables/unused/SuspiciousUnusedLoopIterationVariable.qlref index 4b9f136451e..4931ceb29e8 100644 --- a/python/ql/test/query-tests/Variables/unused/SuspiciousUnusedLoopIterationVariable.qlref +++ b/python/ql/test/query-tests/Variables/unused/SuspiciousUnusedLoopIterationVariable.qlref @@ -1 +1,2 @@ -Variables/SuspiciousUnusedLoopIterationVariable.ql \ No newline at end of file +query: Variables/SuspiciousUnusedLoopIterationVariable.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Variables/unused/UnusedLocalVariable.qlref b/python/ql/test/query-tests/Variables/unused/UnusedLocalVariable.qlref index bd6e5aaa069..122b9d6456f 100644 --- a/python/ql/test/query-tests/Variables/unused/UnusedLocalVariable.qlref +++ b/python/ql/test/query-tests/Variables/unused/UnusedLocalVariable.qlref @@ -1 +1,2 @@ -Variables/UnusedLocalVariable.ql +query: Variables/UnusedLocalVariable.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Variables/unused/test.py b/python/ql/test/query-tests/Variables/unused/test.py index 18dd2020306..2159bf86b6e 100644 --- a/python/ql/test/query-tests/Variables/unused/test.py +++ b/python/ql/test/query-tests/Variables/unused/test.py @@ -1,7 +1,7 @@ #Unused def fail(): - for t in [TypeA, TypeB]: + for t in [TypeA, TypeB]: # $ Alert[py/unused-loop-variable] x = TypeA() run_test(x) @@ -63,19 +63,19 @@ def OK8(seq, output): #Not OK -- Use a constant, but also a variable def fail2(sequence): for x in sequence: - for y in sequence: + for y in sequence: # $ Alert[py/unused-loop-variable] do_something(x+1) def fail3(sequence): for x in sequence: do_something(x+1) - for y in sequence: + for y in sequence: # $ Alert[py/unused-loop-variable] do_something(x+1) def fail4(coll, sequence): while coll: x = coll.pop() - for s in sequence: + for s in sequence: # $ Alert[py/unused-loop-variable] do_something(x+1) #OK See ODASA-4153 and ODASA-4533 @@ -103,7 +103,7 @@ def kwargs_is_a_use(seq): #A deletion is a use, but this is almost certainly an error def cleanup(sessions): - for sess in sessions: + for sess in sessions: # $ Alert[py/unused-loop-variable] # Original code had some comment about deleting sessions del sess diff --git a/python/ql/test/query-tests/Variables/unused/variables_test.py b/python/ql/test/query-tests/Variables/unused/variables_test.py index 611b9fbd6b2..42f8324ca56 100644 --- a/python/ql/test/query-tests/Variables/unused/variables_test.py +++ b/python/ql/test/query-tests/Variables/unused/variables_test.py @@ -26,7 +26,7 @@ def u1(x): return 0 def u2(): - x = 1 + x = 1 # $ Alert[py/unused-local-variable] return 1 #These parameters are OK due to (potential overriding) @@ -86,13 +86,13 @@ def f(t): a,b,c = t def f(t): - a,b,c = t + a,b,c = t # $ Alert[py/unused-local-variable] use(t) def second_def_undefined(): var = 0 use(var) - var = 1 # unused. + var = 1 # $ Alert[py/unused-local-variable] # unused. #And gloablly glob_var = 0 @@ -130,7 +130,7 @@ def decorated_inner_function(): #FP observed def test_dict_unpacking(queryset, field_name, value): #True positive - for tag in value.split(','): + for tag in value.split(','): # $ Alert[py/unused-loop-variable] queryset = queryset.filter(**{field_name + '__name': tag1}) return queryset #False positive diff --git a/python/ql/test/query-tests/Variables/unused_local_nonlocal/UnusedLocalVariable.qlref b/python/ql/test/query-tests/Variables/unused_local_nonlocal/UnusedLocalVariable.qlref index bd6e5aaa069..122b9d6456f 100644 --- a/python/ql/test/query-tests/Variables/unused_local_nonlocal/UnusedLocalVariable.qlref +++ b/python/ql/test/query-tests/Variables/unused_local_nonlocal/UnusedLocalVariable.qlref @@ -1 +1,2 @@ -Variables/UnusedLocalVariable.ql +query: Variables/UnusedLocalVariable.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/ql/test/query-tests/Variables/unused_local_nonlocal/variables_test.py b/python/ql/test/query-tests/Variables/unused_local_nonlocal/variables_test.py index 4986a6f4eb3..da7f7dcf7e5 100644 --- a/python/ql/test/query-tests/Variables/unused_local_nonlocal/variables_test.py +++ b/python/ql/test/query-tests/Variables/unused_local_nonlocal/variables_test.py @@ -29,7 +29,7 @@ def not_fp(): def nonlocal_test(): nonlocal test def set_test(): - test = True + test = True # $ Alert nonlocal_test() set_test() if test: diff --git a/python/ql/test/query-tests/analysis/pointsto/KeyPointsToFailure.qlref b/python/ql/test/query-tests/analysis/pointsto/KeyPointsToFailure.qlref index db945187917..bd2bce68185 100644 --- a/python/ql/test/query-tests/analysis/pointsto/KeyPointsToFailure.qlref +++ b/python/ql/test/query-tests/analysis/pointsto/KeyPointsToFailure.qlref @@ -1 +1,2 @@ -analysis/KeyPointsToFailure.ql \ No newline at end of file +query: analysis/KeyPointsToFailure.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/python/tools/recorded-call-graph-metrics/ql/lib/RecordedCalls.qll b/python/tools/recorded-call-graph-metrics/ql/lib/RecordedCalls.qll index 55015ea5998..79d01776728 100644 --- a/python/tools/recorded-call-graph-metrics/ql/lib/RecordedCalls.qll +++ b/python/tools/recorded-call-graph-metrics/ql/lib/RecordedCalls.qll @@ -238,9 +238,10 @@ module PointsToBasedCallGraph { Value calleeValue; ResolvableRecordedCall() { - exists(Call call, XmlCallee xmlCallee | + exists(Call call, XmlCallee xmlCallee, ControlFlowNode callCfg | call = this.getACall() and - calleeValue.getACall() = call.getAFlowNode() and + callCfg.getNode() = call and + calleeValue.getACall() = callCfg and xmlCallee = this.getXmlCallee() and ( xmlCallee instanceof XmlPythonCallee and diff --git a/ql/ql/src/codeql_ql/ast/internal/TreeSitter.qll b/ql/ql/src/codeql_ql/ast/internal/TreeSitter.qll index c81830e1d59..402cb23b910 100644 --- a/ql/ql/src/codeql_ql/ast/internal/TreeSitter.qll +++ b/ql/ql/src/codeql_ql/ast/internal/TreeSitter.qll @@ -1312,6 +1312,244 @@ module QL { /** Gets a field or child node of this node. */ final override AstNode getAFieldOrChild() { ql_variable_def(this, result) } } + + /** Provides predicates for mapping AST nodes to their named children. */ + module PrintAst { + /** Gets a child of `node` returned by the member predicate with the given `name`. If the predicate takes an index argument, `i` is bound to that index, otherwise `i` is `-1` (which is never a valid index). */ + AstNode getChild(AstNode node, string name, int i) { + result = node.(AddExpr).getLeft() and i = -1 and name = "getLeft" + or + result = node.(AddExpr).getRight() and i = -1 and name = "getRight" + or + result = node.(AddExpr).getChild() and i = -1 and name = "getChild" + or + result = node.(Aggregate).getChild(i) and name = "getChild" + or + result = node.(AnnotArg).getChild() and i = -1 and name = "getChild" + or + result = node.(Annotation).getArgs(i) and name = "getArgs" + or + result = node.(Annotation).getName() and i = -1 and name = "getName" + or + result = node.(AritylessPredicateExpr).getName() and i = -1 and name = "getName" + or + result = node.(AritylessPredicateExpr).getQualifier() and i = -1 and name = "getQualifier" + or + result = node.(AsExpr).getChild(i) and name = "getChild" + or + result = node.(AsExprs).getChild(i) and name = "getChild" + or + result = node.(Body).getChild() and i = -1 and name = "getChild" + or + result = node.(Bool).getChild() and i = -1 and name = "getChild" + or + result = node.(CallBody).getChild(i) and name = "getChild" + or + result = node.(CallOrUnqualAggExpr).getChild(i) and name = "getChild" + or + result = node.(Charpred).getBody() and i = -1 and name = "getBody" + or + result = node.(Charpred).getChild() and i = -1 and name = "getChild" + or + result = node.(ClassMember).getChild(i) and name = "getChild" + or + result = node.(ClasslessPredicate).getName() and i = -1 and name = "getName" + or + result = node.(ClasslessPredicate).getReturnType() and i = -1 and name = "getReturnType" + or + result = node.(ClasslessPredicate).getChild(i) and name = "getChild" + or + result = node.(CompTerm).getLeft() and i = -1 and name = "getLeft" + or + result = node.(CompTerm).getRight() and i = -1 and name = "getRight" + or + result = node.(CompTerm).getChild() and i = -1 and name = "getChild" + or + result = node.(Conjunction).getLeft() and i = -1 and name = "getLeft" + or + result = node.(Conjunction).getRight() and i = -1 and name = "getRight" + or + result = node.(Dataclass).getExtends(i) and name = "getExtends" + or + result = node.(Dataclass).getInstanceof(i) and name = "getInstanceof" + or + result = node.(Dataclass).getName() and i = -1 and name = "getName" + or + result = node.(Dataclass).getChild(i) and name = "getChild" + or + result = node.(Datatype).getName() and i = -1 and name = "getName" + or + result = node.(Datatype).getChild() and i = -1 and name = "getChild" + or + result = node.(DatatypeBranch).getName() and i = -1 and name = "getName" + or + result = node.(DatatypeBranch).getChild(i) and name = "getChild" + or + result = node.(DatatypeBranches).getChild(i) and name = "getChild" + or + result = node.(Disjunction).getLeft() and i = -1 and name = "getLeft" + or + result = node.(Disjunction).getRight() and i = -1 and name = "getRight" + or + result = node.(ExprAggregateBody).getAsExprs() and i = -1 and name = "getAsExprs" + or + result = node.(ExprAggregateBody).getOrderBys() and i = -1 and name = "getOrderBys" + or + result = node.(ExprAnnotation).getAnnotArg() and i = -1 and name = "getAnnotArg" + or + result = node.(ExprAnnotation).getName() and i = -1 and name = "getName" + or + result = node.(ExprAnnotation).getChild() and i = -1 and name = "getChild" + or + result = node.(Field).getChild() and i = -1 and name = "getChild" + or + result = node.(FullAggregateBody).getAsExprs() and i = -1 and name = "getAsExprs" + or + result = node.(FullAggregateBody).getGuard() and i = -1 and name = "getGuard" + or + result = node.(FullAggregateBody).getOrderBys() and i = -1 and name = "getOrderBys" + or + result = node.(FullAggregateBody).getChild(i) and name = "getChild" + or + result = node.(HigherOrderTerm).getName() and i = -1 and name = "getName" + or + result = node.(HigherOrderTerm).getChild(i) and name = "getChild" + or + result = node.(IfTerm).getCond() and i = -1 and name = "getCond" + or + result = node.(IfTerm).getFirst() and i = -1 and name = "getFirst" + or + result = node.(IfTerm).getSecond() and i = -1 and name = "getSecond" + or + result = node.(Implication).getLeft() and i = -1 and name = "getLeft" + or + result = node.(Implication).getRight() and i = -1 and name = "getRight" + or + result = node.(ImportDirective).getChild(i) and name = "getChild" + or + result = node.(ImportModuleExpr).getQualName(i) and name = "getQualName" + or + result = node.(ImportModuleExpr).getChild() and i = -1 and name = "getChild" + or + result = node.(InExpr).getLeft() and i = -1 and name = "getLeft" + or + result = node.(InExpr).getRight() and i = -1 and name = "getRight" + or + result = node.(InstanceOf).getChild(i) and name = "getChild" + or + result = node.(Literal).getChild() and i = -1 and name = "getChild" + or + result = node.(MemberPredicate).getName() and i = -1 and name = "getName" + or + result = node.(MemberPredicate).getReturnType() and i = -1 and name = "getReturnType" + or + result = node.(MemberPredicate).getChild(i) and name = "getChild" + or + result = node.(Module).getImplements(i) and name = "getImplements" + or + result = node.(Module).getName() and i = -1 and name = "getName" + or + result = node.(Module).getParameter(i) and name = "getParameter" + or + result = node.(Module).getChild(i) and name = "getChild" + or + result = node.(ModuleAliasBody).getChild() and i = -1 and name = "getChild" + or + result = node.(ModuleExpr).getName() and i = -1 and name = "getName" + or + result = node.(ModuleExpr).getChild() and i = -1 and name = "getChild" + or + result = node.(ModuleInstantiation).getName() and i = -1 and name = "getName" + or + result = node.(ModuleInstantiation).getChild(i) and name = "getChild" + or + result = node.(ModuleMember).getChild(i) and name = "getChild" + or + result = node.(ModuleName).getChild() and i = -1 and name = "getChild" + or + result = node.(ModuleParam).getParameter() and i = -1 and name = "getParameter" + or + result = node.(ModuleParam).getSignature() and i = -1 and name = "getSignature" + or + result = node.(MulExpr).getLeft() and i = -1 and name = "getLeft" + or + result = node.(MulExpr).getRight() and i = -1 and name = "getRight" + or + result = node.(MulExpr).getChild() and i = -1 and name = "getChild" + or + result = node.(Negation).getChild() and i = -1 and name = "getChild" + or + result = node.(OrderBy).getChild(i) and name = "getChild" + or + result = node.(OrderBys).getChild(i) and name = "getChild" + or + result = node.(ParExpr).getChild() and i = -1 and name = "getChild" + or + result = node.(PredicateAliasBody).getChild() and i = -1 and name = "getChild" + or + result = node.(PredicateExpr).getChild(i) and name = "getChild" + or + result = node.(PrefixCast).getChild(i) and name = "getChild" + or + result = node.(Ql).getChild(i) and name = "getChild" + or + result = node.(QualifiedRhs).getName() and i = -1 and name = "getName" + or + result = node.(QualifiedRhs).getChild(i) and name = "getChild" + or + result = node.(QualifiedExpr).getChild(i) and name = "getChild" + or + result = node.(Quantified).getExpr() and i = -1 and name = "getExpr" + or + result = node.(Quantified).getFormula() and i = -1 and name = "getFormula" + or + result = node.(Quantified).getRange() and i = -1 and name = "getRange" + or + result = node.(Quantified).getChild(i) and name = "getChild" + or + result = node.(Range).getLower() and i = -1 and name = "getLower" + or + result = node.(Range).getUpper() and i = -1 and name = "getUpper" + or + result = node.(Select).getChild(i) and name = "getChild" + or + result = node.(SetLiteral).getChild(i) and name = "getChild" + or + result = node.(SignatureExpr).getModExpr() and i = -1 and name = "getModExpr" + or + result = node.(SignatureExpr).getPredicate() and i = -1 and name = "getPredicate" + or + result = node.(SignatureExpr).getTypeExpr() and i = -1 and name = "getTypeExpr" + or + result = node.(SpecialCall).getChild() and i = -1 and name = "getChild" + or + result = node.(SuperRef).getChild(i) and name = "getChild" + or + result = node.(TypeAliasBody).getChild() and i = -1 and name = "getChild" + or + result = node.(TypeExpr).getName() and i = -1 and name = "getName" + or + result = node.(TypeExpr).getQualifier() and i = -1 and name = "getQualifier" + or + result = node.(TypeExpr).getChild() and i = -1 and name = "getChild" + or + result = node.(TypeUnionBody).getChild(i) and name = "getChild" + or + result = node.(UnaryExpr).getChild(i) and name = "getChild" + or + result = node.(UnqualAggBody).getAsExprs(i) and name = "getAsExprs" + or + result = node.(UnqualAggBody).getGuard() and i = -1 and name = "getGuard" + or + result = node.(UnqualAggBody).getChild(i) and name = "getChild" + or + result = node.(VarDecl).getChild(i) and name = "getChild" + or + result = node.(VarName).getChild() and i = -1 and name = "getChild" + or + result = node.(Variable).getChild() and i = -1 and name = "getChild" + } + } } overlay[local] @@ -1669,6 +1907,60 @@ module Dbscheme { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Varchar" } } + + /** Provides predicates for mapping AST nodes to their named children. */ + module PrintAst { + /** Gets a child of `node` returned by the member predicate with the given `name`. If the predicate takes an index argument, `i` is bound to that index, otherwise `i` is `-1` (which is never a valid index). */ + AstNode getChild(AstNode node, string name, int i) { + result = node.(Annotation).getArgsAnnotation() and i = -1 and name = "getArgsAnnotation" + or + result = node.(Annotation).getSimpleAnnotation() and i = -1 and name = "getSimpleAnnotation" + or + result = node.(ArgsAnnotation).getName() and i = -1 and name = "getName" + or + result = node.(ArgsAnnotation).getChild(i) and name = "getChild" + or + result = node.(Branch).getQldoc() and i = -1 and name = "getQldoc" + or + result = node.(Branch).getChild(i) and name = "getChild" + or + result = node.(CaseDecl).getBase() and i = -1 and name = "getBase" + or + result = node.(CaseDecl).getDiscriminator() and i = -1 and name = "getDiscriminator" + or + result = node.(CaseDecl).getChild(i) and name = "getChild" + or + result = node.(ColType).getChild() and i = -1 and name = "getChild" + or + result = node.(Column).getColName() and i = -1 and name = "getColName" + or + result = node.(Column).getColType() and i = -1 and name = "getColType" + or + result = node.(Column).getIsRef() and i = -1 and name = "getIsRef" + or + result = node.(Column).getIsUnique() and i = -1 and name = "getIsUnique" + or + result = node.(Column).getQldoc() and i = -1 and name = "getQldoc" + or + result = node.(Column).getReprType() and i = -1 and name = "getReprType" + or + result = node.(Dbscheme).getChild(i) and name = "getChild" + or + result = node.(Entry).getChild() and i = -1 and name = "getChild" + or + result = node.(ReprType).getChild(i) and name = "getChild" + or + result = node.(Table).getTableName() and i = -1 and name = "getTableName" + or + result = node.(Table).getChild(i) and name = "getChild" + or + result = node.(TableName).getChild() and i = -1 and name = "getChild" + or + result = node.(UnionDecl).getBase() and i = -1 and name = "getBase" + or + result = node.(UnionDecl).getChild(i) and name = "getChild" + } + } } overlay[local] @@ -1803,6 +2095,24 @@ module Blame { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Number" } } + + /** Provides predicates for mapping AST nodes to their named children. */ + module PrintAst { + /** Gets a child of `node` returned by the member predicate with the given `name`. If the predicate takes an index argument, `i` is bound to that index, otherwise `i` is `-1` (which is never a valid index). */ + AstNode getChild(AstNode node, string name, int i) { + result = node.(BlameEntry).getDate() and i = -1 and name = "getDate" + or + result = node.(BlameEntry).getLine(i) and name = "getLine" + or + result = node.(BlameInfo).getFileEntry(i) and name = "getFileEntry" + or + result = node.(BlameInfo).getToday() and i = -1 and name = "getToday" + or + result = node.(FileEntry).getBlameEntry(i) and name = "getBlameEntry" + or + result = node.(FileEntry).getFileName() and i = -1 and name = "getFileName" + } + } } overlay[local] @@ -1977,4 +2287,22 @@ module JSON { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "True" } } + + /** Provides predicates for mapping AST nodes to their named children. */ + module PrintAst { + /** Gets a child of `node` returned by the member predicate with the given `name`. If the predicate takes an index argument, `i` is bound to that index, otherwise `i` is `-1` (which is never a valid index). */ + AstNode getChild(AstNode node, string name, int i) { + result = node.(Array).getChild(i) and name = "getChild" + or + result = node.(Document).getChild(i) and name = "getChild" + or + result = node.(Object).getChild(i) and name = "getChild" + or + result = node.(Pair).getKey() and i = -1 and name = "getKey" + or + result = node.(Pair).getValue() and i = -1 and name = "getValue" + or + result = node.(String).getChild(i) and name = "getChild" + } + } } diff --git a/ruby/ql/lib/CHANGELOG.md b/ruby/ql/lib/CHANGELOG.md index d26bfa6f205..3e1ebc8c712 100644 --- a/ruby/ql/lib/CHANGELOG.md +++ b/ruby/ql/lib/CHANGELOG.md @@ -1,3 +1,9 @@ +## 6.0.0 + +### Breaking Changes + +* The `else` branch of a `case` expression is no longer represented as a `StmtSequence` directly. Instead, a new `CaseElseBranch` AST node wraps the body (a `StmtSequence`). `CaseExpr.getElseBranch()` now returns a `CaseElseBranch`, and the body of the else branch can be accessed via `CaseElseBranch.getBody()`. + ## 5.2.2 No user-facing changes. diff --git a/ruby/ql/lib/change-notes/2026-06-15-case-else-branch.md b/ruby/ql/lib/change-notes/released/6.0.0.md similarity index 90% rename from ruby/ql/lib/change-notes/2026-06-15-case-else-branch.md rename to ruby/ql/lib/change-notes/released/6.0.0.md index a927f1e2c28..b3c3b67fb94 100644 --- a/ruby/ql/lib/change-notes/2026-06-15-case-else-branch.md +++ b/ruby/ql/lib/change-notes/released/6.0.0.md @@ -1,4 +1,5 @@ ---- -category: breaking ---- +## 6.0.0 + +### Breaking Changes + * The `else` branch of a `case` expression is no longer represented as a `StmtSequence` directly. Instead, a new `CaseElseBranch` AST node wraps the body (a `StmtSequence`). `CaseExpr.getElseBranch()` now returns a `CaseElseBranch`, and the body of the else branch can be accessed via `CaseElseBranch.getBody()`. diff --git a/ruby/ql/lib/codeql-pack.release.yml b/ruby/ql/lib/codeql-pack.release.yml index e3b1b0c079d..f8c4fa43ccb 100644 --- a/ruby/ql/lib/codeql-pack.release.yml +++ b/ruby/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 5.2.2 +lastReleaseVersion: 6.0.0 diff --git a/ruby/ql/lib/codeql/ruby/ast/Control.qll b/ruby/ql/lib/codeql/ruby/ast/Control.qll index ea54d355469..d27e0aaf91d 100644 --- a/ruby/ql/lib/codeql/ruby/ast/Control.qll +++ b/ruby/ql/lib/codeql/ruby/ast/Control.qll @@ -355,7 +355,7 @@ class TernaryIfExpr extends ConditionalExpr, TTernaryIfExpr { */ class CaseExpr extends ControlExpr instanceof CaseExprImpl { /** - * Gets the expression being compared, if any. For example, `foo` in the following example. + * Gets the expression being compared. For example, `foo` in the following example. * ```rb * case foo * when 0 @@ -364,7 +364,7 @@ class CaseExpr extends ControlExpr instanceof CaseExprImpl { * puts 'one' * end * ``` - * There is no result for the following example: + * In the following example, the result is an implicit synthesized `true` literal. * ```rb * case * when a then 0 diff --git a/ruby/ql/lib/codeql/ruby/ast/Expr.qll b/ruby/ql/lib/codeql/ruby/ast/Expr.qll index a49cafa8299..fed7941f3ce 100644 --- a/ruby/ql/lib/codeql/ruby/ast/Expr.qll +++ b/ruby/ql/lib/codeql/ruby/ast/Expr.qll @@ -280,6 +280,36 @@ class Pair extends Expr instanceof PairImpl { final override string getAPrimaryQlClass() { result = "Pair" } } +/** + * A disjunctive exception pattern match in a rescue clause. For example, the exception list + * `FirstError, SecondError` in: + * ```rb + * begin + * do_something + * rescue FirstError, SecondError => e + * handle_error(e) + * end + * ``` + */ +class ExceptionList extends Expr, TExceptionList { + private Ruby::Exceptions g; + + ExceptionList() { this = TExceptionList(g) } + + final override string getAPrimaryQlClass() { result = "ExceptionList" } + + /** Gets the `n`th exception in this list. */ + final Expr getException(int n) { toGenerated(result) = g.getChild(n) } + + final override string toString() { result = "..., ..." } + + final override AstNode getAChild(string pred) { + result = super.getAChild(pred) + or + pred = "getException" and result = this.getException(_) + } +} + /** * A rescue clause. For example: * ```rb @@ -296,23 +326,33 @@ class RescueClause extends Expr, TRescueClause { final override string getAPrimaryQlClass() { result = "RescueClause" } + /** Gets the exception list pattern when there are multiple exception expressions. */ + private ExceptionList getExceptions() { result = TExceptionList(g.getExceptions()) } + /** * Gets the `n`th exception to match, if any. For example `FirstError` or `SecondError` in: * ```rb * begin - * do_something + * do_something * rescue FirstError, SecondError => e * handle_error(e) * end * ``` */ - final Expr getException(int n) { toGenerated(result) = g.getExceptions().getChild(n) } + final Expr getException(int n) { + // 0 or 1 exception: no ExceptionList node, access directly + not exists(this.getExceptions()) and + toGenerated(result) = g.getExceptions().getChild(n) + or + // 2+ exceptions: delegate through ExceptionList + result = this.getExceptions().getException(n) + } /** * Gets an exception to match, if any. For example `FirstError` or `SecondError` in: * ```rb * begin - * do_something + * do_something * rescue FirstError, SecondError => e * handle_error(e) * end @@ -320,12 +360,35 @@ class RescueClause extends Expr, TRescueClause { */ final Expr getAnException() { result = this.getException(_) } + /** + * Gets the exception pattern to match, if any. + * + * This is either a single exception expression, or an `ExceptionList` + * representing a disjunctive match of multiple exceptions when there are two + * or more exceptions expressions. + * + * For example, in the following code, the exception pattern is the + * exception list `FirstError, SecondError`: + * ```rb + * begin + * do_something + * rescue FirstError, SecondError => e + * handle_error(e) + * end + * ``` + */ + final Expr getPattern() { + result = this.getExceptions() + or + not exists(this.getExceptions()) and result = this.getAnException() + } + /** * Gets the variable to which to assign the matched exception, if any. * For example `err` in: * ```rb * begin - * do_something + * do_something * rescue StandardError => err * handle_error(err) * end @@ -343,7 +406,7 @@ class RescueClause extends Expr, TRescueClause { final override AstNode getAChild(string pred) { result = super.getAChild(pred) or - pred = "getException" and result = this.getException(_) + pred = "getPattern" and result = this.getPattern() or pred = "getVariableExpr" and result = this.getVariableExpr() or diff --git a/ruby/ql/lib/codeql/ruby/ast/internal/AST.qll b/ruby/ql/lib/codeql/ruby/ast/internal/AST.qll index 4b3535c490d..45e75000f65 100644 --- a/ruby/ql/lib/codeql/ruby/ast/internal/AST.qll +++ b/ruby/ql/lib/codeql/ruby/ast/internal/AST.qll @@ -155,6 +155,7 @@ private module Cached { TEndBlock(Ruby::EndBlock g) or TEnsure(Ruby::Ensure g) or TEqExpr(Ruby::Binary g) { g instanceof @ruby_binary_equalequal } or + TExceptionList(Ruby::Exceptions g) { strictcount(g.getChild(_)) > 1 } or TExponentExprReal(Ruby::Binary g) { g instanceof @ruby_binary_starstar } or TExponentExprSynth(Ast::AstNode parent, int i) { mkSynthChild(ExponentExprKind(), parent, i) } or TFalseLiteral(Ruby::False g) or @@ -375,8 +376,8 @@ private module Cached { TClassVariableAccessReal or TComplementExpr or TComplexLiteral or TDefinedExprReal or TDelimitedSymbolLiteral or TDestructuredLeftAssignment or TDestructuredParameter or TDivExprReal or TDo or TDoBlock or TElementReference or TElseReal or TElsif or TEmptyStmt or - TEncoding or TEndBlock or TEnsure or TEqExpr or TExponentExprReal or TFalseLiteral or - TFile or TFindPattern or TFloatLiteral or TForExpr or TForwardParameter or + TEncoding or TEndBlock or TEnsure or TEqExpr or TExceptionList or TExponentExprReal or + TFalseLiteral or TFile or TFindPattern or TFloatLiteral or TForExpr or TForwardParameter or TForwardArgument or TGEExpr or TGTExpr or TGlobalVariableAccessReal or THashKeySymbolLiteral or THashLiteral or THashPattern or THashSplatExprReal or THashSplatNilParameter or THashSplatParameter or THereDoc or TIdentifierMethodCall or @@ -475,6 +476,7 @@ private module Cached { n = TEndBlock(result) or n = TEnsure(result) or n = TEqExpr(result) or + n = TExceptionList(result) or n = TExponentExprReal(result) or n = TFalseLiteral(result) or n = TFile(result) or @@ -765,7 +767,7 @@ class TExpr = TSelf or TArgumentList or TRescueClause or TRescueModifierExpr or TPair or TStringConcatenation or TCall or TBlockArgument or TConstantAccess or TControlExpr or TLiteral or TCallable or TVariableAccess or TStmtSequence or TOperation or TForwardArgument or TDestructuredLhsExpr or - TMatchPattern or TTestPattern; + TMatchPattern or TTestPattern or TExceptionList; class TSplatExpr = TSplatExprReal or TSplatExprSynth; diff --git a/ruby/ql/lib/codeql/ruby/ast/internal/Control.qll b/ruby/ql/lib/codeql/ruby/ast/internal/Control.qll index 00076ba996a..3c033fb200b 100644 --- a/ruby/ql/lib/codeql/ruby/ast/internal/Control.qll +++ b/ruby/ql/lib/codeql/ruby/ast/internal/Control.qll @@ -16,7 +16,11 @@ class CaseWhenClause extends CaseExprImpl, TCaseExpr { CaseWhenClause() { this = TCaseExpr(g) } - final override Expr getValue() { toGenerated(result) = g.getValue() } + final override Expr getValue() { + toGenerated(result) = g.getValue() + or + not exists(g.getValue()) and synthChild(this, -2, result) + } final override AstNode getBranch(int n) { // When branches map directly to WhenClause nodes diff --git a/ruby/ql/lib/codeql/ruby/ast/internal/Synthesis.qll b/ruby/ql/lib/codeql/ruby/ast/internal/Synthesis.qll index 081cbd01a38..f05deae5962 100644 --- a/ruby/ql/lib/codeql/ruby/ast/internal/Synthesis.qll +++ b/ruby/ql/lib/codeql/ruby/ast/internal/Synthesis.qll @@ -2002,6 +2002,25 @@ private module CallableBodySynthesis { } } +private module CaseNoValueSynthesis { + pragma[nomagic] + private predicate caseNoValueSynthesis(AstNode parent, int i, Child child) { + // Synthesize a `true` literal as the value of a `case`/`when` expression that has no value + exists(Ruby::Case g | + not exists(g.getValue()) and + parent = TCaseExpr(g) and + child = SynthChild(BooleanLiteralKind(true)) and + i = -2 + ) + } + + private class CaseNoValueSynthesisImpl extends Synthesis { + final override predicate child(AstNode parent, int i, Child child) { + caseNoValueSynthesis(parent, i, child) + } + } +} + private module CaseElseBranchSynthesis { pragma[nomagic] private predicate caseElseBranchSynthesis(AstNode parent, int i, Child child) { diff --git a/ruby/ql/lib/codeql/ruby/ast/internal/TreeSitter.qll b/ruby/ql/lib/codeql/ruby/ast/internal/TreeSitter.qll index dbc7b38b84e..e6b4c63f548 100644 --- a/ruby/ql/lib/codeql/ruby/ast/internal/TreeSitter.qll +++ b/ruby/ql/lib/codeql/ruby/ast/internal/TreeSitter.qll @@ -1964,6 +1964,340 @@ module Ruby { /** Gets a field or child node of this node. */ final override AstNode getAFieldOrChild() { ruby_yield_child(this, result) } } + + /** Provides predicates for mapping AST nodes to their named children. */ + module PrintAst { + /** Gets a child of `node` returned by the member predicate with the given `name`. If the predicate takes an index argument, `i` is bound to that index, otherwise `i` is `-1` (which is never a valid index). */ + AstNode getChild(AstNode node, string name, int i) { + result = node.(Alias).getAlias() and i = -1 and name = "getAlias" + or + result = node.(Alias).getName() and i = -1 and name = "getName" + or + result = node.(AlternativePattern).getAlternatives(i) and name = "getAlternatives" + or + result = node.(ArgumentList).getChild(i) and name = "getChild" + or + result = node.(Array).getChild(i) and name = "getChild" + or + result = node.(ArrayPattern).getClass() and i = -1 and name = "getClass" + or + result = node.(ArrayPattern).getChild(i) and name = "getChild" + or + result = node.(AsPattern).getName() and i = -1 and name = "getName" + or + result = node.(AsPattern).getValue() and i = -1 and name = "getValue" + or + result = node.(Assignment).getLeft() and i = -1 and name = "getLeft" + or + result = node.(Assignment).getRight() and i = -1 and name = "getRight" + or + result = node.(BareString).getChild(i) and name = "getChild" + or + result = node.(BareSymbol).getChild(i) and name = "getChild" + or + result = node.(Begin).getChild(i) and name = "getChild" + or + result = node.(BeginBlock).getChild(i) and name = "getChild" + or + result = node.(Binary).getLeft() and i = -1 and name = "getLeft" + or + result = node.(Binary).getRight() and i = -1 and name = "getRight" + or + result = node.(Block).getBody() and i = -1 and name = "getBody" + or + result = node.(Block).getParameters() and i = -1 and name = "getParameters" + or + result = node.(BlockArgument).getChild() and i = -1 and name = "getChild" + or + result = node.(BlockBody).getChild(i) and name = "getChild" + or + result = node.(BlockParameter).getName() and i = -1 and name = "getName" + or + result = node.(BlockParameters).getLocals(i) and name = "getLocals" + or + result = node.(BlockParameters).getChild(i) and name = "getChild" + or + result = node.(BodyStatement).getChild(i) and name = "getChild" + or + result = node.(Break).getChild() and i = -1 and name = "getChild" + or + result = node.(Call).getArguments() and i = -1 and name = "getArguments" + or + result = node.(Call).getBlock() and i = -1 and name = "getBlock" + or + result = node.(Call).getMethod() and i = -1 and name = "getMethod" + or + result = node.(Call).getOperator() and i = -1 and name = "getOperator" + or + result = node.(Call).getReceiver() and i = -1 and name = "getReceiver" + or + result = node.(Case).getValue() and i = -1 and name = "getValue" + or + result = node.(Case).getChild(i) and name = "getChild" + or + result = node.(CaseMatch).getClauses(i) and name = "getClauses" + or + result = node.(CaseMatch).getElse() and i = -1 and name = "getElse" + or + result = node.(CaseMatch).getValue() and i = -1 and name = "getValue" + or + result = node.(ChainedString).getChild(i) and name = "getChild" + or + result = node.(Class).getBody() and i = -1 and name = "getBody" + or + result = node.(Class).getName() and i = -1 and name = "getName" + or + result = node.(Class).getSuperclass() and i = -1 and name = "getSuperclass" + or + result = node.(Complex).getChild() and i = -1 and name = "getChild" + or + result = node.(Conditional).getAlternative() and i = -1 and name = "getAlternative" + or + result = node.(Conditional).getCondition() and i = -1 and name = "getCondition" + or + result = node.(Conditional).getConsequence() and i = -1 and name = "getConsequence" + or + result = node.(DelimitedSymbol).getChild(i) and name = "getChild" + or + result = node.(DestructuredLeftAssignment).getChild(i) and name = "getChild" + or + result = node.(DestructuredParameter).getChild(i) and name = "getChild" + or + result = node.(Do).getChild(i) and name = "getChild" + or + result = node.(DoBlock).getBody() and i = -1 and name = "getBody" + or + result = node.(DoBlock).getParameters() and i = -1 and name = "getParameters" + or + result = node.(ElementReference).getBlock() and i = -1 and name = "getBlock" + or + result = node.(ElementReference).getObject() and i = -1 and name = "getObject" + or + result = node.(ElementReference).getChild(i) and name = "getChild" + or + result = node.(Else).getChild(i) and name = "getChild" + or + result = node.(Elsif).getAlternative() and i = -1 and name = "getAlternative" + or + result = node.(Elsif).getCondition() and i = -1 and name = "getCondition" + or + result = node.(Elsif).getConsequence() and i = -1 and name = "getConsequence" + or + result = node.(EndBlock).getChild(i) and name = "getChild" + or + result = node.(Ensure).getChild(i) and name = "getChild" + or + result = node.(ExceptionVariable).getChild() and i = -1 and name = "getChild" + or + result = node.(Exceptions).getChild(i) and name = "getChild" + or + result = node.(ExpressionReferencePattern).getValue() and i = -1 and name = "getValue" + or + result = node.(FindPattern).getClass() and i = -1 and name = "getClass" + or + result = node.(FindPattern).getChild(i) and name = "getChild" + or + result = node.(For).getBody() and i = -1 and name = "getBody" + or + result = node.(For).getPattern() and i = -1 and name = "getPattern" + or + result = node.(For).getValue() and i = -1 and name = "getValue" + or + result = node.(Hash).getChild(i) and name = "getChild" + or + result = node.(HashPattern).getClass() and i = -1 and name = "getClass" + or + result = node.(HashPattern).getChild(i) and name = "getChild" + or + result = node.(HashSplatArgument).getChild() and i = -1 and name = "getChild" + or + result = node.(HashSplatParameter).getName() and i = -1 and name = "getName" + or + result = node.(HeredocBody).getChild(i) and name = "getChild" + or + result = node.(If).getAlternative() and i = -1 and name = "getAlternative" + or + result = node.(If).getCondition() and i = -1 and name = "getCondition" + or + result = node.(If).getConsequence() and i = -1 and name = "getConsequence" + or + result = node.(IfGuard).getCondition() and i = -1 and name = "getCondition" + or + result = node.(IfModifier).getBody() and i = -1 and name = "getBody" + or + result = node.(IfModifier).getCondition() and i = -1 and name = "getCondition" + or + result = node.(In).getChild() and i = -1 and name = "getChild" + or + result = node.(InClause).getBody() and i = -1 and name = "getBody" + or + result = node.(InClause).getGuard() and i = -1 and name = "getGuard" + or + result = node.(InClause).getPattern() and i = -1 and name = "getPattern" + or + result = node.(Interpolation).getChild(i) and name = "getChild" + or + result = node.(KeywordParameter).getName() and i = -1 and name = "getName" + or + result = node.(KeywordParameter).getValue() and i = -1 and name = "getValue" + or + result = node.(KeywordPattern).getKey() and i = -1 and name = "getKey" + or + result = node.(KeywordPattern).getValue() and i = -1 and name = "getValue" + or + result = node.(Lambda).getBody() and i = -1 and name = "getBody" + or + result = node.(Lambda).getParameters() and i = -1 and name = "getParameters" + or + result = node.(LambdaParameters).getChild(i) and name = "getChild" + or + result = node.(LeftAssignmentList).getChild(i) and name = "getChild" + or + result = node.(MatchPattern).getPattern() and i = -1 and name = "getPattern" + or + result = node.(MatchPattern).getValue() and i = -1 and name = "getValue" + or + result = node.(Method).getBody() and i = -1 and name = "getBody" + or + result = node.(Method).getName() and i = -1 and name = "getName" + or + result = node.(Method).getParameters() and i = -1 and name = "getParameters" + or + result = node.(MethodParameters).getChild(i) and name = "getChild" + or + result = node.(Module).getBody() and i = -1 and name = "getBody" + or + result = node.(Module).getName() and i = -1 and name = "getName" + or + result = node.(Next).getChild() and i = -1 and name = "getChild" + or + result = node.(OperatorAssignment).getLeft() and i = -1 and name = "getLeft" + or + result = node.(OperatorAssignment).getRight() and i = -1 and name = "getRight" + or + result = node.(OptionalParameter).getName() and i = -1 and name = "getName" + or + result = node.(OptionalParameter).getValue() and i = -1 and name = "getValue" + or + result = node.(Pair).getKey() and i = -1 and name = "getKey" + or + result = node.(Pair).getValue() and i = -1 and name = "getValue" + or + result = node.(ParenthesizedPattern).getChild() and i = -1 and name = "getChild" + or + result = node.(ParenthesizedStatements).getChild(i) and name = "getChild" + or + result = node.(Pattern).getChild() and i = -1 and name = "getChild" + or + result = node.(Program).getChild(i) and name = "getChild" + or + result = node.(Range).getBegin() and i = -1 and name = "getBegin" + or + result = node.(Range).getEnd() and i = -1 and name = "getEnd" + or + result = node.(Rational).getChild() and i = -1 and name = "getChild" + or + result = node.(Redo).getChild() and i = -1 and name = "getChild" + or + result = node.(Regex).getChild(i) and name = "getChild" + or + result = node.(Rescue).getBody() and i = -1 and name = "getBody" + or + result = node.(Rescue).getExceptions() and i = -1 and name = "getExceptions" + or + result = node.(Rescue).getVariable() and i = -1 and name = "getVariable" + or + result = node.(RescueModifier).getBody() and i = -1 and name = "getBody" + or + result = node.(RescueModifier).getHandler() and i = -1 and name = "getHandler" + or + result = node.(RestAssignment).getChild() and i = -1 and name = "getChild" + or + result = node.(Retry).getChild() and i = -1 and name = "getChild" + or + result = node.(Return).getChild() and i = -1 and name = "getChild" + or + result = node.(RightAssignmentList).getChild(i) and name = "getChild" + or + result = node.(ScopeResolution).getName() and i = -1 and name = "getName" + or + result = node.(ScopeResolution).getScope() and i = -1 and name = "getScope" + or + result = node.(Setter).getName() and i = -1 and name = "getName" + or + result = node.(SingletonClass).getBody() and i = -1 and name = "getBody" + or + result = node.(SingletonClass).getValue() and i = -1 and name = "getValue" + or + result = node.(SingletonMethod).getBody() and i = -1 and name = "getBody" + or + result = node.(SingletonMethod).getName() and i = -1 and name = "getName" + or + result = node.(SingletonMethod).getObject() and i = -1 and name = "getObject" + or + result = node.(SingletonMethod).getParameters() and i = -1 and name = "getParameters" + or + result = node.(SplatArgument).getChild() and i = -1 and name = "getChild" + or + result = node.(SplatParameter).getName() and i = -1 and name = "getName" + or + result = node.(String).getChild(i) and name = "getChild" + or + result = node.(StringArray).getChild(i) and name = "getChild" + or + result = node.(Subshell).getChild(i) and name = "getChild" + or + result = node.(Superclass).getChild() and i = -1 and name = "getChild" + or + result = node.(SymbolArray).getChild(i) and name = "getChild" + or + result = node.(TestPattern).getPattern() and i = -1 and name = "getPattern" + or + result = node.(TestPattern).getValue() and i = -1 and name = "getValue" + or + result = node.(Then).getChild(i) and name = "getChild" + or + result = node.(Unary).getOperand() and i = -1 and name = "getOperand" + or + result = node.(Undef).getChild(i) and name = "getChild" + or + result = node.(Unless).getAlternative() and i = -1 and name = "getAlternative" + or + result = node.(Unless).getCondition() and i = -1 and name = "getCondition" + or + result = node.(Unless).getConsequence() and i = -1 and name = "getConsequence" + or + result = node.(UnlessGuard).getCondition() and i = -1 and name = "getCondition" + or + result = node.(UnlessModifier).getBody() and i = -1 and name = "getBody" + or + result = node.(UnlessModifier).getCondition() and i = -1 and name = "getCondition" + or + result = node.(Until).getBody() and i = -1 and name = "getBody" + or + result = node.(Until).getCondition() and i = -1 and name = "getCondition" + or + result = node.(UntilModifier).getBody() and i = -1 and name = "getBody" + or + result = node.(UntilModifier).getCondition() and i = -1 and name = "getCondition" + or + result = node.(VariableReferencePattern).getName() and i = -1 and name = "getName" + or + result = node.(When).getBody() and i = -1 and name = "getBody" + or + result = node.(When).getPattern(i) and name = "getPattern" + or + result = node.(While).getBody() and i = -1 and name = "getBody" + or + result = node.(While).getCondition() and i = -1 and name = "getCondition" + or + result = node.(WhileModifier).getBody() and i = -1 and name = "getBody" + or + result = node.(WhileModifier).getCondition() and i = -1 and name = "getCondition" + or + result = node.(Yield).getChild() and i = -1 and name = "getChild" + } + } } overlay[local] @@ -2107,4 +2441,20 @@ module Erb { /** Gets a field or child node of this node. */ final override AstNode getAFieldOrChild() { erb_template_child(this, _, result) } } + + /** Provides predicates for mapping AST nodes to their named children. */ + module PrintAst { + /** Gets a child of `node` returned by the member predicate with the given `name`. If the predicate takes an index argument, `i` is bound to that index, otherwise `i` is `-1` (which is never a valid index). */ + AstNode getChild(AstNode node, string name, int i) { + result = node.(CommentDirective).getChild() and i = -1 and name = "getChild" + or + result = node.(Directive).getChild() and i = -1 and name = "getChild" + or + result = node.(GraphqlDirective).getChild() and i = -1 and name = "getChild" + or + result = node.(OutputDirective).getChild() and i = -1 and name = "getChild" + or + result = node.(Template).getChild(i) and name = "getChild" + } + } } diff --git a/ruby/ql/lib/qlpack.yml b/ruby/ql/lib/qlpack.yml index 399564bdb33..6957217db6d 100644 --- a/ruby/ql/lib/qlpack.yml +++ b/ruby/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/ruby-all -version: 5.2.3-dev +version: 6.0.1-dev groups: ruby extractor: ruby dbscheme: ruby.dbscheme diff --git a/ruby/ql/src/CHANGELOG.md b/ruby/ql/src/CHANGELOG.md index 384ca633202..1df5dad19b5 100644 --- a/ruby/ql/src/CHANGELOG.md +++ b/ruby/ql/src/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.6.5 + +No user-facing changes. + ## 1.6.4 No user-facing changes. diff --git a/ruby/ql/src/change-notes/released/1.6.5.md b/ruby/ql/src/change-notes/released/1.6.5.md new file mode 100644 index 00000000000..44f1ca6de3e --- /dev/null +++ b/ruby/ql/src/change-notes/released/1.6.5.md @@ -0,0 +1,3 @@ +## 1.6.5 + +No user-facing changes. diff --git a/ruby/ql/src/codeql-pack.release.yml b/ruby/ql/src/codeql-pack.release.yml index 1910e09d6a6..03153270557 100644 --- a/ruby/ql/src/codeql-pack.release.yml +++ b/ruby/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.6.4 +lastReleaseVersion: 1.6.5 diff --git a/ruby/ql/src/qlpack.yml b/ruby/ql/src/qlpack.yml index 72b0258fa30..c34506fd287 100644 --- a/ruby/ql/src/qlpack.yml +++ b/ruby/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/ruby-queries -version: 1.6.5-dev +version: 1.6.6-dev groups: - ruby - queries diff --git a/ruby/ql/test/library-tests/ast/Ast.expected b/ruby/ql/test/library-tests/ast/Ast.expected index da0a58f5d7d..2d047b5a9f9 100644 --- a/ruby/ql/test/library-tests/ast/Ast.expected +++ b/ruby/ql/test/library-tests/ast/Ast.expected @@ -433,363 +433,373 @@ calls/calls.rb: # 246| getReceiver: [ConstantReadAccess] X # 249| getStmt: [BeginExpr] begin ... # 250| getRescue: [RescueClause] rescue ... -# 250| getException: [MethodCall] call to foo +# 250| getPattern: [MethodCall] call to foo # 250| getReceiver: [SelfVariableAccess] self # 251| getEnsure: [StmtSequence] ensure ... # 251| getStmt: [MethodCall] call to bar # 251| getReceiver: [SelfVariableAccess] self # 253| getStmt: [BeginExpr] begin ... # 254| getRescue: [RescueClause] rescue ... -# 254| getException: [MethodCall] call to foo +# 254| getPattern: [MethodCall] call to foo # 254| getReceiver: [ConstantReadAccess] X # 255| getEnsure: [StmtSequence] ensure ... # 255| getStmt: [MethodCall] call to bar # 255| getReceiver: [ConstantReadAccess] X -# 259| getStmt: [RescueModifierExpr] ... rescue ... -# 259| getBody: [MethodCall] call to foo -# 259| getReceiver: [SelfVariableAccess] self -# 259| getHandler: [MethodCall] call to bar -# 259| getReceiver: [SelfVariableAccess] self -# 260| getStmt: [RescueModifierExpr] ... rescue ... -# 260| getBody: [MethodCall] call to foo -# 260| getReceiver: [ConstantReadAccess] X -# 260| getHandler: [MethodCall] call to bar -# 260| getReceiver: [ConstantReadAccess] X -# 263| getStmt: [MethodCall] call to foo -# 263| getReceiver: [SelfVariableAccess] self -# 263| getArgument: [BlockArgument] &... -# 263| getValue: [MethodCall] call to bar -# 263| getReceiver: [SelfVariableAccess] self -# 264| getStmt: [MethodCall] call to foo -# 264| getReceiver: [SelfVariableAccess] self -# 264| getArgument: [BlockArgument] &... -# 264| getValue: [MethodCall] call to bar -# 264| getReceiver: [ConstantReadAccess] X -# 265| getStmt: [MethodCall] call to foo -# 265| getReceiver: [SelfVariableAccess] self -# 265| getArgument: [BlockArgument] &... +# 257| getStmt: [BeginExpr] begin ... +# 258| getRescue: [RescueClause] rescue ... +# 258| getPattern: [ExceptionList] ..., ... +# 258| getException: [MethodCall] call to foo +# 258| getReceiver: [SelfVariableAccess] self +# 258| getException: [MethodCall] call to bar +# 258| getReceiver: [ConstantReadAccess] X +# 259| getEnsure: [StmtSequence] ensure ... +# 259| getStmt: [MethodCall] call to baz +# 259| getReceiver: [SelfVariableAccess] self +# 263| getStmt: [RescueModifierExpr] ... rescue ... +# 263| getBody: [MethodCall] call to foo +# 263| getReceiver: [SelfVariableAccess] self +# 263| getHandler: [MethodCall] call to bar +# 263| getReceiver: [SelfVariableAccess] self +# 264| getStmt: [RescueModifierExpr] ... rescue ... +# 264| getBody: [MethodCall] call to foo +# 264| getReceiver: [ConstantReadAccess] X +# 264| getHandler: [MethodCall] call to bar +# 264| getReceiver: [ConstantReadAccess] X # 267| getStmt: [MethodCall] call to foo # 267| getReceiver: [SelfVariableAccess] self -# 267| getArgument: [SplatExpr] * ... -# 267| getAnOperand/getOperand/getReceiver: [MethodCall] call to bar +# 267| getArgument: [BlockArgument] &... +# 267| getValue: [MethodCall] call to bar # 267| getReceiver: [SelfVariableAccess] self # 268| getStmt: [MethodCall] call to foo # 268| getReceiver: [SelfVariableAccess] self -# 268| getArgument: [SplatExpr] * ... -# 268| getAnOperand/getOperand/getReceiver: [MethodCall] call to bar +# 268| getArgument: [BlockArgument] &... +# 268| getValue: [MethodCall] call to bar # 268| getReceiver: [ConstantReadAccess] X # 269| getStmt: [MethodCall] call to foo # 269| getReceiver: [SelfVariableAccess] self -# 269| getArgument: [SplatExpr] * ... +# 269| getArgument: [BlockArgument] &... +# 271| getStmt: [MethodCall] call to foo +# 271| getReceiver: [SelfVariableAccess] self +# 271| getArgument: [SplatExpr] * ... +# 271| getAnOperand/getOperand/getReceiver: [MethodCall] call to bar +# 271| getReceiver: [SelfVariableAccess] self # 272| getStmt: [MethodCall] call to foo # 272| getReceiver: [SelfVariableAccess] self -# 272| getArgument: [HashSplatExpr] ** ... +# 272| getArgument: [SplatExpr] * ... # 272| getAnOperand/getOperand/getReceiver: [MethodCall] call to bar -# 272| getReceiver: [SelfVariableAccess] self +# 272| getReceiver: [ConstantReadAccess] X # 273| getStmt: [MethodCall] call to foo # 273| getReceiver: [SelfVariableAccess] self -# 273| getArgument: [HashSplatExpr] ** ... -# 273| getAnOperand/getOperand/getReceiver: [MethodCall] call to bar -# 273| getReceiver: [ConstantReadAccess] X -# 274| getStmt: [MethodCall] call to foo -# 274| getReceiver: [SelfVariableAccess] self -# 274| getArgument: [HashSplatExpr] ** ... +# 273| getArgument: [SplatExpr] * ... +# 276| getStmt: [MethodCall] call to foo +# 276| getReceiver: [SelfVariableAccess] self +# 276| getArgument: [HashSplatExpr] ** ... +# 276| getAnOperand/getOperand/getReceiver: [MethodCall] call to bar +# 276| getReceiver: [SelfVariableAccess] self # 277| getStmt: [MethodCall] call to foo # 277| getReceiver: [SelfVariableAccess] self -# 277| getArgument: [Pair] Pair -# 277| getKey: [SymbolLiteral] :blah -# 277| getComponent: [StringTextComponent] blah -# 277| getValue: [MethodCall] call to bar -# 277| getReceiver: [SelfVariableAccess] self +# 277| getArgument: [HashSplatExpr] ** ... +# 277| getAnOperand/getOperand/getReceiver: [MethodCall] call to bar +# 277| getReceiver: [ConstantReadAccess] X # 278| getStmt: [MethodCall] call to foo # 278| getReceiver: [SelfVariableAccess] self -# 278| getArgument: [Pair] Pair -# 278| getKey: [SymbolLiteral] :blah -# 278| getComponent: [StringTextComponent] blah -# 278| getValue: [MethodCall] call to bar -# 278| getReceiver: [ConstantReadAccess] X -# 283| getStmt: [ClassDeclaration] MyClass -# 284| getStmt: [Method] my_method -# 285| getBody: [StmtSequence] ... -# 285| getStmt: [SuperCall] super call to my_method -# 286| getStmt: [SuperCall] super call to my_method -# 287| getStmt: [SuperCall] super call to my_method -# 287| getArgument: [StringLiteral] "blah" -# 287| getComponent: [StringTextComponent] blah -# 288| getStmt: [SuperCall] super call to my_method -# 288| getArgument: [IntegerLiteral] 1 -# 288| getArgument: [IntegerLiteral] 2 -# 288| getArgument: [IntegerLiteral] 3 +# 278| getArgument: [HashSplatExpr] ** ... +# 281| getStmt: [MethodCall] call to foo +# 281| getReceiver: [SelfVariableAccess] self +# 281| getArgument: [Pair] Pair +# 281| getKey: [SymbolLiteral] :blah +# 281| getComponent: [StringTextComponent] blah +# 281| getValue: [MethodCall] call to bar +# 281| getReceiver: [SelfVariableAccess] self +# 282| getStmt: [MethodCall] call to foo +# 282| getReceiver: [SelfVariableAccess] self +# 282| getArgument: [Pair] Pair +# 282| getKey: [SymbolLiteral] :blah +# 282| getComponent: [StringTextComponent] blah +# 282| getValue: [MethodCall] call to bar +# 282| getReceiver: [ConstantReadAccess] X +# 287| getStmt: [ClassDeclaration] MyClass +# 288| getStmt: [Method] my_method +# 289| getBody: [StmtSequence] ... # 289| getStmt: [SuperCall] super call to my_method -# 289| getBlock: [BraceBlock] { ... } -# 289| getParameter: [SimpleParameter] x -# 289| getDefiningAccess: [LocalVariableAccess] x -# 289| getBody: [StmtSequence] ... -# 289| getStmt: [AddExpr] ... + ... -# 289| getAnOperand/getLeftOperand/getReceiver: [LocalVariableAccess] x -# 289| getAnOperand/getArgument/getRightOperand: [IntegerLiteral] 1 # 290| getStmt: [SuperCall] super call to my_method -# 290| getBlock: [DoBlock] do ... end -# 290| getParameter: [SimpleParameter] x -# 290| getDefiningAccess: [LocalVariableAccess] x -# 290| getBody: [StmtSequence] ... -# 290| getStmt: [MulExpr] ... * ... -# 290| getAnOperand/getLeftOperand/getReceiver: [LocalVariableAccess] x -# 290| getAnOperand/getArgument/getRightOperand: [IntegerLiteral] 2 # 291| getStmt: [SuperCall] super call to my_method -# 291| getArgument: [IntegerLiteral] 4 -# 291| getArgument: [IntegerLiteral] 5 -# 291| getBlock: [BraceBlock] { ... } -# 291| getParameter: [SimpleParameter] x -# 291| getDefiningAccess: [LocalVariableAccess] x -# 291| getBody: [StmtSequence] ... -# 291| getStmt: [AddExpr] ... + ... -# 291| getAnOperand/getLeftOperand/getReceiver: [LocalVariableAccess] x -# 291| getAnOperand/getArgument/getRightOperand: [IntegerLiteral] 100 +# 291| getArgument: [StringLiteral] "blah" +# 291| getComponent: [StringTextComponent] blah # 292| getStmt: [SuperCall] super call to my_method -# 292| getArgument: [IntegerLiteral] 6 -# 292| getArgument: [IntegerLiteral] 7 -# 292| getBlock: [DoBlock] do ... end -# 292| getParameter: [SimpleParameter] x -# 292| getDefiningAccess: [LocalVariableAccess] x -# 292| getBody: [StmtSequence] ... -# 292| getStmt: [AddExpr] ... + ... -# 292| getAnOperand/getLeftOperand/getReceiver: [LocalVariableAccess] x -# 292| getAnOperand/getArgument/getRightOperand: [IntegerLiteral] 200 -# 300| getStmt: [ClassDeclaration] AnotherClass -# 301| getStmt: [Method] another_method -# 302| getBody: [StmtSequence] ... -# 302| getStmt: [MethodCall] call to super -# 302| getReceiver: [MethodCall] call to foo -# 302| getReceiver: [SelfVariableAccess] self -# 303| getStmt: [MethodCall] call to super -# 303| getReceiver: [SelfVariableAccess] self -# 304| getStmt: [MethodCall] call to super -# 304| getReceiver: [SuperCall] super call to another_method -# 309| getStmt: [MethodCall] call to call -# 309| getReceiver: [MethodCall] call to foo -# 309| getReceiver: [SelfVariableAccess] self -# 310| getStmt: [MethodCall] call to call -# 310| getReceiver: [MethodCall] call to foo -# 310| getReceiver: [SelfVariableAccess] self -# 310| getArgument: [IntegerLiteral] 1 -# 313| getStmt: [AssignExpr] ... = ... -# 313| getAnOperand/getLeftOperand: [MethodCall] call to foo +# 292| getArgument: [IntegerLiteral] 1 +# 292| getArgument: [IntegerLiteral] 2 +# 292| getArgument: [IntegerLiteral] 3 +# 293| getStmt: [SuperCall] super call to my_method +# 293| getBlock: [BraceBlock] { ... } +# 293| getParameter: [SimpleParameter] x +# 293| getDefiningAccess: [LocalVariableAccess] x +# 293| getBody: [StmtSequence] ... +# 293| getStmt: [AddExpr] ... + ... +# 293| getAnOperand/getLeftOperand/getReceiver: [LocalVariableAccess] x +# 293| getAnOperand/getArgument/getRightOperand: [IntegerLiteral] 1 +# 294| getStmt: [SuperCall] super call to my_method +# 294| getBlock: [DoBlock] do ... end +# 294| getParameter: [SimpleParameter] x +# 294| getDefiningAccess: [LocalVariableAccess] x +# 294| getBody: [StmtSequence] ... +# 294| getStmt: [MulExpr] ... * ... +# 294| getAnOperand/getLeftOperand/getReceiver: [LocalVariableAccess] x +# 294| getAnOperand/getArgument/getRightOperand: [IntegerLiteral] 2 +# 295| getStmt: [SuperCall] super call to my_method +# 295| getArgument: [IntegerLiteral] 4 +# 295| getArgument: [IntegerLiteral] 5 +# 295| getBlock: [BraceBlock] { ... } +# 295| getParameter: [SimpleParameter] x +# 295| getDefiningAccess: [LocalVariableAccess] x +# 295| getBody: [StmtSequence] ... +# 295| getStmt: [AddExpr] ... + ... +# 295| getAnOperand/getLeftOperand/getReceiver: [LocalVariableAccess] x +# 295| getAnOperand/getArgument/getRightOperand: [IntegerLiteral] 100 +# 296| getStmt: [SuperCall] super call to my_method +# 296| getArgument: [IntegerLiteral] 6 +# 296| getArgument: [IntegerLiteral] 7 +# 296| getBlock: [DoBlock] do ... end +# 296| getParameter: [SimpleParameter] x +# 296| getDefiningAccess: [LocalVariableAccess] x +# 296| getBody: [StmtSequence] ... +# 296| getStmt: [AddExpr] ... + ... +# 296| getAnOperand/getLeftOperand/getReceiver: [LocalVariableAccess] x +# 296| getAnOperand/getArgument/getRightOperand: [IntegerLiteral] 200 +# 304| getStmt: [ClassDeclaration] AnotherClass +# 305| getStmt: [Method] another_method +# 306| getBody: [StmtSequence] ... +# 306| getStmt: [MethodCall] call to super +# 306| getReceiver: [MethodCall] call to foo +# 306| getReceiver: [SelfVariableAccess] self +# 307| getStmt: [MethodCall] call to super +# 307| getReceiver: [SelfVariableAccess] self +# 308| getStmt: [MethodCall] call to super +# 308| getReceiver: [SuperCall] super call to another_method +# 313| getStmt: [MethodCall] call to call +# 313| getReceiver: [MethodCall] call to foo # 313| getReceiver: [SelfVariableAccess] self -# 313| getAnOperand/getRightOperand: [IntegerLiteral] 10 -# 314| getStmt: [AssignExpr] ... = ... -# 314| getAnOperand/getLeftOperand: [ElementReference] ...[...] -# 314| getReceiver: [MethodCall] call to foo -# 314| getReceiver: [SelfVariableAccess] self -# 314| getArgument: [IntegerLiteral] 0 -# 314| getAnOperand/getRightOperand: [IntegerLiteral] 10 -# 315| getStmt: [AssignExpr] ... = ... -# 315| getAnOperand/getLeftOperand: [DestructuredLhsExpr] (..., ...) -# 315| getElement: [MethodCall] call to foo -# 315| getReceiver: [SelfVariableAccess] self -# 315| getElement: [MethodCall] call to bar -# 315| getReceiver: [SelfVariableAccess] self -# 315| getElement: [ElementReference] ...[...] -# 315| getReceiver: [MethodCall] call to foo -# 315| getReceiver: [SelfVariableAccess] self -# 315| getArgument: [IntegerLiteral] 4 -# 315| getAnOperand/getRightOperand: [ArrayLiteral] [...] -# 315| getElement: [IntegerLiteral] 1 -# 315| getElement: [IntegerLiteral] 2 -# 315| getElement: [IntegerLiteral] 3 -# 315| getElement: [IntegerLiteral] 4 -# 316| getStmt: [AssignExpr] ... = ... -# 316| getAnOperand/getLeftOperand: [DestructuredLhsExpr] (..., ...) -# 316| getElement: [LocalVariableAccess] a -# 316| getElement: [ElementReference] ...[...] -# 316| getReceiver: [MethodCall] call to foo -# 316| getReceiver: [SelfVariableAccess] self -# 316| getArgument: [IntegerLiteral] 5 -# 316| getAnOperand/getRightOperand: [ArrayLiteral] [...] -# 316| getElement: [IntegerLiteral] 1 -# 316| getElement: [IntegerLiteral] 2 -# 316| getElement: [IntegerLiteral] 3 -# 317| getStmt: [AssignAddExpr] ... += ... -# 317| getAnOperand/getLeftOperand: [MethodCall] call to count +# 314| getStmt: [MethodCall] call to call +# 314| getReceiver: [MethodCall] call to foo +# 314| getReceiver: [SelfVariableAccess] self +# 314| getArgument: [IntegerLiteral] 1 +# 317| getStmt: [AssignExpr] ... = ... +# 317| getAnOperand/getLeftOperand: [MethodCall] call to foo # 317| getReceiver: [SelfVariableAccess] self -# 317| getAnOperand/getRightOperand: [IntegerLiteral] 1 -# 318| getStmt: [AssignAddExpr] ... += ... +# 317| getAnOperand/getRightOperand: [IntegerLiteral] 10 +# 318| getStmt: [AssignExpr] ... = ... # 318| getAnOperand/getLeftOperand: [ElementReference] ...[...] # 318| getReceiver: [MethodCall] call to foo # 318| getReceiver: [SelfVariableAccess] self # 318| getArgument: [IntegerLiteral] 0 -# 318| getAnOperand/getRightOperand: [IntegerLiteral] 1 -# 319| getStmt: [AssignMulExpr] ... *= ... -# 319| getAnOperand/getLeftOperand: [ElementReference] ...[...] -# 319| getReceiver: [MethodCall] call to bar +# 318| getAnOperand/getRightOperand: [IntegerLiteral] 10 +# 319| getStmt: [AssignExpr] ... = ... +# 319| getAnOperand/getLeftOperand: [DestructuredLhsExpr] (..., ...) +# 319| getElement: [MethodCall] call to foo +# 319| getReceiver: [SelfVariableAccess] self +# 319| getElement: [MethodCall] call to bar +# 319| getReceiver: [SelfVariableAccess] self +# 319| getElement: [ElementReference] ...[...] # 319| getReceiver: [MethodCall] call to foo # 319| getReceiver: [SelfVariableAccess] self -# 319| getArgument: [IntegerLiteral] 0 -# 319| getArgument: [MethodCall] call to baz -# 319| getReceiver: [MethodCall] call to foo -# 319| getReceiver: [SelfVariableAccess] self -# 319| getArgument: [AddExpr] ... + ... -# 319| getAnOperand/getLeftOperand/getReceiver: [MethodCall] call to boo -# 319| getReceiver: [MethodCall] call to foo -# 319| getReceiver: [SelfVariableAccess] self -# 319| getAnOperand/getArgument/getRightOperand: [IntegerLiteral] 1 -# 319| getAnOperand/getRightOperand: [IntegerLiteral] 2 -# 322| getStmt: [Method] foo -# 322| getBody: [StmtSequence] ... -# 322| getStmt: [MethodCall] call to bar +# 319| getArgument: [IntegerLiteral] 4 +# 319| getAnOperand/getRightOperand: [ArrayLiteral] [...] +# 319| getElement: [IntegerLiteral] 1 +# 319| getElement: [IntegerLiteral] 2 +# 319| getElement: [IntegerLiteral] 3 +# 319| getElement: [IntegerLiteral] 4 +# 320| getStmt: [AssignExpr] ... = ... +# 320| getAnOperand/getLeftOperand: [DestructuredLhsExpr] (..., ...) +# 320| getElement: [LocalVariableAccess] a +# 320| getElement: [ElementReference] ...[...] +# 320| getReceiver: [MethodCall] call to foo +# 320| getReceiver: [SelfVariableAccess] self +# 320| getArgument: [IntegerLiteral] 5 +# 320| getAnOperand/getRightOperand: [ArrayLiteral] [...] +# 320| getElement: [IntegerLiteral] 1 +# 320| getElement: [IntegerLiteral] 2 +# 320| getElement: [IntegerLiteral] 3 +# 321| getStmt: [AssignAddExpr] ... += ... +# 321| getAnOperand/getLeftOperand: [MethodCall] call to count +# 321| getReceiver: [SelfVariableAccess] self +# 321| getAnOperand/getRightOperand: [IntegerLiteral] 1 +# 322| getStmt: [AssignAddExpr] ... += ... +# 322| getAnOperand/getLeftOperand: [ElementReference] ...[...] +# 322| getReceiver: [MethodCall] call to foo # 322| getReceiver: [SelfVariableAccess] self -# 323| getStmt: [Method] foo -# 323| getBody: [StmtSequence] ... -# 323| getStmt: [MethodCall] call to bar -# 323| getReceiver: [SelfVariableAccess] self -# 324| getStmt: [Method] foo -# 324| getBody: [StmtSequence] ... -# 324| getStmt: [MethodCall] call to bar -# 324| getReceiver: [SelfVariableAccess] self -# 324| getParameter: [SimpleParameter] x -# 324| getDefiningAccess: [LocalVariableAccess] x -# 325| getStmt: [SingletonMethod] foo -# 325| getBody: [StmtSequence] ... -# 325| getStmt: [MethodCall] call to bar -# 325| getReceiver: [SelfVariableAccess] self -# 325| getObject: [ConstantReadAccess] Object -# 326| getStmt: [SingletonMethod] foo +# 322| getArgument: [IntegerLiteral] 0 +# 322| getAnOperand/getRightOperand: [IntegerLiteral] 1 +# 323| getStmt: [AssignMulExpr] ... *= ... +# 323| getAnOperand/getLeftOperand: [ElementReference] ...[...] +# 323| getReceiver: [MethodCall] call to bar +# 323| getReceiver: [MethodCall] call to foo +# 323| getReceiver: [SelfVariableAccess] self +# 323| getArgument: [IntegerLiteral] 0 +# 323| getArgument: [MethodCall] call to baz +# 323| getReceiver: [MethodCall] call to foo +# 323| getReceiver: [SelfVariableAccess] self +# 323| getArgument: [AddExpr] ... + ... +# 323| getAnOperand/getLeftOperand/getReceiver: [MethodCall] call to boo +# 323| getReceiver: [MethodCall] call to foo +# 323| getReceiver: [SelfVariableAccess] self +# 323| getAnOperand/getArgument/getRightOperand: [IntegerLiteral] 1 +# 323| getAnOperand/getRightOperand: [IntegerLiteral] 2 +# 326| getStmt: [Method] foo # 326| getBody: [StmtSequence] ... # 326| getStmt: [MethodCall] call to bar # 326| getReceiver: [SelfVariableAccess] self -# 326| getObject: [ConstantReadAccess] Object -# 326| getParameter: [SimpleParameter] x -# 326| getDefiningAccess: [LocalVariableAccess] x # 327| getStmt: [Method] foo # 327| getBody: [StmtSequence] ... -# 327| getStmt: [RescueModifierExpr] ... rescue ... -# 327| getBody: [MethodCall] call to bar -# 327| getReceiver: [SelfVariableAccess] self -# 327| getHandler: [ParenthesizedExpr] ( ... ) -# 327| getStmt: [MethodCall] call to print -# 327| getReceiver: [SelfVariableAccess] self -# 327| getArgument: [StringLiteral] "error" -# 327| getComponent: [StringTextComponent] error -# 330| getStmt: [Method] foo -# 330| getParameter: [ForwardParameter] ... +# 327| getStmt: [MethodCall] call to bar +# 327| getReceiver: [SelfVariableAccess] self +# 328| getStmt: [Method] foo +# 328| getBody: [StmtSequence] ... +# 328| getStmt: [MethodCall] call to bar +# 328| getReceiver: [SelfVariableAccess] self +# 328| getParameter: [SimpleParameter] x +# 328| getDefiningAccess: [LocalVariableAccess] x +# 329| getStmt: [SingletonMethod] foo +# 329| getBody: [StmtSequence] ... +# 329| getStmt: [MethodCall] call to bar +# 329| getReceiver: [SelfVariableAccess] self +# 329| getObject: [ConstantReadAccess] Object +# 330| getStmt: [SingletonMethod] foo +# 330| getBody: [StmtSequence] ... +# 330| getStmt: [MethodCall] call to bar +# 330| getReceiver: [SelfVariableAccess] self +# 330| getObject: [ConstantReadAccess] Object +# 330| getParameter: [SimpleParameter] x +# 330| getDefiningAccess: [LocalVariableAccess] x +# 331| getStmt: [Method] foo # 331| getBody: [StmtSequence] ... -# 331| getStmt: [SuperCall] super call to foo -# 331| getArgument: [ForwardedArguments] ... +# 331| getStmt: [RescueModifierExpr] ... rescue ... +# 331| getBody: [MethodCall] call to bar +# 331| getReceiver: [SelfVariableAccess] self +# 331| getHandler: [ParenthesizedExpr] ( ... ) +# 331| getStmt: [MethodCall] call to print +# 331| getReceiver: [SelfVariableAccess] self +# 331| getArgument: [StringLiteral] "error" +# 331| getComponent: [StringTextComponent] error # 334| getStmt: [Method] foo -# 334| getParameter: [SimpleParameter] a -# 334| getDefiningAccess: [LocalVariableAccess] a -# 334| getParameter: [SimpleParameter] b -# 334| getDefiningAccess: [LocalVariableAccess] b # 334| getParameter: [ForwardParameter] ... # 335| getBody: [StmtSequence] ... -# 335| getStmt: [MethodCall] call to bar -# 335| getReceiver: [SelfVariableAccess] self -# 335| getArgument: [LocalVariableAccess] b +# 335| getStmt: [SuperCall] super call to foo # 335| getArgument: [ForwardedArguments] ... -# 339| getStmt: [ForExpr] for ... in ... -# 339| getPattern: [DestructuredLhsExpr] (..., ...) -# 339| getElement: [LocalVariableAccess] x -# 339| getElement: [LocalVariableAccess] y -# 339| getElement: [LocalVariableAccess] z -# 339| getValue: [ArrayLiteral] [...] -# 339| getElement: [ArrayLiteral] [...] -# 339| getElement: [IntegerLiteral] 1 -# 339| getElement: [IntegerLiteral] 2 -# 339| getElement: [IntegerLiteral] 3 -# 339| getElement: [ArrayLiteral] [...] -# 339| getElement: [IntegerLiteral] 4 -# 339| getElement: [IntegerLiteral] 5 -# 339| getElement: [IntegerLiteral] 6 -# 339| getBody: [StmtSequence] do ... -# 340| getStmt: [MethodCall] call to foo -# 340| getReceiver: [SelfVariableAccess] self -# 340| getArgument: [LocalVariableAccess] x -# 340| getArgument: [LocalVariableAccess] y -# 340| getArgument: [LocalVariableAccess] z -# 343| getStmt: [MethodCall] call to foo -# 343| getReceiver: [SelfVariableAccess] self -# 343| getArgument: [Pair] Pair -# 343| getKey: [SymbolLiteral] :x -# 343| getComponent: [StringTextComponent] x -# 343| getValue: [IntegerLiteral] 42 -# 344| getStmt: [MethodCall] call to foo -# 344| getReceiver: [SelfVariableAccess] self -# 344| getArgument: [Pair] Pair -# 344| getKey: [SymbolLiteral] :x -# 344| getComponent: [StringTextComponent] x -# 344| getValue: [LocalVariableAccess] x -# 344| getArgument: [Pair] Pair -# 344| getKey: [SymbolLiteral] :novar -# 344| getComponent: [StringTextComponent] novar -# 344| getValue: [MethodCall] call to novar -# 345| getStmt: [MethodCall] call to foo -# 345| getReceiver: [SelfVariableAccess] self -# 345| getArgument: [Pair] Pair -# 345| getKey: [SymbolLiteral] :X -# 345| getComponent: [StringTextComponent] X -# 345| getValue: [IntegerLiteral] 42 -# 346| getStmt: [MethodCall] call to foo -# 346| getReceiver: [SelfVariableAccess] self -# 346| getArgument: [Pair] Pair -# 346| getKey: [SymbolLiteral] :X -# 346| getComponent: [StringTextComponent] X -# 346| getValue: [ConstantReadAccess] X -# 349| getStmt: [AssignExpr] ... = ... -# 349| getAnOperand/getLeftOperand: [LocalVariableAccess] y -# 349| getAnOperand/getRightOperand: [IntegerLiteral] 1 -# 350| getStmt: [AssignExpr] ... = ... -# 350| getAnOperand/getLeftOperand: [LocalVariableAccess] one -# 350| getAnOperand/getRightOperand: [Lambda] -> { ... } -# 350| getParameter: [SimpleParameter] x -# 350| getDefiningAccess: [LocalVariableAccess] x -# 350| getBody: [StmtSequence] ... -# 350| getStmt: [LocalVariableAccess] y -# 351| getStmt: [AssignExpr] ... = ... -# 351| getAnOperand/getLeftOperand: [LocalVariableAccess] f -# 351| getAnOperand/getRightOperand: [Lambda] -> { ... } -# 351| getParameter: [SimpleParameter] x -# 351| getDefiningAccess: [LocalVariableAccess] x -# 351| getBody: [StmtSequence] ... -# 351| getStmt: [MethodCall] call to foo -# 351| getReceiver: [SelfVariableAccess] self -# 351| getArgument: [LocalVariableAccess] x -# 352| getStmt: [AssignExpr] ... = ... -# 352| getAnOperand/getLeftOperand: [LocalVariableAccess] g -# 352| getAnOperand/getRightOperand: [Lambda] -> { ... } -# 352| getParameter: [SimpleParameter] x -# 352| getDefiningAccess: [LocalVariableAccess] x -# 352| getBody: [StmtSequence] ... -# 352| getStmt: [MethodCall] call to unknown_call -# 352| getReceiver: [SelfVariableAccess] self +# 338| getStmt: [Method] foo +# 338| getParameter: [SimpleParameter] a +# 338| getDefiningAccess: [LocalVariableAccess] a +# 338| getParameter: [SimpleParameter] b +# 338| getDefiningAccess: [LocalVariableAccess] b +# 338| getParameter: [ForwardParameter] ... +# 339| getBody: [StmtSequence] ... +# 339| getStmt: [MethodCall] call to bar +# 339| getReceiver: [SelfVariableAccess] self +# 339| getArgument: [LocalVariableAccess] b +# 339| getArgument: [ForwardedArguments] ... +# 343| getStmt: [ForExpr] for ... in ... +# 343| getPattern: [DestructuredLhsExpr] (..., ...) +# 343| getElement: [LocalVariableAccess] x +# 343| getElement: [LocalVariableAccess] y +# 343| getElement: [LocalVariableAccess] z +# 343| getValue: [ArrayLiteral] [...] +# 343| getElement: [ArrayLiteral] [...] +# 343| getElement: [IntegerLiteral] 1 +# 343| getElement: [IntegerLiteral] 2 +# 343| getElement: [IntegerLiteral] 3 +# 343| getElement: [ArrayLiteral] [...] +# 343| getElement: [IntegerLiteral] 4 +# 343| getElement: [IntegerLiteral] 5 +# 343| getElement: [IntegerLiteral] 6 +# 343| getBody: [StmtSequence] do ... +# 344| getStmt: [MethodCall] call to foo +# 344| getReceiver: [SelfVariableAccess] self +# 344| getArgument: [LocalVariableAccess] x +# 344| getArgument: [LocalVariableAccess] y +# 344| getArgument: [LocalVariableAccess] z +# 347| getStmt: [MethodCall] call to foo +# 347| getReceiver: [SelfVariableAccess] self +# 347| getArgument: [Pair] Pair +# 347| getKey: [SymbolLiteral] :x +# 347| getComponent: [StringTextComponent] x +# 347| getValue: [IntegerLiteral] 42 +# 348| getStmt: [MethodCall] call to foo +# 348| getReceiver: [SelfVariableAccess] self +# 348| getArgument: [Pair] Pair +# 348| getKey: [SymbolLiteral] :x +# 348| getComponent: [StringTextComponent] x +# 348| getValue: [LocalVariableAccess] x +# 348| getArgument: [Pair] Pair +# 348| getKey: [SymbolLiteral] :novar +# 348| getComponent: [StringTextComponent] novar +# 348| getValue: [MethodCall] call to novar +# 349| getStmt: [MethodCall] call to foo +# 349| getReceiver: [SelfVariableAccess] self +# 349| getArgument: [Pair] Pair +# 349| getKey: [SymbolLiteral] :X +# 349| getComponent: [StringTextComponent] X +# 349| getValue: [IntegerLiteral] 42 +# 350| getStmt: [MethodCall] call to foo +# 350| getReceiver: [SelfVariableAccess] self +# 350| getArgument: [Pair] Pair +# 350| getKey: [SymbolLiteral] :X +# 350| getComponent: [StringTextComponent] X +# 350| getValue: [ConstantReadAccess] X # 353| getStmt: [AssignExpr] ... = ... -# 353| getAnOperand/getLeftOperand: [LocalVariableAccess] h -# 353| getAnOperand/getRightOperand: [Lambda] -> { ... } -# 353| getParameter: [SimpleParameter] x -# 353| getDefiningAccess: [LocalVariableAccess] x +# 353| getAnOperand/getLeftOperand: [LocalVariableAccess] y +# 353| getAnOperand/getRightOperand: [IntegerLiteral] 1 +# 354| getStmt: [AssignExpr] ... = ... +# 354| getAnOperand/getLeftOperand: [LocalVariableAccess] one +# 354| getAnOperand/getRightOperand: [Lambda] -> { ... } +# 354| getParameter: [SimpleParameter] x +# 354| getDefiningAccess: [LocalVariableAccess] x # 354| getBody: [StmtSequence] ... -# 354| getStmt: [LocalVariableAccess] x -# 355| getStmt: [LocalVariableAccess] y +# 354| getStmt: [LocalVariableAccess] y +# 355| getStmt: [AssignExpr] ... = ... +# 355| getAnOperand/getLeftOperand: [LocalVariableAccess] f +# 355| getAnOperand/getRightOperand: [Lambda] -> { ... } +# 355| getParameter: [SimpleParameter] x +# 355| getDefiningAccess: [LocalVariableAccess] x +# 355| getBody: [StmtSequence] ... +# 355| getStmt: [MethodCall] call to foo +# 355| getReceiver: [SelfVariableAccess] self +# 355| getArgument: [LocalVariableAccess] x +# 356| getStmt: [AssignExpr] ... = ... +# 356| getAnOperand/getLeftOperand: [LocalVariableAccess] g +# 356| getAnOperand/getRightOperand: [Lambda] -> { ... } +# 356| getParameter: [SimpleParameter] x +# 356| getDefiningAccess: [LocalVariableAccess] x +# 356| getBody: [StmtSequence] ... # 356| getStmt: [MethodCall] call to unknown_call # 356| getReceiver: [SelfVariableAccess] self -# 360| getStmt: [MethodCall] call to empty? -# 360| getReceiver: [MethodCall] call to list -# 360| getReceiver: [SelfVariableAccess] self -# 361| getStmt: [MethodCall] call to empty? -# 361| getReceiver: [MethodCall] call to list -# 361| getReceiver: [SelfVariableAccess] self -# 362| getStmt: [MethodCall] call to empty? -# 362| getReceiver: [MethodCall] call to list -# 362| getReceiver: [SelfVariableAccess] self -# 363| getStmt: [MethodCall] call to bar -# 363| getReceiver: [MethodCall] call to foo -# 363| getReceiver: [SelfVariableAccess] self -# 363| getArgument: [IntegerLiteral] 1 -# 363| getArgument: [IntegerLiteral] 2 -# 363| getBlock: [BraceBlock] { ... } -# 363| getParameter: [SimpleParameter] x -# 363| getDefiningAccess: [LocalVariableAccess] x -# 363| getBody: [StmtSequence] ... -# 363| getStmt: [LocalVariableAccess] x +# 357| getStmt: [AssignExpr] ... = ... +# 357| getAnOperand/getLeftOperand: [LocalVariableAccess] h +# 357| getAnOperand/getRightOperand: [Lambda] -> { ... } +# 357| getParameter: [SimpleParameter] x +# 357| getDefiningAccess: [LocalVariableAccess] x +# 358| getBody: [StmtSequence] ... +# 358| getStmt: [LocalVariableAccess] x +# 359| getStmt: [LocalVariableAccess] y +# 360| getStmt: [MethodCall] call to unknown_call +# 360| getReceiver: [SelfVariableAccess] self +# 364| getStmt: [MethodCall] call to empty? +# 364| getReceiver: [MethodCall] call to list +# 364| getReceiver: [SelfVariableAccess] self +# 365| getStmt: [MethodCall] call to empty? +# 365| getReceiver: [MethodCall] call to list +# 365| getReceiver: [SelfVariableAccess] self +# 366| getStmt: [MethodCall] call to empty? +# 366| getReceiver: [MethodCall] call to list +# 366| getReceiver: [SelfVariableAccess] self +# 367| getStmt: [MethodCall] call to bar +# 367| getReceiver: [MethodCall] call to foo +# 367| getReceiver: [SelfVariableAccess] self +# 367| getArgument: [IntegerLiteral] 1 +# 367| getArgument: [IntegerLiteral] 2 +# 367| getBlock: [BraceBlock] { ... } +# 367| getParameter: [SimpleParameter] x +# 367| getDefiningAccess: [LocalVariableAccess] x +# 367| getBody: [StmtSequence] ... +# 367| getStmt: [LocalVariableAccess] x control/cases.rb: # 1| [Toplevel] cases.rb # 2| getStmt: [AssignExpr] ... = ... @@ -819,6 +829,7 @@ control/cases.rb: # 13| getBody: [StmtSequence] else ... # 14| getStmt: [IntegerLiteral] 300 # 18| getStmt: [CaseExpr] case ... +# 18| getValue: [BooleanLiteral] true # 19| getBranch: [WhenClause] when ... # 19| getPattern: [GTExpr] ... > ... # 19| getAnOperand/getGreaterOperand/getLeftOperand/getReceiver: [LocalVariableAccess] a diff --git a/ruby/ql/test/library-tests/ast/AstDesugar.expected b/ruby/ql/test/library-tests/ast/AstDesugar.expected index bd350dc0070..b058d7d12da 100644 --- a/ruby/ql/test/library-tests/ast/AstDesugar.expected +++ b/ruby/ql/test/library-tests/ast/AstDesugar.expected @@ -78,293 +78,293 @@ calls/calls.rb: # 246| getReceiver: [ConstantReadAccess] X # 246| getValue: [MethodCall] call to bar # 246| getReceiver: [ConstantReadAccess] X -# 313| [AssignExpr] ... = ... -# 313| getDesugared: [StmtSequence] ... -# 313| getStmt: [SetterMethodCall] call to foo= -# 313| getReceiver: [SelfVariableAccess] self -# 313| getArgument: [AssignExpr] ... = ... -# 313| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0 -# 313| getAnOperand/getRightOperand: [IntegerLiteral] 10 -# 313| getStmt: [LocalVariableAccess] __synth__0 -# 314| [AssignExpr] ... = ... -# 314| getDesugared: [StmtSequence] ... -# 314| getStmt: [SetterMethodCall] call to []= -# 314| getReceiver: [MethodCall] call to foo -# 314| getReceiver: [SelfVariableAccess] self -# 314| getArgument: [IntegerLiteral] 0 -# 314| getArgument: [AssignExpr] ... = ... -# 314| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0 -# 314| getAnOperand/getRightOperand: [IntegerLiteral] 10 -# 314| getStmt: [LocalVariableAccess] __synth__0 -# 315| [AssignExpr] ... = ... -# 315| getDesugared: [StmtSequence] ... -# 315| getStmt: [AssignExpr] ... = ... -# 315| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0 -# 315| getAnOperand/getRightOperand: [SelfVariableAccess] self -# 315| getStmt: [AssignExpr] ... = ... -# 315| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__1 -# 315| getAnOperand/getRightOperand: [SelfVariableAccess] self -# 315| getStmt: [AssignExpr] ... = ... -# 315| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__2 -# 315| getAnOperand/getRightOperand: [MethodCall] call to foo -# 315| getReceiver: [SelfVariableAccess] self -# 315| getStmt: [AssignExpr] ... = ... -# 315| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__3 -# 315| getAnOperand/getRightOperand: [SplatExpr] * ... -# 315| getAnOperand/getOperand/getReceiver: [ArrayLiteral] [...] -# 315| getDesugared: [MethodCall] call to [] -# 315| getReceiver: [ConstantReadAccess] Array -# 315| getArgument: [IntegerLiteral] 1 -# 315| getArgument: [IntegerLiteral] 2 -# 315| getArgument: [IntegerLiteral] 3 -# 315| getArgument: [IntegerLiteral] 4 -# 315| getStmt: [AssignExpr] ... = ... -# 315| getDesugared: [StmtSequence] ... -# 315| getStmt: [SetterMethodCall] call to foo= -# 315| getReceiver: [LocalVariableAccess] __synth__0 -# 315| getArgument: [AssignExpr] ... = ... -# 315| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0__1 -# 315| getAnOperand/getRightOperand: [MethodCall] call to [] -# 315| getReceiver: [LocalVariableAccess] __synth__3 -# 315| getArgument: [IntegerLiteral] 0 -# 315| getStmt: [LocalVariableAccess] __synth__0__1 -# 315| getAnOperand/getLeftOperand: [MethodCall] call to foo -# 315| getStmt: [AssignExpr] ... = ... -# 315| getDesugared: [StmtSequence] ... -# 315| getStmt: [SetterMethodCall] call to bar= -# 315| getReceiver: [LocalVariableAccess] __synth__1 -# 315| getArgument: [AssignExpr] ... = ... -# 315| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0__1 -# 315| getAnOperand/getRightOperand: [MethodCall] call to [] -# 315| getReceiver: [LocalVariableAccess] __synth__3 -# 315| getArgument: [RangeLiteral] _ .. _ -# 315| getBegin: [IntegerLiteral] 1 -# 315| getEnd: [IntegerLiteral] -2 -# 315| getStmt: [LocalVariableAccess] __synth__0__1 -# 315| getAnOperand/getLeftOperand: [MethodCall] call to bar -# 315| getStmt: [AssignExpr] ... = ... -# 315| getDesugared: [StmtSequence] ... -# 315| getStmt: [SetterMethodCall] call to []= -# 315| getReceiver: [LocalVariableAccess] __synth__2 -# 315| getArgument: [IntegerLiteral] 4 -# 315| getArgument: [AssignExpr] ... = ... -# 315| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0__1 -# 315| getAnOperand/getRightOperand: [MethodCall] call to [] -# 315| getReceiver: [LocalVariableAccess] __synth__3 -# 315| getArgument: [IntegerLiteral] -1 -# 315| getStmt: [LocalVariableAccess] __synth__0__1 -# 315| getAnOperand/getLeftOperand: [MethodCall] call to [] -# 316| [AssignExpr] ... = ... -# 316| getDesugared: [StmtSequence] ... -# 316| getStmt: [AssignExpr] ... = ... -# 316| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__1 -# 316| getAnOperand/getRightOperand: [MethodCall] call to foo -# 316| getReceiver: [SelfVariableAccess] self -# 316| getStmt: [AssignExpr] ... = ... -# 316| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__2 -# 316| getAnOperand/getRightOperand: [SplatExpr] * ... -# 316| getAnOperand/getOperand/getReceiver: [ArrayLiteral] [...] -# 316| getDesugared: [MethodCall] call to [] -# 316| getReceiver: [ConstantReadAccess] Array -# 316| getArgument: [IntegerLiteral] 1 -# 316| getArgument: [IntegerLiteral] 2 -# 316| getArgument: [IntegerLiteral] 3 -# 316| getStmt: [AssignExpr] ... = ... -# 316| getAnOperand/getLeftOperand: [LocalVariableAccess] a -# 316| getAnOperand/getRightOperand: [MethodCall] call to [] -# 316| getReceiver: [LocalVariableAccess] __synth__2 -# 316| getArgument: [IntegerLiteral] 0 -# 316| getStmt: [AssignExpr] ... = ... -# 316| getDesugared: [StmtSequence] ... -# 316| getStmt: [SetterMethodCall] call to []= -# 316| getReceiver: [LocalVariableAccess] __synth__1 -# 316| getArgument: [IntegerLiteral] 5 -# 316| getArgument: [AssignExpr] ... = ... -# 316| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0__1 -# 316| getAnOperand/getRightOperand: [MethodCall] call to [] -# 316| getReceiver: [LocalVariableAccess] __synth__2 -# 316| getArgument: [RangeLiteral] _ .. _ -# 316| getBegin: [IntegerLiteral] 1 -# 316| getEnd: [IntegerLiteral] -1 -# 316| getStmt: [LocalVariableAccess] __synth__0__1 -# 316| getAnOperand/getLeftOperand: [MethodCall] call to [] -# 317| [AssignAddExpr] ... += ... +# 317| [AssignExpr] ... = ... # 317| getDesugared: [StmtSequence] ... -# 317| getStmt: [AssignExpr] ... = ... -# 317| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0 -# 317| getAnOperand/getRightOperand: [SelfVariableAccess] self -# 317| getStmt: [AssignExpr] ... = ... -# 317| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__1 -# 317| getAnOperand/getRightOperand: [AddExpr] ... + ... -# 317| getAnOperand/getLeftOperand/getReceiver: [MethodCall] call to count -# 317| getReceiver: [LocalVariableAccess] __synth__0 -# 317| getAnOperand/getArgument/getRightOperand: [IntegerLiteral] 1 -# 317| getStmt: [SetterMethodCall] call to count= -# 317| getReceiver: [LocalVariableAccess] __synth__0 -# 317| getArgument: [LocalVariableAccess] __synth__1 -# 317| getStmt: [LocalVariableAccess] __synth__1 -# 318| [AssignAddExpr] ... += ... +# 317| getStmt: [SetterMethodCall] call to foo= +# 317| getReceiver: [SelfVariableAccess] self +# 317| getArgument: [AssignExpr] ... = ... +# 317| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0 +# 317| getAnOperand/getRightOperand: [IntegerLiteral] 10 +# 317| getStmt: [LocalVariableAccess] __synth__0 +# 318| [AssignExpr] ... = ... # 318| getDesugared: [StmtSequence] ... -# 318| getStmt: [AssignExpr] ... = ... -# 318| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0 -# 318| getAnOperand/getRightOperand: [MethodCall] call to foo -# 318| getReceiver: [SelfVariableAccess] self -# 318| getStmt: [AssignExpr] ... = ... -# 318| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__1 -# 318| getAnOperand/getRightOperand: [IntegerLiteral] 0 -# 318| getStmt: [AssignExpr] ... = ... -# 318| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__2 -# 318| getAnOperand/getRightOperand: [AddExpr] ... + ... -# 318| getAnOperand/getLeftOperand/getReceiver: [MethodCall] call to [] -# 318| getReceiver: [LocalVariableAccess] __synth__0 -# 318| getArgument: [LocalVariableAccess] __synth__1 -# 318| getAnOperand/getArgument/getRightOperand: [IntegerLiteral] 1 # 318| getStmt: [SetterMethodCall] call to []= -# 318| getReceiver: [LocalVariableAccess] __synth__0 -# 318| getArgument: [LocalVariableAccess] __synth__1 -# 318| getArgument: [LocalVariableAccess] __synth__2 -# 318| getStmt: [LocalVariableAccess] __synth__2 -# 319| [AssignMulExpr] ... *= ... +# 318| getReceiver: [MethodCall] call to foo +# 318| getReceiver: [SelfVariableAccess] self +# 318| getArgument: [IntegerLiteral] 0 +# 318| getArgument: [AssignExpr] ... = ... +# 318| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0 +# 318| getAnOperand/getRightOperand: [IntegerLiteral] 10 +# 318| getStmt: [LocalVariableAccess] __synth__0 +# 319| [AssignExpr] ... = ... # 319| getDesugared: [StmtSequence] ... # 319| getStmt: [AssignExpr] ... = ... # 319| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0 -# 319| getAnOperand/getRightOperand: [MethodCall] call to bar -# 319| getReceiver: [MethodCall] call to foo -# 319| getReceiver: [SelfVariableAccess] self +# 319| getAnOperand/getRightOperand: [SelfVariableAccess] self # 319| getStmt: [AssignExpr] ... = ... # 319| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__1 -# 319| getAnOperand/getRightOperand: [IntegerLiteral] 0 +# 319| getAnOperand/getRightOperand: [SelfVariableAccess] self # 319| getStmt: [AssignExpr] ... = ... # 319| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__2 -# 319| getAnOperand/getRightOperand: [MethodCall] call to baz -# 319| getReceiver: [MethodCall] call to foo -# 319| getReceiver: [SelfVariableAccess] self +# 319| getAnOperand/getRightOperand: [MethodCall] call to foo +# 319| getReceiver: [SelfVariableAccess] self # 319| getStmt: [AssignExpr] ... = ... # 319| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__3 -# 319| getAnOperand/getRightOperand: [AddExpr] ... + ... -# 319| getAnOperand/getLeftOperand/getReceiver: [MethodCall] call to boo -# 319| getReceiver: [MethodCall] call to foo -# 319| getReceiver: [SelfVariableAccess] self -# 319| getAnOperand/getArgument/getRightOperand: [IntegerLiteral] 1 +# 319| getAnOperand/getRightOperand: [SplatExpr] * ... +# 319| getAnOperand/getOperand/getReceiver: [ArrayLiteral] [...] +# 319| getDesugared: [MethodCall] call to [] +# 319| getReceiver: [ConstantReadAccess] Array +# 319| getArgument: [IntegerLiteral] 1 +# 319| getArgument: [IntegerLiteral] 2 +# 319| getArgument: [IntegerLiteral] 3 +# 319| getArgument: [IntegerLiteral] 4 # 319| getStmt: [AssignExpr] ... = ... -# 319| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__4 -# 319| getAnOperand/getRightOperand: [MulExpr] ... * ... -# 319| getAnOperand/getLeftOperand/getReceiver: [MethodCall] call to [] +# 319| getDesugared: [StmtSequence] ... +# 319| getStmt: [SetterMethodCall] call to foo= # 319| getReceiver: [LocalVariableAccess] __synth__0 -# 319| getArgument: [LocalVariableAccess] __synth__1 -# 319| getArgument: [LocalVariableAccess] __synth__2 -# 319| getArgument: [LocalVariableAccess] __synth__3 -# 319| getAnOperand/getArgument/getRightOperand: [IntegerLiteral] 2 -# 319| getStmt: [SetterMethodCall] call to []= -# 319| getReceiver: [LocalVariableAccess] __synth__0 -# 319| getArgument: [LocalVariableAccess] __synth__1 -# 319| getArgument: [LocalVariableAccess] __synth__2 -# 319| getArgument: [LocalVariableAccess] __synth__3 -# 319| getArgument: [LocalVariableAccess] __synth__4 -# 319| getStmt: [LocalVariableAccess] __synth__4 -# 339| [ForExpr] for ... in ... -# 339| getDesugared: [StmtSequence] ... -# 339| getStmt: [IfExpr] if ... -# 339| getCondition: [NotExpr] ! ... -# 339| getAnOperand/getOperand/getReceiver: [DefinedExpr] defined? ... -# 339| getAnOperand/getOperand/getReceiver: [LocalVariableAccess] x -# 339| getBranch/getThen: [AssignExpr] ... = ... -# 339| getAnOperand/getLeftOperand: [LocalVariableAccess] x -# 339| getAnOperand/getRightOperand: [NilLiteral] nil -# 339| getStmt: [IfExpr] if ... -# 339| getCondition: [NotExpr] ! ... -# 339| getAnOperand/getOperand/getReceiver: [DefinedExpr] defined? ... -# 339| getAnOperand/getOperand/getReceiver: [LocalVariableAccess] y -# 339| getBranch/getThen: [AssignExpr] ... = ... -# 339| getAnOperand/getLeftOperand: [LocalVariableAccess] y -# 339| getAnOperand/getRightOperand: [NilLiteral] nil -# 339| getStmt: [IfExpr] if ... -# 339| getCondition: [NotExpr] ! ... -# 339| getAnOperand/getOperand/getReceiver: [DefinedExpr] defined? ... -# 339| getAnOperand/getOperand/getReceiver: [LocalVariableAccess] z -# 339| getBranch/getThen: [AssignExpr] ... = ... -# 339| getAnOperand/getLeftOperand: [LocalVariableAccess] z -# 339| getAnOperand/getRightOperand: [NilLiteral] nil -# 339| getStmt: [MethodCall] call to each -# 339| getReceiver: [ArrayLiteral] [...] -# 339| getDesugared: [MethodCall] call to [] -# 339| getReceiver: [ConstantReadAccess] Array -# 339| getArgument: [ArrayLiteral] [...] -# 339| getDesugared: [MethodCall] call to [] -# 339| getReceiver: [ConstantReadAccess] Array -# 339| getArgument: [IntegerLiteral] 1 -# 339| getArgument: [IntegerLiteral] 2 -# 339| getArgument: [IntegerLiteral] 3 -# 339| getArgument: [ArrayLiteral] [...] -# 339| getDesugared: [MethodCall] call to [] -# 339| getReceiver: [ConstantReadAccess] Array -# 339| getArgument: [IntegerLiteral] 4 -# 339| getArgument: [IntegerLiteral] 5 -# 339| getArgument: [IntegerLiteral] 6 -# 339| getBlock: [BraceBlock] { ... } -# 339| getParameter: [SimpleParameter] __synth__0__1 -# 339| getDefiningAccess: [LocalVariableAccess] __synth__0__1 -# 339| getBody: [StmtSequence] ... -# 339| getStmt: [AssignExpr] ... = ... -# 339| getDesugared: [StmtSequence] ... -# 339| getStmt: [AssignExpr] ... = ... -# 339| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__3__1 -# 339| getAnOperand/getRightOperand: [SplatExpr] * ... -# 339| getAnOperand/getOperand/getReceiver: [LocalVariableAccess] __synth__0__1 -# 339| getStmt: [AssignExpr] ... = ... -# 339| getAnOperand/getLeftOperand: [LocalVariableAccess] x -# 339| getAnOperand/getRightOperand: [MethodCall] call to [] -# 339| getReceiver: [LocalVariableAccess] __synth__3__1 -# 339| getArgument: [IntegerLiteral] 0 -# 339| getStmt: [AssignExpr] ... = ... -# 339| getAnOperand/getLeftOperand: [LocalVariableAccess] y -# 339| getAnOperand/getRightOperand: [MethodCall] call to [] -# 339| getReceiver: [LocalVariableAccess] __synth__3__1 -# 339| getArgument: [IntegerLiteral] 1 -# 339| getStmt: [AssignExpr] ... = ... -# 339| getAnOperand/getLeftOperand: [LocalVariableAccess] z -# 339| getAnOperand/getRightOperand: [MethodCall] call to [] -# 339| getReceiver: [LocalVariableAccess] __synth__3__1 -# 339| getArgument: [IntegerLiteral] 2 -# 339| getAnOperand/getLeftOperand: [DestructuredLhsExpr] (..., ...) -# 340| getStmt: [MethodCall] call to foo -# 340| getReceiver: [SelfVariableAccess] self -# 340| getArgument: [LocalVariableAccess] x -# 340| getArgument: [LocalVariableAccess] y -# 340| getArgument: [LocalVariableAccess] z -# 361| [MethodCall] call to empty? -# 361| getDesugared: [StmtSequence] ... -# 361| getStmt: [AssignExpr] ... = ... -# 361| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0__1 -# 361| getAnOperand/getRightOperand: [MethodCall] call to list -# 361| getReceiver: [SelfVariableAccess] self -# 361| getStmt: [IfExpr] if ... -# 361| getCondition: [MethodCall] call to == -# 361| getReceiver: [NilLiteral] nil -# 361| getArgument: [LocalVariableAccess] __synth__0__1 -# 361| getBranch/getThen: [NilLiteral] nil -# 361| getBranch/getElse: [MethodCall] call to empty? -# 361| getReceiver: [LocalVariableAccess] __synth__0__1 -# 363| [MethodCall] call to bar -# 363| getDesugared: [StmtSequence] ... -# 363| getStmt: [AssignExpr] ... = ... -# 363| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0__1 -# 363| getAnOperand/getRightOperand: [MethodCall] call to foo -# 363| getReceiver: [SelfVariableAccess] self -# 363| getStmt: [IfExpr] if ... -# 363| getCondition: [MethodCall] call to == -# 363| getReceiver: [NilLiteral] nil -# 363| getArgument: [LocalVariableAccess] __synth__0__1 -# 363| getBranch/getThen: [NilLiteral] nil -# 363| getBranch/getElse: [MethodCall] call to bar -# 363| getReceiver: [LocalVariableAccess] __synth__0__1 -# 363| getArgument: [IntegerLiteral] 1 -# 363| getArgument: [IntegerLiteral] 2 -# 363| getBlock: [BraceBlock] { ... } -# 363| getParameter: [SimpleParameter] x -# 363| getDefiningAccess: [LocalVariableAccess] x -# 363| getBody: [StmtSequence] ... -# 363| getStmt: [LocalVariableAccess] x +# 319| getArgument: [AssignExpr] ... = ... +# 319| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0__1 +# 319| getAnOperand/getRightOperand: [MethodCall] call to [] +# 319| getReceiver: [LocalVariableAccess] __synth__3 +# 319| getArgument: [IntegerLiteral] 0 +# 319| getStmt: [LocalVariableAccess] __synth__0__1 +# 319| getAnOperand/getLeftOperand: [MethodCall] call to foo +# 319| getStmt: [AssignExpr] ... = ... +# 319| getDesugared: [StmtSequence] ... +# 319| getStmt: [SetterMethodCall] call to bar= +# 319| getReceiver: [LocalVariableAccess] __synth__1 +# 319| getArgument: [AssignExpr] ... = ... +# 319| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0__1 +# 319| getAnOperand/getRightOperand: [MethodCall] call to [] +# 319| getReceiver: [LocalVariableAccess] __synth__3 +# 319| getArgument: [RangeLiteral] _ .. _ +# 319| getBegin: [IntegerLiteral] 1 +# 319| getEnd: [IntegerLiteral] -2 +# 319| getStmt: [LocalVariableAccess] __synth__0__1 +# 319| getAnOperand/getLeftOperand: [MethodCall] call to bar +# 319| getStmt: [AssignExpr] ... = ... +# 319| getDesugared: [StmtSequence] ... +# 319| getStmt: [SetterMethodCall] call to []= +# 319| getReceiver: [LocalVariableAccess] __synth__2 +# 319| getArgument: [IntegerLiteral] 4 +# 319| getArgument: [AssignExpr] ... = ... +# 319| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0__1 +# 319| getAnOperand/getRightOperand: [MethodCall] call to [] +# 319| getReceiver: [LocalVariableAccess] __synth__3 +# 319| getArgument: [IntegerLiteral] -1 +# 319| getStmt: [LocalVariableAccess] __synth__0__1 +# 319| getAnOperand/getLeftOperand: [MethodCall] call to [] +# 320| [AssignExpr] ... = ... +# 320| getDesugared: [StmtSequence] ... +# 320| getStmt: [AssignExpr] ... = ... +# 320| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__1 +# 320| getAnOperand/getRightOperand: [MethodCall] call to foo +# 320| getReceiver: [SelfVariableAccess] self +# 320| getStmt: [AssignExpr] ... = ... +# 320| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__2 +# 320| getAnOperand/getRightOperand: [SplatExpr] * ... +# 320| getAnOperand/getOperand/getReceiver: [ArrayLiteral] [...] +# 320| getDesugared: [MethodCall] call to [] +# 320| getReceiver: [ConstantReadAccess] Array +# 320| getArgument: [IntegerLiteral] 1 +# 320| getArgument: [IntegerLiteral] 2 +# 320| getArgument: [IntegerLiteral] 3 +# 320| getStmt: [AssignExpr] ... = ... +# 320| getAnOperand/getLeftOperand: [LocalVariableAccess] a +# 320| getAnOperand/getRightOperand: [MethodCall] call to [] +# 320| getReceiver: [LocalVariableAccess] __synth__2 +# 320| getArgument: [IntegerLiteral] 0 +# 320| getStmt: [AssignExpr] ... = ... +# 320| getDesugared: [StmtSequence] ... +# 320| getStmt: [SetterMethodCall] call to []= +# 320| getReceiver: [LocalVariableAccess] __synth__1 +# 320| getArgument: [IntegerLiteral] 5 +# 320| getArgument: [AssignExpr] ... = ... +# 320| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0__1 +# 320| getAnOperand/getRightOperand: [MethodCall] call to [] +# 320| getReceiver: [LocalVariableAccess] __synth__2 +# 320| getArgument: [RangeLiteral] _ .. _ +# 320| getBegin: [IntegerLiteral] 1 +# 320| getEnd: [IntegerLiteral] -1 +# 320| getStmt: [LocalVariableAccess] __synth__0__1 +# 320| getAnOperand/getLeftOperand: [MethodCall] call to [] +# 321| [AssignAddExpr] ... += ... +# 321| getDesugared: [StmtSequence] ... +# 321| getStmt: [AssignExpr] ... = ... +# 321| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0 +# 321| getAnOperand/getRightOperand: [SelfVariableAccess] self +# 321| getStmt: [AssignExpr] ... = ... +# 321| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__1 +# 321| getAnOperand/getRightOperand: [AddExpr] ... + ... +# 321| getAnOperand/getLeftOperand/getReceiver: [MethodCall] call to count +# 321| getReceiver: [LocalVariableAccess] __synth__0 +# 321| getAnOperand/getArgument/getRightOperand: [IntegerLiteral] 1 +# 321| getStmt: [SetterMethodCall] call to count= +# 321| getReceiver: [LocalVariableAccess] __synth__0 +# 321| getArgument: [LocalVariableAccess] __synth__1 +# 321| getStmt: [LocalVariableAccess] __synth__1 +# 322| [AssignAddExpr] ... += ... +# 322| getDesugared: [StmtSequence] ... +# 322| getStmt: [AssignExpr] ... = ... +# 322| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0 +# 322| getAnOperand/getRightOperand: [MethodCall] call to foo +# 322| getReceiver: [SelfVariableAccess] self +# 322| getStmt: [AssignExpr] ... = ... +# 322| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__1 +# 322| getAnOperand/getRightOperand: [IntegerLiteral] 0 +# 322| getStmt: [AssignExpr] ... = ... +# 322| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__2 +# 322| getAnOperand/getRightOperand: [AddExpr] ... + ... +# 322| getAnOperand/getLeftOperand/getReceiver: [MethodCall] call to [] +# 322| getReceiver: [LocalVariableAccess] __synth__0 +# 322| getArgument: [LocalVariableAccess] __synth__1 +# 322| getAnOperand/getArgument/getRightOperand: [IntegerLiteral] 1 +# 322| getStmt: [SetterMethodCall] call to []= +# 322| getReceiver: [LocalVariableAccess] __synth__0 +# 322| getArgument: [LocalVariableAccess] __synth__1 +# 322| getArgument: [LocalVariableAccess] __synth__2 +# 322| getStmt: [LocalVariableAccess] __synth__2 +# 323| [AssignMulExpr] ... *= ... +# 323| getDesugared: [StmtSequence] ... +# 323| getStmt: [AssignExpr] ... = ... +# 323| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0 +# 323| getAnOperand/getRightOperand: [MethodCall] call to bar +# 323| getReceiver: [MethodCall] call to foo +# 323| getReceiver: [SelfVariableAccess] self +# 323| getStmt: [AssignExpr] ... = ... +# 323| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__1 +# 323| getAnOperand/getRightOperand: [IntegerLiteral] 0 +# 323| getStmt: [AssignExpr] ... = ... +# 323| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__2 +# 323| getAnOperand/getRightOperand: [MethodCall] call to baz +# 323| getReceiver: [MethodCall] call to foo +# 323| getReceiver: [SelfVariableAccess] self +# 323| getStmt: [AssignExpr] ... = ... +# 323| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__3 +# 323| getAnOperand/getRightOperand: [AddExpr] ... + ... +# 323| getAnOperand/getLeftOperand/getReceiver: [MethodCall] call to boo +# 323| getReceiver: [MethodCall] call to foo +# 323| getReceiver: [SelfVariableAccess] self +# 323| getAnOperand/getArgument/getRightOperand: [IntegerLiteral] 1 +# 323| getStmt: [AssignExpr] ... = ... +# 323| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__4 +# 323| getAnOperand/getRightOperand: [MulExpr] ... * ... +# 323| getAnOperand/getLeftOperand/getReceiver: [MethodCall] call to [] +# 323| getReceiver: [LocalVariableAccess] __synth__0 +# 323| getArgument: [LocalVariableAccess] __synth__1 +# 323| getArgument: [LocalVariableAccess] __synth__2 +# 323| getArgument: [LocalVariableAccess] __synth__3 +# 323| getAnOperand/getArgument/getRightOperand: [IntegerLiteral] 2 +# 323| getStmt: [SetterMethodCall] call to []= +# 323| getReceiver: [LocalVariableAccess] __synth__0 +# 323| getArgument: [LocalVariableAccess] __synth__1 +# 323| getArgument: [LocalVariableAccess] __synth__2 +# 323| getArgument: [LocalVariableAccess] __synth__3 +# 323| getArgument: [LocalVariableAccess] __synth__4 +# 323| getStmt: [LocalVariableAccess] __synth__4 +# 343| [ForExpr] for ... in ... +# 343| getDesugared: [StmtSequence] ... +# 343| getStmt: [IfExpr] if ... +# 343| getCondition: [NotExpr] ! ... +# 343| getAnOperand/getOperand/getReceiver: [DefinedExpr] defined? ... +# 343| getAnOperand/getOperand/getReceiver: [LocalVariableAccess] x +# 343| getBranch/getThen: [AssignExpr] ... = ... +# 343| getAnOperand/getLeftOperand: [LocalVariableAccess] x +# 343| getAnOperand/getRightOperand: [NilLiteral] nil +# 343| getStmt: [IfExpr] if ... +# 343| getCondition: [NotExpr] ! ... +# 343| getAnOperand/getOperand/getReceiver: [DefinedExpr] defined? ... +# 343| getAnOperand/getOperand/getReceiver: [LocalVariableAccess] y +# 343| getBranch/getThen: [AssignExpr] ... = ... +# 343| getAnOperand/getLeftOperand: [LocalVariableAccess] y +# 343| getAnOperand/getRightOperand: [NilLiteral] nil +# 343| getStmt: [IfExpr] if ... +# 343| getCondition: [NotExpr] ! ... +# 343| getAnOperand/getOperand/getReceiver: [DefinedExpr] defined? ... +# 343| getAnOperand/getOperand/getReceiver: [LocalVariableAccess] z +# 343| getBranch/getThen: [AssignExpr] ... = ... +# 343| getAnOperand/getLeftOperand: [LocalVariableAccess] z +# 343| getAnOperand/getRightOperand: [NilLiteral] nil +# 343| getStmt: [MethodCall] call to each +# 343| getReceiver: [ArrayLiteral] [...] +# 343| getDesugared: [MethodCall] call to [] +# 343| getReceiver: [ConstantReadAccess] Array +# 343| getArgument: [ArrayLiteral] [...] +# 343| getDesugared: [MethodCall] call to [] +# 343| getReceiver: [ConstantReadAccess] Array +# 343| getArgument: [IntegerLiteral] 1 +# 343| getArgument: [IntegerLiteral] 2 +# 343| getArgument: [IntegerLiteral] 3 +# 343| getArgument: [ArrayLiteral] [...] +# 343| getDesugared: [MethodCall] call to [] +# 343| getReceiver: [ConstantReadAccess] Array +# 343| getArgument: [IntegerLiteral] 4 +# 343| getArgument: [IntegerLiteral] 5 +# 343| getArgument: [IntegerLiteral] 6 +# 343| getBlock: [BraceBlock] { ... } +# 343| getParameter: [SimpleParameter] __synth__0__1 +# 343| getDefiningAccess: [LocalVariableAccess] __synth__0__1 +# 343| getBody: [StmtSequence] ... +# 343| getStmt: [AssignExpr] ... = ... +# 343| getDesugared: [StmtSequence] ... +# 343| getStmt: [AssignExpr] ... = ... +# 343| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__3__1 +# 343| getAnOperand/getRightOperand: [SplatExpr] * ... +# 343| getAnOperand/getOperand/getReceiver: [LocalVariableAccess] __synth__0__1 +# 343| getStmt: [AssignExpr] ... = ... +# 343| getAnOperand/getLeftOperand: [LocalVariableAccess] x +# 343| getAnOperand/getRightOperand: [MethodCall] call to [] +# 343| getReceiver: [LocalVariableAccess] __synth__3__1 +# 343| getArgument: [IntegerLiteral] 0 +# 343| getStmt: [AssignExpr] ... = ... +# 343| getAnOperand/getLeftOperand: [LocalVariableAccess] y +# 343| getAnOperand/getRightOperand: [MethodCall] call to [] +# 343| getReceiver: [LocalVariableAccess] __synth__3__1 +# 343| getArgument: [IntegerLiteral] 1 +# 343| getStmt: [AssignExpr] ... = ... +# 343| getAnOperand/getLeftOperand: [LocalVariableAccess] z +# 343| getAnOperand/getRightOperand: [MethodCall] call to [] +# 343| getReceiver: [LocalVariableAccess] __synth__3__1 +# 343| getArgument: [IntegerLiteral] 2 +# 343| getAnOperand/getLeftOperand: [DestructuredLhsExpr] (..., ...) +# 344| getStmt: [MethodCall] call to foo +# 344| getReceiver: [SelfVariableAccess] self +# 344| getArgument: [LocalVariableAccess] x +# 344| getArgument: [LocalVariableAccess] y +# 344| getArgument: [LocalVariableAccess] z +# 365| [MethodCall] call to empty? +# 365| getDesugared: [StmtSequence] ... +# 365| getStmt: [AssignExpr] ... = ... +# 365| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0__1 +# 365| getAnOperand/getRightOperand: [MethodCall] call to list +# 365| getReceiver: [SelfVariableAccess] self +# 365| getStmt: [IfExpr] if ... +# 365| getCondition: [MethodCall] call to == +# 365| getReceiver: [NilLiteral] nil +# 365| getArgument: [LocalVariableAccess] __synth__0__1 +# 365| getBranch/getThen: [NilLiteral] nil +# 365| getBranch/getElse: [MethodCall] call to empty? +# 365| getReceiver: [LocalVariableAccess] __synth__0__1 +# 367| [MethodCall] call to bar +# 367| getDesugared: [StmtSequence] ... +# 367| getStmt: [AssignExpr] ... = ... +# 367| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0__1 +# 367| getAnOperand/getRightOperand: [MethodCall] call to foo +# 367| getReceiver: [SelfVariableAccess] self +# 367| getStmt: [IfExpr] if ... +# 367| getCondition: [MethodCall] call to == +# 367| getReceiver: [NilLiteral] nil +# 367| getArgument: [LocalVariableAccess] __synth__0__1 +# 367| getBranch/getThen: [NilLiteral] nil +# 367| getBranch/getElse: [MethodCall] call to bar +# 367| getReceiver: [LocalVariableAccess] __synth__0__1 +# 367| getArgument: [IntegerLiteral] 1 +# 367| getArgument: [IntegerLiteral] 2 +# 367| getBlock: [BraceBlock] { ... } +# 367| getParameter: [SimpleParameter] x +# 367| getDefiningAccess: [LocalVariableAccess] x +# 367| getBody: [StmtSequence] ... +# 367| getStmt: [LocalVariableAccess] x control/cases.rb: # 90| [ArrayLiteral] %w(...) # 90| getDesugared: [MethodCall] call to [] diff --git a/ruby/ql/test/library-tests/ast/TreeSitter.expected b/ruby/ql/test/library-tests/ast/TreeSitter.expected index ab7937969d1..918a41fd035 100644 --- a/ruby/ql/test/library-tests/ast/TreeSitter.expected +++ b/ruby/ql/test/library-tests/ast/TreeSitter.expected @@ -715,627 +715,642 @@ calls/calls.rb: # 255| 1: [ReservedWord] :: # 255| 2: [Identifier] bar # 256| 3: [ReservedWord] end -# 259| 76: [RescueModifier] RescueModifier -# 259| 0: [Identifier] foo -# 259| 1: [ReservedWord] rescue -# 259| 2: [Identifier] bar -# 260| 77: [RescueModifier] RescueModifier -# 260| 0: [Call] Call -# 260| 0: [Constant] X -# 260| 1: [ReservedWord] :: -# 260| 2: [Identifier] foo -# 260| 1: [ReservedWord] rescue -# 260| 2: [Call] Call -# 260| 0: [Constant] X -# 260| 1: [ReservedWord] :: -# 260| 2: [Identifier] bar -# 263| 78: [Call] Call +# 257| 76: [Begin] Begin +# 257| 0: [ReservedWord] begin +# 258| 1: [Rescue] Rescue +# 258| 0: [ReservedWord] rescue +# 258| 1: [Exceptions] Exceptions +# 258| 0: [Identifier] foo +# 258| 1: [ReservedWord] , +# 258| 2: [Call] Call +# 258| 0: [Constant] X +# 258| 1: [ReservedWord] :: +# 258| 2: [Identifier] bar +# 259| 2: [Ensure] Ensure +# 259| 0: [ReservedWord] ensure +# 259| 1: [Identifier] baz +# 260| 3: [ReservedWord] end +# 263| 77: [RescueModifier] RescueModifier # 263| 0: [Identifier] foo -# 263| 1: [ArgumentList] ArgumentList -# 263| 0: [ReservedWord] ( -# 263| 1: [BlockArgument] BlockArgument -# 263| 0: [ReservedWord] & -# 263| 1: [Identifier] bar -# 263| 2: [ReservedWord] ) -# 264| 79: [Call] Call -# 264| 0: [Identifier] foo -# 264| 1: [ArgumentList] ArgumentList -# 264| 0: [ReservedWord] ( -# 264| 1: [BlockArgument] BlockArgument -# 264| 0: [ReservedWord] & -# 264| 1: [Call] Call -# 264| 0: [Constant] X -# 264| 1: [ReservedWord] :: -# 264| 2: [Identifier] bar -# 264| 2: [ReservedWord] ) -# 265| 80: [Call] Call -# 265| 0: [Identifier] foo -# 265| 1: [ArgumentList] ArgumentList -# 265| 0: [ReservedWord] ( -# 265| 1: [BlockArgument] BlockArgument -# 265| 0: [ReservedWord] & -# 265| 2: [ReservedWord] ) -# 267| 81: [Call] Call +# 263| 1: [ReservedWord] rescue +# 263| 2: [Identifier] bar +# 264| 78: [RescueModifier] RescueModifier +# 264| 0: [Call] Call +# 264| 0: [Constant] X +# 264| 1: [ReservedWord] :: +# 264| 2: [Identifier] foo +# 264| 1: [ReservedWord] rescue +# 264| 2: [Call] Call +# 264| 0: [Constant] X +# 264| 1: [ReservedWord] :: +# 264| 2: [Identifier] bar +# 267| 79: [Call] Call # 267| 0: [Identifier] foo # 267| 1: [ArgumentList] ArgumentList # 267| 0: [ReservedWord] ( -# 267| 1: [SplatArgument] SplatArgument -# 267| 0: [ReservedWord] * +# 267| 1: [BlockArgument] BlockArgument +# 267| 0: [ReservedWord] & # 267| 1: [Identifier] bar # 267| 2: [ReservedWord] ) -# 268| 82: [Call] Call +# 268| 80: [Call] Call # 268| 0: [Identifier] foo # 268| 1: [ArgumentList] ArgumentList # 268| 0: [ReservedWord] ( -# 268| 1: [SplatArgument] SplatArgument -# 268| 0: [ReservedWord] * +# 268| 1: [BlockArgument] BlockArgument +# 268| 0: [ReservedWord] & # 268| 1: [Call] Call # 268| 0: [Constant] X # 268| 1: [ReservedWord] :: # 268| 2: [Identifier] bar # 268| 2: [ReservedWord] ) -# 269| 83: [Call] Call +# 269| 81: [Call] Call # 269| 0: [Identifier] foo # 269| 1: [ArgumentList] ArgumentList # 269| 0: [ReservedWord] ( -# 269| 1: [SplatArgument] SplatArgument -# 269| 0: [ReservedWord] * +# 269| 1: [BlockArgument] BlockArgument +# 269| 0: [ReservedWord] & # 269| 2: [ReservedWord] ) -# 272| 84: [Call] Call +# 271| 82: [Call] Call +# 271| 0: [Identifier] foo +# 271| 1: [ArgumentList] ArgumentList +# 271| 0: [ReservedWord] ( +# 271| 1: [SplatArgument] SplatArgument +# 271| 0: [ReservedWord] * +# 271| 1: [Identifier] bar +# 271| 2: [ReservedWord] ) +# 272| 83: [Call] Call # 272| 0: [Identifier] foo # 272| 1: [ArgumentList] ArgumentList # 272| 0: [ReservedWord] ( -# 272| 1: [HashSplatArgument] HashSplatArgument -# 272| 0: [ReservedWord] ** -# 272| 1: [Identifier] bar +# 272| 1: [SplatArgument] SplatArgument +# 272| 0: [ReservedWord] * +# 272| 1: [Call] Call +# 272| 0: [Constant] X +# 272| 1: [ReservedWord] :: +# 272| 2: [Identifier] bar # 272| 2: [ReservedWord] ) -# 273| 85: [Call] Call +# 273| 84: [Call] Call # 273| 0: [Identifier] foo # 273| 1: [ArgumentList] ArgumentList # 273| 0: [ReservedWord] ( -# 273| 1: [HashSplatArgument] HashSplatArgument -# 273| 0: [ReservedWord] ** -# 273| 1: [Call] Call -# 273| 0: [Constant] X -# 273| 1: [ReservedWord] :: -# 273| 2: [Identifier] bar +# 273| 1: [SplatArgument] SplatArgument +# 273| 0: [ReservedWord] * # 273| 2: [ReservedWord] ) -# 274| 86: [Call] Call -# 274| 0: [Identifier] foo -# 274| 1: [ArgumentList] ArgumentList -# 274| 0: [ReservedWord] ( -# 274| 1: [HashSplatArgument] HashSplatArgument -# 274| 0: [ReservedWord] ** -# 274| 2: [ReservedWord] ) -# 277| 87: [Call] Call +# 276| 85: [Call] Call +# 276| 0: [Identifier] foo +# 276| 1: [ArgumentList] ArgumentList +# 276| 0: [ReservedWord] ( +# 276| 1: [HashSplatArgument] HashSplatArgument +# 276| 0: [ReservedWord] ** +# 276| 1: [Identifier] bar +# 276| 2: [ReservedWord] ) +# 277| 86: [Call] Call # 277| 0: [Identifier] foo # 277| 1: [ArgumentList] ArgumentList # 277| 0: [ReservedWord] ( -# 277| 1: [Pair] Pair -# 277| 0: [HashKeySymbol] blah -# 277| 1: [ReservedWord] : -# 277| 2: [Identifier] bar +# 277| 1: [HashSplatArgument] HashSplatArgument +# 277| 0: [ReservedWord] ** +# 277| 1: [Call] Call +# 277| 0: [Constant] X +# 277| 1: [ReservedWord] :: +# 277| 2: [Identifier] bar # 277| 2: [ReservedWord] ) -# 278| 88: [Call] Call +# 278| 87: [Call] Call # 278| 0: [Identifier] foo # 278| 1: [ArgumentList] ArgumentList # 278| 0: [ReservedWord] ( -# 278| 1: [Pair] Pair -# 278| 0: [HashKeySymbol] blah -# 278| 1: [ReservedWord] : -# 278| 2: [Call] Call -# 278| 0: [Constant] X -# 278| 1: [ReservedWord] :: -# 278| 2: [Identifier] bar +# 278| 1: [HashSplatArgument] HashSplatArgument +# 278| 0: [ReservedWord] ** # 278| 2: [ReservedWord] ) -# 283| 89: [Class] Class -# 283| 0: [ReservedWord] class -# 283| 1: [Constant] MyClass -# 284| 2: [BodyStatement] BodyStatement -# 284| 0: [Method] Method -# 284| 0: [ReservedWord] def -# 284| 1: [Identifier] my_method -# 285| 2: [BodyStatement] BodyStatement -# 285| 0: [Super] super -# 286| 1: [Call] Call -# 286| 0: [Super] super -# 286| 1: [ArgumentList] ArgumentList -# 286| 0: [ReservedWord] ( -# 286| 1: [ReservedWord] ) -# 287| 2: [Call] Call -# 287| 0: [Super] super -# 287| 1: [ArgumentList] ArgumentList -# 287| 0: [String] String -# 287| 0: [ReservedWord] ' -# 287| 1: [StringContent] blah -# 287| 2: [ReservedWord] ' -# 288| 3: [Call] Call -# 288| 0: [Super] super -# 288| 1: [ArgumentList] ArgumentList -# 288| 0: [Integer] 1 -# 288| 1: [ReservedWord] , -# 288| 2: [Integer] 2 -# 288| 3: [ReservedWord] , -# 288| 4: [Integer] 3 -# 289| 4: [Call] Call -# 289| 0: [Super] super -# 289| 1: [Block] Block -# 289| 0: [ReservedWord] { -# 289| 1: [BlockParameters] BlockParameters -# 289| 0: [ReservedWord] | -# 289| 1: [Identifier] x -# 289| 2: [ReservedWord] | -# 289| 2: [BlockBody] BlockBody -# 289| 0: [Binary] Binary -# 289| 0: [Identifier] x -# 289| 1: [ReservedWord] + -# 289| 2: [Integer] 1 -# 289| 3: [ReservedWord] } -# 290| 5: [Call] Call +# 281| 88: [Call] Call +# 281| 0: [Identifier] foo +# 281| 1: [ArgumentList] ArgumentList +# 281| 0: [ReservedWord] ( +# 281| 1: [Pair] Pair +# 281| 0: [HashKeySymbol] blah +# 281| 1: [ReservedWord] : +# 281| 2: [Identifier] bar +# 281| 2: [ReservedWord] ) +# 282| 89: [Call] Call +# 282| 0: [Identifier] foo +# 282| 1: [ArgumentList] ArgumentList +# 282| 0: [ReservedWord] ( +# 282| 1: [Pair] Pair +# 282| 0: [HashKeySymbol] blah +# 282| 1: [ReservedWord] : +# 282| 2: [Call] Call +# 282| 0: [Constant] X +# 282| 1: [ReservedWord] :: +# 282| 2: [Identifier] bar +# 282| 2: [ReservedWord] ) +# 287| 90: [Class] Class +# 287| 0: [ReservedWord] class +# 287| 1: [Constant] MyClass +# 288| 2: [BodyStatement] BodyStatement +# 288| 0: [Method] Method +# 288| 0: [ReservedWord] def +# 288| 1: [Identifier] my_method +# 289| 2: [BodyStatement] BodyStatement +# 289| 0: [Super] super +# 290| 1: [Call] Call # 290| 0: [Super] super -# 290| 1: [DoBlock] DoBlock -# 290| 0: [ReservedWord] do -# 290| 1: [BlockParameters] BlockParameters -# 290| 0: [ReservedWord] | -# 290| 1: [Identifier] x -# 290| 2: [ReservedWord] | -# 290| 2: [BodyStatement] BodyStatement -# 290| 0: [Binary] Binary -# 290| 0: [Identifier] x -# 290| 1: [ReservedWord] * -# 290| 2: [Integer] 2 -# 290| 3: [ReservedWord] end -# 291| 6: [Call] Call +# 290| 1: [ArgumentList] ArgumentList +# 290| 0: [ReservedWord] ( +# 290| 1: [ReservedWord] ) +# 291| 2: [Call] Call # 291| 0: [Super] super # 291| 1: [ArgumentList] ArgumentList -# 291| 0: [Integer] 4 -# 291| 1: [ReservedWord] , -# 291| 2: [Integer] 5 -# 291| 2: [Block] Block -# 291| 0: [ReservedWord] { -# 291| 1: [BlockParameters] BlockParameters -# 291| 0: [ReservedWord] | -# 291| 1: [Identifier] x -# 291| 2: [ReservedWord] | -# 291| 2: [BlockBody] BlockBody -# 291| 0: [Binary] Binary -# 291| 0: [Identifier] x -# 291| 1: [ReservedWord] + -# 291| 2: [Integer] 100 -# 291| 3: [ReservedWord] } -# 292| 7: [Call] Call +# 291| 0: [String] String +# 291| 0: [ReservedWord] ' +# 291| 1: [StringContent] blah +# 291| 2: [ReservedWord] ' +# 292| 3: [Call] Call # 292| 0: [Super] super # 292| 1: [ArgumentList] ArgumentList -# 292| 0: [Integer] 6 +# 292| 0: [Integer] 1 # 292| 1: [ReservedWord] , -# 292| 2: [Integer] 7 -# 292| 2: [DoBlock] DoBlock -# 292| 0: [ReservedWord] do -# 292| 1: [BlockParameters] BlockParameters -# 292| 0: [ReservedWord] | -# 292| 1: [Identifier] x -# 292| 2: [ReservedWord] | -# 292| 2: [BodyStatement] BodyStatement -# 292| 0: [Binary] Binary -# 292| 0: [Identifier] x -# 292| 1: [ReservedWord] + -# 292| 2: [Integer] 200 -# 292| 3: [ReservedWord] end -# 293| 3: [ReservedWord] end -# 294| 3: [ReservedWord] end -# 300| 90: [Class] Class -# 300| 0: [ReservedWord] class -# 300| 1: [Constant] AnotherClass -# 301| 2: [BodyStatement] BodyStatement -# 301| 0: [Method] Method -# 301| 0: [ReservedWord] def -# 301| 1: [Identifier] another_method -# 302| 2: [BodyStatement] BodyStatement -# 302| 0: [Call] Call -# 302| 0: [Identifier] foo -# 302| 1: [ReservedWord] . -# 302| 2: [Identifier] super -# 303| 1: [Call] Call -# 303| 0: [Self] self -# 303| 1: [ReservedWord] . -# 303| 2: [Identifier] super -# 304| 2: [Call] Call -# 304| 0: [Super] super -# 304| 1: [ReservedWord] . -# 304| 2: [Identifier] super -# 305| 3: [ReservedWord] end -# 306| 3: [ReservedWord] end -# 309| 91: [Call] Call -# 309| 0: [Identifier] foo -# 309| 1: [ReservedWord] . -# 309| 2: [ArgumentList] ArgumentList -# 309| 0: [ReservedWord] ( -# 309| 1: [ReservedWord] ) -# 310| 92: [Call] Call -# 310| 0: [Identifier] foo -# 310| 1: [ReservedWord] . -# 310| 2: [ArgumentList] ArgumentList -# 310| 0: [ReservedWord] ( -# 310| 1: [Integer] 1 -# 310| 2: [ReservedWord] ) -# 313| 93: [Assignment] Assignment -# 313| 0: [Call] Call -# 313| 0: [Self] self -# 313| 1: [ReservedWord] . -# 313| 2: [Identifier] foo -# 313| 1: [ReservedWord] = -# 313| 2: [Integer] 10 -# 314| 94: [Assignment] Assignment -# 314| 0: [ElementReference] ElementReference -# 314| 0: [Identifier] foo -# 314| 1: [ReservedWord] [ -# 314| 2: [Integer] 0 -# 314| 3: [ReservedWord] ] -# 314| 1: [ReservedWord] = -# 314| 2: [Integer] 10 -# 315| 95: [Assignment] Assignment -# 315| 0: [LeftAssignmentList] LeftAssignmentList -# 315| 0: [Call] Call -# 315| 0: [Self] self -# 315| 1: [ReservedWord] . -# 315| 2: [Identifier] foo -# 315| 1: [ReservedWord] , -# 315| 2: [RestAssignment] RestAssignment -# 315| 0: [ReservedWord] * -# 315| 1: [Call] Call -# 315| 0: [Self] self -# 315| 1: [ReservedWord] . -# 315| 2: [Identifier] bar -# 315| 3: [ReservedWord] , -# 315| 4: [ElementReference] ElementReference -# 315| 0: [Identifier] foo -# 315| 1: [ReservedWord] [ -# 315| 2: [Integer] 4 -# 315| 3: [ReservedWord] ] -# 315| 1: [ReservedWord] = -# 315| 2: [Array] Array -# 315| 0: [ReservedWord] [ -# 315| 1: [Integer] 1 -# 315| 2: [ReservedWord] , -# 315| 3: [Integer] 2 -# 315| 4: [ReservedWord] , -# 315| 5: [Integer] 3 -# 315| 6: [ReservedWord] , -# 315| 7: [Integer] 4 -# 315| 8: [ReservedWord] ] -# 316| 96: [Assignment] Assignment -# 316| 0: [LeftAssignmentList] LeftAssignmentList -# 316| 0: [Identifier] a -# 316| 1: [ReservedWord] , -# 316| 2: [RestAssignment] RestAssignment -# 316| 0: [ReservedWord] * -# 316| 1: [ElementReference] ElementReference -# 316| 0: [Identifier] foo -# 316| 1: [ReservedWord] [ -# 316| 2: [Integer] 5 -# 316| 3: [ReservedWord] ] -# 316| 1: [ReservedWord] = -# 316| 2: [Array] Array -# 316| 0: [ReservedWord] [ -# 316| 1: [Integer] 1 -# 316| 2: [ReservedWord] , -# 316| 3: [Integer] 2 -# 316| 4: [ReservedWord] , -# 316| 5: [Integer] 3 -# 316| 6: [ReservedWord] ] -# 317| 97: [OperatorAssignment] OperatorAssignment +# 292| 2: [Integer] 2 +# 292| 3: [ReservedWord] , +# 292| 4: [Integer] 3 +# 293| 4: [Call] Call +# 293| 0: [Super] super +# 293| 1: [Block] Block +# 293| 0: [ReservedWord] { +# 293| 1: [BlockParameters] BlockParameters +# 293| 0: [ReservedWord] | +# 293| 1: [Identifier] x +# 293| 2: [ReservedWord] | +# 293| 2: [BlockBody] BlockBody +# 293| 0: [Binary] Binary +# 293| 0: [Identifier] x +# 293| 1: [ReservedWord] + +# 293| 2: [Integer] 1 +# 293| 3: [ReservedWord] } +# 294| 5: [Call] Call +# 294| 0: [Super] super +# 294| 1: [DoBlock] DoBlock +# 294| 0: [ReservedWord] do +# 294| 1: [BlockParameters] BlockParameters +# 294| 0: [ReservedWord] | +# 294| 1: [Identifier] x +# 294| 2: [ReservedWord] | +# 294| 2: [BodyStatement] BodyStatement +# 294| 0: [Binary] Binary +# 294| 0: [Identifier] x +# 294| 1: [ReservedWord] * +# 294| 2: [Integer] 2 +# 294| 3: [ReservedWord] end +# 295| 6: [Call] Call +# 295| 0: [Super] super +# 295| 1: [ArgumentList] ArgumentList +# 295| 0: [Integer] 4 +# 295| 1: [ReservedWord] , +# 295| 2: [Integer] 5 +# 295| 2: [Block] Block +# 295| 0: [ReservedWord] { +# 295| 1: [BlockParameters] BlockParameters +# 295| 0: [ReservedWord] | +# 295| 1: [Identifier] x +# 295| 2: [ReservedWord] | +# 295| 2: [BlockBody] BlockBody +# 295| 0: [Binary] Binary +# 295| 0: [Identifier] x +# 295| 1: [ReservedWord] + +# 295| 2: [Integer] 100 +# 295| 3: [ReservedWord] } +# 296| 7: [Call] Call +# 296| 0: [Super] super +# 296| 1: [ArgumentList] ArgumentList +# 296| 0: [Integer] 6 +# 296| 1: [ReservedWord] , +# 296| 2: [Integer] 7 +# 296| 2: [DoBlock] DoBlock +# 296| 0: [ReservedWord] do +# 296| 1: [BlockParameters] BlockParameters +# 296| 0: [ReservedWord] | +# 296| 1: [Identifier] x +# 296| 2: [ReservedWord] | +# 296| 2: [BodyStatement] BodyStatement +# 296| 0: [Binary] Binary +# 296| 0: [Identifier] x +# 296| 1: [ReservedWord] + +# 296| 2: [Integer] 200 +# 296| 3: [ReservedWord] end +# 297| 3: [ReservedWord] end +# 298| 3: [ReservedWord] end +# 304| 91: [Class] Class +# 304| 0: [ReservedWord] class +# 304| 1: [Constant] AnotherClass +# 305| 2: [BodyStatement] BodyStatement +# 305| 0: [Method] Method +# 305| 0: [ReservedWord] def +# 305| 1: [Identifier] another_method +# 306| 2: [BodyStatement] BodyStatement +# 306| 0: [Call] Call +# 306| 0: [Identifier] foo +# 306| 1: [ReservedWord] . +# 306| 2: [Identifier] super +# 307| 1: [Call] Call +# 307| 0: [Self] self +# 307| 1: [ReservedWord] . +# 307| 2: [Identifier] super +# 308| 2: [Call] Call +# 308| 0: [Super] super +# 308| 1: [ReservedWord] . +# 308| 2: [Identifier] super +# 309| 3: [ReservedWord] end +# 310| 3: [ReservedWord] end +# 313| 92: [Call] Call +# 313| 0: [Identifier] foo +# 313| 1: [ReservedWord] . +# 313| 2: [ArgumentList] ArgumentList +# 313| 0: [ReservedWord] ( +# 313| 1: [ReservedWord] ) +# 314| 93: [Call] Call +# 314| 0: [Identifier] foo +# 314| 1: [ReservedWord] . +# 314| 2: [ArgumentList] ArgumentList +# 314| 0: [ReservedWord] ( +# 314| 1: [Integer] 1 +# 314| 2: [ReservedWord] ) +# 317| 94: [Assignment] Assignment # 317| 0: [Call] Call # 317| 0: [Self] self # 317| 1: [ReservedWord] . -# 317| 2: [Identifier] count -# 317| 1: [ReservedWord] += -# 317| 2: [Integer] 1 -# 318| 98: [OperatorAssignment] OperatorAssignment +# 317| 2: [Identifier] foo +# 317| 1: [ReservedWord] = +# 317| 2: [Integer] 10 +# 318| 95: [Assignment] Assignment # 318| 0: [ElementReference] ElementReference # 318| 0: [Identifier] foo # 318| 1: [ReservedWord] [ # 318| 2: [Integer] 0 # 318| 3: [ReservedWord] ] -# 318| 1: [ReservedWord] += -# 318| 2: [Integer] 1 -# 319| 99: [OperatorAssignment] OperatorAssignment -# 319| 0: [ElementReference] ElementReference +# 318| 1: [ReservedWord] = +# 318| 2: [Integer] 10 +# 319| 96: [Assignment] Assignment +# 319| 0: [LeftAssignmentList] LeftAssignmentList # 319| 0: [Call] Call -# 319| 0: [Identifier] foo +# 319| 0: [Self] self # 319| 1: [ReservedWord] . -# 319| 2: [Identifier] bar -# 319| 1: [ReservedWord] [ -# 319| 2: [Integer] 0 -# 319| 3: [ReservedWord] , -# 319| 4: [Call] Call -# 319| 0: [Identifier] foo -# 319| 1: [ReservedWord] . -# 319| 2: [Identifier] baz -# 319| 5: [ReservedWord] , -# 319| 6: [Binary] Binary -# 319| 0: [Call] Call -# 319| 0: [Identifier] foo +# 319| 2: [Identifier] foo +# 319| 1: [ReservedWord] , +# 319| 2: [RestAssignment] RestAssignment +# 319| 0: [ReservedWord] * +# 319| 1: [Call] Call +# 319| 0: [Self] self # 319| 1: [ReservedWord] . -# 319| 2: [Identifier] boo -# 319| 1: [ReservedWord] + -# 319| 2: [Integer] 1 -# 319| 7: [ReservedWord] ] -# 319| 1: [ReservedWord] *= -# 319| 2: [Integer] 2 -# 322| 100: [Method] Method -# 322| 0: [ReservedWord] def -# 322| 1: [Identifier] foo -# 322| 2: [ReservedWord] = -# 322| 3: [Identifier] bar -# 323| 101: [Method] Method -# 323| 0: [ReservedWord] def -# 323| 1: [Identifier] foo -# 323| 2: [MethodParameters] MethodParameters -# 323| 0: [ReservedWord] ( -# 323| 1: [ReservedWord] ) -# 323| 3: [ReservedWord] = -# 323| 4: [Identifier] bar -# 324| 102: [Method] Method -# 324| 0: [ReservedWord] def -# 324| 1: [Identifier] foo -# 324| 2: [MethodParameters] MethodParameters -# 324| 0: [ReservedWord] ( -# 324| 1: [Identifier] x -# 324| 2: [ReservedWord] ) -# 324| 3: [ReservedWord] = -# 324| 4: [Identifier] bar -# 325| 103: [SingletonMethod] SingletonMethod -# 325| 0: [ReservedWord] def -# 325| 1: [Constant] Object -# 325| 2: [ReservedWord] . -# 325| 3: [Identifier] foo -# 325| 4: [ReservedWord] = -# 325| 5: [Identifier] bar -# 326| 104: [SingletonMethod] SingletonMethod +# 319| 2: [Identifier] bar +# 319| 3: [ReservedWord] , +# 319| 4: [ElementReference] ElementReference +# 319| 0: [Identifier] foo +# 319| 1: [ReservedWord] [ +# 319| 2: [Integer] 4 +# 319| 3: [ReservedWord] ] +# 319| 1: [ReservedWord] = +# 319| 2: [Array] Array +# 319| 0: [ReservedWord] [ +# 319| 1: [Integer] 1 +# 319| 2: [ReservedWord] , +# 319| 3: [Integer] 2 +# 319| 4: [ReservedWord] , +# 319| 5: [Integer] 3 +# 319| 6: [ReservedWord] , +# 319| 7: [Integer] 4 +# 319| 8: [ReservedWord] ] +# 320| 97: [Assignment] Assignment +# 320| 0: [LeftAssignmentList] LeftAssignmentList +# 320| 0: [Identifier] a +# 320| 1: [ReservedWord] , +# 320| 2: [RestAssignment] RestAssignment +# 320| 0: [ReservedWord] * +# 320| 1: [ElementReference] ElementReference +# 320| 0: [Identifier] foo +# 320| 1: [ReservedWord] [ +# 320| 2: [Integer] 5 +# 320| 3: [ReservedWord] ] +# 320| 1: [ReservedWord] = +# 320| 2: [Array] Array +# 320| 0: [ReservedWord] [ +# 320| 1: [Integer] 1 +# 320| 2: [ReservedWord] , +# 320| 3: [Integer] 2 +# 320| 4: [ReservedWord] , +# 320| 5: [Integer] 3 +# 320| 6: [ReservedWord] ] +# 321| 98: [OperatorAssignment] OperatorAssignment +# 321| 0: [Call] Call +# 321| 0: [Self] self +# 321| 1: [ReservedWord] . +# 321| 2: [Identifier] count +# 321| 1: [ReservedWord] += +# 321| 2: [Integer] 1 +# 322| 99: [OperatorAssignment] OperatorAssignment +# 322| 0: [ElementReference] ElementReference +# 322| 0: [Identifier] foo +# 322| 1: [ReservedWord] [ +# 322| 2: [Integer] 0 +# 322| 3: [ReservedWord] ] +# 322| 1: [ReservedWord] += +# 322| 2: [Integer] 1 +# 323| 100: [OperatorAssignment] OperatorAssignment +# 323| 0: [ElementReference] ElementReference +# 323| 0: [Call] Call +# 323| 0: [Identifier] foo +# 323| 1: [ReservedWord] . +# 323| 2: [Identifier] bar +# 323| 1: [ReservedWord] [ +# 323| 2: [Integer] 0 +# 323| 3: [ReservedWord] , +# 323| 4: [Call] Call +# 323| 0: [Identifier] foo +# 323| 1: [ReservedWord] . +# 323| 2: [Identifier] baz +# 323| 5: [ReservedWord] , +# 323| 6: [Binary] Binary +# 323| 0: [Call] Call +# 323| 0: [Identifier] foo +# 323| 1: [ReservedWord] . +# 323| 2: [Identifier] boo +# 323| 1: [ReservedWord] + +# 323| 2: [Integer] 1 +# 323| 7: [ReservedWord] ] +# 323| 1: [ReservedWord] *= +# 323| 2: [Integer] 2 +# 326| 101: [Method] Method # 326| 0: [ReservedWord] def -# 326| 1: [Constant] Object -# 326| 2: [ReservedWord] . -# 326| 3: [Identifier] foo -# 326| 4: [MethodParameters] MethodParameters -# 326| 0: [ReservedWord] ( -# 326| 1: [Identifier] x -# 326| 2: [ReservedWord] ) -# 326| 5: [ReservedWord] = -# 326| 6: [Identifier] bar -# 327| 105: [Method] Method +# 326| 1: [Identifier] foo +# 326| 2: [ReservedWord] = +# 326| 3: [Identifier] bar +# 327| 102: [Method] Method # 327| 0: [ReservedWord] def # 327| 1: [Identifier] foo # 327| 2: [MethodParameters] MethodParameters # 327| 0: [ReservedWord] ( # 327| 1: [ReservedWord] ) # 327| 3: [ReservedWord] = -# 327| 4: [RescueModifier] RescueModifier -# 327| 0: [Identifier] bar -# 327| 1: [ReservedWord] rescue -# 327| 2: [ParenthesizedStatements] ParenthesizedStatements -# 327| 0: [ReservedWord] ( -# 327| 1: [Call] Call -# 327| 0: [Identifier] print -# 327| 1: [ArgumentList] ArgumentList -# 327| 0: [String] String -# 327| 0: [ReservedWord] " -# 327| 1: [StringContent] error -# 327| 2: [ReservedWord] " -# 327| 2: [ReservedWord] ) -# 330| 106: [Method] Method +# 327| 4: [Identifier] bar +# 328| 103: [Method] Method +# 328| 0: [ReservedWord] def +# 328| 1: [Identifier] foo +# 328| 2: [MethodParameters] MethodParameters +# 328| 0: [ReservedWord] ( +# 328| 1: [Identifier] x +# 328| 2: [ReservedWord] ) +# 328| 3: [ReservedWord] = +# 328| 4: [Identifier] bar +# 329| 104: [SingletonMethod] SingletonMethod +# 329| 0: [ReservedWord] def +# 329| 1: [Constant] Object +# 329| 2: [ReservedWord] . +# 329| 3: [Identifier] foo +# 329| 4: [ReservedWord] = +# 329| 5: [Identifier] bar +# 330| 105: [SingletonMethod] SingletonMethod # 330| 0: [ReservedWord] def -# 330| 1: [Identifier] foo -# 330| 2: [MethodParameters] MethodParameters +# 330| 1: [Constant] Object +# 330| 2: [ReservedWord] . +# 330| 3: [Identifier] foo +# 330| 4: [MethodParameters] MethodParameters # 330| 0: [ReservedWord] ( -# 330| 1: [ForwardParameter] ... -# 330| 0: [ReservedWord] ... +# 330| 1: [Identifier] x # 330| 2: [ReservedWord] ) -# 331| 3: [BodyStatement] BodyStatement -# 331| 0: [Call] Call -# 331| 0: [Super] super -# 331| 1: [ArgumentList] ArgumentList -# 331| 0: [ReservedWord] ( -# 331| 1: [ForwardArgument] ... -# 331| 0: [ReservedWord] ... -# 331| 2: [ReservedWord] ) -# 332| 4: [ReservedWord] end +# 330| 5: [ReservedWord] = +# 330| 6: [Identifier] bar +# 331| 106: [Method] Method +# 331| 0: [ReservedWord] def +# 331| 1: [Identifier] foo +# 331| 2: [MethodParameters] MethodParameters +# 331| 0: [ReservedWord] ( +# 331| 1: [ReservedWord] ) +# 331| 3: [ReservedWord] = +# 331| 4: [RescueModifier] RescueModifier +# 331| 0: [Identifier] bar +# 331| 1: [ReservedWord] rescue +# 331| 2: [ParenthesizedStatements] ParenthesizedStatements +# 331| 0: [ReservedWord] ( +# 331| 1: [Call] Call +# 331| 0: [Identifier] print +# 331| 1: [ArgumentList] ArgumentList +# 331| 0: [String] String +# 331| 0: [ReservedWord] " +# 331| 1: [StringContent] error +# 331| 2: [ReservedWord] " +# 331| 2: [ReservedWord] ) # 334| 107: [Method] Method # 334| 0: [ReservedWord] def # 334| 1: [Identifier] foo # 334| 2: [MethodParameters] MethodParameters # 334| 0: [ReservedWord] ( -# 334| 1: [Identifier] a -# 334| 2: [ReservedWord] , -# 334| 3: [Identifier] b -# 334| 4: [ReservedWord] , -# 334| 5: [ForwardParameter] ... +# 334| 1: [ForwardParameter] ... # 334| 0: [ReservedWord] ... -# 334| 6: [ReservedWord] ) +# 334| 2: [ReservedWord] ) # 335| 3: [BodyStatement] BodyStatement # 335| 0: [Call] Call -# 335| 0: [Identifier] bar +# 335| 0: [Super] super # 335| 1: [ArgumentList] ArgumentList # 335| 0: [ReservedWord] ( -# 335| 1: [Identifier] b -# 335| 2: [ReservedWord] , -# 335| 3: [ForwardArgument] ... +# 335| 1: [ForwardArgument] ... # 335| 0: [ReservedWord] ... -# 335| 4: [ReservedWord] ) +# 335| 2: [ReservedWord] ) # 336| 4: [ReservedWord] end -# 339| 108: [For] For -# 339| 0: [ReservedWord] for -# 339| 1: [LeftAssignmentList] LeftAssignmentList -# 339| 0: [Identifier] x -# 339| 1: [ReservedWord] , -# 339| 2: [Identifier] y -# 339| 3: [ReservedWord] , -# 339| 4: [Identifier] z -# 339| 2: [In] In -# 339| 0: [ReservedWord] in -# 339| 1: [Array] Array -# 339| 0: [ReservedWord] [ -# 339| 1: [Array] Array -# 339| 0: [ReservedWord] [ -# 339| 1: [Integer] 1 +# 338| 108: [Method] Method +# 338| 0: [ReservedWord] def +# 338| 1: [Identifier] foo +# 338| 2: [MethodParameters] MethodParameters +# 338| 0: [ReservedWord] ( +# 338| 1: [Identifier] a +# 338| 2: [ReservedWord] , +# 338| 3: [Identifier] b +# 338| 4: [ReservedWord] , +# 338| 5: [ForwardParameter] ... +# 338| 0: [ReservedWord] ... +# 338| 6: [ReservedWord] ) +# 339| 3: [BodyStatement] BodyStatement +# 339| 0: [Call] Call +# 339| 0: [Identifier] bar +# 339| 1: [ArgumentList] ArgumentList +# 339| 0: [ReservedWord] ( +# 339| 1: [Identifier] b # 339| 2: [ReservedWord] , -# 339| 3: [Integer] 2 -# 339| 4: [ReservedWord] , -# 339| 5: [Integer] 3 -# 339| 6: [ReservedWord] ] -# 339| 2: [ReservedWord] , -# 339| 3: [Array] Array -# 339| 0: [ReservedWord] [ -# 339| 1: [Integer] 4 -# 339| 2: [ReservedWord] , -# 339| 3: [Integer] 5 -# 339| 4: [ReservedWord] , -# 339| 5: [Integer] 6 -# 339| 6: [ReservedWord] ] -# 339| 4: [ReservedWord] ] -# 339| 3: [Do] Do -# 340| 0: [Call] Call -# 340| 0: [Identifier] foo -# 340| 1: [ArgumentList] ArgumentList -# 340| 0: [Identifier] x -# 340| 1: [ReservedWord] , -# 340| 2: [Identifier] y -# 340| 3: [ReservedWord] , -# 340| 4: [Identifier] z -# 341| 1: [ReservedWord] end -# 343| 109: [Call] Call -# 343| 0: [Identifier] foo -# 343| 1: [ArgumentList] ArgumentList -# 343| 0: [ReservedWord] ( -# 343| 1: [Pair] Pair -# 343| 0: [HashKeySymbol] x -# 343| 1: [ReservedWord] : -# 343| 2: [Integer] 42 -# 343| 2: [ReservedWord] ) -# 344| 110: [Call] Call -# 344| 0: [Identifier] foo -# 344| 1: [ArgumentList] ArgumentList -# 344| 0: [ReservedWord] ( -# 344| 1: [Pair] Pair -# 344| 0: [HashKeySymbol] x -# 344| 1: [ReservedWord] : -# 344| 2: [ReservedWord] , -# 344| 3: [Pair] Pair -# 344| 0: [HashKeySymbol] novar -# 344| 1: [ReservedWord] : -# 344| 4: [ReservedWord] ) -# 345| 111: [Call] Call -# 345| 0: [Identifier] foo -# 345| 1: [ArgumentList] ArgumentList -# 345| 0: [ReservedWord] ( -# 345| 1: [Pair] Pair -# 345| 0: [HashKeySymbol] X -# 345| 1: [ReservedWord] : -# 345| 2: [Integer] 42 -# 345| 2: [ReservedWord] ) -# 346| 112: [Call] Call -# 346| 0: [Identifier] foo -# 346| 1: [ArgumentList] ArgumentList -# 346| 0: [ReservedWord] ( -# 346| 1: [Pair] Pair -# 346| 0: [HashKeySymbol] X -# 346| 1: [ReservedWord] : -# 346| 2: [ReservedWord] ) -# 349| 113: [Assignment] Assignment -# 349| 0: [Identifier] y -# 349| 1: [ReservedWord] = -# 349| 2: [Integer] 1 -# 350| 114: [Assignment] Assignment -# 350| 0: [Identifier] one -# 350| 1: [ReservedWord] = -# 350| 2: [Lambda] Lambda -# 350| 0: [ReservedWord] -> -# 350| 1: [LambdaParameters] LambdaParameters -# 350| 0: [ReservedWord] ( -# 350| 1: [Identifier] x -# 350| 2: [ReservedWord] ) -# 350| 2: [Block] Block -# 350| 0: [ReservedWord] { -# 350| 1: [BlockBody] BlockBody -# 350| 0: [Identifier] y -# 350| 2: [ReservedWord] } -# 351| 115: [Assignment] Assignment -# 351| 0: [Identifier] f -# 351| 1: [ReservedWord] = -# 351| 2: [Lambda] Lambda -# 351| 0: [ReservedWord] -> -# 351| 1: [LambdaParameters] LambdaParameters -# 351| 0: [ReservedWord] ( -# 351| 1: [Identifier] x -# 351| 2: [ReservedWord] ) -# 351| 2: [Block] Block -# 351| 0: [ReservedWord] { -# 351| 1: [BlockBody] BlockBody -# 351| 0: [Call] Call -# 351| 0: [Identifier] foo -# 351| 1: [ArgumentList] ArgumentList -# 351| 0: [Identifier] x -# 351| 2: [ReservedWord] } -# 352| 116: [Assignment] Assignment -# 352| 0: [Identifier] g -# 352| 1: [ReservedWord] = -# 352| 2: [Lambda] Lambda -# 352| 0: [ReservedWord] -> -# 352| 1: [LambdaParameters] LambdaParameters -# 352| 0: [ReservedWord] ( -# 352| 1: [Identifier] x -# 352| 2: [ReservedWord] ) -# 352| 2: [Block] Block -# 352| 0: [ReservedWord] { -# 352| 1: [BlockBody] BlockBody -# 352| 0: [Identifier] unknown_call -# 352| 2: [ReservedWord] } -# 353| 117: [Assignment] Assignment -# 353| 0: [Identifier] h +# 339| 3: [ForwardArgument] ... +# 339| 0: [ReservedWord] ... +# 339| 4: [ReservedWord] ) +# 340| 4: [ReservedWord] end +# 343| 109: [For] For +# 343| 0: [ReservedWord] for +# 343| 1: [LeftAssignmentList] LeftAssignmentList +# 343| 0: [Identifier] x +# 343| 1: [ReservedWord] , +# 343| 2: [Identifier] y +# 343| 3: [ReservedWord] , +# 343| 4: [Identifier] z +# 343| 2: [In] In +# 343| 0: [ReservedWord] in +# 343| 1: [Array] Array +# 343| 0: [ReservedWord] [ +# 343| 1: [Array] Array +# 343| 0: [ReservedWord] [ +# 343| 1: [Integer] 1 +# 343| 2: [ReservedWord] , +# 343| 3: [Integer] 2 +# 343| 4: [ReservedWord] , +# 343| 5: [Integer] 3 +# 343| 6: [ReservedWord] ] +# 343| 2: [ReservedWord] , +# 343| 3: [Array] Array +# 343| 0: [ReservedWord] [ +# 343| 1: [Integer] 4 +# 343| 2: [ReservedWord] , +# 343| 3: [Integer] 5 +# 343| 4: [ReservedWord] , +# 343| 5: [Integer] 6 +# 343| 6: [ReservedWord] ] +# 343| 4: [ReservedWord] ] +# 343| 3: [Do] Do +# 344| 0: [Call] Call +# 344| 0: [Identifier] foo +# 344| 1: [ArgumentList] ArgumentList +# 344| 0: [Identifier] x +# 344| 1: [ReservedWord] , +# 344| 2: [Identifier] y +# 344| 3: [ReservedWord] , +# 344| 4: [Identifier] z +# 345| 1: [ReservedWord] end +# 347| 110: [Call] Call +# 347| 0: [Identifier] foo +# 347| 1: [ArgumentList] ArgumentList +# 347| 0: [ReservedWord] ( +# 347| 1: [Pair] Pair +# 347| 0: [HashKeySymbol] x +# 347| 1: [ReservedWord] : +# 347| 2: [Integer] 42 +# 347| 2: [ReservedWord] ) +# 348| 111: [Call] Call +# 348| 0: [Identifier] foo +# 348| 1: [ArgumentList] ArgumentList +# 348| 0: [ReservedWord] ( +# 348| 1: [Pair] Pair +# 348| 0: [HashKeySymbol] x +# 348| 1: [ReservedWord] : +# 348| 2: [ReservedWord] , +# 348| 3: [Pair] Pair +# 348| 0: [HashKeySymbol] novar +# 348| 1: [ReservedWord] : +# 348| 4: [ReservedWord] ) +# 349| 112: [Call] Call +# 349| 0: [Identifier] foo +# 349| 1: [ArgumentList] ArgumentList +# 349| 0: [ReservedWord] ( +# 349| 1: [Pair] Pair +# 349| 0: [HashKeySymbol] X +# 349| 1: [ReservedWord] : +# 349| 2: [Integer] 42 +# 349| 2: [ReservedWord] ) +# 350| 113: [Call] Call +# 350| 0: [Identifier] foo +# 350| 1: [ArgumentList] ArgumentList +# 350| 0: [ReservedWord] ( +# 350| 1: [Pair] Pair +# 350| 0: [HashKeySymbol] X +# 350| 1: [ReservedWord] : +# 350| 2: [ReservedWord] ) +# 353| 114: [Assignment] Assignment +# 353| 0: [Identifier] y # 353| 1: [ReservedWord] = -# 353| 2: [Lambda] Lambda -# 353| 0: [ReservedWord] -> -# 353| 1: [LambdaParameters] LambdaParameters -# 353| 0: [ReservedWord] ( -# 353| 1: [Identifier] x -# 353| 2: [ReservedWord] ) -# 353| 2: [DoBlock] DoBlock -# 353| 0: [ReservedWord] do -# 354| 1: [BodyStatement] BodyStatement -# 354| 0: [Identifier] x -# 355| 1: [Identifier] y -# 356| 2: [Identifier] unknown_call -# 357| 2: [ReservedWord] end -# 360| 118: [Call] Call -# 360| 0: [Identifier] list -# 360| 1: [ReservedWord] . -# 360| 2: [Identifier] empty? -# 361| 119: [Call] Call -# 361| 0: [Identifier] list -# 361| 1: [ReservedWord] &. -# 361| 2: [Identifier] empty? -# 362| 120: [Call] Call -# 362| 0: [Identifier] list -# 362| 1: [ReservedWord] :: -# 362| 2: [Identifier] empty? -# 363| 121: [Call] Call -# 363| 0: [Identifier] foo -# 363| 1: [ReservedWord] &. -# 363| 2: [Identifier] bar -# 363| 3: [ArgumentList] ArgumentList -# 363| 0: [ReservedWord] ( -# 363| 1: [Integer] 1 -# 363| 2: [ReservedWord] , -# 363| 3: [Integer] 2 -# 363| 4: [ReservedWord] ) -# 363| 4: [Block] Block -# 363| 0: [ReservedWord] { -# 363| 1: [BlockParameters] BlockParameters -# 363| 0: [ReservedWord] | -# 363| 1: [Identifier] x -# 363| 2: [ReservedWord] | -# 363| 2: [BlockBody] BlockBody -# 363| 0: [Identifier] x -# 363| 3: [ReservedWord] } +# 353| 2: [Integer] 1 +# 354| 115: [Assignment] Assignment +# 354| 0: [Identifier] one +# 354| 1: [ReservedWord] = +# 354| 2: [Lambda] Lambda +# 354| 0: [ReservedWord] -> +# 354| 1: [LambdaParameters] LambdaParameters +# 354| 0: [ReservedWord] ( +# 354| 1: [Identifier] x +# 354| 2: [ReservedWord] ) +# 354| 2: [Block] Block +# 354| 0: [ReservedWord] { +# 354| 1: [BlockBody] BlockBody +# 354| 0: [Identifier] y +# 354| 2: [ReservedWord] } +# 355| 116: [Assignment] Assignment +# 355| 0: [Identifier] f +# 355| 1: [ReservedWord] = +# 355| 2: [Lambda] Lambda +# 355| 0: [ReservedWord] -> +# 355| 1: [LambdaParameters] LambdaParameters +# 355| 0: [ReservedWord] ( +# 355| 1: [Identifier] x +# 355| 2: [ReservedWord] ) +# 355| 2: [Block] Block +# 355| 0: [ReservedWord] { +# 355| 1: [BlockBody] BlockBody +# 355| 0: [Call] Call +# 355| 0: [Identifier] foo +# 355| 1: [ArgumentList] ArgumentList +# 355| 0: [Identifier] x +# 355| 2: [ReservedWord] } +# 356| 117: [Assignment] Assignment +# 356| 0: [Identifier] g +# 356| 1: [ReservedWord] = +# 356| 2: [Lambda] Lambda +# 356| 0: [ReservedWord] -> +# 356| 1: [LambdaParameters] LambdaParameters +# 356| 0: [ReservedWord] ( +# 356| 1: [Identifier] x +# 356| 2: [ReservedWord] ) +# 356| 2: [Block] Block +# 356| 0: [ReservedWord] { +# 356| 1: [BlockBody] BlockBody +# 356| 0: [Identifier] unknown_call +# 356| 2: [ReservedWord] } +# 357| 118: [Assignment] Assignment +# 357| 0: [Identifier] h +# 357| 1: [ReservedWord] = +# 357| 2: [Lambda] Lambda +# 357| 0: [ReservedWord] -> +# 357| 1: [LambdaParameters] LambdaParameters +# 357| 0: [ReservedWord] ( +# 357| 1: [Identifier] x +# 357| 2: [ReservedWord] ) +# 357| 2: [DoBlock] DoBlock +# 357| 0: [ReservedWord] do +# 358| 1: [BodyStatement] BodyStatement +# 358| 0: [Identifier] x +# 359| 1: [Identifier] y +# 360| 2: [Identifier] unknown_call +# 361| 2: [ReservedWord] end +# 364| 119: [Call] Call +# 364| 0: [Identifier] list +# 364| 1: [ReservedWord] . +# 364| 2: [Identifier] empty? +# 365| 120: [Call] Call +# 365| 0: [Identifier] list +# 365| 1: [ReservedWord] &. +# 365| 2: [Identifier] empty? +# 366| 121: [Call] Call +# 366| 0: [Identifier] list +# 366| 1: [ReservedWord] :: +# 366| 2: [Identifier] empty? +# 367| 122: [Call] Call +# 367| 0: [Identifier] foo +# 367| 1: [ReservedWord] &. +# 367| 2: [Identifier] bar +# 367| 3: [ArgumentList] ArgumentList +# 367| 0: [ReservedWord] ( +# 367| 1: [Integer] 1 +# 367| 2: [ReservedWord] , +# 367| 3: [Integer] 2 +# 367| 4: [ReservedWord] ) +# 367| 4: [Block] Block +# 367| 0: [ReservedWord] { +# 367| 1: [BlockParameters] BlockParameters +# 367| 0: [ReservedWord] | +# 367| 1: [Identifier] x +# 367| 2: [ReservedWord] | +# 367| 2: [BlockBody] BlockBody +# 367| 0: [Identifier] x +# 367| 3: [ReservedWord] } # 1| [Comment] # call with no receiver, arguments, or block # 4| [Comment] # call whose name is a scope resolution # 7| [Comment] # call with a receiver, no arguments or block @@ -1391,24 +1406,24 @@ calls/calls.rb: # 241| [Comment] # in a range # 245| [Comment] # the key/value in a hash pair # 248| [Comment] # rescue exceptions and ensure -# 258| [Comment] # rescue-modifier body and handler -# 262| [Comment] # block argument -# 266| [Comment] # splat argument -# 271| [Comment] # hash-splat argument -# 276| [Comment] # the value in a keyword argument -# 280| [Comment] # ------------------------------------------------------------------------------ -# 281| [Comment] # calls to `super` -# 296| [Comment] # ------------------------------------------------------------------------------ -# 297| [Comment] # calls to methods simply named `super`, i.e. *not* calls to the same method in -# 298| [Comment] # a parent classs, so these should be Call but not SuperCall -# 304| [Comment] # we expect the receiver to be a SuperCall, while the outer call should not (it's just a regular Call) -# 308| [Comment] # calls without method name -# 312| [Comment] # setter calls -# 321| [Comment] # endless method definitions -# 329| [Comment] # forward parameter and forwarded arguments -# 338| [Comment] # for loop over nested array -# 348| [Comment] # calls inside lambdas -# 359| [Comment] # calls with various call operators +# 262| [Comment] # rescue-modifier body and handler +# 266| [Comment] # block argument +# 270| [Comment] # splat argument +# 275| [Comment] # hash-splat argument +# 280| [Comment] # the value in a keyword argument +# 284| [Comment] # ------------------------------------------------------------------------------ +# 285| [Comment] # calls to `super` +# 300| [Comment] # ------------------------------------------------------------------------------ +# 301| [Comment] # calls to methods simply named `super`, i.e. *not* calls to the same method in +# 302| [Comment] # a parent classs, so these should be Call but not SuperCall +# 308| [Comment] # we expect the receiver to be a SuperCall, while the outer call should not (it's just a regular Call) +# 312| [Comment] # calls without method name +# 316| [Comment] # setter calls +# 325| [Comment] # endless method definitions +# 333| [Comment] # forward parameter and forwarded arguments +# 342| [Comment] # for loop over nested array +# 352| [Comment] # calls inside lambdas +# 363| [Comment] # calls with various call operators constants/constants.rb: # 1| [Program] Program # 1| 0: [Module] Module diff --git a/ruby/ql/test/library-tests/ast/ValueText.expected b/ruby/ql/test/library-tests/ast/ValueText.expected index e0ad853ba83..42eab5f74d9 100644 --- a/ruby/ql/test/library-tests/ast/ValueText.expected +++ b/ruby/ql/test/library-tests/ast/ValueText.expected @@ -12,79 +12,79 @@ exprValue | calls/calls.rb:33:14:33:16 | 200 | 200 | int | | calls/calls.rb:223:5:223:5 | nil | nil | nil | | calls/calls.rb:226:5:226:5 | nil | nil | nil | -| calls/calls.rb:277:5:277:8 | :blah | :blah | symbol | -| calls/calls.rb:278:5:278:8 | :blah | :blah | symbol | -| calls/calls.rb:287:11:287:16 | "blah" | blah | string | -| calls/calls.rb:288:11:288:11 | 1 | 1 | int | -| calls/calls.rb:288:14:288:14 | 2 | 2 | int | -| calls/calls.rb:288:17:288:17 | 3 | 3 | int | -| calls/calls.rb:289:21:289:21 | 1 | 1 | int | -| calls/calls.rb:290:22:290:22 | 2 | 2 | int | -| calls/calls.rb:291:11:291:11 | 4 | 4 | int | -| calls/calls.rb:291:14:291:14 | 5 | 5 | int | -| calls/calls.rb:291:26:291:28 | 100 | 100 | int | -| calls/calls.rb:292:11:292:11 | 6 | 6 | int | -| calls/calls.rb:292:14:292:14 | 7 | 7 | int | -| calls/calls.rb:292:27:292:29 | 200 | 200 | int | -| calls/calls.rb:310:6:310:6 | 1 | 1 | int | -| calls/calls.rb:313:1:313:8 | __synth__0 | 10 | int | -| calls/calls.rb:313:12:313:13 | 10 | 10 | int | -| calls/calls.rb:314:1:314:6 | __synth__0 | 10 | int | -| calls/calls.rb:314:5:314:5 | 0 | 0 | int | -| calls/calls.rb:314:10:314:11 | 10 | 10 | int | -| calls/calls.rb:315:1:315:8 | 0 | 0 | int | -| calls/calls.rb:315:12:315:19 | 1 | 1 | int | -| calls/calls.rb:315:12:315:19 | -2 | -2 | int | -| calls/calls.rb:315:22:315:27 | -1 | -1 | int | -| calls/calls.rb:315:26:315:26 | 4 | 4 | int | -| calls/calls.rb:315:32:315:32 | 1 | 1 | int | -| calls/calls.rb:315:35:315:35 | 2 | 2 | int | -| calls/calls.rb:315:38:315:38 | 3 | 3 | int | -| calls/calls.rb:315:41:315:41 | 4 | 4 | int | -| calls/calls.rb:316:1:316:1 | 0 | 0 | int | -| calls/calls.rb:316:5:316:10 | 1 | 1 | int | -| calls/calls.rb:316:5:316:10 | -1 | -1 | int | -| calls/calls.rb:316:9:316:9 | 5 | 5 | int | -| calls/calls.rb:316:15:316:15 | 1 | 1 | int | -| calls/calls.rb:316:18:316:18 | 2 | 2 | int | -| calls/calls.rb:316:21:316:21 | 3 | 3 | int | -| calls/calls.rb:317:15:317:15 | 1 | 1 | int | +| calls/calls.rb:281:5:281:8 | :blah | :blah | symbol | +| calls/calls.rb:282:5:282:8 | :blah | :blah | symbol | +| calls/calls.rb:291:11:291:16 | "blah" | blah | string | +| calls/calls.rb:292:11:292:11 | 1 | 1 | int | +| calls/calls.rb:292:14:292:14 | 2 | 2 | int | +| calls/calls.rb:292:17:292:17 | 3 | 3 | int | +| calls/calls.rb:293:21:293:21 | 1 | 1 | int | +| calls/calls.rb:294:22:294:22 | 2 | 2 | int | +| calls/calls.rb:295:11:295:11 | 4 | 4 | int | +| calls/calls.rb:295:14:295:14 | 5 | 5 | int | +| calls/calls.rb:295:26:295:28 | 100 | 100 | int | +| calls/calls.rb:296:11:296:11 | 6 | 6 | int | +| calls/calls.rb:296:14:296:14 | 7 | 7 | int | +| calls/calls.rb:296:27:296:29 | 200 | 200 | int | +| calls/calls.rb:314:6:314:6 | 1 | 1 | int | +| calls/calls.rb:317:1:317:8 | __synth__0 | 10 | int | +| calls/calls.rb:317:12:317:13 | 10 | 10 | int | +| calls/calls.rb:318:1:318:6 | __synth__0 | 10 | int | | calls/calls.rb:318:5:318:5 | 0 | 0 | int | -| calls/calls.rb:318:5:318:5 | __synth__1 | 0 | int | -| calls/calls.rb:318:5:318:5 | __synth__1 | 0 | int | -| calls/calls.rb:318:11:318:11 | 1 | 1 | int | -| calls/calls.rb:319:9:319:9 | 0 | 0 | int | -| calls/calls.rb:319:9:319:9 | __synth__1 | 0 | int | -| calls/calls.rb:319:9:319:9 | __synth__1 | 0 | int | -| calls/calls.rb:319:31:319:31 | 1 | 1 | int | -| calls/calls.rb:319:37:319:37 | 2 | 2 | int | -| calls/calls.rb:327:31:327:37 | "error" | error | string | -| calls/calls.rb:339:5:339:5 | 0 | 0 | int | -| calls/calls.rb:339:5:339:5 | nil | nil | nil | -| calls/calls.rb:339:8:339:8 | 1 | 1 | int | -| calls/calls.rb:339:8:339:8 | nil | nil | nil | -| calls/calls.rb:339:11:339:11 | 2 | 2 | int | -| calls/calls.rb:339:11:339:11 | nil | nil | nil | -| calls/calls.rb:339:18:339:18 | 1 | 1 | int | -| calls/calls.rb:339:20:339:20 | 2 | 2 | int | -| calls/calls.rb:339:22:339:22 | 3 | 3 | int | -| calls/calls.rb:339:27:339:27 | 4 | 4 | int | -| calls/calls.rb:339:29:339:29 | 5 | 5 | int | -| calls/calls.rb:339:31:339:31 | 6 | 6 | int | -| calls/calls.rb:343:5:343:5 | :x | :x | symbol | -| calls/calls.rb:343:8:343:9 | 42 | 42 | int | -| calls/calls.rb:344:5:344:5 | :x | :x | symbol | -| calls/calls.rb:344:9:344:13 | :novar | :novar | symbol | -| calls/calls.rb:345:5:345:5 | :X | :X | symbol | -| calls/calls.rb:345:8:345:9 | 42 | 42 | int | -| calls/calls.rb:346:5:346:5 | :X | :X | symbol | -| calls/calls.rb:349:5:349:5 | 1 | 1 | int | -| calls/calls.rb:361:1:361:4 | nil | nil | nil | -| calls/calls.rb:361:5:361:6 | nil | nil | nil | -| calls/calls.rb:363:1:363:3 | nil | nil | nil | -| calls/calls.rb:363:4:363:5 | nil | nil | nil | -| calls/calls.rb:363:10:363:10 | 1 | 1 | int | -| calls/calls.rb:363:12:363:12 | 2 | 2 | int | +| calls/calls.rb:318:10:318:11 | 10 | 10 | int | +| calls/calls.rb:319:1:319:8 | 0 | 0 | int | +| calls/calls.rb:319:12:319:19 | 1 | 1 | int | +| calls/calls.rb:319:12:319:19 | -2 | -2 | int | +| calls/calls.rb:319:22:319:27 | -1 | -1 | int | +| calls/calls.rb:319:26:319:26 | 4 | 4 | int | +| calls/calls.rb:319:32:319:32 | 1 | 1 | int | +| calls/calls.rb:319:35:319:35 | 2 | 2 | int | +| calls/calls.rb:319:38:319:38 | 3 | 3 | int | +| calls/calls.rb:319:41:319:41 | 4 | 4 | int | +| calls/calls.rb:320:1:320:1 | 0 | 0 | int | +| calls/calls.rb:320:5:320:10 | 1 | 1 | int | +| calls/calls.rb:320:5:320:10 | -1 | -1 | int | +| calls/calls.rb:320:9:320:9 | 5 | 5 | int | +| calls/calls.rb:320:15:320:15 | 1 | 1 | int | +| calls/calls.rb:320:18:320:18 | 2 | 2 | int | +| calls/calls.rb:320:21:320:21 | 3 | 3 | int | +| calls/calls.rb:321:15:321:15 | 1 | 1 | int | +| calls/calls.rb:322:5:322:5 | 0 | 0 | int | +| calls/calls.rb:322:5:322:5 | __synth__1 | 0 | int | +| calls/calls.rb:322:5:322:5 | __synth__1 | 0 | int | +| calls/calls.rb:322:11:322:11 | 1 | 1 | int | +| calls/calls.rb:323:9:323:9 | 0 | 0 | int | +| calls/calls.rb:323:9:323:9 | __synth__1 | 0 | int | +| calls/calls.rb:323:9:323:9 | __synth__1 | 0 | int | +| calls/calls.rb:323:31:323:31 | 1 | 1 | int | +| calls/calls.rb:323:37:323:37 | 2 | 2 | int | +| calls/calls.rb:331:31:331:37 | "error" | error | string | +| calls/calls.rb:343:5:343:5 | 0 | 0 | int | +| calls/calls.rb:343:5:343:5 | nil | nil | nil | +| calls/calls.rb:343:8:343:8 | 1 | 1 | int | +| calls/calls.rb:343:8:343:8 | nil | nil | nil | +| calls/calls.rb:343:11:343:11 | 2 | 2 | int | +| calls/calls.rb:343:11:343:11 | nil | nil | nil | +| calls/calls.rb:343:18:343:18 | 1 | 1 | int | +| calls/calls.rb:343:20:343:20 | 2 | 2 | int | +| calls/calls.rb:343:22:343:22 | 3 | 3 | int | +| calls/calls.rb:343:27:343:27 | 4 | 4 | int | +| calls/calls.rb:343:29:343:29 | 5 | 5 | int | +| calls/calls.rb:343:31:343:31 | 6 | 6 | int | +| calls/calls.rb:347:5:347:5 | :x | :x | symbol | +| calls/calls.rb:347:8:347:9 | 42 | 42 | int | +| calls/calls.rb:348:5:348:5 | :x | :x | symbol | +| calls/calls.rb:348:9:348:13 | :novar | :novar | symbol | +| calls/calls.rb:349:5:349:5 | :X | :X | symbol | +| calls/calls.rb:349:8:349:9 | 42 | 42 | int | +| calls/calls.rb:350:5:350:5 | :X | :X | symbol | +| calls/calls.rb:353:5:353:5 | 1 | 1 | int | +| calls/calls.rb:365:1:365:4 | nil | nil | nil | +| calls/calls.rb:365:5:365:6 | nil | nil | nil | +| calls/calls.rb:367:1:367:3 | nil | nil | nil | +| calls/calls.rb:367:4:367:5 | nil | nil | nil | +| calls/calls.rb:367:10:367:10 | 1 | 1 | int | +| calls/calls.rb:367:12:367:12 | 2 | 2 | int | | constants/constants.rb:3:19:3:27 | "const_a" | const_a | string | | constants/constants.rb:6:15:6:23 | "const_b" | const_b | string | | constants/constants.rb:17:12:17:18 | "Hello" | Hello | string | @@ -131,6 +131,7 @@ exprValue | control/cases.rb:11:9:11:9 | d | 0 | int | | control/cases.rb:12:5:12:7 | 200 | 200 | int | | control/cases.rb:14:5:14:7 | 300 | 300 | int | +| control/cases.rb:18:1:22:3 | true | true | boolean | | control/cases.rb:19:6:19:6 | a | 0 | int | | control/cases.rb:19:10:19:10 | b | 0 | int | | control/cases.rb:19:18:19:19 | 10 | 10 | int | @@ -975,79 +976,79 @@ exprCfgNodeValue | calls/calls.rb:33:14:33:16 | 200 | 200 | int | | calls/calls.rb:223:5:223:5 | nil | nil | nil | | calls/calls.rb:226:5:226:5 | nil | nil | nil | -| calls/calls.rb:277:5:277:8 | :blah | :blah | symbol | -| calls/calls.rb:278:5:278:8 | :blah | :blah | symbol | -| calls/calls.rb:287:11:287:16 | "blah" | blah | string | -| calls/calls.rb:288:11:288:11 | 1 | 1 | int | -| calls/calls.rb:288:14:288:14 | 2 | 2 | int | -| calls/calls.rb:288:17:288:17 | 3 | 3 | int | -| calls/calls.rb:289:21:289:21 | 1 | 1 | int | -| calls/calls.rb:290:22:290:22 | 2 | 2 | int | -| calls/calls.rb:291:11:291:11 | 4 | 4 | int | -| calls/calls.rb:291:14:291:14 | 5 | 5 | int | -| calls/calls.rb:291:26:291:28 | 100 | 100 | int | -| calls/calls.rb:292:11:292:11 | 6 | 6 | int | -| calls/calls.rb:292:14:292:14 | 7 | 7 | int | -| calls/calls.rb:292:27:292:29 | 200 | 200 | int | -| calls/calls.rb:310:6:310:6 | 1 | 1 | int | -| calls/calls.rb:313:1:313:8 | __synth__0 | 10 | int | -| calls/calls.rb:313:12:313:13 | 10 | 10 | int | -| calls/calls.rb:314:1:314:6 | __synth__0 | 10 | int | -| calls/calls.rb:314:5:314:5 | 0 | 0 | int | -| calls/calls.rb:314:10:314:11 | 10 | 10 | int | -| calls/calls.rb:315:1:315:8 | 0 | 0 | int | -| calls/calls.rb:315:12:315:19 | 1 | 1 | int | -| calls/calls.rb:315:12:315:19 | -2 | -2 | int | -| calls/calls.rb:315:22:315:27 | -1 | -1 | int | -| calls/calls.rb:315:26:315:26 | 4 | 4 | int | -| calls/calls.rb:315:32:315:32 | 1 | 1 | int | -| calls/calls.rb:315:35:315:35 | 2 | 2 | int | -| calls/calls.rb:315:38:315:38 | 3 | 3 | int | -| calls/calls.rb:315:41:315:41 | 4 | 4 | int | -| calls/calls.rb:316:1:316:1 | 0 | 0 | int | -| calls/calls.rb:316:5:316:10 | 1 | 1 | int | -| calls/calls.rb:316:5:316:10 | -1 | -1 | int | -| calls/calls.rb:316:9:316:9 | 5 | 5 | int | -| calls/calls.rb:316:15:316:15 | 1 | 1 | int | -| calls/calls.rb:316:18:316:18 | 2 | 2 | int | -| calls/calls.rb:316:21:316:21 | 3 | 3 | int | -| calls/calls.rb:317:15:317:15 | 1 | 1 | int | +| calls/calls.rb:281:5:281:8 | :blah | :blah | symbol | +| calls/calls.rb:282:5:282:8 | :blah | :blah | symbol | +| calls/calls.rb:291:11:291:16 | "blah" | blah | string | +| calls/calls.rb:292:11:292:11 | 1 | 1 | int | +| calls/calls.rb:292:14:292:14 | 2 | 2 | int | +| calls/calls.rb:292:17:292:17 | 3 | 3 | int | +| calls/calls.rb:293:21:293:21 | 1 | 1 | int | +| calls/calls.rb:294:22:294:22 | 2 | 2 | int | +| calls/calls.rb:295:11:295:11 | 4 | 4 | int | +| calls/calls.rb:295:14:295:14 | 5 | 5 | int | +| calls/calls.rb:295:26:295:28 | 100 | 100 | int | +| calls/calls.rb:296:11:296:11 | 6 | 6 | int | +| calls/calls.rb:296:14:296:14 | 7 | 7 | int | +| calls/calls.rb:296:27:296:29 | 200 | 200 | int | +| calls/calls.rb:314:6:314:6 | 1 | 1 | int | +| calls/calls.rb:317:1:317:8 | __synth__0 | 10 | int | +| calls/calls.rb:317:12:317:13 | 10 | 10 | int | +| calls/calls.rb:318:1:318:6 | __synth__0 | 10 | int | | calls/calls.rb:318:5:318:5 | 0 | 0 | int | -| calls/calls.rb:318:5:318:5 | __synth__1 | 0 | int | -| calls/calls.rb:318:5:318:5 | __synth__1 | 0 | int | -| calls/calls.rb:318:11:318:11 | 1 | 1 | int | -| calls/calls.rb:319:9:319:9 | 0 | 0 | int | -| calls/calls.rb:319:9:319:9 | __synth__1 | 0 | int | -| calls/calls.rb:319:9:319:9 | __synth__1 | 0 | int | -| calls/calls.rb:319:31:319:31 | 1 | 1 | int | -| calls/calls.rb:319:37:319:37 | 2 | 2 | int | -| calls/calls.rb:327:31:327:37 | "error" | error | string | -| calls/calls.rb:339:5:339:5 | 0 | 0 | int | -| calls/calls.rb:339:5:339:5 | nil | nil | nil | -| calls/calls.rb:339:8:339:8 | 1 | 1 | int | -| calls/calls.rb:339:8:339:8 | nil | nil | nil | -| calls/calls.rb:339:11:339:11 | 2 | 2 | int | -| calls/calls.rb:339:11:339:11 | nil | nil | nil | -| calls/calls.rb:339:18:339:18 | 1 | 1 | int | -| calls/calls.rb:339:20:339:20 | 2 | 2 | int | -| calls/calls.rb:339:22:339:22 | 3 | 3 | int | -| calls/calls.rb:339:27:339:27 | 4 | 4 | int | -| calls/calls.rb:339:29:339:29 | 5 | 5 | int | -| calls/calls.rb:339:31:339:31 | 6 | 6 | int | -| calls/calls.rb:343:5:343:5 | :x | :x | symbol | -| calls/calls.rb:343:8:343:9 | 42 | 42 | int | -| calls/calls.rb:344:5:344:5 | :x | :x | symbol | -| calls/calls.rb:344:9:344:13 | :novar | :novar | symbol | -| calls/calls.rb:345:5:345:5 | :X | :X | symbol | -| calls/calls.rb:345:8:345:9 | 42 | 42 | int | -| calls/calls.rb:346:5:346:5 | :X | :X | symbol | -| calls/calls.rb:349:5:349:5 | 1 | 1 | int | -| calls/calls.rb:361:1:361:4 | nil | nil | nil | -| calls/calls.rb:361:5:361:6 | nil | nil | nil | -| calls/calls.rb:363:1:363:3 | nil | nil | nil | -| calls/calls.rb:363:4:363:5 | nil | nil | nil | -| calls/calls.rb:363:10:363:10 | 1 | 1 | int | -| calls/calls.rb:363:12:363:12 | 2 | 2 | int | +| calls/calls.rb:318:10:318:11 | 10 | 10 | int | +| calls/calls.rb:319:1:319:8 | 0 | 0 | int | +| calls/calls.rb:319:12:319:19 | 1 | 1 | int | +| calls/calls.rb:319:12:319:19 | -2 | -2 | int | +| calls/calls.rb:319:22:319:27 | -1 | -1 | int | +| calls/calls.rb:319:26:319:26 | 4 | 4 | int | +| calls/calls.rb:319:32:319:32 | 1 | 1 | int | +| calls/calls.rb:319:35:319:35 | 2 | 2 | int | +| calls/calls.rb:319:38:319:38 | 3 | 3 | int | +| calls/calls.rb:319:41:319:41 | 4 | 4 | int | +| calls/calls.rb:320:1:320:1 | 0 | 0 | int | +| calls/calls.rb:320:5:320:10 | 1 | 1 | int | +| calls/calls.rb:320:5:320:10 | -1 | -1 | int | +| calls/calls.rb:320:9:320:9 | 5 | 5 | int | +| calls/calls.rb:320:15:320:15 | 1 | 1 | int | +| calls/calls.rb:320:18:320:18 | 2 | 2 | int | +| calls/calls.rb:320:21:320:21 | 3 | 3 | int | +| calls/calls.rb:321:15:321:15 | 1 | 1 | int | +| calls/calls.rb:322:5:322:5 | 0 | 0 | int | +| calls/calls.rb:322:5:322:5 | __synth__1 | 0 | int | +| calls/calls.rb:322:5:322:5 | __synth__1 | 0 | int | +| calls/calls.rb:322:11:322:11 | 1 | 1 | int | +| calls/calls.rb:323:9:323:9 | 0 | 0 | int | +| calls/calls.rb:323:9:323:9 | __synth__1 | 0 | int | +| calls/calls.rb:323:9:323:9 | __synth__1 | 0 | int | +| calls/calls.rb:323:31:323:31 | 1 | 1 | int | +| calls/calls.rb:323:37:323:37 | 2 | 2 | int | +| calls/calls.rb:331:31:331:37 | "error" | error | string | +| calls/calls.rb:343:5:343:5 | 0 | 0 | int | +| calls/calls.rb:343:5:343:5 | nil | nil | nil | +| calls/calls.rb:343:8:343:8 | 1 | 1 | int | +| calls/calls.rb:343:8:343:8 | nil | nil | nil | +| calls/calls.rb:343:11:343:11 | 2 | 2 | int | +| calls/calls.rb:343:11:343:11 | nil | nil | nil | +| calls/calls.rb:343:18:343:18 | 1 | 1 | int | +| calls/calls.rb:343:20:343:20 | 2 | 2 | int | +| calls/calls.rb:343:22:343:22 | 3 | 3 | int | +| calls/calls.rb:343:27:343:27 | 4 | 4 | int | +| calls/calls.rb:343:29:343:29 | 5 | 5 | int | +| calls/calls.rb:343:31:343:31 | 6 | 6 | int | +| calls/calls.rb:347:5:347:5 | :x | :x | symbol | +| calls/calls.rb:347:8:347:9 | 42 | 42 | int | +| calls/calls.rb:348:5:348:5 | :x | :x | symbol | +| calls/calls.rb:348:9:348:13 | :novar | :novar | symbol | +| calls/calls.rb:349:5:349:5 | :X | :X | symbol | +| calls/calls.rb:349:8:349:9 | 42 | 42 | int | +| calls/calls.rb:350:5:350:5 | :X | :X | symbol | +| calls/calls.rb:353:5:353:5 | 1 | 1 | int | +| calls/calls.rb:365:1:365:4 | nil | nil | nil | +| calls/calls.rb:365:5:365:6 | nil | nil | nil | +| calls/calls.rb:367:1:367:3 | nil | nil | nil | +| calls/calls.rb:367:4:367:5 | nil | nil | nil | +| calls/calls.rb:367:10:367:10 | 1 | 1 | int | +| calls/calls.rb:367:12:367:12 | 2 | 2 | int | | constants/constants.rb:3:19:3:27 | "const_a" | const_a | string | | constants/constants.rb:6:15:6:23 | "const_b" | const_b | string | | constants/constants.rb:17:12:17:18 | "Hello" | Hello | string | @@ -1094,6 +1095,7 @@ exprCfgNodeValue | control/cases.rb:11:9:11:9 | d | 0 | int | | control/cases.rb:12:5:12:7 | 200 | 200 | int | | control/cases.rb:14:5:14:7 | 300 | 300 | int | +| control/cases.rb:18:1:22:3 | true | true | boolean | | control/cases.rb:19:6:19:6 | a | 0 | int | | control/cases.rb:19:10:19:10 | b | 0 | int | | control/cases.rb:19:18:19:19 | 10 | 10 | int | diff --git a/ruby/ql/test/library-tests/ast/calls/arguments.expected b/ruby/ql/test/library-tests/ast/calls/arguments.expected index 0a7ec104b64..4a2f1e10e95 100644 --- a/ruby/ql/test/library-tests/ast/calls/arguments.expected +++ b/ruby/ql/test/library-tests/ast/calls/arguments.expected @@ -1,30 +1,30 @@ blockArguments -| calls.rb:263:5:263:8 | &... | calls.rb:263:6:263:8 | call to bar | -| calls.rb:264:5:264:11 | &... | calls.rb:264:6:264:11 | call to bar | +| calls.rb:267:5:267:8 | &... | calls.rb:267:6:267:8 | call to bar | +| calls.rb:268:5:268:11 | &... | calls.rb:268:6:268:11 | call to bar | splatExpr -| calls.rb:267:5:267:8 | * ... | calls.rb:267:6:267:8 | call to bar | -| calls.rb:268:5:268:11 | * ... | calls.rb:268:6:268:11 | call to bar | -| calls.rb:315:31:315:42 | * ... | calls.rb:315:31:315:42 | [...] | -| calls.rb:316:14:316:22 | * ... | calls.rb:316:14:316:22 | [...] | -| calls.rb:339:1:341:3 | * ... | calls.rb:339:1:341:3 | __synth__0__1 | +| calls.rb:271:5:271:8 | * ... | calls.rb:271:6:271:8 | call to bar | +| calls.rb:272:5:272:11 | * ... | calls.rb:272:6:272:11 | call to bar | +| calls.rb:319:31:319:42 | * ... | calls.rb:319:31:319:42 | [...] | +| calls.rb:320:14:320:22 | * ... | calls.rb:320:14:320:22 | [...] | +| calls.rb:343:1:345:3 | * ... | calls.rb:343:1:345:3 | __synth__0__1 | hashSplatExpr -| calls.rb:272:5:272:9 | ** ... | calls.rb:272:7:272:9 | call to bar | -| calls.rb:273:5:273:12 | ** ... | calls.rb:273:7:273:12 | call to bar | +| calls.rb:276:5:276:9 | ** ... | calls.rb:276:7:276:9 | call to bar | +| calls.rb:277:5:277:12 | ** ... | calls.rb:277:7:277:12 | call to bar | keywordArguments | calls.rb:246:3:246:12 | Pair | calls.rb:246:3:246:5 | call to foo | calls.rb:246:10:246:12 | call to bar | | calls.rb:246:15:246:30 | Pair | calls.rb:246:15:246:20 | call to foo | calls.rb:246:25:246:30 | call to bar | -| calls.rb:277:5:277:13 | Pair | calls.rb:277:5:277:8 | :blah | calls.rb:277:11:277:13 | call to bar | -| calls.rb:278:5:278:16 | Pair | calls.rb:278:5:278:8 | :blah | calls.rb:278:11:278:16 | call to bar | -| calls.rb:343:5:343:9 | Pair | calls.rb:343:5:343:5 | :x | calls.rb:343:8:343:9 | 42 | -| calls.rb:344:5:344:6 | Pair | calls.rb:344:5:344:5 | :x | calls.rb:344:5:344:5 | x | -| calls.rb:344:9:344:14 | Pair | calls.rb:344:9:344:13 | :novar | calls.rb:344:9:344:13 | call to novar | -| calls.rb:345:5:345:9 | Pair | calls.rb:345:5:345:5 | :X | calls.rb:345:8:345:9 | 42 | -| calls.rb:346:5:346:6 | Pair | calls.rb:346:5:346:5 | :X | calls.rb:346:5:346:5 | X | +| calls.rb:281:5:281:13 | Pair | calls.rb:281:5:281:8 | :blah | calls.rb:281:11:281:13 | call to bar | +| calls.rb:282:5:282:16 | Pair | calls.rb:282:5:282:8 | :blah | calls.rb:282:11:282:16 | call to bar | +| calls.rb:347:5:347:9 | Pair | calls.rb:347:5:347:5 | :x | calls.rb:347:8:347:9 | 42 | +| calls.rb:348:5:348:6 | Pair | calls.rb:348:5:348:5 | :x | calls.rb:348:5:348:5 | x | +| calls.rb:348:9:348:14 | Pair | calls.rb:348:9:348:13 | :novar | calls.rb:348:9:348:13 | call to novar | +| calls.rb:349:5:349:9 | Pair | calls.rb:349:5:349:5 | :X | calls.rb:349:8:349:9 | 42 | +| calls.rb:350:5:350:6 | Pair | calls.rb:350:5:350:5 | :X | calls.rb:350:5:350:5 | X | keywordArgumentsByKeyword -| calls.rb:277:1:277:14 | call to foo | blah | calls.rb:277:11:277:13 | call to bar | -| calls.rb:278:1:278:17 | call to foo | blah | calls.rb:278:11:278:16 | call to bar | -| calls.rb:343:1:343:10 | call to foo | x | calls.rb:343:8:343:9 | 42 | -| calls.rb:344:1:344:15 | call to foo | novar | calls.rb:344:9:344:13 | call to novar | -| calls.rb:344:1:344:15 | call to foo | x | calls.rb:344:5:344:5 | x | -| calls.rb:345:1:345:10 | call to foo | X | calls.rb:345:8:345:9 | 42 | -| calls.rb:346:1:346:7 | call to foo | X | calls.rb:346:5:346:5 | X | +| calls.rb:281:1:281:14 | call to foo | blah | calls.rb:281:11:281:13 | call to bar | +| calls.rb:282:1:282:17 | call to foo | blah | calls.rb:282:11:282:16 | call to bar | +| calls.rb:347:1:347:10 | call to foo | x | calls.rb:347:8:347:9 | 42 | +| calls.rb:348:1:348:15 | call to foo | novar | calls.rb:348:9:348:13 | call to novar | +| calls.rb:348:1:348:15 | call to foo | x | calls.rb:348:5:348:5 | x | +| calls.rb:349:1:349:10 | call to foo | X | calls.rb:349:8:349:9 | 42 | +| calls.rb:350:1:350:7 | call to foo | X | calls.rb:350:5:350:5 | X | diff --git a/ruby/ql/test/library-tests/ast/calls/calls.expected b/ruby/ql/test/library-tests/ast/calls/calls.expected index f5af4c89ba6..a8c30218d24 100644 --- a/ruby/ql/test/library-tests/ast/calls/calls.expected +++ b/ruby/ql/test/library-tests/ast/calls/calls.expected @@ -1,11 +1,11 @@ callsWithNoReceiverArgumentsOrBlock | calls.rb:28:3:28:7 | yield ... | (none) | -| calls.rb:269:5:269:5 | * ... | * | -| calls.rb:274:5:274:6 | ** ... | ** | -| calls.rb:285:5:285:9 | super call to my_method | my_method | -| calls.rb:286:5:286:11 | super call to my_method | my_method | -| calls.rb:304:5:304:9 | super call to another_method | another_method | -| calls.rb:344:9:344:13 | call to novar | novar | +| calls.rb:273:5:273:5 | * ... | * | +| calls.rb:278:5:278:6 | ** ... | ** | +| calls.rb:289:5:289:9 | super call to my_method | my_method | +| calls.rb:290:5:290:11 | super call to my_method | my_method | +| calls.rb:308:5:308:9 | super call to another_method | another_method | +| calls.rb:348:9:348:13 | call to novar | novar | callsWithArguments | calls.rb:11:1:11:11 | call to foo | foo | 0 | calls.rb:11:5:11:5 | 0 | | calls.rb:11:1:11:11 | call to foo | foo | 1 | calls.rb:11:8:11:8 | 1 | @@ -27,105 +27,105 @@ callsWithArguments | calls.rb:232:1:232:14 | ...[...] | [] | 0 | calls.rb:232:8:232:13 | call to bar | | calls.rb:246:1:246:32 | call to [] | [] | 0 | calls.rb:246:3:246:12 | Pair | | calls.rb:246:1:246:32 | call to [] | [] | 1 | calls.rb:246:15:246:30 | Pair | -| calls.rb:263:1:263:9 | call to foo | foo | 0 | calls.rb:263:5:263:8 | &... | -| calls.rb:264:1:264:12 | call to foo | foo | 0 | calls.rb:264:5:264:11 | &... | -| calls.rb:265:1:265:6 | call to foo | foo | 0 | calls.rb:265:5:265:5 | &... | -| calls.rb:267:1:267:9 | call to foo | foo | 0 | calls.rb:267:5:267:8 | * ... | -| calls.rb:268:1:268:12 | call to foo | foo | 0 | calls.rb:268:5:268:11 | * ... | -| calls.rb:269:1:269:6 | call to foo | foo | 0 | calls.rb:269:5:269:5 | * ... | -| calls.rb:272:1:272:10 | call to foo | foo | 0 | calls.rb:272:5:272:9 | ** ... | -| calls.rb:273:1:273:13 | call to foo | foo | 0 | calls.rb:273:5:273:12 | ** ... | -| calls.rb:274:1:274:7 | call to foo | foo | 0 | calls.rb:274:5:274:6 | ** ... | -| calls.rb:277:1:277:14 | call to foo | foo | 0 | calls.rb:277:5:277:13 | Pair | -| calls.rb:278:1:278:17 | call to foo | foo | 0 | calls.rb:278:5:278:16 | Pair | -| calls.rb:287:5:287:16 | super call to my_method | my_method | 0 | calls.rb:287:11:287:16 | "blah" | -| calls.rb:288:5:288:17 | super call to my_method | my_method | 0 | calls.rb:288:11:288:11 | 1 | -| calls.rb:288:5:288:17 | super call to my_method | my_method | 1 | calls.rb:288:14:288:14 | 2 | -| calls.rb:288:5:288:17 | super call to my_method | my_method | 2 | calls.rb:288:17:288:17 | 3 | -| calls.rb:289:17:289:21 | ... + ... | + | 0 | calls.rb:289:21:289:21 | 1 | -| calls.rb:290:18:290:22 | ... * ... | * | 0 | calls.rb:290:22:290:22 | 2 | -| calls.rb:291:5:291:30 | super call to my_method | my_method | 0 | calls.rb:291:11:291:11 | 4 | -| calls.rb:291:5:291:30 | super call to my_method | my_method | 1 | calls.rb:291:14:291:14 | 5 | -| calls.rb:291:22:291:28 | ... + ... | + | 0 | calls.rb:291:26:291:28 | 100 | -| calls.rb:292:5:292:33 | super call to my_method | my_method | 0 | calls.rb:292:11:292:11 | 6 | -| calls.rb:292:5:292:33 | super call to my_method | my_method | 1 | calls.rb:292:14:292:14 | 7 | -| calls.rb:292:23:292:29 | ... + ... | + | 0 | calls.rb:292:27:292:29 | 200 | -| calls.rb:310:1:310:7 | call to call | call | 0 | calls.rb:310:6:310:6 | 1 | -| calls.rb:313:1:313:8 | call to foo= | foo= | 0 | calls.rb:313:12:313:13 | ... = ... | -| calls.rb:314:1:314:6 | ...[...] | [] | 0 | calls.rb:314:5:314:5 | 0 | -| calls.rb:314:1:314:6 | call to []= | []= | 0 | calls.rb:314:5:314:5 | 0 | -| calls.rb:314:1:314:6 | call to []= | []= | 1 | calls.rb:314:10:314:11 | ... = ... | -| calls.rb:315:1:315:8 | call to [] | [] | 0 | calls.rb:315:1:315:8 | 0 | -| calls.rb:315:1:315:8 | call to foo= | foo= | 0 | calls.rb:315:1:315:8 | ... = ... | -| calls.rb:315:12:315:19 | call to [] | [] | 0 | calls.rb:315:12:315:19 | _ .. _ | -| calls.rb:315:12:315:19 | call to bar= | bar= | 0 | calls.rb:315:12:315:19 | ... = ... | -| calls.rb:315:22:315:27 | ...[...] | [] | 0 | calls.rb:315:26:315:26 | 4 | -| calls.rb:315:22:315:27 | call to [] | [] | 0 | calls.rb:315:22:315:27 | -1 | -| calls.rb:315:22:315:27 | call to [] | [] | 0 | calls.rb:315:26:315:26 | 4 | -| calls.rb:315:22:315:27 | call to []= | []= | 0 | calls.rb:315:26:315:26 | 4 | -| calls.rb:315:22:315:27 | call to []= | []= | 1 | calls.rb:315:22:315:27 | ... = ... | -| calls.rb:315:31:315:42 | call to [] | [] | 0 | calls.rb:315:32:315:32 | 1 | -| calls.rb:315:31:315:42 | call to [] | [] | 1 | calls.rb:315:35:315:35 | 2 | -| calls.rb:315:31:315:42 | call to [] | [] | 2 | calls.rb:315:38:315:38 | 3 | -| calls.rb:315:31:315:42 | call to [] | [] | 3 | calls.rb:315:41:315:41 | 4 | -| calls.rb:316:1:316:1 | call to [] | [] | 0 | calls.rb:316:1:316:1 | 0 | -| calls.rb:316:5:316:10 | ...[...] | [] | 0 | calls.rb:316:9:316:9 | 5 | -| calls.rb:316:5:316:10 | call to [] | [] | 0 | calls.rb:316:5:316:10 | _ .. _ | -| calls.rb:316:5:316:10 | call to [] | [] | 0 | calls.rb:316:9:316:9 | 5 | -| calls.rb:316:5:316:10 | call to []= | []= | 0 | calls.rb:316:9:316:9 | 5 | -| calls.rb:316:5:316:10 | call to []= | []= | 1 | calls.rb:316:5:316:10 | ... = ... | -| calls.rb:316:14:316:22 | call to [] | [] | 0 | calls.rb:316:15:316:15 | 1 | -| calls.rb:316:14:316:22 | call to [] | [] | 1 | calls.rb:316:18:316:18 | 2 | -| calls.rb:316:14:316:22 | call to [] | [] | 2 | calls.rb:316:21:316:21 | 3 | -| calls.rb:317:1:317:10 | call to count= | count= | 0 | calls.rb:317:1:317:10 | __synth__1 | -| calls.rb:317:12:317:13 | ... + ... | + | 0 | calls.rb:317:15:317:15 | 1 | +| calls.rb:267:1:267:9 | call to foo | foo | 0 | calls.rb:267:5:267:8 | &... | +| calls.rb:268:1:268:12 | call to foo | foo | 0 | calls.rb:268:5:268:11 | &... | +| calls.rb:269:1:269:6 | call to foo | foo | 0 | calls.rb:269:5:269:5 | &... | +| calls.rb:271:1:271:9 | call to foo | foo | 0 | calls.rb:271:5:271:8 | * ... | +| calls.rb:272:1:272:12 | call to foo | foo | 0 | calls.rb:272:5:272:11 | * ... | +| calls.rb:273:1:273:6 | call to foo | foo | 0 | calls.rb:273:5:273:5 | * ... | +| calls.rb:276:1:276:10 | call to foo | foo | 0 | calls.rb:276:5:276:9 | ** ... | +| calls.rb:277:1:277:13 | call to foo | foo | 0 | calls.rb:277:5:277:12 | ** ... | +| calls.rb:278:1:278:7 | call to foo | foo | 0 | calls.rb:278:5:278:6 | ** ... | +| calls.rb:281:1:281:14 | call to foo | foo | 0 | calls.rb:281:5:281:13 | Pair | +| calls.rb:282:1:282:17 | call to foo | foo | 0 | calls.rb:282:5:282:16 | Pair | +| calls.rb:291:5:291:16 | super call to my_method | my_method | 0 | calls.rb:291:11:291:16 | "blah" | +| calls.rb:292:5:292:17 | super call to my_method | my_method | 0 | calls.rb:292:11:292:11 | 1 | +| calls.rb:292:5:292:17 | super call to my_method | my_method | 1 | calls.rb:292:14:292:14 | 2 | +| calls.rb:292:5:292:17 | super call to my_method | my_method | 2 | calls.rb:292:17:292:17 | 3 | +| calls.rb:293:17:293:21 | ... + ... | + | 0 | calls.rb:293:21:293:21 | 1 | +| calls.rb:294:18:294:22 | ... * ... | * | 0 | calls.rb:294:22:294:22 | 2 | +| calls.rb:295:5:295:30 | super call to my_method | my_method | 0 | calls.rb:295:11:295:11 | 4 | +| calls.rb:295:5:295:30 | super call to my_method | my_method | 1 | calls.rb:295:14:295:14 | 5 | +| calls.rb:295:22:295:28 | ... + ... | + | 0 | calls.rb:295:26:295:28 | 100 | +| calls.rb:296:5:296:33 | super call to my_method | my_method | 0 | calls.rb:296:11:296:11 | 6 | +| calls.rb:296:5:296:33 | super call to my_method | my_method | 1 | calls.rb:296:14:296:14 | 7 | +| calls.rb:296:23:296:29 | ... + ... | + | 0 | calls.rb:296:27:296:29 | 200 | +| calls.rb:314:1:314:7 | call to call | call | 0 | calls.rb:314:6:314:6 | 1 | +| calls.rb:317:1:317:8 | call to foo= | foo= | 0 | calls.rb:317:12:317:13 | ... = ... | | calls.rb:318:1:318:6 | ...[...] | [] | 0 | calls.rb:318:5:318:5 | 0 | -| calls.rb:318:1:318:6 | call to [] | [] | 0 | calls.rb:318:5:318:5 | __synth__1 | -| calls.rb:318:1:318:6 | call to []= | []= | 0 | calls.rb:318:5:318:5 | __synth__1 | -| calls.rb:318:1:318:6 | call to []= | []= | 1 | calls.rb:318:1:318:6 | __synth__2 | -| calls.rb:318:8:318:9 | ... + ... | + | 0 | calls.rb:318:11:318:11 | 1 | -| calls.rb:319:1:319:32 | ...[...] | [] | 0 | calls.rb:319:9:319:9 | 0 | -| calls.rb:319:1:319:32 | ...[...] | [] | 1 | calls.rb:319:12:319:18 | call to baz | -| calls.rb:319:1:319:32 | ...[...] | [] | 2 | calls.rb:319:21:319:31 | ... + ... | -| calls.rb:319:1:319:32 | call to [] | [] | 0 | calls.rb:319:9:319:9 | __synth__1 | -| calls.rb:319:1:319:32 | call to [] | [] | 1 | calls.rb:319:12:319:18 | __synth__2 | -| calls.rb:319:1:319:32 | call to [] | [] | 2 | calls.rb:319:21:319:31 | __synth__3 | -| calls.rb:319:1:319:32 | call to []= | []= | 0 | calls.rb:319:9:319:9 | __synth__1 | -| calls.rb:319:1:319:32 | call to []= | []= | 1 | calls.rb:319:12:319:18 | __synth__2 | -| calls.rb:319:1:319:32 | call to []= | []= | 2 | calls.rb:319:21:319:31 | __synth__3 | -| calls.rb:319:1:319:32 | call to []= | []= | 3 | calls.rb:319:1:319:32 | __synth__4 | -| calls.rb:319:21:319:31 | ... + ... | + | 0 | calls.rb:319:31:319:31 | 1 | -| calls.rb:319:34:319:35 | ... * ... | * | 0 | calls.rb:319:37:319:37 | 2 | -| calls.rb:327:25:327:37 | call to print | print | 0 | calls.rb:327:31:327:37 | "error" | -| calls.rb:331:3:331:12 | super call to foo | foo | 0 | calls.rb:331:9:331:11 | ... | -| calls.rb:335:3:335:13 | call to bar | bar | 0 | calls.rb:335:7:335:7 | b | -| calls.rb:335:3:335:13 | call to bar | bar | 1 | calls.rb:335:10:335:12 | ... | -| calls.rb:339:5:339:5 | call to [] | [] | 0 | calls.rb:339:5:339:5 | 0 | -| calls.rb:339:8:339:8 | call to [] | [] | 0 | calls.rb:339:8:339:8 | 1 | -| calls.rb:339:11:339:11 | call to [] | [] | 0 | calls.rb:339:11:339:11 | 2 | -| calls.rb:339:16:339:33 | call to [] | [] | 0 | calls.rb:339:17:339:23 | [...] | -| calls.rb:339:16:339:33 | call to [] | [] | 1 | calls.rb:339:26:339:32 | [...] | -| calls.rb:339:17:339:23 | call to [] | [] | 0 | calls.rb:339:18:339:18 | 1 | -| calls.rb:339:17:339:23 | call to [] | [] | 1 | calls.rb:339:20:339:20 | 2 | -| calls.rb:339:17:339:23 | call to [] | [] | 2 | calls.rb:339:22:339:22 | 3 | -| calls.rb:339:26:339:32 | call to [] | [] | 0 | calls.rb:339:27:339:27 | 4 | -| calls.rb:339:26:339:32 | call to [] | [] | 1 | calls.rb:339:29:339:29 | 5 | -| calls.rb:339:26:339:32 | call to [] | [] | 2 | calls.rb:339:31:339:31 | 6 | -| calls.rb:340:3:340:13 | call to foo | foo | 0 | calls.rb:340:7:340:7 | x | -| calls.rb:340:3:340:13 | call to foo | foo | 1 | calls.rb:340:10:340:10 | y | -| calls.rb:340:3:340:13 | call to foo | foo | 2 | calls.rb:340:13:340:13 | z | -| calls.rb:343:1:343:10 | call to foo | foo | 0 | calls.rb:343:5:343:9 | Pair | -| calls.rb:344:1:344:15 | call to foo | foo | 0 | calls.rb:344:5:344:6 | Pair | -| calls.rb:344:1:344:15 | call to foo | foo | 1 | calls.rb:344:9:344:14 | Pair | -| calls.rb:345:1:345:10 | call to foo | foo | 0 | calls.rb:345:5:345:9 | Pair | -| calls.rb:346:1:346:7 | call to foo | foo | 0 | calls.rb:346:5:346:6 | Pair | -| calls.rb:351:13:351:17 | call to foo | foo | 0 | calls.rb:351:17:351:17 | x | -| calls.rb:361:5:361:6 | call to == | == | 0 | calls.rb:361:1:361:4 | __synth__0__1 | -| calls.rb:363:1:363:23 | call to bar | bar | 0 | calls.rb:363:10:363:10 | 1 | -| calls.rb:363:1:363:23 | call to bar | bar | 0 | calls.rb:363:10:363:10 | 1 | -| calls.rb:363:1:363:23 | call to bar | bar | 1 | calls.rb:363:12:363:12 | 2 | -| calls.rb:363:1:363:23 | call to bar | bar | 1 | calls.rb:363:12:363:12 | 2 | -| calls.rb:363:4:363:5 | call to == | == | 0 | calls.rb:363:1:363:3 | __synth__0__1 | +| calls.rb:318:1:318:6 | call to []= | []= | 0 | calls.rb:318:5:318:5 | 0 | +| calls.rb:318:1:318:6 | call to []= | []= | 1 | calls.rb:318:10:318:11 | ... = ... | +| calls.rb:319:1:319:8 | call to [] | [] | 0 | calls.rb:319:1:319:8 | 0 | +| calls.rb:319:1:319:8 | call to foo= | foo= | 0 | calls.rb:319:1:319:8 | ... = ... | +| calls.rb:319:12:319:19 | call to [] | [] | 0 | calls.rb:319:12:319:19 | _ .. _ | +| calls.rb:319:12:319:19 | call to bar= | bar= | 0 | calls.rb:319:12:319:19 | ... = ... | +| calls.rb:319:22:319:27 | ...[...] | [] | 0 | calls.rb:319:26:319:26 | 4 | +| calls.rb:319:22:319:27 | call to [] | [] | 0 | calls.rb:319:22:319:27 | -1 | +| calls.rb:319:22:319:27 | call to [] | [] | 0 | calls.rb:319:26:319:26 | 4 | +| calls.rb:319:22:319:27 | call to []= | []= | 0 | calls.rb:319:26:319:26 | 4 | +| calls.rb:319:22:319:27 | call to []= | []= | 1 | calls.rb:319:22:319:27 | ... = ... | +| calls.rb:319:31:319:42 | call to [] | [] | 0 | calls.rb:319:32:319:32 | 1 | +| calls.rb:319:31:319:42 | call to [] | [] | 1 | calls.rb:319:35:319:35 | 2 | +| calls.rb:319:31:319:42 | call to [] | [] | 2 | calls.rb:319:38:319:38 | 3 | +| calls.rb:319:31:319:42 | call to [] | [] | 3 | calls.rb:319:41:319:41 | 4 | +| calls.rb:320:1:320:1 | call to [] | [] | 0 | calls.rb:320:1:320:1 | 0 | +| calls.rb:320:5:320:10 | ...[...] | [] | 0 | calls.rb:320:9:320:9 | 5 | +| calls.rb:320:5:320:10 | call to [] | [] | 0 | calls.rb:320:5:320:10 | _ .. _ | +| calls.rb:320:5:320:10 | call to [] | [] | 0 | calls.rb:320:9:320:9 | 5 | +| calls.rb:320:5:320:10 | call to []= | []= | 0 | calls.rb:320:9:320:9 | 5 | +| calls.rb:320:5:320:10 | call to []= | []= | 1 | calls.rb:320:5:320:10 | ... = ... | +| calls.rb:320:14:320:22 | call to [] | [] | 0 | calls.rb:320:15:320:15 | 1 | +| calls.rb:320:14:320:22 | call to [] | [] | 1 | calls.rb:320:18:320:18 | 2 | +| calls.rb:320:14:320:22 | call to [] | [] | 2 | calls.rb:320:21:320:21 | 3 | +| calls.rb:321:1:321:10 | call to count= | count= | 0 | calls.rb:321:1:321:10 | __synth__1 | +| calls.rb:321:12:321:13 | ... + ... | + | 0 | calls.rb:321:15:321:15 | 1 | +| calls.rb:322:1:322:6 | ...[...] | [] | 0 | calls.rb:322:5:322:5 | 0 | +| calls.rb:322:1:322:6 | call to [] | [] | 0 | calls.rb:322:5:322:5 | __synth__1 | +| calls.rb:322:1:322:6 | call to []= | []= | 0 | calls.rb:322:5:322:5 | __synth__1 | +| calls.rb:322:1:322:6 | call to []= | []= | 1 | calls.rb:322:1:322:6 | __synth__2 | +| calls.rb:322:8:322:9 | ... + ... | + | 0 | calls.rb:322:11:322:11 | 1 | +| calls.rb:323:1:323:32 | ...[...] | [] | 0 | calls.rb:323:9:323:9 | 0 | +| calls.rb:323:1:323:32 | ...[...] | [] | 1 | calls.rb:323:12:323:18 | call to baz | +| calls.rb:323:1:323:32 | ...[...] | [] | 2 | calls.rb:323:21:323:31 | ... + ... | +| calls.rb:323:1:323:32 | call to [] | [] | 0 | calls.rb:323:9:323:9 | __synth__1 | +| calls.rb:323:1:323:32 | call to [] | [] | 1 | calls.rb:323:12:323:18 | __synth__2 | +| calls.rb:323:1:323:32 | call to [] | [] | 2 | calls.rb:323:21:323:31 | __synth__3 | +| calls.rb:323:1:323:32 | call to []= | []= | 0 | calls.rb:323:9:323:9 | __synth__1 | +| calls.rb:323:1:323:32 | call to []= | []= | 1 | calls.rb:323:12:323:18 | __synth__2 | +| calls.rb:323:1:323:32 | call to []= | []= | 2 | calls.rb:323:21:323:31 | __synth__3 | +| calls.rb:323:1:323:32 | call to []= | []= | 3 | calls.rb:323:1:323:32 | __synth__4 | +| calls.rb:323:21:323:31 | ... + ... | + | 0 | calls.rb:323:31:323:31 | 1 | +| calls.rb:323:34:323:35 | ... * ... | * | 0 | calls.rb:323:37:323:37 | 2 | +| calls.rb:331:25:331:37 | call to print | print | 0 | calls.rb:331:31:331:37 | "error" | +| calls.rb:335:3:335:12 | super call to foo | foo | 0 | calls.rb:335:9:335:11 | ... | +| calls.rb:339:3:339:13 | call to bar | bar | 0 | calls.rb:339:7:339:7 | b | +| calls.rb:339:3:339:13 | call to bar | bar | 1 | calls.rb:339:10:339:12 | ... | +| calls.rb:343:5:343:5 | call to [] | [] | 0 | calls.rb:343:5:343:5 | 0 | +| calls.rb:343:8:343:8 | call to [] | [] | 0 | calls.rb:343:8:343:8 | 1 | +| calls.rb:343:11:343:11 | call to [] | [] | 0 | calls.rb:343:11:343:11 | 2 | +| calls.rb:343:16:343:33 | call to [] | [] | 0 | calls.rb:343:17:343:23 | [...] | +| calls.rb:343:16:343:33 | call to [] | [] | 1 | calls.rb:343:26:343:32 | [...] | +| calls.rb:343:17:343:23 | call to [] | [] | 0 | calls.rb:343:18:343:18 | 1 | +| calls.rb:343:17:343:23 | call to [] | [] | 1 | calls.rb:343:20:343:20 | 2 | +| calls.rb:343:17:343:23 | call to [] | [] | 2 | calls.rb:343:22:343:22 | 3 | +| calls.rb:343:26:343:32 | call to [] | [] | 0 | calls.rb:343:27:343:27 | 4 | +| calls.rb:343:26:343:32 | call to [] | [] | 1 | calls.rb:343:29:343:29 | 5 | +| calls.rb:343:26:343:32 | call to [] | [] | 2 | calls.rb:343:31:343:31 | 6 | +| calls.rb:344:3:344:13 | call to foo | foo | 0 | calls.rb:344:7:344:7 | x | +| calls.rb:344:3:344:13 | call to foo | foo | 1 | calls.rb:344:10:344:10 | y | +| calls.rb:344:3:344:13 | call to foo | foo | 2 | calls.rb:344:13:344:13 | z | +| calls.rb:347:1:347:10 | call to foo | foo | 0 | calls.rb:347:5:347:9 | Pair | +| calls.rb:348:1:348:15 | call to foo | foo | 0 | calls.rb:348:5:348:6 | Pair | +| calls.rb:348:1:348:15 | call to foo | foo | 1 | calls.rb:348:9:348:14 | Pair | +| calls.rb:349:1:349:10 | call to foo | foo | 0 | calls.rb:349:5:349:9 | Pair | +| calls.rb:350:1:350:7 | call to foo | foo | 0 | calls.rb:350:5:350:6 | Pair | +| calls.rb:355:13:355:17 | call to foo | foo | 0 | calls.rb:355:17:355:17 | x | +| calls.rb:365:5:365:6 | call to == | == | 0 | calls.rb:365:1:365:4 | __synth__0__1 | +| calls.rb:367:1:367:23 | call to bar | bar | 0 | calls.rb:367:10:367:10 | 1 | +| calls.rb:367:1:367:23 | call to bar | bar | 0 | calls.rb:367:10:367:10 | 1 | +| calls.rb:367:1:367:23 | call to bar | bar | 1 | calls.rb:367:12:367:12 | 2 | +| calls.rb:367:1:367:23 | call to bar | bar | 1 | calls.rb:367:12:367:12 | 2 | +| calls.rb:367:4:367:5 | call to == | == | 0 | calls.rb:367:1:367:3 | __synth__0__1 | callsWithReceiver | calls.rb:2:1:2:5 | call to foo | calls.rb:2:1:2:5 | self | | calls.rb:5:1:5:10 | call to bar | calls.rb:5:1:5:3 | Foo | @@ -282,135 +282,138 @@ callsWithReceiver | calls.rb:251:8:251:10 | call to bar | calls.rb:251:8:251:10 | self | | calls.rb:254:8:254:13 | call to foo | calls.rb:254:8:254:8 | X | | calls.rb:255:8:255:13 | call to bar | calls.rb:255:8:255:8 | X | -| calls.rb:259:1:259:3 | call to foo | calls.rb:259:1:259:3 | self | -| calls.rb:259:12:259:14 | call to bar | calls.rb:259:12:259:14 | self | -| calls.rb:260:1:260:6 | call to foo | calls.rb:260:1:260:1 | X | -| calls.rb:260:15:260:20 | call to bar | calls.rb:260:15:260:15 | X | -| calls.rb:263:1:263:9 | call to foo | calls.rb:263:1:263:9 | self | -| calls.rb:263:6:263:8 | call to bar | calls.rb:263:6:263:8 | self | -| calls.rb:264:1:264:12 | call to foo | calls.rb:264:1:264:12 | self | -| calls.rb:264:6:264:11 | call to bar | calls.rb:264:6:264:6 | X | -| calls.rb:265:1:265:6 | call to foo | calls.rb:265:1:265:6 | self | +| calls.rb:258:8:258:10 | call to foo | calls.rb:258:8:258:10 | self | +| calls.rb:258:13:258:18 | call to bar | calls.rb:258:13:258:13 | X | +| calls.rb:259:8:259:10 | call to baz | calls.rb:259:8:259:10 | self | +| calls.rb:263:1:263:3 | call to foo | calls.rb:263:1:263:3 | self | +| calls.rb:263:12:263:14 | call to bar | calls.rb:263:12:263:14 | self | +| calls.rb:264:1:264:6 | call to foo | calls.rb:264:1:264:1 | X | +| calls.rb:264:15:264:20 | call to bar | calls.rb:264:15:264:15 | X | | calls.rb:267:1:267:9 | call to foo | calls.rb:267:1:267:9 | self | -| calls.rb:267:5:267:8 | * ... | calls.rb:267:6:267:8 | call to bar | | calls.rb:267:6:267:8 | call to bar | calls.rb:267:6:267:8 | self | | calls.rb:268:1:268:12 | call to foo | calls.rb:268:1:268:12 | self | -| calls.rb:268:5:268:11 | * ... | calls.rb:268:6:268:11 | call to bar | | calls.rb:268:6:268:11 | call to bar | calls.rb:268:6:268:6 | X | | calls.rb:269:1:269:6 | call to foo | calls.rb:269:1:269:6 | self | -| calls.rb:272:1:272:10 | call to foo | calls.rb:272:1:272:10 | self | -| calls.rb:272:5:272:9 | ** ... | calls.rb:272:7:272:9 | call to bar | -| calls.rb:272:7:272:9 | call to bar | calls.rb:272:7:272:9 | self | -| calls.rb:273:1:273:13 | call to foo | calls.rb:273:1:273:13 | self | -| calls.rb:273:5:273:12 | ** ... | calls.rb:273:7:273:12 | call to bar | -| calls.rb:273:7:273:12 | call to bar | calls.rb:273:7:273:7 | X | -| calls.rb:274:1:274:7 | call to foo | calls.rb:274:1:274:7 | self | -| calls.rb:277:1:277:14 | call to foo | calls.rb:277:1:277:14 | self | -| calls.rb:277:11:277:13 | call to bar | calls.rb:277:11:277:13 | self | -| calls.rb:278:1:278:17 | call to foo | calls.rb:278:1:278:17 | self | -| calls.rb:278:11:278:16 | call to bar | calls.rb:278:11:278:11 | X | -| calls.rb:289:17:289:21 | ... + ... | calls.rb:289:17:289:17 | x | -| calls.rb:290:18:290:22 | ... * ... | calls.rb:290:18:290:18 | x | -| calls.rb:291:22:291:28 | ... + ... | calls.rb:291:22:291:22 | x | -| calls.rb:292:23:292:29 | ... + ... | calls.rb:292:23:292:23 | x | -| calls.rb:302:5:302:7 | call to foo | calls.rb:302:5:302:7 | self | -| calls.rb:302:5:302:13 | call to super | calls.rb:302:5:302:7 | call to foo | -| calls.rb:303:5:303:14 | call to super | calls.rb:303:5:303:8 | self | -| calls.rb:304:5:304:15 | call to super | calls.rb:304:5:304:9 | super call to another_method | -| calls.rb:309:1:309:3 | call to foo | calls.rb:309:1:309:3 | self | -| calls.rb:309:1:309:6 | call to call | calls.rb:309:1:309:3 | call to foo | -| calls.rb:310:1:310:3 | call to foo | calls.rb:310:1:310:3 | self | -| calls.rb:310:1:310:7 | call to call | calls.rb:310:1:310:3 | call to foo | -| calls.rb:313:1:313:8 | call to foo | calls.rb:313:1:313:4 | self | -| calls.rb:313:1:313:8 | call to foo= | calls.rb:313:1:313:4 | self | +| calls.rb:271:1:271:9 | call to foo | calls.rb:271:1:271:9 | self | +| calls.rb:271:5:271:8 | * ... | calls.rb:271:6:271:8 | call to bar | +| calls.rb:271:6:271:8 | call to bar | calls.rb:271:6:271:8 | self | +| calls.rb:272:1:272:12 | call to foo | calls.rb:272:1:272:12 | self | +| calls.rb:272:5:272:11 | * ... | calls.rb:272:6:272:11 | call to bar | +| calls.rb:272:6:272:11 | call to bar | calls.rb:272:6:272:6 | X | +| calls.rb:273:1:273:6 | call to foo | calls.rb:273:1:273:6 | self | +| calls.rb:276:1:276:10 | call to foo | calls.rb:276:1:276:10 | self | +| calls.rb:276:5:276:9 | ** ... | calls.rb:276:7:276:9 | call to bar | +| calls.rb:276:7:276:9 | call to bar | calls.rb:276:7:276:9 | self | +| calls.rb:277:1:277:13 | call to foo | calls.rb:277:1:277:13 | self | +| calls.rb:277:5:277:12 | ** ... | calls.rb:277:7:277:12 | call to bar | +| calls.rb:277:7:277:12 | call to bar | calls.rb:277:7:277:7 | X | +| calls.rb:278:1:278:7 | call to foo | calls.rb:278:1:278:7 | self | +| calls.rb:281:1:281:14 | call to foo | calls.rb:281:1:281:14 | self | +| calls.rb:281:11:281:13 | call to bar | calls.rb:281:11:281:13 | self | +| calls.rb:282:1:282:17 | call to foo | calls.rb:282:1:282:17 | self | +| calls.rb:282:11:282:16 | call to bar | calls.rb:282:11:282:11 | X | +| calls.rb:293:17:293:21 | ... + ... | calls.rb:293:17:293:17 | x | +| calls.rb:294:18:294:22 | ... * ... | calls.rb:294:18:294:18 | x | +| calls.rb:295:22:295:28 | ... + ... | calls.rb:295:22:295:22 | x | +| calls.rb:296:23:296:29 | ... + ... | calls.rb:296:23:296:23 | x | +| calls.rb:306:5:306:7 | call to foo | calls.rb:306:5:306:7 | self | +| calls.rb:306:5:306:13 | call to super | calls.rb:306:5:306:7 | call to foo | +| calls.rb:307:5:307:14 | call to super | calls.rb:307:5:307:8 | self | +| calls.rb:308:5:308:15 | call to super | calls.rb:308:5:308:9 | super call to another_method | +| calls.rb:313:1:313:3 | call to foo | calls.rb:313:1:313:3 | self | +| calls.rb:313:1:313:6 | call to call | calls.rb:313:1:313:3 | call to foo | | calls.rb:314:1:314:3 | call to foo | calls.rb:314:1:314:3 | self | -| calls.rb:314:1:314:6 | ...[...] | calls.rb:314:1:314:3 | call to foo | -| calls.rb:314:1:314:6 | call to []= | calls.rb:314:1:314:3 | call to foo | -| calls.rb:315:1:315:8 | call to [] | calls.rb:315:1:315:8 | __synth__3 | -| calls.rb:315:1:315:8 | call to foo | calls.rb:315:1:315:4 | self | -| calls.rb:315:1:315:8 | call to foo | calls.rb:315:1:315:8 | __synth__0 | -| calls.rb:315:1:315:8 | call to foo= | calls.rb:315:1:315:8 | __synth__0 | -| calls.rb:315:12:315:19 | call to [] | calls.rb:315:12:315:19 | __synth__3 | -| calls.rb:315:12:315:19 | call to bar | calls.rb:315:12:315:15 | self | -| calls.rb:315:12:315:19 | call to bar | calls.rb:315:12:315:19 | __synth__1 | -| calls.rb:315:12:315:19 | call to bar= | calls.rb:315:12:315:19 | __synth__1 | -| calls.rb:315:22:315:24 | call to foo | calls.rb:315:22:315:24 | self | -| calls.rb:315:22:315:27 | ...[...] | calls.rb:315:22:315:24 | call to foo | -| calls.rb:315:22:315:27 | call to [] | calls.rb:315:22:315:27 | __synth__2 | -| calls.rb:315:22:315:27 | call to [] | calls.rb:315:22:315:27 | __synth__3 | -| calls.rb:315:22:315:27 | call to []= | calls.rb:315:22:315:27 | __synth__2 | -| calls.rb:315:31:315:42 | * ... | calls.rb:315:31:315:42 | [...] | -| calls.rb:315:31:315:42 | call to [] | calls.rb:315:31:315:42 | Array | -| calls.rb:316:1:316:1 | call to [] | calls.rb:316:1:316:1 | __synth__2 | -| calls.rb:316:5:316:7 | call to foo | calls.rb:316:5:316:7 | self | -| calls.rb:316:5:316:10 | ...[...] | calls.rb:316:5:316:7 | call to foo | -| calls.rb:316:5:316:10 | call to [] | calls.rb:316:5:316:10 | __synth__1 | -| calls.rb:316:5:316:10 | call to [] | calls.rb:316:5:316:10 | __synth__2 | -| calls.rb:316:5:316:10 | call to []= | calls.rb:316:5:316:10 | __synth__1 | -| calls.rb:316:14:316:22 | * ... | calls.rb:316:14:316:22 | [...] | -| calls.rb:316:14:316:22 | call to [] | calls.rb:316:14:316:22 | Array | -| calls.rb:317:1:317:10 | call to count | calls.rb:317:1:317:4 | __synth__0 | -| calls.rb:317:1:317:10 | call to count | calls.rb:317:1:317:4 | self | -| calls.rb:317:1:317:10 | call to count= | calls.rb:317:1:317:4 | __synth__0 | -| calls.rb:317:12:317:13 | ... + ... | calls.rb:317:1:317:10 | call to count | +| calls.rb:314:1:314:7 | call to call | calls.rb:314:1:314:3 | call to foo | +| calls.rb:317:1:317:8 | call to foo | calls.rb:317:1:317:4 | self | +| calls.rb:317:1:317:8 | call to foo= | calls.rb:317:1:317:4 | self | | calls.rb:318:1:318:3 | call to foo | calls.rb:318:1:318:3 | self | | calls.rb:318:1:318:6 | ...[...] | calls.rb:318:1:318:3 | call to foo | -| calls.rb:318:1:318:6 | call to [] | calls.rb:318:1:318:3 | __synth__0 | -| calls.rb:318:1:318:6 | call to []= | calls.rb:318:1:318:3 | __synth__0 | -| calls.rb:318:8:318:9 | ... + ... | calls.rb:318:1:318:6 | call to [] | -| calls.rb:319:1:319:3 | call to foo | calls.rb:319:1:319:3 | self | -| calls.rb:319:1:319:7 | call to bar | calls.rb:319:1:319:3 | call to foo | -| calls.rb:319:1:319:32 | ...[...] | calls.rb:319:1:319:7 | call to bar | -| calls.rb:319:1:319:32 | call to [] | calls.rb:319:1:319:7 | __synth__0 | -| calls.rb:319:1:319:32 | call to []= | calls.rb:319:1:319:7 | __synth__0 | -| calls.rb:319:12:319:14 | call to foo | calls.rb:319:12:319:14 | self | -| calls.rb:319:12:319:18 | call to baz | calls.rb:319:12:319:14 | call to foo | -| calls.rb:319:21:319:23 | call to foo | calls.rb:319:21:319:23 | self | -| calls.rb:319:21:319:27 | call to boo | calls.rb:319:21:319:23 | call to foo | -| calls.rb:319:21:319:31 | ... + ... | calls.rb:319:21:319:27 | call to boo | -| calls.rb:319:34:319:35 | ... * ... | calls.rb:319:1:319:32 | call to [] | -| calls.rb:322:11:322:13 | call to bar | calls.rb:322:11:322:13 | self | -| calls.rb:323:13:323:15 | call to bar | calls.rb:323:13:323:15 | self | -| calls.rb:324:14:324:16 | call to bar | calls.rb:324:14:324:16 | self | -| calls.rb:325:18:325:20 | call to bar | calls.rb:325:18:325:20 | self | -| calls.rb:326:22:326:24 | call to bar | calls.rb:326:22:326:24 | self | +| calls.rb:318:1:318:6 | call to []= | calls.rb:318:1:318:3 | call to foo | +| calls.rb:319:1:319:8 | call to [] | calls.rb:319:1:319:8 | __synth__3 | +| calls.rb:319:1:319:8 | call to foo | calls.rb:319:1:319:4 | self | +| calls.rb:319:1:319:8 | call to foo | calls.rb:319:1:319:8 | __synth__0 | +| calls.rb:319:1:319:8 | call to foo= | calls.rb:319:1:319:8 | __synth__0 | +| calls.rb:319:12:319:19 | call to [] | calls.rb:319:12:319:19 | __synth__3 | +| calls.rb:319:12:319:19 | call to bar | calls.rb:319:12:319:15 | self | +| calls.rb:319:12:319:19 | call to bar | calls.rb:319:12:319:19 | __synth__1 | +| calls.rb:319:12:319:19 | call to bar= | calls.rb:319:12:319:19 | __synth__1 | +| calls.rb:319:22:319:24 | call to foo | calls.rb:319:22:319:24 | self | +| calls.rb:319:22:319:27 | ...[...] | calls.rb:319:22:319:24 | call to foo | +| calls.rb:319:22:319:27 | call to [] | calls.rb:319:22:319:27 | __synth__2 | +| calls.rb:319:22:319:27 | call to [] | calls.rb:319:22:319:27 | __synth__3 | +| calls.rb:319:22:319:27 | call to []= | calls.rb:319:22:319:27 | __synth__2 | +| calls.rb:319:31:319:42 | * ... | calls.rb:319:31:319:42 | [...] | +| calls.rb:319:31:319:42 | call to [] | calls.rb:319:31:319:42 | Array | +| calls.rb:320:1:320:1 | call to [] | calls.rb:320:1:320:1 | __synth__2 | +| calls.rb:320:5:320:7 | call to foo | calls.rb:320:5:320:7 | self | +| calls.rb:320:5:320:10 | ...[...] | calls.rb:320:5:320:7 | call to foo | +| calls.rb:320:5:320:10 | call to [] | calls.rb:320:5:320:10 | __synth__1 | +| calls.rb:320:5:320:10 | call to [] | calls.rb:320:5:320:10 | __synth__2 | +| calls.rb:320:5:320:10 | call to []= | calls.rb:320:5:320:10 | __synth__1 | +| calls.rb:320:14:320:22 | * ... | calls.rb:320:14:320:22 | [...] | +| calls.rb:320:14:320:22 | call to [] | calls.rb:320:14:320:22 | Array | +| calls.rb:321:1:321:10 | call to count | calls.rb:321:1:321:4 | __synth__0 | +| calls.rb:321:1:321:10 | call to count | calls.rb:321:1:321:4 | self | +| calls.rb:321:1:321:10 | call to count= | calls.rb:321:1:321:4 | __synth__0 | +| calls.rb:321:12:321:13 | ... + ... | calls.rb:321:1:321:10 | call to count | +| calls.rb:322:1:322:3 | call to foo | calls.rb:322:1:322:3 | self | +| calls.rb:322:1:322:6 | ...[...] | calls.rb:322:1:322:3 | call to foo | +| calls.rb:322:1:322:6 | call to [] | calls.rb:322:1:322:3 | __synth__0 | +| calls.rb:322:1:322:6 | call to []= | calls.rb:322:1:322:3 | __synth__0 | +| calls.rb:322:8:322:9 | ... + ... | calls.rb:322:1:322:6 | call to [] | +| calls.rb:323:1:323:3 | call to foo | calls.rb:323:1:323:3 | self | +| calls.rb:323:1:323:7 | call to bar | calls.rb:323:1:323:3 | call to foo | +| calls.rb:323:1:323:32 | ...[...] | calls.rb:323:1:323:7 | call to bar | +| calls.rb:323:1:323:32 | call to [] | calls.rb:323:1:323:7 | __synth__0 | +| calls.rb:323:1:323:32 | call to []= | calls.rb:323:1:323:7 | __synth__0 | +| calls.rb:323:12:323:14 | call to foo | calls.rb:323:12:323:14 | self | +| calls.rb:323:12:323:18 | call to baz | calls.rb:323:12:323:14 | call to foo | +| calls.rb:323:21:323:23 | call to foo | calls.rb:323:21:323:23 | self | +| calls.rb:323:21:323:27 | call to boo | calls.rb:323:21:323:23 | call to foo | +| calls.rb:323:21:323:31 | ... + ... | calls.rb:323:21:323:27 | call to boo | +| calls.rb:323:34:323:35 | ... * ... | calls.rb:323:1:323:32 | call to [] | +| calls.rb:326:11:326:13 | call to bar | calls.rb:326:11:326:13 | self | | calls.rb:327:13:327:15 | call to bar | calls.rb:327:13:327:15 | self | -| calls.rb:327:25:327:37 | call to print | calls.rb:327:25:327:37 | self | -| calls.rb:335:3:335:13 | call to bar | calls.rb:335:3:335:13 | self | -| calls.rb:339:1:341:3 | * ... | calls.rb:339:1:341:3 | __synth__0__1 | -| calls.rb:339:1:341:3 | call to each | calls.rb:339:16:339:33 | [...] | -| calls.rb:339:5:339:5 | ! ... | calls.rb:339:5:339:5 | defined? ... | -| calls.rb:339:5:339:5 | call to [] | calls.rb:339:5:339:5 | __synth__3__1 | -| calls.rb:339:5:339:5 | defined? ... | calls.rb:339:5:339:5 | x | -| calls.rb:339:8:339:8 | ! ... | calls.rb:339:8:339:8 | defined? ... | -| calls.rb:339:8:339:8 | call to [] | calls.rb:339:8:339:8 | __synth__3__1 | -| calls.rb:339:8:339:8 | defined? ... | calls.rb:339:8:339:8 | y | -| calls.rb:339:11:339:11 | ! ... | calls.rb:339:11:339:11 | defined? ... | -| calls.rb:339:11:339:11 | call to [] | calls.rb:339:11:339:11 | __synth__3__1 | -| calls.rb:339:11:339:11 | defined? ... | calls.rb:339:11:339:11 | z | -| calls.rb:339:16:339:33 | call to [] | calls.rb:339:16:339:33 | Array | -| calls.rb:339:17:339:23 | call to [] | calls.rb:339:17:339:23 | Array | -| calls.rb:339:26:339:32 | call to [] | calls.rb:339:26:339:32 | Array | -| calls.rb:340:3:340:13 | call to foo | calls.rb:340:3:340:13 | self | -| calls.rb:343:1:343:10 | call to foo | calls.rb:343:1:343:10 | self | -| calls.rb:344:1:344:15 | call to foo | calls.rb:344:1:344:15 | self | -| calls.rb:345:1:345:10 | call to foo | calls.rb:345:1:345:10 | self | -| calls.rb:346:1:346:7 | call to foo | calls.rb:346:1:346:7 | self | -| calls.rb:351:13:351:17 | call to foo | calls.rb:351:13:351:17 | self | -| calls.rb:352:13:352:24 | call to unknown_call | calls.rb:352:13:352:24 | self | -| calls.rb:356:3:356:14 | call to unknown_call | calls.rb:356:3:356:14 | self | -| calls.rb:360:1:360:4 | call to list | calls.rb:360:1:360:4 | self | -| calls.rb:360:1:360:11 | call to empty? | calls.rb:360:1:360:4 | call to list | -| calls.rb:361:1:361:4 | call to list | calls.rb:361:1:361:4 | self | -| calls.rb:361:1:361:12 | call to empty? | calls.rb:361:1:361:4 | __synth__0__1 | -| calls.rb:361:1:361:12 | call to empty? | calls.rb:361:1:361:4 | call to list | -| calls.rb:361:5:361:6 | call to == | calls.rb:361:5:361:6 | nil | -| calls.rb:362:1:362:4 | call to list | calls.rb:362:1:362:4 | self | -| calls.rb:362:1:362:12 | call to empty? | calls.rb:362:1:362:4 | call to list | -| calls.rb:363:1:363:3 | call to foo | calls.rb:363:1:363:3 | self | -| calls.rb:363:1:363:23 | call to bar | calls.rb:363:1:363:3 | __synth__0__1 | -| calls.rb:363:1:363:23 | call to bar | calls.rb:363:1:363:3 | call to foo | -| calls.rb:363:4:363:5 | call to == | calls.rb:363:4:363:5 | nil | +| calls.rb:328:14:328:16 | call to bar | calls.rb:328:14:328:16 | self | +| calls.rb:329:18:329:20 | call to bar | calls.rb:329:18:329:20 | self | +| calls.rb:330:22:330:24 | call to bar | calls.rb:330:22:330:24 | self | +| calls.rb:331:13:331:15 | call to bar | calls.rb:331:13:331:15 | self | +| calls.rb:331:25:331:37 | call to print | calls.rb:331:25:331:37 | self | +| calls.rb:339:3:339:13 | call to bar | calls.rb:339:3:339:13 | self | +| calls.rb:343:1:345:3 | * ... | calls.rb:343:1:345:3 | __synth__0__1 | +| calls.rb:343:1:345:3 | call to each | calls.rb:343:16:343:33 | [...] | +| calls.rb:343:5:343:5 | ! ... | calls.rb:343:5:343:5 | defined? ... | +| calls.rb:343:5:343:5 | call to [] | calls.rb:343:5:343:5 | __synth__3__1 | +| calls.rb:343:5:343:5 | defined? ... | calls.rb:343:5:343:5 | x | +| calls.rb:343:8:343:8 | ! ... | calls.rb:343:8:343:8 | defined? ... | +| calls.rb:343:8:343:8 | call to [] | calls.rb:343:8:343:8 | __synth__3__1 | +| calls.rb:343:8:343:8 | defined? ... | calls.rb:343:8:343:8 | y | +| calls.rb:343:11:343:11 | ! ... | calls.rb:343:11:343:11 | defined? ... | +| calls.rb:343:11:343:11 | call to [] | calls.rb:343:11:343:11 | __synth__3__1 | +| calls.rb:343:11:343:11 | defined? ... | calls.rb:343:11:343:11 | z | +| calls.rb:343:16:343:33 | call to [] | calls.rb:343:16:343:33 | Array | +| calls.rb:343:17:343:23 | call to [] | calls.rb:343:17:343:23 | Array | +| calls.rb:343:26:343:32 | call to [] | calls.rb:343:26:343:32 | Array | +| calls.rb:344:3:344:13 | call to foo | calls.rb:344:3:344:13 | self | +| calls.rb:347:1:347:10 | call to foo | calls.rb:347:1:347:10 | self | +| calls.rb:348:1:348:15 | call to foo | calls.rb:348:1:348:15 | self | +| calls.rb:349:1:349:10 | call to foo | calls.rb:349:1:349:10 | self | +| calls.rb:350:1:350:7 | call to foo | calls.rb:350:1:350:7 | self | +| calls.rb:355:13:355:17 | call to foo | calls.rb:355:13:355:17 | self | +| calls.rb:356:13:356:24 | call to unknown_call | calls.rb:356:13:356:24 | self | +| calls.rb:360:3:360:14 | call to unknown_call | calls.rb:360:3:360:14 | self | +| calls.rb:364:1:364:4 | call to list | calls.rb:364:1:364:4 | self | +| calls.rb:364:1:364:11 | call to empty? | calls.rb:364:1:364:4 | call to list | +| calls.rb:365:1:365:4 | call to list | calls.rb:365:1:365:4 | self | +| calls.rb:365:1:365:12 | call to empty? | calls.rb:365:1:365:4 | __synth__0__1 | +| calls.rb:365:1:365:12 | call to empty? | calls.rb:365:1:365:4 | call to list | +| calls.rb:365:5:365:6 | call to == | calls.rb:365:5:365:6 | nil | +| calls.rb:366:1:366:4 | call to list | calls.rb:366:1:366:4 | self | +| calls.rb:366:1:366:12 | call to empty? | calls.rb:366:1:366:4 | call to list | +| calls.rb:367:1:367:3 | call to foo | calls.rb:367:1:367:3 | self | +| calls.rb:367:1:367:23 | call to bar | calls.rb:367:1:367:3 | __synth__0__1 | +| calls.rb:367:1:367:23 | call to bar | calls.rb:367:1:367:3 | call to foo | +| calls.rb:367:4:367:5 | call to == | calls.rb:367:4:367:5 | nil | callsWithBlock | calls.rb:14:1:14:17 | call to foo | calls.rb:14:5:14:17 | { ... } | | calls.rb:17:1:19:3 | call to foo | calls.rb:17:5:19:3 | do ... end | @@ -419,52 +422,52 @@ callsWithBlock | calls.rb:92:1:95:3 | call to foo | calls.rb:92:7:95:3 | do ... end | | calls.rb:223:1:225:3 | call to each | calls.rb:223:1:225:3 | { ... } | | calls.rb:226:1:228:3 | call to each | calls.rb:226:1:228:3 | { ... } | -| calls.rb:289:5:289:23 | super call to my_method | calls.rb:289:11:289:23 | { ... } | -| calls.rb:290:5:290:26 | super call to my_method | calls.rb:290:11:290:26 | do ... end | -| calls.rb:291:5:291:30 | super call to my_method | calls.rb:291:16:291:30 | { ... } | -| calls.rb:292:5:292:33 | super call to my_method | calls.rb:292:16:292:33 | do ... end | -| calls.rb:339:1:341:3 | call to each | calls.rb:339:1:341:3 | { ... } | -| calls.rb:363:1:363:23 | call to bar | calls.rb:363:15:363:23 | { ... } | -| calls.rb:363:1:363:23 | call to bar | calls.rb:363:15:363:23 | { ... } | +| calls.rb:293:5:293:23 | super call to my_method | calls.rb:293:11:293:23 | { ... } | +| calls.rb:294:5:294:26 | super call to my_method | calls.rb:294:11:294:26 | do ... end | +| calls.rb:295:5:295:30 | super call to my_method | calls.rb:295:16:295:30 | { ... } | +| calls.rb:296:5:296:33 | super call to my_method | calls.rb:296:16:296:33 | do ... end | +| calls.rb:343:1:345:3 | call to each | calls.rb:343:1:345:3 | { ... } | +| calls.rb:367:1:367:23 | call to bar | calls.rb:367:15:367:23 | { ... } | +| calls.rb:367:1:367:23 | call to bar | calls.rb:367:15:367:23 | { ... } | yieldCalls | calls.rb:28:3:28:7 | yield ... | | calls.rb:33:3:33:16 | yield ... | superCalls -| calls.rb:285:5:285:9 | super call to my_method | -| calls.rb:286:5:286:11 | super call to my_method | -| calls.rb:287:5:287:16 | super call to my_method | -| calls.rb:288:5:288:17 | super call to my_method | -| calls.rb:289:5:289:23 | super call to my_method | -| calls.rb:290:5:290:26 | super call to my_method | -| calls.rb:291:5:291:30 | super call to my_method | -| calls.rb:292:5:292:33 | super call to my_method | -| calls.rb:304:5:304:9 | super call to another_method | -| calls.rb:331:3:331:12 | super call to foo | +| calls.rb:289:5:289:9 | super call to my_method | +| calls.rb:290:5:290:11 | super call to my_method | +| calls.rb:291:5:291:16 | super call to my_method | +| calls.rb:292:5:292:17 | super call to my_method | +| calls.rb:293:5:293:23 | super call to my_method | +| calls.rb:294:5:294:26 | super call to my_method | +| calls.rb:295:5:295:30 | super call to my_method | +| calls.rb:296:5:296:33 | super call to my_method | +| calls.rb:308:5:308:9 | super call to another_method | +| calls.rb:335:3:335:12 | super call to foo | superCallsWithArguments -| calls.rb:287:5:287:16 | super call to my_method | 0 | calls.rb:287:11:287:16 | "blah" | -| calls.rb:288:5:288:17 | super call to my_method | 0 | calls.rb:288:11:288:11 | 1 | -| calls.rb:288:5:288:17 | super call to my_method | 1 | calls.rb:288:14:288:14 | 2 | -| calls.rb:288:5:288:17 | super call to my_method | 2 | calls.rb:288:17:288:17 | 3 | -| calls.rb:291:5:291:30 | super call to my_method | 0 | calls.rb:291:11:291:11 | 4 | -| calls.rb:291:5:291:30 | super call to my_method | 1 | calls.rb:291:14:291:14 | 5 | -| calls.rb:292:5:292:33 | super call to my_method | 0 | calls.rb:292:11:292:11 | 6 | -| calls.rb:292:5:292:33 | super call to my_method | 1 | calls.rb:292:14:292:14 | 7 | -| calls.rb:331:3:331:12 | super call to foo | 0 | calls.rb:331:9:331:11 | ... | +| calls.rb:291:5:291:16 | super call to my_method | 0 | calls.rb:291:11:291:16 | "blah" | +| calls.rb:292:5:292:17 | super call to my_method | 0 | calls.rb:292:11:292:11 | 1 | +| calls.rb:292:5:292:17 | super call to my_method | 1 | calls.rb:292:14:292:14 | 2 | +| calls.rb:292:5:292:17 | super call to my_method | 2 | calls.rb:292:17:292:17 | 3 | +| calls.rb:295:5:295:30 | super call to my_method | 0 | calls.rb:295:11:295:11 | 4 | +| calls.rb:295:5:295:30 | super call to my_method | 1 | calls.rb:295:14:295:14 | 5 | +| calls.rb:296:5:296:33 | super call to my_method | 0 | calls.rb:296:11:296:11 | 6 | +| calls.rb:296:5:296:33 | super call to my_method | 1 | calls.rb:296:14:296:14 | 7 | +| calls.rb:335:3:335:12 | super call to foo | 0 | calls.rb:335:9:335:11 | ... | superCallsWithBlock -| calls.rb:289:5:289:23 | super call to my_method | calls.rb:289:11:289:23 | { ... } | -| calls.rb:290:5:290:26 | super call to my_method | calls.rb:290:11:290:26 | do ... end | -| calls.rb:291:5:291:30 | super call to my_method | calls.rb:291:16:291:30 | { ... } | -| calls.rb:292:5:292:33 | super call to my_method | calls.rb:292:16:292:33 | do ... end | +| calls.rb:293:5:293:23 | super call to my_method | calls.rb:293:11:293:23 | { ... } | +| calls.rb:294:5:294:26 | super call to my_method | calls.rb:294:11:294:26 | do ... end | +| calls.rb:295:5:295:30 | super call to my_method | calls.rb:295:16:295:30 | { ... } | +| calls.rb:296:5:296:33 | super call to my_method | calls.rb:296:16:296:33 | do ... end | setterCalls -| calls.rb:313:1:313:8 | call to foo= | -| calls.rb:314:1:314:6 | call to []= | -| calls.rb:315:1:315:8 | call to foo= | -| calls.rb:315:12:315:19 | call to bar= | -| calls.rb:315:22:315:27 | call to []= | -| calls.rb:316:5:316:10 | call to []= | -| calls.rb:317:1:317:10 | call to count= | +| calls.rb:317:1:317:8 | call to foo= | | calls.rb:318:1:318:6 | call to []= | -| calls.rb:319:1:319:32 | call to []= | +| calls.rb:319:1:319:8 | call to foo= | +| calls.rb:319:12:319:19 | call to bar= | +| calls.rb:319:22:319:27 | call to []= | +| calls.rb:320:5:320:10 | call to []= | +| calls.rb:321:1:321:10 | call to count= | +| calls.rb:322:1:322:6 | call to []= | +| calls.rb:323:1:323:32 | call to []= | callsWithSafeNavigationOperator -| calls.rb:361:1:361:12 | call to empty? | -| calls.rb:363:1:363:23 | call to bar | +| calls.rb:365:1:365:12 | call to empty? | +| calls.rb:367:1:367:23 | call to bar | diff --git a/ruby/ql/test/library-tests/ast/calls/calls.rb b/ruby/ql/test/library-tests/ast/calls/calls.rb index 5f06377b049..34beb26ba03 100644 --- a/ruby/ql/test/library-tests/ast/calls/calls.rb +++ b/ruby/ql/test/library-tests/ast/calls/calls.rb @@ -254,6 +254,10 @@ begin rescue X::foo ensure X::bar end +begin +rescue foo, X::bar +ensure baz +end # rescue-modifier body and handler foo rescue bar @@ -360,4 +364,4 @@ end list.empty? list&.empty? list::empty? -foo&.bar(1,2) { |x| x } \ No newline at end of file +foo&.bar(1,2) { |x| x } diff --git a/ruby/ql/test/library-tests/ast/control/CaseExpr.expected b/ruby/ql/test/library-tests/ast/control/CaseExpr.expected index 0ce764bbb74..eec96acd0b0 100644 --- a/ruby/ql/test/library-tests/ast/control/CaseExpr.expected +++ b/ruby/ql/test/library-tests/ast/control/CaseExpr.expected @@ -1,5 +1,6 @@ caseValues | cases.rb:8:1:15:3 | case ... | cases.rb:8:6:8:6 | a | +| cases.rb:18:1:22:3 | case ... | cases.rb:18:1:22:3 | true | | cases.rb:26:1:29:3 | case ... | cases.rb:26:6:26:9 | call to expr | | cases.rb:31:1:37:3 | case ... | cases.rb:31:6:31:9 | call to expr | | cases.rb:39:1:80:3 | case ... | cases.rb:39:6:39:9 | call to expr | @@ -15,7 +16,6 @@ caseValues | cases.rb:164:1:167:3 | case ... | cases.rb:165:3:165:5 | foo | | cases.rb:169:1:172:3 | case ... | cases.rb:170:3:170:5 | foo | caseNoValues -| cases.rb:18:1:22:3 | case ... | caseElseBranches | cases.rb:8:1:15:3 | case ... | cases.rb:13:1:14:7 | else ... | | cases.rb:26:1:29:3 | case ... | cases.rb:28:3:28:12 | else ... | diff --git a/ruby/ql/test/library-tests/controlflow/graph/BasicBlocks.expected b/ruby/ql/test/library-tests/controlflow/graph/BasicBlocks.expected index 720ee26e679..dd9e84f487a 100644 --- a/ruby/ql/test/library-tests/controlflow/graph/BasicBlocks.expected +++ b/ruby/ql/test/library-tests/controlflow/graph/BasicBlocks.expected @@ -1022,11 +1022,11 @@ dominates | cfg.rb:1:1:221:1 | enter cfg.rb | cfg.rb:43:21:43:31 | self | | cfg.rb:1:1:221:1 | enter cfg.rb | cfg.rb:44:8:44:18 | self | | cfg.rb:1:1:221:1 | enter cfg.rb | cfg.rb:47:1:50:3 | case ... | -| cfg.rb:1:1:221:1 | enter cfg.rb | cfg.rb:48:3:48:29 | [false] when ... | -| cfg.rb:1:1:221:1 | enter cfg.rb | cfg.rb:48:3:48:29 | [true] when ... | +| cfg.rb:1:1:221:1 | enter cfg.rb | cfg.rb:48:3:48:29 | [match] when ... | +| cfg.rb:1:1:221:1 | enter cfg.rb | cfg.rb:48:3:48:29 | [no-match] when ... | | cfg.rb:1:1:221:1 | enter cfg.rb | cfg.rb:48:20:48:29 | self | -| cfg.rb:1:1:221:1 | enter cfg.rb | cfg.rb:49:3:49:37 | [false] when ... | -| cfg.rb:1:1:221:1 | enter cfg.rb | cfg.rb:49:3:49:37 | [true] when ... | +| cfg.rb:1:1:221:1 | enter cfg.rb | cfg.rb:49:3:49:37 | [match] when ... | +| cfg.rb:1:1:221:1 | enter cfg.rb | cfg.rb:49:3:49:37 | [no-match] when ... | | cfg.rb:1:1:221:1 | enter cfg.rb | cfg.rb:49:8:49:8 | b | | cfg.rb:1:1:221:1 | enter cfg.rb | cfg.rb:49:16:49:16 | b | | cfg.rb:1:1:221:1 | enter cfg.rb | cfg.rb:49:27:49:37 | self | @@ -1085,11 +1085,11 @@ dominates | cfg.rb:32:9:32:9 | 1 | cfg.rb:43:21:43:31 | self | | cfg.rb:32:9:32:9 | 1 | cfg.rb:44:8:44:18 | self | | cfg.rb:32:9:32:9 | 1 | cfg.rb:47:1:50:3 | case ... | -| cfg.rb:32:9:32:9 | 1 | cfg.rb:48:3:48:29 | [false] when ... | -| cfg.rb:32:9:32:9 | 1 | cfg.rb:48:3:48:29 | [true] when ... | +| cfg.rb:32:9:32:9 | 1 | cfg.rb:48:3:48:29 | [match] when ... | +| cfg.rb:32:9:32:9 | 1 | cfg.rb:48:3:48:29 | [no-match] when ... | | cfg.rb:32:9:32:9 | 1 | cfg.rb:48:20:48:29 | self | -| cfg.rb:32:9:32:9 | 1 | cfg.rb:49:3:49:37 | [false] when ... | -| cfg.rb:32:9:32:9 | 1 | cfg.rb:49:3:49:37 | [true] when ... | +| cfg.rb:32:9:32:9 | 1 | cfg.rb:49:3:49:37 | [match] when ... | +| cfg.rb:32:9:32:9 | 1 | cfg.rb:49:3:49:37 | [no-match] when ... | | cfg.rb:32:9:32:9 | 1 | cfg.rb:49:8:49:8 | b | | cfg.rb:32:9:32:9 | 1 | cfg.rb:49:16:49:16 | b | | cfg.rb:32:9:32:9 | 1 | cfg.rb:49:27:49:37 | self | @@ -1145,11 +1145,11 @@ dominates | cfg.rb:35:1:37:3 | if ... | cfg.rb:43:21:43:31 | self | | cfg.rb:35:1:37:3 | if ... | cfg.rb:44:8:44:18 | self | | cfg.rb:35:1:37:3 | if ... | cfg.rb:47:1:50:3 | case ... | -| cfg.rb:35:1:37:3 | if ... | cfg.rb:48:3:48:29 | [false] when ... | -| cfg.rb:35:1:37:3 | if ... | cfg.rb:48:3:48:29 | [true] when ... | +| cfg.rb:35:1:37:3 | if ... | cfg.rb:48:3:48:29 | [match] when ... | +| cfg.rb:35:1:37:3 | if ... | cfg.rb:48:3:48:29 | [no-match] when ... | | cfg.rb:35:1:37:3 | if ... | cfg.rb:48:20:48:29 | self | -| cfg.rb:35:1:37:3 | if ... | cfg.rb:49:3:49:37 | [false] when ... | -| cfg.rb:35:1:37:3 | if ... | cfg.rb:49:3:49:37 | [true] when ... | +| cfg.rb:35:1:37:3 | if ... | cfg.rb:49:3:49:37 | [match] when ... | +| cfg.rb:35:1:37:3 | if ... | cfg.rb:49:3:49:37 | [no-match] when ... | | cfg.rb:35:1:37:3 | if ... | cfg.rb:49:8:49:8 | b | | cfg.rb:35:1:37:3 | if ... | cfg.rb:49:16:49:16 | b | | cfg.rb:35:1:37:3 | if ... | cfg.rb:49:27:49:37 | self | @@ -1194,11 +1194,11 @@ dominates | cfg.rb:35:1:37:3 | if ... | cfg.rb:205:4:205:5 | if ... | | cfg.rb:41:1:45:3 | case ... | cfg.rb:41:1:45:3 | case ... | | cfg.rb:41:1:45:3 | case ... | cfg.rb:47:1:50:3 | case ... | -| cfg.rb:41:1:45:3 | case ... | cfg.rb:48:3:48:29 | [false] when ... | -| cfg.rb:41:1:45:3 | case ... | cfg.rb:48:3:48:29 | [true] when ... | +| cfg.rb:41:1:45:3 | case ... | cfg.rb:48:3:48:29 | [match] when ... | +| cfg.rb:41:1:45:3 | case ... | cfg.rb:48:3:48:29 | [no-match] when ... | | cfg.rb:41:1:45:3 | case ... | cfg.rb:48:20:48:29 | self | -| cfg.rb:41:1:45:3 | case ... | cfg.rb:49:3:49:37 | [false] when ... | -| cfg.rb:41:1:45:3 | case ... | cfg.rb:49:3:49:37 | [true] when ... | +| cfg.rb:41:1:45:3 | case ... | cfg.rb:49:3:49:37 | [match] when ... | +| cfg.rb:41:1:45:3 | case ... | cfg.rb:49:3:49:37 | [no-match] when ... | | cfg.rb:41:1:45:3 | case ... | cfg.rb:49:8:49:8 | b | | cfg.rb:41:1:45:3 | case ... | cfg.rb:49:16:49:16 | b | | cfg.rb:41:1:45:3 | case ... | cfg.rb:49:27:49:37 | self | @@ -1312,24 +1312,24 @@ dominates | cfg.rb:47:1:50:3 | case ... | cfg.rb:205:1:205:3 | __synth__0__1 | | cfg.rb:47:1:50:3 | case ... | cfg.rb:205:1:205:3 | nil | | cfg.rb:47:1:50:3 | case ... | cfg.rb:205:4:205:5 | if ... | -| cfg.rb:48:3:48:29 | [false] when ... | cfg.rb:48:3:48:29 | [false] when ... | -| cfg.rb:48:3:48:29 | [false] when ... | cfg.rb:49:3:49:37 | [false] when ... | -| cfg.rb:48:3:48:29 | [false] when ... | cfg.rb:49:3:49:37 | [true] when ... | -| cfg.rb:48:3:48:29 | [false] when ... | cfg.rb:49:8:49:8 | b | -| cfg.rb:48:3:48:29 | [false] when ... | cfg.rb:49:16:49:16 | b | -| cfg.rb:48:3:48:29 | [false] when ... | cfg.rb:49:27:49:37 | self | -| cfg.rb:48:3:48:29 | [true] when ... | cfg.rb:48:3:48:29 | [true] when ... | -| cfg.rb:48:3:48:29 | [true] when ... | cfg.rb:48:20:48:29 | self | +| cfg.rb:48:3:48:29 | [match] when ... | cfg.rb:48:3:48:29 | [match] when ... | +| cfg.rb:48:3:48:29 | [match] when ... | cfg.rb:48:20:48:29 | self | +| cfg.rb:48:3:48:29 | [no-match] when ... | cfg.rb:48:3:48:29 | [no-match] when ... | +| cfg.rb:48:3:48:29 | [no-match] when ... | cfg.rb:49:3:49:37 | [match] when ... | +| cfg.rb:48:3:48:29 | [no-match] when ... | cfg.rb:49:3:49:37 | [no-match] when ... | +| cfg.rb:48:3:48:29 | [no-match] when ... | cfg.rb:49:8:49:8 | b | +| cfg.rb:48:3:48:29 | [no-match] when ... | cfg.rb:49:16:49:16 | b | +| cfg.rb:48:3:48:29 | [no-match] when ... | cfg.rb:49:27:49:37 | self | | cfg.rb:48:20:48:29 | self | cfg.rb:48:20:48:29 | self | -| cfg.rb:49:3:49:37 | [false] when ... | cfg.rb:49:3:49:37 | [false] when ... | -| cfg.rb:49:3:49:37 | [true] when ... | cfg.rb:49:3:49:37 | [true] when ... | -| cfg.rb:49:3:49:37 | [true] when ... | cfg.rb:49:27:49:37 | self | -| cfg.rb:49:8:49:8 | b | cfg.rb:49:3:49:37 | [false] when ... | -| cfg.rb:49:8:49:8 | b | cfg.rb:49:3:49:37 | [true] when ... | +| cfg.rb:49:3:49:37 | [match] when ... | cfg.rb:49:3:49:37 | [match] when ... | +| cfg.rb:49:3:49:37 | [match] when ... | cfg.rb:49:27:49:37 | self | +| cfg.rb:49:3:49:37 | [no-match] when ... | cfg.rb:49:3:49:37 | [no-match] when ... | +| cfg.rb:49:8:49:8 | b | cfg.rb:49:3:49:37 | [match] when ... | +| cfg.rb:49:8:49:8 | b | cfg.rb:49:3:49:37 | [no-match] when ... | | cfg.rb:49:8:49:8 | b | cfg.rb:49:8:49:8 | b | | cfg.rb:49:8:49:8 | b | cfg.rb:49:16:49:16 | b | | cfg.rb:49:8:49:8 | b | cfg.rb:49:27:49:37 | self | -| cfg.rb:49:16:49:16 | b | cfg.rb:49:3:49:37 | [false] when ... | +| cfg.rb:49:16:49:16 | b | cfg.rb:49:3:49:37 | [no-match] when ... | | cfg.rb:49:16:49:16 | b | cfg.rb:49:16:49:16 | b | | cfg.rb:49:27:49:37 | self | cfg.rb:49:27:49:37 | self | | cfg.rb:60:17:60:40 | ... ? ... : ... | cfg.rb:60:17:60:40 | ... ? ... : ... | @@ -2771,24 +2771,24 @@ postDominance | cfg.rb:47:1:50:3 | case ... | cfg.rb:43:21:43:31 | self | | cfg.rb:47:1:50:3 | case ... | cfg.rb:44:8:44:18 | self | | cfg.rb:47:1:50:3 | case ... | cfg.rb:47:1:50:3 | case ... | -| cfg.rb:47:1:50:3 | case ... | cfg.rb:48:3:48:29 | [false] when ... | -| cfg.rb:47:1:50:3 | case ... | cfg.rb:48:3:48:29 | [true] when ... | +| cfg.rb:47:1:50:3 | case ... | cfg.rb:48:3:48:29 | [match] when ... | +| cfg.rb:47:1:50:3 | case ... | cfg.rb:48:3:48:29 | [no-match] when ... | | cfg.rb:47:1:50:3 | case ... | cfg.rb:48:20:48:29 | self | -| cfg.rb:47:1:50:3 | case ... | cfg.rb:49:3:49:37 | [false] when ... | -| cfg.rb:47:1:50:3 | case ... | cfg.rb:49:3:49:37 | [true] when ... | +| cfg.rb:47:1:50:3 | case ... | cfg.rb:49:3:49:37 | [match] when ... | +| cfg.rb:47:1:50:3 | case ... | cfg.rb:49:3:49:37 | [no-match] when ... | | cfg.rb:47:1:50:3 | case ... | cfg.rb:49:8:49:8 | b | | cfg.rb:47:1:50:3 | case ... | cfg.rb:49:16:49:16 | b | | cfg.rb:47:1:50:3 | case ... | cfg.rb:49:27:49:37 | self | -| cfg.rb:48:3:48:29 | [false] when ... | cfg.rb:48:3:48:29 | [false] when ... | -| cfg.rb:48:3:48:29 | [true] when ... | cfg.rb:48:3:48:29 | [true] when ... | -| cfg.rb:48:20:48:29 | self | cfg.rb:48:3:48:29 | [true] when ... | +| cfg.rb:48:3:48:29 | [match] when ... | cfg.rb:48:3:48:29 | [match] when ... | +| cfg.rb:48:3:48:29 | [no-match] when ... | cfg.rb:48:3:48:29 | [no-match] when ... | +| cfg.rb:48:20:48:29 | self | cfg.rb:48:3:48:29 | [match] when ... | | cfg.rb:48:20:48:29 | self | cfg.rb:48:20:48:29 | self | -| cfg.rb:49:3:49:37 | [false] when ... | cfg.rb:49:3:49:37 | [false] when ... | -| cfg.rb:49:3:49:37 | [true] when ... | cfg.rb:49:3:49:37 | [true] when ... | -| cfg.rb:49:8:49:8 | b | cfg.rb:48:3:48:29 | [false] when ... | +| cfg.rb:49:3:49:37 | [match] when ... | cfg.rb:49:3:49:37 | [match] when ... | +| cfg.rb:49:3:49:37 | [no-match] when ... | cfg.rb:49:3:49:37 | [no-match] when ... | +| cfg.rb:49:8:49:8 | b | cfg.rb:48:3:48:29 | [no-match] when ... | | cfg.rb:49:8:49:8 | b | cfg.rb:49:8:49:8 | b | | cfg.rb:49:16:49:16 | b | cfg.rb:49:16:49:16 | b | -| cfg.rb:49:27:49:37 | self | cfg.rb:49:3:49:37 | [true] when ... | +| cfg.rb:49:27:49:37 | self | cfg.rb:49:3:49:37 | [match] when ... | | cfg.rb:49:27:49:37 | self | cfg.rb:49:27:49:37 | self | | cfg.rb:60:17:60:40 | ... ? ... : ... | cfg.rb:1:1:221:1 | enter cfg.rb | | cfg.rb:60:17:60:40 | ... ? ... : ... | cfg.rb:32:9:32:9 | 1 | @@ -2805,11 +2805,11 @@ postDominance | cfg.rb:60:17:60:40 | ... ? ... : ... | cfg.rb:43:21:43:31 | self | | cfg.rb:60:17:60:40 | ... ? ... : ... | cfg.rb:44:8:44:18 | self | | cfg.rb:60:17:60:40 | ... ? ... : ... | cfg.rb:47:1:50:3 | case ... | -| cfg.rb:60:17:60:40 | ... ? ... : ... | cfg.rb:48:3:48:29 | [false] when ... | -| cfg.rb:60:17:60:40 | ... ? ... : ... | cfg.rb:48:3:48:29 | [true] when ... | +| cfg.rb:60:17:60:40 | ... ? ... : ... | cfg.rb:48:3:48:29 | [match] when ... | +| cfg.rb:60:17:60:40 | ... ? ... : ... | cfg.rb:48:3:48:29 | [no-match] when ... | | cfg.rb:60:17:60:40 | ... ? ... : ... | cfg.rb:48:20:48:29 | self | -| cfg.rb:60:17:60:40 | ... ? ... : ... | cfg.rb:49:3:49:37 | [false] when ... | -| cfg.rb:60:17:60:40 | ... ? ... : ... | cfg.rb:49:3:49:37 | [true] when ... | +| cfg.rb:60:17:60:40 | ... ? ... : ... | cfg.rb:49:3:49:37 | [match] when ... | +| cfg.rb:60:17:60:40 | ... ? ... : ... | cfg.rb:49:3:49:37 | [no-match] when ... | | cfg.rb:60:17:60:40 | ... ? ... : ... | cfg.rb:49:8:49:8 | b | | cfg.rb:60:17:60:40 | ... ? ... : ... | cfg.rb:49:16:49:16 | b | | cfg.rb:60:17:60:40 | ... ? ... : ... | cfg.rb:49:27:49:37 | self | @@ -2835,11 +2835,11 @@ postDominance | cfg.rb:75:1:75:47 | if ... | cfg.rb:43:21:43:31 | self | | cfg.rb:75:1:75:47 | if ... | cfg.rb:44:8:44:18 | self | | cfg.rb:75:1:75:47 | if ... | cfg.rb:47:1:50:3 | case ... | -| cfg.rb:75:1:75:47 | if ... | cfg.rb:48:3:48:29 | [false] when ... | -| cfg.rb:75:1:75:47 | if ... | cfg.rb:48:3:48:29 | [true] when ... | +| cfg.rb:75:1:75:47 | if ... | cfg.rb:48:3:48:29 | [match] when ... | +| cfg.rb:75:1:75:47 | if ... | cfg.rb:48:3:48:29 | [no-match] when ... | | cfg.rb:75:1:75:47 | if ... | cfg.rb:48:20:48:29 | self | -| cfg.rb:75:1:75:47 | if ... | cfg.rb:49:3:49:37 | [false] when ... | -| cfg.rb:75:1:75:47 | if ... | cfg.rb:49:3:49:37 | [true] when ... | +| cfg.rb:75:1:75:47 | if ... | cfg.rb:49:3:49:37 | [match] when ... | +| cfg.rb:75:1:75:47 | if ... | cfg.rb:49:3:49:37 | [no-match] when ... | | cfg.rb:75:1:75:47 | if ... | cfg.rb:49:8:49:8 | b | | cfg.rb:75:1:75:47 | if ... | cfg.rb:49:16:49:16 | b | | cfg.rb:75:1:75:47 | if ... | cfg.rb:49:27:49:37 | self | @@ -2882,11 +2882,11 @@ postDominance | cfg.rb:90:5:90:5 | if ... | cfg.rb:43:21:43:31 | self | | cfg.rb:90:5:90:5 | if ... | cfg.rb:44:8:44:18 | self | | cfg.rb:90:5:90:5 | if ... | cfg.rb:47:1:50:3 | case ... | -| cfg.rb:90:5:90:5 | if ... | cfg.rb:48:3:48:29 | [false] when ... | -| cfg.rb:90:5:90:5 | if ... | cfg.rb:48:3:48:29 | [true] when ... | +| cfg.rb:90:5:90:5 | if ... | cfg.rb:48:3:48:29 | [match] when ... | +| cfg.rb:90:5:90:5 | if ... | cfg.rb:48:3:48:29 | [no-match] when ... | | cfg.rb:90:5:90:5 | if ... | cfg.rb:48:20:48:29 | self | -| cfg.rb:90:5:90:5 | if ... | cfg.rb:49:3:49:37 | [false] when ... | -| cfg.rb:90:5:90:5 | if ... | cfg.rb:49:3:49:37 | [true] when ... | +| cfg.rb:90:5:90:5 | if ... | cfg.rb:49:3:49:37 | [match] when ... | +| cfg.rb:90:5:90:5 | if ... | cfg.rb:49:3:49:37 | [no-match] when ... | | cfg.rb:90:5:90:5 | if ... | cfg.rb:49:8:49:8 | b | | cfg.rb:90:5:90:5 | if ... | cfg.rb:49:16:49:16 | b | | cfg.rb:90:5:90:5 | if ... | cfg.rb:49:27:49:37 | self | @@ -2928,11 +2928,11 @@ postDominance | cfg.rb:113:1:113:19 | ... if ... | cfg.rb:43:21:43:31 | self | | cfg.rb:113:1:113:19 | ... if ... | cfg.rb:44:8:44:18 | self | | cfg.rb:113:1:113:19 | ... if ... | cfg.rb:47:1:50:3 | case ... | -| cfg.rb:113:1:113:19 | ... if ... | cfg.rb:48:3:48:29 | [false] when ... | -| cfg.rb:113:1:113:19 | ... if ... | cfg.rb:48:3:48:29 | [true] when ... | +| cfg.rb:113:1:113:19 | ... if ... | cfg.rb:48:3:48:29 | [match] when ... | +| cfg.rb:113:1:113:19 | ... if ... | cfg.rb:48:3:48:29 | [no-match] when ... | | cfg.rb:113:1:113:19 | ... if ... | cfg.rb:48:20:48:29 | self | -| cfg.rb:113:1:113:19 | ... if ... | cfg.rb:49:3:49:37 | [false] when ... | -| cfg.rb:113:1:113:19 | ... if ... | cfg.rb:49:3:49:37 | [true] when ... | +| cfg.rb:113:1:113:19 | ... if ... | cfg.rb:49:3:49:37 | [match] when ... | +| cfg.rb:113:1:113:19 | ... if ... | cfg.rb:49:3:49:37 | [no-match] when ... | | cfg.rb:113:1:113:19 | ... if ... | cfg.rb:49:8:49:8 | b | | cfg.rb:113:1:113:19 | ... if ... | cfg.rb:49:16:49:16 | b | | cfg.rb:113:1:113:19 | ... if ... | cfg.rb:49:27:49:37 | self | @@ -2967,11 +2967,11 @@ postDominance | cfg.rb:136:1:136:29 | ... rescue ... | cfg.rb:43:21:43:31 | self | | cfg.rb:136:1:136:29 | ... rescue ... | cfg.rb:44:8:44:18 | self | | cfg.rb:136:1:136:29 | ... rescue ... | cfg.rb:47:1:50:3 | case ... | -| cfg.rb:136:1:136:29 | ... rescue ... | cfg.rb:48:3:48:29 | [false] when ... | -| cfg.rb:136:1:136:29 | ... rescue ... | cfg.rb:48:3:48:29 | [true] when ... | +| cfg.rb:136:1:136:29 | ... rescue ... | cfg.rb:48:3:48:29 | [match] when ... | +| cfg.rb:136:1:136:29 | ... rescue ... | cfg.rb:48:3:48:29 | [no-match] when ... | | cfg.rb:136:1:136:29 | ... rescue ... | cfg.rb:48:20:48:29 | self | -| cfg.rb:136:1:136:29 | ... rescue ... | cfg.rb:49:3:49:37 | [false] when ... | -| cfg.rb:136:1:136:29 | ... rescue ... | cfg.rb:49:3:49:37 | [true] when ... | +| cfg.rb:136:1:136:29 | ... rescue ... | cfg.rb:49:3:49:37 | [match] when ... | +| cfg.rb:136:1:136:29 | ... rescue ... | cfg.rb:49:3:49:37 | [no-match] when ... | | cfg.rb:136:1:136:29 | ... rescue ... | cfg.rb:49:8:49:8 | b | | cfg.rb:136:1:136:29 | ... rescue ... | cfg.rb:49:16:49:16 | b | | cfg.rb:136:1:136:29 | ... rescue ... | cfg.rb:49:27:49:37 | self | @@ -3011,11 +3011,11 @@ postDominance | cfg.rb:172:1:172:49 | unless ... | cfg.rb:43:21:43:31 | self | | cfg.rb:172:1:172:49 | unless ... | cfg.rb:44:8:44:18 | self | | cfg.rb:172:1:172:49 | unless ... | cfg.rb:47:1:50:3 | case ... | -| cfg.rb:172:1:172:49 | unless ... | cfg.rb:48:3:48:29 | [false] when ... | -| cfg.rb:172:1:172:49 | unless ... | cfg.rb:48:3:48:29 | [true] when ... | +| cfg.rb:172:1:172:49 | unless ... | cfg.rb:48:3:48:29 | [match] when ... | +| cfg.rb:172:1:172:49 | unless ... | cfg.rb:48:3:48:29 | [no-match] when ... | | cfg.rb:172:1:172:49 | unless ... | cfg.rb:48:20:48:29 | self | -| cfg.rb:172:1:172:49 | unless ... | cfg.rb:49:3:49:37 | [false] when ... | -| cfg.rb:172:1:172:49 | unless ... | cfg.rb:49:3:49:37 | [true] when ... | +| cfg.rb:172:1:172:49 | unless ... | cfg.rb:49:3:49:37 | [match] when ... | +| cfg.rb:172:1:172:49 | unless ... | cfg.rb:49:3:49:37 | [no-match] when ... | | cfg.rb:172:1:172:49 | unless ... | cfg.rb:49:8:49:8 | b | | cfg.rb:172:1:172:49 | unless ... | cfg.rb:49:16:49:16 | b | | cfg.rb:172:1:172:49 | unless ... | cfg.rb:49:27:49:37 | self | @@ -3057,11 +3057,11 @@ postDominance | cfg.rb:174:1:174:23 | ... unless ... | cfg.rb:43:21:43:31 | self | | cfg.rb:174:1:174:23 | ... unless ... | cfg.rb:44:8:44:18 | self | | cfg.rb:174:1:174:23 | ... unless ... | cfg.rb:47:1:50:3 | case ... | -| cfg.rb:174:1:174:23 | ... unless ... | cfg.rb:48:3:48:29 | [false] when ... | -| cfg.rb:174:1:174:23 | ... unless ... | cfg.rb:48:3:48:29 | [true] when ... | +| cfg.rb:174:1:174:23 | ... unless ... | cfg.rb:48:3:48:29 | [match] when ... | +| cfg.rb:174:1:174:23 | ... unless ... | cfg.rb:48:3:48:29 | [no-match] when ... | | cfg.rb:174:1:174:23 | ... unless ... | cfg.rb:48:20:48:29 | self | -| cfg.rb:174:1:174:23 | ... unless ... | cfg.rb:49:3:49:37 | [false] when ... | -| cfg.rb:174:1:174:23 | ... unless ... | cfg.rb:49:3:49:37 | [true] when ... | +| cfg.rb:174:1:174:23 | ... unless ... | cfg.rb:49:3:49:37 | [match] when ... | +| cfg.rb:174:1:174:23 | ... unless ... | cfg.rb:49:3:49:37 | [no-match] when ... | | cfg.rb:174:1:174:23 | ... unless ... | cfg.rb:49:8:49:8 | b | | cfg.rb:174:1:174:23 | ... unless ... | cfg.rb:49:16:49:16 | b | | cfg.rb:174:1:174:23 | ... unless ... | cfg.rb:49:27:49:37 | self | @@ -3102,11 +3102,11 @@ postDominance | cfg.rb:176:1:176:41 | until ... | cfg.rb:43:21:43:31 | self | | cfg.rb:176:1:176:41 | until ... | cfg.rb:44:8:44:18 | self | | cfg.rb:176:1:176:41 | until ... | cfg.rb:47:1:50:3 | case ... | -| cfg.rb:176:1:176:41 | until ... | cfg.rb:48:3:48:29 | [false] when ... | -| cfg.rb:176:1:176:41 | until ... | cfg.rb:48:3:48:29 | [true] when ... | +| cfg.rb:176:1:176:41 | until ... | cfg.rb:48:3:48:29 | [match] when ... | +| cfg.rb:176:1:176:41 | until ... | cfg.rb:48:3:48:29 | [no-match] when ... | | cfg.rb:176:1:176:41 | until ... | cfg.rb:48:20:48:29 | self | -| cfg.rb:176:1:176:41 | until ... | cfg.rb:49:3:49:37 | [false] when ... | -| cfg.rb:176:1:176:41 | until ... | cfg.rb:49:3:49:37 | [true] when ... | +| cfg.rb:176:1:176:41 | until ... | cfg.rb:49:3:49:37 | [match] when ... | +| cfg.rb:176:1:176:41 | until ... | cfg.rb:49:3:49:37 | [no-match] when ... | | cfg.rb:176:1:176:41 | until ... | cfg.rb:49:8:49:8 | b | | cfg.rb:176:1:176:41 | until ... | cfg.rb:49:16:49:16 | b | | cfg.rb:176:1:176:41 | until ... | cfg.rb:49:27:49:37 | self | @@ -3150,11 +3150,11 @@ postDominance | cfg.rb:176:7:176:7 | x | cfg.rb:43:21:43:31 | self | | cfg.rb:176:7:176:7 | x | cfg.rb:44:8:44:18 | self | | cfg.rb:176:7:176:7 | x | cfg.rb:47:1:50:3 | case ... | -| cfg.rb:176:7:176:7 | x | cfg.rb:48:3:48:29 | [false] when ... | -| cfg.rb:176:7:176:7 | x | cfg.rb:48:3:48:29 | [true] when ... | +| cfg.rb:176:7:176:7 | x | cfg.rb:48:3:48:29 | [match] when ... | +| cfg.rb:176:7:176:7 | x | cfg.rb:48:3:48:29 | [no-match] when ... | | cfg.rb:176:7:176:7 | x | cfg.rb:48:20:48:29 | self | -| cfg.rb:176:7:176:7 | x | cfg.rb:49:3:49:37 | [false] when ... | -| cfg.rb:176:7:176:7 | x | cfg.rb:49:3:49:37 | [true] when ... | +| cfg.rb:176:7:176:7 | x | cfg.rb:49:3:49:37 | [match] when ... | +| cfg.rb:176:7:176:7 | x | cfg.rb:49:3:49:37 | [no-match] when ... | | cfg.rb:176:7:176:7 | x | cfg.rb:49:8:49:8 | b | | cfg.rb:176:7:176:7 | x | cfg.rb:49:16:49:16 | b | | cfg.rb:176:7:176:7 | x | cfg.rb:49:27:49:37 | self | @@ -3198,11 +3198,11 @@ postDominance | cfg.rb:179:1:179:36 | ... until ... | cfg.rb:43:21:43:31 | self | | cfg.rb:179:1:179:36 | ... until ... | cfg.rb:44:8:44:18 | self | | cfg.rb:179:1:179:36 | ... until ... | cfg.rb:47:1:50:3 | case ... | -| cfg.rb:179:1:179:36 | ... until ... | cfg.rb:48:3:48:29 | [false] when ... | -| cfg.rb:179:1:179:36 | ... until ... | cfg.rb:48:3:48:29 | [true] when ... | +| cfg.rb:179:1:179:36 | ... until ... | cfg.rb:48:3:48:29 | [match] when ... | +| cfg.rb:179:1:179:36 | ... until ... | cfg.rb:48:3:48:29 | [no-match] when ... | | cfg.rb:179:1:179:36 | ... until ... | cfg.rb:48:20:48:29 | self | -| cfg.rb:179:1:179:36 | ... until ... | cfg.rb:49:3:49:37 | [false] when ... | -| cfg.rb:179:1:179:36 | ... until ... | cfg.rb:49:3:49:37 | [true] when ... | +| cfg.rb:179:1:179:36 | ... until ... | cfg.rb:49:3:49:37 | [match] when ... | +| cfg.rb:179:1:179:36 | ... until ... | cfg.rb:49:3:49:37 | [no-match] when ... | | cfg.rb:179:1:179:36 | ... until ... | cfg.rb:49:8:49:8 | b | | cfg.rb:179:1:179:36 | ... until ... | cfg.rb:49:16:49:16 | b | | cfg.rb:179:1:179:36 | ... until ... | cfg.rb:49:27:49:37 | self | @@ -3250,11 +3250,11 @@ postDominance | cfg.rb:179:30:179:30 | i | cfg.rb:43:21:43:31 | self | | cfg.rb:179:30:179:30 | i | cfg.rb:44:8:44:18 | self | | cfg.rb:179:30:179:30 | i | cfg.rb:47:1:50:3 | case ... | -| cfg.rb:179:30:179:30 | i | cfg.rb:48:3:48:29 | [false] when ... | -| cfg.rb:179:30:179:30 | i | cfg.rb:48:3:48:29 | [true] when ... | +| cfg.rb:179:30:179:30 | i | cfg.rb:48:3:48:29 | [match] when ... | +| cfg.rb:179:30:179:30 | i | cfg.rb:48:3:48:29 | [no-match] when ... | | cfg.rb:179:30:179:30 | i | cfg.rb:48:20:48:29 | self | -| cfg.rb:179:30:179:30 | i | cfg.rb:49:3:49:37 | [false] when ... | -| cfg.rb:179:30:179:30 | i | cfg.rb:49:3:49:37 | [true] when ... | +| cfg.rb:179:30:179:30 | i | cfg.rb:49:3:49:37 | [match] when ... | +| cfg.rb:179:30:179:30 | i | cfg.rb:49:3:49:37 | [no-match] when ... | | cfg.rb:179:30:179:30 | i | cfg.rb:49:8:49:8 | b | | cfg.rb:179:30:179:30 | i | cfg.rb:49:16:49:16 | b | | cfg.rb:179:30:179:30 | i | cfg.rb:49:27:49:37 | self | @@ -3300,11 +3300,11 @@ postDominance | cfg.rb:182:1:186:3 | while ... | cfg.rb:43:21:43:31 | self | | cfg.rb:182:1:186:3 | while ... | cfg.rb:44:8:44:18 | self | | cfg.rb:182:1:186:3 | while ... | cfg.rb:47:1:50:3 | case ... | -| cfg.rb:182:1:186:3 | while ... | cfg.rb:48:3:48:29 | [false] when ... | -| cfg.rb:182:1:186:3 | while ... | cfg.rb:48:3:48:29 | [true] when ... | +| cfg.rb:182:1:186:3 | while ... | cfg.rb:48:3:48:29 | [match] when ... | +| cfg.rb:182:1:186:3 | while ... | cfg.rb:48:3:48:29 | [no-match] when ... | | cfg.rb:182:1:186:3 | while ... | cfg.rb:48:20:48:29 | self | -| cfg.rb:182:1:186:3 | while ... | cfg.rb:49:3:49:37 | [false] when ... | -| cfg.rb:182:1:186:3 | while ... | cfg.rb:49:3:49:37 | [true] when ... | +| cfg.rb:182:1:186:3 | while ... | cfg.rb:49:3:49:37 | [match] when ... | +| cfg.rb:182:1:186:3 | while ... | cfg.rb:49:3:49:37 | [no-match] when ... | | cfg.rb:182:1:186:3 | while ... | cfg.rb:49:8:49:8 | b | | cfg.rb:182:1:186:3 | while ... | cfg.rb:49:16:49:16 | b | | cfg.rb:182:1:186:3 | while ... | cfg.rb:49:27:49:37 | self | @@ -3356,11 +3356,11 @@ postDominance | cfg.rb:182:7:182:7 | x | cfg.rb:43:21:43:31 | self | | cfg.rb:182:7:182:7 | x | cfg.rb:44:8:44:18 | self | | cfg.rb:182:7:182:7 | x | cfg.rb:47:1:50:3 | case ... | -| cfg.rb:182:7:182:7 | x | cfg.rb:48:3:48:29 | [false] when ... | -| cfg.rb:182:7:182:7 | x | cfg.rb:48:3:48:29 | [true] when ... | +| cfg.rb:182:7:182:7 | x | cfg.rb:48:3:48:29 | [match] when ... | +| cfg.rb:182:7:182:7 | x | cfg.rb:48:3:48:29 | [no-match] when ... | | cfg.rb:182:7:182:7 | x | cfg.rb:48:20:48:29 | self | -| cfg.rb:182:7:182:7 | x | cfg.rb:49:3:49:37 | [false] when ... | -| cfg.rb:182:7:182:7 | x | cfg.rb:49:3:49:37 | [true] when ... | +| cfg.rb:182:7:182:7 | x | cfg.rb:49:3:49:37 | [match] when ... | +| cfg.rb:182:7:182:7 | x | cfg.rb:49:3:49:37 | [no-match] when ... | | cfg.rb:182:7:182:7 | x | cfg.rb:49:8:49:8 | b | | cfg.rb:182:7:182:7 | x | cfg.rb:49:16:49:16 | b | | cfg.rb:182:7:182:7 | x | cfg.rb:49:27:49:37 | self | @@ -3417,11 +3417,11 @@ postDominance | cfg.rb:188:1:188:35 | ... while ... | cfg.rb:43:21:43:31 | self | | cfg.rb:188:1:188:35 | ... while ... | cfg.rb:44:8:44:18 | self | | cfg.rb:188:1:188:35 | ... while ... | cfg.rb:47:1:50:3 | case ... | -| cfg.rb:188:1:188:35 | ... while ... | cfg.rb:48:3:48:29 | [false] when ... | -| cfg.rb:188:1:188:35 | ... while ... | cfg.rb:48:3:48:29 | [true] when ... | +| cfg.rb:188:1:188:35 | ... while ... | cfg.rb:48:3:48:29 | [match] when ... | +| cfg.rb:188:1:188:35 | ... while ... | cfg.rb:48:3:48:29 | [no-match] when ... | | cfg.rb:188:1:188:35 | ... while ... | cfg.rb:48:20:48:29 | self | -| cfg.rb:188:1:188:35 | ... while ... | cfg.rb:49:3:49:37 | [false] when ... | -| cfg.rb:188:1:188:35 | ... while ... | cfg.rb:49:3:49:37 | [true] when ... | +| cfg.rb:188:1:188:35 | ... while ... | cfg.rb:49:3:49:37 | [match] when ... | +| cfg.rb:188:1:188:35 | ... while ... | cfg.rb:49:3:49:37 | [no-match] when ... | | cfg.rb:188:1:188:35 | ... while ... | cfg.rb:49:8:49:8 | b | | cfg.rb:188:1:188:35 | ... while ... | cfg.rb:49:16:49:16 | b | | cfg.rb:188:1:188:35 | ... while ... | cfg.rb:49:27:49:37 | self | @@ -3477,11 +3477,11 @@ postDominance | cfg.rb:188:30:188:30 | i | cfg.rb:43:21:43:31 | self | | cfg.rb:188:30:188:30 | i | cfg.rb:44:8:44:18 | self | | cfg.rb:188:30:188:30 | i | cfg.rb:47:1:50:3 | case ... | -| cfg.rb:188:30:188:30 | i | cfg.rb:48:3:48:29 | [false] when ... | -| cfg.rb:188:30:188:30 | i | cfg.rb:48:3:48:29 | [true] when ... | +| cfg.rb:188:30:188:30 | i | cfg.rb:48:3:48:29 | [match] when ... | +| cfg.rb:188:30:188:30 | i | cfg.rb:48:3:48:29 | [no-match] when ... | | cfg.rb:188:30:188:30 | i | cfg.rb:48:20:48:29 | self | -| cfg.rb:188:30:188:30 | i | cfg.rb:49:3:49:37 | [false] when ... | -| cfg.rb:188:30:188:30 | i | cfg.rb:49:3:49:37 | [true] when ... | +| cfg.rb:188:30:188:30 | i | cfg.rb:49:3:49:37 | [match] when ... | +| cfg.rb:188:30:188:30 | i | cfg.rb:49:3:49:37 | [no-match] when ... | | cfg.rb:188:30:188:30 | i | cfg.rb:49:8:49:8 | b | | cfg.rb:188:30:188:30 | i | cfg.rb:49:16:49:16 | b | | cfg.rb:188:30:188:30 | i | cfg.rb:49:27:49:37 | self | @@ -3542,11 +3542,11 @@ postDominance | cfg.rb:205:4:205:5 | if ... | cfg.rb:43:21:43:31 | self | | cfg.rb:205:4:205:5 | if ... | cfg.rb:44:8:44:18 | self | | cfg.rb:205:4:205:5 | if ... | cfg.rb:47:1:50:3 | case ... | -| cfg.rb:205:4:205:5 | if ... | cfg.rb:48:3:48:29 | [false] when ... | -| cfg.rb:205:4:205:5 | if ... | cfg.rb:48:3:48:29 | [true] when ... | +| cfg.rb:205:4:205:5 | if ... | cfg.rb:48:3:48:29 | [match] when ... | +| cfg.rb:205:4:205:5 | if ... | cfg.rb:48:3:48:29 | [no-match] when ... | | cfg.rb:205:4:205:5 | if ... | cfg.rb:48:20:48:29 | self | -| cfg.rb:205:4:205:5 | if ... | cfg.rb:49:3:49:37 | [false] when ... | -| cfg.rb:205:4:205:5 | if ... | cfg.rb:49:3:49:37 | [true] when ... | +| cfg.rb:205:4:205:5 | if ... | cfg.rb:49:3:49:37 | [match] when ... | +| cfg.rb:205:4:205:5 | if ... | cfg.rb:49:3:49:37 | [no-match] when ... | | cfg.rb:205:4:205:5 | if ... | cfg.rb:49:8:49:8 | b | | cfg.rb:205:4:205:5 | if ... | cfg.rb:49:16:49:16 | b | | cfg.rb:205:4:205:5 | if ... | cfg.rb:49:27:49:37 | self | @@ -4295,14 +4295,14 @@ immediateDominator | cfg.rb:43:21:43:31 | self | cfg.rb:43:3:43:31 | [match] when ... | | cfg.rb:44:8:44:18 | self | cfg.rb:43:3:43:31 | [no-match] when ... | | cfg.rb:47:1:50:3 | case ... | cfg.rb:41:1:45:3 | case ... | -| cfg.rb:48:3:48:29 | [false] when ... | cfg.rb:41:1:45:3 | case ... | -| cfg.rb:48:3:48:29 | [true] when ... | cfg.rb:41:1:45:3 | case ... | -| cfg.rb:48:20:48:29 | self | cfg.rb:48:3:48:29 | [true] when ... | -| cfg.rb:49:3:49:37 | [false] when ... | cfg.rb:49:16:49:16 | b | -| cfg.rb:49:3:49:37 | [true] when ... | cfg.rb:49:8:49:8 | b | -| cfg.rb:49:8:49:8 | b | cfg.rb:48:3:48:29 | [false] when ... | +| cfg.rb:48:3:48:29 | [match] when ... | cfg.rb:41:1:45:3 | case ... | +| cfg.rb:48:3:48:29 | [no-match] when ... | cfg.rb:41:1:45:3 | case ... | +| cfg.rb:48:20:48:29 | self | cfg.rb:48:3:48:29 | [match] when ... | +| cfg.rb:49:3:49:37 | [match] when ... | cfg.rb:49:8:49:8 | b | +| cfg.rb:49:3:49:37 | [no-match] when ... | cfg.rb:49:16:49:16 | b | +| cfg.rb:49:8:49:8 | b | cfg.rb:48:3:48:29 | [no-match] when ... | | cfg.rb:49:16:49:16 | b | cfg.rb:49:8:49:8 | b | -| cfg.rb:49:27:49:37 | self | cfg.rb:49:3:49:37 | [true] when ... | +| cfg.rb:49:27:49:37 | self | cfg.rb:49:3:49:37 | [match] when ... | | cfg.rb:60:17:60:40 | ... ? ... : ... | cfg.rb:47:1:50:3 | case ... | | cfg.rb:60:27:60:31 | hello | cfg.rb:47:1:50:3 | case ... | | cfg.rb:60:37:60:39 | bye | cfg.rb:47:1:50:3 | case ... | @@ -5310,11 +5310,11 @@ controls | cfg.rb:1:1:221:1 | enter cfg.rb | cfg.rb:43:21:43:31 | self | true | | cfg.rb:1:1:221:1 | enter cfg.rb | cfg.rb:44:8:44:18 | self | true | | cfg.rb:1:1:221:1 | enter cfg.rb | cfg.rb:47:1:50:3 | case ... | true | -| cfg.rb:1:1:221:1 | enter cfg.rb | cfg.rb:48:3:48:29 | [false] when ... | true | -| cfg.rb:1:1:221:1 | enter cfg.rb | cfg.rb:48:3:48:29 | [true] when ... | true | +| cfg.rb:1:1:221:1 | enter cfg.rb | cfg.rb:48:3:48:29 | [match] when ... | true | +| cfg.rb:1:1:221:1 | enter cfg.rb | cfg.rb:48:3:48:29 | [no-match] when ... | true | | cfg.rb:1:1:221:1 | enter cfg.rb | cfg.rb:48:20:48:29 | self | true | -| cfg.rb:1:1:221:1 | enter cfg.rb | cfg.rb:49:3:49:37 | [false] when ... | true | -| cfg.rb:1:1:221:1 | enter cfg.rb | cfg.rb:49:3:49:37 | [true] when ... | true | +| cfg.rb:1:1:221:1 | enter cfg.rb | cfg.rb:49:3:49:37 | [match] when ... | true | +| cfg.rb:1:1:221:1 | enter cfg.rb | cfg.rb:49:3:49:37 | [no-match] when ... | true | | cfg.rb:1:1:221:1 | enter cfg.rb | cfg.rb:49:8:49:8 | b | true | | cfg.rb:1:1:221:1 | enter cfg.rb | cfg.rb:49:16:49:16 | b | true | | cfg.rb:1:1:221:1 | enter cfg.rb | cfg.rb:49:27:49:37 | self | true | @@ -5370,11 +5370,11 @@ controls | cfg.rb:32:9:32:9 | 1 | cfg.rb:43:21:43:31 | self | false | | cfg.rb:32:9:32:9 | 1 | cfg.rb:44:8:44:18 | self | false | | cfg.rb:32:9:32:9 | 1 | cfg.rb:47:1:50:3 | case ... | false | -| cfg.rb:32:9:32:9 | 1 | cfg.rb:48:3:48:29 | [false] when ... | false | -| cfg.rb:32:9:32:9 | 1 | cfg.rb:48:3:48:29 | [true] when ... | false | +| cfg.rb:32:9:32:9 | 1 | cfg.rb:48:3:48:29 | [match] when ... | false | +| cfg.rb:32:9:32:9 | 1 | cfg.rb:48:3:48:29 | [no-match] when ... | false | | cfg.rb:32:9:32:9 | 1 | cfg.rb:48:20:48:29 | self | false | -| cfg.rb:32:9:32:9 | 1 | cfg.rb:49:3:49:37 | [false] when ... | false | -| cfg.rb:32:9:32:9 | 1 | cfg.rb:49:3:49:37 | [true] when ... | false | +| cfg.rb:32:9:32:9 | 1 | cfg.rb:49:3:49:37 | [match] when ... | false | +| cfg.rb:32:9:32:9 | 1 | cfg.rb:49:3:49:37 | [no-match] when ... | false | | cfg.rb:32:9:32:9 | 1 | cfg.rb:49:8:49:8 | b | false | | cfg.rb:32:9:32:9 | 1 | cfg.rb:49:16:49:16 | b | false | | cfg.rb:32:9:32:9 | 1 | cfg.rb:49:27:49:37 | self | false | @@ -5427,14 +5427,14 @@ controls | cfg.rb:35:1:37:3 | if ... | cfg.rb:43:14:43:14 | 4 | no-match | | cfg.rb:35:1:37:3 | if ... | cfg.rb:43:21:43:31 | self | no-match | | cfg.rb:35:1:37:3 | if ... | cfg.rb:44:8:44:18 | self | no-match | -| cfg.rb:41:1:45:3 | case ... | cfg.rb:48:3:48:29 | [false] when ... | false | -| cfg.rb:41:1:45:3 | case ... | cfg.rb:48:3:48:29 | [true] when ... | true | -| cfg.rb:41:1:45:3 | case ... | cfg.rb:48:20:48:29 | self | true | -| cfg.rb:41:1:45:3 | case ... | cfg.rb:49:3:49:37 | [false] when ... | false | -| cfg.rb:41:1:45:3 | case ... | cfg.rb:49:3:49:37 | [true] when ... | false | -| cfg.rb:41:1:45:3 | case ... | cfg.rb:49:8:49:8 | b | false | -| cfg.rb:41:1:45:3 | case ... | cfg.rb:49:16:49:16 | b | false | -| cfg.rb:41:1:45:3 | case ... | cfg.rb:49:27:49:37 | self | false | +| cfg.rb:41:1:45:3 | case ... | cfg.rb:48:3:48:29 | [match] when ... | match | +| cfg.rb:41:1:45:3 | case ... | cfg.rb:48:3:48:29 | [no-match] when ... | no-match | +| cfg.rb:41:1:45:3 | case ... | cfg.rb:48:20:48:29 | self | match | +| cfg.rb:41:1:45:3 | case ... | cfg.rb:49:3:49:37 | [match] when ... | no-match | +| cfg.rb:41:1:45:3 | case ... | cfg.rb:49:3:49:37 | [no-match] when ... | no-match | +| cfg.rb:41:1:45:3 | case ... | cfg.rb:49:8:49:8 | b | no-match | +| cfg.rb:41:1:45:3 | case ... | cfg.rb:49:16:49:16 | b | no-match | +| cfg.rb:41:1:45:3 | case ... | cfg.rb:49:27:49:37 | self | no-match | | cfg.rb:42:3:42:24 | [match] when ... | cfg.rb:42:15:42:24 | self | match | | cfg.rb:42:3:42:24 | [no-match] when ... | cfg.rb:43:3:43:31 | [match] when ... | no-match | | cfg.rb:42:3:42:24 | [no-match] when ... | cfg.rb:43:3:43:31 | [no-match] when ... | no-match | @@ -5456,16 +5456,16 @@ controls | cfg.rb:43:14:43:14 | 4 | cfg.rb:44:8:44:18 | self | no-match | | cfg.rb:47:1:50:3 | case ... | cfg.rb:60:27:60:31 | hello | true | | cfg.rb:47:1:50:3 | case ... | cfg.rb:60:37:60:39 | bye | false | -| cfg.rb:48:3:48:29 | [false] when ... | cfg.rb:49:3:49:37 | [false] when ... | false | -| cfg.rb:48:3:48:29 | [false] when ... | cfg.rb:49:3:49:37 | [true] when ... | false | -| cfg.rb:48:3:48:29 | [false] when ... | cfg.rb:49:8:49:8 | b | false | -| cfg.rb:48:3:48:29 | [false] when ... | cfg.rb:49:16:49:16 | b | false | -| cfg.rb:48:3:48:29 | [false] when ... | cfg.rb:49:27:49:37 | self | false | -| cfg.rb:48:3:48:29 | [true] when ... | cfg.rb:48:20:48:29 | self | true | -| cfg.rb:49:3:49:37 | [true] when ... | cfg.rb:49:27:49:37 | self | true | -| cfg.rb:49:8:49:8 | b | cfg.rb:49:3:49:37 | [false] when ... | false | -| cfg.rb:49:8:49:8 | b | cfg.rb:49:16:49:16 | b | false | -| cfg.rb:49:16:49:16 | b | cfg.rb:49:3:49:37 | [false] when ... | false | +| cfg.rb:48:3:48:29 | [match] when ... | cfg.rb:48:20:48:29 | self | match | +| cfg.rb:48:3:48:29 | [no-match] when ... | cfg.rb:49:3:49:37 | [match] when ... | no-match | +| cfg.rb:48:3:48:29 | [no-match] when ... | cfg.rb:49:3:49:37 | [no-match] when ... | no-match | +| cfg.rb:48:3:48:29 | [no-match] when ... | cfg.rb:49:8:49:8 | b | no-match | +| cfg.rb:48:3:48:29 | [no-match] when ... | cfg.rb:49:16:49:16 | b | no-match | +| cfg.rb:48:3:48:29 | [no-match] when ... | cfg.rb:49:27:49:37 | self | no-match | +| cfg.rb:49:3:49:37 | [match] when ... | cfg.rb:49:27:49:37 | self | match | +| cfg.rb:49:8:49:8 | b | cfg.rb:49:3:49:37 | [no-match] when ... | no-match | +| cfg.rb:49:8:49:8 | b | cfg.rb:49:16:49:16 | b | no-match | +| cfg.rb:49:16:49:16 | b | cfg.rb:49:3:49:37 | [no-match] when ... | no-match | | cfg.rb:60:17:60:40 | ... ? ... : ... | cfg.rb:75:15:75:15 | 0 | true | | cfg.rb:60:17:60:40 | ... ? ... : ... | cfg.rb:75:17:75:43 | elsif ... | false | | cfg.rb:60:17:60:40 | ... ? ... : ... | cfg.rb:75:23:75:23 | x | false | @@ -6010,8 +6010,8 @@ successor | cfg.rb:32:9:32:9 | 1 | cfg.rb:35:1:37:3 | if ... | false | | cfg.rb:35:1:37:3 | if ... | cfg.rb:42:3:42:24 | [match] when ... | match | | cfg.rb:35:1:37:3 | if ... | cfg.rb:42:3:42:24 | [no-match] when ... | no-match | -| cfg.rb:41:1:45:3 | case ... | cfg.rb:48:3:48:29 | [false] when ... | false | -| cfg.rb:41:1:45:3 | case ... | cfg.rb:48:3:48:29 | [true] when ... | true | +| cfg.rb:41:1:45:3 | case ... | cfg.rb:48:3:48:29 | [match] when ... | match | +| cfg.rb:41:1:45:3 | case ... | cfg.rb:48:3:48:29 | [no-match] when ... | no-match | | cfg.rb:42:3:42:24 | [match] when ... | cfg.rb:42:15:42:24 | self | match | | cfg.rb:42:3:42:24 | [no-match] when ... | cfg.rb:43:8:43:8 | 2 | no-match | | cfg.rb:43:3:43:31 | [match] when ... | cfg.rb:43:21:43:31 | self | match | @@ -6024,14 +6024,14 @@ successor | cfg.rb:43:14:43:14 | 4 | cfg.rb:43:3:43:31 | [no-match] when ... | no-match | | cfg.rb:47:1:50:3 | case ... | cfg.rb:60:27:60:31 | hello | true | | cfg.rb:47:1:50:3 | case ... | cfg.rb:60:37:60:39 | bye | false | -| cfg.rb:48:3:48:29 | [false] when ... | cfg.rb:49:8:49:8 | b | false | -| cfg.rb:48:3:48:29 | [true] when ... | cfg.rb:48:20:48:29 | self | true | -| cfg.rb:49:3:49:37 | [false] when ... | cfg.rb:47:1:50:3 | case ... | false | -| cfg.rb:49:3:49:37 | [true] when ... | cfg.rb:49:27:49:37 | self | true | -| cfg.rb:49:8:49:8 | b | cfg.rb:49:3:49:37 | [true] when ... | true | -| cfg.rb:49:8:49:8 | b | cfg.rb:49:16:49:16 | b | false | -| cfg.rb:49:16:49:16 | b | cfg.rb:49:3:49:37 | [false] when ... | false | -| cfg.rb:49:16:49:16 | b | cfg.rb:49:3:49:37 | [true] when ... | true | +| cfg.rb:48:3:48:29 | [match] when ... | cfg.rb:48:20:48:29 | self | match | +| cfg.rb:48:3:48:29 | [no-match] when ... | cfg.rb:49:8:49:8 | b | no-match | +| cfg.rb:49:3:49:37 | [match] when ... | cfg.rb:49:27:49:37 | self | match | +| cfg.rb:49:3:49:37 | [no-match] when ... | cfg.rb:47:1:50:3 | case ... | no-match | +| cfg.rb:49:8:49:8 | b | cfg.rb:49:3:49:37 | [match] when ... | match | +| cfg.rb:49:8:49:8 | b | cfg.rb:49:16:49:16 | b | no-match | +| cfg.rb:49:16:49:16 | b | cfg.rb:49:3:49:37 | [match] when ... | match | +| cfg.rb:49:16:49:16 | b | cfg.rb:49:3:49:37 | [no-match] when ... | no-match | | cfg.rb:60:17:60:40 | ... ? ... : ... | cfg.rb:75:15:75:15 | 0 | true | | cfg.rb:60:17:60:40 | ... ? ... : ... | cfg.rb:75:23:75:23 | x | false | | cfg.rb:75:1:75:47 | if ... | cfg.rb:90:5:90:5 | [false] ! ... | true | @@ -6365,10 +6365,10 @@ joinBlockPredecessor | cfg.rb:43:3:43:31 | [match] when ... | cfg.rb:43:11:43:11 | 3 | 1 | | cfg.rb:43:3:43:31 | [match] when ... | cfg.rb:43:14:43:14 | 4 | 2 | | cfg.rb:47:1:50:3 | case ... | cfg.rb:48:20:48:29 | self | 0 | -| cfg.rb:47:1:50:3 | case ... | cfg.rb:49:3:49:37 | [false] when ... | 1 | +| cfg.rb:47:1:50:3 | case ... | cfg.rb:49:3:49:37 | [no-match] when ... | 1 | | cfg.rb:47:1:50:3 | case ... | cfg.rb:49:27:49:37 | self | 2 | -| cfg.rb:49:3:49:37 | [true] when ... | cfg.rb:49:8:49:8 | b | 0 | -| cfg.rb:49:3:49:37 | [true] when ... | cfg.rb:49:16:49:16 | b | 1 | +| cfg.rb:49:3:49:37 | [match] when ... | cfg.rb:49:8:49:8 | b | 0 | +| cfg.rb:49:3:49:37 | [match] when ... | cfg.rb:49:16:49:16 | b | 1 | | cfg.rb:60:17:60:40 | ... ? ... : ... | cfg.rb:60:27:60:31 | hello | 0 | | cfg.rb:60:17:60:40 | ... ? ... : ... | cfg.rb:60:37:60:39 | bye | 1 | | cfg.rb:75:1:75:47 | if ... | cfg.rb:75:15:75:15 | 0 | 0 | diff --git a/ruby/ql/test/library-tests/controlflow/graph/Cfg.expected b/ruby/ql/test/library-tests/controlflow/graph/Cfg.expected index 583ca5d46a8..e7ce708b63b 100644 --- a/ruby/ql/test/library-tests/controlflow/graph/Cfg.expected +++ b/ruby/ql/test/library-tests/controlflow/graph/Cfg.expected @@ -649,7 +649,7 @@ | cfg.rb:39:1:39:4 | self | cfg.rb:39:11:39:12 | 42 | | | cfg.rb:39:1:39:12 | call to puts | cfg.rb:41:6:41:7 | 10 | | | cfg.rb:39:11:39:12 | 42 | cfg.rb:39:1:39:12 | call to puts | | -| cfg.rb:41:1:45:3 | case ... | cfg.rb:48:8:48:8 | b | | +| cfg.rb:41:1:45:3 | case ... | cfg.rb:47:1:50:3 | true | | | cfg.rb:41:6:41:7 | 10 | cfg.rb:42:8:42:8 | 1 | | | cfg.rb:42:3:42:24 | [match] when ... | cfg.rb:42:15:42:24 | self | match | | cfg.rb:42:3:42:24 | [no-match] when ... | cfg.rb:43:8:43:8 | 2 | no-match | @@ -679,26 +679,27 @@ | cfg.rb:44:13:44:18 | "many" | cfg.rb:44:8:44:18 | call to puts | | | cfg.rb:44:14:44:17 | many | cfg.rb:44:13:44:18 | "many" | | | cfg.rb:47:1:50:3 | case ... | cfg.rb:52:1:52:7 | chained | | -| cfg.rb:48:3:48:29 | [false] when ... | cfg.rb:49:8:49:8 | b | false | -| cfg.rb:48:3:48:29 | [true] when ... | cfg.rb:48:20:48:29 | self | true | +| cfg.rb:47:1:50:3 | true | cfg.rb:48:8:48:8 | b | | +| cfg.rb:48:3:48:29 | [match] when ... | cfg.rb:48:20:48:29 | self | match | +| cfg.rb:48:3:48:29 | [no-match] when ... | cfg.rb:49:8:49:8 | b | no-match | | cfg.rb:48:8:48:8 | b | cfg.rb:48:13:48:13 | 1 | | -| cfg.rb:48:8:48:13 | ... == ... | cfg.rb:48:3:48:29 | [false] when ... | false | -| cfg.rb:48:8:48:13 | ... == ... | cfg.rb:48:3:48:29 | [true] when ... | true | +| cfg.rb:48:8:48:13 | ... == ... | cfg.rb:48:3:48:29 | [match] when ... | match | +| cfg.rb:48:8:48:13 | ... == ... | cfg.rb:48:3:48:29 | [no-match] when ... | no-match | | cfg.rb:48:13:48:13 | 1 | cfg.rb:48:8:48:13 | ... == ... | | | cfg.rb:48:15:48:29 | then ... | cfg.rb:47:1:50:3 | case ... | | | cfg.rb:48:20:48:29 | call to puts | cfg.rb:48:15:48:29 | then ... | | | cfg.rb:48:20:48:29 | self | cfg.rb:48:26:48:28 | one | | | cfg.rb:48:25:48:29 | "one" | cfg.rb:48:20:48:29 | call to puts | | | cfg.rb:48:26:48:28 | one | cfg.rb:48:25:48:29 | "one" | | -| cfg.rb:49:3:49:37 | [false] when ... | cfg.rb:47:1:50:3 | case ... | false | -| cfg.rb:49:3:49:37 | [true] when ... | cfg.rb:49:27:49:37 | self | true | +| cfg.rb:49:3:49:37 | [match] when ... | cfg.rb:49:27:49:37 | self | match | +| cfg.rb:49:3:49:37 | [no-match] when ... | cfg.rb:47:1:50:3 | case ... | no-match | | cfg.rb:49:8:49:8 | b | cfg.rb:49:13:49:13 | 0 | | -| cfg.rb:49:8:49:13 | ... == ... | cfg.rb:49:3:49:37 | [true] when ... | true | -| cfg.rb:49:8:49:13 | ... == ... | cfg.rb:49:16:49:16 | b | false | +| cfg.rb:49:8:49:13 | ... == ... | cfg.rb:49:3:49:37 | [match] when ... | match | +| cfg.rb:49:8:49:13 | ... == ... | cfg.rb:49:16:49:16 | b | no-match | | cfg.rb:49:13:49:13 | 0 | cfg.rb:49:8:49:13 | ... == ... | | | cfg.rb:49:16:49:16 | b | cfg.rb:49:20:49:20 | 1 | | -| cfg.rb:49:16:49:20 | ... > ... | cfg.rb:49:3:49:37 | [false] when ... | false | -| cfg.rb:49:16:49:20 | ... > ... | cfg.rb:49:3:49:37 | [true] when ... | true | +| cfg.rb:49:16:49:20 | ... > ... | cfg.rb:49:3:49:37 | [match] when ... | match | +| cfg.rb:49:16:49:20 | ... > ... | cfg.rb:49:3:49:37 | [no-match] when ... | no-match | | cfg.rb:49:20:49:20 | 1 | cfg.rb:49:16:49:20 | ... > ... | | | cfg.rb:49:22:49:37 | then ... | cfg.rb:47:1:50:3 | case ... | | | cfg.rb:49:27:49:37 | call to puts | cfg.rb:49:22:49:37 | then ... | | diff --git a/ruby/ql/test/library-tests/dataflow/barrier-guards/barrier-guards.expected b/ruby/ql/test/library-tests/dataflow/barrier-guards/barrier-guards.expected index 0da6e95f6ed..1a70b535dc8 100644 --- a/ruby/ql/test/library-tests/dataflow/barrier-guards/barrier-guards.expected +++ b/ruby/ql/test/library-tests/dataflow/barrier-guards/barrier-guards.expected @@ -266,46 +266,46 @@ controls | barrier-guards.rb:227:4:227:21 | [true] ... and ... | barrier-guards.rb:228:5:228:7 | self | true | | barrier-guards.rb:227:21:227:21 | call to y | barrier-guards.rb:227:4:227:21 | [true] ... and ... | true | | barrier-guards.rb:227:21:227:21 | call to y | barrier-guards.rb:228:5:228:7 | self | true | -| barrier-guards.rb:232:1:233:19 | [true] when ... | barrier-guards.rb:233:5:233:7 | foo | true | -| barrier-guards.rb:232:6:232:17 | ... == ... | barrier-guards.rb:232:1:233:19 | [false] when ... | false | -| barrier-guards.rb:232:6:232:17 | ... == ... | barrier-guards.rb:232:1:233:19 | [true] when ... | true | -| barrier-guards.rb:232:6:232:17 | ... == ... | barrier-guards.rb:233:5:233:7 | foo | true | -| barrier-guards.rb:237:1:237:38 | [false] when ... | barrier-guards.rb:238:1:238:26 | [false] when ... | false | -| barrier-guards.rb:237:1:237:38 | [false] when ... | barrier-guards.rb:238:1:238:26 | [true] when ... | false | -| barrier-guards.rb:237:1:237:38 | [false] when ... | barrier-guards.rb:238:6:238:8 | self | false | -| barrier-guards.rb:237:1:237:38 | [false] when ... | barrier-guards.rb:238:24:238:26 | foo | false | -| barrier-guards.rb:237:1:237:38 | [false] when ... | barrier-guards.rb:239:1:239:22 | [false] when ... | false | -| barrier-guards.rb:237:1:237:38 | [false] when ... | barrier-guards.rb:239:1:239:22 | [true] when ... | false | -| barrier-guards.rb:237:1:237:38 | [false] when ... | barrier-guards.rb:239:6:239:8 | foo | false | -| barrier-guards.rb:237:1:237:38 | [false] when ... | barrier-guards.rb:239:20:239:22 | foo | false | -| barrier-guards.rb:237:1:237:38 | [true] when ... | barrier-guards.rb:237:24:237:26 | foo | true | -| barrier-guards.rb:237:6:237:17 | ... == ... | barrier-guards.rb:237:1:237:38 | [false] when ... | false | -| barrier-guards.rb:237:6:237:17 | ... == ... | barrier-guards.rb:237:1:237:38 | [true] when ... | true | -| barrier-guards.rb:237:6:237:17 | ... == ... | barrier-guards.rb:237:24:237:26 | foo | true | -| barrier-guards.rb:237:6:237:17 | ... == ... | barrier-guards.rb:238:1:238:26 | [false] when ... | false | -| barrier-guards.rb:237:6:237:17 | ... == ... | barrier-guards.rb:238:1:238:26 | [true] when ... | false | -| barrier-guards.rb:237:6:237:17 | ... == ... | barrier-guards.rb:238:6:238:8 | self | false | -| barrier-guards.rb:237:6:237:17 | ... == ... | barrier-guards.rb:238:24:238:26 | foo | false | -| barrier-guards.rb:237:6:237:17 | ... == ... | barrier-guards.rb:239:1:239:22 | [false] when ... | false | -| barrier-guards.rb:237:6:237:17 | ... == ... | barrier-guards.rb:239:1:239:22 | [true] when ... | false | -| barrier-guards.rb:237:6:237:17 | ... == ... | barrier-guards.rb:239:6:239:8 | foo | false | -| barrier-guards.rb:237:6:237:17 | ... == ... | barrier-guards.rb:239:20:239:22 | foo | false | -| barrier-guards.rb:238:1:238:26 | [false] when ... | barrier-guards.rb:239:1:239:22 | [false] when ... | false | -| barrier-guards.rb:238:1:238:26 | [false] when ... | barrier-guards.rb:239:1:239:22 | [true] when ... | false | -| barrier-guards.rb:238:1:238:26 | [false] when ... | barrier-guards.rb:239:6:239:8 | foo | false | -| barrier-guards.rb:238:1:238:26 | [false] when ... | barrier-guards.rb:239:20:239:22 | foo | false | -| barrier-guards.rb:238:1:238:26 | [true] when ... | barrier-guards.rb:238:24:238:26 | foo | true | -| barrier-guards.rb:238:6:238:17 | ... == ... | barrier-guards.rb:238:1:238:26 | [false] when ... | false | -| barrier-guards.rb:238:6:238:17 | ... == ... | barrier-guards.rb:238:1:238:26 | [true] when ... | true | -| barrier-guards.rb:238:6:238:17 | ... == ... | barrier-guards.rb:238:24:238:26 | foo | true | -| barrier-guards.rb:238:6:238:17 | ... == ... | barrier-guards.rb:239:1:239:22 | [false] when ... | false | -| barrier-guards.rb:238:6:238:17 | ... == ... | barrier-guards.rb:239:1:239:22 | [true] when ... | false | -| barrier-guards.rb:238:6:238:17 | ... == ... | barrier-guards.rb:239:6:239:8 | foo | false | -| barrier-guards.rb:238:6:238:17 | ... == ... | barrier-guards.rb:239:20:239:22 | foo | false | -| barrier-guards.rb:239:1:239:22 | [true] when ... | barrier-guards.rb:239:20:239:22 | foo | true | -| barrier-guards.rb:239:6:239:13 | ... == ... | barrier-guards.rb:239:1:239:22 | [false] when ... | false | -| barrier-guards.rb:239:6:239:13 | ... == ... | barrier-guards.rb:239:1:239:22 | [true] when ... | true | -| barrier-guards.rb:239:6:239:13 | ... == ... | barrier-guards.rb:239:20:239:22 | foo | true | +| barrier-guards.rb:232:1:233:19 | [match] when ... | barrier-guards.rb:233:5:233:7 | foo | match | +| barrier-guards.rb:232:6:232:17 | ... == ... | barrier-guards.rb:232:1:233:19 | [match] when ... | match | +| barrier-guards.rb:232:6:232:17 | ... == ... | barrier-guards.rb:232:1:233:19 | [no-match] when ... | no-match | +| barrier-guards.rb:232:6:232:17 | ... == ... | barrier-guards.rb:233:5:233:7 | foo | match | +| barrier-guards.rb:237:1:237:38 | [match] when ... | barrier-guards.rb:237:24:237:26 | foo | match | +| barrier-guards.rb:237:1:237:38 | [no-match] when ... | barrier-guards.rb:238:1:238:26 | [match] when ... | no-match | +| barrier-guards.rb:237:1:237:38 | [no-match] when ... | barrier-guards.rb:238:1:238:26 | [no-match] when ... | no-match | +| barrier-guards.rb:237:1:237:38 | [no-match] when ... | barrier-guards.rb:238:6:238:8 | self | no-match | +| barrier-guards.rb:237:1:237:38 | [no-match] when ... | barrier-guards.rb:238:24:238:26 | foo | no-match | +| barrier-guards.rb:237:1:237:38 | [no-match] when ... | barrier-guards.rb:239:1:239:22 | [match] when ... | no-match | +| barrier-guards.rb:237:1:237:38 | [no-match] when ... | barrier-guards.rb:239:1:239:22 | [no-match] when ... | no-match | +| barrier-guards.rb:237:1:237:38 | [no-match] when ... | barrier-guards.rb:239:6:239:8 | foo | no-match | +| barrier-guards.rb:237:1:237:38 | [no-match] when ... | barrier-guards.rb:239:20:239:22 | foo | no-match | +| barrier-guards.rb:237:6:237:17 | ... == ... | barrier-guards.rb:237:1:237:38 | [match] when ... | match | +| barrier-guards.rb:237:6:237:17 | ... == ... | barrier-guards.rb:237:1:237:38 | [no-match] when ... | no-match | +| barrier-guards.rb:237:6:237:17 | ... == ... | barrier-guards.rb:237:24:237:26 | foo | match | +| barrier-guards.rb:237:6:237:17 | ... == ... | barrier-guards.rb:238:1:238:26 | [match] when ... | no-match | +| barrier-guards.rb:237:6:237:17 | ... == ... | barrier-guards.rb:238:1:238:26 | [no-match] when ... | no-match | +| barrier-guards.rb:237:6:237:17 | ... == ... | barrier-guards.rb:238:6:238:8 | self | no-match | +| barrier-guards.rb:237:6:237:17 | ... == ... | barrier-guards.rb:238:24:238:26 | foo | no-match | +| barrier-guards.rb:237:6:237:17 | ... == ... | barrier-guards.rb:239:1:239:22 | [match] when ... | no-match | +| barrier-guards.rb:237:6:237:17 | ... == ... | barrier-guards.rb:239:1:239:22 | [no-match] when ... | no-match | +| barrier-guards.rb:237:6:237:17 | ... == ... | barrier-guards.rb:239:6:239:8 | foo | no-match | +| barrier-guards.rb:237:6:237:17 | ... == ... | barrier-guards.rb:239:20:239:22 | foo | no-match | +| barrier-guards.rb:238:1:238:26 | [match] when ... | barrier-guards.rb:238:24:238:26 | foo | match | +| barrier-guards.rb:238:1:238:26 | [no-match] when ... | barrier-guards.rb:239:1:239:22 | [match] when ... | no-match | +| barrier-guards.rb:238:1:238:26 | [no-match] when ... | barrier-guards.rb:239:1:239:22 | [no-match] when ... | no-match | +| barrier-guards.rb:238:1:238:26 | [no-match] when ... | barrier-guards.rb:239:6:239:8 | foo | no-match | +| barrier-guards.rb:238:1:238:26 | [no-match] when ... | barrier-guards.rb:239:20:239:22 | foo | no-match | +| barrier-guards.rb:238:6:238:17 | ... == ... | barrier-guards.rb:238:1:238:26 | [match] when ... | match | +| barrier-guards.rb:238:6:238:17 | ... == ... | barrier-guards.rb:238:1:238:26 | [no-match] when ... | no-match | +| barrier-guards.rb:238:6:238:17 | ... == ... | barrier-guards.rb:238:24:238:26 | foo | match | +| barrier-guards.rb:238:6:238:17 | ... == ... | barrier-guards.rb:239:1:239:22 | [match] when ... | no-match | +| barrier-guards.rb:238:6:238:17 | ... == ... | barrier-guards.rb:239:1:239:22 | [no-match] when ... | no-match | +| barrier-guards.rb:238:6:238:17 | ... == ... | barrier-guards.rb:239:6:239:8 | foo | no-match | +| barrier-guards.rb:238:6:238:17 | ... == ... | barrier-guards.rb:239:20:239:22 | foo | no-match | +| barrier-guards.rb:239:1:239:22 | [match] when ... | barrier-guards.rb:239:20:239:22 | foo | match | +| barrier-guards.rb:239:6:239:13 | ... == ... | barrier-guards.rb:239:1:239:22 | [match] when ... | match | +| barrier-guards.rb:239:6:239:13 | ... == ... | barrier-guards.rb:239:1:239:22 | [no-match] when ... | no-match | +| barrier-guards.rb:239:6:239:13 | ... == ... | barrier-guards.rb:239:20:239:22 | foo | match | | barrier-guards.rb:243:4:243:8 | "foo" | barrier-guards.rb:244:5:244:7 | foo | match | | barrier-guards.rb:243:4:243:8 | "foo" | barrier-guards.rb:245:1:246:7 | in ... then ... | no-match | | barrier-guards.rb:243:4:243:8 | "foo" | barrier-guards.rb:246:5:246:7 | foo | no-match | diff --git a/rust/ql/lib/CHANGELOG.md b/rust/ql/lib/CHANGELOG.md index 3651026d737..d0ffbecc504 100644 --- a/rust/ql/lib/CHANGELOG.md +++ b/rust/ql/lib/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.2.16 + +No user-facing changes. + ## 0.2.15 ### Minor Analysis Improvements diff --git a/rust/ql/lib/change-notes/released/0.2.16.md b/rust/ql/lib/change-notes/released/0.2.16.md new file mode 100644 index 00000000000..0e384109cab --- /dev/null +++ b/rust/ql/lib/change-notes/released/0.2.16.md @@ -0,0 +1,3 @@ +## 0.2.16 + +No user-facing changes. diff --git a/rust/ql/lib/codeql-pack.release.yml b/rust/ql/lib/codeql-pack.release.yml index 0f574e080e4..2aa64d9ed07 100644 --- a/rust/ql/lib/codeql-pack.release.yml +++ b/rust/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.2.15 +lastReleaseVersion: 0.2.16 diff --git a/rust/ql/lib/codeql/rust/security/LogInjectionExtensions.qll b/rust/ql/lib/codeql/rust/security/LogInjectionExtensions.qll index 40d11362355..e1fe3711ba6 100644 --- a/rust/ql/lib/codeql/rust/security/LogInjectionExtensions.qll +++ b/rust/ql/lib/codeql/rust/security/LogInjectionExtensions.qll @@ -8,7 +8,6 @@ private import codeql.rust.dataflow.DataFlow private import codeql.rust.dataflow.FlowBarrier private import codeql.rust.dataflow.FlowSink private import codeql.rust.Concepts -private import codeql.util.Unit private import codeql.rust.security.Barriers as Barriers /** diff --git a/rust/ql/lib/codeql/rust/security/SensitiveData.qll b/rust/ql/lib/codeql/rust/security/SensitiveData.qll index c4cd7c31366..c00d50ac590 100644 --- a/rust/ql/lib/codeql/rust/security/SensitiveData.qll +++ b/rust/ql/lib/codeql/rust/security/SensitiveData.qll @@ -53,7 +53,6 @@ private class SensitiveVariableAccess extends SensitiveData { HeuristicNames::nameIndicatesSensitiveData(this.asExpr() .(VariableAccess) .getVariable() - .(Variable) .getText(), classification) } diff --git a/rust/ql/lib/codeql/rust/security/SqlInjectionExtensions.qll b/rust/ql/lib/codeql/rust/security/SqlInjectionExtensions.qll index de2622974f6..8c18760820e 100644 --- a/rust/ql/lib/codeql/rust/security/SqlInjectionExtensions.qll +++ b/rust/ql/lib/codeql/rust/security/SqlInjectionExtensions.qll @@ -9,7 +9,6 @@ private import codeql.rust.dataflow.DataFlow private import codeql.rust.dataflow.FlowBarrier private import codeql.rust.dataflow.FlowSink private import codeql.rust.Concepts -private import codeql.util.Unit private import codeql.rust.security.Barriers as Barriers /** diff --git a/rust/ql/lib/codeql/rust/security/TaintedPathExtensions.qll b/rust/ql/lib/codeql/rust/security/TaintedPathExtensions.qll index 2bd009909f6..081afa0ff23 100644 --- a/rust/ql/lib/codeql/rust/security/TaintedPathExtensions.qll +++ b/rust/ql/lib/codeql/rust/security/TaintedPathExtensions.qll @@ -1,13 +1,9 @@ /** Provides classes and predicates to reason about path injection vulnerabilities. */ import rust -private import codeql.rust.controlflow.BasicBlocks -private import codeql.rust.controlflow.ControlFlowGraph private import codeql.rust.dataflow.DataFlow -private import codeql.rust.dataflow.TaintTracking private import codeql.rust.Concepts private import codeql.rust.dataflow.internal.DataFlowImpl -private import codeql.rust.controlflow.ControlFlowGraph as Cfg /** * Provides default sources, sinks and barriers for detecting path injection diff --git a/rust/ql/lib/codeql/rust/security/XssExtensions.qll b/rust/ql/lib/codeql/rust/security/XssExtensions.qll index 74ed161acb0..0920b88b3c3 100644 --- a/rust/ql/lib/codeql/rust/security/XssExtensions.qll +++ b/rust/ql/lib/codeql/rust/security/XssExtensions.qll @@ -8,7 +8,6 @@ private import codeql.rust.dataflow.DataFlow private import codeql.rust.dataflow.FlowBarrier private import codeql.rust.dataflow.FlowSink private import codeql.rust.Concepts -private import codeql.util.Unit private import codeql.rust.security.Barriers as Barriers /** diff --git a/rust/ql/lib/qlpack.yml b/rust/ql/lib/qlpack.yml index 931c069ad24..7750d2a6a3d 100644 --- a/rust/ql/lib/qlpack.yml +++ b/rust/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/rust-all -version: 0.2.16-dev +version: 0.2.17-dev groups: rust extractor: rust dbscheme: rust.dbscheme diff --git a/rust/ql/src/CHANGELOG.md b/rust/ql/src/CHANGELOG.md index 4f4807ff82e..5b50934a5fc 100644 --- a/rust/ql/src/CHANGELOG.md +++ b/rust/ql/src/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.1.37 + +No user-facing changes. + ## 0.1.36 No user-facing changes. diff --git a/rust/ql/src/change-notes/released/0.1.37.md b/rust/ql/src/change-notes/released/0.1.37.md new file mode 100644 index 00000000000..7e19340e948 --- /dev/null +++ b/rust/ql/src/change-notes/released/0.1.37.md @@ -0,0 +1,3 @@ +## 0.1.37 + +No user-facing changes. diff --git a/rust/ql/src/codeql-pack.release.yml b/rust/ql/src/codeql-pack.release.yml index 270bd27a7aa..38d6184e74c 100644 --- a/rust/ql/src/codeql-pack.release.yml +++ b/rust/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.1.36 +lastReleaseVersion: 0.1.37 diff --git a/rust/ql/src/qlpack.yml b/rust/ql/src/qlpack.yml index 9ba6302ecc0..591c913eb69 100644 --- a/rust/ql/src/qlpack.yml +++ b/rust/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/rust-queries -version: 0.1.37-dev +version: 0.1.38-dev groups: - rust - queries diff --git a/rust/ql/test/query-tests/security/CWE-327/WeakSensitiveDataHashing/CryptographicOperations.expected b/rust/ql/test/query-tests/security/CWE-327/WeakSensitiveDataHashing/CryptographicOperations.expected new file mode 100644 index 00000000000..a190d85cce9 --- /dev/null +++ b/rust/ql/test/query-tests/security/CWE-327/WeakSensitiveDataHashing/CryptographicOperations.expected @@ -0,0 +1,12 @@ +| test.rs:19:9:19:34 | ...::compute(...) | HashingAlgorithm MD5 WEAK inputs:1 | +| test.rs:20:9:20:40 | ...::compute(...) | HashingAlgorithm MD5 WEAK inputs:1 | +| test.rs:21:9:21:34 | ...::compute(...) | HashingAlgorithm MD5 WEAK inputs:1 | +| test.rs:22:9:22:44 | ...::compute(...) | HashingAlgorithm MD5 WEAK inputs:1 | +| test.rs:67:26:67:40 | ...::new(...) | HashingAlgorithm MD5 WEAK | +| test.rs:73:9:73:23 | ...::new(...) | HashingAlgorithm MD5 WEAK | +| test.rs:74:9:74:23 | ...::new(...) | HashingAlgorithm MD5 WEAK | +| test.rs:133:26:133:40 | ...::new(...) | HashingAlgorithm MD5 WEAK | +| test.rs:156:26:156:40 | ...::new(...) | HashingAlgorithm MD5 WEAK | +| test.rs:176:13:176:24 | ...::new(...) | EncryptionAlgorithm SEED | +| test.rs:199:22:199:32 | ...::new(...) | HashingAlgorithm SHA1 WEAK | +| test.rs:211:13:211:35 | ...::compute(...) | HashingAlgorithm MD5 WEAK inputs:1 | diff --git a/rust/ql/test/query-tests/security/CWE-327/WeakSensitiveDataHashing/CryptographicOperations.qlref b/rust/ql/test/query-tests/security/CWE-327/WeakSensitiveDataHashing/CryptographicOperations.qlref new file mode 100644 index 00000000000..a7941a724f7 --- /dev/null +++ b/rust/ql/test/query-tests/security/CWE-327/WeakSensitiveDataHashing/CryptographicOperations.qlref @@ -0,0 +1,3 @@ +query: queries/summary/CryptographicOperations.ql +postprocess: + - utils/test/InlineExpectationsTestQuery.ql diff --git a/rust/ql/test/query-tests/security/CWE-327/WeakSensitiveDataHashing/WeakSensitiveDataHashing.expected b/rust/ql/test/query-tests/security/CWE-327/WeakSensitiveDataHashing/WeakSensitiveDataHashing.expected index 2d4e7cd6e72..89078b7c4b9 100644 --- a/rust/ql/test/query-tests/security/CWE-327/WeakSensitiveDataHashing/WeakSensitiveDataHashing.expected +++ b/rust/ql/test/query-tests/security/CWE-327/WeakSensitiveDataHashing/WeakSensitiveDataHashing.expected @@ -1,9 +1,13 @@ #select | test.rs:20:9:20:24 | ...::compute | test.rs:20:26:20:39 | credit_card_no | test.rs:20:9:20:24 | ...::compute | $@ is used in a hashing algorithm (MD5) that is insecure. | test.rs:20:26:20:39 | credit_card_no | Sensitive data (private) | | test.rs:21:9:21:24 | ...::compute | test.rs:21:26:21:33 | password | test.rs:21:9:21:24 | ...::compute | $@ is used in a hashing algorithm (MD5) that is insecure for password hashing, since it is not a computationally expensive hash function. | test.rs:21:26:21:33 | password | Sensitive data (password) | +| test.rs:211:13:211:28 | ...::compute | test.rs:226:29:226:36 | password | test.rs:211:13:211:28 | ...::compute | $@ is used in a hashing algorithm (MD5) that is insecure for password hashing, since it is not a computationally expensive hash function. | test.rs:226:29:226:36 | password | Sensitive data (password) | edges | test.rs:20:26:20:39 | credit_card_no | test.rs:20:9:20:24 | ...::compute | provenance | MaD:1 Sink:MaD:1 | | test.rs:21:26:21:33 | password | test.rs:21:9:21:24 | ...::compute | provenance | MaD:1 Sink:MaD:1 | +| test.rs:210:20:210:30 | ...: ... | test.rs:211:30:211:34 | value | provenance | | +| test.rs:211:30:211:34 | value | test.rs:211:13:211:28 | ...::compute | provenance | MaD:1 Sink:MaD:1 | +| test.rs:226:29:226:36 | password | test.rs:210:20:210:30 | ...: ... | provenance | | models | 1 | Sink: md5::compute; Argument[0]; hasher-input | nodes @@ -11,4 +15,8 @@ nodes | test.rs:20:26:20:39 | credit_card_no | semmle.label | credit_card_no | | test.rs:21:9:21:24 | ...::compute | semmle.label | ...::compute | | test.rs:21:26:21:33 | password | semmle.label | password | +| test.rs:210:20:210:30 | ...: ... | semmle.label | ...: ... | +| test.rs:211:13:211:28 | ...::compute | semmle.label | ...::compute | +| test.rs:211:30:211:34 | value | semmle.label | value | +| test.rs:226:29:226:36 | password | semmle.label | password | subpaths diff --git a/rust/ql/test/query-tests/security/CWE-327/WeakSensitiveDataHashing/test.rs b/rust/ql/test/query-tests/security/CWE-327/WeakSensitiveDataHashing/test.rs index a7e17404df1..d6bdfb5bbdc 100644 --- a/rust/ql/test/query-tests/security/CWE-327/WeakSensitiveDataHashing/test.rs +++ b/rust/ql/test/query-tests/security/CWE-327/WeakSensitiveDataHashing/test.rs @@ -16,10 +16,10 @@ fn test_hash_algorithms( _ = md5::Md5::digest(encrypted_password); // MD5 (alternative / older library) - _ = md5_alt::compute(harmless); - _ = md5_alt::compute(credit_card_no); // $ Alert[rust/weak-sensitive-data-hashing] - _ = md5_alt::compute(password); // $ Alert[rust/weak-sensitive-data-hashing] - _ = md5_alt::compute(encrypted_password); + _ = md5_alt::compute(harmless); // $ Alert[rust/summary/cryptographic-operations] + _ = md5_alt::compute(credit_card_no); // $ Alert[rust/summary/cryptographic-operations] Alert[rust/weak-sensitive-data-hashing] + _ = md5_alt::compute(password); // $ Alert[rust/summary/cryptographic-operations] Alert[rust/weak-sensitive-data-hashing] + _ = md5_alt::compute(encrypted_password); // $ Alert[rust/summary/cryptographic-operations] // SHA-1 _ = sha1::Sha1::digest(harmless); @@ -64,14 +64,14 @@ fn test_hash_code_patterns( _ = md5::Md5::digest(password_vec); // $ MISSING: Alert[rust/weak-sensitive-data-hashing] // hash through a hasher object - let mut md5_hasher = md5::Md5::new(); + let mut md5_hasher = md5::Md5::new(); // $ Alert[rust/summary/cryptographic-operations] md5_hasher.update(b"abc"); md5_hasher.update(harmless); md5_hasher.update(password); // $ MISSING: Alert[rust/weak-sensitive-data-hashing] _ = md5_hasher.finalize(); - _ = md5::Md5::new().chain_update(harmless).chain_update(harmless).chain_update(harmless).finalize(); - _ = md5::Md5::new().chain_update(harmless).chain_update(password).chain_update(harmless).finalize(); // $ MISSING: Alert[rust/weak-sensitive-data-hashing] + _ = md5::Md5::new().chain_update(harmless).chain_update(harmless).chain_update(harmless).finalize(); // $ Alert[rust/summary/cryptographic-operations] + _ = md5::Md5::new().chain_update(harmless).chain_update(password).chain_update(harmless).finalize(); // $ Alert[rust/summary/cryptographic-operations] MISSING: Alert[rust/weak-sensitive-data-hashing] _ = md5::Md5::new_with_prefix(harmless).finalize(); _ = md5::Md5::new_with_prefix(password).finalize(); // $ MISSING: Alert[rust/weak-sensitive-data-hashing] @@ -130,7 +130,7 @@ fn test_hash_structs() { let str3c = serde_urlencoded::to_string(&s3).unwrap(); // hash with MD5 - let mut md5_hasher = md5::Md5::new(); + let mut md5_hasher = md5::Md5::new(); // $ Alert[rust/summary/cryptographic-operations] md5_hasher.update(s1.data); md5_hasher.update(s2.credit_card_no); // $ MISSING: Alert[rust/weak-sensitive-data-hashing] md5_hasher.update(s3.password); // $ MISSING: Alert[rust/weak-sensitive-data-hashing] @@ -153,8 +153,75 @@ fn test_hash_file( let mut harmless_file = std::fs::File::open(harmless_filename).unwrap(); let mut password_file = std::fs::File::open(password_filename).unwrap(); - let mut md5_hasher = md5::Md5::new(); + let mut md5_hasher = md5::Md5::new(); // $ Alert[rust/summary/cryptographic-operations] _ = std::io::copy(&mut harmless_file, &mut md5_hasher); _ = std::io::copy(&mut password_file, &mut md5_hasher); // $ MISSING: Alert[rust/weak-sensitive-data-hashing] _ = md5_hasher.finalize(); } + +// --- + +struct Seed { +} + +impl Seed { + fn new(_seed_value: u64) -> Self { + Seed { } + } +} + +fn test_seed() { + // this will be misrecognized as a use of the SEED algorithm, but SEED is strong and the input + // is not sensitive data, so `rust/weak-sensitive-data-hashing` should not report a result here. + let _ = Seed::new(0); // $ Alert[rust/summary/cryptographic-operations] +} + +// --- + +struct Sha1 { +} + +impl Sha1 { + const fn new() -> Self { + Sha1 { } + } + + const fn update(&mut self, _data: &[u8]) { + // ... + } + + const fn finalize(self) -> [u8; 20] { + [0; 20] + } +} + +fn sha1_test(password: &[u8]) { + let mut hasher = Sha1::new(); // $ Alert[rust/summary/cryptographic-operations] + hasher.update(password); // $ MISSING: Alert[rust/weak-sensitive-data-hashing] + _ = hasher.finalize(); +} + +// --- + +struct HashCollection { +} + +impl HashCollection { + pub fn add_sig(value: &str) -> Self { + _ = md5_alt::compute(value); // $ Alert[rust/summary/cryptographic-operations] Alert[rust/weak-sensitive-data-hashing] + + // ... + + HashCollection { } + } +} + +fn test_hash_collection() { + // this indirectly performs MD5 hashing, but the data is not sensitive + let id: &str = "my_id_1234567890"; + HashCollection::add_sig(id); + + // this indirectly performs MD5 hashing, and the data is sensitive; the result is reported here + let password: &str = "password123"; + HashCollection::add_sig(password); // $ Source +} diff --git a/shared/concepts/CHANGELOG.md b/shared/concepts/CHANGELOG.md index 787779674f0..5e5a0889e5d 100644 --- a/shared/concepts/CHANGELOG.md +++ b/shared/concepts/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.0.26 + +No user-facing changes. + ## 0.0.25 No user-facing changes. diff --git a/shared/concepts/change-notes/released/0.0.26.md b/shared/concepts/change-notes/released/0.0.26.md new file mode 100644 index 00000000000..e6dc680cc11 --- /dev/null +++ b/shared/concepts/change-notes/released/0.0.26.md @@ -0,0 +1,3 @@ +## 0.0.26 + +No user-facing changes. diff --git a/shared/concepts/codeql-pack.release.yml b/shared/concepts/codeql-pack.release.yml index 6d0e80a50c3..c576d2d7db2 100644 --- a/shared/concepts/codeql-pack.release.yml +++ b/shared/concepts/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.0.25 +lastReleaseVersion: 0.0.26 diff --git a/shared/concepts/qlpack.yml b/shared/concepts/qlpack.yml index dd1f0280e79..d8b7fb5b554 100644 --- a/shared/concepts/qlpack.yml +++ b/shared/concepts/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/concepts -version: 0.0.26-dev +version: 0.0.27-dev groups: shared library: true dependencies: diff --git a/shared/controlflow/CHANGELOG.md b/shared/controlflow/CHANGELOG.md index 8ac7faf2554..80735c7276d 100644 --- a/shared/controlflow/CHANGELOG.md +++ b/shared/controlflow/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.36 + +No user-facing changes. + ## 2.0.35 No user-facing changes. diff --git a/shared/controlflow/change-notes/released/2.0.36.md b/shared/controlflow/change-notes/released/2.0.36.md new file mode 100644 index 00000000000..8acdd12366e --- /dev/null +++ b/shared/controlflow/change-notes/released/2.0.36.md @@ -0,0 +1,3 @@ +## 2.0.36 + +No user-facing changes. diff --git a/shared/controlflow/codeql-pack.release.yml b/shared/controlflow/codeql-pack.release.yml index 27eb8ef8ece..7e4aaa0dd67 100644 --- a/shared/controlflow/codeql-pack.release.yml +++ b/shared/controlflow/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 2.0.35 +lastReleaseVersion: 2.0.36 diff --git a/shared/controlflow/codeql/controlflow/ControlFlowGraph.qll b/shared/controlflow/codeql/controlflow/ControlFlowGraph.qll index 522a416c768..2b5ae040284 100644 --- a/shared/controlflow/codeql/controlflow/ControlFlowGraph.qll +++ b/shared/controlflow/codeql/controlflow/ControlFlowGraph.qll @@ -52,6 +52,15 @@ signature module AstSig { /** A parameter of a callable. */ class Parameter extends AstNode { + /** + * Gets the pattern associated with this parameter. + * + * The pattern is included in the CFG while the parameter itself is not. + * Although, in simple cases that do not involve destructuring, it is + * allowed for the pattern to be equal to the parameter. + */ + AstNode getPattern(); + /** Gets the default value of this parameter, if any. */ Expr getDefaultValue(); } @@ -215,15 +224,33 @@ signature module AstSig { */ default AstNode getTryElse(TryStmt try) { none() } + /** + * Gets the `else` block of loop statement `loop`, if any. + * + * Only some languages (e.g. Python) support `for-else` constructs. + */ + default AstNode getLoopElse(LoopStmt loop) { none() } + /** A catch clause in a try statement. */ class CatchClause extends AstNode { - /** Gets the variable declared by this catch clause. */ + /** + * Gets the pattern matched by this catch clause, if any. + * + * A catch clause without a pattern is a catch-all that matches any exception. + */ + AstNode getPattern(); + + /** + * Gets the variable declared by this catch clause, if any. + * + * Some languages include the variable binding as part of the pattern. + */ AstNode getVariable(); /** Gets the guard condition of this catch clause, if any. */ Expr getCondition(); - /** Gets the body of this catch clause. */ + /** Gets the body of this catch clause, if any. */ Stmt getBody(); } @@ -495,7 +522,7 @@ module Make0 Ast> { default Parameter callableGetParameter(Callable c, CallableContext ctx, int index) { none() } /** Holds if catch clause `catch` catches all exceptions. */ - default predicate catchAll(CatchClause catch) { none() } + default predicate catchAll(CatchClause catch) { not exists(catch.getPattern()) } /** * Holds if case `c` matches all possible values, for example, if it is a @@ -627,11 +654,13 @@ module Make0 Ast> { ( n instanceof CatchClause or + n = any(CatchClause catch).getPattern() + or n instanceof Case or n = any(Case case).getPattern(_) or - exists(n.(Parameter).getDefaultValue()) + exists(Parameter p | exists(p.getDefaultValue()) and n = p.getPattern()) ) } @@ -649,6 +678,8 @@ module Make0 Ast> { not inConditionalContext(n, _) } + private string catchClauseEmptyBodyTag() { result = "[CatchClauseEmptyBody]" } + private string loopHeaderTag() { result = "[LoopHeader]" } private string patternMatchTrueTag() { result = "[MatchTrue]" } @@ -661,6 +692,13 @@ module Make0 Ast> { private predicate additionalNode(AstNode n, string tag, NormalSuccessor t) { Input1::additionalNode(n, tag, t) or + exists(CatchClause catch | + n = catch and + not exists(catch.getBody()) and + tag = catchClauseEmptyBodyTag() and + t instanceof DirectSuccessor + ) + or n instanceof LoopStmt and tag = loopHeaderTag() and t instanceof DirectSuccessor @@ -801,26 +839,35 @@ module Make0 Ast> { not exists(c.getPattern(i + 1)) and t.(MatchingSuccessor).getValue() = true ) + or + exists(CatchClause catch | + Input1::catchAll(catch) and + catch.getPattern() = n and + t.(MatchingSuccessor).getValue() = true + ) + } + + private predicate hasCfg(AstNode n) { + exists(getEnclosingCallable(n)) and + (n instanceof Parameter implies n = n.(Parameter).getPattern()) } cached private newtype TNode = - TBeforeNode(AstNode n) { Input1::cfgCachedStageRef() and exists(getEnclosingCallable(n)) } or - TAstNode(AstNode n) { postOrInOrder(n) and exists(getEnclosingCallable(n)) } or + TBeforeNode(AstNode n) { Input1::cfgCachedStageRef() and hasCfg(n) } or + TAstNode(AstNode n) { postOrInOrder(n) and hasCfg(n) } or TAfterValueNode(AstNode n, ConditionalSuccessor t) { inConditionalContext(n, t.getKind()) and - exists(getEnclosingCallable(n)) and + hasCfg(n) and not constantCondition(n, t.getDual()) } or TAfterNode(AstNode n) { - exists(getEnclosingCallable(n)) and + hasCfg(n) and not inConditionalContext(n, _) and not cannotTerminateNormally(n) and not simpleLeafNode(n) } or - TAdditionalNode(AstNode n, string tag) { - additionalNode(n, tag, _) and exists(getEnclosingCallable(n)) - } or + TAdditionalNode(AstNode n, string tag) { additionalNode(n, tag, _) and hasCfg(n) } or TEntryNode(Callable c) { callableHasBodyPart(c, _) } or TAnnotatedExitNode(Callable c, Boolean normal) { callableHasBodyPart(c, _) } or TExitNode(Callable c) { callableHasBodyPart(c, _) } @@ -1390,8 +1437,8 @@ module Make0 Ast> { } pragma[nomagic] - private AstNode getParameterOrBodyEntry(Callable c, CallableContextOption ctx, int i) { - result = getRankedParameter(c, ctx, i) + private AstNode getParameterPatternOrBodyEntry(Callable c, CallableContextOption ctx, int i) { + result = getRankedParameter(c, ctx, i).getPattern() or ( not exists(getRankedParameter(c, _, _)) and @@ -1403,24 +1450,36 @@ module Make0 Ast> { result = getBodyEntry(c, ctx) } + private PreControlFlowNode getBeforeCatchBody(CatchClause catch) { + if exists(catch.getBody()) + then result.isBefore(catch.getBody()) + else result.isAdditional(catch, catchClauseEmptyBodyTag()) + } + + private PreControlFlowNode getAfterCatchBody(CatchClause catch) { + if exists(catch.getBody()) + then result.isAfter(catch.getBody()) + else result.isAdditional(catch, catchClauseEmptyBodyTag()) + } + /** Holds if there is a local non-abrupt step from `n1` to `n2`. */ private predicate explicitStep(PreControlFlowNode n1, PreControlFlowNode n2) { Input2::step(n1, n2) or exists(Callable c | n1.(EntryNodeImpl).getEnclosingCallable() = c and - n2.isBefore(getParameterOrBodyEntry(c, _, 1)) + n2.isBefore(getParameterPatternOrBodyEntry(c, _, 1)) or exists(CallableContextOption ctx, Parameter p, int i | p = getRankedParameter(c, ctx, i) | exists(MatchingSuccessor t | - n1.isAfterValue(p, t) and + n1.isAfterValue(p.getPattern(), t) and if t.isMatch() - then n2.isBefore(getParameterOrBodyEntry(c, ctx, i + 1)) + then n2.isBefore(getParameterPatternOrBodyEntry(c, ctx, i + 1)) else n2.isBefore(p.getDefaultValue()) ) or n1.isAfter(p.getDefaultValue()) and - n2.isBefore(getParameterOrBodyEntry(c, ctx, i + 1)) + n2.isBefore(getParameterPatternOrBodyEntry(c, ctx, i + 1)) ) or exists(Input1::CallableContext ctx, int i | @@ -1566,19 +1625,32 @@ module Make0 Ast> { n2.isBefore(loopstmt.getBody()) or n1.isAfterValue(cond, any(BooleanSuccessor b | b.getValue() = while.booleanNot())) and - n2.isAfter(loopstmt) + ( + n2.isBefore(getLoopElse(loopstmt)) + or + not exists(getLoopElse(loopstmt)) and n2.isAfter(loopstmt) + ) or n1.isAfter(loopstmt.getBody()) and n2.isAdditional(loopstmt, loopHeaderTag()) ) or + exists(LoopStmt loopstmt | + n1.isAfter(getLoopElse(loopstmt)) and + n2.isAfter(loopstmt) + ) + or exists(ForeachStmt foreachstmt | n1.isBefore(foreachstmt) and n2.isBefore(foreachstmt.getCollection()) or n1.isAfterValue(foreachstmt.getCollection(), any(EmptinessSuccessor t | t.getValue() = true)) and - n2.isAfter(foreachstmt) + ( + n2.isBefore(getLoopElse(foreachstmt)) + or + not exists(getLoopElse(foreachstmt)) and n2.isAfter(foreachstmt) + ) or n1.isAfterValue(foreachstmt.getCollection(), any(EmptinessSuccessor t | t.getValue() = false)) and @@ -1591,7 +1663,11 @@ module Make0 Ast> { n2.isAdditional(foreachstmt, loopHeaderTag()) or n1.isAdditional(foreachstmt, loopHeaderTag()) and - n2.isAfter(foreachstmt) + ( + n2.isBefore(getLoopElse(foreachstmt)) + or + not exists(getLoopElse(foreachstmt)) and n2.isAfter(foreachstmt) + ) or n1.isAdditional(foreachstmt, loopHeaderTag()) and n2.isBefore(foreachstmt.getVariable()) @@ -1670,7 +1746,7 @@ module Make0 Ast> { n1.isAfter(getTryElse(trystmt)) and n2 = beforeFinally or - n1.isAfter(trystmt.getCatch(_).getBody()) and + n1 = getAfterCatchBody(trystmt.getCatch(_)) and n2 = beforeFinally ) or @@ -1684,13 +1760,15 @@ module Make0 Ast> { ) or exists(CatchClause catchclause | - exists(MatchingSuccessor t | - n1.isBefore(catchclause) and - n2.isAfterValue(catchclause, t) and - if Input1::catchAll(catchclause) then t.getValue() = true else any() - ) - or - exists(PreControlFlowNode beforeVar, PreControlFlowNode beforeCond | + exists( + PreControlFlowNode beforePattern, PreControlFlowNode beforeVar, + PreControlFlowNode beforeCond + | + ( + beforePattern.isBefore(catchclause.getPattern()) + or + not exists(catchclause.getPattern()) and beforePattern = beforeVar + ) and ( beforeVar.isBefore(catchclause.getVariable()) or @@ -1699,9 +1777,18 @@ module Make0 Ast> { ( beforeCond.isBefore(catchclause.getCondition()) or - not exists(catchclause.getCondition()) and beforeCond.isBefore(catchclause.getBody()) + not exists(catchclause.getCondition()) and + beforeCond = getBeforeCatchBody(catchclause) ) | + n1.isBefore(catchclause) and + n2 = beforePattern + or + exists(MatchingSuccessor t | + n1.isAfterValue(catchclause.getPattern(), t) and + if t.isMatch() then n2 = beforeVar else n2.isAfterValue(catchclause, t) + ) + or n1.isAfterValue(catchclause, any(MatchingSuccessor t | t.getValue() = true)) and n2 = beforeVar or @@ -1710,7 +1797,7 @@ module Make0 Ast> { ) or n1.isAfterTrue(catchclause.getCondition()) and - n2.isBefore(catchclause.getBody()) + n2 = getBeforeCatchBody(catchclause) or n1.isAfterFalse(catchclause.getCondition()) and n2.isAfterValue(catchclause, any(MatchingSuccessor t | t.getValue() = false)) @@ -1796,6 +1883,7 @@ module Make0 Ast> { * and therefore should use default left-to-right evaluation. */ private predicate defaultCfg(AstNode ast) { + hasCfg(ast) and not explicitStep(any(PreControlFlowNode n | n.isBefore(ast)), _) } diff --git a/shared/controlflow/qlpack.yml b/shared/controlflow/qlpack.yml index b3518003b24..d14ee7d34d7 100644 --- a/shared/controlflow/qlpack.yml +++ b/shared/controlflow/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/controlflow -version: 2.0.36-dev +version: 2.0.37-dev groups: shared library: true dependencies: diff --git a/shared/dataflow/CHANGELOG.md b/shared/dataflow/CHANGELOG.md index b2cf75110ac..a1074cfcebb 100644 --- a/shared/dataflow/CHANGELOG.md +++ b/shared/dataflow/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.1.8 + +No user-facing changes. + ## 2.1.7 No user-facing changes. diff --git a/shared/dataflow/change-notes/released/2.1.8.md b/shared/dataflow/change-notes/released/2.1.8.md new file mode 100644 index 00000000000..81d5b413ddf --- /dev/null +++ b/shared/dataflow/change-notes/released/2.1.8.md @@ -0,0 +1,3 @@ +## 2.1.8 + +No user-facing changes. diff --git a/shared/dataflow/codeql-pack.release.yml b/shared/dataflow/codeql-pack.release.yml index cfa57a47251..93b985f46e1 100644 --- a/shared/dataflow/codeql-pack.release.yml +++ b/shared/dataflow/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 2.1.7 +lastReleaseVersion: 2.1.8 diff --git a/shared/dataflow/qlpack.yml b/shared/dataflow/qlpack.yml index cdce161af7e..ae047432fc5 100644 --- a/shared/dataflow/qlpack.yml +++ b/shared/dataflow/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/dataflow -version: 2.1.8-dev +version: 2.1.9-dev groups: shared library: true dependencies: diff --git a/shared/mad/CHANGELOG.md b/shared/mad/CHANGELOG.md index 6619a18079c..08494880152 100644 --- a/shared/mad/CHANGELOG.md +++ b/shared/mad/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.52 + +No user-facing changes. + ## 1.0.51 No user-facing changes. diff --git a/shared/mad/change-notes/released/1.0.52.md b/shared/mad/change-notes/released/1.0.52.md new file mode 100644 index 00000000000..a91f5a8025d --- /dev/null +++ b/shared/mad/change-notes/released/1.0.52.md @@ -0,0 +1,3 @@ +## 1.0.52 + +No user-facing changes. diff --git a/shared/mad/codeql-pack.release.yml b/shared/mad/codeql-pack.release.yml index 232dbe38ec8..ea1d2eed4d2 100644 --- a/shared/mad/codeql-pack.release.yml +++ b/shared/mad/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.0.51 +lastReleaseVersion: 1.0.52 diff --git a/shared/mad/qlpack.yml b/shared/mad/qlpack.yml index 21a06e7cc4d..066ccfdf771 100644 --- a/shared/mad/qlpack.yml +++ b/shared/mad/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/mad -version: 1.0.52-dev +version: 1.0.53-dev groups: shared library: true dependencies: diff --git a/shared/namebinding/CHANGELOG.md b/shared/namebinding/CHANGELOG.md new file mode 100644 index 00000000000..59b60bad0f3 --- /dev/null +++ b/shared/namebinding/CHANGELOG.md @@ -0,0 +1,3 @@ +## 0.0.1 + +No user-facing changes. diff --git a/shared/namebinding/change-notes/released/0.0.1.md b/shared/namebinding/change-notes/released/0.0.1.md new file mode 100644 index 00000000000..59b60bad0f3 --- /dev/null +++ b/shared/namebinding/change-notes/released/0.0.1.md @@ -0,0 +1,3 @@ +## 0.0.1 + +No user-facing changes. diff --git a/shared/namebinding/codeql-pack.release.yml b/shared/namebinding/codeql-pack.release.yml new file mode 100644 index 00000000000..c6933410b71 --- /dev/null +++ b/shared/namebinding/codeql-pack.release.yml @@ -0,0 +1,2 @@ +--- +lastReleaseVersion: 0.0.1 diff --git a/shared/namebinding/qlpack.yml b/shared/namebinding/qlpack.yml index 1bd12ee05dd..15876b50208 100644 --- a/shared/namebinding/qlpack.yml +++ b/shared/namebinding/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/namebinding -version: 0.0.1-dev +version: 0.0.2-dev groups: shared library: true dependencies: diff --git a/shared/quantum/CHANGELOG.md b/shared/quantum/CHANGELOG.md index c8b656e4f35..1652285654a 100644 --- a/shared/quantum/CHANGELOG.md +++ b/shared/quantum/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.0.30 + +No user-facing changes. + ## 0.0.29 No user-facing changes. diff --git a/shared/quantum/change-notes/released/0.0.30.md b/shared/quantum/change-notes/released/0.0.30.md new file mode 100644 index 00000000000..10c7a0c5c13 --- /dev/null +++ b/shared/quantum/change-notes/released/0.0.30.md @@ -0,0 +1,3 @@ +## 0.0.30 + +No user-facing changes. diff --git a/shared/quantum/codeql-pack.release.yml b/shared/quantum/codeql-pack.release.yml index c81f1813120..0c61b463bab 100644 --- a/shared/quantum/codeql-pack.release.yml +++ b/shared/quantum/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.0.29 +lastReleaseVersion: 0.0.30 diff --git a/shared/quantum/qlpack.yml b/shared/quantum/qlpack.yml index c430e4a69be..546491e0768 100644 --- a/shared/quantum/qlpack.yml +++ b/shared/quantum/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/quantum -version: 0.0.30-dev +version: 0.0.31-dev groups: shared library: true dependencies: diff --git a/shared/rangeanalysis/CHANGELOG.md b/shared/rangeanalysis/CHANGELOG.md index a400a91f8c9..cc127126c92 100644 --- a/shared/rangeanalysis/CHANGELOG.md +++ b/shared/rangeanalysis/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.52 + +No user-facing changes. + ## 1.0.51 No user-facing changes. diff --git a/shared/rangeanalysis/change-notes/released/1.0.52.md b/shared/rangeanalysis/change-notes/released/1.0.52.md new file mode 100644 index 00000000000..a91f5a8025d --- /dev/null +++ b/shared/rangeanalysis/change-notes/released/1.0.52.md @@ -0,0 +1,3 @@ +## 1.0.52 + +No user-facing changes. diff --git a/shared/rangeanalysis/codeql-pack.release.yml b/shared/rangeanalysis/codeql-pack.release.yml index 232dbe38ec8..ea1d2eed4d2 100644 --- a/shared/rangeanalysis/codeql-pack.release.yml +++ b/shared/rangeanalysis/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.0.51 +lastReleaseVersion: 1.0.52 diff --git a/shared/rangeanalysis/qlpack.yml b/shared/rangeanalysis/qlpack.yml index 7cecb52325f..cda17399a57 100644 --- a/shared/rangeanalysis/qlpack.yml +++ b/shared/rangeanalysis/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/rangeanalysis -version: 1.0.52-dev +version: 1.0.53-dev groups: shared library: true dependencies: diff --git a/shared/regex/CHANGELOG.md b/shared/regex/CHANGELOG.md index c4b7fc6e87f..488896015d6 100644 --- a/shared/regex/CHANGELOG.md +++ b/shared/regex/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.52 + +No user-facing changes. + ## 1.0.51 No user-facing changes. diff --git a/shared/regex/change-notes/released/1.0.52.md b/shared/regex/change-notes/released/1.0.52.md new file mode 100644 index 00000000000..a91f5a8025d --- /dev/null +++ b/shared/regex/change-notes/released/1.0.52.md @@ -0,0 +1,3 @@ +## 1.0.52 + +No user-facing changes. diff --git a/shared/regex/codeql-pack.release.yml b/shared/regex/codeql-pack.release.yml index 232dbe38ec8..ea1d2eed4d2 100644 --- a/shared/regex/codeql-pack.release.yml +++ b/shared/regex/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.0.51 +lastReleaseVersion: 1.0.52 diff --git a/shared/regex/qlpack.yml b/shared/regex/qlpack.yml index a1ec511b126..de6b49e8483 100644 --- a/shared/regex/qlpack.yml +++ b/shared/regex/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/regex -version: 1.0.52-dev +version: 1.0.53-dev groups: shared library: true dependencies: diff --git a/shared/ssa/CHANGELOG.md b/shared/ssa/CHANGELOG.md index 9cfe68398b2..2348e9a484f 100644 --- a/shared/ssa/CHANGELOG.md +++ b/shared/ssa/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.28 + +No user-facing changes. + ## 2.0.27 No user-facing changes. diff --git a/shared/ssa/change-notes/released/2.0.28.md b/shared/ssa/change-notes/released/2.0.28.md new file mode 100644 index 00000000000..3f9412b6e63 --- /dev/null +++ b/shared/ssa/change-notes/released/2.0.28.md @@ -0,0 +1,3 @@ +## 2.0.28 + +No user-facing changes. diff --git a/shared/ssa/codeql-pack.release.yml b/shared/ssa/codeql-pack.release.yml index a047558f018..ec5bd6ba369 100644 --- a/shared/ssa/codeql-pack.release.yml +++ b/shared/ssa/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 2.0.27 +lastReleaseVersion: 2.0.28 diff --git a/shared/ssa/codeql/ssa/Ssa.qll b/shared/ssa/codeql/ssa/Ssa.qll index 861f797ed6d..b8fe058bc0f 100644 --- a/shared/ssa/codeql/ssa/Ssa.qll +++ b/shared/ssa/codeql/ssa/Ssa.qll @@ -993,6 +993,11 @@ module Make< predicate explicitWrite(VariableWrite w, BasicBlock bb, int i, SourceVariable v); } + /** + * Builds the user-facing SSA API (the `SsaSig` class hierarchy and associated + * predicates) on top of the core SSA construction, using the language-specific + * expressions, parameters, and writes provided by `SsaInput`. + */ module MakeSsa implements SsaSig { diff --git a/shared/ssa/qlpack.yml b/shared/ssa/qlpack.yml index 9c14b9e6469..67bed21c679 100644 --- a/shared/ssa/qlpack.yml +++ b/shared/ssa/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/ssa -version: 2.0.28-dev +version: 2.0.29-dev groups: shared library: true dependencies: diff --git a/shared/threat-models/CHANGELOG.md b/shared/threat-models/CHANGELOG.md index 14258018aea..1b79dbf69e2 100644 --- a/shared/threat-models/CHANGELOG.md +++ b/shared/threat-models/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.52 + +No user-facing changes. + ## 1.0.51 No user-facing changes. diff --git a/shared/threat-models/change-notes/released/1.0.52.md b/shared/threat-models/change-notes/released/1.0.52.md new file mode 100644 index 00000000000..a91f5a8025d --- /dev/null +++ b/shared/threat-models/change-notes/released/1.0.52.md @@ -0,0 +1,3 @@ +## 1.0.52 + +No user-facing changes. diff --git a/shared/threat-models/codeql-pack.release.yml b/shared/threat-models/codeql-pack.release.yml index 232dbe38ec8..ea1d2eed4d2 100644 --- a/shared/threat-models/codeql-pack.release.yml +++ b/shared/threat-models/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.0.51 +lastReleaseVersion: 1.0.52 diff --git a/shared/threat-models/qlpack.yml b/shared/threat-models/qlpack.yml index c7326273c65..9dd6aaa670a 100644 --- a/shared/threat-models/qlpack.yml +++ b/shared/threat-models/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/threat-models -version: 1.0.52-dev +version: 1.0.53-dev library: true groups: shared dataExtensions: diff --git a/shared/tree-sitter-extractor/src/extractor/mod.rs b/shared/tree-sitter-extractor/src/extractor/mod.rs index 436ff9f65a1..b066fbc85b3 100644 --- a/shared/tree-sitter-extractor/src/extractor/mod.rs +++ b/shared/tree-sitter-extractor/src/extractor/mod.rs @@ -280,10 +280,11 @@ pub fn location_label(writer: &mut trap::Writer, location: trap::Location) -> tr } /// Extracts the source file at `path`, which is assumed to be canonicalized. -/// When `yeast_runner` is `Some`, the parsed tree is first transformed -/// through the supplied yeast `Runner` before TRAP extraction. Building the -/// `Runner` (which parses YAML and constructs the schema) is the caller's -/// responsibility, allowing it to be done once and shared across files. +/// When `desugarer` is `Some`, the parsed tree is first transformed +/// through the supplied yeast desugarer before TRAP extraction. Building +/// the desugarer (which parses YAML and constructs the schema) is the +/// caller's responsibility, allowing it to be done once and shared across +/// files. #[allow(clippy::too_many_arguments)] pub fn extract( language: &Language, @@ -295,7 +296,7 @@ pub fn extract( path: &Path, source: &[u8], ranges: &[Range], - yeast_runner: Option<&yeast::Runner<'_>>, + desugarer: Option<&dyn yeast::Desugarer>, ) { let path_str = file_paths::normalize_and_transform_path(path, transformer); let source_root = std::env::current_dir() @@ -328,8 +329,8 @@ pub fn extract( schema, ); - if let Some(yeast_runner) = yeast_runner { - let ast = yeast_runner + if let Some(desugarer) = desugarer { + let ast = desugarer .run_from_tree(&tree, source) .unwrap_or_else(|e| panic!("Desugaring failed for {path_str}: {e}")); traverse_yeast(&ast, &mut visitor); diff --git a/shared/tree-sitter-extractor/src/extractor/simple.rs b/shared/tree-sitter-extractor/src/extractor/simple.rs index 6fcd29b0344..9ba6f21778c 100644 --- a/shared/tree-sitter-extractor/src/extractor/simple.rs +++ b/shared/tree-sitter-extractor/src/extractor/simple.rs @@ -13,11 +13,14 @@ pub struct LanguageSpec { pub prefix: &'static str, pub ts_language: tree_sitter::Language, pub node_types: &'static str, - /// Optional yeast desugaring configuration. When set, the parsed - /// tree is rewritten through yeast before TRAP extraction. The - /// config's `output_node_types_yaml` (if set) provides the schema - /// used both at runtime (for the rewriter) and for TRAP validation. - pub desugar: Option, + /// Optional desugarer. When set, the parsed tree is rewritten through + /// the desugarer before TRAP extraction. The desugarer's + /// `output_node_types_yaml()` (if set) provides the schema used both + /// at runtime (for the rewriter) and for TRAP validation. + /// + /// `Box` so the shared extractor is agnostic to + /// the user-defined context type the desugarer uses internally. + pub desugar: Option>, pub file_globs: Vec, } @@ -91,35 +94,22 @@ impl Extractor { .collect(); let mut schemas = vec![]; - let mut yeast_runners = Vec::new(); for lang in &self.languages { - let effective_node_types: String = - match lang.desugar.as_ref().and_then(|c| c.output_node_types_yaml) { - Some(yaml) => yeast::node_types_yaml::convert(yaml).map_err(|e| { - std::io::Error::other(format!( - "Failed to convert YAML node-types to JSON for {}: {e}", - lang.prefix - )) - })?, - None => lang.node_types.to_string(), - }; - let schema = node_types::read_node_types_str(lang.prefix, &effective_node_types)?; - schemas.push(schema); - - // Build the yeast runner once per language so the YAML schema - // isn't re-parsed for every file. - let yeast_runner = lang + let effective_node_types: String = match lang .desugar .as_ref() - .map(|config| yeast::Runner::from_config(lang.ts_language.clone(), config)) - .transpose() - .map_err(|e| { + .and_then(|d| d.output_node_types_yaml()) + { + Some(yaml) => yeast::node_types_yaml::convert(yaml).map_err(|e| { std::io::Error::other(format!( - "Failed to build desugaring runner for {}: {e}", + "Failed to convert YAML node-types to JSON for {}: {e}", lang.prefix )) - })?; - yeast_runners.push(yeast_runner); + })?, + None => lang.node_types.to_string(), + }; + let schema = node_types::read_node_types_str(lang.prefix, &effective_node_types)?; + schemas.push(schema); } // Construct a single globset containing all language globs, @@ -194,7 +184,7 @@ impl Extractor { &path, &source, &[], - yeast_runners[i].as_ref(), + lang.desugar.as_deref(), ); std::fs::create_dir_all(src_archive_file.parent().unwrap())?; std::fs::copy(&path, &src_archive_file)?; diff --git a/shared/tree-sitter-extractor/src/generator/mod.rs b/shared/tree-sitter-extractor/src/generator/mod.rs index d3880a74579..6c5fbfabda6 100644 --- a/shared/tree-sitter-extractor/src/generator/mod.rs +++ b/shared/tree-sitter-extractor/src/generator/mod.rs @@ -159,6 +159,7 @@ pub fn generate( )); body.append(&mut ql_gen::convert_nodes(&nodes)); + body.push(ql_gen::create_print_ast_module(&nodes)); ql::write( &mut ql_writer, &[ql::TopLevel::Module(ql::Module { diff --git a/shared/tree-sitter-extractor/src/generator/ql.rs b/shared/tree-sitter-extractor/src/generator/ql.rs index cdfe5d8c639..24ae25d854b 100644 --- a/shared/tree-sitter-extractor/src/generator/ql.rs +++ b/shared/tree-sitter-extractor/src/generator/ql.rs @@ -150,12 +150,14 @@ impl fmt::Display for Type<'_> { pub enum Expression<'a> { Var(&'a str), String(&'a str), - Integer(usize), + Integer(i64), Pred(&'a str, Vec>), And(Vec>), Or(Vec>), Equals(Box>, Box>), Dot(Box>, &'a str, Vec>), + /// A type cast, rendered as `x.(Type)`. + Cast(Box>, &'a str), Aggregate { name: &'a str, vars: Vec>, @@ -219,6 +221,7 @@ impl fmt::Display for Expression<'_> { } write!(f, ")") } + Expression::Cast(x, type_name) => write!(f, "{x}.({type_name})"), Expression::Aggregate { name, vars, diff --git a/shared/tree-sitter-extractor/src/generator/ql_gen.rs b/shared/tree-sitter-extractor/src/generator/ql_gen.rs index f827b12580e..bfefdadeaf7 100644 --- a/shared/tree-sitter-extractor/src/generator/ql_gen.rs +++ b/shared/tree-sitter-extractor/src/generator/ql_gen.rs @@ -705,7 +705,7 @@ fn create_field_getters<'a>( ), ql::Expression::Equals( Box::new(ql::Expression::Var("value")), - Box::new(ql::Expression::Integer(*value)), + Box::new(ql::Expression::Integer(*value as i64)), ), ]) }) @@ -874,3 +874,99 @@ pub fn convert_nodes(nodes: &node_types::NodeTypeMap) -> Vec> { classes } + +/// Creates a `PrintAst` module containing a `getChild` predicate that maps each +/// AST node to its children together with the name of the member predicate that +/// produced them (and, for indexed fields, the index). This mirrors the +/// information exposed by `getAFieldOrChild`, but keeps the member predicate +/// name and index so that an AST printer can render labelled edges. +pub fn create_print_ast_module(nodes: &node_types::NodeTypeMap) -> ql::TopLevel<'_> { + let mut disjuncts: Vec = Vec::new(); + for node in nodes.values() { + if let node_types::EntryKind::Table { name: _, fields } = &node.kind { + for field in fields { + // `ReservedWordInt` fields have string-valued getters, so they + // are not children and are excluded (just as they are from + // `getAFieldOrChild`). + if matches!( + field.type_info, + node_types::FieldTypeInfo::ReservedWordInt(_) + ) { + continue; + } + let has_index = matches!( + field.storage, + node_types::Storage::Table { + has_index: true, + .. + } + ); + let getter_call = ql::Expression::Dot( + Box::new(ql::Expression::Cast( + Box::new(ql::Expression::Var("node")), + &node.ql_class_name, + )), + &field.getter_name, + if has_index { + vec![ql::Expression::Var("i")] + } else { + vec![] + }, + ); + let mut conjuncts = vec![ql::Expression::Equals( + Box::new(ql::Expression::Var("result")), + Box::new(getter_call), + )]; + if !has_index { + conjuncts.push(ql::Expression::Equals( + Box::new(ql::Expression::Var("i")), + Box::new(ql::Expression::Integer(-1)), + )); + } + conjuncts.push(ql::Expression::Equals( + Box::new(ql::Expression::Var("name")), + Box::new(ql::Expression::String(&field.getter_name)), + )); + disjuncts.push(ql::Expression::And(conjuncts)); + } + } + } + + let get_child = ql::Predicate { + qldoc: Some(String::from( + "Gets a child of `node` returned by the member predicate with the given `name`. \ + If the predicate takes an index argument, `i` is bound to that index, otherwise \ + `i` is `-1` (which is never a valid index).", + )), + name: "getChild", + overridden: false, + is_private: false, + is_final: false, + return_type: Some(ql::Type::Normal("AstNode")), + formal_parameters: vec![ + ql::FormalParameter { + name: "node", + param_type: ql::Type::Normal("AstNode"), + }, + ql::FormalParameter { + name: "name", + param_type: ql::Type::String, + }, + ql::FormalParameter { + name: "i", + param_type: ql::Type::Int, + }, + ], + body: ql::Expression::Or(disjuncts), + overlay: None, + }; + + ql::TopLevel::Module(ql::Module { + qldoc: Some(String::from( + "Provides predicates for mapping AST nodes to their named children.", + )), + name: "PrintAst", + body: vec![ql::TopLevel::Predicate(get_child)], + overlay: None, + }) +} diff --git a/shared/tutorial/CHANGELOG.md b/shared/tutorial/CHANGELOG.md index 9e78286a1a4..cb1a4642f73 100644 --- a/shared/tutorial/CHANGELOG.md +++ b/shared/tutorial/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.52 + +No user-facing changes. + ## 1.0.51 No user-facing changes. diff --git a/shared/tutorial/change-notes/released/1.0.52.md b/shared/tutorial/change-notes/released/1.0.52.md new file mode 100644 index 00000000000..a91f5a8025d --- /dev/null +++ b/shared/tutorial/change-notes/released/1.0.52.md @@ -0,0 +1,3 @@ +## 1.0.52 + +No user-facing changes. diff --git a/shared/tutorial/codeql-pack.release.yml b/shared/tutorial/codeql-pack.release.yml index 232dbe38ec8..ea1d2eed4d2 100644 --- a/shared/tutorial/codeql-pack.release.yml +++ b/shared/tutorial/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.0.51 +lastReleaseVersion: 1.0.52 diff --git a/shared/tutorial/qlpack.yml b/shared/tutorial/qlpack.yml index bb6eeeb2460..db557278bd8 100644 --- a/shared/tutorial/qlpack.yml +++ b/shared/tutorial/qlpack.yml @@ -1,7 +1,7 @@ name: codeql/tutorial description: Library for the CodeQL detective tutorials, helping new users learn to write CodeQL queries. -version: 1.0.52-dev +version: 1.0.53-dev groups: shared library: true warnOnImplicitThis: true diff --git a/shared/typeflow/CHANGELOG.md b/shared/typeflow/CHANGELOG.md index e9334c9da8d..6e1c15f6a2a 100644 --- a/shared/typeflow/CHANGELOG.md +++ b/shared/typeflow/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.52 + +No user-facing changes. + ## 1.0.51 No user-facing changes. diff --git a/shared/typeflow/change-notes/released/1.0.52.md b/shared/typeflow/change-notes/released/1.0.52.md new file mode 100644 index 00000000000..a91f5a8025d --- /dev/null +++ b/shared/typeflow/change-notes/released/1.0.52.md @@ -0,0 +1,3 @@ +## 1.0.52 + +No user-facing changes. diff --git a/shared/typeflow/codeql-pack.release.yml b/shared/typeflow/codeql-pack.release.yml index 232dbe38ec8..ea1d2eed4d2 100644 --- a/shared/typeflow/codeql-pack.release.yml +++ b/shared/typeflow/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.0.51 +lastReleaseVersion: 1.0.52 diff --git a/shared/typeflow/qlpack.yml b/shared/typeflow/qlpack.yml index 9790bbcaeae..3e904af63e3 100644 --- a/shared/typeflow/qlpack.yml +++ b/shared/typeflow/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/typeflow -version: 1.0.52-dev +version: 1.0.53-dev groups: shared library: true dependencies: diff --git a/shared/typeinference/CHANGELOG.md b/shared/typeinference/CHANGELOG.md index 24dc81f3aa2..66b8fa3444b 100644 --- a/shared/typeinference/CHANGELOG.md +++ b/shared/typeinference/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.0.33 + +No user-facing changes. + ## 0.0.32 No user-facing changes. diff --git a/shared/typeinference/change-notes/released/0.0.33.md b/shared/typeinference/change-notes/released/0.0.33.md new file mode 100644 index 00000000000..0b46f1130fa --- /dev/null +++ b/shared/typeinference/change-notes/released/0.0.33.md @@ -0,0 +1,3 @@ +## 0.0.33 + +No user-facing changes. diff --git a/shared/typeinference/codeql-pack.release.yml b/shared/typeinference/codeql-pack.release.yml index 714fcfc1828..dff9e7f6ea9 100644 --- a/shared/typeinference/codeql-pack.release.yml +++ b/shared/typeinference/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.0.32 +lastReleaseVersion: 0.0.33 diff --git a/shared/typeinference/qlpack.yml b/shared/typeinference/qlpack.yml index ab43c330dcc..f25557f4f13 100644 --- a/shared/typeinference/qlpack.yml +++ b/shared/typeinference/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/typeinference -version: 0.0.33-dev +version: 0.0.34-dev groups: shared library: true dependencies: diff --git a/shared/typetracking/CHANGELOG.md b/shared/typetracking/CHANGELOG.md index e9b5492b0d8..8a7f7ab7014 100644 --- a/shared/typetracking/CHANGELOG.md +++ b/shared/typetracking/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.36 + +No user-facing changes. + ## 2.0.35 No user-facing changes. diff --git a/shared/typetracking/change-notes/released/2.0.36.md b/shared/typetracking/change-notes/released/2.0.36.md new file mode 100644 index 00000000000..8acdd12366e --- /dev/null +++ b/shared/typetracking/change-notes/released/2.0.36.md @@ -0,0 +1,3 @@ +## 2.0.36 + +No user-facing changes. diff --git a/shared/typetracking/codeql-pack.release.yml b/shared/typetracking/codeql-pack.release.yml index 27eb8ef8ece..7e4aaa0dd67 100644 --- a/shared/typetracking/codeql-pack.release.yml +++ b/shared/typetracking/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 2.0.35 +lastReleaseVersion: 2.0.36 diff --git a/shared/typetracking/qlpack.yml b/shared/typetracking/qlpack.yml index de6ff4c16c9..fd9fa8ec813 100644 --- a/shared/typetracking/qlpack.yml +++ b/shared/typetracking/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/typetracking -version: 2.0.36-dev +version: 2.0.37-dev groups: shared library: true dependencies: diff --git a/shared/typos/CHANGELOG.md b/shared/typos/CHANGELOG.md index dbafbea9b98..738e64b021c 100644 --- a/shared/typos/CHANGELOG.md +++ b/shared/typos/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.52 + +No user-facing changes. + ## 1.0.51 No user-facing changes. diff --git a/shared/typos/change-notes/released/1.0.52.md b/shared/typos/change-notes/released/1.0.52.md new file mode 100644 index 00000000000..a91f5a8025d --- /dev/null +++ b/shared/typos/change-notes/released/1.0.52.md @@ -0,0 +1,3 @@ +## 1.0.52 + +No user-facing changes. diff --git a/shared/typos/codeql-pack.release.yml b/shared/typos/codeql-pack.release.yml index 232dbe38ec8..ea1d2eed4d2 100644 --- a/shared/typos/codeql-pack.release.yml +++ b/shared/typos/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.0.51 +lastReleaseVersion: 1.0.52 diff --git a/shared/typos/qlpack.yml b/shared/typos/qlpack.yml index 0b6aee6fd1c..9e8d3b21c01 100644 --- a/shared/typos/qlpack.yml +++ b/shared/typos/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/typos -version: 1.0.52-dev +version: 1.0.53-dev groups: shared library: true warnOnImplicitThis: true diff --git a/shared/util/CHANGELOG.md b/shared/util/CHANGELOG.md index df741ed9d73..10b02218c5f 100644 --- a/shared/util/CHANGELOG.md +++ b/shared/util/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.39 + +No user-facing changes. + ## 2.0.38 No user-facing changes. diff --git a/shared/util/change-notes/released/2.0.39.md b/shared/util/change-notes/released/2.0.39.md new file mode 100644 index 00000000000..887d030df42 --- /dev/null +++ b/shared/util/change-notes/released/2.0.39.md @@ -0,0 +1,3 @@ +## 2.0.39 + +No user-facing changes. diff --git a/shared/util/codeql-pack.release.yml b/shared/util/codeql-pack.release.yml index 4ec9eb0980c..063a268e5f9 100644 --- a/shared/util/codeql-pack.release.yml +++ b/shared/util/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 2.0.38 +lastReleaseVersion: 2.0.39 diff --git a/shared/util/codeql/util/test/InlineExpectationsTest.qll b/shared/util/codeql/util/test/InlineExpectationsTest.qll index e785adda456..4e0b2f67844 100644 --- a/shared/util/codeql/util/test/InlineExpectationsTest.qll +++ b/shared/util/codeql/util/test/InlineExpectationsTest.qll @@ -513,10 +513,10 @@ module Make { /** * RegEx pattern to match a comment containing one or more expected results. The comment must have * `$` as its first non-whitespace character. Any subsequent character - * is treated as part of the expected results, except that the comment may contain a `//` sequence - * to treat the remainder of the line as a regular (non-interpreted) comment. + * is treated as part of the expected results, except that the comment may contain a `//` or `#` + * sequence to treat the remainder of the line as a regular (non-interpreted) comment. */ -private string expectationCommentPattern() { result = "\\s*\\$ ((?:[^/]|/[^/])*)(?://.*)?" } +private string expectationCommentPattern() { result = "\\s*\\$ ((?:[^/]|/[^/])*)(?:(//|#).*)?" } /** * The possible columns in an expectation comment. The `TDefaultColumn` branch represents the first diff --git a/shared/util/qlpack.yml b/shared/util/qlpack.yml index 2914785b146..2ab432b4e47 100644 --- a/shared/util/qlpack.yml +++ b/shared/util/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/util -version: 2.0.39-dev +version: 2.0.40-dev groups: shared library: true dependencies: null diff --git a/shared/xml/CHANGELOG.md b/shared/xml/CHANGELOG.md index 685a8032d64..4a639c1f50f 100644 --- a/shared/xml/CHANGELOG.md +++ b/shared/xml/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.52 + +No user-facing changes. + ## 1.0.51 No user-facing changes. diff --git a/shared/xml/change-notes/released/1.0.52.md b/shared/xml/change-notes/released/1.0.52.md new file mode 100644 index 00000000000..a91f5a8025d --- /dev/null +++ b/shared/xml/change-notes/released/1.0.52.md @@ -0,0 +1,3 @@ +## 1.0.52 + +No user-facing changes. diff --git a/shared/xml/codeql-pack.release.yml b/shared/xml/codeql-pack.release.yml index 232dbe38ec8..ea1d2eed4d2 100644 --- a/shared/xml/codeql-pack.release.yml +++ b/shared/xml/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.0.51 +lastReleaseVersion: 1.0.52 diff --git a/shared/xml/qlpack.yml b/shared/xml/qlpack.yml index 0476610fda8..37565835712 100644 --- a/shared/xml/qlpack.yml +++ b/shared/xml/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/xml -version: 1.0.52-dev +version: 1.0.53-dev groups: shared library: true dependencies: diff --git a/shared/yaml/CHANGELOG.md b/shared/yaml/CHANGELOG.md index 4f57ee07cfa..69f699d7847 100644 --- a/shared/yaml/CHANGELOG.md +++ b/shared/yaml/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.52 + +No user-facing changes. + ## 1.0.51 No user-facing changes. diff --git a/shared/yaml/change-notes/released/1.0.52.md b/shared/yaml/change-notes/released/1.0.52.md new file mode 100644 index 00000000000..a91f5a8025d --- /dev/null +++ b/shared/yaml/change-notes/released/1.0.52.md @@ -0,0 +1,3 @@ +## 1.0.52 + +No user-facing changes. diff --git a/shared/yaml/codeql-pack.release.yml b/shared/yaml/codeql-pack.release.yml index 232dbe38ec8..ea1d2eed4d2 100644 --- a/shared/yaml/codeql-pack.release.yml +++ b/shared/yaml/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.0.51 +lastReleaseVersion: 1.0.52 diff --git a/shared/yaml/qlpack.yml b/shared/yaml/qlpack.yml index ae27690a3f9..795bbb1b1a7 100644 --- a/shared/yaml/qlpack.yml +++ b/shared/yaml/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/yaml -version: 1.0.52-dev +version: 1.0.53-dev groups: shared library: true warnOnImplicitThis: true diff --git a/shared/yeast-macros/src/lib.rs b/shared/yeast-macros/src/lib.rs index 1d7236b500a..7153cf30644 100644 --- a/shared/yeast-macros/src/lib.rs +++ b/shared/yeast-macros/src/lib.rs @@ -44,8 +44,19 @@ pub fn query(input: TokenStream) -> TokenStream { /// {expr} - embed a Rust expression returning Id /// {..expr} - splice an iterable of Id (in child/field position) /// field: {..expr} - splice into a named field +/// {expr}.map(p -> tpl) - apply tpl to each element; splice result +/// {expr}.reduce_left(f -> init, acc, e -> fold) +/// - fold with per-element init; splice 0 or 1 result /// ``` /// +/// Chain syntax after `{expr}` or `{..expr}`: +/// - `.map(param -> template)` — one output node per input element. +/// - `.reduce_left(first -> init, acc, elem -> fold)` — fold left; the first +/// element is converted by `init`, subsequent elements are folded by `fold` +/// with the accumulator bound to `acc`. An empty iterable yields nothing. +/// - Chains always splice (the result is iterable). +/// - Multiple chains can be chained, e.g. `.map(...).reduce_left(...)`. +/// /// Can be called with an explicit context or using the implicit context /// from an enclosing `rule!`: /// @@ -110,3 +121,37 @@ pub fn rule(input: TokenStream) -> TokenStream { Err(err) => err.to_compile_error().into(), } } + +/// Define a desugaring rule whose transform is a hand-written Rust block. +/// +/// Use `manual_rule!` when the transform needs control over capture +/// translation timing — for example, when an outer rule needs to set +/// state in `ctx` (the `BuildCtx`'s user context) before recursive +/// translation reaches inner rules that read that state. +/// +/// ```text +/// manual_rule!( +/// (query_pattern field: (_) @name) +/// { +/// // `ctx` is a `&mut BuildCtx<'_, C>`; capture variables +/// // (`name: NodeRef`, etc.) are bound from the query. +/// let translated = ctx.translate(name)?; +/// Ok(translated) +/// } +/// ) +/// ``` +/// +/// Differences from [`rule!`]: +/// - Captures are **not** auto-translated before the body runs; they +/// refer to raw input-schema nodes. Use [`BuildCtx::translate`] (or +/// [`BuildCtx::translate_opt`]) to translate them when you choose. +/// - The body is plain Rust returning `Result, String>` — no +/// tree template, no `Ok(...)` wrap. +#[proc_macro] +pub fn manual_rule(input: TokenStream) -> TokenStream { + let input2: TokenStream2 = input.into(); + match parse::parse_manual_rule_top(input2) { + Ok(output) => output.into(), + Err(err) => err.to_compile_error().into(), + } +} diff --git a/shared/yeast-macros/src/parse.rs b/shared/yeast-macros/src/parse.rs index eb3b161b295..fc6031eb39d 100644 --- a/shared/yeast-macros/src/parse.rs +++ b/shared/yeast-macros/src/parse.rs @@ -121,9 +121,9 @@ fn parse_query_fields(tokens: &mut Tokens) -> Result> { std::collections::HashMap::new(); let mut bare_children: Vec = Vec::new(); let push_field_elem = |order: &mut Vec, - map: &mut std::collections::HashMap>, - name: String, - elem: TokenStream| { + map: &mut std::collections::HashMap>, + name: String, + elem: TokenStream| { if !map.contains_key(&name) { order.push(name.clone()); map.insert(name, vec![elem]); @@ -141,7 +141,12 @@ fn parse_query_fields(tokens: &mut Tokens) -> Result> { // Parse the field's pattern. To support repetition like // `field: (kind)* @cap`, parse the atom first, then check for // a quantifier, and lastly handle a trailing `@capture`. - let atom = parse_query_atom(tokens)?; + // `field: @cap` is sugar for `field: _ @cap`. + let atom = if peek_is_at(tokens) { + quote! { yeast::query::QueryNode::Any { match_unnamed: true } } + } else { + parse_query_atom(tokens)? + }; if peek_is_repetition(tokens) { let rep = expect_repetition(tokens)?; let elem = quote! { @@ -155,8 +160,7 @@ fn parse_query_fields(tokens: &mut Tokens) -> Result> { } else { let child = if peek_is_at(tokens) { tokens.next(); - let capture_name = - expect_ident(tokens, "expected capture name after @")?; + let capture_name = expect_ident(tokens, "expected capture name after @")?; let name_str = capture_name.to_string(); quote! { yeast::query::QueryNode::Capture { @@ -259,6 +263,7 @@ fn parse_query_list(tokens: &mut Tokens) -> Result> { yeast::query::QueryListElem::SingleNode(#node) }, )?; + let elem = maybe_wrap_list_capture(tokens, elem)?; elems.push(elem); continue; } @@ -276,6 +281,7 @@ fn parse_query_list(tokens: &mut Tokens) -> Result> { yeast::query::QueryListElem::SingleNode(#node) }, )?; + let elem = maybe_wrap_list_capture(tokens, elem)?; elems.push(elem); continue; } @@ -289,10 +295,10 @@ fn parse_query_list(tokens: &mut Tokens) -> Result> { // tree! / trees! parsing — direct code generation against BuildCtx // --------------------------------------------------------------------------- -const IMPLICIT_CTX: &str = "__yeast_ctx"; +const IMPLICIT_CTX: &str = "ctx"; /// Determine the context identifier: either explicit `ctx,` or the implicit -/// `__yeast_ctx` from an enclosing `rule!`. +/// `ctx` from an enclosing `rule!`. fn parse_ctx_or_implicit(tokens: &mut Tokens) -> Ident { // Check if first token is an ident followed by a comma let mut lookahead = tokens.clone(); @@ -352,7 +358,7 @@ fn parse_direct_node(tokens: &mut Tokens, ctx: &Ident) -> Result { Some(TokenTree::Group(g)) if g.delimiter() == Delimiter::Brace => { let group = expect_group(tokens, Delimiter::Brace)?; let expr = group.stream(); - Ok(quote! { ::std::convert::Into::::into(#expr) }) + Ok(quote! { ::std::convert::Into::::into({ #expr }) }) } Some(TokenTree::Group(g)) if g.delimiter() == Delimiter::Parenthesis => { let group = expect_group(tokens, Delimiter::Parenthesis)?; @@ -389,8 +395,10 @@ fn parse_direct_node_inner(tokens: &mut Tokens, ctx: &Ident) -> Result Result Result into the field + // Check for field: {..expr}.chain or field: {expr}.chain — splice a Vec into the field if peek_is_group(tokens, Delimiter::Brace) { let group_clone = tokens.clone().next().unwrap(); if let TokenTree::Group(g) = &group_clone { let mut inner_check = g.stream().into_iter(); let is_splice = matches!(inner_check.next(), Some(TokenTree::Punct(p)) if p.as_char() == '.') && matches!(inner_check.next(), Some(TokenTree::Punct(p)) if p.as_char() == '.'); - if is_splice { + // Determine if a chain (.map(..)) follows the `{}` group. + let mut after = tokens.clone(); + after.next(); // skip the brace group + let has_chain = + matches!(after.peek(), Some(TokenTree::Punct(p)) if p.as_char() == '.'); + + if is_splice || has_chain { let group = expect_group(tokens, Delimiter::Brace)?; - let mut inner = group.stream().into_iter().peekable(); - inner.next(); // consume first . - inner.next(); // consume second . - let expr: proc_macro2::TokenStream = inner.collect(); + let base: TokenStream = if is_splice { + let mut inner = group.stream().into_iter().peekable(); + inner.next(); // consume first . + inner.next(); // consume second . + let expr: TokenStream = inner.collect(); + quote! { + { #expr }.into_iter().map(::std::convert::Into::::into) + } + } else { + let expr = group.stream(); + quote! { { #expr }.into_iter() } + }; + let chained = parse_chain_suffix(tokens, ctx, base)?; stmts.push(quote! { - let #temp: Vec = (#expr).into_iter() - .map(::std::convert::Into::::into) - .collect(); + let #temp: Vec = #chained.collect(); }); // An empty splice means the field is absent — skip it // entirely rather than emitting an empty named field. @@ -472,6 +497,94 @@ fn parse_direct_node_inner(tokens: &mut Tokens, ctx: &Ident) -> Result template) -- iterator map: produces Vec +/// ``` +/// +/// The chain may be empty (returns `base` unchanged). Multiple chained calls +/// are supported, e.g. `.map(p -> ...).map(q -> ...)`. +/// +/// Each call expects the receiver to be an iterator. The `base` argument +/// should therefore already be an iterator (use `.into_iter()` on it before +/// calling this function). +fn parse_chain_suffix(tokens: &mut Tokens, ctx: &Ident, base: TokenStream) -> Result { + let mut current = base; + while matches!(tokens.peek(), Some(TokenTree::Punct(p)) if p.as_char() == '.') { + tokens.next(); // consume . + let method = expect_ident(tokens, "expected method name after `.`")?; + let method_str = method.to_string(); + let args_group = expect_group(tokens, Delimiter::Parenthesis)?; + match method_str.as_str() { + "map" => { + let mut inner = args_group.stream().into_iter().peekable(); + let param = expect_ident(&mut inner, "expected lambda parameter name")?; + expect_punct(&mut inner, '-', "expected `->` after lambda parameter")?; + expect_punct(&mut inner, '>', "expected `->` after lambda parameter")?; + let body = parse_direct_node(&mut inner, ctx)?; + if let Some(tok) = inner.next() { + return Err(syn::Error::new_spanned( + tok, + "unexpected token after lambda body", + )); + } + current = quote! { + #current.map(|#param| #body) + }; + } + "reduce_left" => { + // Syntax: reduce_left(first -> init_tpl, acc, elem -> fold_tpl) + // - first -> init_tpl : converts the first element to the initial accumulator + // - acc, elem -> fold_tpl : fold step (acc = current accumulator, elem = next element) + // Empty iterator produces an empty iterator; non-empty produces a single-element iterator. + let mut inner = args_group.stream().into_iter().peekable(); + let init_param = expect_ident(&mut inner, "expected initial lambda parameter")?; + expect_punct(&mut inner, '-', "expected `->` after init parameter")?; + expect_punct(&mut inner, '>', "expected `->` after init parameter")?; + let init_body = parse_direct_node(&mut inner, ctx)?; + expect_punct(&mut inner, ',', "expected `,` after init template")?; + let acc_param = expect_ident(&mut inner, "expected accumulator parameter")?; + expect_punct(&mut inner, ',', "expected `,` after accumulator parameter")?; + let elem_param = expect_ident(&mut inner, "expected element parameter")?; + expect_punct(&mut inner, '-', "expected `->` after element parameter")?; + expect_punct(&mut inner, '>', "expected `->` after element parameter")?; + let fold_body = parse_direct_node(&mut inner, ctx)?; + if let Some(tok) = inner.next() { + return Err(syn::Error::new_spanned( + tok, + "unexpected token after fold template", + )); + } + current = quote! { + { + let mut __iter = #current; + let __result: Option = if let Some(#init_param) = __iter.next() { + let mut __acc: usize = #init_body; + for #elem_param in __iter { + let #acc_param: usize = __acc; + __acc = #fold_body; + } + Some(__acc) + } else { + None + }; + __result.into_iter() + } + }; + } + _ => { + return Err(syn::Error::new_spanned( + method, + format!("unknown builtin method `.{method_str}()`"), + )); + } + } + } + Ok(current) +} + /// Parse the top-level list of a `trees!` template. /// Each item is a node template or `{expr}` splice. fn parse_direct_list(tokens: &mut Tokens, ctx: &Ident) -> Result> { @@ -492,23 +605,33 @@ fn parse_direct_list(tokens: &mut Tokens, ctx: &Ident) -> Result::into) + } + } else { + let expr = group.stream(); + quote! { { #expr }.into_iter() } + }; + let chained = parse_chain_suffix(tokens, ctx, base)?; items.push(quote! { - __nodes.extend( - (#expr).into_iter().map(::std::convert::Into::::into) - ); + __nodes.extend(#chained); }); } else { let expr = group.stream(); items.push(quote! { - __nodes.push(::std::convert::Into::::into(#expr)); + __nodes.push(::std::convert::Into::::into({ #expr })); }); } continue; @@ -604,8 +727,11 @@ fn extract_captures_inner( } last_mult = CaptureMultiplicity::Single; } - TokenTree::Punct(p) if matches!(p.as_char(), '*' | '+' | '?') => { - // Keep last_mult — the @capture follows + TokenTree::Punct(p) if p.as_char() == '*' || p.as_char() == '+' => { + last_mult = CaptureMultiplicity::Repeated; + } + TokenTree::Punct(p) if p.as_char() == '?' => { + last_mult = CaptureMultiplicity::Optional; } _ => { last_mult = CaptureMultiplicity::Single; @@ -763,10 +889,117 @@ pub fn parse_rule_top(input: TokenStream) -> Result { Ok(quote! { { let __query = #query_code; - yeast::Rule::new(__query, Box::new(|__ast: &mut yeast::Ast, __captures: yeast::captures::Captures, __fresh: &yeast::tree_builder::FreshScope, __source_range: Option| { + yeast::Rule::new(__query, Box::new(|__ast: &mut yeast::Ast, mut __captures: yeast::captures::Captures, __fresh: &yeast::tree_builder::FreshScope, __source_range: Option, __user_ctx: &mut _, __translator: yeast::TranslatorHandle<'_, _>| { + // Auto-translation prefix: recursively translate every + // captured node before invoking the user's transform body. + // For OneShot rules this preserves the legacy behaviour + // (input-schema captures translated to output-schema + // nodes); for Repeating rules it is a no-op. + __translator.auto_translate_captures(&mut __captures, __ast, __user_ctx)?; #(#bindings)* - let mut #ctx_ident = yeast::build::BuildCtx::with_source_range(__ast, &__captures, __fresh, __source_range); - #transform_body + let mut #ctx_ident = yeast::build::BuildCtx::with_translator(__ast, &__captures, __fresh, __source_range, __user_ctx, __translator); + let __result: Vec = { #transform_body }; + Ok(__result) + })) + } + }) +} + +/// Parse `manual_rule!( query { body } )`. +/// +/// Like [`parse_rule_top`] but: +/// - Expects a Rust block `{ ... }` after the query (no `=>` arrow). +/// - Generates code that does NOT auto-translate captures before +/// running the body. Capture variables refer to raw (input-schema) +/// nodes; the body is responsible for explicit translation via +/// `ctx.translate(...)`. +/// - The body is included verbatim and must evaluate to +/// `Result, String>`. +pub fn parse_manual_rule_top(input: TokenStream) -> Result { + let mut tokens = input.into_iter().peekable(); + + // Collect query tokens up to the body block `{ ... }`. + let mut query_tokens = Vec::new(); + loop { + match tokens.peek() { + None => { + return Err(syn::Error::new( + Span::call_site(), + "expected a Rust block `{ ... }` after the query in manual_rule!", + )) + } + Some(TokenTree::Group(g)) if g.delimiter() == Delimiter::Brace => break, + _ => { + query_tokens.push(tokens.next().unwrap()); + } + } + } + + let query_stream: TokenStream = query_tokens.into_iter().collect(); + + // Extract captures from the query (same as in `rule!`). + let captures = extract_captures(&query_stream); + + // Parse the query into the QueryNode-building expression. + let query_code = parse_query_top(query_stream)?; + + // Generate capture bindings (same as in `rule!`). + let ctx_ident = Ident::new(IMPLICIT_CTX, Span::call_site()); + let bindings: Vec = captures + .iter() + .map(|cap| { + let name = Ident::new(&cap.name, Span::call_site()); + let name_str = &cap.name; + match cap.multiplicity { + CaptureMultiplicity::Repeated => quote! { + let #name: Vec = __captures.get_all(#name_str) + .into_iter() + .map(yeast::NodeRef) + .collect(); + }, + CaptureMultiplicity::Optional => quote! { + let #name: Option = + __captures.get_opt(#name_str).map(yeast::NodeRef); + }, + CaptureMultiplicity::Single => quote! { + let #name: yeast::NodeRef = + yeast::NodeRef(__captures.get_var(#name_str).unwrap()); + }, + } + }) + .collect(); + + // Consume the body block. + let body_group = match tokens.next() { + Some(TokenTree::Group(g)) if g.delimiter() == Delimiter::Brace => g, + other => { + return Err(syn::Error::new( + Span::call_site(), + format!( + "expected a Rust block `{{ ... }}` after the query in manual_rule!, found: {other:?}" + ), + )) + } + }; + let body_stream = body_group.stream(); + + // No tokens should follow the body. + if let Some(tok) = tokens.next() { + return Err(syn::Error::new_spanned( + tok, + "unexpected token after manual_rule! body", + )); + } + + Ok(quote! { + { + let __query = #query_code; + yeast::Rule::new(__query, Box::new(|__ast: &mut yeast::Ast, __captures: yeast::captures::Captures, __fresh: &yeast::tree_builder::FreshScope, __source_range: Option, __user_ctx: &mut _, __translator: yeast::TranslatorHandle<'_, _>| { + // No auto-translate prefix for manual rules — the body + // is responsible for translating captures explicitly. + #(#bindings)* + let mut #ctx_ident = yeast::build::BuildCtx::with_translator(__ast, &__captures, __fresh, __source_range, __user_ctx, __translator); + #body_stream })) } }) diff --git a/shared/yeast/doc/yeast.md b/shared/yeast/doc/yeast.md index 823bf1c1942..1700029b43c 100644 --- a/shared/yeast/doc/yeast.md +++ b/shared/yeast/doc/yeast.md @@ -265,7 +265,21 @@ occurrences of the same `$name` within one `BuildCtx` share the same value: ) ``` -`{..expr}` splices a `Vec` (or any iterable of `Id`): +The contents of `{…}` are treated as a Rust block, so multi-statement +expressions (with `let` bindings) work too: + +```rust +(assignment + left: {tmp} + right: { + let lit = ctx.literal("integer", "0"); + tree!((binary_expr op: (operator "+") left: {tmp} right: {lit})) + }) +``` + +`{..expr}` splices a `Vec` (or any iterable of `Id`); the contents +are likewise a Rust block, so the splice can be the result of arbitrary +computation: ```rust yeast::trees!(ctx, diff --git a/shared/yeast/src/bin/main.rs b/shared/yeast/src/bin/main.rs index 975c8e8b25f..978be21cc00 100644 --- a/shared/yeast/src/bin/main.rs +++ b/shared/yeast/src/bin/main.rs @@ -20,7 +20,7 @@ fn main() { let args = Cli::parse(); let language = get_language(&args.language); let source = std::fs::read_to_string(&args.file).unwrap(); - let runner = yeast::Runner::new(language, &[]); + let runner: yeast::Runner = yeast::Runner::new(language, &[]); let ast = runner.run(&source).unwrap(); println!("{}", ast.print(&source, ast.get_root())); } diff --git a/shared/yeast/src/build.rs b/shared/yeast/src/build.rs index bee4c4f7d03..c7c60530599 100644 --- a/shared/yeast/src/build.rs +++ b/shared/yeast/src/build.rs @@ -2,28 +2,60 @@ use std::collections::BTreeMap; use crate::captures::Captures; use crate::tree_builder::FreshScope; -use crate::{Ast, FieldId, Id, NodeContent}; +use crate::{Ast, FieldId, Id, NodeContent, TranslatorHandle}; /// Context for building new AST nodes during a transformation. /// /// Used by the `tree!` and `trees!` macros. Holds a mutable reference to the -/// AST, a reference to the captures from a query match, and a `FreshScope` for -/// generating unique identifiers. -pub struct BuildCtx<'a> { +/// AST, a reference to the captures from a query match, a `FreshScope` for +/// generating unique identifiers, and a mutable reference to a user-defined +/// context of type `C`. +/// +/// The user context `C` is shared across rules via the framework's driver: +/// outer rules can write to it before recursive translation, and inner rules +/// can read (or further mutate) it during their transforms. The framework +/// snapshots and restores the user context around each rule application, so +/// mutations made by a rule are visible to its descendants (via recursive +/// translation) but not to its parent's siblings. +/// +/// `BuildCtx` implements [`Deref`] and [`DerefMut`] targeting `C`, so user +/// context fields are accessible as `ctx.my_field` directly (provided they +/// don't collide with `BuildCtx`'s own fields like `ast`, `captures`, etc.). +/// +/// The default `C = ()` means rules that don't need any user context don't +/// pay any cost. +/// +/// When constructed by the framework (via the rule! macro), `BuildCtx` also +/// carries a [`TranslatorHandle`] that the [`translate`] method delegates +/// to. When constructed by hand (e.g. in tests), the translator is `None` +/// and [`translate`] returns an error. +pub struct BuildCtx<'a, C: 'a = ()> { pub ast: &'a mut Ast, pub captures: &'a Captures, pub fresh: &'a FreshScope, /// Source range of the matched node, inherited by synthetic nodes. pub source_range: Option, + /// User-supplied context, accessible directly via `ctx.field` (via Deref). + pub user_ctx: &'a mut C, + /// Optional translator handle, populated when the context is built by + /// the framework's rule driver. None when the context is built by hand. + pub(crate) translator: Option>, } -impl<'a> BuildCtx<'a> { - pub fn new(ast: &'a mut Ast, captures: &'a Captures, fresh: &'a FreshScope) -> Self { +impl<'a, C> BuildCtx<'a, C> { + pub fn new( + ast: &'a mut Ast, + captures: &'a Captures, + fresh: &'a FreshScope, + user_ctx: &'a mut C, + ) -> Self { Self { ast, captures, fresh, source_range: None, + user_ctx, + translator: None, } } @@ -32,12 +64,35 @@ impl<'a> BuildCtx<'a> { captures: &'a Captures, fresh: &'a FreshScope, source_range: Option, + user_ctx: &'a mut C, ) -> Self { Self { ast, captures, fresh, source_range, + user_ctx, + translator: None, + } + } + + /// Construct a `BuildCtx` carrying a translator handle. Used by the + /// `rule!` macro to enable [`translate`] inside rule transforms. + pub fn with_translator( + ast: &'a mut Ast, + captures: &'a Captures, + fresh: &'a FreshScope, + source_range: Option, + user_ctx: &'a mut C, + translator: TranslatorHandle<'a, C>, + ) -> Self { + Self { + ast, + captures, + fresh, + source_range, + user_ctx, + translator: Some(translator), } } @@ -82,10 +137,83 @@ impl<'a> BuildCtx<'a> { .create_named_token_with_range(kind, value.to_string(), self.source_range) } + /// Create a leaf node with fixed content and an optional preferred source range. + /// If `source_range` is `None`, falls back to this context's inherited range. + pub fn literal_with_source_range( + &mut self, + kind: &'static str, + value: &str, + source_range: Option, + ) -> Id { + self.ast.create_named_token_with_range( + kind, + value.to_string(), + source_range.or(self.source_range), + ) + } + /// Create a leaf node with an auto-generated unique name. pub fn fresh(&mut self, kind: &'static str, name: &str) -> Id { let generated = self.fresh.resolve(name); self.ast .create_named_token_with_range(kind, generated, self.source_range) } + + /// Prepend a value to a field of an existing node. + pub fn prepend_field(&mut self, node_id: Id, field_name: &str, value_id: Id) { + let field_id = self + .ast + .field_id_for_name(field_name) + .unwrap_or_else(|| panic!("build: field '{field_name}' not found")); + self.ast.prepend_field_child(node_id, field_id, value_id); + } +} + +impl BuildCtx<'_, C> { + /// Recursively translate a node via the framework's rule machinery. + /// In a OneShot phase, applies OneShot rules to the given node and + /// returns the resulting node ids. In a Repeating phase, errors + /// (translation is not meaningful when input and output share a + /// schema). + /// + /// Accepts any value convertible to [`Id`] (including [`crate::NodeRef`]), + /// so manual rules can pass capture bindings directly without unwrapping. + /// + /// Errors if this `BuildCtx` was constructed by hand (without a + /// translator handle) — for example, in unit tests that don't go + /// through the rule driver. + pub fn translate>(&mut self, id: I) -> Result, String> { + let id = id.into(); + match &self.translator { + Some(t) => t.translate(self.ast, self.user_ctx, id), + None => Err("translate() called on a BuildCtx without a translator handle".into()), + } + } + + /// Translate an optional capture, returning the first translated id or + /// `None`. Convenience for `?`-quantifier captures (`Option`). + /// + /// If the underlying translation produces multiple ids for a single + /// input, only the first is returned. For most use cases (e.g. + /// translating a single type annotation) this is what you want; if + /// you need all ids, use [`translate`] directly. + pub fn translate_opt>(&mut self, id: Option) -> Result, String> { + match id { + Some(id) => Ok(self.translate(id)?.into_iter().next()), + None => Ok(None), + } + } +} + +impl std::ops::Deref for BuildCtx<'_, C> { + type Target = C; + fn deref(&self) -> &C { + &*self.user_ctx + } +} + +impl std::ops::DerefMut for BuildCtx<'_, C> { + fn deref_mut(&mut self) -> &mut C { + &mut *self.user_ctx + } } diff --git a/shared/yeast/src/dump.rs b/shared/yeast/src/dump.rs index d046c192053..be496d40bd5 100644 --- a/shared/yeast/src/dump.rs +++ b/shared/yeast/src/dump.rs @@ -53,12 +53,7 @@ pub fn dump_ast_with_options( /// /// Any node that does not match the expected type set for its parent field is /// rendered with a trailing `" <-- ERROR: ..."` annotation on the same line. -pub fn dump_ast_with_type_errors( - ast: &Ast, - root: usize, - source: &str, - schema: &Schema, -) -> String { +pub fn dump_ast_with_type_errors(ast: &Ast, root: usize, source: &str, schema: &Schema) -> String { dump_ast_with_type_errors_and_options(ast, root, source, schema, &DumpOptions::default()) } @@ -74,7 +69,15 @@ pub fn dump_ast_with_type_errors_and_options( options: &DumpOptions, ) -> String { let mut out = String::new(); - dump_node(ast, root, source, options, 0, Some((schema, None, None)), &mut out); + dump_node( + ast, + root, + source, + options, + 0, + Some((schema, None, None)), + &mut out, + ); out } @@ -232,8 +235,8 @@ fn dump_node( } let field_name = ast.field_name_for_id(field_id).unwrap_or("?"); let child_type_check = type_check.map(|(schema, _, _)| { - let expected = expected_for_field(schema, node.kind_name(), field_id) - .or(Some(EMPTY_NODE_TYPES)); + let expected = + expected_for_field(schema, node.kind_name(), field_id).or(Some(EMPTY_NODE_TYPES)); let parent_field = Some((node.kind_name(), field_name)); (schema, expected, parent_field) }); diff --git a/shared/yeast/src/lib.rs b/shared/yeast/src/lib.rs index 0717d27e4b8..e0fffc551f3 100644 --- a/shared/yeast/src/lib.rs +++ b/shared/yeast/src/lib.rs @@ -16,7 +16,7 @@ pub mod schema; pub mod tree_builder; mod visitor; -pub use yeast_macros::{query, rule, tree, trees}; +pub use yeast_macros::{manual_rule, query, rule, tree, trees}; use captures::Captures; pub use cursor::Cursor; @@ -58,12 +58,30 @@ pub trait YeastDisplay { fn yeast_to_string(&self, ast: &Ast) -> String; } +/// Optional source range for values used in `#{expr}` interpolations. +/// +/// By default this returns `None`, so synthesized leaves inherit the matched +/// rule's source range. `NodeRef` returns the referenced node's range, letting +/// `(kind #{capture})` carry the captured node's location. +pub trait YeastSourceRange { + fn yeast_source_range(&self, ast: &Ast) -> Option; +} + impl YeastDisplay for NodeRef { fn yeast_to_string(&self, ast: &Ast) -> String { ast.source_text(self.0) } } +impl YeastSourceRange for NodeRef { + fn yeast_source_range(&self, ast: &Ast) -> Option { + ast.get_node(self.0).and_then(|n| match &n.content { + NodeContent::Range(r) => Some(r.clone()), + _ => n.source_range, + }) + } +} + macro_rules! impl_yeast_display_via_display { ($($t:ty),* $(,)?) => { $( @@ -72,6 +90,12 @@ macro_rules! impl_yeast_display_via_display { ::std::string::ToString::to_string(self) } } + + impl YeastSourceRange for $t { + fn yeast_source_range(&self, _ast: &Ast) -> Option { + None + } + } )* }; } @@ -90,6 +114,12 @@ impl YeastDisplay for &T { } } +impl YeastSourceRange for &T { + fn yeast_source_range(&self, ast: &Ast) -> Option { + (**self).yeast_source_range(ast) + } +} + pub const CHILD_FIELD: u16 = u16::MAX; #[derive(Debug)] @@ -267,7 +297,9 @@ impl Ast { /// Returns the source text for `id`, resolving `NodeContent::Range` /// against the stored source bytes when available. pub fn source_text(&self, id: Id) -> String { - let Some(node) = self.get_node(id) else { return String::new(); }; + let Some(node) = self.get_node(id) else { + return String::new(); + }; let read_range = |range: &tree_sitter::Range| { let start = range.start_byte; let end = range.end_byte; @@ -368,6 +400,15 @@ impl Ast { is_named: bool, source_range: Option, ) -> Id { + let source_range = match &content { + // Parsed nodes already carry an exact source range in their content. + NodeContent::Range(_) => source_range, + // Synthesized nodes derive location from children when possible, + // and fall back to the inherited rule-match range otherwise. + _ => self + .union_source_range_of_children(&fields) + .or(source_range), + }; let id = self.nodes.len(); self.nodes.push(Node { kind, @@ -383,10 +424,79 @@ impl Ast { id } + fn union_source_range_of_children( + &self, + fields: &BTreeMap>, + ) -> Option { + let mut start_byte: Option = None; + let mut end_byte: Option = None; + let mut start_point = tree_sitter::Point { row: 0, column: 0 }; + let mut end_point = tree_sitter::Point { row: 0, column: 0 }; + + for child_ids in fields.values() { + for &child_id in child_ids { + let Some(child) = self.get_node(child_id) else { + continue; + }; + + let child_start_byte = child.start_byte(); + let child_end_byte = child.end_byte(); + + // Skip children that carry no usable location. + if child_start_byte == 0 && child_end_byte == 0 { + continue; + } + + match start_byte { + None => { + start_byte = Some(child_start_byte); + start_point = child.start_position(); + } + Some(current_start) if child_start_byte < current_start => { + start_byte = Some(child_start_byte); + start_point = child.start_position(); + } + _ => {} + } + + match end_byte { + None => { + end_byte = Some(child_end_byte); + end_point = child.end_position(); + } + Some(current_end) if child_end_byte > current_end => { + end_byte = Some(child_end_byte); + end_point = child.end_position(); + } + _ => {} + } + } + } + + match (start_byte, end_byte) { + (Some(start_byte), Some(end_byte)) => Some(tree_sitter::Range { + start_byte, + end_byte, + start_point, + end_point, + }), + _ => None, + } + } + pub fn create_named_token(&mut self, kind: &'static str, content: String) -> Id { self.create_named_token_with_range(kind, content, None) } + /// Prepend a child id to the given field of the given node. + pub fn prepend_field_child(&mut self, node_id: Id, field_id: FieldId, value_id: Id) { + let node = self + .nodes + .get_mut(node_id) + .expect("prepend_field_child: invalid node id"); + node.fields.entry(field_id).or_default().insert(0, value_id); + } + pub fn create_named_token_with_range( &mut self, kind: &'static str, @@ -595,18 +705,118 @@ impl From for NodeContent { } } -/// The transform function for a rule: takes the AST, captured variables, a -/// fresh-name scope, and the source range of the matched node, and returns -/// the IDs of the replacement nodes. -pub type Transform = Box< - dyn Fn(&mut Ast, Captures, &tree_builder::FreshScope, Option) -> Vec +/// A handle that lets a rule transform recursively translate AST nodes via +/// the framework's rule machinery. Constructed by the driver and passed as +/// the last argument of every [`Transform`] invocation. +/// +/// The `rule!` macro uses [`TranslatorHandle::auto_translate_captures`] in +/// its generated prefix to translate captures before running the user's +/// transform body. Manually-written transforms (using [`Rule::new`] +/// directly) can call [`TranslatorHandle::translate`] selectively on +/// specific node ids to control when translation happens. +pub struct TranslatorHandle<'a, C> { + inner: TranslatorImpl<'a, C>, +} + +/// Internal phase-specific translation state. Kept private — callers +/// interact with [`TranslatorHandle`] only. +enum TranslatorImpl<'a, C> { + /// OneShot phase translator: recursively applies OneShot rules. + OneShot { + index: &'a RuleIndex<'a, C>, + fresh: &'a tree_builder::FreshScope, + rewrite_depth: usize, + /// The id of the node the current rule is matching. Used by + /// [`auto_translate_captures`] to avoid infinite recursion when a + /// rule captures its own match root (e.g. via `(_) @_`). + matched_root: Id, + }, + /// Repeating phase translator: translation is not meaningful here + /// (input and output schemas are the same). [`translate`] errors; + /// [`auto_translate_captures`] is a no-op so the macro's auto-prefix + /// works unchanged for Repeating rules. + Repeating, +} + +impl<'a, C: Clone> TranslatorHandle<'a, C> { + /// Recursively apply OneShot rules to `id` and return the resulting + /// node ids. Errors in a Repeating phase (where translation is not + /// meaningful). + pub fn translate(&self, ast: &mut Ast, user_ctx: &mut C, id: Id) -> Result, String> { + match &self.inner { + TranslatorImpl::OneShot { + index, + fresh, + rewrite_depth, + .. + } => apply_one_shot_rules_inner(index, ast, user_ctx, id, fresh, rewrite_depth + 1), + TranslatorImpl::Repeating => { + Err("translate() is not available in a Repeating phase".into()) + } + } + } + + /// Translate every captured node in `captures` in place (OneShot phase + /// only). In a Repeating phase this is a no-op — Repeating rules + /// receive raw captures. + /// + /// Used by the `rule!` macro's generated prefix to preserve the + /// pre-existing "auto-translate captures before running the transform + /// body" behavior. Manually-written transforms typically translate + /// captures selectively via [`translate`] instead. + /// + /// To avoid infinite recursion, a capture whose id matches the rule's + /// matched root (e.g. from a `(_) @_` pattern) is left unchanged. + pub fn auto_translate_captures( + &self, + captures: &mut Captures, + ast: &mut Ast, + user_ctx: &mut C, + ) -> Result<(), String> { + match &self.inner { + TranslatorImpl::OneShot { matched_root, .. } => { + let root = *matched_root; + captures.try_map_all_captures(|cid| { + if cid == root { + Ok(vec![cid]) + } else { + self.translate(ast, user_ctx, cid) + } + }) + } + TranslatorImpl::Repeating => Ok(()), + } + } +} + +/// The transform function for a rule. +/// +/// Takes the AST, the (raw, untranslated) captured variables, a fresh-name +/// scope, the source range of the matched node, a mutable reference to the +/// user context of type `C`, and a [`TranslatorHandle`] for recursively +/// translating nodes. Returns the IDs of the replacement nodes, or an +/// error message if the transform could not be completed. +/// +/// Transforms produced by [`Rule::new`] receive **raw** captures and must +/// translate them themselves (via the handle). Transforms produced by the +/// `rule!` macro have an auto-translation prefix injected for backward +/// compatibility. +pub type Transform = Box< + dyn Fn( + &mut Ast, + Captures, + &tree_builder::FreshScope, + Option, + &mut C, + TranslatorHandle<'_, C>, + ) -> Result, String> + Send + Sync, >; -pub struct Rule { +pub struct Rule { query: QueryNode, - transform: Transform, + transform: Transform, /// If true, after this rule fires on a node the engine will try to /// re-apply this same rule on the result root. Defaults to false: /// each rule fires at most once on a given node, which prevents @@ -614,8 +824,8 @@ pub struct Rule { repeated: bool, } -impl Rule { - pub fn new(query: QueryNode, transform: Transform) -> Self { +impl Rule { + pub fn new(query: QueryNode, transform: Transform) -> Self { Self { query, transform, @@ -637,9 +847,13 @@ impl Rule { ast: &mut Ast, node: Id, fresh: &tree_builder::FreshScope, + user_ctx: &mut C, + translator: TranslatorHandle<'_, C>, ) -> Result>, String> { match self.try_match(ast, node)? { - Some(captures) => Ok(Some(self.run_transform(ast, captures, node, fresh))), + Some(captures) => Ok(Some( + self.run_transform(ast, captures, node, fresh, user_ctx, translator)?, + )), None => Ok(None), } } @@ -663,29 +877,31 @@ impl Rule { captures: Captures, node: Id, fresh: &tree_builder::FreshScope, - ) -> Vec { + user_ctx: &mut C, + translator: TranslatorHandle<'_, C>, + ) -> Result, String> { fresh.next_scope(); let source_range = ast.get_node(node).and_then(|n| match n.content { NodeContent::Range(r) => Some(r), _ => n.source_range, }); - (self.transform)(ast, captures, fresh, source_range) + (self.transform)(ast, captures, fresh, source_range, user_ctx, translator) } } const MAX_REWRITE_DEPTH: usize = 100; /// Index of rules by their root query kind for fast lookup. -struct RuleIndex<'a> { +struct RuleIndex<'a, C> { /// Rules indexed by root node kind name. - by_kind: BTreeMap<&'static str, Vec<&'a Rule>>, + by_kind: BTreeMap<&'static str, Vec<&'a Rule>>, /// Rules with wildcard queries (Any) that apply to all nodes. - wildcard: Vec<&'a Rule>, + wildcard: Vec<&'a Rule>, } -impl<'a> RuleIndex<'a> { - fn new(rules: &'a [Rule]) -> Self { - let mut by_kind: BTreeMap<&'static str, Vec<&'a Rule>> = BTreeMap::new(); +impl<'a, C> RuleIndex<'a, C> { + fn new(rules: &'a [Rule]) -> Self { + let mut by_kind: BTreeMap<&'static str, Vec<&'a Rule>> = BTreeMap::new(); let mut wildcard = Vec::new(); for rule in rules { match rule.query.root_kind() { @@ -696,7 +912,7 @@ impl<'a> RuleIndex<'a> { Self { by_kind, wildcard } } - fn rules_for_kind(&self, kind: &str) -> impl Iterator { + fn rules_for_kind(&self, kind: &str) -> impl Iterator> { self.by_kind .get(kind) .into_iter() @@ -705,23 +921,25 @@ impl<'a> RuleIndex<'a> { } } -fn apply_repeating_rules( - rules: &[Rule], +fn apply_repeating_rules( + rules: &[Rule], ast: &mut Ast, + user_ctx: &mut C, id: Id, fresh: &tree_builder::FreshScope, ) -> Result, String> { let index = RuleIndex::new(rules); - apply_repeating_rules_inner(&index, ast, id, fresh, 0, None) + apply_repeating_rules_inner(&index, ast, user_ctx, id, fresh, 0, None) } -fn apply_repeating_rules_inner( - index: &RuleIndex, +fn apply_repeating_rules_inner( + index: &RuleIndex, ast: &mut Ast, + user_ctx: &mut C, id: Id, fresh: &tree_builder::FreshScope, rewrite_depth: usize, - skip_rule: Option<*const Rule>, + skip_rule: Option<*const Rule>, ) -> Result, String> { if rewrite_depth > MAX_REWRITE_DEPTH { return Err(format!( @@ -732,11 +950,23 @@ fn apply_repeating_rules_inner( let node_kind = ast.get_node(id).map(|n| n.kind()).unwrap_or(""); for rule in index.rules_for_kind(node_kind) { - let rule_ptr = *rule as *const Rule; + let rule_ptr = *rule as *const Rule; if Some(rule_ptr) == skip_rule { continue; } - if let Some(result_node) = rule.try_rule(ast, id, fresh)? { + // Snapshot the user context before invoking the rule so that any + // mutations the rule makes are visible during recursive translation + // of its result, but not leaked to the parent's siblings. + let snapshot = user_ctx.clone(); + // Repeating rules don't need a real translator: their captures + // aren't auto-translated (Repeating preserves the input schema), + // and `ctx.translate(id)` errors if invoked from a Repeating + // transform. + let translator = TranslatorHandle { + inner: TranslatorImpl::Repeating, + }; + let try_result = rule.try_rule(ast, id, fresh, user_ctx, translator)?; + if let Some(result_node) = try_result { // For non-repeated rules, suppress further application of *this* // rule on the result root, so a rule whose output matches its own // query doesn't loop. Other rules and child traversal are @@ -747,14 +977,19 @@ fn apply_repeating_rules_inner( results.extend(apply_repeating_rules_inner( index, ast, + user_ctx, node, fresh, rewrite_depth + 1, next_skip, )?); } + *user_ctx = snapshot; return Ok(results); } + // Rule didn't match; restore any speculative changes (none expected + // since try_rule only mutates on match, but be defensive). + *user_ctx = snapshot; } // Take the parent's fields by ownership: the recursion will rewrite @@ -769,7 +1004,15 @@ fn apply_repeating_rules_inner( for children in fields.values_mut() { let mut new_children: Option> = None; for (i, &child_id) in children.iter().enumerate() { - let result = apply_repeating_rules_inner(index, ast, child_id, fresh, rewrite_depth, None)?; + let result = apply_repeating_rules_inner( + index, + ast, + user_ctx, + child_id, + fresh, + rewrite_depth, + None, + )?; let unchanged = result.len() == 1 && result[0] == child_id; match (&mut new_children, unchanged) { (None, true) => {} // unchanged so far, no allocation needed @@ -798,24 +1041,25 @@ fn apply_repeating_rules_inner( /// each visited node, recursion proceeds only through captured nodes (not /// through the input node's children directly), and an error is returned if /// no rule matches a visited node. -fn apply_one_shot_rules( - rules: &[Rule], +fn apply_one_shot_rules( + rules: &[Rule], ast: &mut Ast, + user_ctx: &mut C, id: Id, fresh: &tree_builder::FreshScope, ) -> Result, String> { let index = RuleIndex::new(rules); - apply_one_shot_rules_inner(&index, ast, id, fresh, 0) + apply_one_shot_rules_inner(&index, ast, user_ctx, id, fresh, 0) } -fn apply_one_shot_rules_inner( - index: &RuleIndex, +fn apply_one_shot_rules_inner( + index: &RuleIndex, ast: &mut Ast, + user_ctx: &mut C, id: Id, fresh: &tree_builder::FreshScope, rewrite_depth: usize, ) -> Result, String> { - if rewrite_depth > MAX_REWRITE_DEPTH { return Err(format!( "Desugaring exceeded maximum rewrite depth ({MAX_REWRITE_DEPTH}). \ @@ -825,31 +1069,28 @@ fn apply_one_shot_rules_inner( let node_kind = ast.get_node(id).map(|n| n.kind()).unwrap_or(""); - // Don't rewrite unnamed nodes (punctuation, keywords, etc.); leave them - // as-is. Rules target named nodes only. - if let Some(node) = ast.get_node(id) { - if !node.is_named() { - return Ok(vec![id]); - } - } - for rule in index.rules_for_kind(node_kind) { - if let Some(mut captures) = rule.try_match(ast, id)? { - // Recursively translate every captured node before invoking the - // transform. The transform's output uses output-schema kinds, so - // we must translate captured input-schema nodes to their - // output-schema equivalents first. - captures.try_map_all_captures(|captured_id| { - // Avoid infinite recursion when a capture refers to the root - // node of the matched tree (e.g. an `@_` capture on the - // pattern root): re-analyzing it would match the same rule - // again indefinitely. - if captured_id == id { - return Ok(vec![captured_id]); - } - apply_one_shot_rules_inner(index, ast, captured_id, fresh, rewrite_depth + 1) - })?; - return Ok(rule.run_transform(ast, captures, id, fresh)); + if let Some(captures) = rule.try_match(ast, id)? { + // Snapshot the user context before invoking the rule so that any + // mutations the rule (or its transitively-translated captures) + // make are visible during this rule's transform, but not leaked + // to the parent's siblings. + let snapshot = user_ctx.clone(); + // Build the translator handle the transform will use to + // recursively translate captures (or, for macro-generated + // rules, the auto-translate prefix uses it to translate every + // capture up front, preserving the legacy behavior). + let translator = TranslatorHandle { + inner: TranslatorImpl::OneShot { + index, + fresh, + rewrite_depth, + matched_root: id, + }, + }; + let result = rule.run_transform(ast, captures, id, fresh, user_ctx, translator)?; + *user_ctx = snapshot; + return Ok(result); } } @@ -877,15 +1118,15 @@ pub enum PhaseKind { /// starts. Rules within a phase compete for matches as usual; rules in /// different phases never compete because each traversal only considers the /// current phase's rules. -pub struct Phase { +pub struct Phase { /// Name used in error messages. pub name: String, - pub rules: Vec, + pub rules: Vec>, pub kind: PhaseKind, } -impl Phase { - pub fn new(name: impl Into, kind: PhaseKind, rules: Vec) -> Self { +impl Phase { + pub fn new(name: impl Into, kind: PhaseKind, rules: Vec>) -> Self { Self { name: name.into(), rules, @@ -911,17 +1152,30 @@ impl Phase { /// .add_phase("desugar", PhaseKind::Repeating, desugar_rules) /// .with_output_node_types_yaml(yaml); /// ``` -#[derive(Default)] -pub struct DesugaringConfig { +/// +/// The optional type parameter `C` is the user context type threaded through +/// rule transforms. Defaults to `()` (no user context). +pub struct DesugaringConfig { /// Phases of rule application, applied in order. - pub phases: Vec, + pub phases: Vec>, /// Output node-types in YAML format. If `None`, the input grammar's /// node types are used (i.e. the desugared AST has the same node types /// as the tree-sitter grammar). pub output_node_types_yaml: Option<&'static str>, } -impl DesugaringConfig { +// Manual `Default` impl so users with a custom `C` that doesn't implement +// `Default` can still construct an empty config. +impl Default for DesugaringConfig { + fn default() -> Self { + Self { + phases: Vec::new(), + output_node_types_yaml: None, + } + } +} + +impl DesugaringConfig { /// Create an empty configuration. Add phases via [`add_phase`] and an /// optional output schema via [`with_output_node_types_yaml`]. pub fn new() -> Self { @@ -933,7 +1187,7 @@ impl DesugaringConfig { mut self, name: impl Into, kind: PhaseKind, - rules: Vec, + rules: Vec>, ) -> Self { self.phases.push(Phase::new(name, kind, rules)); self @@ -955,15 +1209,15 @@ impl DesugaringConfig { } } -pub struct Runner<'a> { +pub struct Runner<'a, C = ()> { language: tree_sitter::Language, schema: schema::Schema, - phases: &'a [Phase], + phases: &'a [Phase], } -impl<'a> Runner<'a> { +impl<'a, C> Runner<'a, C> { /// Create a runner using the input grammar's schema for output. - pub fn new(language: tree_sitter::Language, phases: &'a [Phase]) -> Self { + pub fn new(language: tree_sitter::Language, phases: &'a [Phase]) -> Self { let schema = schema::Schema::from_language(&language); Self { language, @@ -976,7 +1230,7 @@ impl<'a> Runner<'a> { pub fn with_schema( language: tree_sitter::Language, schema: &schema::Schema, - phases: &'a [Phase], + phases: &'a [Phase], ) -> Self { Self { language, @@ -988,7 +1242,7 @@ impl<'a> Runner<'a> { /// Create a runner from a [`DesugaringConfig`]. pub fn from_config( language: tree_sitter::Language, - config: &'a DesugaringConfig, + config: &'a DesugaringConfig, ) -> Result { let schema = config.build_schema(&language)?; Ok(Self { @@ -997,11 +1251,17 @@ impl<'a> Runner<'a> { phases: &config.phases, }) } +} - pub fn run_from_tree( +impl<'a, C: Clone> Runner<'a, C> { + /// Parse `tree` against `source` and run all phases, threading + /// `user_ctx` through every rule transform. The caller owns the + /// initial context state. + pub fn run_from_tree_with_ctx( &self, tree: &tree_sitter::Tree, source: &[u8], + user_ctx: &mut C, ) -> Result { let mut ast = Ast::from_tree_with_schema_and_source( self.schema.clone(), @@ -1009,11 +1269,13 @@ impl<'a> Runner<'a> { &self.language, source.to_vec(), ); - self.run_phases(&mut ast)?; + self.run_phases(&mut ast, user_ctx)?; Ok(ast) } - pub fn run(&self, input: &str) -> Result { + /// Parse `input` and run all phases, threading `user_ctx` through + /// every rule transform. The caller owns the initial context state. + pub fn run_with_ctx(&self, input: &str, user_ctx: &mut C) -> Result { let mut parser = tree_sitter::Parser::new(); parser .set_language(&self.language) @@ -1027,20 +1289,24 @@ impl<'a> Runner<'a> { &self.language, input.as_bytes().to_vec(), ); - self.run_phases(&mut ast)?; + self.run_phases(&mut ast, user_ctx)?; Ok(ast) } /// Apply each phase in turn to the AST, threading the root through. /// A single `FreshScope` is shared across phases so that fresh /// identifiers generated in different phases don't collide. - fn run_phases(&self, ast: &mut Ast) -> Result<(), String> { + fn run_phases(&self, ast: &mut Ast, user_ctx: &mut C) -> Result<(), String> { let fresh = tree_builder::FreshScope::new(); let mut root = ast.get_root(); for phase in self.phases { let res = match phase.kind { - PhaseKind::Repeating => apply_repeating_rules(&phase.rules, ast, root, &fresh), - PhaseKind::OneShot => apply_one_shot_rules(&phase.rules, ast, root, &fresh), + PhaseKind::Repeating => { + apply_repeating_rules(&phase.rules, ast, user_ctx, root, &fresh) + } + PhaseKind::OneShot => { + apply_one_shot_rules(&phase.rules, ast, user_ctx, root, &fresh) + } } .map_err(|e| format!("Phase `{}`: {e}", phase.name))?; if res.len() != 1 { @@ -1056,3 +1322,78 @@ impl<'a> Runner<'a> { Ok(()) } } + +impl<'a, C: Clone + Default> Runner<'a, C> { + /// Parse `tree` against `source` and run all phases, using the + /// default context (`C::default()`) as the initial context state. + pub fn run_from_tree(&self, tree: &tree_sitter::Tree, source: &[u8]) -> Result { + let mut user_ctx = C::default(); + self.run_from_tree_with_ctx(tree, source, &mut user_ctx) + } + + /// Parse `input` and run all phases, using the default context + /// (`C::default()`) as the initial context state. + pub fn run(&self, input: &str) -> Result { + let mut user_ctx = C::default(); + self.run_with_ctx(input, &mut user_ctx) + } +} + +// --------------------------------------------------------------------------- +// Desugarer: type-erased view of a DesugaringConfig + Runner +// --------------------------------------------------------------------------- + +/// Type-erased interface to a desugaring pipeline for a single language. +/// +/// Consumers (e.g. a generic tree-sitter extractor) hold +/// `Box` so they can dispatch through the trait without +/// knowing the user context type `C` that's internal to yeast. +/// +/// Construct one via [`ConcreteDesugarer::new`] from a +/// [`DesugaringConfig`] and a [`tree_sitter::Language`]. +pub trait Desugarer: Send + Sync { + /// The output AST schema (in YAML format), or `None` if the input + /// grammar's schema should be used. + fn output_node_types_yaml(&self) -> Option<&'static str>; + + /// Parse `tree` against `source` and run the desugaring pipeline. + /// Each call constructs a fresh default user context internally. + fn run_from_tree(&self, tree: &tree_sitter::Tree, source: &[u8]) -> Result; +} + +/// A concrete [`Desugarer`] backed by a [`DesugaringConfig`] for a +/// specific user context type `C`. Stores the language and a pre-built +/// schema so that per-call cost is bounded to constructing a transient +/// [`Runner`] and cloning the schema (no YAML re-parsing). +pub struct ConcreteDesugarer { + language: tree_sitter::Language, + schema: schema::Schema, + config: DesugaringConfig, +} + +impl ConcreteDesugarer { + /// Build a desugarer for `language` from `config`. Parses the output + /// schema YAML once (if set) and stores it for reuse across files. + pub fn new( + language: tree_sitter::Language, + config: DesugaringConfig, + ) -> Result { + let schema = config.build_schema(&language)?; + Ok(Self { + language, + schema, + config, + }) + } +} + +impl Desugarer for ConcreteDesugarer { + fn output_node_types_yaml(&self) -> Option<&'static str> { + self.config.output_node_types_yaml + } + + fn run_from_tree(&self, tree: &tree_sitter::Tree, source: &[u8]) -> Result { + let runner = Runner::with_schema(self.language.clone(), &self.schema, &self.config.phases); + runner.run_from_tree(tree, source) + } +} diff --git a/shared/yeast/src/node_types_yaml.rs b/shared/yeast/src/node_types_yaml.rs index 797f14cba72..f4d9f2a1c42 100644 --- a/shared/yeast/src/node_types_yaml.rs +++ b/shared/yeast/src/node_types_yaml.rs @@ -242,10 +242,7 @@ pub fn convert(yaml_input: &str) -> Result { /// Apply YAML node-type definitions to a mutable Schema. /// Registers all types, fields, and allowed types from the YAML into the schema. -fn apply_yaml_to_schema( - yaml: &YamlNodeTypes, - schema: &mut crate::schema::Schema, -) { +fn apply_yaml_to_schema(yaml: &YamlNodeTypes, schema: &mut crate::schema::Schema) { // Register all supertypes as node kinds for name in yaml.supertypes.keys() { schema.register_kind(name); @@ -307,7 +304,8 @@ fn apply_yaml_to_schema( .into_vec() .into_iter() .map(|type_ref| { - let (kind, named) = resolve_type_ref_pair(&type_ref, &named_types, &unnamed_types); + let (kind, named) = + resolve_type_ref_pair(&type_ref, &named_types, &unnamed_types); crate::schema::NodeType { kind, named } }) .collect::>(); diff --git a/shared/yeast/src/schema.rs b/shared/yeast/src/schema.rs index bbd425f15a2..da13bb8b6b7 100644 --- a/shared/yeast/src/schema.rs +++ b/shared/yeast/src/schema.rs @@ -198,13 +198,8 @@ impl Schema { .insert((parent_kind.to_string(), field_id), node_types); } - pub fn field_types( - &self, - parent_kind: &str, - field_id: FieldId, - ) -> Option<&Vec> { - self.field_types - .get(&(parent_kind.to_string(), field_id)) + pub fn field_types(&self, parent_kind: &str, field_id: FieldId) -> Option<&Vec> { + self.field_types.get(&(parent_kind.to_string(), field_id)) } pub fn set_field_cardinality( diff --git a/shared/yeast/tests/test.rs b/shared/yeast/tests/test.rs index 7645f3776f8..99471f129ab 100644 --- a/shared/yeast/tests/test.rs +++ b/shared/yeast/tests/test.rs @@ -7,7 +7,7 @@ const OUTPUT_SCHEMA_YAML: &str = include_str!("node-types.yml"); /// Helper: parse Ruby source with no rules, return dump. fn parse_and_dump(input: &str) -> String { - let runner = Runner::new(tree_sitter_ruby::LANGUAGE.into(), &[]); + let runner: Runner = Runner::new(tree_sitter_ruby::LANGUAGE.into(), &[]); let ast = runner.run(input).unwrap(); dump_ast(&ast, ast.get_root(), input) } @@ -18,13 +18,23 @@ fn run_and_dump(input: &str, rules: Vec) -> String { run_phased_and_dump(input, vec![Phase::new("test", PhaseKind::Repeating, rules)]) } +/// Helper: parse Ruby source with custom rules and return the transformed AST. +fn run_and_ast(input: &str, rules: Vec) -> Ast { + let lang: tree_sitter::Language = tree_sitter_ruby::LANGUAGE.into(); + let schema = + yeast::node_types_yaml::schema_from_yaml_with_language(OUTPUT_SCHEMA_YAML, &lang).unwrap(); + let phases = vec![Phase::new("test", PhaseKind::Repeating, rules)]; + let runner: Runner = Runner::with_schema(lang, &schema, &phases); + runner.run(input).unwrap() +} + /// Helper: parse Ruby source with a custom output schema and multiple /// rule phases, return dump. fn run_phased_and_dump(input: &str, phases: Vec) -> String { let lang: tree_sitter::Language = tree_sitter_ruby::LANGUAGE.into(); let schema = yeast::node_types_yaml::schema_from_yaml_with_language(OUTPUT_SCHEMA_YAML, &lang).unwrap(); - let runner = Runner::with_schema(lang, &schema, &phases); + let runner: Runner = Runner::with_schema(lang, &schema, &phases); let ast = runner.run(input).unwrap(); dump_ast(&ast, ast.get_root(), input) } @@ -36,7 +46,7 @@ fn run_and_get_error(input: &str, rules: Vec) -> String { let schema = yeast::node_types_yaml::schema_from_yaml_with_language(OUTPUT_SCHEMA_YAML, &lang).unwrap(); let phases = vec![Phase::new("test", PhaseKind::Repeating, rules)]; - let runner = Runner::with_schema(lang, &schema, &phases); + let runner: Runner = Runner::with_schema(lang, &schema, &phases); runner .run(input) .expect_err("expected runner to return an error") @@ -44,7 +54,7 @@ fn run_and_get_error(input: &str, rules: Vec) -> String { /// Helper: parse Ruby source with no rules and dump with schema type errors. fn parse_and_dump_typed(input: &str, schema_yaml: &str) -> String { - let runner = Runner::new(tree_sitter_ruby::LANGUAGE.into(), &[]); + let runner: Runner = Runner::new(tree_sitter_ruby::LANGUAGE.into(), &[]); let ast = runner.run(input).unwrap(); let schema = yeast::node_types_yaml::schema_from_yaml(schema_yaml).unwrap(); dump_ast_with_type_errors(&ast, ast.get_root(), input, &schema) @@ -54,10 +64,10 @@ fn parse_and_dump_typed(input: &str, schema_yaml: &str) -> String { /// building schema with language IDs so field checks align with parser fields. fn parse_and_dump_typed_with_language(input: &str, schema_yaml: &str) -> String { let lang: tree_sitter::Language = tree_sitter_ruby::LANGUAGE.into(); - let runner = Runner::new(lang.clone(), &[]); + let runner: Runner = Runner::new(lang.clone(), &[]); let ast = runner.run(input).unwrap(); - let schema = yeast::node_types_yaml::schema_from_yaml_with_language(schema_yaml, &lang) - .unwrap(); + let schema = + yeast::node_types_yaml::schema_from_yaml_with_language(schema_yaml, &lang).unwrap(); dump_ast_with_type_errors(&ast, ast.get_root(), input, &schema) } @@ -66,7 +76,7 @@ fn run_and_dump_typed(input: &str, rules: Vec, schema_yaml: &str) -> Strin let lang: tree_sitter::Language = tree_sitter_ruby::LANGUAGE.into(); let schema = yeast::node_types_yaml::schema_from_yaml(schema_yaml).unwrap(); let phases = vec![Phase::new("test", PhaseKind::Repeating, rules)]; - let runner = Runner::with_schema(lang, &schema, &phases); + let runner: Runner = Runner::with_schema(lang, &schema, &phases); let ast = runner.run(input).unwrap(); dump_ast_with_type_errors(&ast, ast.get_root(), input, &schema) } @@ -156,7 +166,7 @@ fn test_parse_for_loop() { #[test] fn test_dump_highlights_type_errors_inline() { - let schema_yaml = r#" + let schema_yaml = r#" named: program: $children*: assignment @@ -166,13 +176,13 @@ named: identifier: "#; - let dump = parse_and_dump_typed("x = 1", schema_yaml); - assert!(dump.contains("integer \"1\" <-- ERROR:")); + let dump = parse_and_dump_typed("x = 1", schema_yaml); + assert!(dump.contains("integer \"1\" <-- ERROR:")); } #[test] fn test_dump_reports_preserved_unknown_kind_after_transformation() { - let schema_yaml = r#" + let schema_yaml = r#" named: program: $children*: assignment @@ -182,25 +192,25 @@ named: identifier: "#; - // This rewrite runs and preserves the RHS node kind via capture. - // With schema above, preserving `integer` should be reported inline. - let rules = vec![yeast::rule!( - (assignment left: (_) @left right: (_) @right) - => - (assignment - left: {left} - right: {right} - ) - )]; + // This rewrite runs and preserves the RHS node kind via capture. + // With schema above, preserving `integer` should be reported inline. + let rules: Vec = vec![yeast::rule!( + (assignment left: (_) @left right: (_) @right) + => + (assignment + left: {left} + right: {right} + ) + )]; - let dump = run_and_dump_typed("x = 1", rules, schema_yaml); - assert!(dump.contains("integer \"1\" <-- ERROR:")); - assert!(dump.contains("node kind 'integer' not in schema")); + let dump = run_and_dump_typed("x = 1", rules, schema_yaml); + assert!(dump.contains("integer \"1\" <-- ERROR:")); + assert!(dump.contains("node kind 'integer' not in schema")); } #[test] fn test_dump_reports_undeclared_field_on_node() { - let schema_yaml = r#" + let schema_yaml = r#" named: program: $children*: assignment @@ -209,14 +219,14 @@ named: identifier: "#; - let dump = parse_and_dump_typed_with_language("x = y", schema_yaml); - assert!(dump.contains("right: identifier \"y\" <-- ERROR:")); - assert!(dump.contains("the node 'assignment' has no field 'right'")); + let dump = parse_and_dump_typed_with_language("x = y", schema_yaml); + assert!(dump.contains("right: identifier \"y\" <-- ERROR:")); + assert!(dump.contains("the node 'assignment' has no field 'right'")); } #[test] fn test_dump_reports_disallowed_kind_in_field_type() { - let schema_yaml = r#" + let schema_yaml = r#" named: program: $children*: assignment @@ -227,17 +237,17 @@ named: integer: "#; - let dump = parse_and_dump_typed_with_language("x = 1", schema_yaml); - assert!(dump.contains("right: integer \"1\" <-- ERROR:")); - assert!(dump.contains("should contain")); - assert!(dump.contains("but got integer")); + let dump = parse_and_dump_typed_with_language("x = 1", schema_yaml); + assert!(dump.contains("right: integer \"1\" <-- ERROR:")); + assert!(dump.contains("should contain")); + assert!(dump.contains("but got integer")); } // ---- Query tests ---- #[test] fn test_query_match() { - let runner = Runner::new(tree_sitter_ruby::LANGUAGE.into(), &[]); + let runner: Runner = Runner::new(tree_sitter_ruby::LANGUAGE.into(), &[]); let ast = runner.run("x = 1").unwrap(); let query = yeast::query!( @@ -258,7 +268,7 @@ fn test_query_match() { #[test] fn test_query_no_match() { - let runner = Runner::new(tree_sitter_ruby::LANGUAGE.into(), &[]); + let runner: Runner = Runner::new(tree_sitter_ruby::LANGUAGE.into(), &[]); let ast = runner.run("x = 1").unwrap(); let query = yeast::query!( @@ -283,7 +293,7 @@ fn test_query_skips_extras_in_positional_match() { // captured comment to nothing (a common idiom, e.g. // `(comment) => ()` in Swift) leaves the capture's match-list empty // and causes the transform to fail with "Variable X has 0 matches". - let runner = Runner::new(tree_sitter_ruby::LANGUAGE.into(), &[]); + let runner: Runner = Runner::new(tree_sitter_ruby::LANGUAGE.into(), &[]); let ast = runner.run("[1, # comment\n2]").unwrap(); // Navigate to the `array` node: program -> array. @@ -299,15 +309,11 @@ fn test_query_skips_extras_in_positional_match() { let matched = query.do_match(&ast, array_id, &mut captures).unwrap(); assert!(matched); assert_eq!( - ast.get_node(captures.get_var("a").unwrap()) - .unwrap() - .kind(), + ast.get_node(captures.get_var("a").unwrap()).unwrap().kind(), "integer" ); assert_eq!( - ast.get_node(captures.get_var("b").unwrap()) - .unwrap() - .kind(), + ast.get_node(captures.get_var("b").unwrap()).unwrap().kind(), "integer" ); } @@ -315,14 +321,14 @@ fn test_query_skips_extras_in_positional_match() { #[test] fn test_reachable_nodes_excludes_orphaned_rewrite_nodes() { let lang: tree_sitter::Language = tree_sitter_ruby::LANGUAGE.into(); - let schema = yeast::node_types_yaml::schema_from_yaml_with_language(OUTPUT_SCHEMA_YAML, &lang) - .unwrap(); - let phases = vec![Phase::new( + let schema = + yeast::node_types_yaml::schema_from_yaml_with_language(OUTPUT_SCHEMA_YAML, &lang).unwrap(); + let phases: Vec = vec![Phase::new( "test", PhaseKind::Repeating, vec![yeast::rule!((integer) => (identifier "replaced"))], )]; - let runner = Runner::with_schema(lang, &schema, &phases); + let runner: Runner = Runner::with_schema(lang, &schema, &phases); let input = "x = 1"; let ast = runner.run(input).unwrap(); @@ -340,7 +346,7 @@ fn test_reachable_nodes_excludes_orphaned_rewrite_nodes() { #[test] fn test_query_repeated_capture() { - let runner = Runner::new(tree_sitter_ruby::LANGUAGE.into(), &[]); + let runner: Runner = Runner::new(tree_sitter_ruby::LANGUAGE.into(), &[]); let ast = runner.run("x, y, z = 1").unwrap(); let query = yeast::query!( @@ -365,7 +371,7 @@ fn test_query_repeated_capture() { #[test] fn test_capture_unnamed_node_parenthesized() { // `("=") @op` captures the unnamed `=` token between left and right. - let runner = Runner::new(tree_sitter_ruby::LANGUAGE.into(), &[]); + let runner: Runner = Runner::new(tree_sitter_ruby::LANGUAGE.into(), &[]); let ast = runner.run("x = 1").unwrap(); let query = yeast::query!( @@ -389,10 +395,33 @@ fn test_capture_unnamed_node_parenthesized() { assert!(!op_node.is_named()); } +#[test] +fn test_capture_bare_underscore_repeated() { + // `_` matches named and unnamed nodes in bare-child position. On this + // assignment shape, bare children correspond to unnamed tokens (the `=`). + let runner: Runner = Runner::new(tree_sitter_ruby::LANGUAGE.into(), &[]); + let ast = runner.run("x = 1").unwrap(); + + let query = yeast::query!((assignment _* @all)); + + let mut cursor = AstCursor::new(&ast); + cursor.goto_first_child(); + let assignment_id = cursor.node_id(); + + let mut captures = yeast::captures::Captures::new(); + let matched = query.do_match(&ast, assignment_id, &mut captures).unwrap(); + assert!(matched); + + let all = captures.get_all("all"); + assert_eq!(all.len(), 1); + assert_eq!(ast.get_node(all[0]).unwrap().kind(), "="); + assert!(!ast.get_node(all[0]).unwrap().is_named()); +} + #[test] fn test_capture_unnamed_node_bare_literal() { // `"=" @op` (without surrounding parens) is the same as `("=") @op`. - let runner = Runner::new(tree_sitter_ruby::LANGUAGE.into(), &[]); + let runner: Runner = Runner::new(tree_sitter_ruby::LANGUAGE.into(), &[]); let ast = runner.run("x = 1").unwrap(); let query = yeast::query!( @@ -421,7 +450,7 @@ fn test_bare_underscore_matches_unnamed() { // Bare `_` matches any node, including unnamed tokens, while `(_)` // matches only named nodes. Demonstrate by matching the unnamed `=` // token in the implicit `child` field of an `assignment`. - let runner = Runner::new(tree_sitter_ruby::LANGUAGE.into(), &[]); + let runner: Runner = Runner::new(tree_sitter_ruby::LANGUAGE.into(), &[]); let ast = runner.run("x = 1").unwrap(); let mut cursor = AstCursor::new(&ast); @@ -460,7 +489,7 @@ fn test_bare_forms_in_field_position() { // field's value, not just in the bare-children position. This is // syntactic sugar for `(_)` / `("…")` and goes through the same // code paths. - let runner = Runner::new(tree_sitter_ruby::LANGUAGE.into(), &[]); + let runner: Runner = Runner::new(tree_sitter_ruby::LANGUAGE.into(), &[]); let ast = runner.run("x = 1").unwrap(); let mut cursor = AstCursor::new(&ast); @@ -499,7 +528,7 @@ fn test_forward_scan_finds_unnamed_token_late() { // query for `("end")` skip past the first two and match the third. // Without forward-scan, the matcher took the first child unconditionally // and failed. - let runner = Runner::new(tree_sitter_ruby::LANGUAGE.into(), &[]); + let runner: Runner = Runner::new(tree_sitter_ruby::LANGUAGE.into(), &[]); let ast = runner.run("for x in list do\n y\nend").unwrap(); // Navigate: program > for > do (the body wrapper). @@ -526,7 +555,7 @@ fn test_forward_scan_preserves_order() { // order. A query for ("end") then ("do") should fail because `do` // appears before `end` in the source order; once forward-scan has // consumed `end`, the iterator is exhausted. - let runner = Runner::new(tree_sitter_ruby::LANGUAGE.into(), &[]); + let runner: Runner = Runner::new(tree_sitter_ruby::LANGUAGE.into(), &[]); let ast = runner.run("for x in list do\n y\nend").unwrap(); let mut cursor = AstCursor::new(&ast); @@ -547,7 +576,7 @@ fn test_forward_scan_preserves_order() { #[test] fn test_tree_builder() { - let runner = Runner::new(tree_sitter_ruby::LANGUAGE.into(), &[]); + let runner: Runner = Runner::new(tree_sitter_ruby::LANGUAGE.into(), &[]); let mut ast = runner.run("x = 1").unwrap(); let input = "x = 1"; @@ -565,7 +594,8 @@ fn test_tree_builder() { // Swap left and right let fresh = yeast::tree_builder::FreshScope::new(); - let mut ctx = yeast::build::BuildCtx::new(&mut ast, &captures, &fresh); + let mut user_ctx = (); + let mut ctx = yeast::build::BuildCtx::new(&mut ast, &captures, &fresh, &mut user_ctx); let new_id = yeast::tree!(ctx, (program child: (assignment @@ -593,7 +623,7 @@ fn test_tree_builder() { // tree-sitter-ruby grammar with named fields for nodes that only have // unnamed children in tree-sitter (e.g. block_body.stmt, block_parameters.parameter). fn ruby_rules() -> Vec { - let assign_rule = yeast::rule!( + let assign_rule: Rule = yeast::rule!( (assignment left: (left_assignment_list (identifier)* @left @@ -618,7 +648,7 @@ fn ruby_rules() -> Vec { )} ); - let for_rule = yeast::rule!( + let for_rule: Rule = yeast::rule!( (for pattern: (_) @pat value: (in (_) @val) @@ -700,7 +730,7 @@ fn test_desugar_for_loop() { #[test] fn test_shorthand_rule() { - let rule = yeast::rule!( + let rule: Rule = yeast::rule!( (assignment left: (_) @method right: (_) @receiver @@ -852,7 +882,7 @@ fn test_phase_error_includes_phase_name() { PhaseKind::Repeating, vec![swap_assignment_rule().repeated()], )]; - let runner = Runner::with_schema(lang, &schema, &phases); + let runner: Runner = Runner::with_schema(lang, &schema, &phases); let err = runner .run("x = 1") .expect_err("expected runner to return an error"); @@ -895,7 +925,7 @@ fn test_one_shot_phase() { PhaseKind::OneShot, one_shot_xeq1_rules(), )]; - let runner = Runner::with_schema(lang, &schema, &phases); + let runner: Runner = Runner::with_schema(lang, &schema, &phases); let input = "x = 1"; let ast = runner.run(input).unwrap(); @@ -921,7 +951,7 @@ fn test_one_shot_phase_errors_when_no_rule_matches() { let mut rules = one_shot_xeq1_rules(); rules.pop(); let phases = vec![Phase::new("translate", PhaseKind::OneShot, rules)]; - let runner = Runner::with_schema(lang, &schema, &phases); + let runner: Runner = Runner::with_schema(lang, &schema, &phases); let err = runner .run("x = 1") @@ -945,7 +975,7 @@ fn test_one_shot_recurses_into_returned_capture() { let lang: tree_sitter::Language = tree_sitter_ruby::LANGUAGE.into(); let schema = yeast::node_types_yaml::schema_from_yaml_with_language(OUTPUT_SCHEMA_YAML, &lang).unwrap(); - let rules = vec![ + let rules: Vec = vec![ yeast::rule!( (program (_)* @stmts) => @@ -961,7 +991,7 @@ fn test_one_shot_recurses_into_returned_capture() { yeast::rule!((integer) => (integer "INT")), ]; let phases = vec![Phase::new("translate", PhaseKind::OneShot, rules)]; - let runner = Runner::with_schema(lang, &schema, &phases); + let runner: Runner = Runner::with_schema(lang, &schema, &phases); let input = "x = 1"; let ast = runner.run(input).unwrap(); @@ -987,7 +1017,7 @@ fn test_one_shot_does_not_recurse_into_wrapper_output() { let lang: tree_sitter::Language = tree_sitter_ruby::LANGUAGE.into(); let schema = yeast::node_types_yaml::schema_from_yaml_with_language(OUTPUT_SCHEMA_YAML, &lang).unwrap(); - let rules = vec![ + let rules: Vec = vec![ yeast::rule!( (program (_)* @stmts) => @@ -1008,7 +1038,7 @@ fn test_one_shot_does_not_recurse_into_wrapper_output() { yeast::rule!((integer) => (integer "INT")), ]; let phases = vec![Phase::new("translate", PhaseKind::OneShot, rules)]; - let runner = Runner::with_schema(lang, &schema, &phases); + let runner: Runner = Runner::with_schema(lang, &schema, &phases); let input = "x = 1"; let ast = runner.run(input).unwrap(); @@ -1032,7 +1062,7 @@ fn test_one_shot_does_not_recurse_into_wrapper_output() { #[test] fn test_cursor_navigation() { - let runner = Runner::new(tree_sitter_ruby::LANGUAGE.into(), &[]); + let runner: Runner = Runner::new(tree_sitter_ruby::LANGUAGE.into(), &[]); let ast = runner.run("x = 1").unwrap(); let mut cursor = AstCursor::new(&ast); @@ -1106,7 +1136,7 @@ fn test_desugar_for_with_multiple_assignment() { /// resolves to the captured node's source text via `YeastDisplay`. #[test] fn test_hash_brace_renders_capture_source_text() { - let rule = rule!( + let rule: Rule = rule!( (call method: (identifier) @name receiver: (identifier) @recv @@ -1135,7 +1165,7 @@ fn test_hash_brace_renders_capture_source_text() { /// `Display` impl (covered by `YeastDisplay`'s blanket impls for primitives). #[test] fn test_hash_brace_renders_integer_expression() { - let rule = rule!( + let rule: Rule = rule!( (identifier) @_ => (identifier #{1 + 2}) @@ -1149,3 +1179,39 @@ fn test_hash_brace_renders_integer_expression() { "#, ); } + +/// Regression test: `(kind #{capture})` should inherit the captured node's +/// source location, not the full source range of the matched rule root. +#[test] +fn test_hash_brace_uses_capture_location_for_leaf() { + let rule: Rule = rule!( + (call + method: (identifier) @name + receiver: (identifier) @recv + ) + => + (call + method: (identifier #{name}) + receiver: (identifier #{recv}) + arguments: (argument_list) + ) + ); + + let ast = run_and_ast("foo.bar()", vec![rule]); + + let mut bar_ids: Vec = Vec::new(); + for id in ast.reachable_node_ids() { + let Some(node) = ast.get_node(id) else { + continue; + }; + if node.kind() == "identifier" && ast.source_text(id) == "bar" { + bar_ids.push(id); + } + } + + assert_eq!(bar_ids.len(), 1, "expected exactly one identifier 'bar'"); + let bar = ast.get_node(bar_ids[0]).unwrap(); + + assert_eq!(bar.start_byte(), 4); + assert_eq!(bar.end_byte(), 7); +} diff --git a/swift/ql/lib/CHANGELOG.md b/swift/ql/lib/CHANGELOG.md index 1eb5afb48e7..1d75e0d4eb1 100644 --- a/swift/ql/lib/CHANGELOG.md +++ b/swift/ql/lib/CHANGELOG.md @@ -1,3 +1,7 @@ +## 6.7.1 + +No user-facing changes. + ## 6.7.0 ### Major Analysis Improvements diff --git a/swift/ql/lib/change-notes/released/6.7.1.md b/swift/ql/lib/change-notes/released/6.7.1.md new file mode 100644 index 00000000000..25234a20eda --- /dev/null +++ b/swift/ql/lib/change-notes/released/6.7.1.md @@ -0,0 +1,3 @@ +## 6.7.1 + +No user-facing changes. diff --git a/swift/ql/lib/codeql-pack.release.yml b/swift/ql/lib/codeql-pack.release.yml index 55a13d309e5..9512a723a32 100644 --- a/swift/ql/lib/codeql-pack.release.yml +++ b/swift/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 6.7.0 +lastReleaseVersion: 6.7.1 diff --git a/swift/ql/lib/qlpack.yml b/swift/ql/lib/qlpack.yml index 960d679e6d9..1000e5b25b9 100644 --- a/swift/ql/lib/qlpack.yml +++ b/swift/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/swift-all -version: 6.7.1-dev +version: 6.7.2-dev groups: swift extractor: swift dbscheme: swift.dbscheme diff --git a/swift/ql/src/CHANGELOG.md b/swift/ql/src/CHANGELOG.md index 4e3b53c37b3..d185e3d5428 100644 --- a/swift/ql/src/CHANGELOG.md +++ b/swift/ql/src/CHANGELOG.md @@ -1,3 +1,9 @@ +## 1.3.5 + +### Minor Analysis Improvements + +* Fixed an issue where common usage patterns for `CryptoKit` weren't being recognized as hashing sinks for the `swift/weak-sensitive-data-hashing` and `swift/weak-password-hashing` queries. These queries may find additional results after this change. + ## 1.3.4 No user-facing changes. diff --git a/swift/ql/src/change-notes/2026-05-26-hashing-sinks.md b/swift/ql/src/change-notes/released/1.3.5.md similarity index 85% rename from swift/ql/src/change-notes/2026-05-26-hashing-sinks.md rename to swift/ql/src/change-notes/released/1.3.5.md index 92a2c1c3a06..c272a72df50 100644 --- a/swift/ql/src/change-notes/2026-05-26-hashing-sinks.md +++ b/swift/ql/src/change-notes/released/1.3.5.md @@ -1,4 +1,5 @@ ---- -category: minorAnalysis ---- +## 1.3.5 + +### Minor Analysis Improvements + * Fixed an issue where common usage patterns for `CryptoKit` weren't being recognized as hashing sinks for the `swift/weak-sensitive-data-hashing` and `swift/weak-password-hashing` queries. These queries may find additional results after this change. diff --git a/swift/ql/src/codeql-pack.release.yml b/swift/ql/src/codeql-pack.release.yml index 8263ddf2c8b..1e1845ea66d 100644 --- a/swift/ql/src/codeql-pack.release.yml +++ b/swift/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.3.4 +lastReleaseVersion: 1.3.5 diff --git a/swift/ql/src/qlpack.yml b/swift/ql/src/qlpack.yml index 578456c089a..de366deabb7 100644 --- a/swift/ql/src/qlpack.yml +++ b/swift/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/swift-queries -version: 1.3.5-dev +version: 1.3.6-dev groups: - swift - queries diff --git a/swift/tools/tracing-config.lua b/swift/tools/tracing-config.lua index 22ce71b2e78..f0f569e1e86 100644 --- a/swift/tools/tracing-config.lua +++ b/swift/tools/tracing-config.lua @@ -62,6 +62,8 @@ function RegisterExtractorPack(id) strip_unsupported_clang_arg(args, '-clang-vendor-feature=+thisNoAlignAttr', 0) strip_unsupported_clang_arg(args, '-clang-vendor-feature=+thisNoNullAttr', 0) strip_unsupported_clang_arg(args, '-clang-vendor-feature=+disableAtImportPrivateFrameworkInImplementationError', 0) + strip_unsupported_clang_arg(args, '-Werror=allocator-wrappers', 0) + strip_unsupported_clang_arg(args, '-Wno-error=allocator-wrappers', 0) -- The four args below are removed to workaround version mismatches due to recent versions -- of Xcode defaulting to explicit modules: strip_unsupported_arg(args, '-disable-implicit-swift-modules', 0) diff --git a/unified/AGENTS.md b/unified/AGENTS.md index aa5007a5656..6c7d697896f 100644 --- a/unified/AGENTS.md +++ b/unified/AGENTS.md @@ -3,25 +3,21 @@ This is a CodeQL extractor based on tree-sitter. ## Building -To build the extractor, run `scripts/create-extractor-pack.sh` +- To build the extractor, run `scripts/create-extractor-pack.sh` -## Editing the Swift grammar -The vendored tree-sitter-swift grammar lives at -`extractor/tree-sitter-swift/`. After editing `grammar.js` (or any other -grammar source), run `scripts/regenerate-grammar.sh` to: -- regenerate `extractor/tree-sitter-swift/src/{parser.c, grammar.json, - node-types.json}` (and the `src/tree_sitter/*.h` headers) via - `tree-sitter generate`; and -- refresh `extractor/tree-sitter-swift/node-types.yml`, the - human-readable companion to `src/node-types.json` produced by yeast's - `node_types_yaml` binary. +## Swift Parser +- The Swift parser is defined by `extractor/tree-sitter-swift/grammar.js` and can be edited if needed. -`node-types.yml` is the recommended review surface for grammar changes — -it shows the impact of a grammar tweak on the named node kinds, fields, -and child types in a form much easier to read than the raw JSON. +- After editing the grammar, always run `scripts/regenerate-grammar.sh`. -## Extractor Testing -- To run extractor tests, run `cargo test` in the `extractor` directory. +- The raw parse tree is described by `extractor/tree-sitter-swift/node-types.yml` and should be reviewed after grammar changes. + +## AST Mapping +- The target AST shape is described by `extractor/ast_types.yml`. + +- The mapping from the parse tree to the target AST is found in `extractor/src/languages/swift/swift.rs` + +- To run tests for the parser and mapping, run `cargo test` in the `extractor` directory. - Do not edit the printed ASTs in `extractor/test/corpus` directly. To regenerate the ASTs, run `scripts/update-corpus.sh`. diff --git a/unified/extractor/BUILD.bazel b/unified/extractor/BUILD.bazel index 80ca1c0057b..0ef7f1b68b0 100644 --- a/unified/extractor/BUILD.bazel +++ b/unified/extractor/BUILD.bazel @@ -7,6 +7,7 @@ codeql_rust_binary( name = "extractor", srcs = glob(["src/**/*.rs"]), aliases = aliases(), + compile_data = ["ast_types.yml"], proc_macro_deps = all_crate_deps( proc_macro = True, ), diff --git a/unified/extractor/ast_types.yml b/unified/extractor/ast_types.yml index 22a5e8b19fb..73f8ac7f66d 100644 --- a/unified/extractor/ast_types.yml +++ b/unified/extractor/ast_types.yml @@ -2,36 +2,103 @@ supertypes: expr: - name_expr - int_literal + - float_literal + - boolean_literal - string_literal + - regex_literal + - builtin_expr - binary_expr - unary_expr - call_expr - member_access_expr - - lambda_expr - - unsupported_node - stmt: - - empty_stmt - - block_stmt - - expr_stmt - - if_stmt - - variable_declaration_stmt - - guard_if_stmt - - unsupported_node - condition: - - expr_condition - - let_pattern_condition - - sequence_condition + - super_expr + - function_expr + - array_literal + - map_literal + - key_value_pair + - tuple_expr + - type_cast_expr + - type_test_expr + - if_expr + - assign_expr + - compound_assign_expr + - pattern_guard_expr + - empty_expr + - block + - break_expr + - continue_expr + - return_expr + - throw_expr + - try_expr + - switch_expr - unsupported_node + expr_or_pattern: + - expr + - pattern + expr_or_type: + - expr + - type_expr pattern: - - var_pattern - - apply_pattern + - name_pattern - tuple_pattern + - constructor_pattern - ignore_pattern + - expr_equality_pattern + - bulk_importing_pattern - unsupported_node + # A statement is anything that can appear in a block. + # This type contains all of 'expr' and has partial overlap with 'member'. + # For example, type_alias_declaration can appear either as a stmt or member. + # constructor_declaration and destructor_declaration appear here because + # tree-sitter-swift's error recovery for #if/#endif in class bodies can place + # init/deinit declarations at the wrong (statement) level. + stmt: + - expr + - variable_declaration + - type_alias_declaration + - function_declaration + - import_declaration + - operator_syntax_declaration + - class_like_declaration + - accessor_declaration + - constructor_declaration + - destructor_declaration + - guard_if_stmt + - for_each_stmt + - while_stmt + - do_while_stmt + - labeled_stmt + # A member is anything that can appear in the body of a class-like declaration + member: + - constructor_declaration + - destructor_declaration + - function_declaration + - variable_declaration + - accessor_declaration + - initializer_declaration + - class_like_declaration + - type_alias_declaration + - associated_type_declaration + - unsupported_node + type_expr: + - named_type_expr + - generic_type_expr + - tuple_type_expr + - function_type_expr + - inferred_type_expr + - unsupported_node + type_constraint: + - equality_type_constraint + - bound_type_constraint + operator: + - infix_operator + - prefix_operator + - postfix_operator named: - # Top-level is the root node, currently containing a list of expressions + # Top-level is the root node, containing a single block of statements + # (which are themselves expressions or declarations). top_level: - body*: [expr, stmt] + body: block # An identifier used in the context of an expression name_expr: @@ -40,13 +107,28 @@ named: # An integer literal int_literal: + # A floating-point literal + float_literal: + + # A boolean literal + boolean_literal: + + # A literal backed by a keyword such as `nil`, `null`, or `nullptr`. + # + # Although nil/null are keyword literals in many languages there should be + # no attempt to normalize "null-like" named entities, like Python's `None`. + builtin_expr: + # A string literal string_literal: + # A regex literal + regex_literal: + # Application of a binary operator, such as `a + b` binary_expr: left: expr - operator: operator + operator: infix_operator right: expr # Application of a unary operator, such as `!x` @@ -54,86 +136,310 @@ named: operand: expr operator: operator - # A function or method call, such as `f(x)` or `obj.m(x)`. Method calls - # are represented as a call whose `function` is a `member_access_expr`. + # Plain assignment + assign_expr: + target: expr_or_pattern + value: expr + + # Compound assignment + compound_assign_expr: + target: expr + operator: infix_operator + value: expr + + # A function or method call, such as `f(x)` or `obj.m(x)`. + # + # Method calls are represented as a call whose `function` is a `member_access_expr`. + # + # Constructor calls are marked by a language-specific modifier, and the target may be + # a `type_expr` if the parser can deduce that the target is a type. call_expr: - function: expr - argument*: expr + modifier*: modifier + callee: expr_or_type + argument*: argument + + argument: + modifier*: modifier + name?: identifier + value: expr # Member access, such as `obj.member`. + # + # The base may be a type expression when it is a static member access like `Array.method`. + # In ambiguous cases where the parser cannot distinguish static and instance member access, the base + # will be typically be an expression. + # + # For `super.x` the base will be an instance of `super_expr`. member_access_expr: - target: expr + base: expr_or_type member: identifier - lambda_expr: + # A type expression that refers to a type inferred from the contextual type. + # This is used to translate Swift's leading-dot syntax, `.foo`, which means `T.foo` where + # `T` is the contextual type of some enclosing expression. This is translated to a member_access + # with an inferred_type_expr as the base. + inferred_type_expr: + + # A `super` token, which can usually only appear as the base of member access. + super_expr: + + function_expr: + modifier*: modifier + capture_declaration*: variable_declaration parameter*: parameter - body: [expr, stmt] + return_type?: type_expr + body: block - # A parameter + array_literal: + element*: expr + + map_literal: + element*: expr + + # A key-value pair, usually appearing as a named argument or as part of a map literal. + # + # For some languages, the key-value pair is a first class value and this type of expression + # may thus appear anywhere in the general case. + key_value_pair: + key: expr + value: expr + + # A tuple expression, such as `(a, b, c)`. + tuple_expr: + element*: expr + + # A parameter. + # + # `type` is its declared type annotation (if any) + # + # `pattern` binds the parameter's internal name(s). For a simple parameter this is a + # `name_pattern`, but may be an arbitrary pattern for languages where patterns may appear + # in the parameter list. + # + # `external_name` is the name by which to call sites refer to the parameter, if the parameter + # can be passed as a named parameter. For example, the Swift function `func greet(person id: String)` + # would have `person` as the external name and a `name_pattern` wrapping `id` is the parameter's pattern. parameter: + modifier*: modifier + external_name?: identifier + type?: type_expr + pattern?: pattern + default?: expr + + # An expression that does nothing. Used where the grammar permits an + # empty statement (e.g. a stray `;`). + empty_expr: + + # A brace-delimited sequence of statements (`{ ... }`). Blocks are the + # only nodes that can directly contain statements; every other body-like + # field holds a single `block`. + block: + stmt*: stmt + + if_expr: + condition: expr + then?: expr + else?: expr + + # A variable declaration or destructuring assignment that introduces new variables. + # + # Any occurrence of `var_patterns` in 'pattern' result in fresh bindings that are + # in scope for the rest of the enclosing block. + # + # The initializer is optional (but typically cannot be omitted if combined with a non-trivial pattern). + # + # Modifiers should include 'var', 'let', 'const', etc, if they are significant. + # A grouped declaration like `let x = 1, y = 2` is emitted as a sequence of + # `variable_declaration`s directly into the enclosing stmt/member slot; every + # declaration after the first in such a group is tagged with a synthetic + # `chained_declaration` modifier so the grouping can be recovered downstream. + variable_declaration: + modifier*: modifier pattern: pattern - - empty_stmt: - - block_stmt: - body*: stmt - - expr_stmt: - expr: expr - - if_stmt: - condition: condition - then?: stmt - else?: stmt - - variable_declaration_stmt: - variable_declarator+: variable_declarator - - # A variable declaration, or assignment to a pattern. - # The initializer is optional (but typically only possible in combination with a simple variable pattern). - variable_declarator: - pattern: pattern + type?: type_expr value?: expr # Evaluate 'condition', and if false, execute 'else' which must break from the enclosing block scope (return, break, etc). # Any variables bound by 'condition' will be in scope for the remainder of the enclosing block scope - # (which differs from how if_stmt works). + # (which differs from how if_expr works). guard_if_stmt: - condition: condition - else: stmt + condition: expr + else: block - # Evaluates the given condition and interprets it as a boolean (by language conventions) - expr_condition: - expr: expr + # `break` (with optional label) + break_expr: + label?: identifier - # A series of statements that are executed before evaluating the trailing condition. - # Useful for languages where a conditional clause may be preceded by side-effecting - # syntactic elements (e.g. binding clauses) that don't themselves form a condition. - sequence_condition: - stmt*: stmt - condition: condition + # `continue` (with optional label) + continue_expr: + label?: identifier + + # A labeled statement, such as `outer: for ... { ... }`. The labeled + # statement appears as the `stmt` field; `break`/`continue` may target + # the label. + labeled_stmt: + label: identifier + stmt: stmt + + # `return value` or bare `return` + return_expr: + value?: expr + + # `throw value` + throw_expr: + value?: expr + + # An import declaration. + # + # The semantics of an import are generally: + # - Evaluate the 'imported_expr' to a value (possibly a compile-time value, such as namespace) + # - Filter away possible values based on modifiers (e.g. type-only imports only accept types) + # - Assign the value to the pattern, binding variables and/or type names in scope + # + import_declaration: + modifier*: modifier + imported_expr: expr # Qualified names are encoded as a chain of member_access_expr ending with a name_expr + pattern?: pattern # Binds local names in scope (possibly via bulk_importing_pattern) + + # `typealias Name = Type` + type_alias_declaration: + modifier*: modifier + name: identifier + type_parameter*: type_parameter + type_constraint*: type_constraint + type: type_expr + + # A top-level function declaration. + function_declaration: + modifier*: modifier + name: identifier + type_parameter*: type_parameter + type_constraint*: type_constraint + parameter*: parameter + return_type?: type_expr + body?: block + + # `for pattern in iterable [where guard] { body }`. + for_each_stmt: + modifier*: modifier + pattern: pattern + iterable: expr + guard?: expr + body?: block + + # `while condition { body }`. + while_stmt: + modifier*: modifier + condition: expr + body?: block + + # `repeat { body } while condition`. + do_while_stmt: + modifier*: modifier + body?: block + condition: expr + + # `do { body } catch pattern { ... } catch ...`. Swift uses `do`/`catch` + # for error handling; for languages with `try`/`catch`, this is the same shape. + try_expr: + modifier*: modifier + body: block + catch_clause*: catch_clause + + catch_clause: + modifier*: modifier + pattern?: pattern + guard?: expr + body: block + + # `switch value { case pattern: body case ...: default: body }` + switch_expr: + modifier*: modifier + value: expr + case*: switch_case + + # A single `case ...:` (or `default:`) entry in a switch. + # An entry with multiple `case p1, p2:` patterns has multiple `pattern`s. + # A `default:` entry has no patterns. + # An optional `guard` corresponds to a `where`-clause on the case. + switch_case: + modifier*: modifier + pattern*: pattern + guard?: expr + body: block # Evaluate 'expr' and match its result against 'pattern', and return true if it matches. - # Variables bound by the pattern will be in scope within the 'true' branch controlled by this condition. - let_pattern_condition: + # Variables bound by the pattern will be in scope within the 'true' branch controlled by this expression. + # + # In Swift, `if case let PATTERN = EXPR` maps to this node + # + # Java: 'if (x instanceof Foo y && w ...) { ... }' + pattern_guard_expr: pattern: pattern value: expr - # A pattern matching anything, binding its value to the given variable - var_pattern: + # A type cast expression, such as `x as T`, `x as? T`, or `x as! T`. The + # operator distinguishes between the variants. + type_cast_expr: + expr: expr + operator: infix_operator + type: type_expr + + # A type-test expression, such as `x is T`. Yields a boolean indicating + # whether `expr` is an instance of `type`. + type_test_expr: + expr: expr + operator: infix_operator + type: type_expr + + # An identifier that introduces a variable. + # + # When used as a pattern, the pattern matches anything and binds its incoming value to the variable + name_pattern: + modifier*: modifier identifier: identifier # A pattern matching anything, binding no variables, usually using the syntax "_" ignore_pattern: - # A pattern such as `Some(x)` where `Some` is the constructor and `x` is an argument - apply_pattern: - constructor: expr - argument*: pattern + # A pattern that matches if the incoming value is equal to the value of the given expression. + # Used for literal patterns in switch (e.g. `case 1:`). + expr_equality_pattern: + expr: expr # A tuple pattern such as `(a, b)` in `let (a, b) = pair`. + # + # Elements of the tuple pattern can have names, such as Swift's `let (foo: x, bar: y) = tuple`. tuple_pattern: - element*: pattern + modifier*: modifier + element*: pattern_element + + # A pattern such as `Some(x)` where `Some` is the constructor and `x` is an element. + # The element names are interpreted as argument labels and/or field names. + constructor_pattern: + modifier*: modifier + constructor: expr_or_type + element*: pattern_element + + # A pattern with an optional associated name. + pattern_element: + modifier*: modifier + key?: identifier + pattern: pattern + + # A pattern that checks if the incoming value has the given type, and if so, the + # value is matched against the given nested pattern (and succeeds iff the nested match succeeds). + # + # In Swift: `if let y = x as? Foo` is a pattern_guard_expr containing a type_test_pattern + # In Java: `x instanceof Foo y` is a type_test_pattern wrapping a name_pattern + type_test_pattern: + pattern: pattern + type: type_expr + + # A '*' pattern that imports all members of the incoming value into the local scope + # Currently this can only appear in import declarations. + bulk_importing_pattern: + modifier*: modifier # An simple unqualified identifier token identifier: @@ -141,4 +447,129 @@ named: # A node that we don't yet translate unsupported_node: - operator: + infix_operator: + + prefix_operator: + + postfix_operator: + + # The fixity of a custom operator declaration (e.g. "prefix", "infix", + # "postfix"). The value is the keyword string. + fixity: + + type_parameter: + modifier*: modifier + name: identifier + bound?: type_expr + + # A generic constraint of the form `T == U`, requiring two types to be + # equal. Appears in `where` clauses on generic declarations + # (e.g. Swift `func foo() where T == U`). + equality_type_constraint: + left: type_expr + right: type_expr + + # A generic constraint of the form `T: Bound`, requiring a type parameter + # to conform to (or inherit from) some other type. Appears in `where` + # clauses on generic declarations (e.g. Swift `where T: Equatable`). + bound_type_constraint: + type: type_expr + bound: type_expr + + # `infix operator +++` (and the like) — a declaration of a custom operator. + operator_syntax_declaration: + modifier*: modifier + name: identifier + # The fixity specifier (`prefix`, `infix`, `postfix`), when applicable. + fixity?: fixity + # The declared precedence level, when present (e.g. Swift's + # `infix operator +++ : AdditionPrecedence`). + precedence?: expr + + # A class-like declaration: class, struct, interface (protocol), enum (or actor). + # The syntactic kind is carried as a `modifier` (e.g. "class", "struct", + # "interface", "enum", "extension"). The `"enum_case"` modifier additionally + # marks a declaration as an enum case with associated values. Extensions are + # represented as a class-like declaration with the `"extension"` modifier and + # no `name`; the extended type appears as a `base_type`. + class_like_declaration: + modifier*: modifier + name?: identifier + type_parameter*: type_parameter + type_constraint*: type_constraint + base_type*: base_type + member*: member + + # One of the base types of a class declaration. + # + # If the language has multiple kinds of base classes (e.g. extends/implements) the + # kind should be included as a modifier on this node. + base_type: + modifier*: modifier + type: type_expr + + constructor_declaration: + modifier*: modifier + name?: identifier + parameter*: parameter + body: block + + # A destructor / finalizer (Swift `deinit`, C++ `~T()`, etc.). + destructor_declaration: + modifier*: modifier + body: block + + # Declaration of a single accessor for a property (such as a getter, setter, + # or observer like Swift's `willSet`/`didSet`). + # + # Multiple accessors for the same property are emitted as a sequence of + # accessor_declaration nodes; every accessor after the first is tagged with + # a synthetic `chained_declaration` modifier so the grouping can be recovered + # downstream. Stored properties with observers are emitted as a + # variable_declaration followed by one accessor_declaration per observer + # (each observer also tagged with `chained_declaration`). + accessor_declaration: + modifier*: modifier + name: identifier + accessor_kind: accessor_kind + parameter*: parameter + type?: type_expr + body?: block + + # "get", "set", or a language-specific kind like "didSet" + accessor_kind: + + # Static or instance initializer block. That is, code that runs at initialization time of either the class or an instance. + initializer_declaration: + modifier*: modifier + body: block + + associated_type_declaration: + modifier*: modifier + name: identifier + bound?: type_expr + + named_type_expr: + qualifier?: type_expr + name: identifier + + generic_type_expr: + base: type_expr + type_argument*: type_expr + + # A tuple type such as `(Int, String)` or `(a: A, b: B)`. + tuple_type_expr: + element*: tuple_type_element + + # An element of a `tuple_type_expr`, optionally carrying a label. + tuple_type_element: + name?: identifier + type: type_expr + + # A function type such as `(Int, String) -> Bool` or `(x: Int) -> Bool`. + function_type_expr: + parameter*: parameter + return_type: type_expr + + # A modifier such as 'static', 'public', or 'async'. For now this is just a leaf node with a string value. + modifier: diff --git a/unified/extractor/src/extractor.rs b/unified/extractor/src/extractor.rs index 7601fa8addb..301c6cf533f 100644 --- a/unified/extractor/src/extractor.rs +++ b/unified/extractor/src/extractor.rs @@ -1,9 +1,9 @@ use clap::Args; use std::path::PathBuf; +use crate::languages; use codeql_extractor::extractor::simple; use codeql_extractor::trap; -use crate::languages; #[derive(Args)] pub struct Options { @@ -35,7 +35,9 @@ pub fn run(options: Options) -> std::io::Result<()> { prefix: "unified".to_string(), languages, trap_dir: options.output_dir, - trap_compression: trap::Compression::from_env("CODEQL_EXTRACTOR_UNIFIED_OPTION_TRAP_COMPRESSION"), + trap_compression: trap::Compression::from_env( + "CODEQL_EXTRACTOR_UNIFIED_OPTION_TRAP_COMPRESSION", + ), source_archive_dir: options.source_archive_dir, file_lists: vec![options.file_list], }; diff --git a/unified/extractor/src/generator.rs b/unified/extractor/src/generator.rs index cbf971a8ff2..974de5dbca9 100644 --- a/unified/extractor/src/generator.rs +++ b/unified/extractor/src/generator.rs @@ -22,14 +22,19 @@ pub fn run(options: Options) -> std::io::Result<()> { // The QL-visible schema is the unified output AST, not the per-language // input grammars. Pass it via `desugar.output_node_types_yaml` so the // generator converts the YAML to JSON node-types. - let desugar = yeast::DesugaringConfig::new() - .with_output_node_types_yaml(languages::OUTPUT_AST_SCHEMA); + let desugar = + yeast::DesugaringConfig::new().with_output_node_types_yaml(languages::OUTPUT_AST_SCHEMA); let languages = vec![Language { name: "Unified".to_owned(), - node_types: "", // unused: generator picks up output_node_types_yaml above + node_types: "", // unused: generator picks up output_node_types_yaml above desugar: Some(desugar), }]; - generate(languages, options.dbscheme, options.library, "run unified/scripts/create-extractor-pack.sh") + generate( + languages, + options.dbscheme, + options.library, + "run unified/scripts/create-extractor-pack.sh", + ) } diff --git a/unified/extractor/src/languages/swift/swift.rs b/unified/extractor/src/languages/swift/swift.rs index 595f56a0b39..c84e3cf3867 100644 --- a/unified/extractor/src/languages/swift/swift.rs +++ b/unified/extractor/src/languages/swift/swift.rs @@ -1,340 +1,1160 @@ use codeql_extractor::extractor::simple; -use yeast::{build::BuildCtx, rule, DesugaringConfig, PhaseKind}; +use yeast::{ConcreteDesugarer, DesugaringConfig, PhaseKind, Rule, manual_rule, rule, tree}; -/// Names of output AST kinds that belong to the `expr` supertype. Kept in -/// sync with `ast_types.yml`. `unsupported_node` is intentionally omitted -/// because it is also a member of the `stmt` supertype. -const EXPR_KINDS: &[&str] = &[ - "name_expr", - "int_literal", - "string_literal", - "binary_expr", - "unary_expr", - "call_expr", - "member_access_expr", - "lambda_expr", -]; +/// User context propagated from outer rules down to the inner rules that +/// emit the corresponding output declarations, so that each emitted node +/// is born with the outer information (name, type, modifiers, etc.) +/// already set — no schema-invalid intermediate state requiring +/// post-hoc mutation. +#[derive(Clone, Default)] +struct SwiftContext { + /// Identifier node for the property name. Set by the outer + /// `property_binding` (computed accessors / willSet-didSet) and + /// `protocol_property_declaration` rules before translating accessor + /// children; read by the accessor inner rules + /// (`computed_getter`/`computed_setter`/`computed_modify`/ + /// `willset_clause`/`didset_clause`/`getter_specifier`/ + /// `setter_specifier`). + property_name: Option, + /// Translated type node for the property type. Set by the outer + /// `property_binding` rule (computed accessors variant) and + /// `protocol_property_declaration` when present; read by the + /// accessor inner rules. + property_type: Option, + /// Default-value expression for the next translated `parameter`. Set + /// by the outer `function_parameter` rule; read by the `parameter` + /// rules. + default_value: Option, + /// Translated outer modifiers (e.g. visibility, attributes) to + /// attach to each child of a flattening outer rule. Set by + /// `property_declaration`, `enum_entry`, and + /// `protocol_property_declaration`. + outer_modifiers: Vec, + /// The `let`/`var` binding modifier for a `property_declaration`. + /// Set by `property_declaration`; read by the inner declaration + /// rules (`property_binding` variants, accessor rules) so they + /// emit it as part of the output node's `modifier:` field. + binding_modifier: Option, + /// True when the current child of a flattening outer rule is not + /// the first one — its inner rule should emit a + /// `chained_declaration` modifier so the original grouping can be + /// recovered downstream. + is_chained: bool, +} -/// If `id` is an `expr`, wrap it in `expr_stmt` so it can sit in a `stmt` -/// position; otherwise return it unchanged. -fn wrap_expr_in_stmt(ctx: &mut BuildCtx, id: usize) -> usize { - let kind = ctx.ast.get_node(id).map(|n| n.kind()).unwrap_or(""); - if EXPR_KINDS.contains(&kind) { - yeast::tree!(ctx, (expr_stmt expr: {id})) +/// Build a freshly-created `chained_declaration` modifier node if +/// `ctx.is_chained`, else `None`. Used by inner declaration rules to +/// emit the chained tag for non-first children of a flattening outer +/// rule. Returns `Option` so it splices via `{..…}` to 0 or 1 ids. +fn chained_modifier(ctx: &mut yeast::build::BuildCtx<'_, SwiftContext>) -> Option { + if ctx.is_chained { + Some(ctx.literal("modifier", "chained_declaration")) } else { - id + None } } -fn translation_rules() -> Vec { +/// Combine a list of boolean sub-conditions into a single expression by +/// left-folding with the infix `&&` operator. Used by control-flow +/// rules (`if`, `guard`, `while`, `repeat-while`) whose tree-sitter +/// nodes carry one or more comma-separated conditions that the target +/// AST represents as a single `condition:` field. Panics on an empty +/// input because every caller's grammar guarantees at least one +/// condition. +fn and_chain( + ctx: &mut yeast::build::BuildCtx<'_, SwiftContext>, + conds: Vec, +) -> yeast::Id { + conds.into_iter() + .map(yeast::Id::from) + .reduce(|acc, elem| { + tree!((binary_expr operator: (infix_operator "&&") left: {acc} right: {elem})) + }) + .expect("control-flow statement must have at least one condition") +} + +/// Translate a multi-part identifier (for example `Foo.Bar.Baz`) into a +/// `member_access_expr` chain rooted at a `name_expr` over the first +/// part. Panics on an empty input because the grammar's `_+` quantifier +/// guarantees at least one part. +fn member_chain( + ctx: &mut yeast::build::BuildCtx<'_, SwiftContext>, + parts: Vec, +) -> yeast::Id { + let mut iter = parts.into_iter(); + let first = iter + .next() + .expect("identifier with `part:` must have at least one part"); + let init = tree!((name_expr identifier: (identifier #{first}))); + iter.fold( + init, + |acc, elem| tree!((member_access_expr base: {acc} member: (identifier #{elem}))), + ) +} + +fn translation_rules() -> Vec> { vec![ + // ---- Top-level ---- + // Capture all top-level statements, including unnamed tokens like `nil`. rule!( - (source_file (_)* @children) + (source_file statement: _* @children) => (top_level - body: {..children} + body: (block stmt: {..children}) ) ), - // ---- Binary expressions ---- - // Swift's parser produces a different node kind for each operator - // family, but the field shape (`lhs` / `op` / `rhs`) is uniform, so - // each maps onto `binary_expr`. - rule!( - (additive_expression - lhs: (_) @left - op: _ @operator - rhs: (_) @right) - => - (binary_expr - left: {left} - operator: (operator #{operator}) - right: {right}) - ), - rule!( - (multiplicative_expression - lhs: (_) @left - op: _ @operator - rhs: (_) @right) - => - (binary_expr - left: {left} - operator: (operator #{operator}) - right: {right}) - ), - rule!( - (comparison_expression - lhs: (_) @left - op: _ @operator - rhs: (_) @right) - => - (binary_expr - left: {left} - operator: (operator #{operator}) - right: {right}) - ), - rule!( - (equality_expression - lhs: (_) @left - op: _ @operator - rhs: (_) @right) - => - (binary_expr - left: {left} - operator: (operator #{operator}) - right: {right}) - ), - rule!( - (conjunction_expression - lhs: (_) @left - op: _ @operator - rhs: (_) @right) - => - (binary_expr - left: {left} - operator: (operator #{operator}) - right: {right}) - ), - rule!( - (disjunction_expression - lhs: (_) @left - op: _ @operator - rhs: (_) @right) - => - (binary_expr - left: {left} - operator: (operator #{operator}) - right: {right}) - ), - rule!( - (nil_coalescing_expression - lhs: (_) @left - op: _ @operator - rhs: (_) @right) - => - (binary_expr - left: {left} - operator: (operator #{operator}) - right: {right}) - ), - rule!( - (range_expression - start: (_) @left - op: _ @operator - end: (_) @right) - => - (binary_expr - left: {left} - operator: (operator #{operator}) - right: {right}) - ), - // ---- Unary expressions ---- - rule!( - (prefix_expression - operation: _ @operator - target: (_) @operand) - => - (unary_expr - operand: {operand} - operator: (operator #{operator})) - ), - // ---- Identifiers / name expressions ---- - rule!( - (simple_identifier) @name - => - (name_expr - identifier: (identifier #{name})) - ), + // Declarations may be wrapped in local/global wrapper nodes. + rule!((global_declaration _ @inner) => {inner}), + rule!((local_declaration _ @inner) => {inner}), // ---- Literals ---- + rule!((integer_literal) => (int_literal)), + rule!((hex_literal) => (int_literal)), + rule!((bin_literal) => (int_literal)), + rule!((oct_literal) => (int_literal)), + rule!((real_literal) => (float_literal)), + rule!((boolean_literal) => (boolean_literal)), + rule!("nil" => (builtin_expr)), + rule!((special_literal) => (builtin_expr)), + rule!((line_string_literal) => (string_literal)), + rule!((multi_line_string_literal) => (string_literal)), + rule!((raw_string_literal) => (string_literal)), + rule!((regex_literal) => (regex_literal)), + // ---- Names ---- + rule!((simple_identifier) @id => (name_expr identifier: (identifier #{id}))), + // A referenceable_operator (e.g. `+` used as a value, as in `reduce(0, +)`) + // is treated as a name reference to the operator symbol. + rule!((referenceable_operator) @op => (name_expr identifier: (identifier #{op}))), + // ---- Operators ---- + // All binary operators share the lhs/op/rhs shape. + rule!((additive_expression lhs: @l op: @op rhs: @r) => (binary_expr left: {l} operator: (infix_operator #{op}) right: {r})), + rule!((multiplicative_expression lhs: @l op: @op rhs: @r) => (binary_expr left: {l} operator: (infix_operator #{op}) right: {r})), + rule!((comparison_expression lhs: @l op: @op rhs: @r) => (binary_expr left: {l} operator: (infix_operator #{op}) right: {r})), + rule!((equality_expression lhs: @l op: @op rhs: @r) => (binary_expr left: {l} operator: (infix_operator #{op}) right: {r})), + rule!((conjunction_expression lhs: @l op: @op rhs: @r) => (binary_expr left: {l} operator: (infix_operator #{op}) right: {r})), + rule!((disjunction_expression lhs: @l op: @op rhs: @r) => (binary_expr left: {l} operator: (infix_operator #{op}) right: {r})), + rule!((infix_expression lhs: @l op: @op rhs: @r) => (binary_expr left: {l} operator: (infix_operator #{op}) right: {r})), + // Range expression `a.. (binary_expr left: {l} operator: (infix_operator #{op}) right: {r})), + // Open-ended ranges `a...` / `...b` + rule!((open_end_range_expression start: @l) => (unary_expr operator: (postfix_operator "...") operand: {l})), + rule!((open_start_range_expression end: @r) => (unary_expr operator: (prefix_operator "...") operand: {r})), + // Custom operator declaration: `[prefix|infix|postfix] operator OP [: PrecedenceGroup]`. + // The fixity keyword is an anonymous child of `operator_declaration`, so we + // dispatch on it with one rule per keyword. rule!( - (integer_literal) @lit + (operator_declaration "prefix" (referenceable_operator _ @op) (simple_identifier)? @prec) => - (int_literal #{lit}) + (operator_syntax_declaration name: (identifier #{op}) fixity: (fixity "prefix") precedence: {..prec}) ), - // String literals: render the *raw* source text, including the - // surrounding quotes. Interpolations (e.g. `"hi \(x)"`) are not - // yet broken out into structured pieces \u2014 they show up as part - // of the literal's source text. rule!( - (line_string_literal) @lit + (operator_declaration "postfix" (referenceable_operator _ @op) (simple_identifier)? @prec) => - (string_literal #{lit}) - ), // ---- Lambdas / closures ---- - // Map a `lambda_literal` whose body is a single statement to - // `lambda_expr`. Multi-statement bodies fall through to - // `unsupported_node` because `lambda_expr.body` is single-valued - // in the current `ast_types.yml`. Parameters from explicit-typed - // closures (`{ (x: Int) -> Int in ... }`) are not yet captured. + (operator_syntax_declaration name: (identifier #{op}) fixity: (fixity "postfix") precedence: {..prec}) + ), + rule!( + (operator_declaration "infix" (referenceable_operator _ @op) (simple_identifier)? @prec) + => + (operator_syntax_declaration + name: (identifier #{op}) + fixity: (fixity "infix") + precedence: {..prec}) + ), + rule!((bitwise_operation lhs: @l op: @op rhs: @r) => (binary_expr left: {l} operator: (infix_operator #{op}) right: {r})), + rule!((nil_coalescing_expression value: @l if_nil: @r) => (binary_expr left: {l} operator: (infix_operator "??") right: {r})), + // Leading-dot member shorthand (e.g. `.some`, `.foo`) means member access + // on a contextually inferred type. + rule!((prefix_expression operation: "." target: @member) => (member_access_expr base: (inferred_type_expr) member: (identifier #{member}))), + // Prefix unary operators + rule!((prefix_expression operation: @op target: @operand) => (unary_expr operator: (prefix_operator #{op}) operand: {operand})), + // Postfix unary operators + rule!((postfix_expression operation: @op target: @operand) => (unary_expr operator: (postfix_operator #{op}) operand: {operand})), + // TODO: Parenthesised single-value tuple is a grouping expression and should pass through. + // Multi-value tuples become tuple_expr. + rule!((tuple_expression value: _* @v) => (tuple_expr element: {..v})), + // Blocks contain statement* directly. + rule!((block statement: _+ @stmts) => (block stmt: {..stmts})), + rule!((block) => (block)), + // ---- Variables ---- + // property_binding rules — these produce variable_declaration and/or accessor_declaration + // nodes for individual declarators. The outer property_declaration rule splices these out + // and attaches binding/modifiers from the parent. + + // Computed property with explicit accessors (get/set/modify) → a + // sequence of `accessor_declaration` nodes. The outer rule + // publishes the property's name and type into `ctx` so that each + // inner accessor rule + // (`computed_getter`/`computed_setter`/`computed_modify`) builds + // its `accessor_declaration` with `name` and `type` set from the + // start — no schema-invalid intermediate state. + // + // Toggles `ctx.is_chained` per accessor iteration: the first + // accessor inherits the outer rule's chained state (i.e. whether + // this whole property_binding is itself a non-first declarator + // of a containing property_declaration); subsequent accessors + // always emit `chained_declaration`. + manual_rule!( + (property_binding + name: @pattern + type: _? @ty + computed_value: (computed_property accessor: _+ @accessors)) + { + // Translate `ty` first so the context holds an + // output-schema node id. + let translated_ty = ctx.translate_opt(ty)?; + // Build the property-name identifier from the + // (untranslated) pattern leaf. + let name_id = tree!((identifier #{pattern})); + + ctx.property_name = Some(name_id); + ctx.property_type = translated_ty; + + let mut result = Vec::new(); + for (i, acc) in accessors.into_iter().enumerate() { + if i > 0 { + ctx.is_chained = true; + } + result.extend(ctx.translate(acc)?); + } + Ok(result) + } + ), + // Computed property: shorthand getter (no explicit get/set, just + // statements) → a single accessor_declaration with kind "get". + // Reads outer modifiers / chained tag from `ctx` (set by the + // outer `property_declaration` rule). + rule!( + (property_binding + name: (pattern bound_identifier: @name) + type: _? @ty + computed_value: (computed_property statement: _* @body)) + => + (accessor_declaration + modifier: {..ctx.binding_modifier} + modifier: {..ctx.outer_modifiers.clone()} + modifier: {..chained_modifier(&mut ctx)} + name: (identifier #{name}) + type: {..ty} + accessor_kind: (accessor_kind "get") + body: (block stmt: {..body})) + ), + // Stored property with willSet/didSet observers (initializer + // optional) → a `variable_declaration` followed by one + // `accessor_declaration` per observer, each born with the + // property name set. Manual rule: we publish the property name + // into `ctx` before translating the observer children so the + // inner `willset_clause` / `didset_clause` rules construct + // valid `accessor_declaration` nodes from the start. + // + // The `variable_declaration` itself inherits the outer rule's + // chained state; observers always get `chained_declaration` + // because they're subsequent outputs of this flattening rule. + manual_rule!( + (property_binding + name: (pattern bound_identifier: @name) + type: _? @ty + value: _? @val + observers: (willset_didset_block willset: _? @ws didset: _? @ds)) + { + // Translate ty and val so the variable_declaration + // below contains output-schema nodes. + let translated_ty = ctx.translate_opt(ty)?; + let translated_val = ctx.translate_opt(val)?; + + let var_decl = tree!( + (variable_declaration + modifier: {..ctx.binding_modifier} + modifier: {..ctx.outer_modifiers.clone()} + modifier: {..chained_modifier(&mut ctx)} + pattern: (name_pattern identifier: (identifier #{name})) + type: {..translated_ty} + value: {..translated_val}) + ); + + // Publish the property name for the observer rules. + ctx.property_name = Some(tree!((identifier #{name}))); + // Observers are subsequent outputs of this flattening + // rule, so they always get `chained_declaration`. + ctx.is_chained = true; + + let mut result = vec![var_decl]; + for obs in ws.into_iter().chain(ds) { + result.extend(ctx.translate(obs)?); + } + Ok(result) + } + ), + // property_binding with any pattern name (identifier or + // destructuring). Reads outer modifiers / chained tag from `ctx`. + rule!( + (property_binding + name: @pattern + type: _? @ty + value: _? @val) + => + (variable_declaration + modifier: {..ctx.binding_modifier} + modifier: {..ctx.outer_modifiers.clone()} + modifier: {..chained_modifier(&mut ctx)} + pattern: {pattern} + type: {..ty} + value: {..val}) + ), + // property_declaration: flatten declarators (each may translate + // to multiple nodes — variable_declaration and/or + // accessor_declaration) and attach the binding modifier + // (let/var), outer modifiers, and `chained_declaration` for + // non-first declarations. Manual rule: publishes + // binding/outer modifiers into `ctx` and translates each + // declarator with `ctx.is_chained` toggled per iteration. The + // inner declaration rules (`property_binding` variants, + // accessor inner rules) read these fields and emit complete + // `modifier:` lists from the start. + manual_rule!( + (property_declaration + binding: (value_binding_pattern mutability: @binding_kind) + declarator: _* @decls + (modifiers)* @mods) + { + let binding_text = ctx.ast.source_text(binding_kind.0); + ctx.binding_modifier = Some(ctx.literal("modifier", &binding_text)); + let mut modifiers = Vec::new(); + for m in mods { + modifiers.extend(ctx.translate(m)?); + } + ctx.outer_modifiers = modifiers; + + let mut result = Vec::new(); + for (i, decl) in decls.into_iter().enumerate() { + ctx.is_chained = i > 0; + result.extend(ctx.translate(decl)?); + } + Ok(result) + } + ), + // ---- Enums ---- + // enum_type_parameter → parameter (with optional name as pattern). + rule!( + (enum_type_parameter name: @name type: @ty) + => + (parameter + pattern: (name_pattern identifier: (identifier #{name})) + type: {ty}) + ), + rule!( + (enum_type_parameter type: @ty) + => + (parameter type: {ty}) + ), + // enum_case_entry with associated values → class_like_declaration + // containing a constructor whose parameters are the data + // parameters. Reads outer modifiers / chained tag from `ctx` + // (set by the outer `enum_entry` rule). + rule!( + (enum_case_entry + name: @name + data_contents: (enum_type_parameters parameter: _* @params)) + => + (class_like_declaration + modifier: {..ctx.outer_modifiers.clone()} + modifier: {..chained_modifier(&mut ctx)} + modifier: (modifier "enum_case") + name: (identifier #{name}) + member: (constructor_declaration parameter: {..params} body: (block))) + ), + // enum_case_entry with explicit raw value → variable_declaration with that value. + rule!( + (enum_case_entry name: @name raw_value: @val) + => + (variable_declaration + modifier: {..ctx.outer_modifiers.clone()} + modifier: {..chained_modifier(&mut ctx)} + modifier: (modifier "enum_case") + pattern: (name_pattern identifier: (identifier #{name})) + value: {val}) + ), + // enum_case_entry without associated values → variable_declaration tagged enum_case. + rule!( + (enum_case_entry name: @name) + => + (variable_declaration + modifier: {..ctx.outer_modifiers.clone()} + modifier: {..chained_modifier(&mut ctx)} + modifier: (modifier "enum_case") + pattern: (name_pattern identifier: (identifier #{name}))) + ), + // enum_entry: flatten case entries; publish outer modifiers + // into `ctx` and translate each case with `ctx.is_chained` + // toggled per iteration so the inner `enum_case_entry` rules + // emit complete `modifier:` lists from the start. + manual_rule!( + (enum_entry case: _+ @cases (modifiers)* @mods) + { + let mut modifiers = Vec::new(); + for m in mods { + modifiers.extend(ctx.translate(m)?); + } + ctx.outer_modifiers = modifiers; + + let mut result = Vec::new(); + for (i, case) in cases.into_iter().enumerate() { + ctx.is_chained = i > 0; + result.extend(ctx.translate(case)?); + } + Ok(result) + } + ), + // Plain assignment: `x = expr` + rule!( + (assignment operator: "=" target: (directly_assignable_expression expr: @target) result: @value) + => + (assign_expr target: {target} value: {value}) + ), + // Compound assignment: `x += expr` etc. + rule!( + (assignment operator: @op target: (directly_assignable_expression expr: @target) result: @value) + => + (compound_assign_expr target: {target} operator: (infix_operator #{op}) value: {value}) + ), + // Unwrap `type` wrapper node + rule!((type name: @inner) => {inner}), + // `directly_assignable_expression` is just a wrapper; unwrap it + rule!((directly_assignable_expression expr: @inner) => {inner}), + // Pattern with bound_identifier → name_pattern + rule!((pattern bound_identifier: @name) => (name_pattern identifier: (identifier #{name}))), + // Pattern with 'let' or 'var' binding: extract the inner pattern + // TODO: Names in a pattern need to be translated to expr_equality_pattern if not under a 'var/let' but we lack a way to pass down context to do this. + rule!( + (pattern kind: (binding_pattern binding: _? pattern: @pattern)) + => + {pattern} + ), + // case T.foo(x,y) pattern + rule!( + (pattern kind: (case_pattern type: @typ name: @name arguments: (tuple_pattern item: (tuple_pattern_item)* @items)? )) + => + (constructor_pattern + constructor: (member_access_expr base: {typ} member: (identifier #{name})) + element: {..items}) + ), + // case .foo(x,y) pattern + rule!( + (pattern kind: (case_pattern dot: @dot name: @name arguments: (tuple_pattern item: (tuple_pattern_item)* @items)? )) + => + (constructor_pattern + constructor: (member_access_expr base: (inferred_type_expr #{dot}) member: (identifier #{name})) + element: {..items}) + ), + // Tuple pattern and its (optionally named) items + rule!((pattern kind: (tuple_pattern item: _* @elems)) => (tuple_pattern element: {..elems})), + rule!((tuple_pattern_item name: @key pattern: @pat) => (pattern_element key: (identifier #{key}) pattern: {pat})), + rule!((tuple_pattern_item pattern: @pat) => (pattern_element pattern: {pat})), + // Type casting pattern (TODO) + rule!((pattern kind: (type_casting_pattern)) => (unsupported_node)), + // Wildcard pattern + rule!((pattern kind: (wildcard_pattern)) => (ignore_pattern)), + // Expression pattern + // We lack a way to check if 'expr' is actually an expression, but due to rule ordering + // the 'expression' case is the only remaining possibility when this rule tries to match. + rule!((pattern kind: @expr) => (expr_equality_pattern expr: {expr})), + // ---- Functions ---- + // Function declaration + // Function declaration (return type optional, body statements optional). + rule!( + (function_declaration + name: @name + parameter: _* @params + return_type: _? @ret + body: (block statement: _* @body_stmts)) + => + (function_declaration + name: (identifier #{name}) + parameter: {..params} + return_type: {..ret} + body: (block stmt: {..body_stmts})) + ), + // Parameters are wrapped in function_parameter, which also carries + // optional default values. Publishes the default value into `ctx` + // before translating the inner `parameter` so the `parameter` + // rules can include it as a `default:` field directly. + manual_rule!( + (function_parameter parameter: @p default_value: _? @def) + { + ctx.default_value = ctx.translate_opt(def)?; + ctx.translate(p) + } + ), + // Parameter with external name and type + rule!( + (parameter external_name: @ext name: @name) + => + (parameter + external_name: (identifier #{ext}) + pattern: (name_pattern identifier: (identifier #{name})) + default: {..ctx.default_value}) + ), + rule!( + (parameter external_name: @ext name: @name type: @ty) + => + (parameter + external_name: (identifier #{ext}) + pattern: (name_pattern identifier: (identifier #{name})) + type: {ty} + default: {..ctx.default_value}) + ), + // Parameter with just name and type (no external name) + rule!( + (parameter name: @name) + => + (parameter + pattern: (name_pattern identifier: (identifier #{name})) + default: {..ctx.default_value}) + ), + rule!( + (parameter name: @name type: @ty) + => + (parameter + pattern: (name_pattern identifier: (identifier #{name})) + type: {ty} + default: {..ctx.default_value}) + ), + // Reference to a function, f(x:y:z:). This is parsed as a call with a single argument with multiple reference_specifier labels. + // We don't want downstream QL to try to handle this as a call_expr with a weird argument, so explicitly mark it as unsupported for now. + // In the future we probably want to translate this to a lambda expression. + rule!( + (call_expression suffix: (call_suffix arguments: (value_arguments argument: (value_argument reference_specifier: _+) @ref_arg))) + => + (unsupported_node) + ), + // Call expression: function(args...) + rule!( + (call_expression function: @func suffix: (call_suffix arguments: (value_arguments argument: (value_argument)* @args))) + => + (call_expr callee: {func} argument: {..args}) + ), + // Value argument with label (value: _ matches both named nodes and anonymous tokens like nil) + rule!( + (value_argument name: (value_argument_label name: @label) value: @val) + => + (argument name: (identifier #{label}) value: {val}) + ), + // Value argument without label + rule!( + (value_argument value: @val) + => + (argument value: {val}) + ), + // Navigation expression → member_access_expr + rule!( + (navigation_expression target: @target suffix: (navigation_suffix suffix: @member)) + => + (member_access_expr base: {target} member: (identifier #{member})) + ), + // Return / break / continue, one rule per keyword. + // The anonymous "return"/"break"/"continue" keywords are matched as + // string literals. + rule!((control_transfer_statement kind: "return" result: _? @val) => (return_expr value: {..val})), + rule!((control_transfer_statement kind: "break" result: @lbl) => (break_expr label: (identifier #{lbl}))), + rule!((control_transfer_statement kind: "break") => (break_expr)), + rule!((control_transfer_statement kind: "continue" result: @lbl) => (continue_expr label: (identifier #{lbl}))), + rule!((control_transfer_statement kind: "continue") => (continue_expr)), + rule!((control_transfer_statement kind: (throw_keyword) result: @val) => (throw_expr value: {val})), + // ---- Closures ---- + // Lambda literal with optional type header (parameters + optional return type). + // The return_type capture is optional, so this rule covers both cases. rule!( (lambda_literal - (statements (_) @body)) + attribute: _* @attrs + captures: (capture_list item: _* @captures)? + type: (lambda_function_type + params: (lambda_function_type_parameters parameter: _* @params) + return_type: _? @ret)? + statement: _* @body) => - (lambda_expr - body: {body}) + (function_expr + modifier: {..attrs} + capture_declaration: {..captures} + parameter: {..params} + return_type: {..ret} + body: (block stmt: {..body})) ), - // ---- Block / statement wrapping ---- - // A `(statements ...)` node corresponds to a brace-delimited block. - // Each child is mapped through translation; bare expression results - // get wrapped in `expr_stmt` so they fit the `body*: stmt` field. + // capture_list_item with ownership modifier (e.g. [weak self], [unowned x]) rule!( - (statements (_)* @stmts) + (capture_list_item ownership: _? @ownership name: @name value: _? @val) => - (block_stmt body: {..stmts.iter().copied().map(|n| - wrap_expr_in_stmt(&mut __yeast_ctx, n.into()) - ).collect::>()}) + (variable_declaration + modifier: {..ownership} + pattern: (name_pattern identifier: (identifier #{name})) + value: {..val}) ), - // ---- Calls and member access ---- - // Member access, e.g. `obj.member`. The Swift parser wraps the - // member name as `(navigation_suffix suffix: (simple_identifier))`. + // Lambda parameter with type and optional external name rule!( - (navigation_expression - target: (_) @target - suffix: (navigation_suffix - suffix: (simple_identifier) @member)) + (lambda_parameter external_name: @ext name: @name type: @ty) => - (member_access_expr - target: {target} - member: (identifier #{member})) + (parameter + external_name: (identifier #{ext}) + pattern: (name_pattern identifier: (identifier #{name})) + type: {ty}) ), - // Function / method call. The callee is the first child of - // `call_expression`; the second is a `call_suffix` whose - // `value_arguments` (if present) hold the parenthesized args. A - // trailing closure (`call_suffix` with a `lambda_literal` child) - // is appended as a final argument. rule!( - (call_expression - (_) @callee - (call_suffix - (value_arguments - (value_argument value: (_) @args)*)? - (lambda_literal)? @trailing)) + (lambda_parameter name: @name type: @ty) + => + (parameter + pattern: (name_pattern identifier: (identifier #{name})) + type: {ty}) + ), + rule!( + (lambda_parameter external_name: @ext name: @name) + => + (parameter + external_name: (identifier #{ext}) + pattern: (name_pattern identifier: (identifier #{name}))) + ), + rule!( + (lambda_parameter name: @name) + => + (parameter pattern: (name_pattern identifier: (identifier #{name}))) + ), + // Call expression with trailing closure (no value_arguments) + rule!( + (call_expression function: @func suffix: (call_suffix lambda: (lambda_literal) @closure)) => (call_expr - function: {callee} - argument: {..args} - argument: {..trailing} - ) + callee: {func} + argument: (argument value: {closure})) ), - // ---- Guard statement ---- - // `guard let x = e else { ... }` — currently only handles the - // let-binding form. The Swift parser models the `let` keyword as a - // `value_binding_pattern` child of `condition`, followed by an - // unnamed `=` and the source expression. + // ---- Control flow ---- + // If statement rule!( - (guard_statement - bound_identifier: (simple_identifier) @id - condition: (value_binding_pattern) - condition: (_) @value - (else) - (statements) @else_branch) + (if_statement condition: _* @cond body: @then_body else_branch: _? @else_stmts) + => + (if_expr + condition: {and_chain(&mut ctx, cond)} + then: {then_body} + else: {..else_stmts}) + ), + // Guard statement + rule!( + (guard_statement condition: _* @cond body: (block statement: _* @else_stmts)) => (guard_if_stmt - condition: (let_pattern_condition - pattern: (var_pattern identifier: (identifier #{id})) - value: {value}) - else: {else_branch}) + condition: {and_chain(&mut ctx, cond)} + else: (block stmt: {..else_stmts})) ), - // ---- If statement ---- - // if-let binding (with optional else branch). The Swift parser puts - // the bound name in `bound_identifier`, the `let` keyword as a - // `value_binding_pattern` child of `condition`, and the source - // expression as a separate child of `condition`. + // Ternary expression → if_expr rule!( - (if_statement - bound_identifier: (simple_identifier) @id - condition: (value_binding_pattern) - condition: (_) @value - (statements) @then - (else) - (_) @else_branch) + (ternary_expression condition: @cond if_true: @then_val if_false: @else_val) => - (if_stmt - condition: (let_pattern_condition - pattern: (var_pattern identifier: (identifier #{id})) - value: {value}) - then: {then} - else: {else_branch}) + (if_expr condition: {cond} then: {then_val} else: {else_val}) + ), + // Switch statement + rule!( + (switch_statement expr: @val entry: (switch_entry)* @cases) + => + (switch_expr value: {val} case: {..cases}) + ), + // Switch entry with patterns and body + rule!( + (switch_entry pattern: (switch_pattern pattern: @pats)* statement: _* @body) + => + (switch_case pattern: {..pats} body: (block stmt: {..body})) + ), + // Switch entry: default case (no patterns) + rule!( + (switch_entry default: (default_keyword) statement: _* @body) + => + (switch_case body: (block stmt: {..body})) + ), + // if case let x = expr — the pattern is taken as-is (no Optional wrapping) + rule!( + (if_let_binding "case" (value_binding_pattern) bound_identifier: @name _ @val) + => + (pattern_guard_expr + value: {val} + pattern: (name_pattern identifier: (identifier #{name}))) ), rule!( - (if_statement - bound_identifier: (simple_identifier) @id - condition: (value_binding_pattern) - condition: (_) @value - (statements) @then) + (if_let_binding + pattern: (pattern binding: (value_binding_pattern) bound_identifier: @name) + value: @val) => - (if_stmt - condition: (let_pattern_condition - pattern: (var_pattern identifier: (identifier #{id})) - value: {value}) - then: {then}) + (pattern_guard_expr + value: {val} + pattern: (constructor_pattern + constructor: (member_access_expr base: (named_type_expr name: (identifier "Optional")) member: (identifier "some")) + element: (pattern_element pattern: (name_pattern identifier: (identifier #{name}))))) ), - // With explicit else branch (block or chained if). + // Shorthand if let x (Swift 5.7+) — also semantically .some(x) rule!( - (if_statement - condition: (_) @cond - (statements) @then - (else) - (_) @else_branch) + (if_let_binding + pattern: (pattern binding: (value_binding_pattern) bound_identifier: @name)) => - (if_stmt - condition: (expr_condition expr: {cond}) - then: {then} - else: {else_branch}) + (pattern_guard_expr + value: (name_expr identifier: (identifier #{name})) + pattern: (constructor_pattern + constructor: (member_access_expr base: (named_type_expr name: (identifier "Optional")) member: (identifier "some")) + element: (pattern_element pattern: (name_pattern identifier: (identifier #{name}))))) ), - // Without else branch. + // If-condition — unwrap (pass through the inner expression/pattern) + rule!((if_condition kind: @inner) => {inner}), + // ---- Loops ---- + // For-in loop with optional where-clause guard. rule!( - (if_statement - condition: (_) @cond - (statements) @then) + (for_statement + item: @pat + collection: @iter + where: (where_clause expr: @guard)? + body: (block statement: _* @body)) => - (if_stmt - condition: (expr_condition expr: {cond}) - then: {then}) - ), // ---- Patterns ---- - // The Swift parser uses a `pattern` node with a `bound_identifier` - // field for simple bindings such as `let x = ...`. - rule!( - (pattern bound_identifier: (simple_identifier) @id) - => - (var_pattern - identifier: (identifier #{id})) + (for_each_stmt + pattern: {pat} + iterable: {iter} + guard: {..guard} + body: (block stmt: {..body})) ), - // Inside tuple patterns, the inner `pattern` node holds a bare - // `simple_identifier` (with no `bound_identifier` field). + // While loop rule!( - (pattern (simple_identifier) @id) + (while_statement condition: _* @cond body: (block statement: _* @body)) => - (var_pattern - identifier: (identifier #{id})) + (while_stmt + condition: {and_chain(&mut ctx, cond)} + body: (block stmt: {..body})) ), - // Tuple destructuring pattern, e.g. `let (a, b) = pair`. The parser - // emits a `pattern` node whose unnamed children are themselves - // `pattern` nodes. + // Repeat-while loop rule!( - (pattern (pattern)+ @parts) + (repeat_while_statement condition: _* @cond body: (block statement: _* @body)) => - (tuple_pattern element: {..parts}) + (do_while_stmt + condition: {and_chain(&mut ctx, cond)} + body: (block stmt: {..body})) ), - // ---- Variable declarations ---- - // Handles single (`let x = e`), multiple (`let x = 1, y = 2`), - // and uninitialized (`var x: T`) bindings. + // Labeled statement (e.g. `outer: for ...`). Strip the trailing ':' from the label token. + rule!((labeled_statement label: (statement_label) @lbl statement: @stmt) => { + let text = ctx.ast.source_text(lbl.into()); + let name = &text[..text.len() - 1]; + tree!((labeled_stmt label: (identifier #{name}) stmt: {stmt})) + }), + // ---- Collections ---- + // Array literal + rule!((array_literal element: _* @elems) => (array_literal element: {..elems})), + // Empty array literal + rule!((array_literal) => (array_literal)), + // Dictionary literal — zip keys and values into key_value_pairs rule!( - (property_declaration - name: (_)* @pats - value: (_)* @vals) + (dictionary_literal key: _* @keys value: _* @vals) => - (variable_declaration_stmt - variable_declarator: {..pats.iter().enumerate().map(|(i, &pat)| { - match vals.get(i).copied() { - Some(val) => yeast::tree!( - (variable_declarator - pattern: {pat} - value: {val})), - None => yeast::tree!( - (variable_declarator - pattern: {pat})), - } - })}) + (map_literal element: {..keys.into_iter().zip(vals).map(|(k, v)| + tree!((key_value_pair key: {k} value: {v})) + )}) ), + rule!((dictionary_literal element: _* @elems) => (map_literal element: {..elems})), + rule!((dictionary_literal_item key: @k value: @v) => (key_value_pair key: {k} value: {v})), + // ---- Optionals and errors ---- + // Optional chaining — unwrap the marker + rule!((optional_chain_marker expr: @inner) => {inner}), + // try/try?/try! expr → unary_expr with operator "try", "try?" or "try!" + rule!((try_expression (try_operator) @op expr: @inner) => (unary_expr operator: (prefix_operator #{op}) operand: {inner})), + rule!((try_expression operator: (try_operator) @op expr: @inner) => (unary_expr operator: (prefix_operator #{op}) operand: {inner})), + // Do-catch → try_expr + rule!( + (do_statement body: (block statement: _* @body) catch: (catch_block)* @catches) + => + (try_expr + body: (block stmt: {..body}) + catch_clause: {..catches}) + ), + // Catch block with bound identifier; optional where-clause guard. + rule!( + (catch_block + keyword: (catch_keyword) + error: @pattern + where: (where_clause expr: @guard)? + body: (block statement: _* @body)) + => + (catch_clause + pattern: {pattern} + guard: {..guard} + body: (block stmt: {..body})) + ), + // Catch block without error binding + rule!( + (catch_block keyword: (catch_keyword) body: (block statement: _* @body)) + => + (catch_clause body: (block stmt: {..body})) + ), + // Empty catch block: catch {} + rule!( + (catch_block (catch_keyword)) + => + (catch_clause body: (block)) + ), + // Catch block with unhandled pattern — preserve pattern; optional body. + rule!( + (catch_block keyword: (catch_keyword) error: @pat body: (block statement: _* @body)) + => + (catch_clause + pattern: {pat} + body: (block stmt: {..body})) + ), + // As expression (type cast) — as?, as! + rule!((as_expression (as_operator) @op expr: @val type: @ty) => (type_cast_expr expr: {val} operator: (infix_operator #{op}) type: {ty})), + // Check expression (`x is T`) → type_test_expr + rule!((check_expression op: @op target: @val type: @ty) => (type_test_expr expr: {val} operator: (infix_operator #{op}) type: {ty})), + // Await expression → unary_expr with operator "await" + rule!((await_expression expr: @val) => (unary_expr operator: (prefix_operator "await") operand: {val})), + // A multi-part identifier (for example `Foo.Bar.Baz`) is translated to + // a member_access_expr chain with a name_expr base. + rule!( + (identifier part: _+ @parts) + => + {member_chain(&mut ctx, parts)} + ), + // Scoped import declaration (for example `import struct Foo.Bar`): + // flatten the identifier parts into a member_access_expr and bind the + // final segment as a name_pattern. + rule!( + (import_declaration scoped_import_kind: @kind name: (identifier part: _+ @parts) @name modifiers: (modifiers)? @mods) + => + (import_declaration + pattern: (name_pattern identifier: (identifier #{parts.last().unwrap()})) + imported_expr: {name} + modifier: (modifier #{kind}) + modifier: {..mods}) + ), + // Non-scoped import declaration (for example `import Foundation`): + // flatten the identifier parts into a member_access_expr and use a + // bulk_importing_pattern. + rule!( + (import_declaration name: @name modifiers: (modifiers)? @mods) + => + (import_declaration + pattern: (bulk_importing_pattern) + imported_expr: {name} + modifier: {..mods}) + ), + // ---- Types and classes ---- + // Self expression → name_expr + rule!((self_expression) => (name_expr identifier: (identifier "self"))), + // Super expression → super_expr + rule!((super_expression) => (super_expr)), + // Modifiers — unwrap to individual modifier children + rule!((modifiers _* @mods) => {..mods}), + rule!((attribute) @m => (modifier #{m})), + rule!((visibility_modifier) @m => (modifier #{m})), + rule!((function_modifier) @m => (modifier #{m})), + rule!((member_modifier) @m => (modifier #{m})), + rule!((mutation_modifier) @m => (modifier #{m})), + rule!((ownership_modifier) @m => (modifier #{m})), + rule!((property_modifier) @m => (modifier #{m})), + rule!((parameter_modifier) @m => (modifier #{m})), + rule!((inheritance_modifier) @m => (modifier #{m})), + rule!((property_behavior_modifier) @m => (modifier #{m})), + // Type annotations — unwrap + rule!((type_annotation type: @inner) => {inner}), + // user_type is split into simple_user_type parts. + // Keep a conservative textual fallback to avoid dropping type information. + rule!((user_type) @ty => (named_type_expr name: (identifier #{ty}))), + // Tuple type → tuple_type_expr + rule!((tuple_type element: _* @elems) => (tuple_type_expr element: {..elems})), + rule!((tuple_type_item name: @name type: @ty) => (tuple_type_element name: (identifier #{name}) type: {ty})), + rule!((tuple_type_item type: @ty) => (tuple_type_element type: {ty})), + // Array type `[T]` → generic_type_expr with Array base + rule!((array_type element: @e) => (generic_type_expr + base: (named_type_expr name: (identifier "Array")) + type_argument: {e})), + // Dictionary type `[K: V]` → generic_type_expr with Dictionary base + rule!((dictionary_type key: @k value: @v) => (generic_type_expr + base: (named_type_expr name: (identifier "Dictionary")) + type_argument: {k} + type_argument: {v})), + // Optional type `T?` → generic_type_expr with Optional base + rule!((optional_type wrapped: @w) => (generic_type_expr + base: (named_type_expr name: (identifier "Optional")) + type_argument: {w})), + // Function type `(Params) -> Ret` → function_type_expr. + rule!((function_type parameter: _* @ps return_type: @ret) => (function_type_expr parameter: {..ps} return_type: {ret})), + rule!((function_type_parameter name: @name type: @ty) => (parameter external_name: (identifier #{name}) type: {ty})), + rule!((function_type_parameter type: @ty) => (parameter type: {ty})), + // Selector expression: `#selector(inner)` -- not yet supported + rule!( + (selector_expression _ @inner) + => + (unsupported_node) + ), + // Key path expressions are currently unsupported. + rule!((key_path_expression) => (unsupported_node)), + // Inheritance specifier → base_type + rule!((inheritance_specifier inherits_from: @ty) => (base_type type: {ty})), + // Class declaration with body containing members + rule!( + (class_declaration + declaration_kind: @kind + name: @name + body: (class_body member: _* @members) + (inheritance_specifier)* @bases + (modifiers)* @mods) + => + (class_like_declaration + modifier: (modifier #{kind}) + modifier: {..mods} + name: (identifier #{name}) + base_type: {..bases} + member: {..members}) + ), + // Enum class declaration: same as a regular class but with an enum body. + rule!( + (class_declaration + declaration_kind: @kind + name: @name + body: (enum_class_body member: _* @members) + (inheritance_specifier)* @bases + (modifiers)* @mods) + => + (class_like_declaration + modifier: (modifier #{kind}) + modifier: {..mods} + name: (identifier #{name}) + base_type: {..bases} + member: {..members}) + ), + // Class declaration with empty body + rule!( + (class_declaration + declaration_kind: @kind + name: @name + body: _ + (inheritance_specifier)* @bases + (modifiers)* @mods) + => + (class_like_declaration + modifier: (modifier #{kind}) + modifier: {..mods} + name: (identifier #{name}) + base_type: {..bases}) + ), + // Protocol declaration + rule!( + (protocol_declaration + name: @name + body: (protocol_body member: _* @members) + (inheritance_specifier)* @bases + (modifiers)* @mods) + => + (class_like_declaration + modifier: (modifier "protocol") + modifier: {..mods} + name: (identifier #{name}) + base_type: {..bases} + member: {..members}) + ), + // Protocol function — return type and body statements both optional. + rule!( + (protocol_function_declaration + name: @name + (parameter)* @params + return_type: _? @ret + body: (block statement: _* @body_stmts)? + (modifiers)* @mods) + => + (function_declaration + modifier: {..mods} + name: (identifier #{name}) + parameter: {..params} + return_type: {..ret} + body: (block stmt: {..body_stmts})) + ), + // Init declaration → constructor_declaration. Body statements optional; + // body itself is also optional (protocol requirement). + rule!( + (init_declaration + (parameter)* @params + body: (block statement: _* @body_stmts)? + (modifiers)* @mods) + => + (constructor_declaration + modifier: {..mods} + parameter: {..params} + body: (block stmt: {..body_stmts})) + ), + // Deinit declaration → destructor_declaration. Body statements optional. + rule!( + (deinit_declaration + body: (block statement: _* @body_stmts) + (modifiers)* @mods) + => + (destructor_declaration + modifier: {..mods} + body: (block stmt: {..body_stmts})) + ), + // Typealias declaration + rule!( + (typealias_declaration name: @name value: @val (modifiers)* @mods) + => + (type_alias_declaration + modifier: {..mods} + name: (identifier #{name}) + r#type: {val}) + ), + // Subscript declaration (not yet supported -- grammar needs to distinguish plain calls from subscript calls) + rule!( + (subscript_declaration (parameter)* @params (modifiers)* @mods) + => + (unsupported_node) + ), + // Associated type declaration (with optional bound) + rule!( + (associatedtype_declaration name: @name inherits_from: _? @bound (modifiers)* @mods) + => + (associated_type_declaration + modifier: {..mods} + name: (identifier #{name}) + bound: {..bound}) + ), + // Protocol property declaration: translate each accessor + // requirement to an `accessor_declaration` carrying the property + // name, type, and outer modifiers. Manual rule: we publish the + // property's name/type/modifiers into `ctx` and translate each + // accessor with `ctx.is_chained` toggled per iteration so the + // inner `getter_specifier`/`setter_specifier` rules emit + // complete nodes from the start (including the + // `chained_declaration` tag for non-first accessors). + manual_rule!( + (protocol_property_declaration + name: (pattern bound_identifier: @name) + requirements: (protocol_property_requirements accessor: _+ @accessors) + type: _? @ty + (modifiers)* @mods) + { + ctx.property_name = Some(tree!((identifier #{name}))); + ctx.property_type = ctx.translate_opt(ty)?; + let mut modifiers = Vec::new(); + for m in mods { + modifiers.extend(ctx.translate(m)?); + } + ctx.outer_modifiers = modifiers; + + let mut result = Vec::new(); + for (i, acc) in accessors.into_iter().enumerate() { + ctx.is_chained = i > 0; + result.extend(ctx.translate(acc)?); + } + Ok(result) + } + ), + // getter_specifier / setter_specifier → bodyless accessor_declaration + // getter_specifier / setter_specifier → bodyless + // accessor_declaration. Reads property name/type/modifiers from + // `ctx` set by the outer `protocol_property_declaration` rule. + rule!( + (getter_specifier) + => + (accessor_declaration + name: {ctx.property_name.ok_or("getter_specifier outside protocol_property_declaration context")?} + type: {..ctx.property_type} + accessor_kind: (accessor_kind "get") + modifier: {..ctx.outer_modifiers.clone()} + modifier: {..chained_modifier(&mut ctx)}) + ), + rule!( + (setter_specifier) + => + (accessor_declaration + name: {ctx.property_name.ok_or("setter_specifier outside protocol_property_declaration context")?} + type: {..ctx.property_type} + accessor_kind: (accessor_kind "set") + modifier: {..ctx.outer_modifiers.clone()} + modifier: {..chained_modifier(&mut ctx)}) + ), + // protocol_property_requirements wrapper — should be consumed by above; fallback + rule!((protocol_property_requirements accessor: _* @accs) => {..accs}), + // Computed getter → accessor_declaration (body optional). + // Reads property name/type from the outer property_binding rule + // and binding/outer modifiers + chained tag from the outer + // property_declaration rule. + rule!( + (computed_getter body: (block statement: _* @body)?) + => + (accessor_declaration + modifier: {..ctx.binding_modifier} + modifier: {..ctx.outer_modifiers.clone()} + modifier: {..chained_modifier(&mut ctx)} + name: {ctx.property_name.ok_or("computed_getter outside property_binding context")?} + type: {..ctx.property_type} + accessor_kind: (accessor_kind "get") + body: (block stmt: {..body})) + ), + // Computed setter with explicit parameter name. + rule!( + (computed_setter parameter: @param body: (block statement: _* @body)) + => + (accessor_declaration + modifier: {..ctx.binding_modifier} + modifier: {..ctx.outer_modifiers.clone()} + modifier: {..chained_modifier(&mut ctx)} + name: {ctx.property_name.ok_or("computed_setter outside property_binding context")?} + type: {..ctx.property_type} + accessor_kind: (accessor_kind "set") + parameter: (parameter pattern: (name_pattern identifier: (identifier #{param}))) + body: (block stmt: {..body})) + ), + // Computed setter without explicit parameter name; body optional. + rule!( + (computed_setter body: (block statement: _* @body)?) + => + (accessor_declaration + modifier: {..ctx.binding_modifier} + modifier: {..ctx.outer_modifiers.clone()} + modifier: {..chained_modifier(&mut ctx)} + name: {ctx.property_name.ok_or("computed_setter outside property_binding context")?} + type: {..ctx.property_type} + accessor_kind: (accessor_kind "set") + body: (block stmt: {..body})) + ), + // Computed modify → accessor_declaration + rule!( + (computed_modify body: (block statement: _* @body)) + => + (accessor_declaration + modifier: {..ctx.binding_modifier} + modifier: {..ctx.outer_modifiers.clone()} + modifier: {..chained_modifier(&mut ctx)} + name: {ctx.property_name.ok_or("computed_modify outside property_binding context")?} + type: {..ctx.property_type} + accessor_kind: (accessor_kind "modify") + body: (block stmt: {..body})) + ), + // willset/didset block — spread to children (only reachable as a + // fallback; the outer property_binding manual rule normally + // captures the willset/didset clauses directly). + rule!((willset_didset_block _* @clauses) => {..clauses}), + // willset clause → accessor_declaration (body optional). Reads + // `ctx.property_name` set by the outer property_binding rule and + // binding/outer modifiers + chained tag from the outer + // property_declaration rule. + rule!( + (willset_clause body: (block statement: _* @body)?) + => + (accessor_declaration + modifier: {..ctx.binding_modifier} + modifier: {..ctx.outer_modifiers.clone()} + modifier: {..chained_modifier(&mut ctx)} + name: {ctx.property_name.ok_or("willset_clause outside property_binding context")?} + accessor_kind: (accessor_kind "willSet") + body: (block stmt: {..body})) + ), + // didset clause → accessor_declaration (body optional). + rule!( + (didset_clause body: (block statement: _* @body)?) + => + (accessor_declaration + modifier: {..ctx.binding_modifier} + modifier: {..ctx.outer_modifiers.clone()} + modifier: {..chained_modifier(&mut ctx)} + name: {ctx.property_name.ok_or("didset_clause outside property_binding context")?} + accessor_kind: (accessor_kind "didSet") + body: (block stmt: {..body})) + ), + // Preprocessor conditionals — unsupported + rule!((diagnostic) => (unsupported_node)), // ---- Fallbacks ---- rule!( (_) @@ -350,14 +1170,17 @@ fn translation_rules() -> Vec { } pub fn language_spec(desugared_ast_schema: &'static str) -> simple::LanguageSpec { - let desugar = DesugaringConfig::new() + let ts_language: tree_sitter::Language = tree_sitter_swift::LANGUAGE.into(); + let config = DesugaringConfig::::new() .add_phase("translate", PhaseKind::OneShot, translation_rules()) .with_output_node_types_yaml(desugared_ast_schema); + let desugarer = ConcreteDesugarer::new(ts_language.clone(), config) + .expect("failed to build Swift desugarer"); simple::LanguageSpec { prefix: "swift", - ts_language: tree_sitter_swift::LANGUAGE.into(), + ts_language, node_types: tree_sitter_swift::NODE_TYPES, file_globs: vec!["*.swift".into(), "*.swiftinterface".into()], - desugar: Some(desugar), + desugar: Some(Box::new(desugarer)), } } diff --git a/unified/extractor/tests/corpus/swift/closures.txt b/unified/extractor/tests/corpus/swift/closures.txt index 0afea480a19..1d058dfb1e3 100644 --- a/unified/extractor/tests/corpus/swift/closures.txt +++ b/unified/extractor/tests/corpus/swift/closures.txt @@ -50,6 +50,35 @@ source_file top_level body: + block + stmt: + variable_declaration + modifier: modifier "let" + pattern: + name_pattern + identifier: identifier "f" + value: + function_expr + body: + block + stmt: + binary_expr + operator: infix_operator "*" + left: + name_expr + identifier: identifier "x" + right: int_literal "2" + parameter: + parameter + pattern: + name_pattern + identifier: identifier "x" + type: + named_type_expr + name: identifier "Int" + return_type: + named_type_expr + name: identifier "Int" === Closure with shorthand parameters @@ -82,6 +111,26 @@ source_file top_level body: + block + stmt: + variable_declaration + modifier: modifier "let" + pattern: + name_pattern + identifier: identifier "f" + value: + function_expr + body: + block + stmt: + binary_expr + operator: infix_operator "+" + left: + name_expr + identifier: identifier "$0" + right: + name_expr + identifier: identifier "$1" === Trailing closure @@ -114,6 +163,28 @@ source_file top_level body: + block + stmt: + call_expr + argument: + argument + value: + function_expr + body: + block + stmt: + binary_expr + operator: infix_operator "*" + left: + name_expr + identifier: identifier "$0" + right: int_literal "2" + callee: + member_access_expr + base: + name_expr + identifier: identifier "xs" + member: identifier "map" === Closure with capture list @@ -163,6 +234,31 @@ source_file top_level body: + block + stmt: + variable_declaration + modifier: modifier "let" + pattern: + name_pattern + identifier: identifier "f" + value: + function_expr + body: + block + stmt: + call_expr + callee: + member_access_expr + base: + name_expr + identifier: identifier "self" + member: identifier "doThing" + capture_declaration: + variable_declaration + modifier: modifier "weak" + pattern: + name_pattern + identifier: identifier "self" === Multi-statement closure @@ -236,3 +332,46 @@ source_file top_level body: + block + stmt: + variable_declaration + modifier: modifier "let" + pattern: + name_pattern + identifier: identifier "f" + value: + function_expr + body: + block + stmt: + variable_declaration + modifier: modifier "let" + pattern: + name_pattern + identifier: identifier "y" + value: + binary_expr + operator: infix_operator "+" + left: + name_expr + identifier: identifier "x" + right: int_literal "1" + return_expr + value: + binary_expr + operator: infix_operator "*" + left: + name_expr + identifier: identifier "y" + right: int_literal "2" + parameter: + parameter + pattern: + name_pattern + identifier: identifier "x" + type: + named_type_expr + name: identifier "Int" + return_type: + named_type_expr + name: identifier "Int" diff --git a/unified/extractor/tests/corpus/swift/collections.txt b/unified/extractor/tests/corpus/swift/collections.txt index afafc1e69ef..2ecdf5a0179 100644 --- a/unified/extractor/tests/corpus/swift/collections.txt +++ b/unified/extractor/tests/corpus/swift/collections.txt @@ -28,6 +28,19 @@ source_file top_level body: + block + stmt: + variable_declaration + modifier: modifier "let" + pattern: + name_pattern + identifier: identifier "xs" + value: + array_literal + element: + int_literal "1" + int_literal "2" + int_literal "3" === Empty array literal with type @@ -68,6 +81,22 @@ source_file top_level body: + block + stmt: + variable_declaration + modifier: modifier "let" + pattern: + name_pattern + identifier: identifier "xs" + type: + generic_type_expr + base: + named_type_expr + name: identifier "Array" + type_argument: + named_type_expr + name: identifier "Int" + value: array_literal "[]" === Dictionary literal @@ -106,6 +135,14 @@ source_file top_level body: + block + stmt: + variable_declaration + modifier: modifier "let" + pattern: + name_pattern + identifier: identifier "d" + value: map_literal "[\"a\": 1, \"b\": 2]" === Set literal @@ -155,6 +192,22 @@ source_file top_level body: + block + stmt: + variable_declaration + modifier: modifier "let" + pattern: + name_pattern + identifier: identifier "s" + type: + named_type_expr + name: identifier "Set" + value: + array_literal + element: + int_literal "1" + int_literal "2" + int_literal "3" === Tuple literal @@ -191,6 +244,14 @@ source_file top_level body: + block + stmt: + variable_declaration + modifier: modifier "let" + pattern: + name_pattern + identifier: identifier "t" + value: tuple_expr "(1, \"two\", 3.0)" === Subscript access @@ -232,9 +293,21 @@ source_file top_level body: - unsupported_node "// TODO: tree-sitter-swift parses `xs[0]` as a call_expression (same shape" - unsupported_node "// as `xs(0)`), so the mapping currently produces a call_expr. Update the" - unsupported_node "// parser / add a separate subscript_expr node and remap when fixed." + block + stmt: + variable_declaration + modifier: modifier "let" + pattern: + name_pattern + identifier: identifier "first" + value: + call_expr + argument: + argument + value: int_literal "0" + callee: + name_expr + identifier: identifier "xs" === Dictionary subscript @@ -276,8 +349,21 @@ source_file top_level body: - unsupported_node "// TODO: same parser issue as the array subscript case above —" - unsupported_node "// `d[\"key\"]` is parsed as `call_expression(d, (\"key\"))`." + block + stmt: + variable_declaration + modifier: modifier "let" + pattern: + name_pattern + identifier: identifier "v" + value: + call_expr + argument: + argument + value: string_literal "\"key\"" + callee: + name_expr + identifier: identifier "d" === Tuple member access @@ -309,3 +395,16 @@ source_file top_level body: + block + stmt: + variable_declaration + modifier: modifier "let" + pattern: + name_pattern + identifier: identifier "n" + value: + member_access_expr + base: + name_expr + identifier: identifier "t" + member: identifier "0" diff --git a/unified/extractor/tests/corpus/swift/control-flow.txt b/unified/extractor/tests/corpus/swift/control-flow.txt index 600e1126cbf..9a740cb9d45 100644 --- a/unified/extractor/tests/corpus/swift/control-flow.txt +++ b/unified/extractor/tests/corpus/swift/control-flow.txt @@ -35,6 +35,28 @@ source_file top_level body: + block + stmt: + if_expr + condition: + binary_expr + operator: infix_operator ">" + left: + name_expr + identifier: identifier "x" + right: int_literal "0" + then: + block + stmt: + call_expr + argument: + argument + value: + name_expr + identifier: identifier "x" + callee: + name_expr + identifier: identifier "print" === If-else @@ -90,6 +112,43 @@ source_file top_level body: + block + stmt: + if_expr + condition: + binary_expr + operator: infix_operator ">" + left: + name_expr + identifier: identifier "x" + right: int_literal "0" + else: + block + stmt: + call_expr + argument: + argument + value: + unary_expr + operand: + name_expr + identifier: identifier "x" + operator: prefix_operator "-" + callee: + name_expr + identifier: identifier "print" + then: + block + stmt: + call_expr + argument: + argument + value: + name_expr + identifier: identifier "x" + callee: + name_expr + identifier: identifier "print" === If-else-if chain @@ -165,6 +224,55 @@ source_file top_level body: + block + stmt: + if_expr + condition: + binary_expr + operator: infix_operator ">" + left: + name_expr + identifier: identifier "x" + right: int_literal "0" + else: + if_expr + condition: + binary_expr + operator: infix_operator "<" + left: + name_expr + identifier: identifier "x" + right: int_literal "0" + else: + block + stmt: + call_expr + argument: + argument + value: int_literal "3" + callee: + name_expr + identifier: identifier "print" + then: + block + stmt: + call_expr + argument: + argument + value: int_literal "2" + callee: + name_expr + identifier: identifier "print" + then: + block + stmt: + call_expr + argument: + argument + value: int_literal "1" + callee: + name_expr + identifier: identifier "print" === If-let optional binding @@ -207,6 +315,39 @@ source_file top_level body: + block + stmt: + if_expr + condition: + pattern_guard_expr + pattern: + constructor_pattern + element: + pattern_element + pattern: + name_pattern + identifier: identifier "value" + constructor: + member_access_expr + base: + named_type_expr + name: identifier "Optional" + member: identifier "some" + value: + name_expr + identifier: identifier "optional" + then: + block + stmt: + call_expr + argument: + argument + value: + name_expr + identifier: identifier "value" + callee: + name_expr + identifier: identifier "print" === Guard let @@ -240,6 +381,30 @@ source_file top_level body: + block + stmt: + guard_if_stmt + condition: + pattern_guard_expr + pattern: + constructor_pattern + element: + pattern_element + pattern: + name_pattern + identifier: identifier "value" + constructor: + member_access_expr + base: + named_type_expr + name: identifier "Optional" + member: identifier "some" + value: + name_expr + identifier: identifier "optional" + else: + block + stmt: return_expr "return" === Ternary expression @@ -277,6 +442,27 @@ source_file top_level body: + block + stmt: + variable_declaration + modifier: modifier "let" + pattern: + name_pattern + identifier: identifier "y" + value: + if_expr + condition: + binary_expr + operator: infix_operator ">" + left: + name_expr + identifier: identifier "x" + right: int_literal "0" + else: + unary_expr + operand: int_literal "1" + operator: prefix_operator "-" + then: int_literal "1" === Switch statement @@ -357,6 +543,54 @@ source_file top_level body: + block + stmt: + switch_expr + case: + switch_case + body: + block + stmt: + call_expr + argument: + argument + value: string_literal "\"one\"" + callee: + name_expr + identifier: identifier "print" + pattern: + expr_equality_pattern + expr: int_literal "1" + switch_case + body: + block + stmt: + call_expr + argument: + argument + value: string_literal "\"two or three\"" + callee: + name_expr + identifier: identifier "print" + pattern: + expr_equality_pattern + expr: int_literal "2" + expr_equality_pattern + expr: int_literal "3" + switch_case + body: + block + stmt: + call_expr + argument: + argument + value: string_literal "\"other\"" + callee: + name_expr + identifier: identifier "print" + value: + name_expr + identifier: identifier "x" === Switch with binding pattern @@ -396,6 +630,7 @@ source_file pattern: pattern bound_identifier: simple_identifier "r" + dot: . name: simple_identifier "circle" statement: call_expression @@ -428,6 +663,7 @@ source_file pattern: pattern bound_identifier: simple_identifier "s" + dot: . name: simple_identifier "square" statement: call_expression @@ -445,3 +681,207 @@ source_file top_level body: + block + stmt: + switch_expr + case: + switch_case + body: + block + stmt: + call_expr + argument: + argument + value: + name_expr + identifier: identifier "r" + callee: + name_expr + identifier: identifier "print" + pattern: + constructor_pattern + element: + pattern_element + pattern: + name_pattern + identifier: identifier "r" + constructor: + member_access_expr + base: inferred_type_expr "." + member: identifier "circle" + switch_case + body: + block + stmt: + call_expr + argument: + argument + value: + name_expr + identifier: identifier "s" + callee: + name_expr + identifier: identifier "print" + pattern: + constructor_pattern + element: + pattern_element + pattern: + name_pattern + identifier: identifier "s" + constructor: + member_access_expr + base: inferred_type_expr "." + member: identifier "square" + value: + name_expr + identifier: identifier "shape" + +=== +Switch with labeled case pattern arguments +=== + +switch x { +case .implicit(isAcknowledged: false): + print("yes") +case .thread(threadRowId: _, let rowId): + print(rowId) +} + +--- + +source_file + statement: + switch_statement + entry: + switch_entry + pattern: + switch_pattern + pattern: + pattern + kind: + case_pattern + arguments: + tuple_pattern + item: + tuple_pattern_item + name: simple_identifier "isAcknowledged" + pattern: + pattern + kind: + boolean_literal + dot: . + name: simple_identifier "implicit" + statement: + call_expression + function: simple_identifier "print" + suffix: + call_suffix + arguments: + value_arguments + argument: + value_argument + value: + line_string_literal + text: line_str_text "yes" + switch_entry + pattern: + switch_pattern + pattern: + pattern + kind: + case_pattern + arguments: + tuple_pattern + item: + tuple_pattern_item + name: simple_identifier "threadRowId" + pattern: + pattern + kind: wildcard_pattern "_" + tuple_pattern_item + pattern: + pattern + kind: + binding_pattern + binding: + value_binding_pattern + mutability: let + pattern: + pattern + bound_identifier: simple_identifier "rowId" + dot: . + name: simple_identifier "thread" + statement: + call_expression + function: simple_identifier "print" + suffix: + call_suffix + arguments: + value_arguments + argument: + value_argument + value: simple_identifier "rowId" + expr: simple_identifier "x" + +--- + +top_level + body: + block + stmt: + switch_expr + case: + switch_case + body: + block + stmt: + call_expr + argument: + argument + value: string_literal "\"yes\"" + callee: + name_expr + identifier: identifier "print" + pattern: + constructor_pattern + element: + pattern_element + key: identifier "isAcknowledged" + pattern: + expr_equality_pattern + expr: boolean_literal "false" + constructor: + member_access_expr + base: inferred_type_expr "." + member: identifier "implicit" + switch_case + body: + block + stmt: + call_expr + argument: + argument + value: + name_expr + identifier: identifier "rowId" + callee: + name_expr + identifier: identifier "print" + pattern: + constructor_pattern + element: + pattern_element + key: identifier "threadRowId" + pattern: ignore_pattern "_" + pattern_element + pattern: + name_pattern + identifier: identifier "rowId" + constructor: + member_access_expr + base: inferred_type_expr "." + member: identifier "thread" + value: + name_expr + identifier: identifier "x" diff --git a/unified/extractor/tests/corpus/swift/desugar.txt b/unified/extractor/tests/corpus/swift/desugar.txt index 9f9ffeb070a..1611943bf1a 100644 --- a/unified/extractor/tests/corpus/swift/desugar.txt +++ b/unified/extractor/tests/corpus/swift/desugar.txt @@ -17,6 +17,12 @@ source_file top_level body: + block + stmt: + binary_expr + operator: infix_operator "+" + left: int_literal "1" + right: int_literal "2" === Another additive expression is desugared @@ -37,3 +43,144 @@ source_file top_level body: + block + stmt: + binary_expr + operator: infix_operator "+" + left: + name_expr + identifier: identifier "foo" + right: + name_expr + identifier: identifier "bar" + +=== +Simple import with single name +=== + +import Foundation + +--- + +source_file + statement: + import_declaration + name: + identifier + part: simple_identifier "Foundation" + +--- + +top_level + body: + block + stmt: + import_declaration + pattern: bulk_importing_pattern "import Foundation" + imported_expr: + name_expr + identifier: identifier "Foundation" + +=== +Import with dotted path (two parts) +=== + +import Foundation.Networking + +--- + +source_file + statement: + import_declaration + name: + identifier + part: + simple_identifier "Foundation" + simple_identifier "Networking" + +--- + +top_level + body: + block + stmt: + import_declaration + pattern: bulk_importing_pattern "import Foundation.Networking" + imported_expr: + member_access_expr + base: + name_expr + identifier: identifier "Foundation" + member: identifier "Networking" + +=== +Import with deeply nested path (three parts) +=== + +import Foundation.Networking.URLSession + +--- + +source_file + statement: + import_declaration + name: + identifier + part: + simple_identifier "Foundation" + simple_identifier "Networking" + simple_identifier "URLSession" + +--- + +top_level + body: + block + stmt: + import_declaration + pattern: bulk_importing_pattern "import Foundation.Networking.URLSession" + imported_expr: + member_access_expr + base: + member_access_expr + base: + name_expr + identifier: identifier "Foundation" + member: identifier "Networking" + member: identifier "URLSession" + +=== +Scoped import uses name_pattern +=== + +import struct Foundation.Date + +--- + +source_file + statement: + import_declaration + name: + identifier + part: + simple_identifier "Foundation" + simple_identifier "Date" + scoped_import_kind: struct + +--- + +top_level + body: + block + stmt: + import_declaration + modifier: modifier "struct" + pattern: + name_pattern + identifier: identifier "Date" + imported_expr: + member_access_expr + base: + name_expr + identifier: identifier "Foundation" + member: identifier "Date" diff --git a/unified/extractor/tests/corpus/swift/functions.txt b/unified/extractor/tests/corpus/swift/functions.txt index 0a8210a4cf7..ed86618910c 100644 --- a/unified/extractor/tests/corpus/swift/functions.txt +++ b/unified/extractor/tests/corpus/swift/functions.txt @@ -31,6 +31,20 @@ source_file top_level body: + block + stmt: + function_declaration + body: + block + stmt: + call_expr + argument: + argument + value: string_literal "\"hello\"" + callee: + name_expr + identifier: identifier "print" + name: identifier "greet" === Function with parameters and return type @@ -93,6 +107,37 @@ source_file top_level body: + block + stmt: + function_declaration + body: + block + stmt: + return_expr + value: + binary_expr + operator: infix_operator "+" + left: + name_expr + identifier: identifier "a" + right: + name_expr + identifier: identifier "b" + name: identifier "add" + parameter: + parameter + external_name: identifier "_" + pattern: + name_pattern + identifier: identifier "a" + parameter + external_name: identifier "_" + pattern: + name_pattern + identifier: identifier "b" + return_type: + named_type_expr + name: identifier "Int" === Function with named parameters @@ -138,6 +183,28 @@ source_file top_level body: + block + stmt: + function_declaration + body: + block + stmt: + call_expr + argument: + argument + value: + name_expr + identifier: identifier "name" + callee: + name_expr + identifier: identifier "print" + name: identifier "greet" + parameter: + parameter + external_name: identifier "person" + pattern: + name_pattern + identifier: identifier "name" === Function with default parameter value @@ -185,6 +252,28 @@ source_file top_level body: + block + stmt: + function_declaration + body: + block + stmt: + call_expr + argument: + argument + value: + name_expr + identifier: identifier "name" + callee: + name_expr + identifier: identifier "print" + name: identifier "greet" + parameter: + parameter + default: string_literal "\"world\"" + pattern: + name_pattern + identifier: identifier "name" === Variadic function @@ -249,6 +338,38 @@ source_file top_level body: + block + stmt: + function_declaration + body: + block + stmt: + return_expr + value: + call_expr + argument: + argument + value: int_literal "0" + argument + value: + name_expr + identifier: identifier "+" + callee: + member_access_expr + base: + name_expr + identifier: identifier "values" + member: identifier "reduce" + name: identifier "sum" + parameter: + parameter + external_name: identifier "_" + pattern: + name_pattern + identifier: identifier "values" + return_type: + named_type_expr + name: identifier "Int" === Function call @@ -276,6 +397,17 @@ source_file top_level body: + block + stmt: + call_expr + argument: + argument + value: int_literal "1" + argument + value: int_literal "2" + callee: + name_expr + identifier: identifier "foo" === Function call with labelled arguments @@ -306,6 +438,16 @@ source_file top_level body: + block + stmt: + call_expr + argument: + argument + name: identifier "person" + value: string_literal "\"Bob\"" + callee: + name_expr + identifier: identifier "greet" === Method call @@ -336,6 +478,18 @@ source_file top_level body: + block + stmt: + call_expr + argument: + argument + value: int_literal "1" + callee: + member_access_expr + base: + name_expr + identifier: identifier "list" + member: identifier "append" === Generic function @@ -387,3 +541,117 @@ source_file top_level body: + block + stmt: + function_declaration + body: + block + stmt: + return_expr + value: + name_expr + identifier: identifier "x" + name: identifier "identity" + parameter: + parameter + external_name: identifier "_" + pattern: + name_pattern + identifier: identifier "x" + return_type: + named_type_expr + name: identifier "T" + +=== +Leading-dot expression value +=== + +let x = .foo + +--- + +source_file + statement: + property_declaration + binding: + value_binding_pattern + mutability: let + declarator: + property_binding + name: + pattern + bound_identifier: simple_identifier "x" + value: + prefix_expression + operation: . + target: simple_identifier "foo" + +--- + +top_level + body: + block + stmt: + variable_declaration + modifier: modifier "let" + pattern: + name_pattern + identifier: identifier "x" + value: + member_access_expr + base: inferred_type_expr ".foo" + member: identifier "foo" + +=== +Leading-dot expression call +=== + +let y = .some(1) + +--- + +source_file + statement: + property_declaration + binding: + value_binding_pattern + mutability: let + declarator: + property_binding + name: + pattern + bound_identifier: simple_identifier "y" + value: + call_expression + function: + prefix_expression + operation: . + target: simple_identifier "some" + suffix: + call_suffix + arguments: + value_arguments + argument: + value_argument + value: integer_literal "1" + +--- + +top_level + body: + block + stmt: + variable_declaration + modifier: modifier "let" + pattern: + name_pattern + identifier: identifier "y" + value: + call_expr + argument: + argument + value: int_literal "1" + callee: + member_access_expr + base: inferred_type_expr ".some" + member: identifier "some" diff --git a/unified/extractor/tests/corpus/swift/literals.txt b/unified/extractor/tests/corpus/swift/literals.txt index 5044831a869..bf0e4aae560 100644 --- a/unified/extractor/tests/corpus/swift/literals.txt +++ b/unified/extractor/tests/corpus/swift/literals.txt @@ -13,6 +13,8 @@ source_file top_level body: + block + stmt: int_literal "42" === Negative integer literal @@ -32,6 +34,11 @@ source_file top_level body: + block + stmt: + unary_expr + operand: int_literal "7" + operator: prefix_operator "-" === Floating-point literal @@ -48,6 +55,8 @@ source_file top_level body: + block + stmt: float_literal "3.14" === Boolean literals @@ -67,6 +76,10 @@ source_file top_level body: + block + stmt: + boolean_literal "true" + boolean_literal "false" === Nil literal @@ -83,6 +96,8 @@ source_file top_level body: + block + stmt: builtin_expr "nil" === String literal @@ -101,6 +116,8 @@ source_file top_level body: + block + stmt: string_literal "\"hello\"" === String with interpolation @@ -122,3 +139,5 @@ source_file top_level body: + block + stmt: string_literal "\"hello \\(name)\"" diff --git a/unified/extractor/tests/corpus/swift/loops.txt b/unified/extractor/tests/corpus/swift/loops.txt index 8b9f3410d35..b0e25debff5 100644 --- a/unified/extractor/tests/corpus/swift/loops.txt +++ b/unified/extractor/tests/corpus/swift/loops.txt @@ -37,6 +37,30 @@ source_file top_level body: + block + stmt: + for_each_stmt + body: + block + stmt: + call_expr + argument: + argument + value: + name_expr + identifier: identifier "x" + callee: + name_expr + identifier: identifier "print" + pattern: + name_pattern + identifier: identifier "x" + iterable: + array_literal + element: + int_literal "1" + int_literal "2" + int_literal "3" === For-in over range @@ -76,6 +100,29 @@ source_file top_level body: + block + stmt: + for_each_stmt + body: + block + stmt: + call_expr + argument: + argument + value: + name_expr + identifier: identifier "i" + callee: + name_expr + identifier: identifier "print" + pattern: + name_pattern + identifier: identifier "i" + iterable: + binary_expr + operator: infix_operator "..<" + left: int_literal "0" + right: int_literal "10" === For-in with where clause @@ -119,6 +166,34 @@ source_file top_level body: + block + stmt: + for_each_stmt + body: + block + stmt: + call_expr + argument: + argument + value: + name_expr + identifier: identifier "x" + callee: + name_expr + identifier: identifier "print" + pattern: + name_pattern + identifier: identifier "x" + guard: + binary_expr + operator: infix_operator ">" + left: + name_expr + identifier: identifier "x" + right: int_literal "0" + iterable: + name_expr + identifier: identifier "xs" === While loop @@ -154,6 +229,25 @@ source_file top_level body: + block + stmt: + while_stmt + body: + block + stmt: + compound_assign_expr + operator: infix_operator "-=" + target: + name_expr + identifier: identifier "x" + value: int_literal "1" + condition: + binary_expr + operator: infix_operator ">" + left: + name_expr + identifier: identifier "x" + right: int_literal "0" === Repeat-while loop @@ -189,6 +283,25 @@ source_file top_level body: + block + stmt: + do_while_stmt + body: + block + stmt: + compound_assign_expr + operator: infix_operator "-=" + target: + name_expr + identifier: identifier "x" + value: int_literal "1" + condition: + binary_expr + operator: infix_operator ">" + left: + name_expr + identifier: identifier "x" + right: int_literal "0" === Break and continue @@ -252,3 +365,46 @@ source_file top_level body: + block + stmt: + for_each_stmt + body: + block + stmt: + if_expr + condition: + binary_expr + operator: infix_operator "<" + left: + name_expr + identifier: identifier "x" + right: int_literal "0" + then: + block + stmt: continue_expr "continue" + if_expr + condition: + binary_expr + operator: infix_operator ">" + left: + name_expr + identifier: identifier "x" + right: int_literal "100" + then: + block + stmt: break_expr "break" + call_expr + argument: + argument + value: + name_expr + identifier: identifier "x" + callee: + name_expr + identifier: identifier "print" + pattern: + name_pattern + identifier: identifier "x" + iterable: + name_expr + identifier: identifier "xs" diff --git a/unified/extractor/tests/corpus/swift/operators.txt b/unified/extractor/tests/corpus/swift/operators.txt index f1a4a5fcdb2..d912a1085dc 100644 --- a/unified/extractor/tests/corpus/swift/operators.txt +++ b/unified/extractor/tests/corpus/swift/operators.txt @@ -17,6 +17,16 @@ source_file top_level body: + block + stmt: + binary_expr + operator: infix_operator "+" + left: + name_expr + identifier: identifier "a" + right: + name_expr + identifier: identifier "b" === Subtraction @@ -37,6 +47,16 @@ source_file top_level body: + block + stmt: + binary_expr + operator: infix_operator "-" + left: + name_expr + identifier: identifier "a" + right: + name_expr + identifier: identifier "b" === Multiplication @@ -57,6 +77,16 @@ source_file top_level body: + block + stmt: + binary_expr + operator: infix_operator "*" + left: + name_expr + identifier: identifier "a" + right: + name_expr + identifier: identifier "b" === Division @@ -77,6 +107,16 @@ source_file top_level body: + block + stmt: + binary_expr + operator: infix_operator "/" + left: + name_expr + identifier: identifier "a" + right: + name_expr + identifier: identifier "b" === Operator precedence: addition and multiplication @@ -101,6 +141,22 @@ source_file top_level body: + block + stmt: + binary_expr + operator: infix_operator "+" + left: + name_expr + identifier: identifier "a" + right: + binary_expr + operator: infix_operator "*" + left: + name_expr + identifier: identifier "b" + right: + name_expr + identifier: identifier "c" === Parenthesised expression @@ -129,6 +185,14 @@ source_file top_level body: + block + stmt: + binary_expr + operator: infix_operator "*" + left: tuple_expr "(a + b)" + right: + name_expr + identifier: identifier "c" === Comparison @@ -149,6 +213,16 @@ source_file top_level body: + block + stmt: + binary_expr + operator: infix_operator "<" + left: + name_expr + identifier: identifier "a" + right: + name_expr + identifier: identifier "b" === Equality @@ -169,6 +243,16 @@ source_file top_level body: + block + stmt: + binary_expr + operator: infix_operator "==" + left: + name_expr + identifier: identifier "a" + right: + name_expr + identifier: identifier "b" === Logical and @@ -189,6 +273,16 @@ source_file top_level body: + block + stmt: + binary_expr + operator: infix_operator "&&" + left: + name_expr + identifier: identifier "a" + right: + name_expr + identifier: identifier "b" === Logical or @@ -209,6 +303,16 @@ source_file top_level body: + block + stmt: + binary_expr + operator: infix_operator "||" + left: + name_expr + identifier: identifier "a" + right: + name_expr + identifier: identifier "b" === Logical not @@ -228,6 +332,13 @@ source_file top_level body: + block + stmt: + unary_expr + operand: + name_expr + identifier: identifier "a" + operator: prefix_operator "!" === Range operator @@ -248,3 +359,9 @@ source_file top_level body: + block + stmt: + binary_expr + operator: infix_operator "..." + left: int_literal "1" + right: int_literal "10" diff --git a/unified/extractor/tests/corpus/swift/optionals-and-errors.txt b/unified/extractor/tests/corpus/swift/optionals-and-errors.txt index 572e9181a68..23e545f5463 100644 --- a/unified/extractor/tests/corpus/swift/optionals-and-errors.txt +++ b/unified/extractor/tests/corpus/swift/optionals-and-errors.txt @@ -34,6 +34,22 @@ source_file top_level body: + block + stmt: + variable_declaration + modifier: modifier "let" + pattern: + name_pattern + identifier: identifier "x" + type: + generic_type_expr + base: + named_type_expr + name: identifier "Optional" + type_argument: + named_type_expr + name: identifier "Int" + value: builtin_expr "nil" === Optional chaining @@ -74,6 +90,22 @@ source_file top_level body: + block + stmt: + variable_declaration + modifier: modifier "let" + pattern: + name_pattern + identifier: identifier "n" + value: + member_access_expr + base: + member_access_expr + base: + name_expr + identifier: identifier "obj" + member: identifier "foo" + member: identifier "bar" === Force unwrap @@ -103,6 +135,19 @@ source_file top_level body: + block + stmt: + variable_declaration + modifier: modifier "let" + pattern: + name_pattern + identifier: identifier "n" + value: + unary_expr + operand: + name_expr + identifier: identifier "opt" + operator: postfix_operator "!" === Nil-coalescing @@ -132,6 +177,20 @@ source_file top_level body: + block + stmt: + variable_declaration + modifier: modifier "let" + pattern: + name_pattern + identifier: identifier "n" + value: + binary_expr + operator: infix_operator "??" + left: + name_expr + identifier: identifier "opt" + right: int_literal "0" === Throwing function @@ -167,6 +226,18 @@ source_file top_level body: + block + stmt: + function_declaration + body: + block + stmt: + return_expr + value: string_literal "\"\"" + name: identifier "read" + return_type: + named_type_expr + name: identifier "String" === Do-catch @@ -216,6 +287,33 @@ source_file top_level body: + block + stmt: + try_expr + body: + block + stmt: + unary_expr + operand: + call_expr + callee: + name_expr + identifier: identifier "foo" + operator: prefix_operator "try" + catch_clause: + catch_clause + body: + block + stmt: + call_expr + argument: + argument + value: + name_expr + identifier: identifier "error" + callee: + name_expr + identifier: identifier "print" === Try? expression @@ -252,6 +350,21 @@ source_file top_level body: + block + stmt: + variable_declaration + modifier: modifier "let" + pattern: + name_pattern + identifier: identifier "result" + value: + unary_expr + operand: + call_expr + callee: + name_expr + identifier: identifier "foo" + operator: prefix_operator "try?" === Try! expression @@ -288,3 +401,18 @@ source_file top_level body: + block + stmt: + variable_declaration + modifier: modifier "let" + pattern: + name_pattern + identifier: identifier "result" + value: + unary_expr + operand: + call_expr + callee: + name_expr + identifier: identifier "foo" + operator: prefix_operator "try!" diff --git a/unified/extractor/tests/corpus/swift/types.txt b/unified/extractor/tests/corpus/swift/types.txt index 0bebaa1238f..9c22ae74798 100644 --- a/unified/extractor/tests/corpus/swift/types.txt +++ b/unified/extractor/tests/corpus/swift/types.txt @@ -18,6 +18,11 @@ source_file top_level body: + block + stmt: + class_like_declaration + modifier: modifier "class" + name: identifier "Foo" === Class with stored properties @@ -79,6 +84,28 @@ source_file top_level body: + block + stmt: + class_like_declaration + member: + variable_declaration + modifier: modifier "var" + pattern: + name_pattern + identifier: identifier "x" + type: + named_type_expr + name: identifier "Int" + variable_declaration + modifier: modifier "var" + pattern: + name_pattern + identifier: identifier "y" + type: + named_type_expr + name: identifier "Int" + modifier: modifier "class" + name: identifier "Point" === Class with initializer @@ -152,6 +179,34 @@ source_file top_level body: + block + stmt: + class_like_declaration + member: + variable_declaration + modifier: modifier "var" + pattern: + name_pattern + identifier: identifier "x" + type: + named_type_expr + name: identifier "Int" + constructor_declaration + body: + block + stmt: + assign_expr + target: + member_access_expr + base: + name_expr + identifier: identifier "self" + member: identifier "x" + value: + name_expr + identifier: identifier "x" + modifier: modifier "class" + name: identifier "Point" === Class with method @@ -200,6 +255,29 @@ source_file top_level body: + block + stmt: + class_like_declaration + member: + variable_declaration + modifier: modifier "var" + pattern: + name_pattern + identifier: identifier "n" + value: int_literal "0" + function_declaration + body: + block + stmt: + compound_assign_expr + operator: infix_operator "+=" + target: + name_expr + identifier: identifier "n" + value: int_literal "1" + name: identifier "bump" + modifier: modifier "class" + name: identifier "Counter" === Class inheritance @@ -228,6 +306,11 @@ source_file top_level body: + block + stmt: + class_like_declaration + modifier: modifier "class" + name: identifier "Dog" === Struct @@ -289,6 +372,28 @@ source_file top_level body: + block + stmt: + class_like_declaration + member: + variable_declaration + modifier: modifier "let" + pattern: + name_pattern + identifier: identifier "x" + type: + named_type_expr + name: identifier "Int" + variable_declaration + modifier: modifier "let" + pattern: + name_pattern + identifier: identifier "y" + type: + named_type_expr + name: identifier "Int" + modifier: modifier "struct" + name: identifier "Point" === Enum with cases @@ -332,6 +437,32 @@ source_file top_level body: + block + stmt: + class_like_declaration + member: + variable_declaration + modifier: modifier "enum_case" + pattern: + name_pattern + identifier: identifier "north" + variable_declaration + modifier: modifier "enum_case" + pattern: + name_pattern + identifier: identifier "south" + variable_declaration + modifier: modifier "enum_case" + pattern: + name_pattern + identifier: identifier "east" + variable_declaration + modifier: modifier "enum_case" + pattern: + name_pattern + identifier: identifier "west" + modifier: modifier "enum" + name: identifier "Direction" === Enum with associated values @@ -389,6 +520,40 @@ source_file top_level body: + block + stmt: + class_like_declaration + member: + class_like_declaration + member: + constructor_declaration + body: block "circle(radius: Double)" + parameter: + parameter + pattern: + name_pattern + identifier: identifier "radius" + type: + named_type_expr + name: identifier "Double" + modifier: modifier "enum_case" + name: identifier "circle" + class_like_declaration + member: + constructor_declaration + body: block "square(side: Double)" + parameter: + parameter + pattern: + name_pattern + identifier: identifier "side" + type: + named_type_expr + name: identifier "Double" + modifier: modifier "enum_case" + name: identifier "square" + modifier: modifier "enum" + name: identifier "Shape" === Protocol declaration @@ -414,6 +579,15 @@ source_file top_level body: + block + stmt: + class_like_declaration + member: + function_declaration + body: block "func draw()" + name: identifier "draw" + modifier: modifier "protocol" + name: identifier "Drawable" === Extension @@ -463,6 +637,30 @@ source_file top_level body: + block + stmt: + class_like_declaration + member: + function_declaration + body: + block + stmt: + return_expr + value: + binary_expr + operator: infix_operator "*" + left: + name_expr + identifier: identifier "self" + right: + name_expr + identifier: identifier "self" + name: identifier "squared" + return_type: + named_type_expr + name: identifier "Int" + modifier: modifier "extension" + name: identifier "Int" === Computed property @@ -555,6 +753,48 @@ source_file top_level body: + block + stmt: + class_like_declaration + member: + variable_declaration + modifier: modifier "var" + pattern: + name_pattern + identifier: identifier "w" + type: + named_type_expr + name: identifier "Double" + variable_declaration + modifier: modifier "var" + pattern: + name_pattern + identifier: identifier "h" + type: + named_type_expr + name: identifier "Double" + accessor_declaration + body: + block + stmt: + return_expr + value: + binary_expr + operator: infix_operator "*" + left: + name_expr + identifier: identifier "w" + right: + name_expr + identifier: identifier "h" + modifier: modifier "var" + name: identifier "area" + type: + named_type_expr + name: identifier "Double" + accessor_kind: accessor_kind "get" + modifier: modifier "class" + name: identifier "Rect" === Property with getter and setter @@ -639,3 +879,204 @@ source_file top_level body: + block + stmt: + class_like_declaration + member: + variable_declaration + modifier: modifier "var" + pattern: + name_pattern + identifier: identifier "_v" + value: int_literal "0" + accessor_declaration + body: + block + stmt: + return_expr + value: + name_expr + identifier: identifier "_v" + modifier: modifier "var" + name: identifier "v" + type: + named_type_expr + name: identifier "Int" + accessor_kind: accessor_kind "get" + accessor_declaration + body: + block + stmt: + assign_expr + target: + name_expr + identifier: identifier "_v" + value: + name_expr + identifier: identifier "newValue" + modifier: + modifier "var" + modifier "chained_declaration" + name: identifier "v" + type: + named_type_expr + name: identifier "Int" + accessor_kind: accessor_kind "set" + modifier: modifier "class" + name: identifier "Box" + +=== +Protocol with read-only and read-write property requirements +=== + +protocol P { + var foo: Int { get } + var bar: String { get set } +} + +--- + +source_file + statement: + protocol_declaration + body: + protocol_body + member: + protocol_property_declaration + name: + pattern + binding: + value_binding_pattern + mutability: var + bound_identifier: simple_identifier "foo" + requirements: + protocol_property_requirements + accessor: + getter_specifier + type: + type_annotation + type: + type + name: + user_type + part: + simple_user_type + name: type_identifier "Int" + protocol_property_declaration + name: + pattern + binding: + value_binding_pattern + mutability: var + bound_identifier: simple_identifier "bar" + requirements: + protocol_property_requirements + accessor: + getter_specifier + setter_specifier + type: + type_annotation + type: + type + name: + user_type + part: + simple_user_type + name: type_identifier "String" + name: type_identifier "P" + +--- + +top_level + body: + block + stmt: + class_like_declaration + member: + accessor_declaration + name: identifier "foo" + type: + named_type_expr + name: identifier "Int" + accessor_kind: accessor_kind "get" + accessor_declaration + name: identifier "bar" + type: + named_type_expr + name: identifier "String" + accessor_kind: accessor_kind "get" + accessor_declaration + modifier: modifier "chained_declaration" + name: identifier "bar" + type: + named_type_expr + name: identifier "String" + accessor_kind: accessor_kind "set" + modifier: modifier "protocol" + name: identifier "P" + +=== +Enum with comma-separated cases (chained_declaration) +=== + +enum Suit { + case clubs, diamonds, hearts, spades +} + +--- + +source_file + statement: + class_declaration + body: + enum_class_body + member: + enum_entry + case: + enum_case_entry + name: simple_identifier "clubs" + enum_case_entry + name: simple_identifier "diamonds" + enum_case_entry + name: simple_identifier "hearts" + enum_case_entry + name: simple_identifier "spades" + declaration_kind: enum + name: type_identifier "Suit" + +--- + +top_level + body: + block + stmt: + class_like_declaration + member: + variable_declaration + modifier: modifier "enum_case" + pattern: + name_pattern + identifier: identifier "clubs" + variable_declaration + modifier: + modifier "chained_declaration" + modifier "enum_case" + pattern: + name_pattern + identifier: identifier "diamonds" + variable_declaration + modifier: + modifier "chained_declaration" + modifier "enum_case" + pattern: + name_pattern + identifier: identifier "hearts" + variable_declaration + modifier: + modifier "chained_declaration" + modifier "enum_case" + pattern: + name_pattern + identifier: identifier "spades" + modifier: modifier "enum" + name: identifier "Suit" diff --git a/unified/extractor/tests/corpus/swift/variables.txt b/unified/extractor/tests/corpus/swift/variables.txt index 1911ddd02b1..78b80d9a509 100644 --- a/unified/extractor/tests/corpus/swift/variables.txt +++ b/unified/extractor/tests/corpus/swift/variables.txt @@ -23,6 +23,14 @@ source_file top_level body: + block + stmt: + variable_declaration + modifier: modifier "let" + pattern: + name_pattern + identifier: identifier "x" + value: int_literal "1" === Var binding @@ -49,6 +57,14 @@ source_file top_level body: + block + stmt: + variable_declaration + modifier: modifier "var" + pattern: + name_pattern + identifier: identifier "x" + value: int_literal "1" === Let with type annotation @@ -84,6 +100,17 @@ source_file top_level body: + block + stmt: + variable_declaration + modifier: modifier "let" + pattern: + name_pattern + identifier: identifier "x" + type: + named_type_expr + name: identifier "Int" + value: int_literal "1" === Var without initialiser @@ -118,6 +145,16 @@ source_file top_level body: + block + stmt: + variable_declaration + modifier: modifier "var" + pattern: + name_pattern + identifier: identifier "x" + type: + named_type_expr + name: identifier "Int" === Tuple destructuring binding @@ -154,6 +191,28 @@ source_file top_level body: + block + stmt: + variable_declaration + modifier: modifier "let" + pattern: + tuple_pattern + element: + pattern_element + pattern: + expr_equality_pattern + expr: + name_expr + identifier: identifier "a" + pattern_element + pattern: + expr_equality_pattern + expr: + name_expr + identifier: identifier "b" + value: + name_expr + identifier: identifier "pair" === Multiple bindings on one line @@ -185,6 +244,22 @@ source_file top_level body: + block + stmt: + variable_declaration + modifier: modifier "let" + pattern: + name_pattern + identifier: identifier "x" + value: int_literal "1" + variable_declaration + modifier: + modifier "let" + modifier "chained_declaration" + pattern: + name_pattern + identifier: identifier "y" + value: int_literal "2" === Assignment @@ -207,6 +282,13 @@ source_file top_level body: + block + stmt: + assign_expr + target: + name_expr + identifier: identifier "x" + value: int_literal "1" === Compound assignment @@ -229,3 +311,138 @@ source_file top_level body: + block + stmt: + compound_assign_expr + operator: infix_operator "+=" + target: + name_expr + identifier: identifier "x" + value: int_literal "1" + +=== +Property with willSet and didSet observers +=== + +class C { + var x: Int = 0 { + willSet { print(newValue) } + didSet { print(oldValue) } + } +} + +--- + +source_file + statement: + class_declaration + body: + class_body + member: + property_declaration + binding: + value_binding_pattern + mutability: var + declarator: + property_binding + name: + pattern + bound_identifier: simple_identifier "x" + observers: + willset_didset_block + didset: + didset_clause + body: + block + statement: + call_expression + function: simple_identifier "print" + suffix: + call_suffix + arguments: + value_arguments + argument: + value_argument + value: simple_identifier "oldValue" + willset: + willset_clause + body: + block + statement: + call_expression + function: simple_identifier "print" + suffix: + call_suffix + arguments: + value_arguments + argument: + value_argument + value: simple_identifier "newValue" + type: + type_annotation + type: + type + name: + user_type + part: + simple_user_type + name: type_identifier "Int" + value: integer_literal "0" + declaration_kind: class + name: type_identifier "C" + +--- + +top_level + body: + block + stmt: + class_like_declaration + member: + variable_declaration + modifier: modifier "var" + pattern: + name_pattern + identifier: identifier "x" + type: + named_type_expr + name: identifier "Int" + value: int_literal "0" + accessor_declaration + body: + block + stmt: + call_expr + argument: + argument + value: + name_expr + identifier: identifier "newValue" + callee: + name_expr + identifier: identifier "print" + modifier: + modifier "var" + modifier "chained_declaration" + name: identifier "x" + accessor_kind: accessor_kind "willSet" + accessor_declaration + body: + block + stmt: + call_expr + argument: + argument + value: + name_expr + identifier: identifier "oldValue" + callee: + name_expr + identifier: identifier "print" + modifier: + modifier "var" + modifier "chained_declaration" + name: identifier "x" + accessor_kind: accessor_kind "didSet" + modifier: modifier "class" + name: identifier "C" diff --git a/unified/extractor/tests/corpus_tests.rs b/unified/extractor/tests/corpus_tests.rs index 0f1057a8e5b..6c859c2f6cf 100644 --- a/unified/extractor/tests/corpus_tests.rs +++ b/unified/extractor/tests/corpus_tests.rs @@ -2,7 +2,7 @@ use std::fs; use std::path::Path; use codeql_extractor::extractor::simple; -use yeast::{dump::dump_ast, dump::dump_ast_with_type_errors, Runner}; +use yeast::{Runner, dump::dump_ast, dump::dump_ast_with_type_errors}; #[path = "../src/languages/mod.rs"] mod languages; @@ -146,29 +146,36 @@ fn render_corpus(cases: &[CorpusCase]) -> String { out } -fn run_desugaring( - lang: &simple::LanguageSpec, - input: &str, -) -> Result { - let runner = match lang.desugar.as_ref() { - Some(config) => Runner::from_config(lang.ts_language.clone(), config) - .map_err(|e| format!("Failed to create yeast runner: {e}"))?, - None => Runner::new(lang.ts_language.clone(), &[]), - }; - - runner - .run(input) - .map_err(|e| format!("Failed to parse input: {e}")) +fn run_desugaring(lang: &simple::LanguageSpec, input: &str) -> Result { + match lang.desugar.as_deref() { + Some(desugarer) => { + // Parse the input ourselves so we don't depend on the desugarer + // knowing about the language. + let mut parser = tree_sitter::Parser::new(); + parser + .set_language(&lang.ts_language) + .map_err(|e| format!("Failed to set language: {e}"))?; + let tree = parser + .parse(input, None) + .ok_or_else(|| "Failed to parse input".to_string())?; + desugarer + .run_from_tree(&tree, input.as_bytes()) + .map_err(|e| format!("Desugaring failed: {e}")) + } + None => { + let runner: Runner = Runner::new(lang.ts_language.clone(), &[]); + runner + .run(input) + .map_err(|e| format!("Failed to parse input: {e}")) + } + } } /// Produce the raw tree-sitter parse tree dump for `input`, with no /// desugaring rules applied. Uses a `Runner` with an empty phase list and /// the input grammar's own schema. -fn dump_raw_parse( - lang: &simple::LanguageSpec, - input: &str, -) -> Result { - let runner = Runner::new(lang.ts_language.clone(), &[]); +fn dump_raw_parse(lang: &simple::LanguageSpec, input: &str) -> Result { + let runner: Runner = Runner::new(lang.ts_language.clone(), &[]); let ast = runner .run(input) .map_err(|e| format!("Failed to parse input: {e}"))?; @@ -272,11 +279,7 @@ fn test_corpus() { } } - assert!( - failures.is_empty(), - "{}", - failures.join("\n\n") + "\n\n" - ); + assert!(failures.is_empty(), "{}", failures.join("\n\n") + "\n\n"); if update_mode { let updated = render_corpus(&cases); @@ -285,7 +288,9 @@ fn test_corpus() { write_result.is_ok(), "Failed to update corpus file {}: {}", corpus_path.display(), - write_result.err().map_or_else(String::new, |e| e.to_string()) + write_result + .err() + .map_or_else(String::new, |e| e.to_string()) ); } } diff --git a/unified/extractor/tree-sitter-swift/bindings/rust/build.rs b/unified/extractor/tree-sitter-swift/bindings/rust/build.rs index 6b939358ed4..2dd899ea521 100644 --- a/unified/extractor/tree-sitter-swift/bindings/rust/build.rs +++ b/unified/extractor/tree-sitter-swift/bindings/rust/build.rs @@ -16,7 +16,9 @@ fn main() { Some(&grammar_js), tree_sitter_generate::ABI_VERSION_MAX, None, - None, + // Evaluate grammar.js with the embedded QuickJS runtime instead of + // spawning `node`, which isn't available inside Bazel's sandbox. + Some("native"), true, tree_sitter_generate::OptLevel::default(), ) diff --git a/unified/extractor/tree-sitter-swift/grammar.js b/unified/extractor/tree-sitter-swift/grammar.js index 1e63a7eaabb..7052d2ebdd5 100644 --- a/unified/extractor/tree-sitter-swift/grammar.js +++ b/unified/extractor/tree-sitter-swift/grammar.js @@ -1368,7 +1368,7 @@ module.exports = grammar({ seq( field("modifiers", optional($.modifiers)), "import", - optional($._import_kind), + optional(field("scoped_import_kind", $._import_kind)), field("name", $.identifier) ), _import_kind: ($) => @@ -1930,7 +1930,7 @@ module.exports = grammar({ seq( optional("case"), optional(field("type", $.user_type)), // XXX this should just be _type but that creates ambiguity - $._dot, + field("dot", $._dot), field("name", $.simple_identifier), optional(field("arguments", $.tuple_pattern)) ), diff --git a/unified/extractor/tree-sitter-swift/node-types.yml b/unified/extractor/tree-sitter-swift/node-types.yml index 8e1a4209d74..35dfb985b4a 100644 --- a/unified/extractor/tree-sitter-swift/node-types.yml +++ b/unified/extractor/tree-sitter-swift/node-types.yml @@ -173,6 +173,7 @@ named: value?: expression case_pattern: arguments?: tuple_pattern + dot: "." name: simple_identifier type?: user_type catch_block: @@ -351,6 +352,7 @@ named: import_declaration: modifiers?: modifiers name: identifier + scoped_import_kind?: ["class", "enum", "func", "let", "protocol", "struct", "typealias", "var"] infix_expression: lhs: expression op: custom_operator diff --git a/unified/ql/lib/codeql/IDEContextual.qll b/unified/ql/lib/codeql/IDEContextual.qll new file mode 100644 index 00000000000..3b8486b4526 --- /dev/null +++ b/unified/ql/lib/codeql/IDEContextual.qll @@ -0,0 +1,16 @@ +/** + * Provides shared predicates related to contextual queries in the code viewer. + */ + +private import codeql.files.FileSystem +private import codeql.util.FileSystem + +/** + * Returns an appropriately encoded version of a filename `name` + * passed by the VS Code extension in order to coincide with the + * output of `.getFile()` on locatable entities. + */ +cached +File getFileBySourceArchiveName(string name) { + result = IdeContextual::getFileBySourceArchiveName(name) +} diff --git a/unified/ql/lib/codeql/unified/Ast.qll b/unified/ql/lib/codeql/unified/Ast.qll index b6d6a76b549..1c2d5f3dd4a 100644 --- a/unified/ql/lib/codeql/unified/Ast.qll +++ b/unified/ql/lib/codeql/unified/Ast.qll @@ -93,20 +93,135 @@ module Unified { ) } - /** A class representing `apply_pattern` nodes. */ - class ApplyPattern extends @unified_apply_pattern, AstNode { + /** A class representing `accessor_declaration` nodes. */ + class AccessorDeclaration extends @unified_accessor_declaration, AstNode { /** Gets the name of the primary QL class for this element. */ - final override string getAPrimaryQlClass() { result = "ApplyPattern" } + final override string getAPrimaryQlClass() { result = "AccessorDeclaration" } - /** Gets the node corresponding to the field `argument`. */ - final Pattern getArgument(int i) { unified_apply_pattern_argument(this, i, result) } + /** Gets the node corresponding to the field `accessor_kind`. */ + final AccessorKind getAccessorKind() { unified_accessor_declaration_def(this, result, _) } - /** Gets the node corresponding to the field `constructor`. */ - final Expr getConstructor() { unified_apply_pattern_def(this, result) } + /** Gets the node corresponding to the field `body`. */ + final Block getBody() { unified_accessor_declaration_body(this, result) } + + /** Gets the node corresponding to the field `modifier`. */ + final Modifier getModifier(int i) { unified_accessor_declaration_modifier(this, i, result) } + + /** Gets the node corresponding to the field `name`. */ + final Identifier getName() { unified_accessor_declaration_def(this, _, result) } + + /** Gets the node corresponding to the field `parameter`. */ + final Parameter getParameter(int i) { unified_accessor_declaration_parameter(this, i, result) } + + /** Gets the node corresponding to the field `type`. */ + final TypeExpr getType() { unified_accessor_declaration_type(this, result) } /** Gets a field or child node of this node. */ final override AstNode getAFieldOrChild() { - unified_apply_pattern_argument(this, _, result) or unified_apply_pattern_def(this, result) + unified_accessor_declaration_def(this, result, _) or + unified_accessor_declaration_body(this, result) or + unified_accessor_declaration_modifier(this, _, result) or + unified_accessor_declaration_def(this, _, result) or + unified_accessor_declaration_parameter(this, _, result) or + unified_accessor_declaration_type(this, result) + } + } + + /** A class representing `accessor_kind` tokens. */ + class AccessorKind extends @unified_token_accessor_kind, Token { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "AccessorKind" } + } + + /** A class representing `argument` nodes. */ + class Argument extends @unified_argument, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "Argument" } + + /** Gets the node corresponding to the field `modifier`. */ + final Modifier getModifier(int i) { unified_argument_modifier(this, i, result) } + + /** Gets the node corresponding to the field `name`. */ + final Identifier getName() { unified_argument_name(this, result) } + + /** Gets the node corresponding to the field `value`. */ + final Expr getValue() { unified_argument_def(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + unified_argument_modifier(this, _, result) or + unified_argument_name(this, result) or + unified_argument_def(this, result) + } + } + + /** A class representing `array_literal` nodes. */ + class ArrayLiteral extends @unified_array_literal, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "ArrayLiteral" } + + /** Gets the node corresponding to the field `element`. */ + final Expr getElement(int i) { unified_array_literal_element(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { unified_array_literal_element(this, _, result) } + } + + /** A class representing `assign_expr` nodes. */ + class AssignExpr extends @unified_assign_expr, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "AssignExpr" } + + /** Gets the node corresponding to the field `target`. */ + final ExprOrPattern getTarget() { unified_assign_expr_def(this, result, _) } + + /** Gets the node corresponding to the field `value`. */ + final Expr getValue() { unified_assign_expr_def(this, _, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + unified_assign_expr_def(this, result, _) or unified_assign_expr_def(this, _, result) + } + } + + /** A class representing `associated_type_declaration` nodes. */ + class AssociatedTypeDeclaration extends @unified_associated_type_declaration, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "AssociatedTypeDeclaration" } + + /** Gets the node corresponding to the field `bound`. */ + final TypeExpr getBound() { unified_associated_type_declaration_bound(this, result) } + + /** Gets the node corresponding to the field `modifier`. */ + final Modifier getModifier(int i) { + unified_associated_type_declaration_modifier(this, i, result) + } + + /** Gets the node corresponding to the field `name`. */ + final Identifier getName() { unified_associated_type_declaration_def(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + unified_associated_type_declaration_bound(this, result) or + unified_associated_type_declaration_modifier(this, _, result) or + unified_associated_type_declaration_def(this, result) + } + } + + /** A class representing `base_type` nodes. */ + class BaseType extends @unified_base_type, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "BaseType" } + + /** Gets the node corresponding to the field `modifier`. */ + final Modifier getModifier(int i) { unified_base_type_modifier(this, i, result) } + + /** Gets the node corresponding to the field `type`. */ + final TypeExpr getType() { unified_base_type_def(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + unified_base_type_modifier(this, _, result) or unified_base_type_def(this, result) } } @@ -119,7 +234,7 @@ module Unified { final Expr getLeft() { unified_binary_expr_def(this, result, _, _) } /** Gets the node corresponding to the field `operator`. */ - final Operator getOperator() { unified_binary_expr_def(this, _, result, _) } + final InfixOperator getOperator() { unified_binary_expr_def(this, _, result, _) } /** Gets the node corresponding to the field `right`. */ final Expr getRight() { unified_binary_expr_def(this, _, _, result) } @@ -132,16 +247,72 @@ module Unified { } } - /** A class representing `block_stmt` nodes. */ - class BlockStmt extends @unified_block_stmt, AstNode { + /** A class representing `block` nodes. */ + class Block extends @unified_block, AstNode { /** Gets the name of the primary QL class for this element. */ - final override string getAPrimaryQlClass() { result = "BlockStmt" } + final override string getAPrimaryQlClass() { result = "Block" } - /** Gets the node corresponding to the field `body`. */ - final Stmt getBody(int i) { unified_block_stmt_body(this, i, result) } + /** Gets the node corresponding to the field `stmt`. */ + final Stmt getStmt(int i) { unified_block_stmt(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { unified_block_stmt_body(this, _, result) } + final override AstNode getAFieldOrChild() { unified_block_stmt(this, _, result) } + } + + /** A class representing `boolean_literal` tokens. */ + class BooleanLiteral extends @unified_token_boolean_literal, Token { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "BooleanLiteral" } + } + + /** A class representing `bound_type_constraint` nodes. */ + class BoundTypeConstraint extends @unified_bound_type_constraint, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "BoundTypeConstraint" } + + /** Gets the node corresponding to the field `bound`. */ + final TypeExpr getBound() { unified_bound_type_constraint_def(this, result, _) } + + /** Gets the node corresponding to the field `type`. */ + final TypeExpr getType() { unified_bound_type_constraint_def(this, _, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + unified_bound_type_constraint_def(this, result, _) or + unified_bound_type_constraint_def(this, _, result) + } + } + + /** A class representing `break_expr` nodes. */ + class BreakExpr extends @unified_break_expr, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "BreakExpr" } + + /** Gets the node corresponding to the field `label`. */ + final Identifier getLabel() { unified_break_expr_label(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { unified_break_expr_label(this, result) } + } + + /** A class representing `builtin_expr` tokens. */ + class BuiltinExpr extends @unified_token_builtin_expr, Token { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "BuiltinExpr" } + } + + /** A class representing `bulk_importing_pattern` nodes. */ + class BulkImportingPattern extends @unified_bulk_importing_pattern, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "BulkImportingPattern" } + + /** Gets the node corresponding to the field `modifier`. */ + final Modifier getModifier(int i) { unified_bulk_importing_pattern_modifier(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + unified_bulk_importing_pattern_modifier(this, _, result) + } } /** A class representing `call_expr` nodes. */ @@ -150,49 +321,404 @@ module Unified { final override string getAPrimaryQlClass() { result = "CallExpr" } /** Gets the node corresponding to the field `argument`. */ - final Expr getArgument(int i) { unified_call_expr_argument(this, i, result) } + final Argument getArgument(int i) { unified_call_expr_argument(this, i, result) } - /** Gets the node corresponding to the field `function`. */ - final Expr getFunction() { unified_call_expr_def(this, result) } + /** Gets the node corresponding to the field `callee`. */ + final ExprOrType getCallee() { unified_call_expr_def(this, result) } + + /** Gets the node corresponding to the field `modifier`. */ + final Modifier getModifier(int i) { unified_call_expr_modifier(this, i, result) } /** Gets a field or child node of this node. */ final override AstNode getAFieldOrChild() { - unified_call_expr_argument(this, _, result) or unified_call_expr_def(this, result) + unified_call_expr_argument(this, _, result) or + unified_call_expr_def(this, result) or + unified_call_expr_modifier(this, _, result) } } - class Condition extends @unified_condition, AstNode { } - - /** A class representing `empty_stmt` tokens. */ - class EmptyStmt extends @unified_token_empty_stmt, Token { + /** A class representing `catch_clause` nodes. */ + class CatchClause extends @unified_catch_clause, AstNode { /** Gets the name of the primary QL class for this element. */ - final override string getAPrimaryQlClass() { result = "EmptyStmt" } + final override string getAPrimaryQlClass() { result = "CatchClause" } + + /** Gets the node corresponding to the field `body`. */ + final Block getBody() { unified_catch_clause_def(this, result) } + + /** Gets the node corresponding to the field `guard`. */ + final Expr getGuard() { unified_catch_clause_guard(this, result) } + + /** Gets the node corresponding to the field `modifier`. */ + final Modifier getModifier(int i) { unified_catch_clause_modifier(this, i, result) } + + /** Gets the node corresponding to the field `pattern`. */ + final Pattern getPattern() { unified_catch_clause_pattern(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + unified_catch_clause_def(this, result) or + unified_catch_clause_guard(this, result) or + unified_catch_clause_modifier(this, _, result) or + unified_catch_clause_pattern(this, result) + } + } + + /** A class representing `class_like_declaration` nodes. */ + class ClassLikeDeclaration extends @unified_class_like_declaration, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "ClassLikeDeclaration" } + + /** Gets the node corresponding to the field `base_type`. */ + final BaseType getBaseType(int i) { unified_class_like_declaration_base_type(this, i, result) } + + /** Gets the node corresponding to the field `member`. */ + final Member getMember(int i) { unified_class_like_declaration_member(this, i, result) } + + /** Gets the node corresponding to the field `modifier`. */ + final Modifier getModifier(int i) { unified_class_like_declaration_modifier(this, i, result) } + + /** Gets the node corresponding to the field `name`. */ + final Identifier getName() { unified_class_like_declaration_name(this, result) } + + /** Gets the node corresponding to the field `type_constraint`. */ + final TypeConstraint getTypeConstraint(int i) { + unified_class_like_declaration_type_constraint(this, i, result) + } + + /** Gets the node corresponding to the field `type_parameter`. */ + final TypeParameter getTypeParameter(int i) { + unified_class_like_declaration_type_parameter(this, i, result) + } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + unified_class_like_declaration_base_type(this, _, result) or + unified_class_like_declaration_member(this, _, result) or + unified_class_like_declaration_modifier(this, _, result) or + unified_class_like_declaration_name(this, result) or + unified_class_like_declaration_type_constraint(this, _, result) or + unified_class_like_declaration_type_parameter(this, _, result) + } + } + + /** A class representing `compound_assign_expr` nodes. */ + class CompoundAssignExpr extends @unified_compound_assign_expr, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "CompoundAssignExpr" } + + /** Gets the node corresponding to the field `operator`. */ + final InfixOperator getOperator() { unified_compound_assign_expr_def(this, result, _, _) } + + /** Gets the node corresponding to the field `target`. */ + final Expr getTarget() { unified_compound_assign_expr_def(this, _, result, _) } + + /** Gets the node corresponding to the field `value`. */ + final Expr getValue() { unified_compound_assign_expr_def(this, _, _, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + unified_compound_assign_expr_def(this, result, _, _) or + unified_compound_assign_expr_def(this, _, result, _) or + unified_compound_assign_expr_def(this, _, _, result) + } + } + + /** A class representing `constructor_declaration` nodes. */ + class ConstructorDeclaration extends @unified_constructor_declaration, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "ConstructorDeclaration" } + + /** Gets the node corresponding to the field `body`. */ + final Block getBody() { unified_constructor_declaration_def(this, result) } + + /** Gets the node corresponding to the field `modifier`. */ + final Modifier getModifier(int i) { unified_constructor_declaration_modifier(this, i, result) } + + /** Gets the node corresponding to the field `name`. */ + final Identifier getName() { unified_constructor_declaration_name(this, result) } + + /** Gets the node corresponding to the field `parameter`. */ + final Parameter getParameter(int i) { + unified_constructor_declaration_parameter(this, i, result) + } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + unified_constructor_declaration_def(this, result) or + unified_constructor_declaration_modifier(this, _, result) or + unified_constructor_declaration_name(this, result) or + unified_constructor_declaration_parameter(this, _, result) + } + } + + /** A class representing `constructor_pattern` nodes. */ + class ConstructorPattern extends @unified_constructor_pattern, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "ConstructorPattern" } + + /** Gets the node corresponding to the field `constructor`. */ + final ExprOrType getConstructor() { unified_constructor_pattern_def(this, result) } + + /** Gets the node corresponding to the field `element`. */ + final PatternElement getElement(int i) { unified_constructor_pattern_element(this, i, result) } + + /** Gets the node corresponding to the field `modifier`. */ + final Modifier getModifier(int i) { unified_constructor_pattern_modifier(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + unified_constructor_pattern_def(this, result) or + unified_constructor_pattern_element(this, _, result) or + unified_constructor_pattern_modifier(this, _, result) + } + } + + /** A class representing `continue_expr` nodes. */ + class ContinueExpr extends @unified_continue_expr, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "ContinueExpr" } + + /** Gets the node corresponding to the field `label`. */ + final Identifier getLabel() { unified_continue_expr_label(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { unified_continue_expr_label(this, result) } + } + + /** A class representing `destructor_declaration` nodes. */ + class DestructorDeclaration extends @unified_destructor_declaration, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "DestructorDeclaration" } + + /** Gets the node corresponding to the field `body`. */ + final Block getBody() { unified_destructor_declaration_def(this, result) } + + /** Gets the node corresponding to the field `modifier`. */ + final Modifier getModifier(int i) { unified_destructor_declaration_modifier(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + unified_destructor_declaration_def(this, result) or + unified_destructor_declaration_modifier(this, _, result) + } + } + + /** A class representing `do_while_stmt` nodes. */ + class DoWhileStmt extends @unified_do_while_stmt, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "DoWhileStmt" } + + /** Gets the node corresponding to the field `body`. */ + final Block getBody() { unified_do_while_stmt_body(this, result) } + + /** Gets the node corresponding to the field `condition`. */ + final Expr getCondition() { unified_do_while_stmt_def(this, result) } + + /** Gets the node corresponding to the field `modifier`. */ + final Modifier getModifier(int i) { unified_do_while_stmt_modifier(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + unified_do_while_stmt_body(this, result) or + unified_do_while_stmt_def(this, result) or + unified_do_while_stmt_modifier(this, _, result) + } + } + + /** A class representing `empty_expr` tokens. */ + class EmptyExpr extends @unified_token_empty_expr, Token { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "EmptyExpr" } + } + + /** A class representing `equality_type_constraint` nodes. */ + class EqualityTypeConstraint extends @unified_equality_type_constraint, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "EqualityTypeConstraint" } + + /** Gets the node corresponding to the field `left`. */ + final TypeExpr getLeft() { unified_equality_type_constraint_def(this, result, _) } + + /** Gets the node corresponding to the field `right`. */ + final TypeExpr getRight() { unified_equality_type_constraint_def(this, _, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + unified_equality_type_constraint_def(this, result, _) or + unified_equality_type_constraint_def(this, _, result) + } } class Expr extends @unified_expr, AstNode { } - /** A class representing `expr_condition` nodes. */ - class ExprCondition extends @unified_expr_condition, AstNode { + /** A class representing `expr_equality_pattern` nodes. */ + class ExprEqualityPattern extends @unified_expr_equality_pattern, AstNode { /** Gets the name of the primary QL class for this element. */ - final override string getAPrimaryQlClass() { result = "ExprCondition" } + final override string getAPrimaryQlClass() { result = "ExprEqualityPattern" } /** Gets the node corresponding to the field `expr`. */ - final Expr getExpr() { unified_expr_condition_def(this, result) } + final Expr getExpr() { unified_expr_equality_pattern_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { unified_expr_condition_def(this, result) } + final override AstNode getAFieldOrChild() { unified_expr_equality_pattern_def(this, result) } } - /** A class representing `expr_stmt` nodes. */ - class ExprStmt extends @unified_expr_stmt, AstNode { - /** Gets the name of the primary QL class for this element. */ - final override string getAPrimaryQlClass() { result = "ExprStmt" } + class ExprOrPattern extends @unified_expr_or_pattern, AstNode { } - /** Gets the node corresponding to the field `expr`. */ - final Expr getExpr() { unified_expr_stmt_def(this, result) } + class ExprOrType extends @unified_expr_or_type, AstNode { } + + /** A class representing `fixity` tokens. */ + class Fixity extends @unified_token_fixity, Token { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "Fixity" } + } + + /** A class representing `float_literal` tokens. */ + class FloatLiteral extends @unified_token_float_literal, Token { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "FloatLiteral" } + } + + /** A class representing `for_each_stmt` nodes. */ + class ForEachStmt extends @unified_for_each_stmt, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "ForEachStmt" } + + /** Gets the node corresponding to the field `body`. */ + final Block getBody() { unified_for_each_stmt_body(this, result) } + + /** Gets the node corresponding to the field `guard`. */ + final Expr getGuard() { unified_for_each_stmt_guard(this, result) } + + /** Gets the node corresponding to the field `iterable`. */ + final Expr getIterable() { unified_for_each_stmt_def(this, result, _) } + + /** Gets the node corresponding to the field `modifier`. */ + final Modifier getModifier(int i) { unified_for_each_stmt_modifier(this, i, result) } + + /** Gets the node corresponding to the field `pattern`. */ + final Pattern getPattern() { unified_for_each_stmt_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { unified_expr_stmt_def(this, result) } + final override AstNode getAFieldOrChild() { + unified_for_each_stmt_body(this, result) or + unified_for_each_stmt_guard(this, result) or + unified_for_each_stmt_def(this, result, _) or + unified_for_each_stmt_modifier(this, _, result) or + unified_for_each_stmt_def(this, _, result) + } + } + + /** A class representing `function_declaration` nodes. */ + class FunctionDeclaration extends @unified_function_declaration, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "FunctionDeclaration" } + + /** Gets the node corresponding to the field `body`. */ + final Block getBody() { unified_function_declaration_body(this, result) } + + /** Gets the node corresponding to the field `modifier`. */ + final Modifier getModifier(int i) { unified_function_declaration_modifier(this, i, result) } + + /** Gets the node corresponding to the field `name`. */ + final Identifier getName() { unified_function_declaration_def(this, result) } + + /** Gets the node corresponding to the field `parameter`. */ + final Parameter getParameter(int i) { unified_function_declaration_parameter(this, i, result) } + + /** Gets the node corresponding to the field `return_type`. */ + final TypeExpr getReturnType() { unified_function_declaration_return_type(this, result) } + + /** Gets the node corresponding to the field `type_constraint`. */ + final TypeConstraint getTypeConstraint(int i) { + unified_function_declaration_type_constraint(this, i, result) + } + + /** Gets the node corresponding to the field `type_parameter`. */ + final TypeParameter getTypeParameter(int i) { + unified_function_declaration_type_parameter(this, i, result) + } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + unified_function_declaration_body(this, result) or + unified_function_declaration_modifier(this, _, result) or + unified_function_declaration_def(this, result) or + unified_function_declaration_parameter(this, _, result) or + unified_function_declaration_return_type(this, result) or + unified_function_declaration_type_constraint(this, _, result) or + unified_function_declaration_type_parameter(this, _, result) + } + } + + /** A class representing `function_expr` nodes. */ + class FunctionExpr extends @unified_function_expr, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "FunctionExpr" } + + /** Gets the node corresponding to the field `body`. */ + final Block getBody() { unified_function_expr_def(this, result) } + + /** Gets the node corresponding to the field `capture_declaration`. */ + final VariableDeclaration getCaptureDeclaration(int i) { + unified_function_expr_capture_declaration(this, i, result) + } + + /** Gets the node corresponding to the field `modifier`. */ + final Modifier getModifier(int i) { unified_function_expr_modifier(this, i, result) } + + /** Gets the node corresponding to the field `parameter`. */ + final Parameter getParameter(int i) { unified_function_expr_parameter(this, i, result) } + + /** Gets the node corresponding to the field `return_type`. */ + final TypeExpr getReturnType() { unified_function_expr_return_type(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + unified_function_expr_def(this, result) or + unified_function_expr_capture_declaration(this, _, result) or + unified_function_expr_modifier(this, _, result) or + unified_function_expr_parameter(this, _, result) or + unified_function_expr_return_type(this, result) + } + } + + /** A class representing `function_type_expr` nodes. */ + class FunctionTypeExpr extends @unified_function_type_expr, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "FunctionTypeExpr" } + + /** Gets the node corresponding to the field `parameter`. */ + final Parameter getParameter(int i) { unified_function_type_expr_parameter(this, i, result) } + + /** Gets the node corresponding to the field `return_type`. */ + final TypeExpr getReturnType() { unified_function_type_expr_def(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + unified_function_type_expr_parameter(this, _, result) or + unified_function_type_expr_def(this, result) + } + } + + /** A class representing `generic_type_expr` nodes. */ + class GenericTypeExpr extends @unified_generic_type_expr, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "GenericTypeExpr" } + + /** Gets the node corresponding to the field `base`. */ + final TypeExpr getBase() { unified_generic_type_expr_def(this, result) } + + /** Gets the node corresponding to the field `type_argument`. */ + final TypeExpr getTypeArgument(int i) { + unified_generic_type_expr_type_argument(this, i, result) + } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + unified_generic_type_expr_def(this, result) or + unified_generic_type_expr_type_argument(this, _, result) + } } /** A class representing `guard_if_stmt` nodes. */ @@ -201,10 +727,10 @@ module Unified { final override string getAPrimaryQlClass() { result = "GuardIfStmt" } /** Gets the node corresponding to the field `condition`. */ - final Condition getCondition() { unified_guard_if_stmt_def(this, result, _) } + final Expr getCondition() { unified_guard_if_stmt_def(this, result, _) } /** Gets the node corresponding to the field `else`. */ - final Stmt getElse() { unified_guard_if_stmt_def(this, _, result) } + final Block getElse() { unified_guard_if_stmt_def(this, _, result) } /** Gets a field or child node of this node. */ final override AstNode getAFieldOrChild() { @@ -218,25 +744,25 @@ module Unified { final override string getAPrimaryQlClass() { result = "Identifier" } } - /** A class representing `if_stmt` nodes. */ - class IfStmt extends @unified_if_stmt, AstNode { + /** A class representing `if_expr` nodes. */ + class IfExpr extends @unified_if_expr, AstNode { /** Gets the name of the primary QL class for this element. */ - final override string getAPrimaryQlClass() { result = "IfStmt" } + final override string getAPrimaryQlClass() { result = "IfExpr" } /** Gets the node corresponding to the field `condition`. */ - final Condition getCondition() { unified_if_stmt_def(this, result) } + final Expr getCondition() { unified_if_expr_def(this, result) } /** Gets the node corresponding to the field `else`. */ - final Stmt getElse() { unified_if_stmt_else(this, result) } + final Expr getElse() { unified_if_expr_else(this, result) } /** Gets the node corresponding to the field `then`. */ - final Stmt getThen() { unified_if_stmt_then(this, result) } + final Expr getThen() { unified_if_expr_then(this, result) } /** Gets a field or child node of this node. */ final override AstNode getAFieldOrChild() { - unified_if_stmt_def(this, result) or - unified_if_stmt_else(this, result) or - unified_if_stmt_then(this, result) + unified_if_expr_def(this, result) or + unified_if_expr_else(this, result) or + unified_if_expr_then(this, result) } } @@ -246,57 +772,122 @@ module Unified { final override string getAPrimaryQlClass() { result = "IgnorePattern" } } + /** A class representing `import_declaration` nodes. */ + class ImportDeclaration extends @unified_import_declaration, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "ImportDeclaration" } + + /** Gets the node corresponding to the field `imported_expr`. */ + final Expr getImportedExpr() { unified_import_declaration_def(this, result) } + + /** Gets the node corresponding to the field `modifier`. */ + final Modifier getModifier(int i) { unified_import_declaration_modifier(this, i, result) } + + /** Gets the node corresponding to the field `pattern`. */ + final Pattern getPattern() { unified_import_declaration_pattern(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + unified_import_declaration_def(this, result) or + unified_import_declaration_modifier(this, _, result) or + unified_import_declaration_pattern(this, result) + } + } + + /** A class representing `inferred_type_expr` tokens. */ + class InferredTypeExpr extends @unified_token_inferred_type_expr, Token { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "InferredTypeExpr" } + } + + /** A class representing `infix_operator` tokens. */ + class InfixOperator extends @unified_token_infix_operator, Token { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "InfixOperator" } + } + + /** A class representing `initializer_declaration` nodes. */ + class InitializerDeclaration extends @unified_initializer_declaration, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "InitializerDeclaration" } + + /** Gets the node corresponding to the field `body`. */ + final Block getBody() { unified_initializer_declaration_def(this, result) } + + /** Gets the node corresponding to the field `modifier`. */ + final Modifier getModifier(int i) { unified_initializer_declaration_modifier(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + unified_initializer_declaration_def(this, result) or + unified_initializer_declaration_modifier(this, _, result) + } + } + /** A class representing `int_literal` tokens. */ class IntLiteral extends @unified_token_int_literal, Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "IntLiteral" } } - /** A class representing `lambda_expr` nodes. */ - class LambdaExpr extends @unified_lambda_expr, AstNode { + /** A class representing `key_value_pair` nodes. */ + class KeyValuePair extends @unified_key_value_pair, AstNode { /** Gets the name of the primary QL class for this element. */ - final override string getAPrimaryQlClass() { result = "LambdaExpr" } + final override string getAPrimaryQlClass() { result = "KeyValuePair" } - /** Gets the node corresponding to the field `body`. */ - final AstNode getBody() { unified_lambda_expr_def(this, result) } - - /** Gets the node corresponding to the field `parameter`. */ - final Parameter getParameter(int i) { unified_lambda_expr_parameter(this, i, result) } - - /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { - unified_lambda_expr_def(this, result) or unified_lambda_expr_parameter(this, _, result) - } - } - - /** A class representing `let_pattern_condition` nodes. */ - class LetPatternCondition extends @unified_let_pattern_condition, AstNode { - /** Gets the name of the primary QL class for this element. */ - final override string getAPrimaryQlClass() { result = "LetPatternCondition" } - - /** Gets the node corresponding to the field `pattern`. */ - final Pattern getPattern() { unified_let_pattern_condition_def(this, result, _) } + /** Gets the node corresponding to the field `key`. */ + final Expr getKey() { unified_key_value_pair_def(this, result, _) } /** Gets the node corresponding to the field `value`. */ - final Expr getValue() { unified_let_pattern_condition_def(this, _, result) } + final Expr getValue() { unified_key_value_pair_def(this, _, result) } /** Gets a field or child node of this node. */ final override AstNode getAFieldOrChild() { - unified_let_pattern_condition_def(this, result, _) or - unified_let_pattern_condition_def(this, _, result) + unified_key_value_pair_def(this, result, _) or unified_key_value_pair_def(this, _, result) } } + /** A class representing `labeled_stmt` nodes. */ + class LabeledStmt extends @unified_labeled_stmt, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "LabeledStmt" } + + /** Gets the node corresponding to the field `label`. */ + final Identifier getLabel() { unified_labeled_stmt_def(this, result, _) } + + /** Gets the node corresponding to the field `stmt`. */ + final Stmt getStmt() { unified_labeled_stmt_def(this, _, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + unified_labeled_stmt_def(this, result, _) or unified_labeled_stmt_def(this, _, result) + } + } + + /** A class representing `map_literal` nodes. */ + class MapLiteral extends @unified_map_literal, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "MapLiteral" } + + /** Gets the node corresponding to the field `element`. */ + final Expr getElement(int i) { unified_map_literal_element(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { unified_map_literal_element(this, _, result) } + } + + class Member extends @unified_member, AstNode { } + /** A class representing `member_access_expr` nodes. */ class MemberAccessExpr extends @unified_member_access_expr, AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "MemberAccessExpr" } - /** Gets the node corresponding to the field `member`. */ - final Identifier getMember() { unified_member_access_expr_def(this, result, _) } + /** Gets the node corresponding to the field `base`. */ + final ExprOrType getBase() { unified_member_access_expr_def(this, result, _) } - /** Gets the node corresponding to the field `target`. */ - final Expr getTarget() { unified_member_access_expr_def(this, _, result) } + /** Gets the node corresponding to the field `member`. */ + final Identifier getMember() { unified_member_access_expr_def(this, _, result) } /** Gets a field or child node of this node. */ final override AstNode getAFieldOrChild() { @@ -305,6 +896,12 @@ module Unified { } } + /** A class representing `modifier` tokens. */ + class Modifier extends @unified_token_modifier, Token { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "Modifier" } + } + /** A class representing `name_expr` nodes. */ class NameExpr extends @unified_name_expr, AstNode { /** Gets the name of the primary QL class for this element. */ @@ -317,10 +914,68 @@ module Unified { final override AstNode getAFieldOrChild() { unified_name_expr_def(this, result) } } - /** A class representing `operator` tokens. */ - class Operator extends @unified_token_operator, Token { + /** A class representing `name_pattern` nodes. */ + class NamePattern extends @unified_name_pattern, AstNode { /** Gets the name of the primary QL class for this element. */ - final override string getAPrimaryQlClass() { result = "Operator" } + final override string getAPrimaryQlClass() { result = "NamePattern" } + + /** Gets the node corresponding to the field `identifier`. */ + final Identifier getIdentifier() { unified_name_pattern_def(this, result) } + + /** Gets the node corresponding to the field `modifier`. */ + final Modifier getModifier(int i) { unified_name_pattern_modifier(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + unified_name_pattern_def(this, result) or unified_name_pattern_modifier(this, _, result) + } + } + + /** A class representing `named_type_expr` nodes. */ + class NamedTypeExpr extends @unified_named_type_expr, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "NamedTypeExpr" } + + /** Gets the node corresponding to the field `name`. */ + final Identifier getName() { unified_named_type_expr_def(this, result) } + + /** Gets the node corresponding to the field `qualifier`. */ + final TypeExpr getQualifier() { unified_named_type_expr_qualifier(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + unified_named_type_expr_def(this, result) or unified_named_type_expr_qualifier(this, result) + } + } + + class Operator extends @unified_operator, AstNode { } + + /** A class representing `operator_syntax_declaration` nodes. */ + class OperatorSyntaxDeclaration extends @unified_operator_syntax_declaration, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "OperatorSyntaxDeclaration" } + + /** Gets the node corresponding to the field `fixity`. */ + final Fixity getFixity() { unified_operator_syntax_declaration_fixity(this, result) } + + /** Gets the node corresponding to the field `modifier`. */ + final Modifier getModifier(int i) { + unified_operator_syntax_declaration_modifier(this, i, result) + } + + /** Gets the node corresponding to the field `name`. */ + final Identifier getName() { unified_operator_syntax_declaration_def(this, result) } + + /** Gets the node corresponding to the field `precedence`. */ + final Expr getPrecedence() { unified_operator_syntax_declaration_precedence(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + unified_operator_syntax_declaration_fixity(this, result) or + unified_operator_syntax_declaration_modifier(this, _, result) or + unified_operator_syntax_declaration_def(this, result) or + unified_operator_syntax_declaration_precedence(this, result) + } } /** A class representing `parameter` nodes. */ @@ -328,33 +983,103 @@ module Unified { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Parameter" } + /** Gets the node corresponding to the field `default`. */ + final Expr getDefault() { unified_parameter_default(this, result) } + + /** Gets the node corresponding to the field `external_name`. */ + final Identifier getExternalName() { unified_parameter_external_name(this, result) } + + /** Gets the node corresponding to the field `modifier`. */ + final Modifier getModifier(int i) { unified_parameter_modifier(this, i, result) } + /** Gets the node corresponding to the field `pattern`. */ - final Pattern getPattern() { unified_parameter_def(this, result) } + final Pattern getPattern() { unified_parameter_pattern(this, result) } + + /** Gets the node corresponding to the field `type`. */ + final TypeExpr getType() { unified_parameter_type(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { unified_parameter_def(this, result) } + final override AstNode getAFieldOrChild() { + unified_parameter_default(this, result) or + unified_parameter_external_name(this, result) or + unified_parameter_modifier(this, _, result) or + unified_parameter_pattern(this, result) or + unified_parameter_type(this, result) + } } class Pattern extends @unified_pattern, AstNode { } - /** A class representing `sequence_condition` nodes. */ - class SequenceCondition extends @unified_sequence_condition, AstNode { + /** A class representing `pattern_element` nodes. */ + class PatternElement extends @unified_pattern_element, AstNode { /** Gets the name of the primary QL class for this element. */ - final override string getAPrimaryQlClass() { result = "SequenceCondition" } + final override string getAPrimaryQlClass() { result = "PatternElement" } - /** Gets the node corresponding to the field `condition`. */ - final Condition getCondition() { unified_sequence_condition_def(this, result) } + /** Gets the node corresponding to the field `key`. */ + final Identifier getKey() { unified_pattern_element_key(this, result) } - /** Gets the node corresponding to the field `stmt`. */ - final Stmt getStmt(int i) { unified_sequence_condition_stmt(this, i, result) } + /** Gets the node corresponding to the field `modifier`. */ + final Modifier getModifier(int i) { unified_pattern_element_modifier(this, i, result) } + + /** Gets the node corresponding to the field `pattern`. */ + final Pattern getPattern() { unified_pattern_element_def(this, result) } /** Gets a field or child node of this node. */ final override AstNode getAFieldOrChild() { - unified_sequence_condition_def(this, result) or - unified_sequence_condition_stmt(this, _, result) + unified_pattern_element_key(this, result) or + unified_pattern_element_modifier(this, _, result) or + unified_pattern_element_def(this, result) } } + /** A class representing `pattern_guard_expr` nodes. */ + class PatternGuardExpr extends @unified_pattern_guard_expr, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "PatternGuardExpr" } + + /** Gets the node corresponding to the field `pattern`. */ + final Pattern getPattern() { unified_pattern_guard_expr_def(this, result, _) } + + /** Gets the node corresponding to the field `value`. */ + final Expr getValue() { unified_pattern_guard_expr_def(this, _, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + unified_pattern_guard_expr_def(this, result, _) or + unified_pattern_guard_expr_def(this, _, result) + } + } + + /** A class representing `postfix_operator` tokens. */ + class PostfixOperator extends @unified_token_postfix_operator, Token { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "PostfixOperator" } + } + + /** A class representing `prefix_operator` tokens. */ + class PrefixOperator extends @unified_token_prefix_operator, Token { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "PrefixOperator" } + } + + /** A class representing `regex_literal` tokens. */ + class RegexLiteral extends @unified_token_regex_literal, Token { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "RegexLiteral" } + } + + /** A class representing `return_expr` nodes. */ + class ReturnExpr extends @unified_return_expr, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "ReturnExpr" } + + /** Gets the node corresponding to the field `value`. */ + final Expr getValue() { unified_return_expr_value(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { unified_return_expr_value(this, result) } + } + class Stmt extends @unified_stmt, AstNode { } /** A class representing `string_literal` tokens. */ @@ -363,16 +1088,116 @@ module Unified { final override string getAPrimaryQlClass() { result = "StringLiteral" } } + /** A class representing `super_expr` tokens. */ + class SuperExpr extends @unified_token_super_expr, Token { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "SuperExpr" } + } + + /** A class representing `switch_case` nodes. */ + class SwitchCase extends @unified_switch_case, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "SwitchCase" } + + /** Gets the node corresponding to the field `body`. */ + final Block getBody() { unified_switch_case_def(this, result) } + + /** Gets the node corresponding to the field `guard`. */ + final Expr getGuard() { unified_switch_case_guard(this, result) } + + /** Gets the node corresponding to the field `modifier`. */ + final Modifier getModifier(int i) { unified_switch_case_modifier(this, i, result) } + + /** Gets the node corresponding to the field `pattern`. */ + final Pattern getPattern(int i) { unified_switch_case_pattern(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + unified_switch_case_def(this, result) or + unified_switch_case_guard(this, result) or + unified_switch_case_modifier(this, _, result) or + unified_switch_case_pattern(this, _, result) + } + } + + /** A class representing `switch_expr` nodes. */ + class SwitchExpr extends @unified_switch_expr, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "SwitchExpr" } + + /** Gets the node corresponding to the field `case`. */ + final SwitchCase getCase(int i) { unified_switch_expr_case(this, i, result) } + + /** Gets the node corresponding to the field `modifier`. */ + final Modifier getModifier(int i) { unified_switch_expr_modifier(this, i, result) } + + /** Gets the node corresponding to the field `value`. */ + final Expr getValue() { unified_switch_expr_def(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + unified_switch_expr_case(this, _, result) or + unified_switch_expr_modifier(this, _, result) or + unified_switch_expr_def(this, result) + } + } + + /** A class representing `throw_expr` nodes. */ + class ThrowExpr extends @unified_throw_expr, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "ThrowExpr" } + + /** Gets the node corresponding to the field `value`. */ + final Expr getValue() { unified_throw_expr_value(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { unified_throw_expr_value(this, result) } + } + /** A class representing `top_level` nodes. */ class TopLevel extends @unified_top_level, AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "TopLevel" } /** Gets the node corresponding to the field `body`. */ - final AstNode getBody(int i) { unified_top_level_body(this, i, result) } + final Block getBody() { unified_top_level_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { unified_top_level_body(this, _, result) } + final override AstNode getAFieldOrChild() { unified_top_level_def(this, result) } + } + + /** A class representing `try_expr` nodes. */ + class TryExpr extends @unified_try_expr, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "TryExpr" } + + /** Gets the node corresponding to the field `body`. */ + final Block getBody() { unified_try_expr_def(this, result) } + + /** Gets the node corresponding to the field `catch_clause`. */ + final CatchClause getCatchClause(int i) { unified_try_expr_catch_clause(this, i, result) } + + /** Gets the node corresponding to the field `modifier`. */ + final Modifier getModifier(int i) { unified_try_expr_modifier(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + unified_try_expr_def(this, result) or + unified_try_expr_catch_clause(this, _, result) or + unified_try_expr_modifier(this, _, result) + } + } + + /** A class representing `tuple_expr` nodes. */ + class TupleExpr extends @unified_tuple_expr, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "TupleExpr" } + + /** Gets the node corresponding to the field `element`. */ + final Expr getElement(int i) { unified_tuple_expr_element(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { unified_tuple_expr_element(this, _, result) } } /** A class representing `tuple_pattern` nodes. */ @@ -381,10 +1206,167 @@ module Unified { final override string getAPrimaryQlClass() { result = "TuplePattern" } /** Gets the node corresponding to the field `element`. */ - final Pattern getElement(int i) { unified_tuple_pattern_element(this, i, result) } + final PatternElement getElement(int i) { unified_tuple_pattern_element(this, i, result) } + + /** Gets the node corresponding to the field `modifier`. */ + final Modifier getModifier(int i) { unified_tuple_pattern_modifier(this, i, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { unified_tuple_pattern_element(this, _, result) } + final override AstNode getAFieldOrChild() { + unified_tuple_pattern_element(this, _, result) or + unified_tuple_pattern_modifier(this, _, result) + } + } + + /** A class representing `tuple_type_element` nodes. */ + class TupleTypeElement extends @unified_tuple_type_element, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "TupleTypeElement" } + + /** Gets the node corresponding to the field `name`. */ + final Identifier getName() { unified_tuple_type_element_name(this, result) } + + /** Gets the node corresponding to the field `type`. */ + final TypeExpr getType() { unified_tuple_type_element_def(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + unified_tuple_type_element_name(this, result) or unified_tuple_type_element_def(this, result) + } + } + + /** A class representing `tuple_type_expr` nodes. */ + class TupleTypeExpr extends @unified_tuple_type_expr, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "TupleTypeExpr" } + + /** Gets the node corresponding to the field `element`. */ + final TupleTypeElement getElement(int i) { unified_tuple_type_expr_element(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { unified_tuple_type_expr_element(this, _, result) } + } + + /** A class representing `type_alias_declaration` nodes. */ + class TypeAliasDeclaration extends @unified_type_alias_declaration, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "TypeAliasDeclaration" } + + /** Gets the node corresponding to the field `modifier`. */ + final Modifier getModifier(int i) { unified_type_alias_declaration_modifier(this, i, result) } + + /** Gets the node corresponding to the field `name`. */ + final Identifier getName() { unified_type_alias_declaration_def(this, result, _) } + + /** Gets the node corresponding to the field `type`. */ + final TypeExpr getType() { unified_type_alias_declaration_def(this, _, result) } + + /** Gets the node corresponding to the field `type_constraint`. */ + final TypeConstraint getTypeConstraint(int i) { + unified_type_alias_declaration_type_constraint(this, i, result) + } + + /** Gets the node corresponding to the field `type_parameter`. */ + final TypeParameter getTypeParameter(int i) { + unified_type_alias_declaration_type_parameter(this, i, result) + } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + unified_type_alias_declaration_modifier(this, _, result) or + unified_type_alias_declaration_def(this, result, _) or + unified_type_alias_declaration_def(this, _, result) or + unified_type_alias_declaration_type_constraint(this, _, result) or + unified_type_alias_declaration_type_parameter(this, _, result) + } + } + + /** A class representing `type_cast_expr` nodes. */ + class TypeCastExpr extends @unified_type_cast_expr, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "TypeCastExpr" } + + /** Gets the node corresponding to the field `expr`. */ + final Expr getExpr() { unified_type_cast_expr_def(this, result, _, _) } + + /** Gets the node corresponding to the field `operator`. */ + final InfixOperator getOperator() { unified_type_cast_expr_def(this, _, result, _) } + + /** Gets the node corresponding to the field `type`. */ + final TypeExpr getType() { unified_type_cast_expr_def(this, _, _, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + unified_type_cast_expr_def(this, result, _, _) or + unified_type_cast_expr_def(this, _, result, _) or + unified_type_cast_expr_def(this, _, _, result) + } + } + + class TypeConstraint extends @unified_type_constraint, AstNode { } + + class TypeExpr extends @unified_type_expr, AstNode { } + + /** A class representing `type_parameter` nodes. */ + class TypeParameter extends @unified_type_parameter, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "TypeParameter" } + + /** Gets the node corresponding to the field `bound`. */ + final TypeExpr getBound() { unified_type_parameter_bound(this, result) } + + /** Gets the node corresponding to the field `modifier`. */ + final Modifier getModifier(int i) { unified_type_parameter_modifier(this, i, result) } + + /** Gets the node corresponding to the field `name`. */ + final Identifier getName() { unified_type_parameter_def(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + unified_type_parameter_bound(this, result) or + unified_type_parameter_modifier(this, _, result) or + unified_type_parameter_def(this, result) + } + } + + /** A class representing `type_test_expr` nodes. */ + class TypeTestExpr extends @unified_type_test_expr, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "TypeTestExpr" } + + /** Gets the node corresponding to the field `expr`. */ + final Expr getExpr() { unified_type_test_expr_def(this, result, _, _) } + + /** Gets the node corresponding to the field `operator`. */ + final InfixOperator getOperator() { unified_type_test_expr_def(this, _, result, _) } + + /** Gets the node corresponding to the field `type`. */ + final TypeExpr getType() { unified_type_test_expr_def(this, _, _, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + unified_type_test_expr_def(this, result, _, _) or + unified_type_test_expr_def(this, _, result, _) or + unified_type_test_expr_def(this, _, _, result) + } + } + + /** A class representing `type_test_pattern` nodes. */ + class TypeTestPattern extends @unified_type_test_pattern, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "TypeTestPattern" } + + /** Gets the node corresponding to the field `pattern`. */ + final Pattern getPattern() { unified_type_test_pattern_def(this, result, _) } + + /** Gets the node corresponding to the field `type`. */ + final TypeExpr getType() { unified_type_test_pattern_def(this, _, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + unified_type_test_pattern_def(this, result, _) or + unified_type_test_pattern_def(this, _, result) + } } /** A class representing `unary_expr` nodes. */ @@ -410,49 +1392,375 @@ module Unified { final override string getAPrimaryQlClass() { result = "UnsupportedNode" } } - /** A class representing `var_pattern` nodes. */ - class VarPattern extends @unified_var_pattern, AstNode { + /** A class representing `variable_declaration` nodes. */ + class VariableDeclaration extends @unified_variable_declaration, AstNode { /** Gets the name of the primary QL class for this element. */ - final override string getAPrimaryQlClass() { result = "VarPattern" } + final override string getAPrimaryQlClass() { result = "VariableDeclaration" } - /** Gets the node corresponding to the field `identifier`. */ - final Identifier getIdentifier() { unified_var_pattern_def(this, result) } - - /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { unified_var_pattern_def(this, result) } - } - - /** A class representing `variable_declaration_stmt` nodes. */ - class VariableDeclarationStmt extends @unified_variable_declaration_stmt, AstNode { - /** Gets the name of the primary QL class for this element. */ - final override string getAPrimaryQlClass() { result = "VariableDeclarationStmt" } - - /** Gets the node corresponding to the field `variable_declarator`. */ - final VariableDeclarator getVariableDeclarator(int i) { - unified_variable_declaration_stmt_variable_declarator(this, i, result) - } - - /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { - unified_variable_declaration_stmt_variable_declarator(this, _, result) - } - } - - /** A class representing `variable_declarator` nodes. */ - class VariableDeclarator extends @unified_variable_declarator, AstNode { - /** Gets the name of the primary QL class for this element. */ - final override string getAPrimaryQlClass() { result = "VariableDeclarator" } + /** Gets the node corresponding to the field `modifier`. */ + final Modifier getModifier(int i) { unified_variable_declaration_modifier(this, i, result) } /** Gets the node corresponding to the field `pattern`. */ - final Pattern getPattern() { unified_variable_declarator_def(this, result) } + final Pattern getPattern() { unified_variable_declaration_def(this, result) } + + /** Gets the node corresponding to the field `type`. */ + final TypeExpr getType() { unified_variable_declaration_type(this, result) } /** Gets the node corresponding to the field `value`. */ - final Expr getValue() { unified_variable_declarator_value(this, result) } + final Expr getValue() { unified_variable_declaration_value(this, result) } /** Gets a field or child node of this node. */ final override AstNode getAFieldOrChild() { - unified_variable_declarator_def(this, result) or - unified_variable_declarator_value(this, result) + unified_variable_declaration_modifier(this, _, result) or + unified_variable_declaration_def(this, result) or + unified_variable_declaration_type(this, result) or + unified_variable_declaration_value(this, result) + } + } + + /** A class representing `while_stmt` nodes. */ + class WhileStmt extends @unified_while_stmt, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "WhileStmt" } + + /** Gets the node corresponding to the field `body`. */ + final Block getBody() { unified_while_stmt_body(this, result) } + + /** Gets the node corresponding to the field `condition`. */ + final Expr getCondition() { unified_while_stmt_def(this, result) } + + /** Gets the node corresponding to the field `modifier`. */ + final Modifier getModifier(int i) { unified_while_stmt_modifier(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + unified_while_stmt_body(this, result) or + unified_while_stmt_def(this, result) or + unified_while_stmt_modifier(this, _, result) + } + } + + /** Provides predicates for mapping AST nodes to their named children. */ + module PrintAst { + /** Gets a child of `node` returned by the member predicate with the given `name`. If the predicate takes an index argument, `i` is bound to that index, otherwise `i` is `-1` (which is never a valid index). */ + AstNode getChild(AstNode node, string name, int i) { + result = node.(AccessorDeclaration).getAccessorKind() and i = -1 and name = "getAccessorKind" + or + result = node.(AccessorDeclaration).getBody() and i = -1 and name = "getBody" + or + result = node.(AccessorDeclaration).getModifier(i) and name = "getModifier" + or + result = node.(AccessorDeclaration).getName() and i = -1 and name = "getName" + or + result = node.(AccessorDeclaration).getParameter(i) and name = "getParameter" + or + result = node.(AccessorDeclaration).getType() and i = -1 and name = "getType" + or + result = node.(Argument).getModifier(i) and name = "getModifier" + or + result = node.(Argument).getName() and i = -1 and name = "getName" + or + result = node.(Argument).getValue() and i = -1 and name = "getValue" + or + result = node.(ArrayLiteral).getElement(i) and name = "getElement" + or + result = node.(AssignExpr).getTarget() and i = -1 and name = "getTarget" + or + result = node.(AssignExpr).getValue() and i = -1 and name = "getValue" + or + result = node.(AssociatedTypeDeclaration).getBound() and i = -1 and name = "getBound" + or + result = node.(AssociatedTypeDeclaration).getModifier(i) and name = "getModifier" + or + result = node.(AssociatedTypeDeclaration).getName() and i = -1 and name = "getName" + or + result = node.(BaseType).getModifier(i) and name = "getModifier" + or + result = node.(BaseType).getType() and i = -1 and name = "getType" + or + result = node.(BinaryExpr).getLeft() and i = -1 and name = "getLeft" + or + result = node.(BinaryExpr).getOperator() and i = -1 and name = "getOperator" + or + result = node.(BinaryExpr).getRight() and i = -1 and name = "getRight" + or + result = node.(Block).getStmt(i) and name = "getStmt" + or + result = node.(BoundTypeConstraint).getBound() and i = -1 and name = "getBound" + or + result = node.(BoundTypeConstraint).getType() and i = -1 and name = "getType" + or + result = node.(BreakExpr).getLabel() and i = -1 and name = "getLabel" + or + result = node.(BulkImportingPattern).getModifier(i) and name = "getModifier" + or + result = node.(CallExpr).getArgument(i) and name = "getArgument" + or + result = node.(CallExpr).getCallee() and i = -1 and name = "getCallee" + or + result = node.(CallExpr).getModifier(i) and name = "getModifier" + or + result = node.(CatchClause).getBody() and i = -1 and name = "getBody" + or + result = node.(CatchClause).getGuard() and i = -1 and name = "getGuard" + or + result = node.(CatchClause).getModifier(i) and name = "getModifier" + or + result = node.(CatchClause).getPattern() and i = -1 and name = "getPattern" + or + result = node.(ClassLikeDeclaration).getBaseType(i) and name = "getBaseType" + or + result = node.(ClassLikeDeclaration).getMember(i) and name = "getMember" + or + result = node.(ClassLikeDeclaration).getModifier(i) and name = "getModifier" + or + result = node.(ClassLikeDeclaration).getName() and i = -1 and name = "getName" + or + result = node.(ClassLikeDeclaration).getTypeConstraint(i) and name = "getTypeConstraint" + or + result = node.(ClassLikeDeclaration).getTypeParameter(i) and name = "getTypeParameter" + or + result = node.(CompoundAssignExpr).getOperator() and i = -1 and name = "getOperator" + or + result = node.(CompoundAssignExpr).getTarget() and i = -1 and name = "getTarget" + or + result = node.(CompoundAssignExpr).getValue() and i = -1 and name = "getValue" + or + result = node.(ConstructorDeclaration).getBody() and i = -1 and name = "getBody" + or + result = node.(ConstructorDeclaration).getModifier(i) and name = "getModifier" + or + result = node.(ConstructorDeclaration).getName() and i = -1 and name = "getName" + or + result = node.(ConstructorDeclaration).getParameter(i) and name = "getParameter" + or + result = node.(ConstructorPattern).getConstructor() and i = -1 and name = "getConstructor" + or + result = node.(ConstructorPattern).getElement(i) and name = "getElement" + or + result = node.(ConstructorPattern).getModifier(i) and name = "getModifier" + or + result = node.(ContinueExpr).getLabel() and i = -1 and name = "getLabel" + or + result = node.(DestructorDeclaration).getBody() and i = -1 and name = "getBody" + or + result = node.(DestructorDeclaration).getModifier(i) and name = "getModifier" + or + result = node.(DoWhileStmt).getBody() and i = -1 and name = "getBody" + or + result = node.(DoWhileStmt).getCondition() and i = -1 and name = "getCondition" + or + result = node.(DoWhileStmt).getModifier(i) and name = "getModifier" + or + result = node.(EqualityTypeConstraint).getLeft() and i = -1 and name = "getLeft" + or + result = node.(EqualityTypeConstraint).getRight() and i = -1 and name = "getRight" + or + result = node.(ExprEqualityPattern).getExpr() and i = -1 and name = "getExpr" + or + result = node.(ForEachStmt).getBody() and i = -1 and name = "getBody" + or + result = node.(ForEachStmt).getGuard() and i = -1 and name = "getGuard" + or + result = node.(ForEachStmt).getIterable() and i = -1 and name = "getIterable" + or + result = node.(ForEachStmt).getModifier(i) and name = "getModifier" + or + result = node.(ForEachStmt).getPattern() and i = -1 and name = "getPattern" + or + result = node.(FunctionDeclaration).getBody() and i = -1 and name = "getBody" + or + result = node.(FunctionDeclaration).getModifier(i) and name = "getModifier" + or + result = node.(FunctionDeclaration).getName() and i = -1 and name = "getName" + or + result = node.(FunctionDeclaration).getParameter(i) and name = "getParameter" + or + result = node.(FunctionDeclaration).getReturnType() and i = -1 and name = "getReturnType" + or + result = node.(FunctionDeclaration).getTypeConstraint(i) and name = "getTypeConstraint" + or + result = node.(FunctionDeclaration).getTypeParameter(i) and name = "getTypeParameter" + or + result = node.(FunctionExpr).getBody() and i = -1 and name = "getBody" + or + result = node.(FunctionExpr).getCaptureDeclaration(i) and name = "getCaptureDeclaration" + or + result = node.(FunctionExpr).getModifier(i) and name = "getModifier" + or + result = node.(FunctionExpr).getParameter(i) and name = "getParameter" + or + result = node.(FunctionExpr).getReturnType() and i = -1 and name = "getReturnType" + or + result = node.(FunctionTypeExpr).getParameter(i) and name = "getParameter" + or + result = node.(FunctionTypeExpr).getReturnType() and i = -1 and name = "getReturnType" + or + result = node.(GenericTypeExpr).getBase() and i = -1 and name = "getBase" + or + result = node.(GenericTypeExpr).getTypeArgument(i) and name = "getTypeArgument" + or + result = node.(GuardIfStmt).getCondition() and i = -1 and name = "getCondition" + or + result = node.(GuardIfStmt).getElse() and i = -1 and name = "getElse" + or + result = node.(IfExpr).getCondition() and i = -1 and name = "getCondition" + or + result = node.(IfExpr).getElse() and i = -1 and name = "getElse" + or + result = node.(IfExpr).getThen() and i = -1 and name = "getThen" + or + result = node.(ImportDeclaration).getImportedExpr() and i = -1 and name = "getImportedExpr" + or + result = node.(ImportDeclaration).getModifier(i) and name = "getModifier" + or + result = node.(ImportDeclaration).getPattern() and i = -1 and name = "getPattern" + or + result = node.(InitializerDeclaration).getBody() and i = -1 and name = "getBody" + or + result = node.(InitializerDeclaration).getModifier(i) and name = "getModifier" + or + result = node.(KeyValuePair).getKey() and i = -1 and name = "getKey" + or + result = node.(KeyValuePair).getValue() and i = -1 and name = "getValue" + or + result = node.(LabeledStmt).getLabel() and i = -1 and name = "getLabel" + or + result = node.(LabeledStmt).getStmt() and i = -1 and name = "getStmt" + or + result = node.(MapLiteral).getElement(i) and name = "getElement" + or + result = node.(MemberAccessExpr).getBase() and i = -1 and name = "getBase" + or + result = node.(MemberAccessExpr).getMember() and i = -1 and name = "getMember" + or + result = node.(NameExpr).getIdentifier() and i = -1 and name = "getIdentifier" + or + result = node.(NamePattern).getIdentifier() and i = -1 and name = "getIdentifier" + or + result = node.(NamePattern).getModifier(i) and name = "getModifier" + or + result = node.(NamedTypeExpr).getName() and i = -1 and name = "getName" + or + result = node.(NamedTypeExpr).getQualifier() and i = -1 and name = "getQualifier" + or + result = node.(OperatorSyntaxDeclaration).getFixity() and i = -1 and name = "getFixity" + or + result = node.(OperatorSyntaxDeclaration).getModifier(i) and name = "getModifier" + or + result = node.(OperatorSyntaxDeclaration).getName() and i = -1 and name = "getName" + or + result = node.(OperatorSyntaxDeclaration).getPrecedence() and + i = -1 and + name = "getPrecedence" + or + result = node.(Parameter).getDefault() and i = -1 and name = "getDefault" + or + result = node.(Parameter).getExternalName() and i = -1 and name = "getExternalName" + or + result = node.(Parameter).getModifier(i) and name = "getModifier" + or + result = node.(Parameter).getPattern() and i = -1 and name = "getPattern" + or + result = node.(Parameter).getType() and i = -1 and name = "getType" + or + result = node.(PatternElement).getKey() and i = -1 and name = "getKey" + or + result = node.(PatternElement).getModifier(i) and name = "getModifier" + or + result = node.(PatternElement).getPattern() and i = -1 and name = "getPattern" + or + result = node.(PatternGuardExpr).getPattern() and i = -1 and name = "getPattern" + or + result = node.(PatternGuardExpr).getValue() and i = -1 and name = "getValue" + or + result = node.(ReturnExpr).getValue() and i = -1 and name = "getValue" + or + result = node.(SwitchCase).getBody() and i = -1 and name = "getBody" + or + result = node.(SwitchCase).getGuard() and i = -1 and name = "getGuard" + or + result = node.(SwitchCase).getModifier(i) and name = "getModifier" + or + result = node.(SwitchCase).getPattern(i) and name = "getPattern" + or + result = node.(SwitchExpr).getCase(i) and name = "getCase" + or + result = node.(SwitchExpr).getModifier(i) and name = "getModifier" + or + result = node.(SwitchExpr).getValue() and i = -1 and name = "getValue" + or + result = node.(ThrowExpr).getValue() and i = -1 and name = "getValue" + or + result = node.(TopLevel).getBody() and i = -1 and name = "getBody" + or + result = node.(TryExpr).getBody() and i = -1 and name = "getBody" + or + result = node.(TryExpr).getCatchClause(i) and name = "getCatchClause" + or + result = node.(TryExpr).getModifier(i) and name = "getModifier" + or + result = node.(TupleExpr).getElement(i) and name = "getElement" + or + result = node.(TuplePattern).getElement(i) and name = "getElement" + or + result = node.(TuplePattern).getModifier(i) and name = "getModifier" + or + result = node.(TupleTypeElement).getName() and i = -1 and name = "getName" + or + result = node.(TupleTypeElement).getType() and i = -1 and name = "getType" + or + result = node.(TupleTypeExpr).getElement(i) and name = "getElement" + or + result = node.(TypeAliasDeclaration).getModifier(i) and name = "getModifier" + or + result = node.(TypeAliasDeclaration).getName() and i = -1 and name = "getName" + or + result = node.(TypeAliasDeclaration).getType() and i = -1 and name = "getType" + or + result = node.(TypeAliasDeclaration).getTypeConstraint(i) and name = "getTypeConstraint" + or + result = node.(TypeAliasDeclaration).getTypeParameter(i) and name = "getTypeParameter" + or + result = node.(TypeCastExpr).getExpr() and i = -1 and name = "getExpr" + or + result = node.(TypeCastExpr).getOperator() and i = -1 and name = "getOperator" + or + result = node.(TypeCastExpr).getType() and i = -1 and name = "getType" + or + result = node.(TypeParameter).getBound() and i = -1 and name = "getBound" + or + result = node.(TypeParameter).getModifier(i) and name = "getModifier" + or + result = node.(TypeParameter).getName() and i = -1 and name = "getName" + or + result = node.(TypeTestExpr).getExpr() and i = -1 and name = "getExpr" + or + result = node.(TypeTestExpr).getOperator() and i = -1 and name = "getOperator" + or + result = node.(TypeTestExpr).getType() and i = -1 and name = "getType" + or + result = node.(TypeTestPattern).getPattern() and i = -1 and name = "getPattern" + or + result = node.(TypeTestPattern).getType() and i = -1 and name = "getType" + or + result = node.(UnaryExpr).getOperand() and i = -1 and name = "getOperand" + or + result = node.(UnaryExpr).getOperator() and i = -1 and name = "getOperator" + or + result = node.(VariableDeclaration).getModifier(i) and name = "getModifier" + or + result = node.(VariableDeclaration).getPattern() and i = -1 and name = "getPattern" + or + result = node.(VariableDeclaration).getType() and i = -1 and name = "getType" + or + result = node.(VariableDeclaration).getValue() and i = -1 and name = "getValue" + or + result = node.(WhileStmt).getBody() and i = -1 and name = "getBody" + or + result = node.(WhileStmt).getCondition() and i = -1 and name = "getCondition" + or + result = node.(WhileStmt).getModifier(i) and name = "getModifier" } } } diff --git a/unified/ql/lib/codeql/unified/printAst.qll b/unified/ql/lib/codeql/unified/printAst.qll new file mode 100644 index 00000000000..93ff11f5c8b --- /dev/null +++ b/unified/ql/lib/codeql/unified/printAst.qll @@ -0,0 +1,96 @@ +/** Provides a configurable query for printing AST nodes */ + +private import unified + +/** + * The query can extend this class to control which nodes are printed. + */ +class PrintAstConfiguration extends string { + PrintAstConfiguration() { this = "PrintAstConfiguration" } + + /** + * Holds if the given node should be printed. + */ + predicate shouldPrintNode(AstNode n) { not n instanceof TriviaToken } + + /** + * Holds if the given edge should be printed. + */ + predicate shouldPrintAstEdge(AstNode parent, string edgeName, AstNode child) { + exists(string name, int i | + child = PrintAst::getChild(parent, name, i) and + (if i = -1 then edgeName = name else edgeName = name + "(" + i + ")") + ) + } +} + +private predicate shouldPrintNode(AstNode n) { + any(PrintAstConfiguration config).shouldPrintNode(n) +} + +private predicate shouldPrintAstEdge(AstNode parent, string edgeName, AstNode child) { + any(PrintAstConfiguration config).shouldPrintAstEdge(parent, edgeName, child) and + shouldPrintNode(parent) and + shouldPrintNode(child) +} + +/** + * Get an alias for the predicate `name` to use for ordering purposes, to control where + * in the list of children it should appear. + */ +private string reorderName1(string name) { name = "getModifier" and result = "00_getModifier" } + +bindingset[name] +private string reorderName(string name) { + result = reorderName1(name) + or + not exists(reorderName1(name)) and + result = name +} + +class PrintAstNode extends AstNode { + final int getOrder() { + this = + rank[result](AstNode parent, AstNode child, string name, int i | + child = PrintAst::getChild(parent, name, i) + | + child order by reorderName(name), i + ) + } + + final string getProperty(string key) { + key = "semmle.label" and + result = this.toString() + or + key = "semmle.order" and result = this.getOrder().toString() + } +} + +/** + * Holds if `node` belongs to the output tree, and its property `key` has the + * given `value`. + */ +query predicate nodes(PrintAstNode node, string key, string value) { + shouldPrintNode(node) and + value = node.getProperty(key) +} + +/** + * Holds if `target` is a child of `source` in the AST, and property `key` of + * the edge has the given `value`. + */ +query predicate edges(PrintAstNode source, PrintAstNode target, string key, string value) { + key = "semmle.label" and + shouldPrintAstEdge(source, value, target) + or + key = "semmle.order" and + shouldPrintAstEdge(source, _, target) and + value = target.getProperty("semmle.order") +} + +/** + * Holds if property `key` of the graph has the given `value`. + */ +query predicate graphProperties(string key, string value) { + key = "semmle.graphKind" and value = "tree" +} diff --git a/unified/ql/lib/ide-contextual-queries/printAst.ql b/unified/ql/lib/ide-contextual-queries/printAst.ql new file mode 100644 index 00000000000..3622babe07f --- /dev/null +++ b/unified/ql/lib/ide-contextual-queries/printAst.ql @@ -0,0 +1,27 @@ +/** + * @name Print AST + * @description Produces a representation of a file's Abstract Syntax Tree. + * This query is used by the VS Code extension. + * @id unified/print-ast + * @kind graph + * @tags ide-contextual-queries/print-ast + */ + +private import codeql.IDEContextual +private import unified +private import codeql.unified.printAst + +/** + * The source file to generate an AST from. + */ +external string selectedSourceFile(); + +/** + * A configuration that only prints nodes in the selected source file. + */ +class Cfg extends PrintAstConfiguration { + override predicate shouldPrintNode(AstNode n) { + super.shouldPrintNode(n) and + n.getLocation().getFile() = getFileBySourceArchiveName(selectedSourceFile()) + } +} diff --git a/unified/ql/lib/unified.dbscheme b/unified/ql/lib/unified.dbscheme index 3617d83fd5f..3d9e5cddae0 100644 --- a/unified/ql/lib/unified.dbscheme +++ b/unified/ql/lib/unified.dbscheme @@ -136,107 +136,533 @@ overlayChangedFiles( ); /*- Unified dbscheme -*/ -#keyset[unified_apply_pattern, index] -unified_apply_pattern_argument( - int unified_apply_pattern: @unified_apply_pattern ref, - int index: int ref, - unique int argument: @unified_pattern ref +unified_accessor_declaration_body( + unique int unified_accessor_declaration: @unified_accessor_declaration ref, + unique int body: @unified_block ref ); -unified_apply_pattern_def( - unique int id: @unified_apply_pattern, - int constructor: @unified_expr ref +#keyset[unified_accessor_declaration, index] +unified_accessor_declaration_modifier( + int unified_accessor_declaration: @unified_accessor_declaration ref, + int index: int ref, + unique int modifier: @unified_token_modifier ref +); + +#keyset[unified_accessor_declaration, index] +unified_accessor_declaration_parameter( + int unified_accessor_declaration: @unified_accessor_declaration ref, + int index: int ref, + unique int parameter: @unified_parameter ref +); + +unified_accessor_declaration_type( + unique int unified_accessor_declaration: @unified_accessor_declaration ref, + unique int type__: @unified_type_expr ref +); + +unified_accessor_declaration_def( + unique int id: @unified_accessor_declaration, + int accessor_kind: @unified_token_accessor_kind ref, + int name: @unified_token_identifier ref +); + +#keyset[unified_argument, index] +unified_argument_modifier( + int unified_argument: @unified_argument ref, + int index: int ref, + unique int modifier: @unified_token_modifier ref +); + +unified_argument_name( + unique int unified_argument: @unified_argument ref, + unique int name: @unified_token_identifier ref +); + +unified_argument_def( + unique int id: @unified_argument, + int value: @unified_expr ref +); + +#keyset[unified_array_literal, index] +unified_array_literal_element( + int unified_array_literal: @unified_array_literal ref, + int index: int ref, + unique int element: @unified_expr ref +); + +unified_array_literal_def( + unique int id: @unified_array_literal +); + +unified_assign_expr_def( + unique int id: @unified_assign_expr, + int target: @unified_expr_or_pattern ref, + int value: @unified_expr ref +); + +unified_associated_type_declaration_bound( + unique int unified_associated_type_declaration: @unified_associated_type_declaration ref, + unique int bound: @unified_type_expr ref +); + +#keyset[unified_associated_type_declaration, index] +unified_associated_type_declaration_modifier( + int unified_associated_type_declaration: @unified_associated_type_declaration ref, + int index: int ref, + unique int modifier: @unified_token_modifier ref +); + +unified_associated_type_declaration_def( + unique int id: @unified_associated_type_declaration, + int name: @unified_token_identifier ref +); + +#keyset[unified_base_type, index] +unified_base_type_modifier( + int unified_base_type: @unified_base_type ref, + int index: int ref, + unique int modifier: @unified_token_modifier ref +); + +unified_base_type_def( + unique int id: @unified_base_type, + int type__: @unified_type_expr ref ); unified_binary_expr_def( unique int id: @unified_binary_expr, int left: @unified_expr ref, - int operator: @unified_token_operator ref, + int operator: @unified_token_infix_operator ref, int right: @unified_expr ref ); -#keyset[unified_block_stmt, index] -unified_block_stmt_body( - int unified_block_stmt: @unified_block_stmt ref, +#keyset[unified_block, index] +unified_block_stmt( + int unified_block: @unified_block ref, int index: int ref, - unique int body: @unified_stmt ref + unique int stmt: @unified_stmt ref ); -unified_block_stmt_def( - unique int id: @unified_block_stmt +unified_block_def( + unique int id: @unified_block +); + +unified_bound_type_constraint_def( + unique int id: @unified_bound_type_constraint, + int bound: @unified_type_expr ref, + int type__: @unified_type_expr ref +); + +unified_break_expr_label( + unique int unified_break_expr: @unified_break_expr ref, + unique int label: @unified_token_identifier ref +); + +unified_break_expr_def( + unique int id: @unified_break_expr +); + +#keyset[unified_bulk_importing_pattern, index] +unified_bulk_importing_pattern_modifier( + int unified_bulk_importing_pattern: @unified_bulk_importing_pattern ref, + int index: int ref, + unique int modifier: @unified_token_modifier ref +); + +unified_bulk_importing_pattern_def( + unique int id: @unified_bulk_importing_pattern ); #keyset[unified_call_expr, index] unified_call_expr_argument( int unified_call_expr: @unified_call_expr ref, int index: int ref, - unique int argument: @unified_expr ref + unique int argument: @unified_argument ref +); + +#keyset[unified_call_expr, index] +unified_call_expr_modifier( + int unified_call_expr: @unified_call_expr ref, + int index: int ref, + unique int modifier: @unified_token_modifier ref ); unified_call_expr_def( unique int id: @unified_call_expr, - int function: @unified_expr ref + int callee: @unified_expr_or_type ref ); -@unified_condition = @unified_expr_condition | @unified_let_pattern_condition | @unified_sequence_condition | @unified_token_unsupported_node - -@unified_expr = @unified_binary_expr | @unified_call_expr | @unified_lambda_expr | @unified_member_access_expr | @unified_name_expr | @unified_token_int_literal | @unified_token_string_literal | @unified_token_unsupported_node | @unified_unary_expr - -unified_expr_condition_def( - unique int id: @unified_expr_condition, - int expr: @unified_expr ref +unified_catch_clause_guard( + unique int unified_catch_clause: @unified_catch_clause ref, + unique int guard: @unified_expr ref ); -unified_expr_stmt_def( - unique int id: @unified_expr_stmt, - int expr: @unified_expr ref +#keyset[unified_catch_clause, index] +unified_catch_clause_modifier( + int unified_catch_clause: @unified_catch_clause ref, + int index: int ref, + unique int modifier: @unified_token_modifier ref ); -unified_guard_if_stmt_def( - unique int id: @unified_guard_if_stmt, - int condition: @unified_condition ref, - int else: @unified_stmt ref +unified_catch_clause_pattern( + unique int unified_catch_clause: @unified_catch_clause ref, + unique int pattern: @unified_pattern ref ); -unified_if_stmt_else( - unique int unified_if_stmt: @unified_if_stmt ref, - unique int else: @unified_stmt ref +unified_catch_clause_def( + unique int id: @unified_catch_clause, + int body: @unified_block ref ); -unified_if_stmt_then( - unique int unified_if_stmt: @unified_if_stmt ref, - unique int then: @unified_stmt ref +#keyset[unified_class_like_declaration, index] +unified_class_like_declaration_base_type( + int unified_class_like_declaration: @unified_class_like_declaration ref, + int index: int ref, + unique int base_type: @unified_base_type ref ); -unified_if_stmt_def( - unique int id: @unified_if_stmt, - int condition: @unified_condition ref +#keyset[unified_class_like_declaration, index] +unified_class_like_declaration_member( + int unified_class_like_declaration: @unified_class_like_declaration ref, + int index: int ref, + unique int member: @unified_member ref ); -@unified_lambda_expr_body_type = @unified_expr | @unified_stmt +#keyset[unified_class_like_declaration, index] +unified_class_like_declaration_modifier( + int unified_class_like_declaration: @unified_class_like_declaration ref, + int index: int ref, + unique int modifier: @unified_token_modifier ref +); -#keyset[unified_lambda_expr, index] -unified_lambda_expr_parameter( - int unified_lambda_expr: @unified_lambda_expr ref, +unified_class_like_declaration_name( + unique int unified_class_like_declaration: @unified_class_like_declaration ref, + unique int name: @unified_token_identifier ref +); + +#keyset[unified_class_like_declaration, index] +unified_class_like_declaration_type_constraint( + int unified_class_like_declaration: @unified_class_like_declaration ref, + int index: int ref, + unique int type_constraint: @unified_type_constraint ref +); + +#keyset[unified_class_like_declaration, index] +unified_class_like_declaration_type_parameter( + int unified_class_like_declaration: @unified_class_like_declaration ref, + int index: int ref, + unique int type_parameter: @unified_type_parameter ref +); + +unified_class_like_declaration_def( + unique int id: @unified_class_like_declaration +); + +unified_compound_assign_expr_def( + unique int id: @unified_compound_assign_expr, + int operator: @unified_token_infix_operator ref, + int target: @unified_expr ref, + int value: @unified_expr ref +); + +#keyset[unified_constructor_declaration, index] +unified_constructor_declaration_modifier( + int unified_constructor_declaration: @unified_constructor_declaration ref, + int index: int ref, + unique int modifier: @unified_token_modifier ref +); + +unified_constructor_declaration_name( + unique int unified_constructor_declaration: @unified_constructor_declaration ref, + unique int name: @unified_token_identifier ref +); + +#keyset[unified_constructor_declaration, index] +unified_constructor_declaration_parameter( + int unified_constructor_declaration: @unified_constructor_declaration ref, int index: int ref, unique int parameter: @unified_parameter ref ); -unified_lambda_expr_def( - unique int id: @unified_lambda_expr, - int body: @unified_lambda_expr_body_type ref +unified_constructor_declaration_def( + unique int id: @unified_constructor_declaration, + int body: @unified_block ref ); -unified_let_pattern_condition_def( - unique int id: @unified_let_pattern_condition, - int pattern: @unified_pattern ref, +#keyset[unified_constructor_pattern, index] +unified_constructor_pattern_element( + int unified_constructor_pattern: @unified_constructor_pattern ref, + int index: int ref, + unique int element: @unified_pattern_element ref +); + +#keyset[unified_constructor_pattern, index] +unified_constructor_pattern_modifier( + int unified_constructor_pattern: @unified_constructor_pattern ref, + int index: int ref, + unique int modifier: @unified_token_modifier ref +); + +unified_constructor_pattern_def( + unique int id: @unified_constructor_pattern, + int constructor: @unified_expr_or_type ref +); + +unified_continue_expr_label( + unique int unified_continue_expr: @unified_continue_expr ref, + unique int label: @unified_token_identifier ref +); + +unified_continue_expr_def( + unique int id: @unified_continue_expr +); + +#keyset[unified_destructor_declaration, index] +unified_destructor_declaration_modifier( + int unified_destructor_declaration: @unified_destructor_declaration ref, + int index: int ref, + unique int modifier: @unified_token_modifier ref +); + +unified_destructor_declaration_def( + unique int id: @unified_destructor_declaration, + int body: @unified_block ref +); + +unified_do_while_stmt_body( + unique int unified_do_while_stmt: @unified_do_while_stmt ref, + unique int body: @unified_block ref +); + +#keyset[unified_do_while_stmt, index] +unified_do_while_stmt_modifier( + int unified_do_while_stmt: @unified_do_while_stmt ref, + int index: int ref, + unique int modifier: @unified_token_modifier ref +); + +unified_do_while_stmt_def( + unique int id: @unified_do_while_stmt, + int condition: @unified_expr ref +); + +unified_equality_type_constraint_def( + unique int id: @unified_equality_type_constraint, + int left: @unified_type_expr ref, + int right: @unified_type_expr ref +); + +@unified_expr = @unified_array_literal | @unified_assign_expr | @unified_binary_expr | @unified_block | @unified_break_expr | @unified_call_expr | @unified_compound_assign_expr | @unified_continue_expr | @unified_function_expr | @unified_if_expr | @unified_key_value_pair | @unified_map_literal | @unified_member_access_expr | @unified_name_expr | @unified_pattern_guard_expr | @unified_return_expr | @unified_switch_expr | @unified_throw_expr | @unified_token_boolean_literal | @unified_token_builtin_expr | @unified_token_empty_expr | @unified_token_float_literal | @unified_token_int_literal | @unified_token_regex_literal | @unified_token_string_literal | @unified_token_super_expr | @unified_token_unsupported_node | @unified_try_expr | @unified_tuple_expr | @unified_type_cast_expr | @unified_type_test_expr | @unified_unary_expr + +unified_expr_equality_pattern_def( + unique int id: @unified_expr_equality_pattern, + int expr: @unified_expr ref +); + +@unified_expr_or_pattern = @unified_expr | @unified_pattern + +@unified_expr_or_type = @unified_expr | @unified_type_expr + +unified_for_each_stmt_body( + unique int unified_for_each_stmt: @unified_for_each_stmt ref, + unique int body: @unified_block ref +); + +unified_for_each_stmt_guard( + unique int unified_for_each_stmt: @unified_for_each_stmt ref, + unique int guard: @unified_expr ref +); + +#keyset[unified_for_each_stmt, index] +unified_for_each_stmt_modifier( + int unified_for_each_stmt: @unified_for_each_stmt ref, + int index: int ref, + unique int modifier: @unified_token_modifier ref +); + +unified_for_each_stmt_def( + unique int id: @unified_for_each_stmt, + int iterable: @unified_expr ref, + int pattern: @unified_pattern ref +); + +unified_function_declaration_body( + unique int unified_function_declaration: @unified_function_declaration ref, + unique int body: @unified_block ref +); + +#keyset[unified_function_declaration, index] +unified_function_declaration_modifier( + int unified_function_declaration: @unified_function_declaration ref, + int index: int ref, + unique int modifier: @unified_token_modifier ref +); + +#keyset[unified_function_declaration, index] +unified_function_declaration_parameter( + int unified_function_declaration: @unified_function_declaration ref, + int index: int ref, + unique int parameter: @unified_parameter ref +); + +unified_function_declaration_return_type( + unique int unified_function_declaration: @unified_function_declaration ref, + unique int return_type: @unified_type_expr ref +); + +#keyset[unified_function_declaration, index] +unified_function_declaration_type_constraint( + int unified_function_declaration: @unified_function_declaration ref, + int index: int ref, + unique int type_constraint: @unified_type_constraint ref +); + +#keyset[unified_function_declaration, index] +unified_function_declaration_type_parameter( + int unified_function_declaration: @unified_function_declaration ref, + int index: int ref, + unique int type_parameter: @unified_type_parameter ref +); + +unified_function_declaration_def( + unique int id: @unified_function_declaration, + int name: @unified_token_identifier ref +); + +#keyset[unified_function_expr, index] +unified_function_expr_capture_declaration( + int unified_function_expr: @unified_function_expr ref, + int index: int ref, + unique int capture_declaration: @unified_variable_declaration ref +); + +#keyset[unified_function_expr, index] +unified_function_expr_modifier( + int unified_function_expr: @unified_function_expr ref, + int index: int ref, + unique int modifier: @unified_token_modifier ref +); + +#keyset[unified_function_expr, index] +unified_function_expr_parameter( + int unified_function_expr: @unified_function_expr ref, + int index: int ref, + unique int parameter: @unified_parameter ref +); + +unified_function_expr_return_type( + unique int unified_function_expr: @unified_function_expr ref, + unique int return_type: @unified_type_expr ref +); + +unified_function_expr_def( + unique int id: @unified_function_expr, + int body: @unified_block ref +); + +#keyset[unified_function_type_expr, index] +unified_function_type_expr_parameter( + int unified_function_type_expr: @unified_function_type_expr ref, + int index: int ref, + unique int parameter: @unified_parameter ref +); + +unified_function_type_expr_def( + unique int id: @unified_function_type_expr, + int return_type: @unified_type_expr ref +); + +#keyset[unified_generic_type_expr, index] +unified_generic_type_expr_type_argument( + int unified_generic_type_expr: @unified_generic_type_expr ref, + int index: int ref, + unique int type_argument: @unified_type_expr ref +); + +unified_generic_type_expr_def( + unique int id: @unified_generic_type_expr, + int base: @unified_type_expr ref +); + +unified_guard_if_stmt_def( + unique int id: @unified_guard_if_stmt, + int condition: @unified_expr ref, + int else: @unified_block ref +); + +unified_if_expr_else( + unique int unified_if_expr: @unified_if_expr ref, + unique int else: @unified_expr ref +); + +unified_if_expr_then( + unique int unified_if_expr: @unified_if_expr ref, + unique int then: @unified_expr ref +); + +unified_if_expr_def( + unique int id: @unified_if_expr, + int condition: @unified_expr ref +); + +#keyset[unified_import_declaration, index] +unified_import_declaration_modifier( + int unified_import_declaration: @unified_import_declaration ref, + int index: int ref, + unique int modifier: @unified_token_modifier ref +); + +unified_import_declaration_pattern( + unique int unified_import_declaration: @unified_import_declaration ref, + unique int pattern: @unified_pattern ref +); + +unified_import_declaration_def( + unique int id: @unified_import_declaration, + int imported_expr: @unified_expr ref +); + +#keyset[unified_initializer_declaration, index] +unified_initializer_declaration_modifier( + int unified_initializer_declaration: @unified_initializer_declaration ref, + int index: int ref, + unique int modifier: @unified_token_modifier ref +); + +unified_initializer_declaration_def( + unique int id: @unified_initializer_declaration, + int body: @unified_block ref +); + +unified_key_value_pair_def( + unique int id: @unified_key_value_pair, + int key__: @unified_expr ref, int value: @unified_expr ref ); +unified_labeled_stmt_def( + unique int id: @unified_labeled_stmt, + int label: @unified_token_identifier ref, + int stmt: @unified_stmt ref +); + +#keyset[unified_map_literal, index] +unified_map_literal_element( + int unified_map_literal: @unified_map_literal ref, + int index: int ref, + unique int element: @unified_expr ref +); + +unified_map_literal_def( + unique int id: @unified_map_literal +); + +@unified_member = @unified_accessor_declaration | @unified_associated_type_declaration | @unified_class_like_declaration | @unified_constructor_declaration | @unified_destructor_declaration | @unified_function_declaration | @unified_initializer_declaration | @unified_token_unsupported_node | @unified_type_alias_declaration | @unified_variable_declaration + unified_member_access_expr_def( unique int id: @unified_member_access_expr, - int member: @unified_token_identifier ref, - int target: @unified_expr ref + int base: @unified_expr_or_type ref, + int member: @unified_token_identifier ref ); unified_name_expr_def( @@ -244,83 +670,358 @@ unified_name_expr_def( int identifier: @unified_token_identifier ref ); +#keyset[unified_name_pattern, index] +unified_name_pattern_modifier( + int unified_name_pattern: @unified_name_pattern ref, + int index: int ref, + unique int modifier: @unified_token_modifier ref +); + +unified_name_pattern_def( + unique int id: @unified_name_pattern, + int identifier: @unified_token_identifier ref +); + +unified_named_type_expr_qualifier( + unique int unified_named_type_expr: @unified_named_type_expr ref, + unique int qualifier: @unified_type_expr ref +); + +unified_named_type_expr_def( + unique int id: @unified_named_type_expr, + int name: @unified_token_identifier ref +); + +@unified_operator = @unified_token_infix_operator | @unified_token_postfix_operator | @unified_token_prefix_operator + +unified_operator_syntax_declaration_fixity( + unique int unified_operator_syntax_declaration: @unified_operator_syntax_declaration ref, + unique int fixity: @unified_token_fixity ref +); + +#keyset[unified_operator_syntax_declaration, index] +unified_operator_syntax_declaration_modifier( + int unified_operator_syntax_declaration: @unified_operator_syntax_declaration ref, + int index: int ref, + unique int modifier: @unified_token_modifier ref +); + +unified_operator_syntax_declaration_precedence( + unique int unified_operator_syntax_declaration: @unified_operator_syntax_declaration ref, + unique int precedence: @unified_expr ref +); + +unified_operator_syntax_declaration_def( + unique int id: @unified_operator_syntax_declaration, + int name: @unified_token_identifier ref +); + +unified_parameter_default( + unique int unified_parameter: @unified_parameter ref, + unique int default: @unified_expr ref +); + +unified_parameter_external_name( + unique int unified_parameter: @unified_parameter ref, + unique int external_name: @unified_token_identifier ref +); + +#keyset[unified_parameter, index] +unified_parameter_modifier( + int unified_parameter: @unified_parameter ref, + int index: int ref, + unique int modifier: @unified_token_modifier ref +); + +unified_parameter_pattern( + unique int unified_parameter: @unified_parameter ref, + unique int pattern: @unified_pattern ref +); + +unified_parameter_type( + unique int unified_parameter: @unified_parameter ref, + unique int type__: @unified_type_expr ref +); + unified_parameter_def( - unique int id: @unified_parameter, + unique int id: @unified_parameter +); + +@unified_pattern = @unified_bulk_importing_pattern | @unified_constructor_pattern | @unified_expr_equality_pattern | @unified_name_pattern | @unified_token_ignore_pattern | @unified_token_unsupported_node | @unified_tuple_pattern + +unified_pattern_element_key( + unique int unified_pattern_element: @unified_pattern_element ref, + unique int key__: @unified_token_identifier ref +); + +#keyset[unified_pattern_element, index] +unified_pattern_element_modifier( + int unified_pattern_element: @unified_pattern_element ref, + int index: int ref, + unique int modifier: @unified_token_modifier ref +); + +unified_pattern_element_def( + unique int id: @unified_pattern_element, int pattern: @unified_pattern ref ); -@unified_pattern = @unified_apply_pattern | @unified_token_ignore_pattern | @unified_token_unsupported_node | @unified_tuple_pattern | @unified_var_pattern - -#keyset[unified_sequence_condition, index] -unified_sequence_condition_stmt( - int unified_sequence_condition: @unified_sequence_condition ref, - int index: int ref, - unique int stmt: @unified_stmt ref +unified_pattern_guard_expr_def( + unique int id: @unified_pattern_guard_expr, + int pattern: @unified_pattern ref, + int value: @unified_expr ref ); -unified_sequence_condition_def( - unique int id: @unified_sequence_condition, - int condition: @unified_condition ref +unified_return_expr_value( + unique int unified_return_expr: @unified_return_expr ref, + unique int value: @unified_expr ref ); -@unified_stmt = @unified_block_stmt | @unified_expr_stmt | @unified_guard_if_stmt | @unified_if_stmt | @unified_token_empty_stmt | @unified_token_unsupported_node | @unified_variable_declaration_stmt +unified_return_expr_def( + unique int id: @unified_return_expr +); -@unified_top_level_body_type = @unified_expr | @unified_stmt +@unified_stmt = @unified_accessor_declaration | @unified_class_like_declaration | @unified_constructor_declaration | @unified_destructor_declaration | @unified_do_while_stmt | @unified_expr | @unified_for_each_stmt | @unified_function_declaration | @unified_guard_if_stmt | @unified_import_declaration | @unified_labeled_stmt | @unified_operator_syntax_declaration | @unified_type_alias_declaration | @unified_variable_declaration | @unified_while_stmt -#keyset[unified_top_level, index] -unified_top_level_body( - int unified_top_level: @unified_top_level ref, +unified_switch_case_guard( + unique int unified_switch_case: @unified_switch_case ref, + unique int guard: @unified_expr ref +); + +#keyset[unified_switch_case, index] +unified_switch_case_modifier( + int unified_switch_case: @unified_switch_case ref, int index: int ref, - unique int body: @unified_top_level_body_type ref + unique int modifier: @unified_token_modifier ref +); + +#keyset[unified_switch_case, index] +unified_switch_case_pattern( + int unified_switch_case: @unified_switch_case ref, + int index: int ref, + unique int pattern: @unified_pattern ref +); + +unified_switch_case_def( + unique int id: @unified_switch_case, + int body: @unified_block ref +); + +#keyset[unified_switch_expr, index] +unified_switch_expr_case( + int unified_switch_expr: @unified_switch_expr ref, + int index: int ref, + unique int case__: @unified_switch_case ref +); + +#keyset[unified_switch_expr, index] +unified_switch_expr_modifier( + int unified_switch_expr: @unified_switch_expr ref, + int index: int ref, + unique int modifier: @unified_token_modifier ref +); + +unified_switch_expr_def( + unique int id: @unified_switch_expr, + int value: @unified_expr ref +); + +unified_throw_expr_value( + unique int unified_throw_expr: @unified_throw_expr ref, + unique int value: @unified_expr ref +); + +unified_throw_expr_def( + unique int id: @unified_throw_expr ); unified_top_level_def( - unique int id: @unified_top_level + unique int id: @unified_top_level, + int body: @unified_block ref +); + +#keyset[unified_try_expr, index] +unified_try_expr_catch_clause( + int unified_try_expr: @unified_try_expr ref, + int index: int ref, + unique int catch_clause: @unified_catch_clause ref +); + +#keyset[unified_try_expr, index] +unified_try_expr_modifier( + int unified_try_expr: @unified_try_expr ref, + int index: int ref, + unique int modifier: @unified_token_modifier ref +); + +unified_try_expr_def( + unique int id: @unified_try_expr, + int body: @unified_block ref +); + +#keyset[unified_tuple_expr, index] +unified_tuple_expr_element( + int unified_tuple_expr: @unified_tuple_expr ref, + int index: int ref, + unique int element: @unified_expr ref +); + +unified_tuple_expr_def( + unique int id: @unified_tuple_expr ); #keyset[unified_tuple_pattern, index] unified_tuple_pattern_element( int unified_tuple_pattern: @unified_tuple_pattern ref, int index: int ref, - unique int element: @unified_pattern ref + unique int element: @unified_pattern_element ref +); + +#keyset[unified_tuple_pattern, index] +unified_tuple_pattern_modifier( + int unified_tuple_pattern: @unified_tuple_pattern ref, + int index: int ref, + unique int modifier: @unified_token_modifier ref ); unified_tuple_pattern_def( unique int id: @unified_tuple_pattern ); +unified_tuple_type_element_name( + unique int unified_tuple_type_element: @unified_tuple_type_element ref, + unique int name: @unified_token_identifier ref +); + +unified_tuple_type_element_def( + unique int id: @unified_tuple_type_element, + int type__: @unified_type_expr ref +); + +#keyset[unified_tuple_type_expr, index] +unified_tuple_type_expr_element( + int unified_tuple_type_expr: @unified_tuple_type_expr ref, + int index: int ref, + unique int element: @unified_tuple_type_element ref +); + +unified_tuple_type_expr_def( + unique int id: @unified_tuple_type_expr +); + +#keyset[unified_type_alias_declaration, index] +unified_type_alias_declaration_modifier( + int unified_type_alias_declaration: @unified_type_alias_declaration ref, + int index: int ref, + unique int modifier: @unified_token_modifier ref +); + +#keyset[unified_type_alias_declaration, index] +unified_type_alias_declaration_type_constraint( + int unified_type_alias_declaration: @unified_type_alias_declaration ref, + int index: int ref, + unique int type_constraint: @unified_type_constraint ref +); + +#keyset[unified_type_alias_declaration, index] +unified_type_alias_declaration_type_parameter( + int unified_type_alias_declaration: @unified_type_alias_declaration ref, + int index: int ref, + unique int type_parameter: @unified_type_parameter ref +); + +unified_type_alias_declaration_def( + unique int id: @unified_type_alias_declaration, + int name: @unified_token_identifier ref, + int type__: @unified_type_expr ref +); + +unified_type_cast_expr_def( + unique int id: @unified_type_cast_expr, + int expr: @unified_expr ref, + int operator: @unified_token_infix_operator ref, + int type__: @unified_type_expr ref +); + +@unified_type_constraint = @unified_bound_type_constraint | @unified_equality_type_constraint + +@unified_type_expr = @unified_function_type_expr | @unified_generic_type_expr | @unified_named_type_expr | @unified_token_inferred_type_expr | @unified_token_unsupported_node | @unified_tuple_type_expr + +unified_type_parameter_bound( + unique int unified_type_parameter: @unified_type_parameter ref, + unique int bound: @unified_type_expr ref +); + +#keyset[unified_type_parameter, index] +unified_type_parameter_modifier( + int unified_type_parameter: @unified_type_parameter ref, + int index: int ref, + unique int modifier: @unified_token_modifier ref +); + +unified_type_parameter_def( + unique int id: @unified_type_parameter, + int name: @unified_token_identifier ref +); + +unified_type_test_expr_def( + unique int id: @unified_type_test_expr, + int expr: @unified_expr ref, + int operator: @unified_token_infix_operator ref, + int type__: @unified_type_expr ref +); + +unified_type_test_pattern_def( + unique int id: @unified_type_test_pattern, + int pattern: @unified_pattern ref, + int type__: @unified_type_expr ref +); + unified_unary_expr_def( unique int id: @unified_unary_expr, int operand: @unified_expr ref, - int operator: @unified_token_operator ref + int operator: @unified_operator ref ); -unified_var_pattern_def( - unique int id: @unified_var_pattern, - int identifier: @unified_token_identifier ref -); - -#keyset[unified_variable_declaration_stmt, index] -unified_variable_declaration_stmt_variable_declarator( - int unified_variable_declaration_stmt: @unified_variable_declaration_stmt ref, +#keyset[unified_variable_declaration, index] +unified_variable_declaration_modifier( + int unified_variable_declaration: @unified_variable_declaration ref, int index: int ref, - unique int variable_declarator: @unified_variable_declarator ref + unique int modifier: @unified_token_modifier ref ); -unified_variable_declaration_stmt_def( - unique int id: @unified_variable_declaration_stmt +unified_variable_declaration_type( + unique int unified_variable_declaration: @unified_variable_declaration ref, + unique int type__: @unified_type_expr ref ); -unified_variable_declarator_value( - unique int unified_variable_declarator: @unified_variable_declarator ref, +unified_variable_declaration_value( + unique int unified_variable_declaration: @unified_variable_declaration ref, unique int value: @unified_expr ref ); -unified_variable_declarator_def( - unique int id: @unified_variable_declarator, +unified_variable_declaration_def( + unique int id: @unified_variable_declaration, int pattern: @unified_pattern ref ); +unified_while_stmt_body( + unique int unified_while_stmt: @unified_while_stmt ref, + unique int body: @unified_block ref +); + +#keyset[unified_while_stmt, index] +unified_while_stmt_modifier( + int unified_while_stmt: @unified_while_stmt ref, + int index: int ref, + unique int modifier: @unified_token_modifier ref +); + +unified_while_stmt_def( + unique int id: @unified_while_stmt, + int condition: @unified_expr ref +); + unified_tokeninfo( unique int id: @unified_token, int kind: int ref, @@ -328,13 +1029,24 @@ unified_tokeninfo( ); case @unified_token.kind of - 1 = @unified_token_empty_stmt -| 2 = @unified_token_identifier -| 3 = @unified_token_ignore_pattern -| 4 = @unified_token_int_literal -| 5 = @unified_token_operator -| 6 = @unified_token_string_literal -| 7 = @unified_token_unsupported_node + 1 = @unified_token_accessor_kind +| 2 = @unified_token_boolean_literal +| 3 = @unified_token_builtin_expr +| 4 = @unified_token_empty_expr +| 5 = @unified_token_fixity +| 6 = @unified_token_float_literal +| 7 = @unified_token_identifier +| 8 = @unified_token_ignore_pattern +| 9 = @unified_token_inferred_type_expr +| 10 = @unified_token_infix_operator +| 11 = @unified_token_int_literal +| 12 = @unified_token_modifier +| 13 = @unified_token_postfix_operator +| 14 = @unified_token_prefix_operator +| 15 = @unified_token_regex_literal +| 16 = @unified_token_string_literal +| 17 = @unified_token_super_expr +| 18 = @unified_token_unsupported_node ; @@ -344,7 +1056,7 @@ unified_trivia_tokeninfo( string value: string ref ); -@unified_ast_node = @unified_apply_pattern | @unified_binary_expr | @unified_block_stmt | @unified_call_expr | @unified_expr_condition | @unified_expr_stmt | @unified_guard_if_stmt | @unified_if_stmt | @unified_lambda_expr | @unified_let_pattern_condition | @unified_member_access_expr | @unified_name_expr | @unified_parameter | @unified_sequence_condition | @unified_token | @unified_top_level | @unified_trivia_token | @unified_tuple_pattern | @unified_unary_expr | @unified_var_pattern | @unified_variable_declaration_stmt | @unified_variable_declarator +@unified_ast_node = @unified_accessor_declaration | @unified_argument | @unified_array_literal | @unified_assign_expr | @unified_associated_type_declaration | @unified_base_type | @unified_binary_expr | @unified_block | @unified_bound_type_constraint | @unified_break_expr | @unified_bulk_importing_pattern | @unified_call_expr | @unified_catch_clause | @unified_class_like_declaration | @unified_compound_assign_expr | @unified_constructor_declaration | @unified_constructor_pattern | @unified_continue_expr | @unified_destructor_declaration | @unified_do_while_stmt | @unified_equality_type_constraint | @unified_expr_equality_pattern | @unified_for_each_stmt | @unified_function_declaration | @unified_function_expr | @unified_function_type_expr | @unified_generic_type_expr | @unified_guard_if_stmt | @unified_if_expr | @unified_import_declaration | @unified_initializer_declaration | @unified_key_value_pair | @unified_labeled_stmt | @unified_map_literal | @unified_member_access_expr | @unified_name_expr | @unified_name_pattern | @unified_named_type_expr | @unified_operator_syntax_declaration | @unified_parameter | @unified_pattern_element | @unified_pattern_guard_expr | @unified_return_expr | @unified_switch_case | @unified_switch_expr | @unified_throw_expr | @unified_token | @unified_top_level | @unified_trivia_token | @unified_try_expr | @unified_tuple_expr | @unified_tuple_pattern | @unified_tuple_type_element | @unified_tuple_type_expr | @unified_type_alias_declaration | @unified_type_cast_expr | @unified_type_parameter | @unified_type_test_expr | @unified_type_test_pattern | @unified_unary_expr | @unified_variable_declaration | @unified_while_stmt unified_ast_node_location( unique int node: @unified_ast_node ref, diff --git a/unified/ql/test/library-tests/BasicTest/test.expected b/unified/ql/test/library-tests/BasicTest/test.expected index 5298ec6f982..b9f4eafe865 100644 --- a/unified/ql/test/library-tests/BasicTest/test.expected +++ b/unified/ql/test/library-tests/BasicTest/test.expected @@ -1,9 +1,37 @@ nameExpr +| name_expr.swift:1:9:1:9 | NameExpr | y | +| test.swift:1:8:1:17 | NameExpr | Foundation | +| test.swift:8:9:8:13 | NameExpr | items | +| test.swift:8:22:8:25 | NameExpr | item | +| test.swift:12:16:12:20 | NameExpr | items | +| test.swift:12:31:12:34 | NameExpr | item | +| test.swift:25:18:25:22 | NameExpr | Array | +| test.swift:25:24:25:28 | NameExpr | first | +| test.swift:26:17:26:22 | NameExpr | second | +| test.swift:27:13:27:18 | NameExpr | result | +| test.swift:27:29:27:32 | NameExpr | item | +| test.swift:28:13:28:18 | NameExpr | result | +| test.swift:28:27:28:30 | NameExpr | item | +| test.swift:31:12:31:17 | NameExpr | result | +| test.swift:40:16:40:19 | NameExpr | data | +| test.swift:44:9:44:12 | NameExpr | data | +| test.swift:48:15:48:19 | NameExpr | index | +| test.swift:48:29:48:33 | NameExpr | index | +| test.swift:48:37:48:40 | NameExpr | data | +| test.swift:49:16:49:19 | NameExpr | data | +| test.swift:49:21:49:25 | NameExpr | index | +| test.swift:53:9:53:12 | NameExpr | data | +| test.swift:53:21:53:24 | NameExpr | item | +| test.swift:63:16:63:19 | NameExpr | self | +| test.swift:65:29:65:37 | NameExpr | transform | +| test.swift:65:39:65:43 | NameExpr | value | +| test.swift:67:29:67:33 | NameExpr | error | +| test.swift:76:16:76:19 | NameExpr | self | +| test.swift:76:21:76:21 | NameExpr | i | +| test.swift:76:26:76:29 | NameExpr | self | +| test.swift:76:31:76:31 | NameExpr | i | +| test.swift:86:12:86:17 | NameExpr | values | +| test.swift:87:12:87:17 | NameExpr | values | +| test.swift:87:38:87:43 | NameExpr | values | +| test.swift:87:49:87:57 | NameExpr | transform | unsupported -| test.swift:3:1:3:38 | | | -| test.swift:16:1:16:32 | | | -| test.swift:23:1:23:37 | | | -| test.swift:34:1:34:49 | | | -| test.swift:57:1:57:30 | | | -| test.swift:72:1:72:37 | | | -| test.swift:84:1:84:24 | | |