From e57089a84ee48374258de51968751e5b74767536 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Wed, 4 Jun 2025 00:31:56 -0700 Subject: [PATCH 01/15] Initial CI/CD config to try --- .github/workflows/codeql-query-format.yaml | 32 +++++ .github/workflows/codeql-unit-tests.yaml | 135 +++++++++++++++++++++ 2 files changed, 167 insertions(+) create mode 100644 .github/workflows/codeql-query-format.yaml create mode 100644 .github/workflows/codeql-unit-tests.yaml diff --git a/.github/workflows/codeql-query-format.yaml b/.github/workflows/codeql-query-format.yaml new file mode 100644 index 0000000..6787e1d --- /dev/null +++ b/.github/workflows/codeql-query-format.yaml @@ -0,0 +1,32 @@ +name: "Validate Query Formatting" +on: + pull_request: + branches: + - main + +env: + XARGS_MAX_PROCS: 4 + +jobs: + validate-query-formatting: + runs-on: ubuntu-22.04 + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref }} + + - name: Setup CodeQL + id: install-codeql + uses: ./.github/actions/install-codeql + + - name: Validate query format + env: + LANGUAGE: ${{ matrix.language }} + run: | + codeql version + find . \( -name \*.ql -or -name \*.qll \) -print0 | xargs -0 --max-procs "$XARGS_MAX_PROCS" codeql query format --in-place + + git diff + git diff --compact-summary + git diff --quiet \ No newline at end of file diff --git a/.github/workflows/codeql-unit-tests.yaml b/.github/workflows/codeql-unit-tests.yaml new file mode 100644 index 0000000..d558eca --- /dev/null +++ b/.github/workflows/codeql-unit-tests.yaml @@ -0,0 +1,135 @@ +name: Build CodeQL Packs + +on: + pull_request: + branches: [ main ] + workflow_dispatch: + +jobs: + compile-and-test: + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + language: [ 'common', 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby', 'swift' ] + + steps: + - uses: actions/checkout@v4 + + - name: Setup CodeQL + id: install-codeql + uses: ./.github/actions/install-codeql + + - name: Install CodeQL packs + uses: ./.github/actions/install-codeql-packs + with: + cli_path: ${{ github.workspace }}/codeql_home/codeql + + - name: Pre-Compile Queries + id: pre-compile-queries + run: | + ${{ github.workspace }}/codeql_home/codeql/codeql query compile --threads 0 ${{ matrix.language }} + + - name: Test Queries + if: steps.changes.outputs.src == 'true' + env: + RUNNER_TEMP: ${{ runner.temp }} + shell: python + run: | + import os + import sys + import subprocess + from pathlib import Path + + def print_error(fmt, *args): + print(f"::error::{fmt}", *args) + + def print_error_and_fail(fmt, *args): + print_error(fmt, args) + sys.exit(1) + + runner_temp = os.environ['RUNNER_TEMP'] + + if ${{ matrix.language }} == 'common': + test_root = Path('${{ github.workspace }}', 'test') + else: + test_root = Path('${{ github.workspace }}', '${{ matrix.language }}', 'test') + print(f"Executing tests found (recursively) in the directory '{test_root}'") + files_to_close = [] + try: + # Runners have 4 cores, so split the tests into 4 "slices", and run one per thread + num_slices = 4 + procs = [] + + for slice in range(1, num_slices+1): + test_report_path = os.path.join(runner_temp, "${{ matrix.language }}", f"test_report_slice_{slice}_of_{num_slices}.json") + os.makedirs(os.path.dirname(test_report_path), exist_ok=True) + test_report_file = open(test_report_path, 'w') + files_to_close.append(test_report_file) + procs.append(subprocess.Popen(["codeql", "test", "run", "--failing-exitcode=122", f"--slice={slice}/{num_slices}", "--ram=2048", "--format=json", test_root], stdout=test_report_file, stderr=subprocess.PIPE)) + + for p in procs: + _, err = p.communicate() + if p.returncode != 0: + if p.returncode == 122: + # Failed because a test case failed, so just print the regular output. + # This will allow us to proceed to validate-test-results, which will fail if + # any test cases failed + print(f"{err.decode()}") + else: + # Some more serious problem occurred, so print and fail fast + print_error_and_fail(f"Failed to run tests with return code {p.returncode}\n{err.decode()}") + finally: + for file in files_to_close: + file.close() + + - name: Upload test results + if: steps.changes.outputs.src == 'true' + uses: actions/upload-artifact@v4 + with: + name: ${{ matrix.language }}-test-results + path: | + ${{ runner.temp }}/${{ matrix.language }}/test_report_slice_*.json + if-no-files-found: error + + - name: Compile / Check Suites & Packs + if: steps.changes.outputs.src == 'true' + env: + GITHUB_TOKEN: ${{ github.token }} + run: | + ./.github/scripts/pr-suites-packs.sh ${{ github.event.number }} ${{ matrix.language }} + + validate-test-results: + name: Validate test results + needs: compile-and-test + runs-on: ubuntu-latest + steps: + - name: Check if compile-and-test job failed to complete, if so fail + if: ${{ needs.compile-and-test.result == 'failure' }} + uses: actions/github-script@v7 + with: + script: | + core.setFailed('Test run job failed') + + - name: Collect test results + uses: actions/download-artifact@v4 + + - name: Validate test results + run: | + if [[ ! -n "$(find . -name 'test_report_*' -print -quit)" ]]; then + echo "No test results found" + exit 0 + fi + + for json_report in *-test-results/test_report_* + do + jq --raw-output '"PASS \(map(select(.pass == true)) | length)/\(length)'" $json_report\"" "$json_report" + done + FAILING_TESTS=$(jq --raw-output '.[] | select(.pass == false)' *-test-results/test_report_*.json) + if [[ ! -z "$FAILING_TESTS" ]]; then + echo "ERROR: The following tests failed:" + echo $FAILING_TESTS | jq . + exit 1 + fi + \ No newline at end of file From 96b50d1ce98fb0c4634900ce2029bea513f47746 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Wed, 4 Jun 2025 00:37:30 -0700 Subject: [PATCH 02/15] First pass fixing CI/CD issues --- .../actions/install-codeql-packs/action.yml | 25 ++++++++ .github/actions/install-codeql/action.yml | 62 +++++++++++++++++++ .github/workflows/codeql-query-format.yaml | 2 - 3 files changed, 87 insertions(+), 2 deletions(-) create mode 100644 .github/actions/install-codeql-packs/action.yml create mode 100644 .github/actions/install-codeql/action.yml diff --git a/.github/actions/install-codeql-packs/action.yml b/.github/actions/install-codeql-packs/action.yml new file mode 100644 index 0000000..2e6d5f1 --- /dev/null +++ b/.github/actions/install-codeql-packs/action.yml @@ -0,0 +1,25 @@ +name: Install CodeQL library pack dependencies +description: | + Downloads any necessary CodeQL library packs needed by packs in the repo. +inputs: + cli_path: + description: | + The path to the CodeQL CLI directory. + required: false + + mode: + description: | + The `--mode` option to `codeql pack install`. + required: true + default: verify + +runs: + using: composite + steps: + - name: Install CodeQL library packs + shell: bash + env: + CODEQL_CLI: ${{ inputs.cli_path }} + run: | + PATH=$PATH:$CODEQL_CLI + python scripts/install-packs.py --mode ${{ inputs.mode }} diff --git a/.github/actions/install-codeql/action.yml b/.github/actions/install-codeql/action.yml new file mode 100644 index 0000000..92c126c --- /dev/null +++ b/.github/actions/install-codeql/action.yml @@ -0,0 +1,62 @@ +name: Setup CodeQL CLI +description: | + Install a CodeQL CLI or re-use an existing one from the cache and it to the path. + +outputs: + codeql-cli-version: + description: "The version of the CodeQL CLI that was installed or retrieved from cache" + value: ${{ steps.codeql-version.outputs.codeql-cli-version }} + +runs: + using: composite + steps: + - name: "CodeQL Version" + id: codeql-version + shell: bash + run: | + echo "Reading CodeQL CLI version from .codeqlversion file." + CODEQL_CLI_VERSION=$(cat ./.codeqlversion) + echo "CODEQL_CLI_VERSION=${CODEQL_CLI_VERSION}" >> $GITHUB_ENV + echo "codeql-cli-version=${CODEQL_CLI_VERSION}" >> $GITHUB_OUTPUT + + - name: Cache CodeQL + id: cache-codeql + uses: actions/cache@v4 + with: + # A list of files, directories, and wildcard patterns to cache and restore + path: ${{github.workspace}}/codeql_home + # An explicit key for restoring and saving the cache + key: codeql-home-${{ steps.codeql-version.outputs.codeql-cli-version }} + + - name: Install CodeQL + id: install-codeql + if: steps.cache-codeql.outputs.cache-hit != 'true' + shell: bash + env: + GITHUB_TOKEN: ${{ github.token }} + CODEQL_HOME: ${{ github.workspace }}/codeql_home + CODEQL_CLI_VERSION: ${{ steps.codeql-version.outputs.codeql-cli-version }} + run: | + echo "Installing CodeQL CLI v${CODEQL_CLI_VERSION}." + + mkdir -p $CODEQL_HOME + echo "Change directory to $CODEQL_HOME" + pushd $CODEQL_HOME + + echo "Downloading CodeQL CLI v${CODEQL_CLI_VERSION}." + gh release download "v${CODEQL_CLI_VERSION}" --repo https://github.com/github/codeql-cli-binaries --pattern codeql-linux64.zip + + echo "Unzipping CodeQL CLI." + unzip -q codeql-linux64.zip + + popd + echo "Done." + echo "codeql-cli-version=${CODEQL_CLI_VERSION}" >> $GITHUB_OUTPUT + + - name: Add CodeQL to the PATH + shell: bash + env: + CODEQL_HOME: ${{ github.workspace }}/codeql_home + run: | + echo "Adding CodeQL CLI to the PATH." + echo "$CODEQL_HOME/codeql" >> $GITHUB_PATH \ No newline at end of file diff --git a/.github/workflows/codeql-query-format.yaml b/.github/workflows/codeql-query-format.yaml index 6787e1d..b7ff390 100644 --- a/.github/workflows/codeql-query-format.yaml +++ b/.github/workflows/codeql-query-format.yaml @@ -21,8 +21,6 @@ jobs: uses: ./.github/actions/install-codeql - name: Validate query format - env: - LANGUAGE: ${{ matrix.language }} run: | codeql version find . \( -name \*.ql -or -name \*.qll \) -print0 | xargs -0 --max-procs "$XARGS_MAX_PROCS" codeql query format --in-place From a94a2d6880355a21ac00b9920fb9d4b0fd70b6bb Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Wed, 4 Jun 2025 00:39:53 -0700 Subject: [PATCH 03/15] Second try fixing CI/CD --- .codeqlversion | 1 + .github/workflows/codeql-query-format.yaml | 23 ++++++++++------------ 2 files changed, 11 insertions(+), 13 deletions(-) create mode 100644 .codeqlversion diff --git a/.codeqlversion b/.codeqlversion new file mode 100644 index 0000000..0352eb1 --- /dev/null +++ b/.codeqlversion @@ -0,0 +1 @@ +2.20.1 \ No newline at end of file diff --git a/.github/workflows/codeql-query-format.yaml b/.github/workflows/codeql-query-format.yaml index b7ff390..2b5d098 100644 --- a/.github/workflows/codeql-query-format.yaml +++ b/.github/workflows/codeql-query-format.yaml @@ -9,22 +9,19 @@ env: jobs: validate-query-formatting: - runs-on: ubuntu-22.04 - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - ref: ${{ inputs.ref }} + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 - name: Setup CodeQL id: install-codeql uses: ./.github/actions/install-codeql - - name: Validate query format - run: | - codeql version - find . \( -name \*.ql -or -name \*.qll \) -print0 | xargs -0 --max-procs "$XARGS_MAX_PROCS" codeql query format --in-place + - name: Validate query format + run: | + codeql version + find . \( -name \*.ql -or -name \*.qll \) -print0 | xargs -0 --max-procs "$XARGS_MAX_PROCS" codeql query format --in-place - git diff - git diff --compact-summary - git diff --quiet \ No newline at end of file + git diff + git diff --compact-summary + git diff --quiet \ No newline at end of file From f7c704ab252d57a82a5f14ec9205f67020a663af Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Wed, 4 Jun 2025 00:46:21 -0700 Subject: [PATCH 04/15] Third try fixing CI/CD --- .../actions/install-codeql-packs/action.yml | 2 +- .github/scripts/install-packs.py | 23 +++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 .github/scripts/install-packs.py diff --git a/.github/actions/install-codeql-packs/action.yml b/.github/actions/install-codeql-packs/action.yml index 2e6d5f1..fbd2c8b 100644 --- a/.github/actions/install-codeql-packs/action.yml +++ b/.github/actions/install-codeql-packs/action.yml @@ -22,4 +22,4 @@ runs: CODEQL_CLI: ${{ inputs.cli_path }} run: | PATH=$PATH:$CODEQL_CLI - python scripts/install-packs.py --mode ${{ inputs.mode }} + python .github/scripts/install-packs.py --mode ${{ inputs.mode }} diff --git a/.github/scripts/install-packs.py b/.github/scripts/install-packs.py new file mode 100644 index 0000000..ab45c32 --- /dev/null +++ b/.github/scripts/install-packs.py @@ -0,0 +1,23 @@ +import argparse +import os +import subprocess +import get_workspace_packs + +parser = argparse.ArgumentParser(description="Install CodeQL library pack dependencies.") +parser.add_argument('--mode', required=False, choices=['use-lock', 'update', 'verify', 'no-lock'], default="use-lock", help="Installation mode, identical to the `--mode` argument to `codeql pack install`") +parser.add_argument('--codeql', required=False, default='codeql', help="Path to the `codeql` executable.") +args = parser.parse_args() + +# Find the root of the repo +root = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + +packs = get_workspace_packs.get_workspace_packs(root) + +# Find the CodeQL packs in the repo. This can also return packs outside of the repo, if those packs +# are installed in a sibling directory to the CLI. +for pack in packs: + pack_path = os.path.join(root, pack) + # Run `codeql pack install` to install dependencies. + command = [args.codeql, 'pack', 'install', '--allow-prerelease', '--mode', args.mode, pack_path] + print(f'Running `{" ".join(command)}`') + subprocess.check_call(command) From 58b6526148859426882bb84b0e5102e691234dd4 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Wed, 4 Jun 2025 00:48:02 -0700 Subject: [PATCH 05/15] Fourth try fix CI/CD --- .github/scripts/install-packs.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/.github/scripts/install-packs.py b/.github/scripts/install-packs.py index ab45c32..72c8fef 100644 --- a/.github/scripts/install-packs.py +++ b/.github/scripts/install-packs.py @@ -1,7 +1,19 @@ import argparse import os import subprocess -import get_workspace_packs +import glob +import json + +def get_workspace_packs(root): + # Find the packs by globbing using the 'provide' patterns in the manifest. + os.chdir(root) + with open('.codeqlmanifest.json') as manifest_file: + manifest = json.load(manifest_file) + packs = [] + for pattern in manifest['provide']: + packs.extend(glob.glob(pattern, recursive=True)) + + return packs parser = argparse.ArgumentParser(description="Install CodeQL library pack dependencies.") parser.add_argument('--mode', required=False, choices=['use-lock', 'update', 'verify', 'no-lock'], default="use-lock", help="Installation mode, identical to the `--mode` argument to `codeql pack install`") From ecdb5cded3b0e6f2d9e809776d986a180c1c9a29 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Wed, 4 Jun 2025 00:49:19 -0700 Subject: [PATCH 06/15] Fifth try fixing CI/CD --- .github/scripts/install-packs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/scripts/install-packs.py b/.github/scripts/install-packs.py index 72c8fef..68c9ed4 100644 --- a/.github/scripts/install-packs.py +++ b/.github/scripts/install-packs.py @@ -23,7 +23,7 @@ def get_workspace_packs(root): # Find the root of the repo root = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) -packs = get_workspace_packs.get_workspace_packs(root) +packs = get_workspace_packs(root) # Find the CodeQL packs in the repo. This can also return packs outside of the repo, if those packs # are installed in a sibling directory to the CLI. From 39c4edbe86ff69ff3c7eafea7bb80ebb01893803 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Wed, 4 Jun 2025 00:53:39 -0700 Subject: [PATCH 07/15] Sixth try fixing CI/CD --- .github/scripts/install-packs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/scripts/install-packs.py b/.github/scripts/install-packs.py index 68c9ed4..292375b 100644 --- a/.github/scripts/install-packs.py +++ b/.github/scripts/install-packs.py @@ -21,7 +21,7 @@ def get_workspace_packs(root): args = parser.parse_args() # Find the root of the repo -root = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) packs = get_workspace_packs(root) From cb741705d178be5915c8361eaba027809b2d2503 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Wed, 4 Jun 2025 01:06:49 -0700 Subject: [PATCH 08/15] Remove experimental PredicateClasses.qll, seventh try for CI/CD: common compile --- .github/workflows/codeql-unit-tests.yaml | 4 +- .../predicateclasses/PredicateClasses.qll | 98 ------------------- 2 files changed, 3 insertions(+), 99 deletions(-) delete mode 100644 src/qtil/predicateclasses/PredicateClasses.qll diff --git a/.github/workflows/codeql-unit-tests.yaml b/.github/workflows/codeql-unit-tests.yaml index d558eca..7068004 100644 --- a/.github/workflows/codeql-unit-tests.yaml +++ b/.github/workflows/codeql-unit-tests.yaml @@ -29,7 +29,9 @@ jobs: - name: Pre-Compile Queries id: pre-compile-queries run: | - ${{ github.workspace }}/codeql_home/codeql/codeql query compile --threads 0 ${{ matrix.language }} + if [ "${{ matrix.language }}" != "common" ]; then + ${{ github.workspace }}/codeql_home/codeql/codeql query compile --threads 0 ${{ matrix.language }} + fi - name: Test Queries if: steps.changes.outputs.src == 'true' diff --git a/src/qtil/predicateclasses/PredicateClasses.qll b/src/qtil/predicateclasses/PredicateClasses.qll deleted file mode 100644 index 4a190d1..0000000 --- a/src/qtil/predicateclasses/PredicateClasses.qll +++ /dev/null @@ -1,98 +0,0 @@ -/** - * A true abomination of a module. - * - * .....anything cool we can do with this?? - */ -private import qtil.parameterization.SignatureTypes -private import qtil.parameterization.SignaturePredicates -private import qtil.inheritance.Instance -private import qtil.tuple.StringTuple -private import qtil.strings.SeparatedList -private import codeql.util.Unit - -module BinaryToClass::pred/2 pred> { - final class Type instanceof Unit { - predicate holds(A t1, B t2) { pred(t1, t2) } - - bindingset[t1] - Curryable curry(A t1) { - result.curried(t1) - } - - string toString() { result = "Binary predicate class" } - } - - bindingset[this] - private class Curryable extends InfInstance::Type { - bindingset[t1] - predicate curried(A t1) { - this = t1 - } - - predicate curry(B t2) { - } - - predicate holds(B t) { - pred(this, t) - } - } -} - -module UnaryToClass::pred/1 pred> { - final class Type instanceof Unit { - predicate holds(T t) { pred(t) } - - bindingset[t] - Curryable curry(T t) { - result.curried(t) - } - - string toString() { result = "Unary predicate class" } - } - - bindingset[this] - private class Curryable extends InfInstance::Type { - bindingset[t] - predicate curried(T t) { - this = t - } - - predicate holds() { - pred(this) - } - } -} - -module UnaryClassSig { - signature class Type { - predicate holds(T t); - } -} - -module NullaryClassSig { - signature class Type { - predicate holds(); - } -} - -signature class UnaryIntSig { - predicate holds(int t); -} - -module ClassToUnary::Type UnaryClass> { - predicate pred(T t) { any(UnaryClass u).holds(t) } -} - -module ClassToNullary { - predicate pred() { any(NullaryClass u).holds() } -} - -predicate isEven(int i) { i % 2 = 0 and i in [0..10] } - -class IsEvenClass = UnaryToClass::Type; -predicate test() { - exists(IsEvenClass unary | - ClassToUnary::pred(1) and - unary.curry(2).holds() - ) -} \ No newline at end of file From fcd0284fd1eb6c2b0fab50e1be8a05dfa2b7a419 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Wed, 4 Jun 2025 01:14:34 -0700 Subject: [PATCH 09/15] Format all --- cpp/src/qtil/Cpp.qll | 4 +- cpp/src/qtil/cpp/ast/TwoOperands.qll | 2 +- cpp/src/qtil/cpp/format/QlFormat.qll | 3 +- cpp/src/qtil/cpp/graph/CustomPathProblem.qll | 3 +- cpp/test/qtil/cpp/format/QlFormatTest.ql | 2 +- .../qtil/cpp/graph/CustomPathProblemTest.ql | 8 +- csharp/src/qtil/csharp/ast/TwoOperands.qll | 2 +- csharp/src/qtil/csharp/format/QlFormat.qll | 3 +- .../qtil/csharp/graph/CustomPathProblem.qll | 3 +- .../test/qtil/csharp/format/QlFormatTest.ql | 2 +- .../csharp/graph/CustomPathProblemTest.ql | 8 +- go/src/qtil/Go.qll | 4 +- go/src/qtil/go/ast/TwoOperands.qll | 2 +- go/src/qtil/go/format/QlFormat.qll | 3 +- go/src/qtil/go/graph/CustomPathProblem.qll | 3 +- go/test/qtil/go/format/QlFormatTest.ql | 2 +- .../qtil/go/graph/CustomPathProblemTest.ql | 7 +- java/src/qtil/Java.qll | 4 +- java/src/qtil/java/ast/TwoOperands.qll | 2 +- java/src/qtil/java/format/QlFormat.qll | 3 +- .../src/qtil/java/graph/CustomPathProblem.qll | 3 +- java/test/qtil/java/format/QlFormatTest.ql | 2 +- javascript/src/qtil/Javascript.qll | 4 +- .../src/qtil/javascript/ast/TwoOperands.qll | 2 +- .../src/qtil/javascript/format/QlFormat.qll | 3 +- .../javascript/graph/CustomPathProblem.qll | 3 +- .../test/qtil/cpp/format/QlFormatTest.ql | 2 +- python/src/qtil/Python.qll | 4 +- python/src/qtil/python/ast/TwoOperands.qll | 2 +- python/src/qtil/python/format/QlFormat.qll | 3 +- .../qtil/python/graph/CustomPathProblem.qll | 3 +- .../test/qtil/python/format/QlFormatTest.ql | 2 +- ruby/src/qtil/Ruby.qll | 4 +- ruby/src/qtil/ruby/ast/TwoOperands.qll | 2 +- ruby/src/qtil/ruby/format/QlFormat.qll | 3 +- .../src/qtil/ruby/graph/CustomPathProblem.qll | 3 +- ruby/test/qtil/cpp/format/QlFormatTest.ql | 2 +- .../qtil/cpp/graph/CustomPathProblemTest.ql | 10 +-- src/qtil/Qtil.qll | 4 +- src/qtil/ast/TwoOperands.qll | 10 +-- src/qtil/fn/All.qll | 5 +- src/qtil/fn/Fn.qll | 2 +- src/qtil/fn/FnTypes.qll | 5 +- src/qtil/fn/Ordering.qll | 2 +- src/qtil/fn/ResultSet.qll | 5 +- src/qtil/fn/Tp.qll | 3 +- src/qtil/fn/TupleGet.qll | 5 +- src/qtil/graph/GraphPathSearch.qll | 53 +++++++------ src/qtil/inheritance/Finitize.qll | 6 +- src/qtil/inheritance/Instance.qll | 39 +++++----- src/qtil/inheritance/UnderlyingString.qll | 11 +-- src/qtil/locations/NullLocation.qll | 2 +- src/qtil/locations/OptionalLocation.qll | 2 +- src/qtil/locations/StringLocation.qll | 2 +- src/qtil/parameterization/Finalize.qll | 8 +- src/qtil/parameterization/SignatureTypes.qll | 28 +++---- src/qtil/strings/FluentString.qll | 8 +- src/qtil/strings/Join.qll | 20 ++--- src/qtil/testing/Qnit.qll | 1 + src/qtil/testing/impl/Qnit.qll | 2 +- src/qtil/tuple/Pair.qll | 3 +- src/qtil/tuple/Product.qll | 26 +++---- swift/src/qtil/Swift.qll | 4 +- swift/src/qtil/swift/ast/TwoOperands.qll | 2 +- swift/src/qtil/swift/format/QlFormat.qll | 3 +- .../qtil/swift/graph/CustomPathProblem.qll | 3 +- swift/test/qtil/swift/format/QlFormatTest.ql | 2 +- .../qtil/swift/graph/CustomPathProblemTest.ql | 4 +- test/qtil/ast/TwoOperandsTest.ql | 74 +++++++++++-------- test/qtil/fn/FnTest.ql | 2 +- test/qtil/fn/TpTest.ql | 13 ++-- test/qtil/fn/testlib.qll | 28 ++----- test/qtil/format/QLFormat/QLFormatTest.ql | 1 - test/qtil/graph/GraphPathSearchTest.ql | 2 +- test/qtil/list/CondensedListTest.ql | 1 - test/qtil/list/ListBuilderTest.ql | 20 ++--- test/qtil/list/fib.qll | 2 +- test/qtil/strings/Plural/PluralTest.ql | 72 +++++++++--------- test/qtil/testing/Qnit/QnitTestAllPass.ql | 11 ++- test/qtil/testing/Qnit/QnitTestSomeFail.ql | 46 ++++++------ 80 files changed, 315 insertions(+), 354 deletions(-) diff --git a/cpp/src/qtil/Cpp.qll b/cpp/src/qtil/Cpp.qll index fee2878..e0c5228 100644 --- a/cpp/src/qtil/Cpp.qll +++ b/cpp/src/qtil/Cpp.qll @@ -2,7 +2,7 @@ module Qtil { private import qtil.Qtil as Common // Importing qtil.Cpp should import all of Qtil. import Common::Qtil - import qtil.cpp.ast.TwoOperands + import qtil.cpp.ast.TwoOperands import qtil.cpp.format.QlFormat import qtil.cpp.graph.CustomPathProblem -} \ No newline at end of file +} diff --git a/cpp/src/qtil/cpp/ast/TwoOperands.qll b/cpp/src/qtil/cpp/ast/TwoOperands.qll index ef56037..cac7010 100644 --- a/cpp/src/qtil/cpp/ast/TwoOperands.qll +++ b/cpp/src/qtil/cpp/ast/TwoOperands.qll @@ -52,4 +52,4 @@ import qtil.parameterization.SignatureTypes module TwoOperands::Type BinOp> { private import qtil.ast.TwoOperands as Make import Make::TwoOperands -} \ No newline at end of file +} diff --git a/cpp/src/qtil/cpp/format/QlFormat.qll b/cpp/src/qtil/cpp/format/QlFormat.qll index a6c88fd..2b744a2 100644 --- a/cpp/src/qtil/cpp/format/QlFormat.qll +++ b/cpp/src/qtil/cpp/format/QlFormat.qll @@ -1,5 +1,4 @@ private import qtil.format.QLFormat private import cpp private import qtil.cpp.locations.Locatable - -import QlFormat \ No newline at end of file +import QlFormat diff --git a/cpp/src/qtil/cpp/graph/CustomPathProblem.qll b/cpp/src/qtil/cpp/graph/CustomPathProblem.qll index 5c5fefa..12b875b 100644 --- a/cpp/src/qtil/cpp/graph/CustomPathProblem.qll +++ b/cpp/src/qtil/cpp/graph/CustomPathProblem.qll @@ -1,6 +1,5 @@ private import qtil.locations.CustomPathProblem private import qtil.cpp.locations.Locatable private import cpp - // Import the C++ specific configuration for making custom path problems. -import PathProblem \ No newline at end of file +import PathProblem diff --git a/cpp/test/qtil/cpp/format/QlFormatTest.ql b/cpp/test/qtil/cpp/format/QlFormatTest.ql index e19dbc0..bfca262 100644 --- a/cpp/test/qtil/cpp/format/QlFormatTest.ql +++ b/cpp/test/qtil/cpp/format/QlFormatTest.ql @@ -12,4 +12,4 @@ predicate problem(Locatable elem, Template msg) { ) } -import Problem::Query \ No newline at end of file +import Problem::Query diff --git a/cpp/test/qtil/cpp/graph/CustomPathProblemTest.ql b/cpp/test/qtil/cpp/graph/CustomPathProblemTest.ql index 8ea3999..8cf1920 100644 --- a/cpp/test/qtil/cpp/graph/CustomPathProblemTest.ql +++ b/cpp/test/qtil/cpp/graph/CustomPathProblemTest.ql @@ -7,13 +7,9 @@ module CallGraphPathProblemConfig implements CustomPathProblemConfigSig { predicate start(Node n) { n.getName() = "start" } - predicate end(Node n) { - n.getName() = "end" - } + predicate end(Node n) { n.getName() = "end" } - predicate edge(Variable a, Variable b) { - a.getAnAssignedValue().(VariableAccess).getTarget() = b - } + predicate edge(Variable a, Variable b) { a.getAnAssignedValue().(VariableAccess).getTarget() = b } } import CustomPathProblem diff --git a/csharp/src/qtil/csharp/ast/TwoOperands.qll b/csharp/src/qtil/csharp/ast/TwoOperands.qll index f0dac42..c54cddb 100644 --- a/csharp/src/qtil/csharp/ast/TwoOperands.qll +++ b/csharp/src/qtil/csharp/ast/TwoOperands.qll @@ -52,4 +52,4 @@ import qtil.parameterization.SignatureTypes module TwoOperands::Type BinOp> { private import qtil.ast.TwoOperands as Make import Make::TwoOperands -} \ No newline at end of file +} diff --git a/csharp/src/qtil/csharp/format/QlFormat.qll b/csharp/src/qtil/csharp/format/QlFormat.qll index 783880f..c9ea1f6 100644 --- a/csharp/src/qtil/csharp/format/QlFormat.qll +++ b/csharp/src/qtil/csharp/format/QlFormat.qll @@ -1,5 +1,4 @@ private import qtil.format.QLFormat private import csharp private import qtil.csharp.locations.Locatable - -import QlFormat \ No newline at end of file +import QlFormat diff --git a/csharp/src/qtil/csharp/graph/CustomPathProblem.qll b/csharp/src/qtil/csharp/graph/CustomPathProblem.qll index 4dd6f49..0f279bb 100644 --- a/csharp/src/qtil/csharp/graph/CustomPathProblem.qll +++ b/csharp/src/qtil/csharp/graph/CustomPathProblem.qll @@ -1,6 +1,5 @@ private import qtil.locations.CustomPathProblem private import qtil.csharp.locations.Locatable private import csharp - // Import the C# specific configuration for making custom path problems. -import PathProblem \ No newline at end of file +import PathProblem diff --git a/csharp/test/qtil/csharp/format/QlFormatTest.ql b/csharp/test/qtil/csharp/format/QlFormatTest.ql index 4ebe591..5bf5b77 100644 --- a/csharp/test/qtil/csharp/format/QlFormatTest.ql +++ b/csharp/test/qtil/csharp/format/QlFormatTest.ql @@ -12,4 +12,4 @@ predicate problem(Element elem, Template msg) { ) } -import Problem::Query \ No newline at end of file +import Problem::Query diff --git a/csharp/test/qtil/csharp/graph/CustomPathProblemTest.ql b/csharp/test/qtil/csharp/graph/CustomPathProblemTest.ql index bcfccb3..92f7637 100644 --- a/csharp/test/qtil/csharp/graph/CustomPathProblemTest.ql +++ b/csharp/test/qtil/csharp/graph/CustomPathProblemTest.ql @@ -7,13 +7,9 @@ module CallGraphPathProblemConfig implements CustomPathProblemConfigSig { predicate start(Node n) { n.getName() = "start" } - predicate end(Node n) { - n.getName() = "end" - } + predicate end(Node n) { n.getName() = "end" } - predicate edge(Variable a, Variable b) { - a.getAnAssignedValue().(VariableAccess).getTarget() = b - } + predicate edge(Variable a, Variable b) { a.getAnAssignedValue().(VariableAccess).getTarget() = b } } import CustomPathProblem diff --git a/go/src/qtil/Go.qll b/go/src/qtil/Go.qll index e98f458..b924f6c 100644 --- a/go/src/qtil/Go.qll +++ b/go/src/qtil/Go.qll @@ -2,7 +2,7 @@ module Qtil { private import qtil.Qtil as Common // Importing qtil.Go should import all of Qtil. import Common::Qtil - import qtil.go.ast.TwoOperands + import qtil.go.ast.TwoOperands import qtil.go.format.QlFormat import qtil.go.graph.CustomPathProblem -} \ No newline at end of file +} diff --git a/go/src/qtil/go/ast/TwoOperands.qll b/go/src/qtil/go/ast/TwoOperands.qll index d4e3f68..b30fe53 100644 --- a/go/src/qtil/go/ast/TwoOperands.qll +++ b/go/src/qtil/go/ast/TwoOperands.qll @@ -52,4 +52,4 @@ import qtil.parameterization.SignatureTypes module TwoOperands::Type BinOp> { private import qtil.ast.TwoOperands as Make import Make::TwoOperands -} \ No newline at end of file +} diff --git a/go/src/qtil/go/format/QlFormat.qll b/go/src/qtil/go/format/QlFormat.qll index 40e16d7..1ea200c 100644 --- a/go/src/qtil/go/format/QlFormat.qll +++ b/go/src/qtil/go/format/QlFormat.qll @@ -1,5 +1,4 @@ private import qtil.format.QLFormat private import go private import qtil.go.locations.Locatable - -import QlFormat \ No newline at end of file +import QlFormat diff --git a/go/src/qtil/go/graph/CustomPathProblem.qll b/go/src/qtil/go/graph/CustomPathProblem.qll index 7fcaeec..94aa073 100644 --- a/go/src/qtil/go/graph/CustomPathProblem.qll +++ b/go/src/qtil/go/graph/CustomPathProblem.qll @@ -1,6 +1,5 @@ private import qtil.locations.CustomPathProblem private import qtil.go.locations.Locatable private import go - // Import the Go specific configuration for making custom path problems. -import PathProblem \ No newline at end of file +import PathProblem diff --git a/go/test/qtil/go/format/QlFormatTest.ql b/go/test/qtil/go/format/QlFormatTest.ql index 0291db0..be076cd 100644 --- a/go/test/qtil/go/format/QlFormatTest.ql +++ b/go/test/qtil/go/format/QlFormatTest.ql @@ -12,4 +12,4 @@ predicate problem(Locatable elem, Template msg) { ) } -import Problem::Query \ No newline at end of file +import Problem::Query diff --git a/go/test/qtil/go/graph/CustomPathProblemTest.ql b/go/test/qtil/go/graph/CustomPathProblemTest.ql index ec77b15..38f5972 100644 --- a/go/test/qtil/go/graph/CustomPathProblemTest.ql +++ b/go/test/qtil/go/graph/CustomPathProblemTest.ql @@ -7,13 +7,12 @@ module CallGraphPathProblemConfig implements CustomPathProblemConfigSig { predicate start(Node n) { n.getName() = "start" } - predicate end(Node n) { - n.getName() = "end" - } + predicate end(Node n) { n.getName() = "end" } predicate edge(Node a, Node b) { exists(Assignment assign | - assign.getLhs().(Name).getTarget().getDeclaration() = a and assign.getRhs().(Name).getTarget().getDeclaration() = b + assign.getLhs().(Name).getTarget().getDeclaration() = a and + assign.getRhs().(Name).getTarget().getDeclaration() = b ) } } diff --git a/java/src/qtil/Java.qll b/java/src/qtil/Java.qll index 5d933b2..31ef1dc 100644 --- a/java/src/qtil/Java.qll +++ b/java/src/qtil/Java.qll @@ -2,7 +2,7 @@ module Qtil { private import qtil.Qtil as Common // Importing qtil.Cpp should import all of Qtil. import Common::Qtil - import qtil.java.ast.TwoOperands + import qtil.java.ast.TwoOperands import qtil.java.format.QlFormat import qtil.java.graph.CustomPathProblem -} \ No newline at end of file +} diff --git a/java/src/qtil/java/ast/TwoOperands.qll b/java/src/qtil/java/ast/TwoOperands.qll index 6e32796..26c26c3 100644 --- a/java/src/qtil/java/ast/TwoOperands.qll +++ b/java/src/qtil/java/ast/TwoOperands.qll @@ -52,4 +52,4 @@ import qtil.parameterization.SignatureTypes module TwoOperands::Type BinOp> { private import qtil.ast.TwoOperands as Make import Make::TwoOperands -} \ No newline at end of file +} diff --git a/java/src/qtil/java/format/QlFormat.qll b/java/src/qtil/java/format/QlFormat.qll index 36f2eb3..3f76469 100644 --- a/java/src/qtil/java/format/QlFormat.qll +++ b/java/src/qtil/java/format/QlFormat.qll @@ -1,5 +1,4 @@ private import qtil.format.QLFormat private import java private import qtil.java.locations.Locatable - -import QlFormat \ No newline at end of file +import QlFormat diff --git a/java/src/qtil/java/graph/CustomPathProblem.qll b/java/src/qtil/java/graph/CustomPathProblem.qll index 11e07de..4a28377 100644 --- a/java/src/qtil/java/graph/CustomPathProblem.qll +++ b/java/src/qtil/java/graph/CustomPathProblem.qll @@ -1,6 +1,5 @@ private import qtil.locations.CustomPathProblem private import qtil.java.locations.Locatable private import java - // Import the Java specific configuration for making custom path problems. -import PathProblem \ No newline at end of file +import PathProblem diff --git a/java/test/qtil/java/format/QlFormatTest.ql b/java/test/qtil/java/format/QlFormatTest.ql index d351b69..5d1195c 100644 --- a/java/test/qtil/java/format/QlFormatTest.ql +++ b/java/test/qtil/java/format/QlFormatTest.ql @@ -12,4 +12,4 @@ predicate problem(Element elem, Template msg) { ) } -import Problem::Query \ No newline at end of file +import Problem::Query diff --git a/javascript/src/qtil/Javascript.qll b/javascript/src/qtil/Javascript.qll index b551188..489d559 100644 --- a/javascript/src/qtil/Javascript.qll +++ b/javascript/src/qtil/Javascript.qll @@ -2,7 +2,7 @@ module Qtil { private import qtil.Qtil as Common // Importing qtil.Javascript should import all of Qtil. import Common::Qtil - import qtil.javascript.ast.TwoOperands + import qtil.javascript.ast.TwoOperands import qtil.javascript.format.QlFormat import qtil.javascript.graph.CustomPathProblem -} \ No newline at end of file +} diff --git a/javascript/src/qtil/javascript/ast/TwoOperands.qll b/javascript/src/qtil/javascript/ast/TwoOperands.qll index 06713cc..f6d97e8 100644 --- a/javascript/src/qtil/javascript/ast/TwoOperands.qll +++ b/javascript/src/qtil/javascript/ast/TwoOperands.qll @@ -52,4 +52,4 @@ import qtil.parameterization.SignatureTypes module TwoOperands::Type BinOp> { private import qtil.ast.TwoOperands as Make import Make::TwoOperands -} \ No newline at end of file +} diff --git a/javascript/src/qtil/javascript/format/QlFormat.qll b/javascript/src/qtil/javascript/format/QlFormat.qll index cb7ad1f..76a9315 100644 --- a/javascript/src/qtil/javascript/format/QlFormat.qll +++ b/javascript/src/qtil/javascript/format/QlFormat.qll @@ -1,5 +1,4 @@ private import qtil.format.QLFormat private import javascript private import qtil.javascript.locations.Locatable - -import QlFormat \ No newline at end of file +import QlFormat diff --git a/javascript/src/qtil/javascript/graph/CustomPathProblem.qll b/javascript/src/qtil/javascript/graph/CustomPathProblem.qll index 3764c3a..126d9f1 100644 --- a/javascript/src/qtil/javascript/graph/CustomPathProblem.qll +++ b/javascript/src/qtil/javascript/graph/CustomPathProblem.qll @@ -1,6 +1,5 @@ private import qtil.locations.CustomPathProblem private import qtil.javascript.locations.Locatable private import javascript - // Import the javascript specific configuration for making custom path problems. -import PathProblem \ No newline at end of file +import PathProblem diff --git a/javascript/test/qtil/cpp/format/QlFormatTest.ql b/javascript/test/qtil/cpp/format/QlFormatTest.ql index d08ed66..e5602d5 100644 --- a/javascript/test/qtil/cpp/format/QlFormatTest.ql +++ b/javascript/test/qtil/cpp/format/QlFormatTest.ql @@ -12,4 +12,4 @@ predicate problem(Locatable elem, Template msg) { ) } -import Problem::Query \ No newline at end of file +import Problem::Query diff --git a/python/src/qtil/Python.qll b/python/src/qtil/Python.qll index a9e0ddc..e6fabcd 100644 --- a/python/src/qtil/Python.qll +++ b/python/src/qtil/Python.qll @@ -2,7 +2,7 @@ module Qtil { private import qtil.Qtil as Common // Importing qtil.Cpp should import all of Qtil. import Common::Qtil - import qtil.python.ast.TwoOperands + import qtil.python.ast.TwoOperands import qtil.python.format.QlFormat import qtil.python.graph.CustomPathProblem -} \ No newline at end of file +} diff --git a/python/src/qtil/python/ast/TwoOperands.qll b/python/src/qtil/python/ast/TwoOperands.qll index e562332..a9616ec 100644 --- a/python/src/qtil/python/ast/TwoOperands.qll +++ b/python/src/qtil/python/ast/TwoOperands.qll @@ -60,4 +60,4 @@ module TwoOperands::Type BinOp> { } import Make::TwoOperands -} \ No newline at end of file +} diff --git a/python/src/qtil/python/format/QlFormat.qll b/python/src/qtil/python/format/QlFormat.qll index 1626c41..4be97e3 100644 --- a/python/src/qtil/python/format/QlFormat.qll +++ b/python/src/qtil/python/format/QlFormat.qll @@ -1,5 +1,4 @@ private import qtil.format.QLFormat private import python private import qtil.python.locations.Locatable - -import QlFormat \ No newline at end of file +import QlFormat diff --git a/python/src/qtil/python/graph/CustomPathProblem.qll b/python/src/qtil/python/graph/CustomPathProblem.qll index 8ecbb26..ae51def 100644 --- a/python/src/qtil/python/graph/CustomPathProblem.qll +++ b/python/src/qtil/python/graph/CustomPathProblem.qll @@ -1,6 +1,5 @@ private import qtil.locations.CustomPathProblem private import qtil.python.locations.Locatable private import python - // Import the python specific configuration for making custom path problems. -import PathProblem \ No newline at end of file +import PathProblem diff --git a/python/test/qtil/python/format/QlFormatTest.ql b/python/test/qtil/python/format/QlFormatTest.ql index 2a530d4..c18153b 100644 --- a/python/test/qtil/python/format/QlFormatTest.ql +++ b/python/test/qtil/python/format/QlFormatTest.ql @@ -13,4 +13,4 @@ predicate problem(AstNode elem, Template msg) { ) } -import Problem::Query \ No newline at end of file +import Problem::Query diff --git a/ruby/src/qtil/Ruby.qll b/ruby/src/qtil/Ruby.qll index 6cae11c..c569289 100644 --- a/ruby/src/qtil/Ruby.qll +++ b/ruby/src/qtil/Ruby.qll @@ -2,7 +2,7 @@ module Qtil { private import qtil.Qtil as Common // Importing qtil.Ruby should import all of Qtil. import Common::Qtil - import qtil.ruby.ast.TwoOperands + import qtil.ruby.ast.TwoOperands import qtil.ruby.format.QlFormat import qtil.ruby.graph.CustomPathProblem -} \ No newline at end of file +} diff --git a/ruby/src/qtil/ruby/ast/TwoOperands.qll b/ruby/src/qtil/ruby/ast/TwoOperands.qll index 95276f7..26765ec 100644 --- a/ruby/src/qtil/ruby/ast/TwoOperands.qll +++ b/ruby/src/qtil/ruby/ast/TwoOperands.qll @@ -52,4 +52,4 @@ import qtil.parameterization.SignatureTypes module TwoOperands::Type BinOp> { private import qtil.ast.TwoOperands as Make import Make::TwoOperands -} \ No newline at end of file +} diff --git a/ruby/src/qtil/ruby/format/QlFormat.qll b/ruby/src/qtil/ruby/format/QlFormat.qll index d022f77..8b624e5 100644 --- a/ruby/src/qtil/ruby/format/QlFormat.qll +++ b/ruby/src/qtil/ruby/format/QlFormat.qll @@ -1,5 +1,4 @@ private import qtil.format.QLFormat private import ruby private import qtil.ruby.locations.Locatable - -import QlFormat \ No newline at end of file +import QlFormat diff --git a/ruby/src/qtil/ruby/graph/CustomPathProblem.qll b/ruby/src/qtil/ruby/graph/CustomPathProblem.qll index bce8dc9..5ae2759 100644 --- a/ruby/src/qtil/ruby/graph/CustomPathProblem.qll +++ b/ruby/src/qtil/ruby/graph/CustomPathProblem.qll @@ -1,6 +1,5 @@ private import qtil.locations.CustomPathProblem private import qtil.ruby.locations.Locatable private import ruby - // Import the Ruby specific configuration for making custom path problems. -import PathProblem \ No newline at end of file +import PathProblem diff --git a/ruby/test/qtil/cpp/format/QlFormatTest.ql b/ruby/test/qtil/cpp/format/QlFormatTest.ql index 9ee2f4a..42b41ae 100644 --- a/ruby/test/qtil/cpp/format/QlFormatTest.ql +++ b/ruby/test/qtil/cpp/format/QlFormatTest.ql @@ -13,4 +13,4 @@ predicate problem(Ast::AstNode elem, Template msg) { ) } -import Problem::Query \ No newline at end of file +import Problem::Query diff --git a/ruby/test/qtil/cpp/graph/CustomPathProblemTest.ql b/ruby/test/qtil/cpp/graph/CustomPathProblemTest.ql index 1512c06..4e85c9d 100644 --- a/ruby/test/qtil/cpp/graph/CustomPathProblemTest.ql +++ b/ruby/test/qtil/cpp/graph/CustomPathProblemTest.ql @@ -7,13 +7,12 @@ module CallGraphPathProblemConfig implements CustomPathProblemConfigSig { predicate start(Node n) { n.getVariable().getName() = "v_start" } - predicate end(Node n) { - n.getVariable().getName() = "v_end" - } + predicate end(Node n) { n.getVariable().getName() = "v_end" } predicate edge(Ast::VariableWriteAccess a, Ast::VariableWriteAccess b) { exists(Ast::VariableReadAccess mid, Ast::AssignExpr assign | - a = assign.getLeftOperand() and assign.getRightOperand() = mid and + a = assign.getLeftOperand() and + assign.getRightOperand() = mid and mid.getVariable() = b.getVariable() ) } @@ -23,4 +22,5 @@ import CustomPathProblem from Ast::VariableWriteAccess start, Ast::VariableWriteAccess end where problem(start, end) -select start, end, "Path from $@ to $@.", start.getVariable().getName(), start, end.getVariable().getName(), end +select start, end, "Path from $@ to $@.", start.getVariable().getName(), start, + end.getVariable().getName(), end diff --git a/src/qtil/Qtil.qll b/src/qtil/Qtil.qll index 3b9f5eb..3595e30 100644 --- a/src/qtil/Qtil.qll +++ b/src/qtil/Qtil.qll @@ -30,14 +30,12 @@ module Qtil { import qtil.tuple.Product import qtil.tuple.StringTuple import qtil.tuple.Tuple - // The following files are not imported, because the require configuration per language to be // useful. They should be imported in the language-specific modules, such as `qtil.cpp` or // `qtil.java`, etc: // import qtil.ast.TwoOperands // import qtil.locations.CustomPathProblem // import qtil.format.QLFormat - // Qnit is not imported by default. // import qtil.testing.Qnit -} \ No newline at end of file +} diff --git a/src/qtil/ast/TwoOperands.qll b/src/qtil/ast/TwoOperands.qll index e4735a2..2d1de64 100644 --- a/src/qtil/ast/TwoOperands.qll +++ b/src/qtil/ast/TwoOperands.qll @@ -136,7 +136,7 @@ module TwoOperands::HasOpe * approach is done to allow the CodeQL engine to perform optimizations by inlining which * would not be possible if the `Set` class was a `newtype` of all operand pairs, while * allowing that `someOperand()` and `otherOperand()` to consistent and different. - * + * * For an alternative, more minimal API see the `set` predicate. */ class Set extends Instance::Type { @@ -165,26 +165,26 @@ module TwoOperands::HasOpe /** * Get a set of operands for the given operation, ordered (a, b) or (b, a). - * + * * Never mix `getASet` calls without binding the result, e.g. * `...::getASet(e).someOperand().... and ...::getASet(e).otherOperand()....`, or else the * `getASet` predicate may hold for two different orders of the two operands. The consequence of * this is that `.someOperand()` and `otherOperand()` may refer to the same operand. Always bind * the result of this predicate to a singular instance, e.g. * `exists(TwoOperands::Set set | ... )`. - * + * * Example usage: * ```ql * predicate myBinaryTest(TwoOperands::Set set) { * set.someOperand().isInteger() and * set.otherOperand().isConstant() * } - * + * * from BinaryExpr e * where myBinaryTest(TwoOperands::getASet(e)) * select e, "found match" * ``` - * + * * For an alternative, more minimal API see the `set` predicate. */ Set getASet(HasOperands a) { result = a.getAnOperand() } diff --git a/src/qtil/fn/All.qll b/src/qtil/fn/All.qll index 4a04a9e..9e7500a 100644 --- a/src/qtil/fn/All.qll +++ b/src/qtil/fn/All.qll @@ -7,10 +7,11 @@ private import qtil.fn.Tp * * This is a wrapper around `Tp1`, a tuple predicate that represents a set of tuples with only one * element, where the element is any value of the type. - * + * * See `Tp1` for more details and the full API, which includes mapping and filtering etc. */ module All { private predicate baseTp(T t) { any() } + import Tp1 -} \ No newline at end of file +} diff --git a/src/qtil/fn/Fn.qll b/src/qtil/fn/Fn.qll index 5cc0bcc..a2f7f45 100644 --- a/src/qtil/fn/Fn.qll +++ b/src/qtil/fn/Fn.qll @@ -1 +1 @@ -import qtil.fn.generated.Fn \ No newline at end of file +import qtil.fn.generated.Fn diff --git a/src/qtil/fn/FnTypes.qll b/src/qtil/fn/FnTypes.qll index cfe96d5..d1a616e 100644 --- a/src/qtil/fn/FnTypes.qll +++ b/src/qtil/fn/FnTypes.qll @@ -5,7 +5,8 @@ * - `FnX` - a "Function predicate" with three unbound arguments and a result. * - `RelX` - a "Relation predicate" with three bound arguments and a finite result. * - `PropX` - a "Property predicate" with three unbound arguments and no result. - * + * * See documentation of the fn module for more details on what these types mean. */ -import qtil.fn.generated.Types \ No newline at end of file + +import qtil.fn.generated.Types diff --git a/src/qtil/fn/Ordering.qll b/src/qtil/fn/Ordering.qll index 1fc70f7..176bf70 100644 --- a/src/qtil/fn/Ordering.qll +++ b/src/qtil/fn/Ordering.qll @@ -1 +1 @@ -import qtil.fn.generated.Ordering \ No newline at end of file +import qtil.fn.generated.Ordering diff --git a/src/qtil/fn/ResultSet.qll b/src/qtil/fn/ResultSet.qll index 9121e24..5d2bcb7 100644 --- a/src/qtil/fn/ResultSet.qll +++ b/src/qtil/fn/ResultSet.qll @@ -7,10 +7,11 @@ private import qtil.fn.Tp * * This is a wrapper around `Tp1`, a tuple predicate that represents a set of tuples with only one * element, which is the result of the function. - * + * * See `Tp1` for more details and the full API, which includes mapping and filtering etc. */ module ResultSet::fn/0 baseFn> { private predicate baseTp(T t) { t = baseFn() } + import Tp1 -} \ No newline at end of file +} diff --git a/src/qtil/fn/Tp.qll b/src/qtil/fn/Tp.qll index 74859bb..7206092 100644 --- a/src/qtil/fn/Tp.qll +++ b/src/qtil/fn/Tp.qll @@ -1,4 +1,5 @@ /** * This module defines "tuple predicates." */ -import qtil.fn.generated.Tp \ No newline at end of file + +import qtil.fn.generated.Tp diff --git a/src/qtil/fn/TupleGet.qll b/src/qtil/fn/TupleGet.qll index e09f1b1..4befdbd 100644 --- a/src/qtil/fn/TupleGet.qll +++ b/src/qtil/fn/TupleGet.qll @@ -1,6 +1,7 @@ /** * A module that defines getters for tuples of various arities. - * + * * For example, `Tuple2Get::getFirst(1, "foo")` will yield the integer 1. */ -import qtil.fn.generated.TupleGet \ No newline at end of file + +import qtil.fn.generated.TupleGet diff --git a/src/qtil/graph/GraphPathSearch.qll b/src/qtil/graph/GraphPathSearch.qll index e8ac0fb..0fb3de1 100644 --- a/src/qtil/graph/GraphPathSearch.qll +++ b/src/qtil/graph/GraphPathSearch.qll @@ -1,23 +1,24 @@ /** * A module for efficiently finding paths in a directional graph using a performant pattern called * forward-reverse pruning. - * + * * This pattern is useful for efficiently finding connections between nodes in a directional graph. * In a first pass, it finds nodes reachable from the starting point. In the second pass, it finds * the subset of those nodes that can be reached from the end point. Together, these create a path * from start points to end points. - * + * * As with the other performance patterns in qtil, this module may be useful as is, or it may not * fit your needs exactly. CodeQL evaluation and performance is very complex. In that case, consider * this pattern as an example to create your own solution that fits your needs. */ + private import qtil.parameterization.SignatureTypes private import qtil.parameterization.Finalize /** * Implement this signature to define a graph, and a search for paths within that graph, using the * `GraphPathSearch` module. - * + * * ```ql * module MyConfig implements GraphPathSearchSig { * predicate start(Node n1) { ... } @@ -29,13 +30,13 @@ private import qtil.parameterization.Finalize signature module GraphPathSearchSig { /** * The nodes that begin the search of the graph. - * + * * Ultimately, only paths from a start node to an end node will be found by this module. - * + * * In most cases, this will ideally be a smaller set of nodes than the end nodes. However, if the * graph branches in one direction more than the other, a larger set which branches less may be * preferable. - * + * * The design of this predicate has a great effect in how well this performance pattern will * ultimately perform. */ @@ -43,10 +44,10 @@ signature module GraphPathSearchSig { /** * A directional edge from `n1` to `n2`. - * + * * This module will search for paths from `start` to `end` by looking following the direction of * these edges. - * + * * The design of this predicate has a great effect in how well this performance pattern will * ultimately perform. */ @@ -54,9 +55,9 @@ signature module GraphPathSearchSig { /** * The end nodes of the search. - * + * * Ultimately, only paths from a start node to an end node will be found by this module. - * + * * The design of this predicate has a great effect in how well this performance pattern will * ultimately perform. */ @@ -66,18 +67,18 @@ signature module GraphPathSearchSig { /** * A module that implements an efficient search for a path within a custom directional graph from a * set of start nodes to a set of end nodes. - * + * * To show discovered paths to users, see the module `CustomPathProblem` which uses this module as * its underlying search implementation. - * + * * This module uses a pattern called "forward reverse pruning" for efficiency. This pattern is * useful for reducing the search space when looking for paths in a directional graph. In a first * pass, it finds nodes reachable from the starting point. In the second pass, it finds the subset * of those nodes that can be reached from the end point. Together, these create a path from start * points to end points. - * + * * To use this module, provide an implementation of the `GraphPathSearchSig` signature as follows: - * + * * ```ql * module Config implements GraphPathSearchSig { * predicate start(Person p) { p.checkSomething() } @@ -85,31 +86,31 @@ signature module GraphPathSearchSig { * predicate end(Person p) { p.checkSomethingElse() } * } * ``` - * + * * The design of these predicate has a great effect in how well this performance pattern will * ultimately perform. - * + * * The resulting predicate `hasPath` should be a much more efficient search of connected start nodes * to end nodes than a naive search (which in CodeQL could easily be evaluated as either a full * graph search, or a search over the cross product of all nodes). - * + * * ```ql * from Person p1, Person p2 * // Fast graph path detection thanks to forward-reverse pruning. * where GraphPathSearch::hasPath(p1, p2) * select p1, p2 * ``` - * + * * The resulting module also exposes two classes: * - `ForwardNode`: All nodes reachable from the start nodes. * - `ReverseNode`: All forward nodes that reach end nodes. - * + * * These classes may be useful in addition to the `hasPath` predicate. */ module GraphPathSearch Config> { /** * The set of all nodes reachable from the start nodes (inclusive). - * + * * Note: this is fast to compute because it is essentially a unary predicate. */ class ForwardNode extends Final::Type { @@ -123,9 +124,9 @@ module GraphPathSearch Config> { /** * The set of all forward nodes that reach end nodes (inclusive). - * + * * These nodes are the nodes that exist along the path from start nodes to end nodes. - * + * * Note: this is fast to compute because it is essentially a unary predicate. */ class ReverseNode extends ForwardNode { @@ -149,14 +150,12 @@ module GraphPathSearch Config> { /** * All relevant edges in the graph which participate in a connection from a start to an end node. */ - predicate pathEdge(ReverseNode n1, ReverseNode n2) { - Config::edge(n1, n2) - } + predicate pathEdge(ReverseNode n1, ReverseNode n2) { Config::edge(n1, n2) } /** * A performant path search within a custom directed graph from a set of start nodes to a set of * end nodes. - * + * * This predicate is the main entry point for the forward-reverse pruning pattern. The design of * the config predicates has a great effect in how well this performance pattern will ultimately * perform. @@ -167,7 +166,7 @@ module GraphPathSearch Config> { * where GraphPathSearch::hasPath(p1, p2) * select p1, p2 * ``` - * + * * Note: this is fast to compute because limits the search space to nodes found by the fast unary * searches done to find `ForwardNode` and `ReverseNode`. */ diff --git a/src/qtil/inheritance/Finitize.qll b/src/qtil/inheritance/Finitize.qll index 1782ccb..7666f5f 100644 --- a/src/qtil/inheritance/Finitize.qll +++ b/src/qtil/inheritance/Finitize.qll @@ -5,7 +5,7 @@ private import qtil.parameterization.Finalize /** * A module to convert an infinite type to a finite type by constraining it to a finite set of * values. - * + * * The result of instantiating this module exposes a `Type` class that is the finite version of the * infinite input type, e.g. `Finitize::Type`. * @@ -19,7 +19,7 @@ private import qtil.parameterization.Finalize * result = str.toUpperCase() * } * ``` - * + * * Note that this module cannot strip `bindingset[this]` from the members of the given infinite type * without knowing the names and signatures. This isn't usually a problem, but can prevent the use * of some parameterized modules. This module does strip the `bindingset[this]` from the @@ -45,4 +45,4 @@ module Finitize::pred/1 constraint> { */ string toString() { result = super.toString() } } -} \ No newline at end of file +} diff --git a/src/qtil/inheritance/Instance.qll b/src/qtil/inheritance/Instance.qll index e8f9a61..7c6c5f1 100644 --- a/src/qtil/inheritance/Instance.qll +++ b/src/qtil/inheritance/Instance.qll @@ -1,60 +1,58 @@ private import qtil.parameterization.SignatureTypes /** - * A module to make it more convenient to use `instanceof` inheritance in QL, by providing a + * A module to make it more convenient to use `instanceof` inheritance in QL, by providing a * convenience cast member, and inheriting `toString()` from the instance type. - * + * * To use this module, instead of declaring `instanceof T`, declare `extend Instance::Type` and * then use the `inst()` member to access members on the base class `T`. - * + * * Example usage: * ```ql * class MyExpr extends Instance::Type { * predicate isConstant() { inst().isConstant() } * } - * + * * // is equivalent to: * class MyExpr2 instanceof Expr { * string toString() { result = this.(Expr).toString() } * predicate isConstant() {this.(Expr).isConstant() } * } * ``` - * + * * For using `instanceof` inheritance with infinite types, use the `InfInstance` module instead, as * additional bindingset declarations are required to support infinite types. */ module Instance { /** * A convenience base class that is an `instanceof` the type `T`. - * + * * This class inherits the `toString()` method from the instance type `T`, and provides a * convenience method `inst()` to cast `this` to the instance type `T`. */ final class Type instanceof T { /** * Convenience method to cast `this` to the instance type `T`. - * + * * Specified as `final` for performance and maintainability reasons. - **/ + */ final T inst() { result = this } - string toString() { - result = inst().toString() - } + string toString() { result = inst().toString() } } } /** * A version of the `Instance` module that works with infinite types. - * + * * See `Instance` for more details. - * + * * When using `instanceof` inheritance with finite types, prefer using the `Instance` module. */ module InfInstance { /** * A convenience base class that is an `instanceof` an infinite type `T`. - * + * * This class inherits the `toString()` method from the instance type `T`, and provides a * convenience method `inst()` to cast `this` to the instance type `T`. */ @@ -62,17 +60,16 @@ module InfInstance { final class Type instanceof T { /** * Convenience method to cast `this` to the infinite instance type `T`. - * + * * Specifies bindingsets to allow for two-way bindings, so that the underlying instance value * can be constrained to a finite set of values and vice versa. Specified as `final` for * performance and maintainability reasons. - **/ - bindingset[result] bindingset[this] + */ + bindingset[result] + bindingset[this] T inst() { result = this } bindingset[this] - string toString() { - result = inst().toString() - } + string toString() { result = inst().toString() } } -} \ No newline at end of file +} diff --git a/src/qtil/inheritance/UnderlyingString.qll b/src/qtil/inheritance/UnderlyingString.qll index 023a221..862c1f7 100644 --- a/src/qtil/inheritance/UnderlyingString.qll +++ b/src/qtil/inheritance/UnderlyingString.qll @@ -35,7 +35,7 @@ * * // Option 2: create a custom finite type backed by a string * class FiniteStringType extends UnderlyingString { - * + * * // Properly bind str() in the constructor: * FiniteStringType() { str() = ["a", "b", "c"] } * @@ -43,7 +43,7 @@ * string myMember() { result = str() + " is my method" } * } * ``` - * + * * At this point, the members can be used to produce almost any API through string operations. For * instance, a set of names could be represented as a comma-separated alphabetical list. See the * caution above about performance. @@ -52,15 +52,16 @@ bindingset[this] class UnderlyingString instanceof string { /** * Get the underlying string value backing this type. - * + * * Specifies bindingsets to allow for two-way bindings, so that the underlying string value can be * constrained to a finite set of values and vice versa. Specified as `final` for performance and * maintainability reasons. */ - bindingset[this] bindingset[result] + bindingset[result] + bindingset[this] final string str() { result = this } /** Default `toString()` implementation, to simply return the underlying string. */ bindingset[this] string toString() { result = this } -} \ No newline at end of file +} diff --git a/src/qtil/locations/NullLocation.qll b/src/qtil/locations/NullLocation.qll index 524596a..f0fc010 100644 --- a/src/qtil/locations/NullLocation.qll +++ b/src/qtil/locations/NullLocation.qll @@ -5,7 +5,7 @@ private import qtil.parameterization.Finalize /** * A class that represents a location that does not exist. - * + * * Satisfies the `LocationSig` interface, but does not have any location information. The CodeQL * engine will use an empty filename and line/column numbers of 0 when this class is selected as a * query result location. diff --git a/src/qtil/locations/OptionalLocation.qll b/src/qtil/locations/OptionalLocation.qll index dc12d24..6d0a8c1 100644 --- a/src/qtil/locations/OptionalLocation.qll +++ b/src/qtil/locations/OptionalLocation.qll @@ -66,7 +66,7 @@ module OptionalLocation { /** * Location info predicate so that CodeQL can use this class as a location. - * + * * Only holds if the location exists. If it does not exist, and this is selected as a query * location, then the CodeQL engine will use an empty filename and line/column numbers of 0. */ diff --git a/src/qtil/locations/StringLocation.qll b/src/qtil/locations/StringLocation.qll index efe5f8d..b0e5451 100644 --- a/src/qtil/locations/StringLocation.qll +++ b/src/qtil/locations/StringLocation.qll @@ -122,7 +122,7 @@ module FinitizeStringLocation::pred/1 locations> { /** * The finite class. - * + * * Note that we have to override getFilePath(), getStartLine(), etc. to ensure that the * `bindingset[this]` is removed, so that the class can be used as a location. */ diff --git a/src/qtil/parameterization/Finalize.qll b/src/qtil/parameterization/Finalize.qll index a2132c3..cd89c07 100644 --- a/src/qtil/parameterization/Finalize.qll +++ b/src/qtil/parameterization/Finalize.qll @@ -3,16 +3,16 @@ private import qtil.parameterization.SignatureTypes /** * A convenience module to create a final version of a type, for the purposes of extending it in a * parameterized module, without having to define a new final alias of that type. - * + * * ```ql * module MyModule<...> { * // Using this module: * class MyExpr extends Final::Type { ... } - * + * * // Ordinary behavior: * // Error: cannot extend types outside the current parameterized module * class MyExpr extends Expr { ... } - * + * * // Ordinary behavior: * // Workaround: define a new final alias of the type * class FinalExpr = Expr; @@ -23,4 +23,4 @@ private import qtil.parameterization.SignatureTypes module Final { /** The class to extend, i.e., `class MyExpr extends Final::Type {...}` */ final class Type = T; -} \ No newline at end of file +} diff --git a/src/qtil/parameterization/SignatureTypes.qll b/src/qtil/parameterization/SignatureTypes.qll index a25fcf2..2fd3e1f 100644 --- a/src/qtil/parameterization/SignatureTypes.qll +++ b/src/qtil/parameterization/SignatureTypes.qll @@ -1,10 +1,10 @@ /** * A module to declare any finite type as a signature type, without a separate declaration. - * + * * With this module, rather than writing `signature class ExprSig extends Expr;`, you can simply * declare a module `module MyModule::Type T> { ... }` to declare a parameterized * module that takes a type that extends `Expr` as a parameter. - * + * * To create an infinite signature type, use `InfSignature` instead. */ module Signature { @@ -13,11 +13,11 @@ module Signature { /** * A module to declare any infinite type as a signature type, without a separate declaration. - * + * * With this module, rather than writing `signature class MyInt extends int;` with a `bindingset`, * you can simply declare a module `module MyModule::Type T> { ... }` to declare * a * parameterized module that takes a type that extends `int` as a parameter. - * + * * To create a finite signature type, use `Signature` instead. */ module InfSignature { @@ -27,11 +27,11 @@ module InfSignature { /** * A common signature type that can be used to represent any finite type, including `newtype`s. - * + * * Cannot be used to represent infinite types, such as `int` or `string`, but can be used to * represent finite types such as any normal class or algebraic `newtype`. To support infinite * types in your module, use `InfiniteType` instead. - * + * * Note that `newtype`s do not have the member predicate `toString()`. If you need `toString()` in * your parameterization, you should use `FiniteStringableType` instead, and your module will no * longer support `newtype`s. @@ -41,12 +41,12 @@ signature class FiniteType; /** * A common signature type that can be used to represent any finite type, excluding `newtype`s, in * order to provide a `toString()` method. - * + * * Cannot be used to represent infinite types, such as `int` or `string`, and cannot represent * `newtype`s since those do not have a `toString()` member predicate, but can be used to represent * finite classes such as most normal classes. To support infinite types in your module, use * `InfiniteType` instead, and to support `newtype`s, use `FiniteType`. - * + * * If you do not need `toString()` in your parameterization, you should prefer to use `FiniteType` * over this class, so that your module will support `newtype`s as well as normal classes. */ @@ -57,12 +57,12 @@ signature class FiniteStringableType { /** * A common signature type that can be used to represent any possibly infinite type, including * `int` and `string`, as well as any normal class or algebraic `newtype`. - * + * * Generally, using this type and supporting infinite types will constrain options in your module * design. For this reason, it is often preferable to use one of the finite types `FiniteType` or * `FiniteStringableType` instead, unless you specifically need to support infinite types in your * module. - * + * * Note that `newtype`s do not have the member predicate `toString()`. If you need `toString()` in * your parameterization, you should use `InfiniteStringableType` instead, and your module will no * longer support `newtype`s. @@ -74,12 +74,12 @@ signature class InfiniteType; * A common signature type that can be used to represent any possibly infinite type, such as `int` * and `string` and normal classes, but excludes `newtype`s, in order to provide a `toString()` * method. - * + * * Generally, using this type and supporting infinite types will constrain options in your module * design. For this reason, it is often preferable to use one of the finite types `FiniteType` or * `FiniteStringableType` instead, unless you specifically need to support infinite types in your * module. - * + * * If you do not need `toString()` in your parameterization, you should prefer to use `InfiniteType` * over this class, so that your module will support `newtype`s as well as normal classes. */ @@ -92,9 +92,9 @@ signature class InfiniteStringableType { /** * A common signature type that can be used to represent any string type, including `string` and * classes that are instances of `string` via `instanceof` inheritance. - * + * * This type is useful for creating modules that assemble strings and cast them to a string-like * type, such as those that extend `UnderlyingString`. */ bindingset[this] -signature class StringlikeType instanceof string; \ No newline at end of file +signature class StringlikeType instanceof string; diff --git a/src/qtil/strings/FluentString.qll b/src/qtil/strings/FluentString.qll index 952faba..11fb2a4 100644 --- a/src/qtil/strings/FluentString.qll +++ b/src/qtil/strings/FluentString.qll @@ -1,8 +1,6 @@ - -bindingset[s] bindingset[result] -FluentString fluentString(string s) { - result = s -} +bindingset[result] +bindingset[s] +FluentString fluentString(string s) { result = s } class FluentString extends string { bindingset[this] diff --git a/src/qtil/strings/Join.qll b/src/qtil/strings/Join.qll index b8f7890..698dae8 100644 --- a/src/qtil/strings/Join.qll +++ b/src/qtil/strings/Join.qll @@ -1,16 +1,16 @@ /** * A module for joining strings with a separator, for example, `join(":", "a", "b") = "a:b"`. - * + * * This module is not designed to replace the `concat` aggregation in CodeQL, but may be useful in * rare cases where joining is required without aggregation. - * + * * There are join predicate for joining 2 to 8 parts, all named `join`. The first argument is always * the separator string, and the remaining arguments are the strings to be joined. */ /** * Use the first argument as a separator to join two strings. - * + * * This predicate is overloaded to allow for 2 to 8 non-separator arguments. */ bindingset[sep, v1, v2] @@ -18,7 +18,7 @@ string join(string sep, string v1, string v2) { result = v1 + sep + v2 } /** * Use the first argument as a separator to join three strings. - * + * * This predicate is overloaded to allow for 2 to 8 non-separator arguments. */ bindingset[sep, v1, v2, v3] @@ -26,7 +26,7 @@ string join(string sep, string v1, string v2, string v3) { result = v1 + sep + v /** * Use the first argument as a separator to join four strings. - * + * * This predicate is overloaded to allow for 2 to 8 non-separator arguments. */ bindingset[sep, v1, v2, v3, v4] @@ -36,7 +36,7 @@ string join(string sep, string v1, string v2, string v3, string v4) { /** * Use the first argument as a separator to join five strings. - * + * * This predicate is overloaded to allow for 2 to 8 non-separator arguments. */ bindingset[sep, v1, v2, v3, v4, v5] @@ -46,7 +46,7 @@ string join(string sep, string v1, string v2, string v3, string v4, string v5) { /** * Use the first argument as a separator to join six strings. - * + * * This predicate is overloaded to allow for 2 to 8 non-separator arguments. */ bindingset[sep, v1, v2, v3, v4, v5, v6] @@ -56,7 +56,7 @@ string join(string sep, string v1, string v2, string v3, string v4, string v5, s /** * Use the first argument as a separator to join seven strings. - * + * * This predicate is overloaded to allow for 2 to 8 non-separator arguments. */ bindingset[sep, v1, v2, v3, v4, v5, v6, v7] @@ -66,7 +66,7 @@ string join(string sep, string v1, string v2, string v3, string v4, string v5, s /** * Use the first argument as a separator to join eight strings. - * + * * This predicate is overloaded to allow for 2 to 8 non-separator arguments. */ bindingset[sep, v1, v2, v3, v4, v5, v6, v7, v8] @@ -74,4 +74,4 @@ string join( string sep, string v1, string v2, string v3, string v4, string v5, string v6, string v7, string v8 ) { result = v1 + sep + v2 + sep + v3 + sep + v4 + sep + v5 + sep + v6 + sep + v7 + sep + v8 -} \ No newline at end of file +} diff --git a/src/qtil/testing/Qnit.qll b/src/qtil/testing/Qnit.qll index 32d35c2..b2788fc 100644 --- a/src/qtil/testing/Qnit.qll +++ b/src/qtil/testing/Qnit.qll @@ -27,6 +27,7 @@ * Be careful in deviating from this pattern, but do so at your own risk, so long as `pass()` and * `fail()` hold as in the example above. */ + import qtil.testing.impl.Qnit import qtil.testing.impl.Test import qtil.testing.impl.Runner diff --git a/src/qtil/testing/impl/Qnit.qll b/src/qtil/testing/impl/Qnit.qll index 73ba284..c06bd7e 100644 --- a/src/qtil/testing/impl/Qnit.qll +++ b/src/qtil/testing/impl/Qnit.qll @@ -43,4 +43,4 @@ class Qnit extends UnderlyingString { bindingset[this] string getDescription() { result = str().regexpReplaceAll("^(FAILURE|PASS): ", "") } -} \ No newline at end of file +} diff --git a/src/qtil/tuple/Pair.qll b/src/qtil/tuple/Pair.qll index 7713b1c..f922fd6 100644 --- a/src/qtil/tuple/Pair.qll +++ b/src/qtil/tuple/Pair.qll @@ -24,8 +24,7 @@ private import qtil.parameterization.SignaturePredicates * Each tuple type exposes the `getFirst()` and `getSecond()` member predicates, which retrieves * the first and second values of the pair, respectively. */ -module Pair::pred/2 constraint> -{ +module Pair::pred/2 constraint> { private newtype TAll = TSome(A a, B b) { constraint(a, b) } class Pair extends TAll { diff --git a/src/qtil/tuple/Product.qll b/src/qtil/tuple/Product.qll index 32f353b..2f86bea 100644 --- a/src/qtil/tuple/Product.qll +++ b/src/qtil/tuple/Product.qll @@ -2,24 +2,24 @@ private import qtil.parameterization.SignatureTypes /** * A module that provides the product of values of type A and B. - * + * * *Caution*: Product types can have a large number of values and are not suitable for many use * cases. Carefully consider if using a `Pair` or `Tuple` type is more appropriate before using * this module. - * + * * In `qtil` parlance, a "Pair" is a specific set of two types, A and B, constrained by some * predicate, a "Tuple" has three or more types/values, and a "Product" is the combination of * types/values which are not constrained by a predicate. - * + * * To use this module, instantiate the module with a set of finite types. Infinite types are not * supportable. - * + * * ```ql * import qtil.tuple.Product - * + * * class ABProduct = Product2::Product; * ``` - * + * * Each product exposes the `getFirst()` and `getSecond()` member predicates, which retrieves * the first and second values of the product, respectively. */ @@ -27,16 +27,10 @@ module Product2 { private newtype TAll = TSome(A a, B b) class Product extends TAll { - A getFirst() { - this = TSome(result, _) - } + A getFirst() { this = TSome(result, _) } - B getSecond() { - this = TSome(_, result) - } + B getSecond() { this = TSome(_, result) } - string toString() { - result = getFirst().toString() + ", " + getSecond().toString() - } + string toString() { result = getFirst().toString() + ", " + getSecond().toString() } } -} \ No newline at end of file +} diff --git a/swift/src/qtil/Swift.qll b/swift/src/qtil/Swift.qll index 591572f..422d3c5 100644 --- a/swift/src/qtil/Swift.qll +++ b/swift/src/qtil/Swift.qll @@ -2,7 +2,7 @@ module Qtil { private import qtil.Qtil as Common // Importing qtil.Swift should import all of Qtil. import Common::Qtil - import qtil.swift.ast.TwoOperands + import qtil.swift.ast.TwoOperands import qtil.swift.format.QlFormat import qtil.swift.graph.CustomPathProblem -} \ No newline at end of file +} diff --git a/swift/src/qtil/swift/ast/TwoOperands.qll b/swift/src/qtil/swift/ast/TwoOperands.qll index 34b6461..ebc8f33 100644 --- a/swift/src/qtil/swift/ast/TwoOperands.qll +++ b/swift/src/qtil/swift/ast/TwoOperands.qll @@ -52,4 +52,4 @@ import qtil.parameterization.SignatureTypes module TwoOperands::Type BinOp> { private import qtil.ast.TwoOperands as Make import Make::TwoOperands -} \ No newline at end of file +} diff --git a/swift/src/qtil/swift/format/QlFormat.qll b/swift/src/qtil/swift/format/QlFormat.qll index 0d9835c..36f1337 100644 --- a/swift/src/qtil/swift/format/QlFormat.qll +++ b/swift/src/qtil/swift/format/QlFormat.qll @@ -1,5 +1,4 @@ private import qtil.format.QLFormat private import swift private import qtil.swift.locations.Locatable - -import QlFormat \ No newline at end of file +import QlFormat diff --git a/swift/src/qtil/swift/graph/CustomPathProblem.qll b/swift/src/qtil/swift/graph/CustomPathProblem.qll index efeb260..c7b1102 100644 --- a/swift/src/qtil/swift/graph/CustomPathProblem.qll +++ b/swift/src/qtil/swift/graph/CustomPathProblem.qll @@ -1,6 +1,5 @@ private import qtil.locations.CustomPathProblem private import qtil.swift.locations.Locatable private import swift - // Import the swift specific configuration for making custom path problems. -import PathProblem \ No newline at end of file +import PathProblem diff --git a/swift/test/qtil/swift/format/QlFormatTest.ql b/swift/test/qtil/swift/format/QlFormatTest.ql index 4e20bff..c00c871 100644 --- a/swift/test/qtil/swift/format/QlFormatTest.ql +++ b/swift/test/qtil/swift/format/QlFormatTest.ql @@ -12,4 +12,4 @@ predicate problem(Locatable elem, Template msg) { ) } -import Problem::Query \ No newline at end of file +import Problem::Query diff --git a/swift/test/qtil/swift/graph/CustomPathProblemTest.ql b/swift/test/qtil/swift/graph/CustomPathProblemTest.ql index 18fa27b..033c349 100644 --- a/swift/test/qtil/swift/graph/CustomPathProblemTest.ql +++ b/swift/test/qtil/swift/graph/CustomPathProblemTest.ql @@ -7,9 +7,7 @@ module CallGraphPathProblemConfig implements CustomPathProblemConfigSig { predicate start(Node n) { n.getName() = "start" } - predicate end(Node n) { - n.getName() = "end" - } + predicate end(Node n) { n.getName() = "end" } predicate edge(VarDecl a, VarDecl b) { exists(AssignExpr assign | diff --git a/test/qtil/ast/TwoOperandsTest.ql b/test/qtil/ast/TwoOperandsTest.ql index 4e80996..6987d2a 100644 --- a/test/qtil/ast/TwoOperandsTest.ql +++ b/test/qtil/ast/TwoOperandsTest.ql @@ -2,6 +2,7 @@ import cpp as cpp import qtil.testing.Qnit signature class BinaryOperationSig extends cpp::BinaryOperation; + module TwoOperands { private import qtil.ast.TwoOperands as Make import Make::TwoOperands @@ -9,10 +10,11 @@ module TwoOperands { class FiveMatchesClassApiTest extends Test, Case { override predicate run(Qnit test) { - if count(TwoOperands::Set set | - set.someOperand().isConstant() and - set.otherOperand().getType() instanceof cpp::IntType - ) = 5 + if + count(TwoOperands::Set set | + set.someOperand().isConstant() and + set.otherOperand().getType() instanceof cpp::IntType + ) = 5 then test.pass("Correct number of matches with class API") else test.fail("Incorrect number of matches with class API") } @@ -20,10 +22,12 @@ class FiveMatchesClassApiTest extends Test, Case { class FiveMatchesPredicateApiTest extends Test, Case { override predicate run(Qnit test) { - if count(cpp::AddExpr op, cpp::Expr one, cpp::Expr another | - TwoOperands::set(op, one, another) and - one.isConstant() and another.getType() instanceof cpp::IntType - ) = 5 + if + count(cpp::AddExpr op, cpp::Expr one, cpp::Expr another | + TwoOperands::set(op, one, another) and + one.isConstant() and + another.getType() instanceof cpp::IntType + ) = 5 then test.pass("Correct number of matches with predicate API") else test.fail("Incorrect number of matches with predicate API") } @@ -31,10 +35,12 @@ class FiveMatchesPredicateApiTest extends Test, Case { class TestOperandAllOperandsAreChildrenPredicateAPI extends Test, Case { override predicate run(Qnit test) { - if forall(cpp::AddExpr op, cpp::Expr one, cpp::Expr another | - TwoOperands::set(op, one, another) - | one = op.getAnOperand() and another = op.getAnOperand() - ) + if + forall(cpp::AddExpr op, cpp::Expr one, cpp::Expr another | + TwoOperands::set(op, one, another) + | + one = op.getAnOperand() and another = op.getAnOperand() + ) then test.pass("All operands are children in predicate API") else test.fail("Not all operands are children in predicate API") } @@ -42,10 +48,11 @@ class TestOperandAllOperandsAreChildrenPredicateAPI extends Test, Case { class TestOperandAllOperandsAreChildrenClassAPI extends Test, Case { override predicate run(Qnit test) { - if forall(TwoOperands::Set set | any() | - set.someOperand() = set.getOperation().getAnOperand() and - set.otherOperand() = set.getOperation().getAnOperand() - ) + if + forall(TwoOperands::Set set | any() | + set.someOperand() = set.getOperation().getAnOperand() and + set.otherOperand() = set.getOperation().getAnOperand() + ) then test.pass("All operands are children in class API") else test.fail("Not all operands are children in class API") } @@ -53,14 +60,16 @@ class TestOperandAllOperandsAreChildrenClassAPI extends Test, Case { class TestNoMissingOperands extends Test, Case { override predicate run(Qnit test) { - if forall(cpp::AddExpr op, cpp::Expr one, cpp::Expr another | - op.getAnOperand() = one and op.getAnOperand() = another and not one = another | - TwoOperands::set(op, one, another) and - exists(TwoOperands::Set set | - set.someOperand() = op.getAnOperand() and - set.otherOperand() = op.getAnOperand() + if + forall(cpp::AddExpr op, cpp::Expr one, cpp::Expr another | + op.getAnOperand() = one and op.getAnOperand() = another and not one = another + | + TwoOperands::set(op, one, another) and + exists(TwoOperands::Set set | + set.someOperand() = op.getAnOperand() and + set.otherOperand() = op.getAnOperand() + ) ) - ) then test.pass("No missing operands") else test.fail("Missing operands") } @@ -68,10 +77,12 @@ class TestNoMissingOperands extends Test, Case { class TestNoOperandsOverlapPredicateAPI extends Test, Case { override predicate run(Qnit test) { - if forall(cpp::AddExpr op, cpp::Expr one, cpp::Expr another | - TwoOperands::set(op, one, another) | - not one = another - ) + if + forall(cpp::AddExpr op, cpp::Expr one, cpp::Expr another | + TwoOperands::set(op, one, another) + | + not one = another + ) then test.pass("No operands overlap in predicate API") else test.fail("Operands overlap in predicate API") } @@ -79,10 +90,11 @@ class TestNoOperandsOverlapPredicateAPI extends Test, Case { class TestNoOperandsOverlapClassAPI extends Test, Case { override predicate run(Qnit test) { - if forall(TwoOperands::Set set | any() | - not set.someOperand() = set.otherOperand() - ) + if + forall(TwoOperands::Set set | any() | + not set.someOperand() = set.otherOperand() + ) then test.pass("No operands overlap in class API") else test.fail("Operands overlap in class API") } -} \ No newline at end of file +} diff --git a/test/qtil/fn/FnTest.ql b/test/qtil/fn/FnTest.ql index e67324e..5137b21 100644 --- a/test/qtil/fn/FnTest.ql +++ b/test/qtil/fn/FnTest.ql @@ -94,4 +94,4 @@ class TestToRelation extends Test, Case { then test.pass("ToRelation working correctly") else test.fail("ToRelation not working correctly") } -} \ No newline at end of file +} diff --git a/test/qtil/fn/TpTest.ql b/test/qtil/fn/TpTest.ql index 45547d9..4e4d1dd 100644 --- a/test/qtil/fn/TpTest.ql +++ b/test/qtil/fn/TpTest.ql @@ -170,9 +170,11 @@ class TestMapRelateFirst extends Test, Case { class TestMapRelateSecond extends Test, Case { override predicate run(Qnit test) { if - count(Tp2::MapRelateSecond::find()) = 5 and + count(Tp2::MapRelateSecond::find()) = + 5 and Tp2::MapRelateSecond::find() = "Marie" and - Tp2::MapRelateSecond::find() = "Albert" and + Tp2::MapRelateSecond::find() = + "Albert" and Tp2::MapRelateSecond::find() = "Ada" and Tp2::MapRelateSecond::find() = "Alan" and Tp2::MapRelateSecond::find() = "Grace" @@ -288,8 +290,8 @@ class TestExtendMapSecond extends Test, Case { ) = 5 and Tp2::ExtendMapSecond::tp("Marie", "Curie", "CURIE") and - Tp2::ExtendMapSecond::tp("Albert", "Einstein", - "EINSTEIN") and + Tp2::ExtendMapSecond::tp("Albert", + "Einstein", "EINSTEIN") and Tp2::ExtendMapSecond::tp("Ada", "Lovelace", "LOVELACE") and Tp2::ExtendMapSecond::tp("Alan", "Turing", @@ -300,6 +302,7 @@ class TestExtendMapSecond extends Test, Case { else test.fail("ExtendMapSecond gets incorrect names") } } + class TestExtendRelateSecond extends Test, Case { override predicate run(Qnit test) { if @@ -319,4 +322,4 @@ class TestExtendRelateSecond extends Test, Case { then test.pass("ExtendRelateSecond gets all names") else test.fail("ExtendRelateSecond gets incorrect names") } -} \ No newline at end of file +} diff --git a/test/qtil/fn/testlib.qll b/test/qtil/fn/testlib.qll index 906af33..9bdb848 100644 --- a/test/qtil/fn/testlib.qll +++ b/test/qtil/fn/testlib.qll @@ -25,27 +25,19 @@ bindingset[i] predicate isOdd(int i) { i % 2 = 1 } bindingset[str] -string toUpperCase(string str) { - result = str.toUpperCase() -} +string toUpperCase(string str) { result = str.toUpperCase() } bindingset[a, b] -string spaceJoin(string a, string b) { - result = a + " " + b -} +string spaceJoin(string a, string b) { result = a + " " + b } -bindingset[a, b] -string rspaceJoin(string a, string b) { - result = b + " " + a -} +bindingset[a, b] +string rspaceJoin(string a, string b) { result = b + " " + a } bindingset[i] string stringifyInt(int i) { result = i.toString() } bindingset[str] -predicate isOneChar(string str) { - str.length() = 1 -} +predicate isOneChar(string str) { str.length() = 1 } predicate person(string firstName, string lastName) { firstName = "Marie" and lastName = "Curie" @@ -70,14 +62,10 @@ string getInitials(string firstName, string lastName) { result = firstName.charAt(0).toUpperCase() + lastName.charAt(0).toUpperCase() } -string mightHaveLastName(string firstName) { - person(firstName, result) -} +string mightHaveLastName(string firstName) { person(firstName, result) } -string mightHaveFirstName(string lastName) { - person(result, lastName) -} +string mightHaveFirstName(string lastName) { person(result, lastName) } predicate personInitialed(string firstName, string lastName, string initials) { getInitials(firstName, lastName) = initials -} \ No newline at end of file +} diff --git a/test/qtil/format/QLFormat/QLFormatTest.ql b/test/qtil/format/QLFormat/QLFormatTest.ql index b84150e..1ecf07f 100644 --- a/test/qtil/format/QLFormat/QLFormatTest.ql +++ b/test/qtil/format/QLFormat/QLFormatTest.ql @@ -32,7 +32,6 @@ predicate problem(Locatable elem, Template msg) { } import Problem::Query - //from VariableDeclarationEntry var, Expr initializer //where //initializer = var.getDeclaration().getInitializer().getExpr() diff --git a/test/qtil/graph/GraphPathSearchTest.ql b/test/qtil/graph/GraphPathSearchTest.ql index 517d98f..10057fa 100644 --- a/test/qtil/graph/GraphPathSearchTest.ql +++ b/test/qtil/graph/GraphPathSearchTest.ql @@ -108,4 +108,4 @@ class TestGrandpaToBartReverseNodesDoNotContain extends Test, Case { then test.fail("Some unexpected reverse nodes from Grandpa exist") else test.pass("No reverse nodes from Grandpa exist that shouldn't") } -} \ No newline at end of file +} diff --git a/test/qtil/list/CondensedListTest.ql b/test/qtil/list/CondensedListTest.ql index 01e260b..2d8527e 100644 --- a/test/qtil/list/CondensedListTest.ql +++ b/test/qtil/list/CondensedListTest.ql @@ -1,7 +1,6 @@ import qtil.list.CondensedList import qtil.testing.Qnit import fib - import CondenseList::Global import CondenseList::GroupBy as Grouped diff --git a/test/qtil/list/ListBuilderTest.ql b/test/qtil/list/ListBuilderTest.ql index 8ed936c..4fec8e6 100644 --- a/test/qtil/list/ListBuilderTest.ql +++ b/test/qtil/list/ListBuilderTest.ql @@ -20,10 +20,8 @@ class TestBasicListBuilder extends Test, Case { ListBuilder::of6("a", "b", "c", "d", "e", "f") = "a:b:c:d:e:f" and ListBuilder::of7("a", "b", "c", "d", "e", "f", "g") = "a,b,c,d,e,f,g" and ListBuilder::of7("a", "b", "c", "d", "e", "f", "g") = "a:b:c:d:e:f:g" and - ListBuilder::of8("a", "b", "c", "d", "e", "f", "g", "h") = - "a,b,c,d,e,f,g,h" and - ListBuilder::of8("a", "b", "c", "d", "e", "f", "g", "h") = - "a:b:c:d:e:f:g:h" + ListBuilder::of8("a", "b", "c", "d", "e", "f", "g", "h") = "a,b,c,d,e,f,g,h" and + ListBuilder::of8("a", "b", "c", "d", "e", "f", "g", "h") = "a:b:c:d:e:f:g:h" then test.pass("Basic list builder works") else test.fail("Basic list builder does not work") } @@ -60,10 +58,10 @@ class TestTypedListBuilder extends Test, Case { .isEqualTo("a,b,c,d,e,f,g") and TypedListBuilder::of7("a", "b", "c", "d", "e", "f", "g") .isEqualTo("a:b:c:d:e:f:g") and - TypedListBuilder::of8("a", "b", "c", "d", "e", "f", - "g", "h").isEqualTo("a,b,c,d,e,f,g,h") and - TypedListBuilder::of8("a", "b", "c", "d", "e", "f", - "g", "h").isEqualTo("a:b:c:d:e:f:g:h") + TypedListBuilder::of8("a", "b", "c", "d", "e", "f", "g", + "h").isEqualTo("a,b,c,d,e,f,g,h") and + TypedListBuilder::of8("a", "b", "c", "d", "e", "f", "g", + "h").isEqualTo("a:b:c:d:e:f:g:h") then test.pass("Typed list builder works") else test.fail("Typed list builder does not work") } @@ -91,10 +89,8 @@ class TestListBuilderOf extends Test, Case { ListBuilderOf::of5(1, 2, 3, 4, 5) = "1:2:3:4:5" and ListBuilderOf::of6(1, 2, 3, 4, 5, 6) = "1,2,3,4,5,6" and ListBuilderOf::of6(1, 2, 3, 4, 5, 6) = "1:2:3:4:5:6" and - ListBuilderOf::of7(1, 2, 3, 4, 5, 6, 7) = - "1,2,3,4,5,6,7" and - ListBuilderOf::of7(1, 2, 3, 4, 5, 6, 7) = - "1:2:3:4:5:6:7" and + ListBuilderOf::of7(1, 2, 3, 4, 5, 6, 7) = "1,2,3,4,5,6,7" and + ListBuilderOf::of7(1, 2, 3, 4, 5, 6, 7) = "1:2:3:4:5:6:7" and ListBuilderOf::of8(1, 2, 3, 4, 5, 6, 7, 8) = "1,2,3,4,5,6,7,8" and ListBuilderOf::of8(1, 2, 3, 4, 5, 6, 7, 8) = diff --git a/test/qtil/list/fib.qll b/test/qtil/list/fib.qll index 611323b..1b49f83 100644 --- a/test/qtil/list/fib.qll +++ b/test/qtil/list/fib.qll @@ -27,4 +27,4 @@ TEvenOrOdd evenOrOdd(Fib i) { i % 2 = 0 and result = TEven() or i % 2 = 1 and result = TOdd() -} \ No newline at end of file +} diff --git a/test/qtil/strings/Plural/PluralTest.ql b/test/qtil/strings/Plural/PluralTest.ql index 9253078..12d2bc4 100644 --- a/test/qtil/strings/Plural/PluralTest.ql +++ b/test/qtil/strings/Plural/PluralTest.ql @@ -2,57 +2,57 @@ import qtil.strings.Plural import qtil.testing.Qnit class TestBasePlural extends Test, Case { - override predicate run(Qnit test) { - if plural("apple") = "apples" - then test.pass("Basic pluralization works") - else test.fail("Basic pluralization doesn't work") - } + override predicate run(Qnit test) { + if plural("apple") = "apples" + then test.pass("Basic pluralization works") + else test.fail("Basic pluralization doesn't work") + } } class TestPluralZero extends Test, Case { - override predicate run(Qnit test) { - if plural("apple", 0) = "apples" - then test.pass("Pluralization with zero works") - else test.fail("Pluralization with zero doesn't work") - } + override predicate run(Qnit test) { + if plural("apple", 0) = "apples" + then test.pass("Pluralization with zero works") + else test.fail("Pluralization with zero doesn't work") + } } class TestPluralOne extends Test, Case { - override predicate run(Qnit test) { - if plural("apple", 1) = "apple" - then test.pass("Pluralization with one works") - else test.fail("Pluralization with one doesn't work") - } + override predicate run(Qnit test) { + if plural("apple", 1) = "apple" + then test.pass("Pluralization with one works") + else test.fail("Pluralization with one doesn't work") + } } class TestPluralNegativeOne extends Test, Case { - override predicate run(Qnit test) { - if plural("apple", -1) = "apples" - then test.pass("Pluralization with negative one works") - else test.fail("Pluralization with negative one doesn't work") - } + override predicate run(Qnit test) { + if plural("apple", -1) = "apples" + then test.pass("Pluralization with negative one works") + else test.fail("Pluralization with negative one doesn't work") + } } class TestPluralMany extends Test, Case { - override predicate run(Qnit test) { - if plural("apple", [2..100]) = "apples" - then test.pass("Pluralization with two works") - else test.fail("Pluralization with two doesn't work") - } + override predicate run(Qnit test) { + if plural("apple", [2 .. 100]) = "apples" + then test.pass("Pluralization with two works") + else test.fail("Pluralization with two doesn't work") + } } class TestPluralWithCustomTerms extends Test, Case { - override predicate run(Qnit test) { - if plural("octopus", "octopi", 2) = "octopi" - then test.pass("Pluralization with custom terms works") - else test.fail("Pluralization with custom terms doesn't work") - } + override predicate run(Qnit test) { + if plural("octopus", "octopi", 2) = "octopi" + then test.pass("Pluralization with custom terms works") + else test.fail("Pluralization with custom terms doesn't work") + } } class TestPluralWithCustomTermsSingular extends Test, Case { - override predicate run(Qnit test) { - if plural("octopus", "octopi", 1) = "octopus" - then test.pass("Pluralization with custom terms singular works") - else test.fail("Pluralization with custom terms singular doesn't work") - } -} \ No newline at end of file + override predicate run(Qnit test) { + if plural("octopus", "octopi", 1) = "octopus" + then test.pass("Pluralization with custom terms singular works") + else test.fail("Pluralization with custom terms singular doesn't work") + } +} diff --git a/test/qtil/testing/Qnit/QnitTestAllPass.ql b/test/qtil/testing/Qnit/QnitTestAllPass.ql index c7e43f4..b5c28db 100644 --- a/test/qtil/testing/Qnit/QnitTestAllPass.ql +++ b/test/qtil/testing/Qnit/QnitTestAllPass.ql @@ -1,8 +1,7 @@ import qtil.testing.Qnit + class QnitTestPass extends Test, Case { - override predicate run(Qnit test) { - if (any()) - then test.pass("A test case can pass") - else test.fail("A test case can't pass") - } -} \ No newline at end of file + override predicate run(Qnit test) { + if any() then test.pass("A test case can pass") else test.fail("A test case can't pass") + } +} diff --git a/test/qtil/testing/Qnit/QnitTestSomeFail.ql b/test/qtil/testing/Qnit/QnitTestSomeFail.ql index d246fbc..303032b 100644 --- a/test/qtil/testing/Qnit/QnitTestSomeFail.ql +++ b/test/qtil/testing/Qnit/QnitTestSomeFail.ql @@ -1,35 +1,35 @@ import qtil.testing.Qnit class QnitTestPass extends Test, Case { - override predicate run(Qnit test) { - if (any()) - then test.pass("A test case can pass") - else test.fail("A test case can't pass") - } + override predicate run(Qnit test) { + if any() then test.pass("A test case can pass") else test.fail("A test case can't pass") + } } class QnitTestFail extends Test, Case { - override predicate run(Qnit test) { - if (none()) - then test.pass("This test should have failed") - else test.fail("This test is supposed to fail") - } + override predicate run(Qnit test) { + if none() + then test.pass("This test should have failed") + else test.fail("This test is supposed to fail") + } } class QnitTestComplexPass extends Test, Case { - predicate isEqualToOne(int i) { i = 1 } - override predicate run(Qnit test) { - if isEqualToOne(1) - then test.pass("A complex test case can pass") - else test.fail("A complex test case can't pass") - } + predicate isEqualToOne(int i) { i = 1 } + + override predicate run(Qnit test) { + if isEqualToOne(1) + then test.pass("A complex test case can pass") + else test.fail("A complex test case can't pass") + } } class QnitTestComplexFail extends Test, Case { - predicate isEqualToOne(int i) { i = 1 } - override predicate run(Qnit test) { - if isEqualToOne(2) - then test.pass("This complex test should have failed") - else test.fail("This complex test is supposed to fail") - } -} \ No newline at end of file + predicate isEqualToOne(int i) { i = 1 } + + override predicate run(Qnit test) { + if isEqualToOne(2) + then test.pass("This complex test should have failed") + else test.fail("This complex test is supposed to fail") + } +} From 3b4bf718a25ed9497014045354232069c7454c4b Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Wed, 4 Jun 2025 01:17:42 -0700 Subject: [PATCH 10/15] eighth try for CI/CD: don't skip the tests... --- .github/workflows/codeql-unit-tests.yaml | 9 --------- 1 file changed, 9 deletions(-) diff --git a/.github/workflows/codeql-unit-tests.yaml b/.github/workflows/codeql-unit-tests.yaml index 7068004..cd9e304 100644 --- a/.github/workflows/codeql-unit-tests.yaml +++ b/.github/workflows/codeql-unit-tests.yaml @@ -34,7 +34,6 @@ jobs: fi - name: Test Queries - if: steps.changes.outputs.src == 'true' env: RUNNER_TEMP: ${{ runner.temp }} shell: python @@ -87,7 +86,6 @@ jobs: file.close() - name: Upload test results - if: steps.changes.outputs.src == 'true' uses: actions/upload-artifact@v4 with: name: ${{ matrix.language }}-test-results @@ -95,13 +93,6 @@ jobs: ${{ runner.temp }}/${{ matrix.language }}/test_report_slice_*.json if-no-files-found: error - - name: Compile / Check Suites & Packs - if: steps.changes.outputs.src == 'true' - env: - GITHUB_TOKEN: ${{ github.token }} - run: | - ./.github/scripts/pr-suites-packs.sh ${{ github.event.number }} ${{ matrix.language }} - validate-test-results: name: Validate test results needs: compile-and-test From 45a8d3acb0c643fc6870585b40b75502e0f035dd Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Wed, 4 Jun 2025 01:24:08 -0700 Subject: [PATCH 11/15] Ninth try fixing CI/CD --- .github/workflows/codeql-unit-tests.yaml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql-unit-tests.yaml b/.github/workflows/codeql-unit-tests.yaml index cd9e304..795c749 100644 --- a/.github/workflows/codeql-unit-tests.yaml +++ b/.github/workflows/codeql-unit-tests.yaml @@ -28,10 +28,9 @@ jobs: - name: Pre-Compile Queries id: pre-compile-queries + if: ${{ matrix.language != 'common' }} run: | - if [ "${{ matrix.language }}" != "common" ]; then - ${{ github.workspace }}/codeql_home/codeql/codeql query compile --threads 0 ${{ matrix.language }} - fi + ${{ github.workspace }}/codeql_home/codeql/codeql query compile --threads 0 ${{ matrix.language }} - name: Test Queries env: From 39b36118466bac35e6da0d66134cff5bb32ce778 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Wed, 4 Jun 2025 01:24:56 -0700 Subject: [PATCH 12/15] Tenth try fix CI/CD --- .github/workflows/codeql-unit-tests.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/codeql-unit-tests.yaml b/.github/workflows/codeql-unit-tests.yaml index 795c749..1d09201 100644 --- a/.github/workflows/codeql-unit-tests.yaml +++ b/.github/workflows/codeql-unit-tests.yaml @@ -51,7 +51,7 @@ jobs: runner_temp = os.environ['RUNNER_TEMP'] - if ${{ matrix.language }} == 'common': + if '${{ matrix.language }}' == 'common': test_root = Path('${{ github.workspace }}', 'test') else: test_root = Path('${{ github.workspace }}', '${{ matrix.language }}', 'test') From bab6a6e1d8fac48f97763cdfd776330e4657f8fc Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Wed, 4 Jun 2025 01:31:47 -0700 Subject: [PATCH 13/15] Eleventh try fixing CI/CD --- .github/workflows/codeql-unit-tests.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/codeql-unit-tests.yaml b/.github/workflows/codeql-unit-tests.yaml index 1d09201..9e7f8e2 100644 --- a/.github/workflows/codeql-unit-tests.yaml +++ b/.github/workflows/codeql-unit-tests.yaml @@ -95,6 +95,7 @@ jobs: validate-test-results: name: Validate test results needs: compile-and-test + if: ${{ always() }} runs-on: ubuntu-latest steps: - name: Check if compile-and-test job failed to complete, if so fail From 4bbd96d8312c80d423e3dd150dfca5a243686242 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Wed, 4 Jun 2025 01:46:36 -0700 Subject: [PATCH 14/15] Twelfth try fixing CI/CD; install fewer packs per job --- .github/scripts/install-packs.py | 24 ++++++++++++++++-------- .github/workflows/codeql-unit-tests.yaml | 2 ++ 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/.github/scripts/install-packs.py b/.github/scripts/install-packs.py index 292375b..0788f88 100644 --- a/.github/scripts/install-packs.py +++ b/.github/scripts/install-packs.py @@ -15,9 +15,16 @@ def get_workspace_packs(root): return packs +def install_pack(pack_path, codeql_executable, mode): + # Run `codeql pack install` to install dependencies. + command = [codeql_executable, 'pack', 'install', '--allow-prerelease', '--mode', mode, pack_path] + print(f'Running `{" ".join(command)}`') + subprocess.check_call(command) + parser = argparse.ArgumentParser(description="Install CodeQL library pack dependencies.") parser.add_argument('--mode', required=False, choices=['use-lock', 'update', 'verify', 'no-lock'], default="use-lock", help="Installation mode, identical to the `--mode` argument to `codeql pack install`") parser.add_argument('--codeql', required=False, default='codeql', help="Path to the `codeql` executable.") +parser.add_argument('--language', required=False, help="Which language (or 'common') to install pack dependencies for.") args = parser.parse_args() # Find the root of the repo @@ -25,11 +32,12 @@ def get_workspace_packs(root): packs = get_workspace_packs(root) -# Find the CodeQL packs in the repo. This can also return packs outside of the repo, if those packs -# are installed in a sibling directory to the CLI. -for pack in packs: - pack_path = os.path.join(root, pack) - # Run `codeql pack install` to install dependencies. - command = [args.codeql, 'pack', 'install', '--allow-prerelease', '--mode', args.mode, pack_path] - print(f'Running `{" ".join(command)}`') - subprocess.check_call(command) +# Always install the qtil source pack, which is used by all languages. +install_pack(os.path.join(root, 'src'), args.codeql, args.mode) +if args.language == 'common': + # common means we want to run test/. + install_pack(os.path.join(root, 'test'), args.codeql, args.mode) +else: + # Otherwise, we need to install the language-specific src and test packs. + install_pack(os.path.join(root, args.language, 'src'), args.codeql, args.mode) + install_pack(os.path.join(root, args.language, 'test'), args.codeql, args.mode) \ No newline at end of file diff --git a/.github/workflows/codeql-unit-tests.yaml b/.github/workflows/codeql-unit-tests.yaml index 9e7f8e2..b8a0386 100644 --- a/.github/workflows/codeql-unit-tests.yaml +++ b/.github/workflows/codeql-unit-tests.yaml @@ -7,6 +7,7 @@ on: jobs: compile-and-test: + name: Compile and Test CodeQL Packs runs-on: ubuntu-latest strategy: @@ -25,6 +26,7 @@ jobs: uses: ./.github/actions/install-codeql-packs with: cli_path: ${{ github.workspace }}/codeql_home/codeql + language: ${{ matrix.language }} - name: Pre-Compile Queries id: pre-compile-queries From eaf3485fe07803c17dd6eb45e7ed0093d74bf80a Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Wed, 4 Jun 2025 01:49:57 -0700 Subject: [PATCH 15/15] Lucky thirteenth try fixing CI/CD; remove swift --- .github/actions/install-codeql-packs/action.yml | 8 +++++++- .github/workflows/codeql-unit-tests.yaml | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/.github/actions/install-codeql-packs/action.yml b/.github/actions/install-codeql-packs/action.yml index fbd2c8b..08f52ea 100644 --- a/.github/actions/install-codeql-packs/action.yml +++ b/.github/actions/install-codeql-packs/action.yml @@ -12,6 +12,12 @@ inputs: The `--mode` option to `codeql pack install`. required: true default: verify + + language: + description: | + The language of the CodeQL library pack to install. + required: false + default: common runs: using: composite @@ -22,4 +28,4 @@ runs: CODEQL_CLI: ${{ inputs.cli_path }} run: | PATH=$PATH:$CODEQL_CLI - python .github/scripts/install-packs.py --mode ${{ inputs.mode }} + python .github/scripts/install-packs.py --mode ${{ inputs.mode }} --language ${{ inputs.language }} diff --git a/.github/workflows/codeql-unit-tests.yaml b/.github/workflows/codeql-unit-tests.yaml index b8a0386..9a32b52 100644 --- a/.github/workflows/codeql-unit-tests.yaml +++ b/.github/workflows/codeql-unit-tests.yaml @@ -13,7 +13,7 @@ jobs: strategy: fail-fast: false matrix: - language: [ 'common', 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby', 'swift' ] + language: [ 'common', 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] steps: - uses: actions/checkout@v4