diff --git a/.github/workflows/swift-codegen.yml b/.github/workflows/swift-codegen.yml index d5d74af87c2..46a27709717 100644 --- a/.github/workflows/swift-codegen.yml +++ b/.github/workflows/swift-codegen.yml @@ -15,18 +15,22 @@ jobs: - uses: actions/checkout@v3 - uses: ./.github/actions/fetch-codeql - uses: bazelbuild/setup-bazelisk@v2 + - uses: actions/setup-python@v3 + - uses: pre-commit/action@v3.0.0 + name: Check that python code is properly formatted + with: + extra_args: autopep8 --all-files - name: Run unit tests run: | bazel test //swift/codegen/test --test_output=errors - - name: Check that QL generated code was checked in - run: | - bazel run //swift/codegen - git add swift - git diff --exit-code HEAD + - uses: pre-commit/action@v3.0.0 + name: Check that QL generated code was checked in + with: + extra_args: swift-codegen --all-files - name: Generate C++ files run: | - bazel run //swift/codegen:codegen -- --generate=trap,cpp --cpp-output=$PWD/swift-generated-headers + bazel run //swift/codegen:codegen -- --generate=trap,cpp --cpp-output=$PWD/swift-generated-cpp-files - uses: actions/upload-artifact@v3 with: - name: swift-generated-headers - path: swift-generated-headers/*.h + name: swift-generated-cpp-files + path: swift-generated-cpp-files/** diff --git a/.github/workflows/swift-integration-tests.yml b/.github/workflows/swift-integration-tests.yml new file mode 100644 index 00000000000..591ea2b12f7 --- /dev/null +++ b/.github/workflows/swift-integration-tests.yml @@ -0,0 +1,34 @@ +name: "Swift: Run Integration Tests" + +on: + pull_request: + paths: + - "swift/**" + - .github/workflows/swift-integration-tests.yml + - codeql-workspace.yml + branches: + - main +defaults: + run: + working-directory: swift + +jobs: + integration-tests: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: + - ubuntu-20.04 +# - macos-latest TODO + steps: + - uses: actions/checkout@v3 + - uses: ./.github/actions/fetch-codeql + - uses: bazelbuild/setup-bazelisk@v2 + - uses: actions/setup-python@v3 + - name: Build Swift extractor + run: | + bazel run //swift:create-extractor-pack + - name: Run integration tests + run: | + python integration-tests/runner.py diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 1b44de000fb..d51681aa65c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -15,6 +15,12 @@ repos: - id: clang-format files: ^swift/.*\.(h|c|cpp)$ + - repo: https://github.com/pre-commit/mirrors-autopep8 + rev: v1.6.0 + hooks: + - id: autopep8 + files: ^swift/codegen/.*\.py + - repo: local hooks: - id: codeql-format diff --git a/CODEOWNERS b/CODEOWNERS index da71d1ec5d8..1754d58af63 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -42,3 +42,4 @@ WORKSPACE.bazel @github/codeql-ci-reviewers /.github/workflows/js-ml-tests.yml @github/codeql-ml-powered-queries-reviewers /.github/workflows/ql-for-ql-* @github/codeql-ql-for-ql-reviewers /.github/workflows/ruby-* @github/codeql-ruby +/.github/workflows/swift-* @github/codeql-c diff --git a/config/identical-files.json b/config/identical-files.json index 77e39399cec..990ba49f033 100644 --- a/config/identical-files.json +++ b/config/identical-files.json @@ -453,11 +453,11 @@ "python/ql/src/Lexical/CommentedOutCodeReferences.inc.qhelp" ], "IDE Contextual Queries": [ - "cpp/ql/src/IDEContextual.qll", - "csharp/ql/src/IDEContextual.qll", - "java/ql/src/IDEContextual.qll", - "javascript/ql/src/IDEContextual.qll", - "python/ql/src/analysis/IDEContextual.qll" + "cpp/ql/lib/IDEContextual.qll", + "csharp/ql/lib/IDEContextual.qll", + "java/ql/lib/IDEContextual.qll", + "javascript/ql/lib/IDEContextual.qll", + "python/ql/lib/analysis/IDEContextual.qll" ], "SSA C#": [ "csharp/ql/lib/semmle/code/csharp/dataflow/internal/SsaImplCommon.qll", diff --git a/cpp/ql/lib/CHANGELOG.md b/cpp/ql/lib/CHANGELOG.md index 52dd2c7a843..c1cefbed8f9 100644 --- a/cpp/ql/lib/CHANGELOG.md +++ b/cpp/ql/lib/CHANGELOG.md @@ -1,3 +1,13 @@ +## 0.3.0 + +### Deprecated APIs + +* The `BarrierGuard` class has been deprecated. Such barriers and sanitizers can now instead be created using the new `BarrierGuard` parameterized module. + +### Bug Fixes + +* `UserType.getADeclarationEntry()` now yields all forward declarations when the user type is a `class`, `struct`, or `union`. + ## 0.2.3 ### New Features diff --git a/cpp/ql/src/IDEContextual.qll b/cpp/ql/lib/IDEContextual.qll similarity index 100% rename from cpp/ql/src/IDEContextual.qll rename to cpp/ql/lib/IDEContextual.qll diff --git a/cpp/ql/lib/change-notes/2022-05-30-braced-initializers.md b/cpp/ql/lib/change-notes/2022-05-30-braced-initializers.md deleted file mode 100644 index 8a31f06ab98..00000000000 --- a/cpp/ql/lib/change-notes/2022-05-30-braced-initializers.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: feature ---- -* An `isBraced` predicate was added to the `Initializer` class which holds when a C++ braced initializer was used in the initialization. diff --git a/cpp/ql/lib/change-notes/2022-06-22-class-declaration-entry-fix.md b/cpp/ql/lib/change-notes/2022-06-22-class-declaration-entry-fix.md deleted file mode 100644 index fb301705e79..00000000000 --- a/cpp/ql/lib/change-notes/2022-06-22-class-declaration-entry-fix.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: fix ---- -* `UserType.getADeclarationEntry()` now yields all forward declarations when the user type is a `class`, `struct`, or `union`. diff --git a/cpp/ql/lib/change-notes/released/0.3.0.md b/cpp/ql/lib/change-notes/released/0.3.0.md new file mode 100644 index 00000000000..8c45dc21817 --- /dev/null +++ b/cpp/ql/lib/change-notes/released/0.3.0.md @@ -0,0 +1,9 @@ +## 0.3.0 + +### Deprecated APIs + +* The `BarrierGuard` class has been deprecated. Such barriers and sanitizers can now instead be created using the new `BarrierGuard` parameterized module. + +### Bug Fixes + +* `UserType.getADeclarationEntry()` now yields all forward declarations when the user type is a `class`, `struct`, or `union`. diff --git a/cpp/ql/lib/codeql-pack.release.yml b/cpp/ql/lib/codeql-pack.release.yml index 0b605901b42..95f6e3a0ba6 100644 --- a/cpp/ql/lib/codeql-pack.release.yml +++ b/cpp/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.2.3 +lastReleaseVersion: 0.3.0 diff --git a/cpp/ql/src/definitions.qll b/cpp/ql/lib/definitions.qll similarity index 100% rename from cpp/ql/src/definitions.qll rename to cpp/ql/lib/definitions.qll diff --git a/cpp/ql/src/localDefinitions.ql b/cpp/ql/lib/localDefinitions.ql similarity index 100% rename from cpp/ql/src/localDefinitions.ql rename to cpp/ql/lib/localDefinitions.ql diff --git a/cpp/ql/src/localReferences.ql b/cpp/ql/lib/localReferences.ql similarity index 100% rename from cpp/ql/src/localReferences.ql rename to cpp/ql/lib/localReferences.ql diff --git a/cpp/ql/src/printAst.ql b/cpp/ql/lib/printAst.ql similarity index 100% rename from cpp/ql/src/printAst.ql rename to cpp/ql/lib/printAst.ql diff --git a/cpp/ql/lib/qlpack.yml b/cpp/ql/lib/qlpack.yml index 28cddcb3b00..a20077271d7 100644 --- a/cpp/ql/lib/qlpack.yml +++ b/cpp/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cpp-all -version: 0.3.0-dev +version: 0.3.1-dev groups: cpp dbscheme: semmlecode.cpp.dbscheme extractor: cpp diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll index 7b9e78d2c4b..a076f7a2e45 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll @@ -428,7 +428,7 @@ private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - simpleLocalFlowStepExt(n1, n2) and + simpleLocalFlowStepExt(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and stepFilter(node1, node2, config) ) or @@ -447,7 +447,7 @@ private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configurat exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - config.isAdditionalFlowStep(n1, n2) and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and stepFilter(node1, node2, config) ) @@ -466,7 +466,7 @@ private predicate additionalLocalStateStep( exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - config.isAdditionalFlowStep(n1, s1, n2, s2) and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), s1, pragma[only_bind_into](n2), s2) and getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and stepFilter(node1, node2, config) and not stateBarrier(node1, s1, config) and @@ -481,7 +481,7 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) { exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - jumpStepCached(n1, n2) and + jumpStepCached(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and stepFilter(node1, node2, config) and not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) @@ -494,7 +494,7 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - config.isAdditionalFlowStep(n1, n2) and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and stepFilter(node1, node2, config) and not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext @@ -507,7 +507,7 @@ private predicate additionalJumpStateStep( exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - config.isAdditionalFlowStep(n1, s1, n2, s2) and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), s1, pragma[only_bind_into](n2), s2) and getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and stepFilter(node1, node2, config) and not stateBarrier(node1, s1, config) and @@ -518,7 +518,7 @@ private predicate additionalJumpStateStep( pragma[nomagic] private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) { - readSet(node1.asNode(), c, node2.asNode()) and + readSet(pragma[only_bind_into](node1.asNode()), c, pragma[only_bind_into](node2.asNode())) and stepFilter(node1, node2, config) or exists(Node n | @@ -562,7 +562,8 @@ pragma[nomagic] private predicate store( NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config ) { - store(node1.asNode(), tc, node2.asNode(), contentType) and + store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()), + contentType) and read(_, tc.getContent(), _, config) and stepFilter(node1, node2, config) } diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll index 7b9e78d2c4b..a076f7a2e45 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll @@ -428,7 +428,7 @@ private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - simpleLocalFlowStepExt(n1, n2) and + simpleLocalFlowStepExt(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and stepFilter(node1, node2, config) ) or @@ -447,7 +447,7 @@ private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configurat exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - config.isAdditionalFlowStep(n1, n2) and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and stepFilter(node1, node2, config) ) @@ -466,7 +466,7 @@ private predicate additionalLocalStateStep( exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - config.isAdditionalFlowStep(n1, s1, n2, s2) and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), s1, pragma[only_bind_into](n2), s2) and getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and stepFilter(node1, node2, config) and not stateBarrier(node1, s1, config) and @@ -481,7 +481,7 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) { exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - jumpStepCached(n1, n2) and + jumpStepCached(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and stepFilter(node1, node2, config) and not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) @@ -494,7 +494,7 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - config.isAdditionalFlowStep(n1, n2) and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and stepFilter(node1, node2, config) and not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext @@ -507,7 +507,7 @@ private predicate additionalJumpStateStep( exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - config.isAdditionalFlowStep(n1, s1, n2, s2) and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), s1, pragma[only_bind_into](n2), s2) and getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and stepFilter(node1, node2, config) and not stateBarrier(node1, s1, config) and @@ -518,7 +518,7 @@ private predicate additionalJumpStateStep( pragma[nomagic] private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) { - readSet(node1.asNode(), c, node2.asNode()) and + readSet(pragma[only_bind_into](node1.asNode()), c, pragma[only_bind_into](node2.asNode())) and stepFilter(node1, node2, config) or exists(Node n | @@ -562,7 +562,8 @@ pragma[nomagic] private predicate store( NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config ) { - store(node1.asNode(), tc, node2.asNode(), contentType) and + store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()), + contentType) and read(_, tc.getContent(), _, config) and stepFilter(node1, node2, config) } diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll index 7b9e78d2c4b..a076f7a2e45 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll @@ -428,7 +428,7 @@ private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - simpleLocalFlowStepExt(n1, n2) and + simpleLocalFlowStepExt(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and stepFilter(node1, node2, config) ) or @@ -447,7 +447,7 @@ private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configurat exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - config.isAdditionalFlowStep(n1, n2) and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and stepFilter(node1, node2, config) ) @@ -466,7 +466,7 @@ private predicate additionalLocalStateStep( exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - config.isAdditionalFlowStep(n1, s1, n2, s2) and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), s1, pragma[only_bind_into](n2), s2) and getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and stepFilter(node1, node2, config) and not stateBarrier(node1, s1, config) and @@ -481,7 +481,7 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) { exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - jumpStepCached(n1, n2) and + jumpStepCached(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and stepFilter(node1, node2, config) and not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) @@ -494,7 +494,7 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - config.isAdditionalFlowStep(n1, n2) and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and stepFilter(node1, node2, config) and not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext @@ -507,7 +507,7 @@ private predicate additionalJumpStateStep( exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - config.isAdditionalFlowStep(n1, s1, n2, s2) and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), s1, pragma[only_bind_into](n2), s2) and getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and stepFilter(node1, node2, config) and not stateBarrier(node1, s1, config) and @@ -518,7 +518,7 @@ private predicate additionalJumpStateStep( pragma[nomagic] private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) { - readSet(node1.asNode(), c, node2.asNode()) and + readSet(pragma[only_bind_into](node1.asNode()), c, pragma[only_bind_into](node2.asNode())) and stepFilter(node1, node2, config) or exists(Node n | @@ -562,7 +562,8 @@ pragma[nomagic] private predicate store( NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config ) { - store(node1.asNode(), tc, node2.asNode(), contentType) and + store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()), + contentType) and read(_, tc.getContent(), _, config) and stepFilter(node1, node2, config) } diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll index 7b9e78d2c4b..a076f7a2e45 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll @@ -428,7 +428,7 @@ private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - simpleLocalFlowStepExt(n1, n2) and + simpleLocalFlowStepExt(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and stepFilter(node1, node2, config) ) or @@ -447,7 +447,7 @@ private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configurat exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - config.isAdditionalFlowStep(n1, n2) and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and stepFilter(node1, node2, config) ) @@ -466,7 +466,7 @@ private predicate additionalLocalStateStep( exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - config.isAdditionalFlowStep(n1, s1, n2, s2) and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), s1, pragma[only_bind_into](n2), s2) and getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and stepFilter(node1, node2, config) and not stateBarrier(node1, s1, config) and @@ -481,7 +481,7 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) { exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - jumpStepCached(n1, n2) and + jumpStepCached(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and stepFilter(node1, node2, config) and not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) @@ -494,7 +494,7 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - config.isAdditionalFlowStep(n1, n2) and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and stepFilter(node1, node2, config) and not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext @@ -507,7 +507,7 @@ private predicate additionalJumpStateStep( exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - config.isAdditionalFlowStep(n1, s1, n2, s2) and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), s1, pragma[only_bind_into](n2), s2) and getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and stepFilter(node1, node2, config) and not stateBarrier(node1, s1, config) and @@ -518,7 +518,7 @@ private predicate additionalJumpStateStep( pragma[nomagic] private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) { - readSet(node1.asNode(), c, node2.asNode()) and + readSet(pragma[only_bind_into](node1.asNode()), c, pragma[only_bind_into](node2.asNode())) and stepFilter(node1, node2, config) or exists(Node n | @@ -562,7 +562,8 @@ pragma[nomagic] private predicate store( NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config ) { - store(node1.asNode(), tc, node2.asNode(), contentType) and + store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()), + contentType) and read(_, tc.getContent(), _, config) and stepFilter(node1, node2, config) } diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll index 7b9e78d2c4b..a076f7a2e45 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll @@ -428,7 +428,7 @@ private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - simpleLocalFlowStepExt(n1, n2) and + simpleLocalFlowStepExt(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and stepFilter(node1, node2, config) ) or @@ -447,7 +447,7 @@ private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configurat exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - config.isAdditionalFlowStep(n1, n2) and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and stepFilter(node1, node2, config) ) @@ -466,7 +466,7 @@ private predicate additionalLocalStateStep( exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - config.isAdditionalFlowStep(n1, s1, n2, s2) and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), s1, pragma[only_bind_into](n2), s2) and getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and stepFilter(node1, node2, config) and not stateBarrier(node1, s1, config) and @@ -481,7 +481,7 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) { exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - jumpStepCached(n1, n2) and + jumpStepCached(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and stepFilter(node1, node2, config) and not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) @@ -494,7 +494,7 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - config.isAdditionalFlowStep(n1, n2) and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and stepFilter(node1, node2, config) and not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext @@ -507,7 +507,7 @@ private predicate additionalJumpStateStep( exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - config.isAdditionalFlowStep(n1, s1, n2, s2) and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), s1, pragma[only_bind_into](n2), s2) and getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and stepFilter(node1, node2, config) and not stateBarrier(node1, s1, config) and @@ -518,7 +518,7 @@ private predicate additionalJumpStateStep( pragma[nomagic] private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) { - readSet(node1.asNode(), c, node2.asNode()) and + readSet(pragma[only_bind_into](node1.asNode()), c, pragma[only_bind_into](node2.asNode())) and stepFilter(node1, node2, config) or exists(Node n | @@ -562,7 +562,8 @@ pragma[nomagic] private predicate store( NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config ) { - store(node1.asNode(), tc, node2.asNode(), contentType) and + store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()), + contentType) and read(_, tc.getContent(), _, config) and stepFilter(node1, node2, config) } diff --git a/cpp/ql/lib/semmle/code/cpp/internal/QualifiedName.qll b/cpp/ql/lib/semmle/code/cpp/internal/QualifiedName.qll index 7cf0c647142..6d795048734 100644 --- a/cpp/ql/lib/semmle/code/cpp/internal/QualifiedName.qll +++ b/cpp/ql/lib/semmle/code/cpp/internal/QualifiedName.qll @@ -4,11 +4,7 @@ * qualified. * * This file contains classes that mirror the standard AST classes for C++, but - * these classes are only concerned with naming. The other difference is that - * these classes don't use the `ResolveClass.qll` mechanisms like - * `unresolveElement` because these classes should eventually be part of the - * implementation of `ResolveClass.qll`, allowing it to match up classes when - * their qualified names and parameters match. + * these classes are only concerned with naming. */ private import semmle.code.cpp.Declaration as D diff --git a/cpp/ql/lib/semmle/code/cpp/internal/ResolveClass.qll b/cpp/ql/lib/semmle/code/cpp/internal/ResolveClass.qll index 42568a5c58d..e9882383dca 100644 --- a/cpp/ql/lib/semmle/code/cpp/internal/ResolveClass.qll +++ b/cpp/ql/lib/semmle/code/cpp/internal/ResolveClass.qll @@ -115,15 +115,13 @@ private module Cached { */ cached predicate isClass(@usertype t) { - ( - usertypes(t, _, 1) or - usertypes(t, _, 2) or - usertypes(t, _, 3) or - usertypes(t, _, 6) or - usertypes(t, _, 10) or - usertypes(t, _, 11) or - usertypes(t, _, 12) - ) + usertypes(t, _, 1) or + usertypes(t, _, 2) or + usertypes(t, _, 3) or + usertypes(t, _, 6) or + usertypes(t, _, 10) or + usertypes(t, _, 11) or + usertypes(t, _, 12) } cached diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll index 7b9e78d2c4b..a076f7a2e45 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll @@ -428,7 +428,7 @@ private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - simpleLocalFlowStepExt(n1, n2) and + simpleLocalFlowStepExt(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and stepFilter(node1, node2, config) ) or @@ -447,7 +447,7 @@ private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configurat exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - config.isAdditionalFlowStep(n1, n2) and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and stepFilter(node1, node2, config) ) @@ -466,7 +466,7 @@ private predicate additionalLocalStateStep( exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - config.isAdditionalFlowStep(n1, s1, n2, s2) and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), s1, pragma[only_bind_into](n2), s2) and getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and stepFilter(node1, node2, config) and not stateBarrier(node1, s1, config) and @@ -481,7 +481,7 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) { exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - jumpStepCached(n1, n2) and + jumpStepCached(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and stepFilter(node1, node2, config) and not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) @@ -494,7 +494,7 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - config.isAdditionalFlowStep(n1, n2) and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and stepFilter(node1, node2, config) and not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext @@ -507,7 +507,7 @@ private predicate additionalJumpStateStep( exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - config.isAdditionalFlowStep(n1, s1, n2, s2) and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), s1, pragma[only_bind_into](n2), s2) and getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and stepFilter(node1, node2, config) and not stateBarrier(node1, s1, config) and @@ -518,7 +518,7 @@ private predicate additionalJumpStateStep( pragma[nomagic] private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) { - readSet(node1.asNode(), c, node2.asNode()) and + readSet(pragma[only_bind_into](node1.asNode()), c, pragma[only_bind_into](node2.asNode())) and stepFilter(node1, node2, config) or exists(Node n | @@ -562,7 +562,8 @@ pragma[nomagic] private predicate store( NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config ) { - store(node1.asNode(), tc, node2.asNode(), contentType) and + store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()), + contentType) and read(_, tc.getContent(), _, config) and stepFilter(node1, node2, config) } diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll index 7b9e78d2c4b..a076f7a2e45 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll @@ -428,7 +428,7 @@ private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - simpleLocalFlowStepExt(n1, n2) and + simpleLocalFlowStepExt(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and stepFilter(node1, node2, config) ) or @@ -447,7 +447,7 @@ private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configurat exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - config.isAdditionalFlowStep(n1, n2) and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and stepFilter(node1, node2, config) ) @@ -466,7 +466,7 @@ private predicate additionalLocalStateStep( exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - config.isAdditionalFlowStep(n1, s1, n2, s2) and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), s1, pragma[only_bind_into](n2), s2) and getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and stepFilter(node1, node2, config) and not stateBarrier(node1, s1, config) and @@ -481,7 +481,7 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) { exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - jumpStepCached(n1, n2) and + jumpStepCached(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and stepFilter(node1, node2, config) and not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) @@ -494,7 +494,7 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - config.isAdditionalFlowStep(n1, n2) and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and stepFilter(node1, node2, config) and not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext @@ -507,7 +507,7 @@ private predicate additionalJumpStateStep( exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - config.isAdditionalFlowStep(n1, s1, n2, s2) and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), s1, pragma[only_bind_into](n2), s2) and getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and stepFilter(node1, node2, config) and not stateBarrier(node1, s1, config) and @@ -518,7 +518,7 @@ private predicate additionalJumpStateStep( pragma[nomagic] private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) { - readSet(node1.asNode(), c, node2.asNode()) and + readSet(pragma[only_bind_into](node1.asNode()), c, pragma[only_bind_into](node2.asNode())) and stepFilter(node1, node2, config) or exists(Node n | @@ -562,7 +562,8 @@ pragma[nomagic] private predicate store( NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config ) { - store(node1.asNode(), tc, node2.asNode(), contentType) and + store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()), + contentType) and read(_, tc.getContent(), _, config) and stepFilter(node1, node2, config) } diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll index 7b9e78d2c4b..a076f7a2e45 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll @@ -428,7 +428,7 @@ private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - simpleLocalFlowStepExt(n1, n2) and + simpleLocalFlowStepExt(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and stepFilter(node1, node2, config) ) or @@ -447,7 +447,7 @@ private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configurat exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - config.isAdditionalFlowStep(n1, n2) and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and stepFilter(node1, node2, config) ) @@ -466,7 +466,7 @@ private predicate additionalLocalStateStep( exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - config.isAdditionalFlowStep(n1, s1, n2, s2) and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), s1, pragma[only_bind_into](n2), s2) and getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and stepFilter(node1, node2, config) and not stateBarrier(node1, s1, config) and @@ -481,7 +481,7 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) { exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - jumpStepCached(n1, n2) and + jumpStepCached(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and stepFilter(node1, node2, config) and not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) @@ -494,7 +494,7 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - config.isAdditionalFlowStep(n1, n2) and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and stepFilter(node1, node2, config) and not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext @@ -507,7 +507,7 @@ private predicate additionalJumpStateStep( exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - config.isAdditionalFlowStep(n1, s1, n2, s2) and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), s1, pragma[only_bind_into](n2), s2) and getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and stepFilter(node1, node2, config) and not stateBarrier(node1, s1, config) and @@ -518,7 +518,7 @@ private predicate additionalJumpStateStep( pragma[nomagic] private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) { - readSet(node1.asNode(), c, node2.asNode()) and + readSet(pragma[only_bind_into](node1.asNode()), c, pragma[only_bind_into](node2.asNode())) and stepFilter(node1, node2, config) or exists(Node n | @@ -562,7 +562,8 @@ pragma[nomagic] private predicate store( NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config ) { - store(node1.asNode(), tc, node2.asNode(), contentType) and + store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()), + contentType) and read(_, tc.getContent(), _, config) and stepFilter(node1, node2, config) } diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll index 7b9e78d2c4b..a076f7a2e45 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll @@ -428,7 +428,7 @@ private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - simpleLocalFlowStepExt(n1, n2) and + simpleLocalFlowStepExt(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and stepFilter(node1, node2, config) ) or @@ -447,7 +447,7 @@ private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configurat exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - config.isAdditionalFlowStep(n1, n2) and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and stepFilter(node1, node2, config) ) @@ -466,7 +466,7 @@ private predicate additionalLocalStateStep( exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - config.isAdditionalFlowStep(n1, s1, n2, s2) and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), s1, pragma[only_bind_into](n2), s2) and getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and stepFilter(node1, node2, config) and not stateBarrier(node1, s1, config) and @@ -481,7 +481,7 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) { exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - jumpStepCached(n1, n2) and + jumpStepCached(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and stepFilter(node1, node2, config) and not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) @@ -494,7 +494,7 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - config.isAdditionalFlowStep(n1, n2) and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and stepFilter(node1, node2, config) and not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext @@ -507,7 +507,7 @@ private predicate additionalJumpStateStep( exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - config.isAdditionalFlowStep(n1, s1, n2, s2) and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), s1, pragma[only_bind_into](n2), s2) and getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and stepFilter(node1, node2, config) and not stateBarrier(node1, s1, config) and @@ -518,7 +518,7 @@ private predicate additionalJumpStateStep( pragma[nomagic] private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) { - readSet(node1.asNode(), c, node2.asNode()) and + readSet(pragma[only_bind_into](node1.asNode()), c, pragma[only_bind_into](node2.asNode())) and stepFilter(node1, node2, config) or exists(Node n | @@ -562,7 +562,8 @@ pragma[nomagic] private predicate store( NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config ) { - store(node1.asNode(), tc, node2.asNode(), contentType) and + store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()), + contentType) and read(_, tc.getContent(), _, config) and stepFilter(node1, node2, config) } diff --git a/cpp/ql/src/CHANGELOG.md b/cpp/ql/src/CHANGELOG.md index 449af46b6b8..2b404ff5288 100644 --- a/cpp/ql/src/CHANGELOG.md +++ b/cpp/ql/src/CHANGELOG.md @@ -1,3 +1,5 @@ +## 0.2.0 + ## 0.1.4 ## 0.1.3 diff --git a/cpp/ql/src/Likely Bugs/Memory Management/ReturnStackAllocatedMemory.ql b/cpp/ql/src/Likely Bugs/Memory Management/ReturnStackAllocatedMemory.ql index c72e25f61df..bd55008677c 100644 --- a/cpp/ql/src/Likely Bugs/Memory Management/ReturnStackAllocatedMemory.ql +++ b/cpp/ql/src/Likely Bugs/Memory Management/ReturnStackAllocatedMemory.ql @@ -18,7 +18,7 @@ import semmle.code.cpp.ir.IR import semmle.code.cpp.ir.dataflow.MustFlow import PathGraph -/** Holds if `f` has a name that we intrepret as evidence of intentionally returning the value of the stack pointer. */ +/** Holds if `f` has a name that we interpret as evidence of intentionally returning the value of the stack pointer. */ predicate intentionallyReturnsStackPointer(Function f) { f.getName().toLowerCase().matches(["%stack%", "%sp%"]) } diff --git a/cpp/ql/src/Likely Bugs/Memory Management/UsingExpiredStackAddress.ql b/cpp/ql/src/Likely Bugs/Memory Management/UsingExpiredStackAddress.ql index 27aeabbaf49..3f3997315d4 100644 --- a/cpp/ql/src/Likely Bugs/Memory Management/UsingExpiredStackAddress.ql +++ b/cpp/ql/src/Likely Bugs/Memory Management/UsingExpiredStackAddress.ql @@ -133,7 +133,9 @@ TGlobalAddress globalAddress(Instruction instr) { ) or exists(FieldAddressInstruction fai | instr = fai | - result = TFieldAddress(globalAddress(fai.getObjectAddress()), fai.getField()) + result = + TFieldAddress(globalAddress(pragma[only_bind_into](fai.getObjectAddress())), + pragma[only_bind_out](fai.getField())) ) or result = globalAddress(instr.(PointerOffsetInstruction).getLeft()) diff --git a/cpp/ql/src/change-notes/2022-06-29-move-contextual-queries.md b/cpp/ql/src/change-notes/2022-06-29-move-contextual-queries.md new file mode 100644 index 00000000000..cc5464d58b3 --- /dev/null +++ b/cpp/ql/src/change-notes/2022-06-29-move-contextual-queries.md @@ -0,0 +1,4 @@ +--- +category: breaking +--- +* Contextual queries and the query libraries they depend on have been moved to the `codeql/cpp-all` package. diff --git a/cpp/ql/src/change-notes/released/0.2.0.md b/cpp/ql/src/change-notes/released/0.2.0.md new file mode 100644 index 00000000000..79a5f33514f --- /dev/null +++ b/cpp/ql/src/change-notes/released/0.2.0.md @@ -0,0 +1 @@ +## 0.2.0 diff --git a/cpp/ql/src/codeql-pack.release.yml b/cpp/ql/src/codeql-pack.release.yml index e8ee3af8ef9..5274e27ed52 100644 --- a/cpp/ql/src/codeql-pack.release.yml +++ b/cpp/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.1.4 +lastReleaseVersion: 0.2.0 diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-670/DangerousUseSSL_shutdown.cpp b/cpp/ql/src/experimental/Security/CWE/CWE-670/DangerousUseSSL_shutdown.cpp new file mode 100644 index 00000000000..291cbc8edca --- /dev/null +++ b/cpp/ql/src/experimental/Security/CWE/CWE-670/DangerousUseSSL_shutdown.cpp @@ -0,0 +1,11 @@ +... +SSL_shutdown(ssl); +SSL_shutdown(ssl); // BAD +... + switch ((ret = SSL_shutdown(ssl))) { + case 1: + break; + case 0: + ERR_clear_error(); + if (-1 != (ret = SSL_shutdown(ssl))) break; // GOOD +... diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-670/DangerousUseSSL_shutdown.qhelp b/cpp/ql/src/experimental/Security/CWE/CWE-670/DangerousUseSSL_shutdown.qhelp new file mode 100644 index 00000000000..bc3f8fcc875 --- /dev/null +++ b/cpp/ql/src/experimental/Security/CWE/CWE-670/DangerousUseSSL_shutdown.qhelp @@ -0,0 +1,27 @@ + + + +Incorrect closing of the connection leads to the creation of different states for the server and client, which can be exploited by an attacker. + + + + +The following example shows the incorrect and correct usage of function SSL_shutdown. + + + + + + + CERT Coding Standard: + EXP12-C. Do not ignore values returned by functions - SEI CERT C Coding Standard - Confluence. + + + Openssl.org: + SSL_shutdown - shut down a TLS/SSL connection. + + + + diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-670/DangerousUseSSL_shutdown.ql b/cpp/ql/src/experimental/Security/CWE/CWE-670/DangerousUseSSL_shutdown.ql new file mode 100644 index 00000000000..d608fd5a7ed --- /dev/null +++ b/cpp/ql/src/experimental/Security/CWE/CWE-670/DangerousUseSSL_shutdown.ql @@ -0,0 +1,33 @@ +/** + * @name Dangerous use SSL_shutdown. + * @description Incorrect closing of the connection leads to the creation of different states for the server and client, which can be exploited by an attacker. + * @kind problem + * @id cpp/dangerous-use-of-ssl-shutdown + * @problem.severity warning + * @precision medium + * @tags correctness + * security + * external/cwe/cwe-670 + */ + +import cpp +import semmle.code.cpp.commons.Exclusions +import semmle.code.cpp.valuenumbering.GlobalValueNumbering + +from FunctionCall fc, FunctionCall fc1 +where + fc != fc1 and + fc.getASuccessor+() = fc1 and + fc.getTarget().hasName("SSL_shutdown") and + fc1.getTarget().hasName("SSL_shutdown") and + fc1 instanceof ExprInVoidContext and + ( + globalValueNumber(fc.getArgument(0)) = globalValueNumber(fc1.getArgument(0)) or + fc.getArgument(0).(VariableAccess).getTarget() = fc1.getArgument(0).(VariableAccess).getTarget() + ) and + not exists(FunctionCall fctmp | + fctmp.getTarget().hasName("SSL_free") and + fc.getASuccessor+() = fctmp and + fctmp.getASuccessor+() = fc1 + ) +select fc, "You need to handle the return value SSL_shutdown" diff --git a/cpp/ql/src/qlpack.yml b/cpp/ql/src/qlpack.yml index a373e4717d8..62cac967801 100644 --- a/cpp/ql/src/qlpack.yml +++ b/cpp/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cpp-queries -version: 0.2.0-dev +version: 0.2.1-dev groups: - cpp - queries diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-670/semmle/tests/DangerousUseSSL_shutdown.expected b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-670/semmle/tests/DangerousUseSSL_shutdown.expected new file mode 100644 index 00000000000..bb3d9157148 --- /dev/null +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-670/semmle/tests/DangerousUseSSL_shutdown.expected @@ -0,0 +1,2 @@ +| test.cpp:45:20:45:31 | call to SSL_shutdown | You need to handle the return value SSL_shutdown | +| test.cpp:61:11:61:22 | call to SSL_shutdown | You need to handle the return value SSL_shutdown | diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-670/semmle/tests/DangerousUseSSL_shutdown.qlref b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-670/semmle/tests/DangerousUseSSL_shutdown.qlref new file mode 100644 index 00000000000..0c2096f68ff --- /dev/null +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-670/semmle/tests/DangerousUseSSL_shutdown.qlref @@ -0,0 +1 @@ +experimental/Security/CWE/CWE-670/DangerousUseSSL_shutdown.ql diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-670/semmle/tests/test.cpp b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-670/semmle/tests/test.cpp new file mode 100644 index 00000000000..9ebe1cc10a5 --- /dev/null +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-670/semmle/tests/test.cpp @@ -0,0 +1,75 @@ +// it's not exact, but it's enough for an example +typedef int SSL; + + +int SSL_shutdown(SSL *ssl); +int SSL_get_error(const SSL *ssl, int ret); +void ERR_clear_error(void); +void print_error(char *buff,int code); + +int gootTest1(SSL *ssl) +{ + int ret; + switch ((ret = SSL_shutdown(ssl))) { + case 1: + break; + case 0: + ERR_clear_error(); + if ((ret = SSL_shutdown(ssl)) == 1) break; // GOOD + default: + print_error("error shutdown", + SSL_get_error(ssl, ret)); + return -1; + } + return 0; +} +int gootTest2(SSL *ssl) +{ + int ret; + switch ((ret = SSL_shutdown(ssl))) { + case 1: + break; + case 0: + ERR_clear_error(); + if (-1 != (ret = SSL_shutdown(ssl))) break; // GOOD + default: + print_error("error shutdown", + SSL_get_error(ssl, ret)); + return -1; + } + return 0; +} +int badTest1(SSL *ssl) +{ + int ret; + switch ((ret = SSL_shutdown(ssl))) { + case 1: + break; + case 0: + SSL_shutdown(ssl); // BAD + break; + default: + print_error("error shutdown", + SSL_get_error(ssl, ret)); + return -1; + } + return 0; +} +int badTest2(SSL *ssl) +{ + int ret; + ret = SSL_shutdown(ssl); + switch (ret) { + case 1: + break; + case 0: + SSL_shutdown(ssl); // BAD + break; + default: + print_error("error shutdown", + SSL_get_error(ssl, ret)); + return -1; + } + return 0; +} + diff --git a/csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md b/csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md index 0bb47844d19..30c583ee913 100644 --- a/csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md +++ b/csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md @@ -1,3 +1,5 @@ +## 1.2.0 + ## 1.1.4 ## 1.1.3 diff --git a/csharp/ql/campaigns/Solorigate/lib/change-notes/released/1.2.0.md b/csharp/ql/campaigns/Solorigate/lib/change-notes/released/1.2.0.md new file mode 100644 index 00000000000..0ff42339575 --- /dev/null +++ b/csharp/ql/campaigns/Solorigate/lib/change-notes/released/1.2.0.md @@ -0,0 +1 @@ +## 1.2.0 diff --git a/csharp/ql/campaigns/Solorigate/lib/codeql-pack.release.yml b/csharp/ql/campaigns/Solorigate/lib/codeql-pack.release.yml index 26cbcd3f123..75430e73d1c 100644 --- a/csharp/ql/campaigns/Solorigate/lib/codeql-pack.release.yml +++ b/csharp/ql/campaigns/Solorigate/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.1.4 +lastReleaseVersion: 1.2.0 diff --git a/csharp/ql/campaigns/Solorigate/lib/qlpack.yml b/csharp/ql/campaigns/Solorigate/lib/qlpack.yml index 9cb7bec181f..bc7eaf4142c 100644 --- a/csharp/ql/campaigns/Solorigate/lib/qlpack.yml +++ b/csharp/ql/campaigns/Solorigate/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/csharp-solorigate-all -version: 1.2.0-dev +version: 1.2.1-dev groups: - csharp - solorigate diff --git a/csharp/ql/campaigns/Solorigate/src/CHANGELOG.md b/csharp/ql/campaigns/Solorigate/src/CHANGELOG.md index 0bb47844d19..30c583ee913 100644 --- a/csharp/ql/campaigns/Solorigate/src/CHANGELOG.md +++ b/csharp/ql/campaigns/Solorigate/src/CHANGELOG.md @@ -1,3 +1,5 @@ +## 1.2.0 + ## 1.1.4 ## 1.1.3 diff --git a/csharp/ql/campaigns/Solorigate/src/change-notes/released/1.2.0.md b/csharp/ql/campaigns/Solorigate/src/change-notes/released/1.2.0.md new file mode 100644 index 00000000000..0ff42339575 --- /dev/null +++ b/csharp/ql/campaigns/Solorigate/src/change-notes/released/1.2.0.md @@ -0,0 +1 @@ +## 1.2.0 diff --git a/csharp/ql/campaigns/Solorigate/src/codeql-pack.release.yml b/csharp/ql/campaigns/Solorigate/src/codeql-pack.release.yml index 26cbcd3f123..75430e73d1c 100644 --- a/csharp/ql/campaigns/Solorigate/src/codeql-pack.release.yml +++ b/csharp/ql/campaigns/Solorigate/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.1.4 +lastReleaseVersion: 1.2.0 diff --git a/csharp/ql/campaigns/Solorigate/src/qlpack.yml b/csharp/ql/campaigns/Solorigate/src/qlpack.yml index 07419f1b469..00725e23666 100644 --- a/csharp/ql/campaigns/Solorigate/src/qlpack.yml +++ b/csharp/ql/campaigns/Solorigate/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/csharp-solorigate-queries -version: 1.2.0-dev +version: 1.2.1-dev groups: - csharp - solorigate diff --git a/csharp/ql/lib/CHANGELOG.md b/csharp/ql/lib/CHANGELOG.md index 3df8b95eeb6..3f49fe5ade3 100644 --- a/csharp/ql/lib/CHANGELOG.md +++ b/csharp/ql/lib/CHANGELOG.md @@ -1,3 +1,9 @@ +## 0.3.0 + +### Deprecated APIs + +* The `BarrierGuard` class has been deprecated. Such barriers and sanitizers can now instead be created using the new `BarrierGuard` parameterized module. + ## 0.2.3 ## 0.2.2 diff --git a/csharp/ql/src/IDEContextual.qll b/csharp/ql/lib/IDEContextual.qll similarity index 100% rename from csharp/ql/src/IDEContextual.qll rename to csharp/ql/lib/IDEContextual.qll diff --git a/go/ql/lib/change-notes/2022-06-21-barrierguard-deprecation.md b/csharp/ql/lib/change-notes/released/0.3.0.md similarity index 83% rename from go/ql/lib/change-notes/2022-06-21-barrierguard-deprecation.md rename to csharp/ql/lib/change-notes/released/0.3.0.md index 2bd95798f89..54af6e00ac0 100644 --- a/go/ql/lib/change-notes/2022-06-21-barrierguard-deprecation.md +++ b/csharp/ql/lib/change-notes/released/0.3.0.md @@ -1,4 +1,5 @@ ---- -category: deprecated ---- +## 0.3.0 + +### Deprecated APIs + * The `BarrierGuard` class has been deprecated. Such barriers and sanitizers can now instead be created using the new `BarrierGuard` parameterized module. diff --git a/csharp/ql/lib/codeql-pack.release.yml b/csharp/ql/lib/codeql-pack.release.yml index 0b605901b42..95f6e3a0ba6 100644 --- a/csharp/ql/lib/codeql-pack.release.yml +++ b/csharp/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.2.3 +lastReleaseVersion: 0.3.0 diff --git a/csharp/ql/src/definitions.qll b/csharp/ql/lib/definitions.qll similarity index 100% rename from csharp/ql/src/definitions.qll rename to csharp/ql/lib/definitions.qll diff --git a/csharp/ql/src/localDefinitions.ql b/csharp/ql/lib/localDefinitions.ql similarity index 100% rename from csharp/ql/src/localDefinitions.ql rename to csharp/ql/lib/localDefinitions.ql diff --git a/csharp/ql/src/localReferences.ql b/csharp/ql/lib/localReferences.ql similarity index 100% rename from csharp/ql/src/localReferences.ql rename to csharp/ql/lib/localReferences.ql diff --git a/csharp/ql/src/printAst.ql b/csharp/ql/lib/printAst.ql similarity index 100% rename from csharp/ql/src/printAst.ql rename to csharp/ql/lib/printAst.ql diff --git a/csharp/ql/lib/qlpack.yml b/csharp/ql/lib/qlpack.yml index 2e2d17e36fa..3f371c01e92 100644 --- a/csharp/ql/lib/qlpack.yml +++ b/csharp/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/csharp-all -version: 0.3.0-dev +version: 0.3.1-dev groups: csharp dbscheme: semmlecode.csharp.dbscheme extractor: csharp diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll index 7b9e78d2c4b..a076f7a2e45 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll @@ -428,7 +428,7 @@ private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - simpleLocalFlowStepExt(n1, n2) and + simpleLocalFlowStepExt(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and stepFilter(node1, node2, config) ) or @@ -447,7 +447,7 @@ private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configurat exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - config.isAdditionalFlowStep(n1, n2) and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and stepFilter(node1, node2, config) ) @@ -466,7 +466,7 @@ private predicate additionalLocalStateStep( exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - config.isAdditionalFlowStep(n1, s1, n2, s2) and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), s1, pragma[only_bind_into](n2), s2) and getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and stepFilter(node1, node2, config) and not stateBarrier(node1, s1, config) and @@ -481,7 +481,7 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) { exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - jumpStepCached(n1, n2) and + jumpStepCached(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and stepFilter(node1, node2, config) and not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) @@ -494,7 +494,7 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - config.isAdditionalFlowStep(n1, n2) and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and stepFilter(node1, node2, config) and not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext @@ -507,7 +507,7 @@ private predicate additionalJumpStateStep( exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - config.isAdditionalFlowStep(n1, s1, n2, s2) and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), s1, pragma[only_bind_into](n2), s2) and getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and stepFilter(node1, node2, config) and not stateBarrier(node1, s1, config) and @@ -518,7 +518,7 @@ private predicate additionalJumpStateStep( pragma[nomagic] private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) { - readSet(node1.asNode(), c, node2.asNode()) and + readSet(pragma[only_bind_into](node1.asNode()), c, pragma[only_bind_into](node2.asNode())) and stepFilter(node1, node2, config) or exists(Node n | @@ -562,7 +562,8 @@ pragma[nomagic] private predicate store( NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config ) { - store(node1.asNode(), tc, node2.asNode(), contentType) and + store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()), + contentType) and read(_, tc.getContent(), _, config) and stepFilter(node1, node2, config) } diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll index 7b9e78d2c4b..a076f7a2e45 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll @@ -428,7 +428,7 @@ private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - simpleLocalFlowStepExt(n1, n2) and + simpleLocalFlowStepExt(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and stepFilter(node1, node2, config) ) or @@ -447,7 +447,7 @@ private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configurat exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - config.isAdditionalFlowStep(n1, n2) and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and stepFilter(node1, node2, config) ) @@ -466,7 +466,7 @@ private predicate additionalLocalStateStep( exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - config.isAdditionalFlowStep(n1, s1, n2, s2) and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), s1, pragma[only_bind_into](n2), s2) and getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and stepFilter(node1, node2, config) and not stateBarrier(node1, s1, config) and @@ -481,7 +481,7 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) { exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - jumpStepCached(n1, n2) and + jumpStepCached(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and stepFilter(node1, node2, config) and not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) @@ -494,7 +494,7 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - config.isAdditionalFlowStep(n1, n2) and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and stepFilter(node1, node2, config) and not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext @@ -507,7 +507,7 @@ private predicate additionalJumpStateStep( exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - config.isAdditionalFlowStep(n1, s1, n2, s2) and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), s1, pragma[only_bind_into](n2), s2) and getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and stepFilter(node1, node2, config) and not stateBarrier(node1, s1, config) and @@ -518,7 +518,7 @@ private predicate additionalJumpStateStep( pragma[nomagic] private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) { - readSet(node1.asNode(), c, node2.asNode()) and + readSet(pragma[only_bind_into](node1.asNode()), c, pragma[only_bind_into](node2.asNode())) and stepFilter(node1, node2, config) or exists(Node n | @@ -562,7 +562,8 @@ pragma[nomagic] private predicate store( NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config ) { - store(node1.asNode(), tc, node2.asNode(), contentType) and + store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()), + contentType) and read(_, tc.getContent(), _, config) and stepFilter(node1, node2, config) } diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll index 7b9e78d2c4b..a076f7a2e45 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll @@ -428,7 +428,7 @@ private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - simpleLocalFlowStepExt(n1, n2) and + simpleLocalFlowStepExt(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and stepFilter(node1, node2, config) ) or @@ -447,7 +447,7 @@ private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configurat exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - config.isAdditionalFlowStep(n1, n2) and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and stepFilter(node1, node2, config) ) @@ -466,7 +466,7 @@ private predicate additionalLocalStateStep( exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - config.isAdditionalFlowStep(n1, s1, n2, s2) and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), s1, pragma[only_bind_into](n2), s2) and getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and stepFilter(node1, node2, config) and not stateBarrier(node1, s1, config) and @@ -481,7 +481,7 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) { exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - jumpStepCached(n1, n2) and + jumpStepCached(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and stepFilter(node1, node2, config) and not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) @@ -494,7 +494,7 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - config.isAdditionalFlowStep(n1, n2) and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and stepFilter(node1, node2, config) and not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext @@ -507,7 +507,7 @@ private predicate additionalJumpStateStep( exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - config.isAdditionalFlowStep(n1, s1, n2, s2) and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), s1, pragma[only_bind_into](n2), s2) and getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and stepFilter(node1, node2, config) and not stateBarrier(node1, s1, config) and @@ -518,7 +518,7 @@ private predicate additionalJumpStateStep( pragma[nomagic] private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) { - readSet(node1.asNode(), c, node2.asNode()) and + readSet(pragma[only_bind_into](node1.asNode()), c, pragma[only_bind_into](node2.asNode())) and stepFilter(node1, node2, config) or exists(Node n | @@ -562,7 +562,8 @@ pragma[nomagic] private predicate store( NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config ) { - store(node1.asNode(), tc, node2.asNode(), contentType) and + store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()), + contentType) and read(_, tc.getContent(), _, config) and stepFilter(node1, node2, config) } diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll index 7b9e78d2c4b..a076f7a2e45 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll @@ -428,7 +428,7 @@ private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - simpleLocalFlowStepExt(n1, n2) and + simpleLocalFlowStepExt(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and stepFilter(node1, node2, config) ) or @@ -447,7 +447,7 @@ private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configurat exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - config.isAdditionalFlowStep(n1, n2) and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and stepFilter(node1, node2, config) ) @@ -466,7 +466,7 @@ private predicate additionalLocalStateStep( exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - config.isAdditionalFlowStep(n1, s1, n2, s2) and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), s1, pragma[only_bind_into](n2), s2) and getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and stepFilter(node1, node2, config) and not stateBarrier(node1, s1, config) and @@ -481,7 +481,7 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) { exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - jumpStepCached(n1, n2) and + jumpStepCached(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and stepFilter(node1, node2, config) and not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) @@ -494,7 +494,7 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - config.isAdditionalFlowStep(n1, n2) and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and stepFilter(node1, node2, config) and not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext @@ -507,7 +507,7 @@ private predicate additionalJumpStateStep( exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - config.isAdditionalFlowStep(n1, s1, n2, s2) and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), s1, pragma[only_bind_into](n2), s2) and getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and stepFilter(node1, node2, config) and not stateBarrier(node1, s1, config) and @@ -518,7 +518,7 @@ private predicate additionalJumpStateStep( pragma[nomagic] private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) { - readSet(node1.asNode(), c, node2.asNode()) and + readSet(pragma[only_bind_into](node1.asNode()), c, pragma[only_bind_into](node2.asNode())) and stepFilter(node1, node2, config) or exists(Node n | @@ -562,7 +562,8 @@ pragma[nomagic] private predicate store( NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config ) { - store(node1.asNode(), tc, node2.asNode(), contentType) and + store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()), + contentType) and read(_, tc.getContent(), _, config) and stepFilter(node1, node2, config) } diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll index 7b9e78d2c4b..a076f7a2e45 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll @@ -428,7 +428,7 @@ private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - simpleLocalFlowStepExt(n1, n2) and + simpleLocalFlowStepExt(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and stepFilter(node1, node2, config) ) or @@ -447,7 +447,7 @@ private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configurat exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - config.isAdditionalFlowStep(n1, n2) and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and stepFilter(node1, node2, config) ) @@ -466,7 +466,7 @@ private predicate additionalLocalStateStep( exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - config.isAdditionalFlowStep(n1, s1, n2, s2) and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), s1, pragma[only_bind_into](n2), s2) and getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and stepFilter(node1, node2, config) and not stateBarrier(node1, s1, config) and @@ -481,7 +481,7 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) { exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - jumpStepCached(n1, n2) and + jumpStepCached(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and stepFilter(node1, node2, config) and not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) @@ -494,7 +494,7 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - config.isAdditionalFlowStep(n1, n2) and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and stepFilter(node1, node2, config) and not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext @@ -507,7 +507,7 @@ private predicate additionalJumpStateStep( exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - config.isAdditionalFlowStep(n1, s1, n2, s2) and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), s1, pragma[only_bind_into](n2), s2) and getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and stepFilter(node1, node2, config) and not stateBarrier(node1, s1, config) and @@ -518,7 +518,7 @@ private predicate additionalJumpStateStep( pragma[nomagic] private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) { - readSet(node1.asNode(), c, node2.asNode()) and + readSet(pragma[only_bind_into](node1.asNode()), c, pragma[only_bind_into](node2.asNode())) and stepFilter(node1, node2, config) or exists(Node n | @@ -562,7 +562,8 @@ pragma[nomagic] private predicate store( NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config ) { - store(node1.asNode(), tc, node2.asNode(), contentType) and + store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()), + contentType) and read(_, tc.getContent(), _, config) and stepFilter(node1, node2, config) } diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImplForContentDataFlow.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImplForContentDataFlow.qll index 7b9e78d2c4b..a076f7a2e45 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImplForContentDataFlow.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImplForContentDataFlow.qll @@ -428,7 +428,7 @@ private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - simpleLocalFlowStepExt(n1, n2) and + simpleLocalFlowStepExt(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and stepFilter(node1, node2, config) ) or @@ -447,7 +447,7 @@ private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configurat exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - config.isAdditionalFlowStep(n1, n2) and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and stepFilter(node1, node2, config) ) @@ -466,7 +466,7 @@ private predicate additionalLocalStateStep( exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - config.isAdditionalFlowStep(n1, s1, n2, s2) and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), s1, pragma[only_bind_into](n2), s2) and getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and stepFilter(node1, node2, config) and not stateBarrier(node1, s1, config) and @@ -481,7 +481,7 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) { exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - jumpStepCached(n1, n2) and + jumpStepCached(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and stepFilter(node1, node2, config) and not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext ) @@ -494,7 +494,7 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - config.isAdditionalFlowStep(n1, n2) and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), pragma[only_bind_into](n2)) and getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and stepFilter(node1, node2, config) and not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext @@ -507,7 +507,7 @@ private predicate additionalJumpStateStep( exists(Node n1, Node n2 | node1.asNode() = n1 and node2.asNode() = n2 and - config.isAdditionalFlowStep(n1, s1, n2, s2) and + config.isAdditionalFlowStep(pragma[only_bind_into](n1), s1, pragma[only_bind_into](n2), s2) and getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and stepFilter(node1, node2, config) and not stateBarrier(node1, s1, config) and @@ -518,7 +518,7 @@ private predicate additionalJumpStateStep( pragma[nomagic] private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) { - readSet(node1.asNode(), c, node2.asNode()) and + readSet(pragma[only_bind_into](node1.asNode()), c, pragma[only_bind_into](node2.asNode())) and stepFilter(node1, node2, config) or exists(Node n | @@ -562,7 +562,8 @@ pragma[nomagic] private predicate store( NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config ) { - store(node1.asNode(), tc, node2.asNode(), contentType) and + store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()), + contentType) and read(_, tc.getContent(), _, config) and stepFilter(node1, node2, config) } diff --git a/csharp/ql/src/CHANGELOG.md b/csharp/ql/src/CHANGELOG.md index bc553b74fe4..e7ce0b0b471 100644 --- a/csharp/ql/src/CHANGELOG.md +++ b/csharp/ql/src/CHANGELOG.md @@ -1,3 +1,14 @@ +## 0.2.0 + +### Query Metadata Changes + +* The `kind` query metadata was changed to `diagnostic` on `cs/compilation-error`, `cs/compilation-message`, `cs/extraction-error`, and `cs/extraction-message`. + +### Minor Analysis Improvements + +* The syntax of the (source|sink|summary)model CSV format has been changed slightly for Java and C#. A new column called `provenance` has been introduced, where the allowed values are `manual` and `generated`. The value used to indicate whether a model as been written by hand (`manual`) or create by the CSV model generator (`generated`). +* All auto implemented public properties with public getters and setters on ASP.NET Core remote flow sources are now also considered to be tainted. + ## 0.1.4 ## 0.1.3 diff --git a/csharp/ql/src/change-notes/2022-06-02-aspnetcoretaintedmembers.md b/csharp/ql/src/change-notes/2022-06-02-aspnetcoretaintedmembers.md deleted file mode 100644 index b80e90e0434..00000000000 --- a/csharp/ql/src/change-notes/2022-06-02-aspnetcoretaintedmembers.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: minorAnalysis ---- -* All auto implemented public properties with public getters and setters on ASP.NET Core remote flow sources are now also considered to be tainted. \ No newline at end of file diff --git a/csharp/ql/src/change-notes/2022-06-14-madformatchange.md b/csharp/ql/src/change-notes/2022-06-14-madformatchange.md deleted file mode 100644 index 1dd215a89c7..00000000000 --- a/csharp/ql/src/change-notes/2022-06-14-madformatchange.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: minorAnalysis ---- -* The syntax of the (source|sink|summary)model CSV format has been changed slightly for Java and C#. A new column called `provenance` has been introduced, where the allowed values are `manual` and `generated`. The value used to indicate whether a model as been written by hand (`manual`) or create by the CSV model generator (`generated`). \ No newline at end of file diff --git a/csharp/ql/src/change-notes/2022-06-15-diagnostic-query-metadata.md b/csharp/ql/src/change-notes/2022-06-15-diagnostic-query-metadata.md deleted file mode 100644 index d5cfc4d35e1..00000000000 --- a/csharp/ql/src/change-notes/2022-06-15-diagnostic-query-metadata.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: queryMetadata ---- -* The `kind` query metadata was changed to `diagnostic` on `cs/compilation-error`, `cs/compilation-message`, `cs/extraction-error`, and `cs/extraction-message`. diff --git a/csharp/ql/src/change-notes/2022-06-29-move-contextual-queries.md b/csharp/ql/src/change-notes/2022-06-29-move-contextual-queries.md new file mode 100644 index 00000000000..a27c68766c0 --- /dev/null +++ b/csharp/ql/src/change-notes/2022-06-29-move-contextual-queries.md @@ -0,0 +1,4 @@ +--- +category: breaking +--- +* Contextual queries and the query libraries they depend on have been moved to the `codeql/csharp-all` package. diff --git a/csharp/ql/src/change-notes/released/0.2.0.md b/csharp/ql/src/change-notes/released/0.2.0.md new file mode 100644 index 00000000000..1b7d3928c1c --- /dev/null +++ b/csharp/ql/src/change-notes/released/0.2.0.md @@ -0,0 +1,10 @@ +## 0.2.0 + +### Query Metadata Changes + +* The `kind` query metadata was changed to `diagnostic` on `cs/compilation-error`, `cs/compilation-message`, `cs/extraction-error`, and `cs/extraction-message`. + +### Minor Analysis Improvements + +* The syntax of the (source|sink|summary)model CSV format has been changed slightly for Java and C#. A new column called `provenance` has been introduced, where the allowed values are `manual` and `generated`. The value used to indicate whether a model as been written by hand (`manual`) or create by the CSV model generator (`generated`). +* All auto implemented public properties with public getters and setters on ASP.NET Core remote flow sources are now also considered to be tainted. diff --git a/csharp/ql/src/codeql-pack.release.yml b/csharp/ql/src/codeql-pack.release.yml index e8ee3af8ef9..5274e27ed52 100644 --- a/csharp/ql/src/codeql-pack.release.yml +++ b/csharp/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.1.4 +lastReleaseVersion: 0.2.0 diff --git a/csharp/ql/src/qlpack.yml b/csharp/ql/src/qlpack.yml index a9d6dcf0e69..1002c6a56ad 100644 --- a/csharp/ql/src/qlpack.yml +++ b/csharp/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/csharp-queries -version: 0.2.0-dev +version: 0.2.1-dev groups: - csharp - queries diff --git a/docs/codeql/reusables/beta-note-package-management.rst b/docs/codeql/reusables/beta-note-package-management.rst index a4fd362a70c..7697c9a47d9 100644 --- a/docs/codeql/reusables/beta-note-package-management.rst +++ b/docs/codeql/reusables/beta-note-package-management.rst @@ -2,4 +2,4 @@ Note - The CodeQL package management functionality, including CodeQL packs, is currently available as a beta release and is subject to change. During the beta release, CodeQL packs are available only using GitHub Packages - the GitHub Container registry. To use this beta functionality, install version 2.6.0 or higher of the CodeQL CLI bundle from: https://github.com/github/codeql-action/releases. \ No newline at end of file + The CodeQL package management functionality, including CodeQL packs, is currently available as a beta release and is subject to change. During the beta release, CodeQL packs are available only using GitHub Packages - the GitHub Container registry. To use this beta functionality, install the latest version of the CodeQL CLI bundle from: https://github.com/github/codeql-action/releases. diff --git a/go/ql/lib/CHANGELOG.md b/go/ql/lib/CHANGELOG.md index 1767b297fc6..112f4fab585 100644 --- a/go/ql/lib/CHANGELOG.md +++ b/go/ql/lib/CHANGELOG.md @@ -1,3 +1,9 @@ +## 0.2.0 + +### Deprecated APIs + +* The `BarrierGuard` class has been deprecated. Such barriers and sanitizers can now instead be created using the new `BarrierGuard` parameterized module. + ## 0.1.4 ## 0.1.3 diff --git a/cpp/ql/lib/change-notes/2022-06-21-barrierguard-deprecation.md b/go/ql/lib/change-notes/released/0.2.0.md similarity index 83% rename from cpp/ql/lib/change-notes/2022-06-21-barrierguard-deprecation.md rename to go/ql/lib/change-notes/released/0.2.0.md index 2bd95798f89..ded60d11b7e 100644 --- a/cpp/ql/lib/change-notes/2022-06-21-barrierguard-deprecation.md +++ b/go/ql/lib/change-notes/released/0.2.0.md @@ -1,4 +1,5 @@ ---- -category: deprecated ---- +## 0.2.0 + +### Deprecated APIs + * The `BarrierGuard` class has been deprecated. Such barriers and sanitizers can now instead be created using the new `BarrierGuard` parameterized module. diff --git a/go/ql/lib/codeql-pack.release.yml b/go/ql/lib/codeql-pack.release.yml index e8ee3af8ef9..5274e27ed52 100644 --- a/go/ql/lib/codeql-pack.release.yml +++ b/go/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.1.4 +lastReleaseVersion: 0.2.0 diff --git a/go/ql/lib/qlpack.yml b/go/ql/lib/qlpack.yml index f416a2612a8..964f5d4dd13 100644 --- a/go/ql/lib/qlpack.yml +++ b/go/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/go-all -version: 0.2.0-dev +version: 0.2.1-dev groups: go dbscheme: go.dbscheme extractor: go diff --git a/go/ql/src/CHANGELOG.md b/go/ql/src/CHANGELOG.md index 541c8c95377..bed2509f5d3 100644 --- a/go/ql/src/CHANGELOG.md +++ b/go/ql/src/CHANGELOG.md @@ -1,3 +1,5 @@ +## 0.2.0 + ## 0.1.4 ## 0.1.3 diff --git a/go/ql/src/change-notes/released/0.2.0.md b/go/ql/src/change-notes/released/0.2.0.md new file mode 100644 index 00000000000..79a5f33514f --- /dev/null +++ b/go/ql/src/change-notes/released/0.2.0.md @@ -0,0 +1 @@ +## 0.2.0 diff --git a/go/ql/src/codeql-pack.release.yml b/go/ql/src/codeql-pack.release.yml index e8ee3af8ef9..5274e27ed52 100644 --- a/go/ql/src/codeql-pack.release.yml +++ b/go/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.1.4 +lastReleaseVersion: 0.2.0 diff --git a/go/ql/src/qlpack.yml b/go/ql/src/qlpack.yml index 062631cb68b..80a4430b8da 100644 --- a/go/ql/src/qlpack.yml +++ b/go/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/go-queries -version: 0.2.0-dev +version: 0.2.1-dev groups: - go - queries diff --git a/java/documentation/library-coverage/coverage.csv b/java/documentation/library-coverage/coverage.csv index b9d52d9d75e..06ec8d978d4 100644 --- a/java/documentation/library-coverage/coverage.csv +++ b/java/documentation/library-coverage/coverage.csv @@ -1,121 +1,121 @@ -package,sink,source,summary,sink:bean-validation,sink:create-file,sink:groovy,sink:header-splitting,sink:information-leak,sink:intent-start,sink:jdbc-url,sink:jexl,sink:jndi-injection,sink:ldap,sink:logging,sink:mvel,sink:ognl-injection,sink:open-url,sink:pending-intent-sent,sink:regex-use[-1],sink:regex-use[0],sink:regex-use[],sink:regex-use[f-1],sink:regex-use[f1],sink:regex-use[f],sink:set-hostname-verifier,sink:sql,sink:url-open-stream,sink:url-redirect,sink:write-file,sink:xpath,sink:xslt,sink:xss,source:android-widget,source:contentprovider,source:remote,summary:taint,summary:value -android.app,16,,103,,,,,,7,,,,,,,,,9,,,,,,,,,,,,,,,,,,18,85 -android.content,24,27,108,,,,,,16,,,,,,,,,,,,,,,,,8,,,,,,,,27,,31,77 -android.database,59,,30,,,,,,,,,,,,,,,,,,,,,,,59,,,,,,,,,,30, -android.net,,,60,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,45,15 -android.os,,,122,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,41,81 -android.util,6,16,,,,,,,,,,,,6,,,,,,,,,,,,,,,,,,,,,16,, -android.webkit,3,2,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3,,,2,, -android.widget,,1,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,,,1, -androidx.slice,2,5,88,,,,,,,,,,,,,,,2,,,,,,,,,,,,,,,,5,,27,61 -cn.hutool.core.codec,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, -com.esotericsoftware.kryo.io,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, -com.esotericsoftware.kryo5.io,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, -com.fasterxml.jackson.core,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, -com.fasterxml.jackson.databind,,,6,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,6, -com.google.common.base,4,,85,,,,,,,,,,,,,,,,,3,1,,,,,,,,,,,,,,,62,23 -com.google.common.cache,,,17,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,17 -com.google.common.collect,,,553,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,551 -com.google.common.flogger,29,,,,,,,,,,,,,29,,,,,,,,,,,,,,,,,,,,,,, -com.google.common.io,6,,73,,,,,,,,,,,,,,,,,,,,,,,,6,,,,,,,,,72,1 -com.opensymphony.xwork2.ognl,3,,,,,,,,,,,,,,,3,,,,,,,,,,,,,,,,,,,,, -com.rabbitmq.client,,21,7,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,21,7, -com.unboundid.ldap.sdk,17,,,,,,,,,,,,17,,,,,,,,,,,,,,,,,,,,,,,, -com.zaxxer.hikari,2,,,,,,,,,2,,,,,,,,,,,,,,,,,,,,,,,,,,, -flexjson,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1 -groovy.lang,26,,,,,26,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -groovy.util,5,,,,,5,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -jakarta.faces.context,2,7,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,,,7,, -jakarta.json,,,123,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,100,23 -jakarta.ws.rs.client,1,,,,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,, -jakarta.ws.rs.container,,9,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,9,, -jakarta.ws.rs.core,2,,149,,,,,,,,,,,,,,,,,,,,,,,,,2,,,,,,,,94,55 -java.beans,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, -java.io,37,,39,,15,,,,,,,,,,,,,,,,,,,,,,,,22,,,,,,,39, -java.lang,13,,58,,,,,,,,,,,8,,,,,4,,,1,,,,,,,,,,,,,,46,12 -java.net,10,3,7,,,,,,,,,,,,,,10,,,,,,,,,,,,,,,,,,3,7, -java.nio,15,,6,,13,,,,,,,,,,,,,,,,,,,,,,,,2,,,,,,,6, -java.sql,11,,,,,,,,,4,,,,,,,,,,,,,,,,7,,,,,,,,,,, -java.util,44,,438,,,,,,,,,,,34,,,,,,5,2,,1,2,,,,,,,,,,,,24,414 -javax.faces.context,2,7,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,,,7,, -javax.jms,,9,57,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,9,57, -javax.json,,,123,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,100,23 -javax.management.remote,2,,,,,,,,,,,2,,,,,,,,,,,,,,,,,,,,,,,,, -javax.naming,7,,,,,,,,,,,6,1,,,,,,,,,,,,,,,,,,,,,,,, -javax.net.ssl,2,,,,,,,,,,,,,,,,,,,,,,,,2,,,,,,,,,,,, -javax.script,1,,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,,, -javax.servlet,4,21,2,,,,3,1,,,,,,,,,,,,,,,,,,,,,,,,,,,21,2, -javax.validation,1,1,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,, -javax.ws.rs.client,1,,,,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,, -javax.ws.rs.container,,9,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,9,, -javax.ws.rs.core,3,,149,,,,1,,,,,,,,,,,,,,,,,,,,,2,,,,,,,,94,55 -javax.xml.transform,1,,6,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,,,,,6, -javax.xml.xpath,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3,,,,,,, -jodd.json,,,10,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,10 -kotlin.jvm.internal,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1 -net.sf.saxon.s9api,5,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,5,,,,,, -ognl,6,,,,,,,,,,,,,,,6,,,,,,,,,,,,,,,,,,,,, -okhttp3,2,,47,,,,,,,,,,,,,,2,,,,,,,,,,,,,,,,,,,22,25 -org.apache.commons.codec,,,6,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,6, -org.apache.commons.collections,,,800,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,17,783 -org.apache.commons.collections4,,,800,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,17,783 -org.apache.commons.io,104,,561,,89,,,,,,,,,,,,15,,,,,,,,,,,,,,,,,,,547,14 -org.apache.commons.jexl2,15,,,,,,,,,,15,,,,,,,,,,,,,,,,,,,,,,,,,, -org.apache.commons.jexl3,15,,,,,,,,,,15,,,,,,,,,,,,,,,,,,,,,,,,,, -org.apache.commons.lang3,,,424,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,293,131 -org.apache.commons.logging,6,,,,,,,,,,,,,6,,,,,,,,,,,,,,,,,,,,,,, -org.apache.commons.ognl,6,,,,,,,,,,,,,,,6,,,,,,,,,,,,,,,,,,,,, -org.apache.commons.text,,,272,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,220,52 -org.apache.directory.ldap.client.api,1,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,,,,, -org.apache.hc.core5.function,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, -org.apache.hc.core5.http,1,2,39,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,,,2,39, -org.apache.hc.core5.net,,,2,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2, -org.apache.hc.core5.util,,,24,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,18,6 -org.apache.http,27,3,70,,,,,,,,,,,,,,25,,,,,,,,,,,,,,,2,,,3,62,8 -org.apache.ibatis.jdbc,6,,57,,,,,,,,,,,,,,,,,,,,,,,6,,,,,,,,,,57, -org.apache.log4j,11,,,,,,,,,,,,,11,,,,,,,,,,,,,,,,,,,,,,, -org.apache.logging.log4j,359,,8,,,,,,,,,,,359,,,,,,,,,,,,,,,,,,,,,,4,4 -org.apache.shiro.codec,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, -org.apache.shiro.jndi,1,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,,,,,, -org.codehaus.groovy.control,1,,,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -org.dom4j,20,,,,,,,,,,,,,,,,,,,,,,,,,,,,,20,,,,,,, -org.hibernate,7,,,,,,,,,,,,,,,,,,,,,,,,,7,,,,,,,,,,, -org.jboss.logging,324,,,,,,,,,,,,,324,,,,,,,,,,,,,,,,,,,,,,, -org.jdbi.v3.core,6,,,,,,,,,6,,,,,,,,,,,,,,,,,,,,,,,,,,, -org.jooq,1,,,,,,,,,,,,,,,,,,,,,,,,,1,,,,,,,,,,, -org.json,,,236,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,198,38 -org.mvel2,16,,,,,,,,,,,,,,16,,,,,,,,,,,,,,,,,,,,,, -org.scijava.log,13,,,,,,,,,,,,,13,,,,,,,,,,,,,,,,,,,,,,, -org.slf4j,55,,6,,,,,,,,,,,55,,,,,,,,,,,,,,,,,,,,,,2,4 -org.springframework.beans,,,30,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,30 -org.springframework.boot.jdbc,1,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,, -org.springframework.cache,,,13,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,13 -org.springframework.context,,,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3, -org.springframework.http,14,,70,,,,,,,,,,,,,,14,,,,,,,,,,,,,,,,,,,60,10 -org.springframework.jdbc.core,10,,,,,,,,,,,,,,,,,,,,,,,,,10,,,,,,,,,,, -org.springframework.jdbc.datasource,4,,,,,,,,,4,,,,,,,,,,,,,,,,,,,,,,,,,,, -org.springframework.jdbc.object,9,,,,,,,,,,,,,,,,,,,,,,,,,9,,,,,,,,,,, -org.springframework.jndi,1,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,,,,,, -org.springframework.ldap,47,,,,,,,,,,,33,14,,,,,,,,,,,,,,,,,,,,,,,, -org.springframework.security.web.savedrequest,,6,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,6,, -org.springframework.ui,,,32,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,32 -org.springframework.util,,,139,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,87,52 -org.springframework.validation,,,13,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,13, -org.springframework.web.client,13,3,,,,,,,,,,,,,,,13,,,,,,,,,,,,,,,,,,3,, -org.springframework.web.context.request,,8,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,8,, -org.springframework.web.multipart,,12,13,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,12,13, -org.springframework.web.reactive.function.client,2,,,,,,,,,,,,,,,,2,,,,,,,,,,,,,,,,,,,, -org.springframework.web.util,,,163,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,138,25 -org.xml.sax,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, -org.xmlpull.v1,,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3,, -play.mvc,,4,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,4,, -ratpack.core.form,,,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3, -ratpack.core.handling,,6,4,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,6,4, -ratpack.core.http,,10,10,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,10,10, -ratpack.exec,,,48,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,48 -ratpack.form,,,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3, -ratpack.func,,,35,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,35 -ratpack.handling,,6,4,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,6,4, -ratpack.http,,10,10,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,10,10, -ratpack.util,,,35,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,35 -retrofit2,1,,,,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,, +package,sink,source,summary,sink:bean-validation,sink:create-file,sink:groovy,sink:header-splitting,sink:information-leak,sink:intent-start,sink:jdbc-url,sink:jexl,sink:jndi-injection,sink:ldap,sink:logging,sink:mvel,sink:ognl-injection,sink:open-url,sink:pending-intent-sent,sink:regex-use[-1],sink:regex-use[0],sink:regex-use[],sink:regex-use[f-1],sink:regex-use[f1],sink:regex-use[f],sink:set-hostname-verifier,sink:sql,sink:url-open-stream,sink:url-redirect,sink:write-file,sink:xpath,sink:xslt,sink:xss,source:android-external-storage-dir,source:android-widget,source:contentprovider,source:remote,summary:taint,summary:value +android.app,16,,103,,,,,,7,,,,,,,,,9,,,,,,,,,,,,,,,,,,,18,85 +android.content,24,31,108,,,,,,16,,,,,,,,,,,,,,,,,8,,,,,,,4,,27,,31,77 +android.database,59,,30,,,,,,,,,,,,,,,,,,,,,,,59,,,,,,,,,,,30, +android.net,,,60,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,45,15 +android.os,,2,122,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,,,,41,81 +android.util,6,16,,,,,,,,,,,,6,,,,,,,,,,,,,,,,,,,,,,16,, +android.webkit,3,2,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3,,,,2,, +android.widget,,1,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,,,1, +androidx.slice,2,5,88,,,,,,,,,,,,,,,2,,,,,,,,,,,,,,,,,5,,27,61 +cn.hutool.core.codec,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, +com.esotericsoftware.kryo.io,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, +com.esotericsoftware.kryo5.io,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, +com.fasterxml.jackson.core,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, +com.fasterxml.jackson.databind,,,6,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,6, +com.google.common.base,4,,85,,,,,,,,,,,,,,,,,3,1,,,,,,,,,,,,,,,,62,23 +com.google.common.cache,,,17,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,17 +com.google.common.collect,,,553,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,551 +com.google.common.flogger,29,,,,,,,,,,,,,29,,,,,,,,,,,,,,,,,,,,,,,, +com.google.common.io,6,,73,,,,,,,,,,,,,,,,,,,,,,,,6,,,,,,,,,,72,1 +com.opensymphony.xwork2.ognl,3,,,,,,,,,,,,,,,3,,,,,,,,,,,,,,,,,,,,,, +com.rabbitmq.client,,21,7,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,21,7, +com.unboundid.ldap.sdk,17,,,,,,,,,,,,17,,,,,,,,,,,,,,,,,,,,,,,,, +com.zaxxer.hikari,2,,,,,,,,,2,,,,,,,,,,,,,,,,,,,,,,,,,,,, +flexjson,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1 +groovy.lang,26,,,,,26,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +groovy.util,5,,,,,5,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +jakarta.faces.context,2,7,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,,,,7,, +jakarta.json,,,123,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,100,23 +jakarta.ws.rs.client,1,,,,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,, +jakarta.ws.rs.container,,9,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,9,, +jakarta.ws.rs.core,2,,149,,,,,,,,,,,,,,,,,,,,,,,,,2,,,,,,,,,94,55 +java.beans,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, +java.io,37,,39,,15,,,,,,,,,,,,,,,,,,,,,,,,22,,,,,,,,39, +java.lang,13,,58,,,,,,,,,,,8,,,,,4,,,1,,,,,,,,,,,,,,,46,12 +java.net,10,3,7,,,,,,,,,,,,,,10,,,,,,,,,,,,,,,,,,,3,7, +java.nio,15,,6,,13,,,,,,,,,,,,,,,,,,,,,,,,2,,,,,,,,6, +java.sql,11,,,,,,,,,4,,,,,,,,,,,,,,,,7,,,,,,,,,,,, +java.util,44,,438,,,,,,,,,,,34,,,,,,5,2,,1,2,,,,,,,,,,,,,24,414 +javax.faces.context,2,7,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,,,,7,, +javax.jms,,9,57,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,9,57, +javax.json,,,123,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,100,23 +javax.management.remote,2,,,,,,,,,,,2,,,,,,,,,,,,,,,,,,,,,,,,,, +javax.naming,7,,,,,,,,,,,6,1,,,,,,,,,,,,,,,,,,,,,,,,, +javax.net.ssl,2,,,,,,,,,,,,,,,,,,,,,,,,2,,,,,,,,,,,,, +javax.script,1,,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,,,, +javax.servlet,4,21,2,,,,3,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,21,2, +javax.validation,1,1,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,, +javax.ws.rs.client,1,,,,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,, +javax.ws.rs.container,,9,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,9,, +javax.ws.rs.core,3,,149,,,,1,,,,,,,,,,,,,,,,,,,,,2,,,,,,,,,94,55 +javax.xml.transform,1,,6,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,,,,,,6, +javax.xml.xpath,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3,,,,,,,, +jodd.json,,,10,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,10 +kotlin.jvm.internal,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1 +net.sf.saxon.s9api,5,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,5,,,,,,, +ognl,6,,,,,,,,,,,,,,,6,,,,,,,,,,,,,,,,,,,,,, +okhttp3,2,,47,,,,,,,,,,,,,,2,,,,,,,,,,,,,,,,,,,,22,25 +org.apache.commons.codec,,,6,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,6, +org.apache.commons.collections,,,800,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,17,783 +org.apache.commons.collections4,,,800,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,17,783 +org.apache.commons.io,104,,561,,89,,,,,,,,,,,,15,,,,,,,,,,,,,,,,,,,,547,14 +org.apache.commons.jexl2,15,,,,,,,,,,15,,,,,,,,,,,,,,,,,,,,,,,,,,, +org.apache.commons.jexl3,15,,,,,,,,,,15,,,,,,,,,,,,,,,,,,,,,,,,,,, +org.apache.commons.lang3,,,424,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,293,131 +org.apache.commons.logging,6,,,,,,,,,,,,,6,,,,,,,,,,,,,,,,,,,,,,,, +org.apache.commons.ognl,6,,,,,,,,,,,,,,,6,,,,,,,,,,,,,,,,,,,,,, +org.apache.commons.text,,,272,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,220,52 +org.apache.directory.ldap.client.api,1,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,,,,,, +org.apache.hc.core5.function,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, +org.apache.hc.core5.http,1,2,39,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,,,,2,39, +org.apache.hc.core5.net,,,2,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2, +org.apache.hc.core5.util,,,24,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,18,6 +org.apache.http,27,3,70,,,,,,,,,,,,,,25,,,,,,,,,,,,,,,2,,,,3,62,8 +org.apache.ibatis.jdbc,6,,57,,,,,,,,,,,,,,,,,,,,,,,6,,,,,,,,,,,57, +org.apache.log4j,11,,,,,,,,,,,,,11,,,,,,,,,,,,,,,,,,,,,,,, +org.apache.logging.log4j,359,,8,,,,,,,,,,,359,,,,,,,,,,,,,,,,,,,,,,,4,4 +org.apache.shiro.codec,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, +org.apache.shiro.jndi,1,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,,,,,,, +org.codehaus.groovy.control,1,,,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +org.dom4j,20,,,,,,,,,,,,,,,,,,,,,,,,,,,,,20,,,,,,,, +org.hibernate,7,,,,,,,,,,,,,,,,,,,,,,,,,7,,,,,,,,,,,, +org.jboss.logging,324,,,,,,,,,,,,,324,,,,,,,,,,,,,,,,,,,,,,,, +org.jdbi.v3.core,6,,,,,,,,,6,,,,,,,,,,,,,,,,,,,,,,,,,,,, +org.jooq,1,,,,,,,,,,,,,,,,,,,,,,,,,1,,,,,,,,,,,, +org.json,,,236,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,198,38 +org.mvel2,16,,,,,,,,,,,,,,16,,,,,,,,,,,,,,,,,,,,,,, +org.scijava.log,13,,,,,,,,,,,,,13,,,,,,,,,,,,,,,,,,,,,,,, +org.slf4j,55,,6,,,,,,,,,,,55,,,,,,,,,,,,,,,,,,,,,,,2,4 +org.springframework.beans,,,30,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,30 +org.springframework.boot.jdbc,1,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,, +org.springframework.cache,,,13,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,13 +org.springframework.context,,,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3, +org.springframework.http,14,,70,,,,,,,,,,,,,,14,,,,,,,,,,,,,,,,,,,,60,10 +org.springframework.jdbc.core,10,,,,,,,,,,,,,,,,,,,,,,,,,10,,,,,,,,,,,, +org.springframework.jdbc.datasource,4,,,,,,,,,4,,,,,,,,,,,,,,,,,,,,,,,,,,,, +org.springframework.jdbc.object,9,,,,,,,,,,,,,,,,,,,,,,,,,9,,,,,,,,,,,, +org.springframework.jndi,1,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,,,,,,, +org.springframework.ldap,47,,,,,,,,,,,33,14,,,,,,,,,,,,,,,,,,,,,,,,, +org.springframework.security.web.savedrequest,,6,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,6,, +org.springframework.ui,,,32,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,32 +org.springframework.util,,,139,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,87,52 +org.springframework.validation,,,13,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,13, +org.springframework.web.client,13,3,,,,,,,,,,,,,,,13,,,,,,,,,,,,,,,,,,,3,, +org.springframework.web.context.request,,8,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,8,, +org.springframework.web.multipart,,12,13,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,12,13, +org.springframework.web.reactive.function.client,2,,,,,,,,,,,,,,,,2,,,,,,,,,,,,,,,,,,,,, +org.springframework.web.util,,,163,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,138,25 +org.xml.sax,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, +org.xmlpull.v1,,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3,, +play.mvc,,4,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,4,, +ratpack.core.form,,,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3, +ratpack.core.handling,,6,4,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,6,4, +ratpack.core.http,,10,10,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,10,10, +ratpack.exec,,,48,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,48 +ratpack.form,,,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3, +ratpack.func,,,35,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,35 +ratpack.handling,,6,4,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,6,4, +ratpack.http,,10,10,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,10,10, +ratpack.util,,,35,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,35 +retrofit2,1,,,,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,, diff --git a/java/documentation/library-coverage/coverage.rst b/java/documentation/library-coverage/coverage.rst index cd8995b77d5..7b45a3115b1 100644 --- a/java/documentation/library-coverage/coverage.rst +++ b/java/documentation/library-coverage/coverage.rst @@ -7,7 +7,7 @@ Java framework & library support :widths: auto Framework / library,Package,Flow sources,Taint & value steps,Sinks (total),`CWE‑022` :sub:`Path injection`,`CWE‑036` :sub:`Path traversal`,`CWE‑079` :sub:`Cross-site scripting`,`CWE‑089` :sub:`SQL injection`,`CWE‑090` :sub:`LDAP injection`,`CWE‑094` :sub:`Code injection`,`CWE‑319` :sub:`Cleartext transmission` - Android,``android.*``,46,424,108,,,3,67,,, + Android,``android.*``,52,424,108,,,3,67,,, `Apache Commons Collections `_,"``org.apache.commons.collections``, ``org.apache.commons.collections4``",,1600,,,,,,,, `Apache Commons IO `_,``org.apache.commons.io``,,561,104,89,,,,,,15 `Apache Commons Lang `_,``org.apache.commons.lang3``,,424,,,,,,,, @@ -19,5 +19,5 @@ Java framework & library support Java extensions,"``javax.*``, ``jakarta.*``",63,609,32,,,4,,1,1,2 `Spring `_,``org.springframework.*``,29,476,101,,,,19,14,,29 Others,"``androidx.slice``, ``cn.hutool.core.codec``, ``com.esotericsoftware.kryo.io``, ``com.esotericsoftware.kryo5.io``, ``com.fasterxml.jackson.core``, ``com.fasterxml.jackson.databind``, ``com.opensymphony.xwork2.ognl``, ``com.rabbitmq.client``, ``com.unboundid.ldap.sdk``, ``com.zaxxer.hikari``, ``flexjson``, ``groovy.lang``, ``groovy.util``, ``jodd.json``, ``kotlin.jvm.internal``, ``net.sf.saxon.s9api``, ``ognl``, ``okhttp3``, ``org.apache.commons.codec``, ``org.apache.commons.jexl2``, ``org.apache.commons.jexl3``, ``org.apache.commons.logging``, ``org.apache.commons.ognl``, ``org.apache.directory.ldap.client.api``, ``org.apache.ibatis.jdbc``, ``org.apache.log4j``, ``org.apache.logging.log4j``, ``org.apache.shiro.codec``, ``org.apache.shiro.jndi``, ``org.codehaus.groovy.control``, ``org.dom4j``, ``org.hibernate``, ``org.jboss.logging``, ``org.jdbi.v3.core``, ``org.jooq``, ``org.mvel2``, ``org.scijava.log``, ``org.slf4j``, ``org.xml.sax``, ``org.xmlpull.v1``, ``play.mvc``, ``ratpack.core.form``, ``ratpack.core.handling``, ``ratpack.core.http``, ``ratpack.exec``, ``ratpack.form``, ``ratpack.func``, ``ratpack.handling``, ``ratpack.http``, ``ratpack.util``, ``retrofit2``",65,395,932,,,,14,18,,3 - Totals,,211,6410,1474,117,6,10,107,33,1,84 + Totals,,217,6410,1474,117,6,10,107,33,1,84 diff --git a/java/kotlin-extractor/build.gradle b/java/kotlin-extractor/build.gradle index a4bf5748c29..3926962fd3d 100644 --- a/java/kotlin-extractor/build.gradle +++ b/java/kotlin-extractor/build.gradle @@ -35,8 +35,8 @@ sourceSets { "utils/versions/v_1_5_21/*.kt", "utils/versions/v_1_5_31/*.kt", "utils/versions/v_1_6_10/*.kt", - "utils/versions/v_1_7_0-RC/*.kt", - // "utils/versions/v_1_6_20/*.kt", + "utils/versions/v_1_6_20/*.kt", + // "utils/versions/v_1_7_0/*.kt", ] } } diff --git a/java/kotlin-extractor/gradle.properties b/java/kotlin-extractor/gradle.properties index 69e0a36ba4c..16f621c2d74 100644 --- a/java/kotlin-extractor/gradle.properties +++ b/java/kotlin-extractor/gradle.properties @@ -1,5 +1,5 @@ kotlin.code.style=official -kotlinVersion=1.6.20 +kotlinVersion=1.7.0 GROUP=com.github.codeql VERSION_NAME=0.0.1 diff --git a/java/kotlin-extractor/kotlin_plugin_versions.py b/java/kotlin-extractor/kotlin_plugin_versions.py index bd60c019236..e84764dbefc 100755 --- a/java/kotlin-extractor/kotlin_plugin_versions.py +++ b/java/kotlin-extractor/kotlin_plugin_versions.py @@ -21,7 +21,7 @@ def version_string_to_tuple(version): m = re.match(r'([0-9]+)\.([0-9]+)\.([0-9]+)(.*)', version) return tuple([int(m.group(i)) for i in range(1, 4)] + [m.group(4)]) -many_versions = [ '1.4.32', '1.5.0', '1.5.10', '1.5.21', '1.5.31', '1.6.10', '1.7.0-RC', '1.6.20' ] +many_versions = [ '1.4.32', '1.5.0', '1.5.10', '1.5.21', '1.5.31', '1.6.10', '1.6.20', '1.7.0' ] many_versions_tuples = [version_string_to_tuple(v) for v in many_versions] diff --git a/java/kotlin-extractor/src/main/kotlin/ExternalDeclExtractor.kt b/java/kotlin-extractor/src/main/kotlin/ExternalDeclExtractor.kt index 5edb16271c1..b1b2823b6b5 100644 --- a/java/kotlin-extractor/src/main/kotlin/ExternalDeclExtractor.kt +++ b/java/kotlin-extractor/src/main/kotlin/ExternalDeclExtractor.kt @@ -6,9 +6,11 @@ import com.semmle.extractor.java.OdasaOutput import com.semmle.util.data.StringDigestor import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable import org.jetbrains.kotlin.ir.util.isFileClass import org.jetbrains.kotlin.ir.util.packageFqName import org.jetbrains.kotlin.ir.util.parentClassOrNull +import org.jetbrains.kotlin.name.FqName import java.io.File import java.util.ArrayList import java.util.HashSet @@ -16,18 +18,20 @@ import java.util.zip.GZIPOutputStream class ExternalDeclExtractor(val logger: FileLogger, val invocationTrapFile: String, val sourceFilePath: String, val primitiveTypeMapping: PrimitiveTypeMapping, val pluginContext: IrPluginContext, val globalExtensionState: KotlinExtractorGlobalState, val diagnosticTrapWriter: TrapWriter) { - val externalDeclsDone = HashSet() + val declBinaryNames = HashMap() + val externalDeclsDone = HashSet>() val externalDeclWorkList = ArrayList>() val propertySignature = ";property" val fieldSignature = ";field" - fun extractLater(d: IrDeclaration, signature: String): Boolean { + fun extractLater(d: IrDeclarationWithName, signature: String): Boolean { if (d !is IrClass && !isExternalFileClassMember(d)) { logger.errorElement("External declaration is neither a class, nor a top-level declaration", d) return false } - val ret = externalDeclsDone.add(d) + val declBinaryName = declBinaryNames.getOrPut(d) { getIrDeclBinaryName(d) } + val ret = externalDeclsDone.add(Pair(declBinaryName, signature)) if (ret) externalDeclWorkList.add(Pair(d, signature)) return ret } diff --git a/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt b/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt index 743c04bd33f..21b35fbcdd1 100644 --- a/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt +++ b/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt @@ -6,6 +6,7 @@ import com.github.codeql.utils.versions.functionN import com.github.codeql.utils.versions.getIrStubFromDescriptor import com.semmle.extractor.java.OdasaOutput import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext +import org.jetbrains.kotlin.backend.common.lower.parents import org.jetbrains.kotlin.backend.common.pop import org.jetbrains.kotlin.builtins.functions.BuiltInFunctionArity import org.jetbrains.kotlin.descriptors.* @@ -41,7 +42,7 @@ open class KotlinFileExtractor( globalExtensionState: KotlinExtractorGlobalState ): KotlinUsesExtractor(logger, tw, dependencyCollector, externalClassExtractor, primitiveTypeMapping, pluginContext, globalExtensionState) { - inline fun with(kind: String, element: IrElement, f: () -> T): T { + private inline fun with(kind: String, element: IrElement, f: () -> T): T { val name = when (element) { is IrFile -> element.name is IrDeclarationWithName -> element.name.asString() @@ -80,12 +81,13 @@ open class KotlinFileExtractor( } } - file.declarations.map { extractDeclaration(it, extractPrivateMembers = true, extractFunctionBodies = true) } + file.declarations.forEach { extractDeclaration(it, extractPrivateMembers = true, extractFunctionBodies = true) } extractStaticInitializer(file, null) CommentExtractor(this, file, tw.fileId).extract() } } + @OptIn(ObsoleteDescriptorBasedAPI::class) private fun isFake(d: IrDeclarationWithVisibility): Boolean { val visibility = d.visibility if (visibility is DelegatedDescriptorVisibility && visibility.delegate == Visibilities.InvisibleFake) { @@ -94,6 +96,9 @@ open class KotlinFileExtractor( if (d.isFakeOverride) { return true } + if ((d as? IrFunction)?.descriptor?.isHiddenToOvercomeSignatureClash == true) { + return true + } return false } @@ -177,7 +182,7 @@ open class KotlinFileExtractor( } } - fun extractTypeParameter(tp: IrTypeParameter, apparentIndex: Int, javaTypeParameter: JavaTypeParameter?): Label? { + private fun extractTypeParameter(tp: IrTypeParameter, apparentIndex: Int, javaTypeParameter: JavaTypeParameter?): Label? { with("type parameter", tp) { val parentId = getTypeParameterParentLabel(tp) ?: return null val id = tw.getLabelFor(getTypeParameterLabel(tp)) @@ -212,7 +217,7 @@ open class KotlinFileExtractor( } } - fun extractVisibility(elementForLocation: IrElement, id: Label, v: DescriptorVisibility) { + private fun extractVisibility(elementForLocation: IrElement, id: Label, v: DescriptorVisibility) { with("visibility", elementForLocation) { when (v) { DescriptorVisibilities.PRIVATE -> addModifiers(id, "private") @@ -246,7 +251,7 @@ open class KotlinFileExtractor( } } - fun extractClassModifiers(c: IrClass, id: Label) { + private fun extractClassModifiers(c: IrClass, id: Label) { with("class modifiers", c) { when (c.modality) { Modality.FINAL -> addModifiers(id, "final") @@ -310,8 +315,21 @@ open class KotlinFileExtractor( val locId = getLocation(c, argsIncludingOuterClasses) tw.writeHasLocation(id, locId) - // Extract the outer <-> inner class relationship, passing on any type arguments in excess to this class' parameters. - extractEnclosingClass(c, id, locId, argsIncludingOuterClasses?.drop(c.typeParameters.size) ?: listOf()) + // Extract the outer <-> inner class relationship, passing on any type arguments in excess to this class' parameters if this is an inner class. + // For example, in `class Outer { inner class Inner { } }`, `Inner` nests within `Outer` and raw `Inner<>` within `Outer<>`, + // but for a similar non-`inner` (in Java terms, static nested) class both `Inner` and `Inner<>` nest within the unbound type `Outer`. + val useBoundOuterType = (c.isInner || c.isLocal) && (c.parents.map { // Would use `firstNotNullOfOrNull`, but this doesn't exist in Kotlin 1.4 + when(it) { + is IrClass -> when { + it.typeParameters.isNotEmpty() -> true // Type parameters visible to this class -- extract an enclosing bound or raw type. + !(it.isInner || it.isLocal) -> false // No type parameters seen yet, and this is a static class -- extract an enclosing unbound type. + else -> null // No type parameters seen here, but may be visible enclosing type parameters; keep searching. + } + else -> null // Look through enclosing non-class entities (this may need to change) + } + }.firstOrNull { it != null } ?: false) + + extractEnclosingClass(c, id, locId, if (useBoundOuterType) argsIncludingOuterClasses?.drop(c.typeParameters.size) else listOf()) return id } @@ -367,6 +385,29 @@ open class KotlinFileExtractor( tw.writeHasLocation(stmtId, locId) } + private fun extractObinitFunction(c: IrClass, parentId: Label) { + // add method: + val obinitLabel = getObinitLabel(c) + val obinitId = tw.getLabelFor(obinitLabel) + val returnType = useType(pluginContext.irBuiltIns.unitType, TypeContext.RETURN) + tw.writeMethods(obinitId, "", "()", returnType.javaResult.id, parentId, obinitId) + tw.writeMethodsKotlinType(obinitId, returnType.kotlinResult.id) + + val locId = tw.getLocation(c) + tw.writeHasLocation(obinitId, locId) + + addModifiers(obinitId, "private") + + // add body: + val blockId = tw.getFreshIdLabel() + tw.writeStmts_block(blockId, obinitId, 0, obinitId) + tw.writeHasLocation(blockId, locId) + + extractDeclInitializers(c.declarations, false) { Pair(blockId, obinitId) } + } + + val jvmStaticFqName = FqName("kotlin.jvm.JvmStatic") + fun extractClassSource(c: IrClass, extractDeclarations: Boolean, extractStaticInitializer: Boolean, extractPrivateMembers: Boolean, extractFunctionBodies: Boolean): Label { with("class source", c) { DeclarationStackAdjuster(c).use { @@ -403,9 +444,10 @@ open class KotlinFileExtractor( c.typeParameters.mapIndexed { idx, param -> extractTypeParameter(param, idx, javaClass?.typeParameters?.getOrNull(idx)) } if (extractDeclarations) { - c.declarations.map { extractDeclaration(it, extractPrivateMembers = extractPrivateMembers, extractFunctionBodies = extractFunctionBodies) } + c.declarations.forEach { extractDeclaration(it, extractPrivateMembers = extractPrivateMembers, extractFunctionBodies = extractFunctionBodies) } if (extractStaticInitializer) extractStaticInitializer(c, id) + extractJvmStaticProxyMethods(c, id, extractPrivateMembers, extractFunctionBodies) } if (c.isNonCompanionObject) { // For `object MyObject { ... }`, the .class has an @@ -421,6 +463,9 @@ open class KotlinFileExtractor( addModifiers(instance.id, "public", "static", "final") tw.writeClass_object(id.cast(), instance.id) } + if (extractFunctionBodies && needsObinitFunction(c)) { + extractObinitFunction(c, id) + } extractClassModifiers(c, id) extractClassSupertypes(c, id, inReceiverContext = true) // inReceiverContext = true is specified to force extraction of member prototypes of base types @@ -430,7 +475,78 @@ open class KotlinFileExtractor( } } - private fun extractEnclosingClass(innerDeclaration: IrDeclaration, innerId: Label, innerLocId: Label, parentClassTypeArguments: List) { + private fun extractJvmStaticProxyMethods(c: IrClass, classId: Label, extractPrivateMembers: Boolean, extractFunctionBodies: Boolean) { + + // Add synthetic forwarders for any JvmStatic methods or properties: + val companionObject = c.companionObject() ?: return + + val cType = c.typeWith() + val companionType = companionObject.typeWith() + + fun makeProxyFunction(f: IrFunction) { + // Emit a function in class `c` that delegates to the same function defined on `c.CompanionInstance`. + val proxyFunctionId = tw.getLabelFor(getFunctionLabel(f, classId, listOf())) + // We extract the function prototype with its ID overridden to belong to `c` not the companion object, + // but suppress outputting the body, which we will replace with a delegating call below. + forceExtractFunction(f, classId, extractBody = false, extractMethodAndParameterTypeAccesses = extractFunctionBodies, typeSubstitution = null, classTypeArgsIncludingOuterClasses = listOf(), idOverride = proxyFunctionId, locOverride = null, extractOrigin = false) + addModifiers(proxyFunctionId, "static") + tw.writeCompiler_generated(proxyFunctionId, CompilerGeneratedKinds.JVMSTATIC_PROXY_METHOD.kind) + if (extractFunctionBodies) { + val realFunctionLocId = tw.getLocation(f) + extractExpressionBody(proxyFunctionId, realFunctionLocId).also { returnId -> + extractRawMethodAccess( + f, + realFunctionLocId, + f.returnType, + proxyFunctionId, + returnId, + 0, + returnId, + f.valueParameters.size, + { argParent, idxOffset -> + f.valueParameters.forEachIndexed { idx, param -> + val syntheticParamId = useValueParameter(param, proxyFunctionId) + extractVariableAccess(syntheticParamId, param.type, realFunctionLocId, argParent, idxOffset + idx, proxyFunctionId, returnId) + } + }, + companionType, + { callId -> + val companionField = useCompanionObjectClassInstance(companionObject)?.id + extractVariableAccess(companionField, companionType, realFunctionLocId, callId, -1, proxyFunctionId, returnId).also { varAccessId -> + extractTypeAccessRecursive(cType, realFunctionLocId, varAccessId, -1, proxyFunctionId, returnId) + } + }, + null + ) + } + } + } + + companionObject.declarations.forEach { + if (shouldExtractDecl(it, extractPrivateMembers)) { + val wholeDeclAnnotated = it.hasAnnotation(jvmStaticFqName) + when(it) { + is IrFunction -> { + if (wholeDeclAnnotated) + makeProxyFunction(it) + } + is IrProperty -> { + it.getter?.let { getter -> + if (wholeDeclAnnotated || getter.hasAnnotation(jvmStaticFqName)) + makeProxyFunction(getter) + } + it.setter?.let { setter -> + if (wholeDeclAnnotated || setter.hasAnnotation(jvmStaticFqName)) + makeProxyFunction(setter) + } + } + } + } + } + } + + // If `parentClassTypeArguments` is null, the parent class is a raw type. + private fun extractEnclosingClass(innerDeclaration: IrDeclaration, innerId: Label, innerLocId: Label, parentClassTypeArguments: List?) { with("enclosing class", innerDeclaration) { var parent: IrDeclarationParent? = innerDeclaration.parent while (parent != null) { @@ -478,7 +594,7 @@ open class KotlinFileExtractor( data class FieldResult(val id: Label, val name: String) - fun useCompanionObjectClassInstance(c: IrClass): FieldResult? { + private fun useCompanionObjectClassInstance(c: IrClass): FieldResult? { val parent = c.parent if(!c.isCompanion) { logger.error("Using companion instance for non-companion class") @@ -496,7 +612,7 @@ open class KotlinFileExtractor( } } - fun useObjectClassInstance(c: IrClass): FieldResult { + private fun useObjectClassInstance(c: IrClass): FieldResult { if(!c.isNonCompanionObject) { logger.error("Using instance for non-object class") } @@ -567,6 +683,8 @@ open class KotlinFileExtractor( tw.writeMethods(clinitId, "", "()", returnType.javaResult.id, parentId, clinitId) tw.writeMethodsKotlinType(clinitId, returnType.kotlinResult.id) + tw.writeCompiler_generated(clinitId, CompilerGeneratedKinds.CLASS_INITIALISATION_METHOD.kind) + val locId = tw.getWholeFileLocation() tw.writeHasLocation(clinitId, locId) @@ -689,13 +807,13 @@ open class KotlinFileExtractor( } } - fun extractFunction(f: IrFunction, parentId: Label, extractBody: Boolean, extractMethodAndParameterTypeAccesses: Boolean, typeSubstitution: TypeSubstitution?, classTypeArgsIncludingOuterClasses: List?) = + private fun extractFunction(f: IrFunction, parentId: Label, extractBody: Boolean, extractMethodAndParameterTypeAccesses: Boolean, typeSubstitution: TypeSubstitution?, classTypeArgsIncludingOuterClasses: List?) = if (isFake(f)) null else forceExtractFunction(f, parentId, extractBody, extractMethodAndParameterTypeAccesses, typeSubstitution, classTypeArgsIncludingOuterClasses, null, null) - fun forceExtractFunction(f: IrFunction, parentId: Label, extractBody: Boolean, extractMethodAndParameterTypeAccesses: Boolean, typeSubstitution: TypeSubstitution?, classTypeArgsIncludingOuterClasses: List?, idOverride: Label?, locOverride: Label?): Label { + private fun forceExtractFunction(f: IrFunction, parentId: Label, extractBody: Boolean, extractMethodAndParameterTypeAccesses: Boolean, typeSubstitution: TypeSubstitution?, classTypeArgsIncludingOuterClasses: List?, idOverride: Label?, locOverride: Label?, extractOrigin: Boolean = true): Label { with("function", f) { DeclarationStackAdjuster(f).use { @@ -704,12 +822,9 @@ open class KotlinFileExtractor( val id = idOverride - ?: if (f.isLocalFunction()) - getLocallyVisibleFunctionLabels(f).function - else - // If this is a class that would ordinarily be replaced by a Java equivalent (e.g. kotlin.Map -> java.util.Map), - // don't replace here, really extract the Kotlin version: - useFunction(f, parentId, classTypeArgsIncludingOuterClasses, noReplace = true) + ?: // If this is a class that would ordinarily be replaced by a Java equivalent (e.g. kotlin.Map -> java.util.Map), + // don't replace here, really extract the Kotlin version: + useFunction(f, parentId, classTypeArgsIncludingOuterClasses, noReplace = true) val sourceDeclaration = if (typeSubstitution != null && idOverride == null) @@ -755,6 +870,16 @@ open class KotlinFileExtractor( val methodId = id.cast() tw.writeMethods(methodId, shortName.nameInDB, "${shortName.nameInDB}$paramsSignature", returnType.javaResult.id, parentId, sourceDeclaration.cast()) tw.writeMethodsKotlinType(methodId, returnType.kotlinResult.id) + if (extractOrigin) { + when (f.origin) { + IrDeclarationOrigin.GENERATED_DATA_CLASS_MEMBER -> + tw.writeCompiler_generated(methodId, CompilerGeneratedKinds.GENERATED_DATA_CLASS_MEMBER.kind) + IrDeclarationOrigin.DEFAULT_PROPERTY_ACCESSOR -> + tw.writeCompiler_generated(methodId, CompilerGeneratedKinds.DEFAULT_PROPERTY_ACCESSOR.kind) + IrDeclarationOrigin.ENUM_CLASS_SPECIAL_MEMBER -> + tw.writeCompiler_generated(methodId, CompilerGeneratedKinds.ENUM_CLASS_SPECIAL_MEMBER.kind) + } + } if (extractMethodAndParameterTypeAccesses) { extractTypeAccessRecursive(substReturnType, locId, id, -1) @@ -774,10 +899,13 @@ open class KotlinFileExtractor( } extractVisibility(f, id, f.visibility) - if (isStaticFunction(f)) { + + if (f.isInline) { + addModifiers(id, "inline") + } + if (f.shouldExtractAsStatic) { addModifiers(id, "static") } - if (f is IrSimpleFunction && f.overriddenSymbols.isNotEmpty()) { addModifiers(id, "override") } @@ -793,7 +921,7 @@ open class KotlinFileExtractor( && f.symbol !is IrConstructorSymbol // not a constructor } - fun extractField(f: IrField, parentId: Label): Label { + private fun extractField(f: IrField, parentId: Label): Label { with("field", f) { DeclarationStackAdjuster(f).use { declarationStack.push(f) @@ -827,7 +955,7 @@ open class KotlinFileExtractor( return id } - fun extractProperty(p: IrProperty, parentId: Label, extractBackingField: Boolean, extractFunctionBodies: Boolean, typeSubstitution: TypeSubstitution?, classTypeArgsIncludingOuterClasses: List?) { + private fun extractProperty(p: IrProperty, parentId: Label, extractBackingField: Boolean, extractFunctionBodies: Boolean, typeSubstitution: TypeSubstitution?, classTypeArgsIncludingOuterClasses: List?) { with("property", p) { if (isFake(p)) return @@ -846,6 +974,9 @@ open class KotlinFileExtractor( val getterId = extractFunction(getter, parentId, extractBody = extractFunctionBodies, extractMethodAndParameterTypeAccesses = extractFunctionBodies, typeSubstitution, classTypeArgsIncludingOuterClasses)?.cast() if (getterId != null) { tw.writeKtPropertyGetters(id, getterId) + if (getter.origin == IrDeclarationOrigin.DELEGATED_PROPERTY_ACCESSOR) { + tw.writeCompiler_generated(getterId, CompilerGeneratedKinds.DELEGATED_PROPERTY_GETTER.kind) + } } } else { if (p.modality != Modality.FINAL || !isExternalDeclaration(p)) { @@ -860,6 +991,9 @@ open class KotlinFileExtractor( val setterId = extractFunction(setter, parentId, extractBody = extractFunctionBodies, extractMethodAndParameterTypeAccesses = extractFunctionBodies, typeSubstitution, classTypeArgsIncludingOuterClasses)?.cast() if (setterId != null) { tw.writeKtPropertySetters(id, setterId) + if (setter.origin == IrDeclarationOrigin.DELEGATED_PROPERTY_ACCESSOR) { + tw.writeCompiler_generated(setterId, CompilerGeneratedKinds.DELEGATED_PROPERTY_SETTER.kind) + } } } else { if (p.isVar && !isExternalDeclaration(p)) { @@ -896,7 +1030,7 @@ open class KotlinFileExtractor( } } - fun extractEnumEntry(ee: IrEnumEntry, parentId: Label, extractTypeAccess: Boolean) { + private fun extractEnumEntry(ee: IrEnumEntry, parentId: Label, extractTypeAccess: Boolean) { with("enum entry", ee) { DeclarationStackAdjuster(ee).use { val id = useEnumEntry(ee) @@ -918,7 +1052,7 @@ open class KotlinFileExtractor( } } - fun extractTypeAlias(ta: IrTypeAlias) { + private fun extractTypeAlias(ta: IrTypeAlias) { with("type alias", ta) { if (ta.typeParameters.isNotEmpty()) { // TODO: Extract this information @@ -933,7 +1067,7 @@ open class KotlinFileExtractor( } } - fun extractBody(b: IrBody, callable: Label) { + private fun extractBody(b: IrBody, callable: Label) { with("body", b) { when (b) { is IrBlockBody -> extractBlockBody(b, callable) @@ -946,7 +1080,7 @@ open class KotlinFileExtractor( } } - fun extractBlockBody(b: IrBlockBody, callable: Label) { + private fun extractBlockBody(b: IrBlockBody, callable: Label) { with("block body", b) { val id = tw.getFreshIdLabel() val locId = tw.getLocation(b) @@ -958,7 +1092,7 @@ open class KotlinFileExtractor( } } - fun extractSyntheticBody(b: IrSyntheticBody, callable: Label) { + private fun extractSyntheticBody(b: IrSyntheticBody, callable: Label) { with("synthetic body", b) { when (b.kind) { IrSyntheticBodyKind.ENUM_VALUES -> tw.writeKtSyntheticBody(callable, 1) @@ -967,17 +1101,23 @@ open class KotlinFileExtractor( } } - fun extractExpressionBody(b: IrExpressionBody, callable: Label) { + private fun extractExpressionBody(b: IrExpressionBody, callable: Label) { with("expression body", b) { - val blockId = tw.getFreshIdLabel() val locId = tw.getLocation(b) - tw.writeStmts_block(blockId, callable, 0, callable) - tw.writeHasLocation(blockId, locId) + extractExpressionBody(callable, locId).also { returnId -> + extractExpressionExpr(b.expression, callable, returnId, 0, returnId) + } + } + } - val returnId = tw.getFreshIdLabel() + fun extractExpressionBody(callable: Label, locId: Label): Label { + val blockId = tw.getFreshIdLabel() + tw.writeStmts_block(blockId, callable, 0, callable) + tw.writeHasLocation(blockId, locId) + + return tw.getFreshIdLabel().also { returnId -> tw.writeStmts_returnstmt(returnId, blockId, 0, callable) tw.writeHasLocation(returnId, locId) - extractExpressionExpr(b.expression, callable, returnId, 0, returnId) } } @@ -991,7 +1131,7 @@ open class KotlinFileExtractor( return v } - fun extractVariable(v: IrVariable, callable: Label, parent: Label, idx: Int) { + private fun extractVariable(v: IrVariable, callable: Label, parent: Label, idx: Int) { with("variable", v) { val stmtId = tw.getFreshIdLabel() val locId = tw.getLocation(getVariableLocationProvider(v)) @@ -1001,7 +1141,7 @@ open class KotlinFileExtractor( } } - fun extractVariableExpr(v: IrVariable, callable: Label, parent: Label, idx: Int, enclosingStmt: Label) { + private fun extractVariableExpr(v: IrVariable, callable: Label, parent: Label, idx: Int, enclosingStmt: Label) { with("variable expr", v) { val varId = useVariable(v) val exprId = tw.getFreshIdLabel() @@ -1025,7 +1165,7 @@ open class KotlinFileExtractor( } } - fun extractStatement(s: IrStatement, callable: Label, parent: Label, idx: Int) { + private fun extractStatement(s: IrStatement, callable: Label, parent: Label, idx: Int) { with("statement", s) { when(s) { is IrExpression -> { @@ -1045,7 +1185,7 @@ open class KotlinFileExtractor( tw.writeKtLocalFunction(ids.function) if (s.origin == IrDeclarationOrigin.ADAPTER_FOR_CALLABLE_REFERENCE) { - tw.writeCompiler_generated(classId, 1) + tw.writeCompiler_generated(classId, CompilerGeneratedKinds.DECLARING_CLASSES_OF_ADAPTER_FUNCTIONS.kind) } } else { logger.errorElement("Expected to find local function", s) @@ -1248,10 +1388,48 @@ open class KotlinFileExtractor( typeArguments: List = listOf(), extractClassTypeArguments: Boolean = false) { + val locId = tw.getLocation(callsite) + + extractRawMethodAccess( + syntacticCallTarget, + locId, + callsite.type, + enclosingCallable, + callsiteParent, + childIdx, + enclosingStmt, + valueArguments.size, + { argParent, idxOffset -> extractCallValueArguments(argParent, valueArguments, enclosingStmt, enclosingCallable, idxOffset) }, + dispatchReceiver?.type, + dispatchReceiver?.let { { callId -> extractExpressionExpr(dispatchReceiver, enclosingCallable, callId, -1, enclosingStmt) } }, + extensionReceiver?.let { { argParent -> extractExpressionExpr(extensionReceiver, enclosingCallable, argParent, 0, enclosingStmt) } }, + typeArguments, + extractClassTypeArguments + ) + + } + + + fun extractRawMethodAccess( + syntacticCallTarget: IrFunction, + locId: Label, + returnType: IrType, + enclosingCallable: Label, + callsiteParent: Label, + childIdx: Int, + enclosingStmt: Label, + nValueArguments: Int, + extractValueArguments: (Label, Int) -> Unit, + drType: IrType?, + extractDispatchReceiver: ((Label) -> Unit)?, + extractExtensionReceiver: ((Label) -> Unit)?, + typeArguments: List = listOf(), + extractClassTypeArguments: Boolean = false) { + val callTarget = syntacticCallTarget.target.realOverrideTarget val id = tw.getFreshIdLabel() - val type = useType(callsite.type) - val locId = tw.getLocation(callsite) + val type = useType(returnType) + tw.writeExprs_methodaccess(id, type.javaResult.id, callsiteParent, childIdx) tw.writeExprsKotlinType(id, type.kotlinResult.id) tw.writeHasLocation(id, locId) @@ -1261,8 +1439,6 @@ open class KotlinFileExtractor( // type arguments at index -2, -3, ... extractTypeArguments(typeArguments, locId, id, enclosingCallable, enclosingStmt, -2, true) - val drType = dispatchReceiver?.type - val isFunctionInvoke = drType != null && drType is IrSimpleType && drType.isFunctionOrKFunction() @@ -1305,44 +1481,48 @@ open class KotlinFileExtractor( tw.writeCallableBinding(id, methodId) - if (dispatchReceiver != null) { - extractExpressionExpr(dispatchReceiver, enclosingCallable, id, -1, enclosingStmt) - } else if (isStaticFunction(callTarget)) { + if (callTarget.shouldExtractAsStatic) { extractStaticTypeAccessQualifier(callTarget, id, locId, enclosingCallable, enclosingStmt) + } else if (extractDispatchReceiver != null) { + extractDispatchReceiver(id) } } - val idxOffset = if (extensionReceiver != null) 1 else 0 + val idxOffset = if (extractExtensionReceiver != null) 1 else 0 val argParent = if (isBigArityFunctionInvoke) { - extractArrayCreationWithInitializer(id, valueArguments.size + idxOffset, locId, enclosingCallable, enclosingStmt) + extractArrayCreationWithInitializer(id, nValueArguments + idxOffset, locId, enclosingCallable, enclosingStmt) } else { id } - if (extensionReceiver != null) { - extractExpressionExpr(extensionReceiver, enclosingCallable, argParent, 0, enclosingStmt) + if (extractExtensionReceiver != null) { + extractExtensionReceiver(argParent) } - extractCallValueArguments(argParent, valueArguments, enclosingStmt, enclosingCallable, idxOffset) + extractValueArguments(argParent, idxOffset) } private fun extractStaticTypeAccessQualifier(target: IrDeclaration, parentExpr: Label, locId: Label, enclosingCallable: Label, enclosingStmt: Label) { - if (target.isStaticOfClass) { + if (target.shouldExtractAsStaticMemberOfClass) { extractTypeAccessRecursive(target.parentAsClass.toRawType(), locId, parentExpr, -1, enclosingCallable, enclosingStmt) - } else if (target.isStaticOfFile) { + } else if (target.shouldExtractAsStaticMemberOfFile) { extractTypeAccess(useFileClassType(target.parent as IrFile), locId, parentExpr, -1, enclosingCallable, enclosingStmt) } } - private val IrDeclaration.isStaticOfClass: Boolean - get() = this.isStatic && parent is IrClass + private val IrDeclaration.shouldExtractAsStaticMemberOfClass: Boolean + get() = this.shouldExtractAsStatic && parent is IrClass - private val IrDeclaration.isStaticOfFile: Boolean - get() = this.isStatic && parent is IrFile + private val IrDeclaration.shouldExtractAsStaticMemberOfFile: Boolean + get() = this.shouldExtractAsStatic && parent is IrFile - private val IrDeclaration.isStatic: Boolean - get() = this is IrSimpleFunction && dispatchReceiverParameter == null || + private fun isStaticAnnotatedNonCompanionMember(f: IrSimpleFunction) = + f.parentClassOrNull?.isNonCompanionObject == true && + (f.hasAnnotation(jvmStaticFqName) || f.correspondingPropertySymbol?.owner?.hasAnnotation(jvmStaticFqName) == true) + + private val IrDeclaration.shouldExtractAsStatic: Boolean + get() = this is IrSimpleFunction && (isStaticFunction(this) || isStaticAnnotatedNonCompanionMember(this)) || this is IrField && this.isStatic || this is IrEnumEntry @@ -1364,7 +1544,7 @@ open class KotlinFileExtractor( } } - fun findFunction(cls: IrClass, name: String): IrFunction? = cls.declarations.find { it is IrFunction && it.name.asString() == name } as IrFunction? + private fun findFunction(cls: IrClass, name: String): IrFunction? = cls.declarations.find { it is IrFunction && it.name.asString() == name } as IrFunction? val jvmIntrinsicsClass by lazy { val result = pluginContext.referenceClass(FqName("kotlin.jvm.internal.Intrinsics"))?.owner @@ -1372,7 +1552,7 @@ open class KotlinFileExtractor( result } - fun findJdkIntrinsicOrWarn(name: String, warnAgainstElement: IrElement): IrFunction? { + private fun findJdkIntrinsicOrWarn(name: String, warnAgainstElement: IrElement): IrFunction? { val result = jvmIntrinsicsClass?.let { findFunction(it, name) } if(result == null) { logger.errorElement("Couldn't find JVM intrinsic function $name", warnAgainstElement) @@ -1466,7 +1646,7 @@ open class KotlinFileExtractor( result } - fun isFunction(target: IrFunction, pkgName: String, classNameLogged: String, classNamePredicate: (String) -> Boolean, fName: String, hasQuestionMark: Boolean? = false): Boolean { + private fun isFunction(target: IrFunction, pkgName: String, classNameLogged: String, classNamePredicate: (String) -> Boolean, fName: String, hasQuestionMark: Boolean? = false): Boolean { val verbose = false fun verboseln(s: String) { if(verbose) println(s) } verboseln("Attempting match for $pkgName $classNameLogged $fName") @@ -1510,10 +1690,10 @@ open class KotlinFileExtractor( return true } - fun isFunction(target: IrFunction, pkgName: String, className: String, fName: String, hasQuestionMark: Boolean? = false) = + private fun isFunction(target: IrFunction, pkgName: String, className: String, fName: String, hasQuestionMark: Boolean? = false) = isFunction(target, pkgName, className, { it == className }, fName, hasQuestionMark) - fun isNumericFunction(target: IrFunction, fName: String): Boolean { + private fun isNumericFunction(target: IrFunction, fName: String): Boolean { return isFunction(target, "kotlin", "Int", fName) || isFunction(target, "kotlin", "Byte", fName) || isFunction(target, "kotlin", "Short", fName) || @@ -1522,7 +1702,7 @@ open class KotlinFileExtractor( isFunction(target, "kotlin", "Double", fName) } - fun isArrayType(typeName: String) = + private fun isArrayType(typeName: String) = when(typeName) { "Array" -> true "IntArray" -> true @@ -1536,7 +1716,7 @@ open class KotlinFileExtractor( else -> false } - fun extractCall(c: IrCall, callable: Label, stmtExprParent: StmtExprParent) { + private fun extractCall(c: IrCall, callable: Label, stmtExprParent: StmtExprParent) { with("call", c) { val target = tryReplaceSyntheticFunction(c.symbol.owner) @@ -2101,6 +2281,22 @@ open class KotlinFileExtractor( enclosingStmt: Label ): Label = extractNewExpr(useFunction(calledConstructor, constructorTypeArgs), constructedType, locId, parent, idx, callable, enclosingStmt) + private fun needsObinitFunction(c: IrClass) = c.primaryConstructor == null && c.constructors.count() > 1 + + private fun getObinitLabel(c: IrClass) = getFunctionLabel( + c, + null, + "", + listOf(), + pluginContext.irBuiltIns.unitType, + null, + functionTypeParameters = listOf(), + classTypeArgsIncludingOuterClasses = listOf(), + overridesCollectionsMethod = false, + javaSignature = null, + addParameterWildcardsByDefault = false + ) + private fun extractConstructorCall( e: IrFunctionAccessExpression, parent: Label, @@ -2153,8 +2349,6 @@ open class KotlinFileExtractor( } } - private val loopIdMap: MutableMap> = mutableMapOf() - // todo: calculating the enclosing ref type could be done through this, instead of walking up the declaration parent chain private val declarationStack: Stack = Stack() @@ -2192,7 +2386,7 @@ open class KotlinFileExtractor( } } - fun getStatementOriginOperator(origin: IrStatementOrigin?) = when (origin) { + private fun getStatementOriginOperator(origin: IrStatementOrigin?) = when (origin) { IrStatementOrigin.PLUSEQ -> "plus" IrStatementOrigin.MINUSEQ -> "minus" IrStatementOrigin.MULTEQ -> "times" @@ -2201,7 +2395,7 @@ open class KotlinFileExtractor( else -> null } - fun getUpdateInPlaceRHS(origin: IrStatementOrigin?, isExpectedLhs: (IrExpression?) -> Boolean, updateRhs: IrExpression): IrExpression? { + private fun getUpdateInPlaceRHS(origin: IrStatementOrigin?, isExpectedLhs: (IrExpression?) -> Boolean, updateRhs: IrExpression): IrExpression? { // Check for a desugared in-place update operator, such as "v += e": return getStatementOriginOperator(origin)?.let { if (updateRhs is IrCall && @@ -2216,7 +2410,7 @@ open class KotlinFileExtractor( } } - fun writeUpdateInPlaceExpr(origin: IrStatementOrigin, tw: TrapWriter, id: Label, type: TypeResults, exprParent: ExprParent): Boolean { + private fun writeUpdateInPlaceExpr(origin: IrStatementOrigin, tw: TrapWriter, id: Label, type: TypeResults, exprParent: ExprParent): Boolean { when(origin) { IrStatementOrigin.PLUSEQ -> tw.writeExprs_assignaddexpr(id.cast(), type.javaResult.id, exprParent.parent, exprParent.idx) IrStatementOrigin.MINUSEQ -> tw.writeExprs_assignsubexpr(id.cast(), type.javaResult.id, exprParent.parent, exprParent.idx) @@ -2228,7 +2422,7 @@ open class KotlinFileExtractor( return true } - fun tryExtractArrayUpdate(e: IrContainerExpression, callable: Label, parent: StmtExprParent): Boolean { + private fun tryExtractArrayUpdate(e: IrContainerExpression, callable: Label, parent: StmtExprParent): Boolean { /* * We're expecting the pattern * { @@ -2299,7 +2493,7 @@ open class KotlinFileExtractor( return false } - fun extractExpressionStmt(e: IrExpression, callable: Label, parent: Label, idx: Int) { + private fun extractExpressionStmt(e: IrExpression, callable: Label, parent: Label, idx: Int) { extractExpression(e, callable, StmtParent(parent, idx)) } @@ -2307,7 +2501,7 @@ open class KotlinFileExtractor( extractExpression(e, callable, ExprParent(parent, idx, enclosingStmt)) } - fun extractExpression(e: IrExpression, callable: Label, parent: StmtExprParent) { + private fun extractExpression(e: IrExpression, callable: Label, parent: StmtExprParent) { with("expression", e) { when(e) { is IrDelegatingConstructorCall -> { @@ -2402,41 +2596,35 @@ open class KotlinFileExtractor( } } is IrWhileLoop -> { - val stmtParent = parent.stmt(e, callable) - val id = tw.getFreshIdLabel() - loopIdMap[e] = id - val locId = tw.getLocation(e) - tw.writeStmts_whilestmt(id, stmtParent.parent, stmtParent.idx, callable) - tw.writeHasLocation(id, locId) - extractExpressionExpr(e.condition, callable, id, 0, id) - val body = e.body - if(body != null) { - extractExpressionStmt(body, callable, id, 1) - } - loopIdMap.remove(e) + extractLoop(e, parent, callable) } is IrDoWhileLoop -> { - val stmtParent = parent.stmt(e, callable) - val id = tw.getFreshIdLabel() - loopIdMap[e] = id - val locId = tw.getLocation(e) - tw.writeStmts_dostmt(id, stmtParent.parent, stmtParent.idx, callable) - tw.writeHasLocation(id, locId) - extractExpressionExpr(e.condition, callable, id, 0, id) - val body = e.body - if(body != null) { - extractExpressionStmt(body, callable, id, 1) - } - loopIdMap.remove(e) + extractLoop(e, parent, callable) } is IrInstanceInitializerCall -> { - val stmtParent = parent.stmt(e, callable) val irConstructor = declarationStack.peek() as? IrConstructor if (irConstructor == null) { logger.errorElement("IrInstanceInitializerCall outside constructor", e) return } - extractInstanceInitializerBlock(stmtParent, irConstructor) + if (needsObinitFunction(irConstructor.parentAsClass)) { + val exprParent = parent.expr(e, callable) + val id = tw.getFreshIdLabel() + val type = useType(pluginContext.irBuiltIns.unitType) + val locId = tw.getLocation(e) + val methodLabel = getObinitLabel(irConstructor.parentAsClass) + val methodId = tw.getLabelFor(methodLabel) + tw.writeExprs_methodaccess(id, type.javaResult.id, exprParent.parent, exprParent.idx) + tw.writeExprsKotlinType(id, type.kotlinResult.id) + tw.writeHasLocation(id, locId) + tw.writeCallableEnclosingExpr(id, callable) + tw.writeStatementEnclosingExpr(id, exprParent.enclosingStmt) + tw.writeCallableBinding(id, methodId) + } + else { + val stmtParent = parent.stmt(e, callable) + extractInstanceInitializerBlock(stmtParent, irConstructor) + } } is IrConstructorCall -> { val exprParent = parent.expr(e, callable) @@ -2556,78 +2744,22 @@ open class KotlinFileExtractor( val exprParent = parent.expr(e, callable) val owner = e.symbol.owner if (owner is IrValueParameter && owner.index == -1 && !owner.isExtensionReceiver()) { - val id = tw.getFreshIdLabel() - val type = useType(e.type) - val locId = tw.getLocation(e) - tw.writeExprs_thisaccess(id, type.javaResult.id, exprParent.parent, exprParent.idx) - tw.writeExprsKotlinType(id, type.kotlinResult.id) - tw.writeHasLocation(id, locId) - tw.writeCallableEnclosingExpr(id, callable) - tw.writeStatementEnclosingExpr(id, exprParent.enclosingStmt) - - - fun extractTypeAccess(parent: IrClass){ - extractTypeAccessRecursive(parent.typeWith(listOf()), locId, id, 0, callable, exprParent.enclosingStmt) - } - - when(val ownerParent = owner.parent) { - is IrFunction -> { - if (ownerParent.dispatchReceiverParameter == owner && - ownerParent.extensionReceiverParameter != null) { - - val ownerParent2 = ownerParent.parent - if (ownerParent2 is IrClass){ - extractTypeAccess(ownerParent2) - } else { - logger.errorElement("Unhandled qualifier for this", e) - } - } - } - is IrClass -> { - if (ownerParent.thisReceiver == owner) { - extractTypeAccess(ownerParent) - } - } - else -> { - logger.errorElement("Unexpected owner parent for this access: " + ownerParent.javaClass, e) - } - } + extractThisAccess(e, exprParent, callable) } else { - val id = tw.getFreshIdLabel() - val type = useType(e.type) - val locId = tw.getLocation(e) - tw.writeExprs_varaccess(id, type.javaResult.id, exprParent.parent, exprParent.idx) - tw.writeExprsKotlinType(id, type.kotlinResult.id) - tw.writeHasLocation(id, locId) - tw.writeCallableEnclosingExpr(id, callable) - tw.writeStatementEnclosingExpr(id, exprParent.enclosingStmt) - - val vId = useValueDeclaration(owner) - if (vId != null) { - tw.writeVariableBinding(id, vId) - } + extractVariableAccess(useValueDeclaration(owner), e.type, tw.getLocation(e), exprParent.parent, exprParent.idx, callable, exprParent.enclosingStmt) } } is IrGetField -> { val exprParent = parent.expr(e, callable) - val id = tw.getFreshIdLabel() - val type = useType(e.type) - val locId = tw.getLocation(e) - tw.writeExprs_varaccess(id, type.javaResult.id, exprParent.parent, exprParent.idx) - tw.writeExprsKotlinType(id, type.kotlinResult.id) - tw.writeHasLocation(id, locId) - tw.writeCallableEnclosingExpr(id, callable) - tw.writeStatementEnclosingExpr(id, exprParent.enclosingStmt) val owner = tryReplaceAndroidSyntheticField(e.symbol.owner) - val vId = useField(owner) - tw.writeVariableBinding(id, vId) - tw.writeStatementEnclosingExpr(id, exprParent.enclosingStmt) - - val receiver = e.receiver - if (receiver != null) { - extractExpressionExpr(receiver, callable, id, -1, exprParent.enclosingStmt) - } else if (owner.isStatic) { - extractStaticTypeAccessQualifier(owner, id, locId, callable, exprParent.enclosingStmt) + val locId = tw.getLocation(e) + extractVariableAccess(useField(owner), e.type, locId, exprParent.parent, exprParent.idx, callable, exprParent.enclosingStmt).also { id -> + val receiver = e.receiver + if (receiver != null) { + extractExpressionExpr(receiver, callable, id, -1, exprParent.enclosingStmt) + } else if (owner.isStatic) { + extractStaticTypeAccessQualifier(owner, id, locId, callable, exprParent.enclosingStmt) + } } } is IrGetEnumValue -> { @@ -2928,6 +3060,114 @@ open class KotlinFileExtractor( } } + private fun extractThisAccess(e: IrGetValue, exprParent: ExprParent, callable: Label) { + val containingDeclaration = declarationStack.peek() + val locId = tw.getLocation(e) + val type = useType(e.type) + + if (containingDeclaration.shouldExtractAsStatic && containingDeclaration.parentClassOrNull?.isNonCompanionObject == true) { + // Use of `this` in a non-companion object member that will be lowered to a static function -- replace with a reference + // to the corresponding static object instance. + val instanceField = useObjectClassInstance(containingDeclaration.parentAsClass) + extractVariableAccess(instanceField.id, e.type, locId, exprParent.parent, exprParent.idx, callable, exprParent.enclosingStmt).also { varAccessId -> + extractStaticTypeAccessQualifier(containingDeclaration, varAccessId, locId, callable, exprParent.enclosingStmt) + } + } else { + val id = tw.getFreshIdLabel() + + tw.writeExprs_thisaccess(id, type.javaResult.id, exprParent.parent, exprParent.idx) + tw.writeExprsKotlinType(id, type.kotlinResult.id) + tw.writeHasLocation(id, locId) + tw.writeCallableEnclosingExpr(id, callable) + tw.writeStatementEnclosingExpr(id, exprParent.enclosingStmt) + + fun extractTypeAccess(parent: IrClass) { + extractTypeAccessRecursive(parent.typeWith(listOf()), locId, id, 0, callable, exprParent.enclosingStmt) + } + + val owner = e.symbol.owner + when(val ownerParent = owner.parent) { + is IrFunction -> { + if (ownerParent.dispatchReceiverParameter == owner && + ownerParent.extensionReceiverParameter != null) { + + val ownerParent2 = ownerParent.parent + if (ownerParent2 is IrClass){ + extractTypeAccess(ownerParent2) + } else { + logger.errorElement("Unhandled qualifier for this", e) + } + } + } + is IrClass -> { + if (ownerParent.thisReceiver == owner) { + extractTypeAccess(ownerParent) + } + } + else -> { + logger.errorElement("Unexpected owner parent for this access: " + ownerParent.javaClass, e) + } + } + } + } + + private fun extractVariableAccess(variable: Label?, irType: IrType, locId: Label, parent: Label, idx: Int, callable: Label, enclosingStmt: Label) = + tw.getFreshIdLabel().also { + val type = useType(irType) + tw.writeExprs_varaccess(it, type.javaResult.id, parent, idx) + tw.writeExprsKotlinType(it, type.kotlinResult.id) + tw.writeHasLocation(it, locId) + tw.writeCallableEnclosingExpr(it, callable) + tw.writeStatementEnclosingExpr(it, enclosingStmt) + + if (variable != null) { + tw.writeVariableBinding(it, variable) + } + } + + private fun extractLoop( + loop: IrLoop, + stmtExprParent: StmtExprParent, + callable: Label + ) { + val stmtParent = stmtExprParent.stmt(loop, callable) + val locId = tw.getLocation(loop) + + val idx: Int + val parent: Label + + val label = loop.label + if (label != null) { + val labeledStmt = tw.getFreshIdLabel() + tw.writeStmts_labeledstmt(labeledStmt, stmtParent.parent, stmtParent.idx, callable) + tw.writeHasLocation(labeledStmt, locId) + + tw.writeNamestrings(label, "", labeledStmt) + idx = 0 + parent = labeledStmt + } else { + idx = stmtParent.idx + parent = stmtParent.parent + } + + val id = if (loop is IrWhileLoop) { + val id = tw.getFreshIdLabel() + tw.writeStmts_whilestmt(id, parent, idx, callable) + id + } else { + val id = tw.getFreshIdLabel() + tw.writeStmts_dostmt(id, parent, idx, callable) + id + } + + tw.writeHasLocation(id, locId) + extractExpressionExpr(loop.condition, callable, id, 0, id) + val body = loop.body + if (body != null) { + extractExpressionStmt(body, callable, id, 1) + } + } + private fun IrValueParameter.isExtensionReceiver(): Boolean { val parentFun = parent as? IrFunction ?: return false return parentFun.extensionReceiverParameter == this @@ -3733,7 +3973,7 @@ open class KotlinFileExtractor( } } - fun extractVarargElement(e: IrVarargElement, callable: Label, parent: Label, idx: Int, enclosingStmt: Label) { + private fun extractVarargElement(e: IrVarargElement, callable: Label, parent: Label, idx: Int, enclosingStmt: Label) { with("vararg element", e) { val argExpr = when(e) { is IrExpression -> e @@ -3925,7 +4165,7 @@ open class KotlinFileExtractor( return initId } - fun extractTypeOperatorCall(e: IrTypeOperatorCall, callable: Label, parent: Label, idx: Int, enclosingStmt: Label) { + private fun extractTypeOperatorCall(e: IrTypeOperatorCall, callable: Label, parent: Label, idx: Int, enclosingStmt: Label) { with("type operator call", e) { when(e.operator) { IrTypeOperator.CAST -> { @@ -4201,7 +4441,7 @@ open class KotlinFileExtractor( private fun extractBreakContinue( e: IrBreakContinue, - id: Label + id: Label ) { with("break/continue", e) { val locId = tw.getLocation(e) @@ -4210,14 +4450,6 @@ open class KotlinFileExtractor( if (label != null) { tw.writeNamestrings(label, "", id) } - - val loopId = loopIdMap[e.loop] - if (loopId == null) { - logger.errorElement("Missing break/continue target", e) - return - } - - tw.writeKtBreakContinueTargets(id, loopId) } } @@ -4299,4 +4531,15 @@ open class KotlinFileExtractor( declarationStack.pop() } } + + private enum class CompilerGeneratedKinds(val kind: Int) { + DECLARING_CLASSES_OF_ADAPTER_FUNCTIONS(1), + GENERATED_DATA_CLASS_MEMBER(2), + DEFAULT_PROPERTY_ACCESSOR(3), + CLASS_INITIALISATION_METHOD(4), + ENUM_CLASS_SPECIAL_MEMBER(5), + DELEGATED_PROPERTY_GETTER(6), + DELEGATED_PROPERTY_SETTER(7), + JVMSTATIC_PROXY_METHOD(8), + } } diff --git a/java/kotlin-extractor/src/main/kotlin/KotlinUsesExtractor.kt b/java/kotlin-extractor/src/main/kotlin/KotlinUsesExtractor.kt index b5fcad1372d..a63ac756bd1 100644 --- a/java/kotlin-extractor/src/main/kotlin/KotlinUsesExtractor.kt +++ b/java/kotlin-extractor/src/main/kotlin/KotlinUsesExtractor.kt @@ -11,6 +11,7 @@ import org.jetbrains.kotlin.backend.common.lower.parents import org.jetbrains.kotlin.backend.common.lower.parentsWithSelf import org.jetbrains.kotlin.backend.jvm.ir.propertyIfAccessor import org.jetbrains.kotlin.builtins.StandardNames +import org.jetbrains.kotlin.codegen.JvmCodegenUtil import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI import org.jetbrains.kotlin.ir.declarations.* @@ -23,8 +24,10 @@ import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.load.java.sources.JavaSourceElement import org.jetbrains.kotlin.load.java.structure.* +import org.jetbrains.kotlin.load.kotlin.getJvmModuleNameForDeserializedDescriptor import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.name.NameUtils import org.jetbrains.kotlin.name.SpecialNames import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.util.OperatorNameConventions @@ -49,7 +52,7 @@ open class KotlinUsesExtractor( javaLangObject?.typeWith() } - fun usePackage(pkg: String): Label { + private fun usePackage(pkg: String): Label { return extractPackage(pkg) } @@ -154,12 +157,12 @@ open class KotlinUsesExtractor( } ?: argsIncludingOuterClasses } - fun isStaticClass(c: IrClass) = c.visibility != DescriptorVisibilities.LOCAL && !c.isInner + private fun isStaticClass(c: IrClass) = c.visibility != DescriptorVisibilities.LOCAL && !c.isInner // Gets nested inner classes starting at `c` and proceeding outwards to the innermost enclosing static class. // For example, for (java syntax) `class A { static class B { class C { class D { } } } }`, // `nonStaticParentsWithSelf(D)` = `[D, C, B]`. - fun parentsWithTypeParametersInScope(c: IrClass): List { + private fun parentsWithTypeParametersInScope(c: IrClass): List { val parentsList = c.parentsWithSelf.toList() val firstOuterClassIdx = parentsList.indexOfFirst { it is IrClass && isStaticClass(it) } return if (firstOuterClassIdx == -1) parentsList else parentsList.subList(0, firstOuterClassIdx + 1) @@ -168,14 +171,14 @@ open class KotlinUsesExtractor( // Gets the type parameter symbols that are in scope for class `c` in Kotlin order (i.e. for // `class NotInScope { static class OutermostInScope { class QueryClass { } } }`, // `getTypeParametersInScope(QueryClass)` = `[C, D, A, B]`. - fun getTypeParametersInScope(c: IrClass) = + private fun getTypeParametersInScope(c: IrClass) = parentsWithTypeParametersInScope(c).mapNotNull({ getTypeParameters(it) }).flatten() // Returns a map from `c`'s type variables in scope to type arguments `argsIncludingOuterClasses`. // Hack for the time being: the substituted types are always nullable, to prevent downstream code // from replacing a generic parameter by a primitive. As and when we extract Kotlin types we will // need to track this information in more detail. - fun makeTypeGenericSubstitutionMap(c: IrClass, argsIncludingOuterClasses: List) = + private fun makeTypeGenericSubstitutionMap(c: IrClass, argsIncludingOuterClasses: List) = getTypeParametersInScope(c).map({ it.symbol }).zip(argsIncludingOuterClasses.map { it.withQuestionMark(true) }).toMap() fun makeGenericSubstitutionFunction(c: IrClass, argsIncludingOuterClasses: List) = @@ -190,7 +193,7 @@ open class KotlinUsesExtractor( } // The Kotlin compiler internal representation of Outer.Inner.InnerInner.someFunction.LocalClass is LocalClass. This function returns [A, B, C, D, E, F, G, H, I, J]. - fun orderTypeArgsLeftToRight(c: IrClass, argsIncludingOuterClasses: List?): List? { + private fun orderTypeArgsLeftToRight(c: IrClass, argsIncludingOuterClasses: List?): List? { if(argsIncludingOuterClasses.isNullOrEmpty()) return argsIncludingOuterClasses val ret = ArrayList() @@ -237,15 +240,15 @@ open class KotlinUsesExtractor( return UseClassInstanceResult(classTypeResult, extractClass) } - fun isArray(t: IrSimpleType) = t.isBoxedArray || t.isPrimitiveArray() + private fun isArray(t: IrSimpleType) = t.isBoxedArray || t.isPrimitiveArray() - fun extractClassLaterIfExternal(c: IrClass) { + private fun extractClassLaterIfExternal(c: IrClass) { if (isExternalDeclaration(c)) { extractExternalClassLater(c) } } - fun extractExternalEnclosingClassLater(d: IrDeclaration) { + private fun extractExternalEnclosingClassLater(d: IrDeclaration) { when (val parent = d.parent) { is IrClass -> extractExternalClassLater(parent) is IrFunction -> extractExternalEnclosingClassLater(parent) @@ -254,7 +257,7 @@ open class KotlinUsesExtractor( } } - fun extractPropertyLaterIfExternalFileMember(p: IrProperty) { + private fun extractPropertyLaterIfExternalFileMember(p: IrProperty) { if (isExternalFileClassMember(p)) { extractExternalClassLater(p.parentAsClass) dependencyCollector?.addDependency(p, externalClassExtractor.propertySignature) @@ -262,7 +265,7 @@ open class KotlinUsesExtractor( } } - fun extractFieldLaterIfExternalFileMember(f: IrField) { + private fun extractFieldLaterIfExternalFileMember(f: IrField) { if (isExternalFileClassMember(f)) { extractExternalClassLater(f.parentAsClass) dependencyCollector?.addDependency(f, externalClassExtractor.fieldSignature) @@ -270,7 +273,7 @@ open class KotlinUsesExtractor( } } - fun extractFunctionLaterIfExternalFileMember(f: IrFunction) { + private fun extractFunctionLaterIfExternalFileMember(f: IrFunction) { if (isExternalFileClassMember(f)) { extractExternalClassLater(f.parentAsClass) (f as? IrSimpleFunction)?.correspondingPropertySymbol?.let { @@ -301,7 +304,7 @@ open class KotlinUsesExtractor( externalClassExtractor.extractLater(c) } - fun tryReplaceAndroidSyntheticClass(c: IrClass): IrClass { + private fun tryReplaceAndroidSyntheticClass(c: IrClass): IrClass { // The Android Kotlin Extensions Gradle plugin introduces synthetic functions, fields and classes. The most // obvious signature is that they lack any supertype information even though they are not root classes. // If possible, replace them by a real version of the same class. @@ -503,7 +506,7 @@ open class KotlinUsesExtractor( // but returns boxed arrays with a nullable, invariant component type, with any nested arrays // similarly transformed. For example, Array> would become Array?> // Array<*> will become Array. - fun getInvariantNullableArrayType(arrayType: IrSimpleType): IrSimpleType = + private fun getInvariantNullableArrayType(arrayType: IrSimpleType): IrSimpleType = if (arrayType.isPrimitiveArray()) arrayType else { @@ -528,7 +531,7 @@ open class KotlinUsesExtractor( ) } - fun useArrayType(arrayType: IrSimpleType, componentType: IrType, elementType: IrType, dimensions: Int, isPrimitiveArray: Boolean): TypeResults { + private fun useArrayType(arrayType: IrSimpleType, componentType: IrType, elementType: IrType, dimensions: Int, isPrimitiveArray: Boolean): TypeResults { // Ensure we extract Array as Integer[], not int[], for example: fun nullableIfNotPrimitive(type: IrType) = if (type.isPrimitiveType() && !isPrimitiveArray) type.makeNullable() else type @@ -579,7 +582,7 @@ open class KotlinUsesExtractor( RETURN, GENERIC_ARGUMENT, OTHER } - fun useSimpleType(s: IrSimpleType, context: TypeContext): TypeResults { + private fun useSimpleType(s: IrSimpleType, context: TypeContext): TypeResults { if (s.abbreviation != null) { // TODO: Extract this information } @@ -754,11 +757,25 @@ open class KotlinUsesExtractor( data class FunctionNames(val nameInDB: String, val kotlinName: String) + @OptIn(ObsoleteDescriptorBasedAPI::class) + private fun getJvmModuleName(f: IrFunction) = + NameUtils.sanitizeAsJavaIdentifier( + getJvmModuleNameForDeserializedDescriptor(f.descriptor) ?: JvmCodegenUtil.getModuleName(pluginContext.moduleDescriptor) + ) + fun getFunctionShortName(f: IrFunction) : FunctionNames { if (f.origin == IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA || f.isAnonymousFunction) return FunctionNames( OperatorNameConventions.INVOKE.asString(), OperatorNameConventions.INVOKE.asString()) + + fun getSuffixIfInternal() = + if (f.visibility == DescriptorVisibilities.INTERNAL) { + "\$" + getJvmModuleName(f) + } else { + "" + } + (f as? IrSimpleFunction)?.correspondingPropertySymbol?.let { val propName = it.owner.name.asString() val getter = it.owner.getter @@ -774,35 +791,26 @@ open class KotlinUsesExtractor( } } - when (f) { - getter -> { - val defaultFunctionName = JvmAbi.getterName(propName) - val defaultDbName = if (getter.visibility == DescriptorVisibilities.PRIVATE && getter.origin == IrDeclarationOrigin.DEFAULT_PROPERTY_ACCESSOR) { - // In JVM these functions don't exist, instead the backing field is accessed directly - defaultFunctionName + "\$private" - } else { - defaultFunctionName - } - return FunctionNames(getJvmName(getter) ?: defaultDbName, defaultFunctionName) - } - setter -> { - val defaultFunctionName = JvmAbi.setterName(propName) - val defaultDbName = if (setter.visibility == DescriptorVisibilities.PRIVATE && setter.origin == IrDeclarationOrigin.DEFAULT_PROPERTY_ACCESSOR) { - // In JVM these functions don't exist, instead the backing field is accessed directly - defaultFunctionName + "\$private" - } else { - defaultFunctionName - } - return FunctionNames(getJvmName(setter) ?: defaultDbName, defaultFunctionName) - } + val maybeFunctionName = when (f) { + getter -> JvmAbi.getterName(propName) + setter -> JvmAbi.setterName(propName) else -> { logger.error( "Function has a corresponding property, but is neither the getter nor the setter" ) + null } } + maybeFunctionName?.let { defaultFunctionName -> + val suffix = if (f.visibility == DescriptorVisibilities.PRIVATE && f.origin == IrDeclarationOrigin.DEFAULT_PROPERTY_ACCESSOR) { + "\$private" + } else { + getSuffixIfInternal() + } + return FunctionNames(getJvmName(f) ?: "$defaultFunctionName$suffix", defaultFunctionName) + } } - return FunctionNames(getJvmName(f) ?: f.name.asString(), f.name.asString()) + return FunctionNames(getJvmName(f) ?: "${f.name.asString()}${getSuffixIfInternal()}", f.name.asString()) } // This excludes class type parameters that show up in (at least) constructors' typeParameters list. @@ -810,14 +818,14 @@ open class KotlinUsesExtractor( return if (f is IrConstructor) f.typeParameters else f.typeParameters.filter { it.parent == f } } - fun getTypeParameters(dp: IrDeclarationParent): List = + private fun getTypeParameters(dp: IrDeclarationParent): List = when(dp) { is IrClass -> dp.typeParameters is IrFunction -> getFunctionTypeParameters(dp) else -> listOf() } - fun getEnclosingClass(it: IrDeclarationParent): IrClass? = + private fun getEnclosingClass(it: IrDeclarationParent): IrClass? = when(it) { is IrClass -> it is IrFunction -> getEnclosingClass(it.parent) @@ -924,7 +932,7 @@ open class KotlinUsesExtractor( null } ?: t - fun getJavaTypeArgument(jt: JavaType, idx: Int) = + private fun getJavaTypeArgument(jt: JavaType, idx: Int) = when(jt) { is JavaClassifierType -> jt.typeArguments.getOrNull(idx) is JavaArrayType -> if (idx == 0) jt.componentType else null @@ -1146,15 +1154,6 @@ open class KotlinUsesExtractor( return res } - fun useFunctionCommon(f: IrFunction, label: String): Label { - val id: Label = tw.getLabelFor(label) - if (isExternalDeclaration(f)) { - extractFunctionLaterIfExternalFileMember(f) - extractExternalEnclosingClassLater(f) - } - return id - } - // These are classes with Java equivalents, but whose methods don't all exist on those Java equivalents-- // for example, the numeric classes define arithmetic functions (Int.plus, Long.or and so on) that lower to // primitive arithmetic on the JVM, but which we extract as calls to reflect the source syntax more closely. @@ -1162,7 +1161,7 @@ open class KotlinUsesExtractor( "kotlin.Boolean", "kotlin.Byte", "kotlin.Char", "kotlin.Double", "kotlin.Float", "kotlin.Int", "kotlin.Long", "kotlin.Number", "kotlin.Short" ) - fun kotlinFunctionToJavaEquivalent(f: IrFunction, noReplace: Boolean) = + private fun kotlinFunctionToJavaEquivalent(f: IrFunction, noReplace: Boolean) = if (noReplace) f else @@ -1210,20 +1209,24 @@ open class KotlinUsesExtractor( } as IrFunction? ?: f fun useFunction(f: IrFunction, classTypeArgsIncludingOuterClasses: List? = null, noReplace: Boolean = false): Label { + return useFunction(f, null, classTypeArgsIncludingOuterClasses, noReplace) + } + + fun useFunction(f: IrFunction, parentId: Label?, classTypeArgsIncludingOuterClasses: List?, noReplace: Boolean = false): Label { if (f.isLocalFunction()) { val ids = getLocallyVisibleFunctionLabels(f) return ids.function.cast() - } else { - val realFunction = kotlinFunctionToJavaEquivalent(f, noReplace) - return useFunctionCommon(realFunction, getFunctionLabel(realFunction, classTypeArgsIncludingOuterClasses)) } + val javaFun = kotlinFunctionToJavaEquivalent(f, noReplace) + val label = getFunctionLabel(javaFun, parentId, classTypeArgsIncludingOuterClasses) + val id: Label = tw.getLabelFor(label) + if (isExternalDeclaration(javaFun)) { + extractFunctionLaterIfExternalFileMember(javaFun) + extractExternalEnclosingClassLater(javaFun) + } + return id } - fun useFunction(f: IrFunction, parentId: Label, classTypeArgsIncludingOuterClasses: List?, noReplace: Boolean = false) = - kotlinFunctionToJavaEquivalent(f, noReplace).let { - useFunctionCommon(it, getFunctionLabel(it, parentId, classTypeArgsIncludingOuterClasses)) - } - fun getTypeArgumentLabel( arg: IrTypeArgument ): TypeResult { @@ -1351,14 +1354,14 @@ open class KotlinUsesExtractor( return "@\"typevar;{$parentLabel};${param.name}\"" } - fun useTypeParameter(param: IrTypeParameter) = + private fun useTypeParameter(param: IrTypeParameter) = TypeResult( tw.getLabelFor(getTypeParameterLabel(param)), useType(eraseTypeParameter(param)).javaResult.signature, param.name.asString() ) - fun extractModifier(m: String): Label { + private fun extractModifier(m: String): Label { val modifierLabel = "@\"modifier;$m\"" val id: Label = tw.getLabelFor(modifierLabel, { tw.writeModifiers(it, m) @@ -1440,7 +1443,7 @@ open class KotlinUsesExtractor( * Note that `Array` is retained (with `T` itself erased) because these are expected to be lowered to Java * arrays, which are not generic. */ - fun erase (t: IrType): IrType { + private fun erase (t: IrType): IrType { if (t is IrSimpleType) { val classifier = t.classifier val owner = classifier.owner @@ -1464,7 +1467,7 @@ open class KotlinUsesExtractor( return t } - fun eraseTypeParameter(t: IrTypeParameter) = + private fun eraseTypeParameter(t: IrTypeParameter) = erase(t.superTypes[0]) /** @@ -1493,7 +1496,7 @@ open class KotlinUsesExtractor( fun useValueParameter(vp: IrValueParameter, parent: Label?): Label = tw.getLabelFor(getValueParameterLabel(vp, parent)) - fun isDirectlyExposedCompanionObjectField(f: IrField) = + private fun isDirectlyExposedCompanionObjectField(f: IrField) = f.hasAnnotation(FqName("kotlin.jvm.JvmField")) || f.correspondingPropertySymbol?.owner?.let { it.isConst || it.isLateinit @@ -1519,7 +1522,7 @@ open class KotlinUsesExtractor( // otherwise two extension properties declared in the same enclosing context will get // clashing trap labels. These are always private, so we can just make up a label without // worrying about their names as seen from Java. - val extensionPropertyDiscriminator = getExtensionReceiverType(f)?.let { "extension;${useType(it)}" } ?: "" + val extensionPropertyDiscriminator = getExtensionReceiverType(f)?.let { "extension;${useType(it).javaResult.id}" } ?: "" return "@\"field;{$parentId};${extensionPropertyDiscriminator}${f.name.asString()}\"" } diff --git a/java/kotlin-extractor/src/main/kotlin/PrimitiveTypeInfo.kt b/java/kotlin-extractor/src/main/kotlin/PrimitiveTypeInfo.kt index 6eaa27b0ca4..8d844a65ec8 100644 --- a/java/kotlin-extractor/src/main/kotlin/PrimitiveTypeInfo.kt +++ b/java/kotlin-extractor/src/main/kotlin/PrimitiveTypeInfo.kt @@ -1,14 +1,21 @@ package com.github.codeql import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext +import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.ir.declarations.IrClass +import org.jetbrains.kotlin.ir.declarations.IrPackageFragment import org.jetbrains.kotlin.ir.types.IrSimpleType -import org.jetbrains.kotlin.ir.types.IdSignatureValues -import org.jetbrains.kotlin.ir.util.IdSignature +import org.jetbrains.kotlin.ir.types.classOrNull import org.jetbrains.kotlin.name.FqName class PrimitiveTypeMapping(val logger: Logger, val pluginContext: IrPluginContext) { - fun getPrimitiveInfo(s: IrSimpleType) = mapping[s.classifier.signature] + fun getPrimitiveInfo(s: IrSimpleType) = + s.classOrNull?.let { + if ((it.owner.parent as? IrPackageFragment)?.fqName == StandardNames.BUILT_INS_PACKAGE_FQ_NAME) + mapping[it.owner.name] + else + null + } data class PrimitiveTypeInfo( val primitiveName: String?, @@ -60,25 +67,25 @@ class PrimitiveTypeMapping(val logger: Logger, val pluginContext: IrPluginContex val javaLangVoid = findClass("java.lang.Void", kotlinNothing) mapOf( - IdSignatureValues._byte to PrimitiveTypeInfo("byte", true, javaLangByte, "kotlin", "Byte"), - IdSignatureValues._short to PrimitiveTypeInfo("short", true, javaLangShort, "kotlin", "Short"), - IdSignatureValues._int to PrimitiveTypeInfo("int", true, javaLangInteger, "kotlin", "Int"), - IdSignatureValues._long to PrimitiveTypeInfo("long", true, javaLangLong, "kotlin", "Long"), + StandardNames.FqNames._byte.shortName() to PrimitiveTypeInfo("byte", true, javaLangByte, "kotlin", "Byte"), + StandardNames.FqNames._short.shortName() to PrimitiveTypeInfo("short", true, javaLangShort, "kotlin", "Short"), + StandardNames.FqNames._int.shortName() to PrimitiveTypeInfo("int", true, javaLangInteger, "kotlin", "Int"), + StandardNames.FqNames._long.shortName() to PrimitiveTypeInfo("long", true, javaLangLong, "kotlin", "Long"), - IdSignatureValues.uByte to PrimitiveTypeInfo("byte", true, kotlinUByte, "kotlin", "UByte"), - IdSignatureValues.uShort to PrimitiveTypeInfo("short", true, kotlinUShort, "kotlin", "UShort"), - IdSignatureValues.uInt to PrimitiveTypeInfo("int", true, kotlinUInt, "kotlin", "UInt"), - IdSignatureValues.uLong to PrimitiveTypeInfo("long", true, kotlinULong, "kotlin", "ULong"), + StandardNames.FqNames.uByteFqName.shortName() to PrimitiveTypeInfo("byte", true, kotlinUByte, "kotlin", "UByte"), + StandardNames.FqNames.uShortFqName.shortName() to PrimitiveTypeInfo("short", true, kotlinUShort, "kotlin", "UShort"), + StandardNames.FqNames.uIntFqName.shortName() to PrimitiveTypeInfo("int", true, kotlinUInt, "kotlin", "UInt"), + StandardNames.FqNames.uLongFqName.shortName() to PrimitiveTypeInfo("long", true, kotlinULong, "kotlin", "ULong"), - IdSignatureValues._double to PrimitiveTypeInfo("double", true, javaLangDouble, "kotlin", "Double"), - IdSignatureValues._float to PrimitiveTypeInfo("float", true, javaLangFloat, "kotlin", "Float"), + StandardNames.FqNames._double.shortName() to PrimitiveTypeInfo("double", true, javaLangDouble, "kotlin", "Double"), + StandardNames.FqNames._float.shortName() to PrimitiveTypeInfo("float", true, javaLangFloat, "kotlin", "Float"), - IdSignatureValues._boolean to PrimitiveTypeInfo("boolean", true, javaLangBoolean, "kotlin", "Boolean"), + StandardNames.FqNames._boolean.shortName() to PrimitiveTypeInfo("boolean", true, javaLangBoolean, "kotlin", "Boolean"), - IdSignatureValues._char to PrimitiveTypeInfo("char", true, javaLangCharacter, "kotlin", "Char"), + StandardNames.FqNames._char.shortName() to PrimitiveTypeInfo("char", true, javaLangCharacter, "kotlin", "Char"), - IdSignatureValues.unit to PrimitiveTypeInfo("void", false, kotlinUnit, "kotlin", "Unit"), - IdSignatureValues.nothing to PrimitiveTypeInfo(null, true, javaLangVoid, "kotlin", "Nothing"), + StandardNames.FqNames.unit.shortName() to PrimitiveTypeInfo("void", false, kotlinUnit, "kotlin", "Unit"), + StandardNames.FqNames.nothing.shortName() to PrimitiveTypeInfo(null, true, javaLangVoid, "kotlin", "Nothing"), ) }() } diff --git a/java/kotlin-extractor/src/main/kotlin/utils/AutoCloseableUse.kt b/java/kotlin-extractor/src/main/kotlin/utils/AutoCloseableUse.kt index fe68f308893..dad820ab6ee 100644 --- a/java/kotlin-extractor/src/main/kotlin/utils/AutoCloseableUse.kt +++ b/java/kotlin-extractor/src/main/kotlin/utils/AutoCloseableUse.kt @@ -40,4 +40,4 @@ fun AutoCloseable?.closeFinallyAC(cause: Throwable?) = when { } catch (closeException: Throwable) { cause.addSuppressed(closeException) } -} \ No newline at end of file +} diff --git a/java/kotlin-extractor/src/main/kotlin/utils/ClassNames.kt b/java/kotlin-extractor/src/main/kotlin/utils/ClassNames.kt index 6f3954cfc34..15ca35a1438 100644 --- a/java/kotlin-extractor/src/main/kotlin/utils/ClassNames.kt +++ b/java/kotlin-extractor/src/main/kotlin/utils/ClassNames.kt @@ -68,7 +68,7 @@ fun getIrClassVirtualFile(irClass: IrClass): VirtualFile? { return null } -fun getRawIrClassBinaryPath(irClass: IrClass) = +private fun getRawIrClassBinaryPath(irClass: IrClass) = getIrClassVirtualFile(irClass)?.let { val path = it.path if(it.fileSystem.protocol == StandardFileSystems.JRT_PROTOCOL) @@ -92,4 +92,4 @@ fun getContainingClassOrSelf(decl: IrDeclaration): IrClass? { } fun getJavaEquivalentClassId(c: IrClass) = - c.fqNameWhenAvailable?.toUnsafe()?.let { JavaToKotlinClassMap.mapKotlinToJava(it) } \ No newline at end of file + c.fqNameWhenAvailable?.toUnsafe()?.let { JavaToKotlinClassMap.mapKotlinToJava(it) } diff --git a/java/kotlin-extractor/src/main/kotlin/utils/JvmNames.kt b/java/kotlin-extractor/src/main/kotlin/utils/JvmNames.kt index dce49790e0e..57a3e92e6b2 100644 --- a/java/kotlin-extractor/src/main/kotlin/utils/JvmNames.kt +++ b/java/kotlin-extractor/src/main/kotlin/utils/JvmNames.kt @@ -55,7 +55,7 @@ private val specialFunctions = mapOf( private val specialFunctionShortNames = specialFunctions.keys.map { it.functionName }.toSet() -fun getSpecialJvmName(f: IrFunction): String? { +private fun getSpecialJvmName(f: IrFunction): String? { if (specialFunctionShortNames.contains(f.name) && f is IrSimpleFunction) { f.allOverridden(true).forEach { overriddenFunc -> overriddenFunc.parentClassOrNull?.fqNameWhenAvailable?.let { parentFqName -> @@ -87,4 +87,4 @@ fun getJvmName(container: IrAnnotationContainer): String? { } } return (container as? IrFunction)?.let { getSpecialJvmName(container) } -} \ No newline at end of file +} diff --git a/java/kotlin-extractor/src/main/kotlin/utils/Logger.kt b/java/kotlin-extractor/src/main/kotlin/utils/Logger.kt index 1349380cbc4..ca27217ac6c 100644 --- a/java/kotlin-extractor/src/main/kotlin/utils/Logger.kt +++ b/java/kotlin-extractor/src/main/kotlin/utils/Logger.kt @@ -207,20 +207,6 @@ open class LoggerBase(val logCounter: LogCounter) { } open class Logger(val loggerBase: LoggerBase, open val tw: TrapWriter) { - private fun getDiagnosticLocation(): String? { - val st = Exception().stackTrace - for(x in st) { - when(x.className) { - "com.github.codeql.Logger", - "com.github.codeql.FileLogger" -> {} - else -> { - return x.toString() - } - } - } - return null - } - fun flush() { tw.flush() loggerBase.flush() @@ -240,7 +226,7 @@ open class Logger(val loggerBase: LoggerBase, open val tw: TrapWriter) { loggerBase.info(tw, msg) } - fun warn(msg: String, extraInfo: String?) { + private fun warn(msg: String, extraInfo: String?) { loggerBase.warn(tw, msg, extraInfo) } fun warn(msg: String, exn: Throwable) { @@ -250,7 +236,7 @@ open class Logger(val loggerBase: LoggerBase, open val tw: TrapWriter) { warn(msg, null) } - fun error(msg: String, extraInfo: String?) { + private fun error(msg: String, extraInfo: String?) { loggerBase.error(tw, msg, extraInfo) } fun error(msg: String) { diff --git a/java/kotlin-extractor/src/main/kotlin/utils/TypeSubstitution.kt b/java/kotlin-extractor/src/main/kotlin/utils/TypeSubstitution.kt index b249bb0091a..694b3dff289 100644 --- a/java/kotlin-extractor/src/main/kotlin/utils/TypeSubstitution.kt +++ b/java/kotlin-extractor/src/main/kotlin/utils/TypeSubstitution.kt @@ -37,7 +37,7 @@ fun IrType.substituteTypeArguments(params: List, arguments: Lis else -> this } -fun IrSimpleType.substituteTypeArguments(substitutionMap: Map): IrSimpleType { +private fun IrSimpleType.substituteTypeArguments(substitutionMap: Map): IrSimpleType { if (substitutionMap.isEmpty()) return this val newArguments = arguments.map { @@ -100,7 +100,7 @@ private fun subProjectedType(substitutionMap: Map context.irBuiltIns.anyNType is IrTypeProjection -> when(this.variance) { @@ -111,7 +111,7 @@ fun IrTypeArgument.upperBound(context: IrPluginContext) = else -> context.irBuiltIns.anyNType } -fun IrTypeArgument.lowerBound(context: IrPluginContext) = +private fun IrTypeArgument.lowerBound(context: IrPluginContext) = when(this) { is IrStarProjection -> context.irBuiltIns.nothingType is IrTypeProjection -> when(this.variance) { @@ -200,7 +200,7 @@ fun IrTypeArgument.withQuestionMark(b: Boolean): IrTypeArgument = typealias TypeSubstitution = (IrType, KotlinUsesExtractor.TypeContext, IrPluginContext) -> IrType -fun matchingTypeParameters(l: IrTypeParameter?, r: IrTypeParameter): Boolean { +private fun matchingTypeParameters(l: IrTypeParameter?, r: IrTypeParameter): Boolean { if (l === r) return true if (l == null) diff --git a/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_7_0-RC/Descriptors.kt b/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_7_0-RC/Descriptors.kt deleted file mode 100644 index 77cd96d541d..00000000000 --- a/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_7_0-RC/Descriptors.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.github.codeql.utils.versions - -import com.github.codeql.KotlinUsesExtractor -import org.jetbrains.kotlin.ir.util.DeclarationStubGenerator - -fun KotlinUsesExtractor.getIrStubFromDescriptor(generateStub: (DeclarationStubGenerator) -> TIrStub) : TIrStub? { - logger.error("Descriptors not yet supported for Kotlin 1.7") - return null -} diff --git a/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_7_0/Descriptors.kt b/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_7_0/Descriptors.kt new file mode 100644 index 00000000000..45b2afcc858 --- /dev/null +++ b/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_7_0/Descriptors.kt @@ -0,0 +1,27 @@ +package com.github.codeql.utils.versions + +import com.github.codeql.KotlinUsesExtractor +import org.jetbrains.kotlin.backend.common.serialization.DescriptorByIdSignatureFinderImpl +import org.jetbrains.kotlin.idea.MainFunctionDetector +import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI +import org.jetbrains.kotlin.ir.backend.jvm.serialization.JvmDescriptorMangler +import org.jetbrains.kotlin.ir.util.DeclarationStubGenerator +import org.jetbrains.kotlin.ir.util.SymbolTable +import org.jetbrains.kotlin.psi2ir.generators.DeclarationStubGeneratorImpl + +@OptIn(ObsoleteDescriptorBasedAPI::class) +fun KotlinUsesExtractor.getIrStubFromDescriptor(generateStub: (DeclarationStubGenerator) -> TIrStub) : TIrStub? = + (pluginContext.symbolTable as? SymbolTable) ?.let { + // Copying the construction seen in JvmIrLinker.kt + val mangler = JvmDescriptorMangler(MainFunctionDetector(pluginContext.bindingContext, pluginContext.languageVersionSettings)) + val descriptorFinder = DescriptorByIdSignatureFinderImpl( + pluginContext.moduleDescriptor, + mangler, + DescriptorByIdSignatureFinderImpl.LookupMode.MODULE_ONLY + ) + val stubGenerator = DeclarationStubGeneratorImpl(pluginContext.moduleDescriptor, it, pluginContext.irBuiltIns, descriptorFinder) + generateStub(stubGenerator) + } ?: run { + logger.error("Plugin context has no symbol table, couldn't get IR stub") + null + } diff --git a/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_7_0-RC/FileEntry.kt b/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_7_0/FileEntry.kt similarity index 100% rename from java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_7_0-RC/FileEntry.kt rename to java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_7_0/FileEntry.kt diff --git a/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_7_0-RC/Functions.kt b/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_7_0/Functions.kt similarity index 100% rename from java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_7_0-RC/Functions.kt rename to java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_7_0/Functions.kt diff --git a/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_7_0-RC/Psi2Ir.kt b/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_7_0/Psi2Ir.kt similarity index 100% rename from java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_7_0-RC/Psi2Ir.kt rename to java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_7_0/Psi2Ir.kt diff --git a/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_7_0-RC/Types.kt b/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_7_0/Types.kt similarity index 100% rename from java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_7_0-RC/Types.kt rename to java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_7_0/Types.kt diff --git a/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_7_0-RC/withHasQuestionMark.kt b/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_7_0/withHasQuestionMark.kt similarity index 100% rename from java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_7_0-RC/withHasQuestionMark.kt rename to java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_7_0/withHasQuestionMark.kt diff --git a/java/ql/consistency-queries/calls.ql b/java/ql/consistency-queries/calls.ql index 207d7bd45b3..78ebc3fa9a6 100644 --- a/java/ql/consistency-queries/calls.ql +++ b/java/ql/consistency-queries/calls.ql @@ -1,5 +1,10 @@ import java from MethodAccess ma -where not exists(ma.getQualifier()) and ma.getFile().isKotlinSourceFile() +// Generally Kotlin calls will always use an explicit qualifier, except for calls +// to the synthetic instance initializer , which use an implicit `this`. +where + not exists(ma.getQualifier()) and + ma.getFile().isKotlinSourceFile() and + not ma.getCallee() instanceof InstanceInitializer select ma diff --git a/java/ql/consistency-queries/visibility.ql b/java/ql/consistency-queries/visibility.ql index ba90d598236..1b6744cea1d 100644 --- a/java/ql/consistency-queries/visibility.ql +++ b/java/ql/consistency-queries/visibility.ql @@ -18,5 +18,6 @@ where m.getFile().isKotlinSourceFile() and // TODO: This ought to have visibility information not m.getName() = "" and - count(visibility(m)) != 1 + count(visibility(m)) != 1 and + not (count(visibility(m)) = 2 and visibility(m) = "public" and visibility(m) = "internal") // This is a reasonable result, since the JVM symbol is declared public, but Kotlin metadata flags it as internal select m, concat(visibility(m), ", ") diff --git a/java/ql/integration-tests/linux-only/kotlin/custom_plugin/PrintAst.expected b/java/ql/integration-tests/linux-only/kotlin/custom_plugin/PrintAst.expected new file mode 100644 index 00000000000..51186ef7b15 --- /dev/null +++ b/java/ql/integration-tests/linux-only/kotlin/custom_plugin/PrintAst.expected @@ -0,0 +1,83 @@ +a.kt: +# 0| [CompilationUnit] a +# 1| 1: [Class] A +# 0| 1: [Method] +# 0| 3: [TypeAccess] int +# 0| 5: [BlockStmt] { ... } +# 0| 0: [ReturnStmt] return ... +# 0| 0: [IntegerLiteral] 42 +# 1| 2: [Constructor] A +# 1| 5: [BlockStmt] { ... } +# 1| 0: [SuperConstructorInvocationStmt] super(...) +# 1| 1: [BlockStmt] { ... } +# 2| 3: [Method] f1 +# 2| 3: [TypeAccess] int +# 2| 5: [BlockStmt] { ... } +# 2| 0: [ReturnStmt] return ... +# 2| 0: [IntegerLiteral] 1 +b.kt: +# 0| [CompilationUnit] b +# 1| 1: [Class] B +# 0| 1: [Method] +# 0| 3: [TypeAccess] int +# 0| 5: [BlockStmt] { ... } +# 0| 0: [ReturnStmt] return ... +# 0| 0: [UnsafeCoerceExpr] +# 0| 0: [TypeAccess] int +# 0| 1: [IntegerLiteral] 1 +# 1| 2: [Constructor] B +# 1| 5: [BlockStmt] { ... } +# 1| 0: [SuperConstructorInvocationStmt] super(...) +# 1| 1: [BlockStmt] { ... } +c.kt: +# 0| [CompilationUnit] c +# 1| 1: [Class] C +# 0| 1: [Method] +# 0| 3: [TypeAccess] Unit +#-----| 4: (Parameters) +# 0| 0: [Parameter] param +# 0| 0: [TypeAccess] ProcessBuilder +# 0| 5: [BlockStmt] { ... } +# 0| 0: [ReturnStmt] return ... +# 0| 0: [MethodAccess] start(...) +# 0| -1: [VarAccess] param +# 1| 2: [Constructor] C +# 1| 5: [BlockStmt] { ... } +# 1| 0: [SuperConstructorInvocationStmt] super(...) +# 1| 1: [BlockStmt] { ... } +d.kt: +# 0| [CompilationUnit] d +# 1| 1: [Class] D +# 0| 2: [FieldDeclaration] String bar; +# 0| -1: [TypeAccess] String +# 0| 0: [StringLiteral] Foobar +# 1| 3: [Constructor] D +# 1| 5: [BlockStmt] { ... } +# 1| 0: [SuperConstructorInvocationStmt] super(...) +# 1| 1: [BlockStmt] { ... } +e.kt: +# 0| [CompilationUnit] e +# 1| 1: [Class] E +# 0| 1: [Method] +# 0| 3: [TypeAccess] boolean +# 0| 5: [BlockStmt] { ... } +# 0| 0: [ReturnStmt] return ... +# 0| 0: [MethodAccess] add(...) +# 0| -1: [ClassInstanceExpr] new ArrayList(...) +# 0| -3: [TypeAccess] ArrayList +# 0| 0: [IntegerLiteral] 1 +# 0| 0: [NullLiteral] null +# 0| 2: [Method] +# 0| 3: [TypeAccess] Object +# 0| 5: [BlockStmt] { ... } +# 0| 0: [ReturnStmt] return ... +# 0| 0: [MethodAccess] put(...) +# 0| -1: [ClassInstanceExpr] new LinkedHashMap(...) +# 0| -3: [TypeAccess] LinkedHashMap +# 0| 0: [IntegerLiteral] 1 +# 0| 0: [NullLiteral] null +# 0| 1: [NullLiteral] null +# 1| 3: [Constructor] E +# 1| 5: [BlockStmt] { ... } +# 1| 0: [SuperConstructorInvocationStmt] super(...) +# 1| 1: [BlockStmt] { ... } diff --git a/java/ql/integration-tests/linux-only/kotlin/custom_plugin/PrintAst.qlref b/java/ql/integration-tests/linux-only/kotlin/custom_plugin/PrintAst.qlref new file mode 100644 index 00000000000..c7fd5faf239 --- /dev/null +++ b/java/ql/integration-tests/linux-only/kotlin/custom_plugin/PrintAst.qlref @@ -0,0 +1 @@ +semmle/code/java/PrintAst.ql \ No newline at end of file diff --git a/java/ql/integration-tests/linux-only/kotlin/custom_plugin/a.kt b/java/ql/integration-tests/linux-only/kotlin/custom_plugin/a.kt new file mode 100644 index 00000000000..922e7e86703 --- /dev/null +++ b/java/ql/integration-tests/linux-only/kotlin/custom_plugin/a.kt @@ -0,0 +1,3 @@ +class A { + fun f1() = 1 +} diff --git a/java/ql/integration-tests/linux-only/kotlin/custom_plugin/b.kt b/java/ql/integration-tests/linux-only/kotlin/custom_plugin/b.kt new file mode 100644 index 00000000000..7d95eb64996 --- /dev/null +++ b/java/ql/integration-tests/linux-only/kotlin/custom_plugin/b.kt @@ -0,0 +1,2 @@ +class B { +} diff --git a/java/ql/integration-tests/linux-only/kotlin/custom_plugin/build_plugin b/java/ql/integration-tests/linux-only/kotlin/custom_plugin/build_plugin new file mode 100755 index 00000000000..c38ab33eb75 --- /dev/null +++ b/java/ql/integration-tests/linux-only/kotlin/custom_plugin/build_plugin @@ -0,0 +1,53 @@ +#!/usr/bin/env python3 + +import subprocess +import shutil +import os +import os.path +import sys +import shlex + + +def run_process(cmd): + try: + print("Running command: " + shlex.join(cmd)) + return subprocess.run(cmd, check=True, capture_output=True) + except subprocess.CalledProcessError as e: + print("In: " + os.getcwd(), file=sys.stderr) + print("Command failed: " + shlex.join(cmd), file=sys.stderr) + print("stdout output:\n" + e.stdout.decode(encoding='UTF-8', + errors='strict'), file=sys.stderr) + print("stderr output:\n" + e.stderr.decode(encoding='UTF-8', + errors='strict'), file=sys.stderr) + raise e + +root = '../../../../../../../../..' + +sys.path.append(root + '/ql/java/kotlin-extractor') +import kotlin_plugin_versions +defaultKotlinDependencyVersion = kotlin_plugin_versions.get_single_version() + +builddir = 'build' +dependency_dir = root + '/resources/kotlin-dependencies/' +dependencies = ['kotlin-stdlib-' + defaultKotlinDependencyVersion + + '.jar', 'kotlin-compiler-' + defaultKotlinDependencyVersion + '.jar'] +classpath = ':'.join([dependency_dir + dep for dep in dependencies]) +srcs = ['plugin/Plugin.kt'] +output = 'plugin.jar' + +if os.path.exists(builddir): + shutil.rmtree(builddir) +os.makedirs(builddir) + +run_process(['kotlinc', + '-J-Xmx2G', + '-d', builddir, + '-module-name', 'test', + '-no-reflect', '-no-stdlib', + '-jvm-target', '1.8', + '-classpath', classpath] + srcs) + +run_process(['jar', '-c', '-f', output, + '-C', builddir, '.', + '-C', 'plugin/resources', 'META-INF']) +shutil.rmtree(builddir) diff --git a/java/ql/integration-tests/linux-only/kotlin/custom_plugin/c.kt b/java/ql/integration-tests/linux-only/kotlin/custom_plugin/c.kt new file mode 100644 index 00000000000..b0a84db03d1 --- /dev/null +++ b/java/ql/integration-tests/linux-only/kotlin/custom_plugin/c.kt @@ -0,0 +1 @@ +class C { } diff --git a/java/ql/integration-tests/linux-only/kotlin/custom_plugin/d.kt b/java/ql/integration-tests/linux-only/kotlin/custom_plugin/d.kt new file mode 100644 index 00000000000..8472937f6bc --- /dev/null +++ b/java/ql/integration-tests/linux-only/kotlin/custom_plugin/d.kt @@ -0,0 +1 @@ +class D { } diff --git a/java/ql/integration-tests/linux-only/kotlin/custom_plugin/diagnostics.expected b/java/ql/integration-tests/linux-only/kotlin/custom_plugin/diagnostics.expected new file mode 100644 index 00000000000..183abf9a986 --- /dev/null +++ b/java/ql/integration-tests/linux-only/kotlin/custom_plugin/diagnostics.expected @@ -0,0 +1,2 @@ +| CodeQL Kotlin extractor | 2 | | IrProperty without a getter | d.kt:0:0:0:0 | d.kt:0:0:0:0 | +| CodeQL Kotlin extractor | 2 | | Not rewriting trap file for: Boolean -1.0-0- -1.0-0-null test-db/trap/java/classes/kotlin/Boolean.members.trap.gz | file://:0:0:0:0 | file://:0:0:0:0 | diff --git a/java/ql/integration-tests/linux-only/kotlin/custom_plugin/diagnostics.ql b/java/ql/integration-tests/linux-only/kotlin/custom_plugin/diagnostics.ql new file mode 100755 index 00000000000..57ec32bb048 --- /dev/null +++ b/java/ql/integration-tests/linux-only/kotlin/custom_plugin/diagnostics.ql @@ -0,0 +1,13 @@ +import java + +from string genBy, int severity, string tag, string msg, Location l +where + diagnostics(_, genBy, severity, tag, msg, _, l) and + ( + // Different installations get different sets of these messages, + // so we filter out all but one that happens everywhere. + msg.matches("Not rewriting trap file for: %") + implies + msg.matches("Not rewriting trap file for: Boolean %") + ) +select genBy, severity, tag, msg, l diff --git a/java/ql/integration-tests/linux-only/kotlin/custom_plugin/e.kt b/java/ql/integration-tests/linux-only/kotlin/custom_plugin/e.kt new file mode 100644 index 00000000000..f4b8aa5df61 --- /dev/null +++ b/java/ql/integration-tests/linux-only/kotlin/custom_plugin/e.kt @@ -0,0 +1 @@ +class E { } diff --git a/java/ql/integration-tests/linux-only/kotlin/custom_plugin/methods.expected b/java/ql/integration-tests/linux-only/kotlin/custom_plugin/methods.expected new file mode 100644 index 00000000000..c485610e7b3 --- /dev/null +++ b/java/ql/integration-tests/linux-only/kotlin/custom_plugin/methods.expected @@ -0,0 +1,7 @@ +| a.kt:0:0:0:0 | | has body | +| a.kt:2:5:2:16 | f1 | has body | +| b.kt:0:0:0:0 | | has body | +| c.kt:0:0:0:0 | | has body | +| d.kt:0:0:0:0 | | has body | +| e.kt:0:0:0:0 | | has body | +| e.kt:0:0:0:0 | | has body | diff --git a/java/ql/integration-tests/linux-only/kotlin/custom_plugin/methods.ql b/java/ql/integration-tests/linux-only/kotlin/custom_plugin/methods.ql new file mode 100755 index 00000000000..adb7c8784e5 --- /dev/null +++ b/java/ql/integration-tests/linux-only/kotlin/custom_plugin/methods.ql @@ -0,0 +1,7 @@ +import java + +from Method m, string body +where + m.fromSource() and + if exists(m.getBody()) then body = "has body" else body = "has no body" +select m, body diff --git a/java/ql/integration-tests/linux-only/kotlin/custom_plugin/plugin/Plugin.kt b/java/ql/integration-tests/linux-only/kotlin/custom_plugin/plugin/Plugin.kt new file mode 100644 index 00000000000..c88410ca9db --- /dev/null +++ b/java/ql/integration-tests/linux-only/kotlin/custom_plugin/plugin/Plugin.kt @@ -0,0 +1,280 @@ +package com.github.codeql + +import com.intellij.mock.MockProject +import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext +import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension +import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext +import org.jetbrains.kotlin.backend.common.ir.createImplicitParameterDeclarationWithWrappedDescriptor +import org.jetbrains.kotlin.backend.common.lower.DeclarationIrBuilder +import org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar +import org.jetbrains.kotlin.config.CompilerConfiguration +import org.jetbrains.kotlin.descriptors.ClassKind +import org.jetbrains.kotlin.descriptors.DescriptorVisibilities +import org.jetbrains.kotlin.descriptors.Modality +import org.jetbrains.kotlin.ir.IrStatement +import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI +import org.jetbrains.kotlin.ir.builders.declarations.* +import org.jetbrains.kotlin.ir.builders.irCall +import org.jetbrains.kotlin.ir.builders.irExprBody +import org.jetbrains.kotlin.ir.builders.irGet +import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.declarations.impl.IrExternalPackageFragmentImpl +import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl +import org.jetbrains.kotlin.ir.expressions.IrExpression +import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl +import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl +import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl +import org.jetbrains.kotlin.ir.symbols.IrClassSymbol +import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol +import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol +import org.jetbrains.kotlin.ir.types.IrType +import org.jetbrains.kotlin.ir.types.defaultType +import org.jetbrains.kotlin.ir.types.typeWith +import org.jetbrains.kotlin.ir.util.defaultType +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.Name + +class TestComponentRegistrar : ComponentRegistrar { + override fun registerProjectComponents( + project: MockProject, + configuration: CompilerConfiguration + ) { + IrGenerationExtension.registerExtension(project, IrAdder()) + } +} + +@OptIn(ObsoleteDescriptorBasedAPI::class) +class IrAdder : IrGenerationExtension { + override fun generate(moduleFragment: IrModuleFragment, pluginContext: IrPluginContext) { + + class AndroidSymbols { + private val irFactory: IrFactory = IrFactoryImpl + private val kotlinJvmInternalPackage: IrPackageFragment = createPackage("kotlin.jvm.internal") + private val javaUtil: IrPackageFragment = createPackage("java.util") + + private fun createPackage(packageName: String): IrPackageFragment = + IrExternalPackageFragmentImpl.createEmptyExternalPackageFragment( + moduleFragment.descriptor, + FqName(packageName) + ) + + private fun createClass( + irPackage: IrPackageFragment, + shortName: String, + classKind: ClassKind, + classModality: Modality + ): IrClassSymbol = irFactory.buildClass { + name = Name.identifier(shortName) + kind = classKind + modality = classModality + }.apply { + parent = irPackage + createImplicitParameterDeclarationWithWrappedDescriptor() + }.symbol + + val unsafeCoerceIntrinsic: IrSimpleFunctionSymbol = + irFactory.buildFun { + name = Name.special("") + origin = IrDeclarationOrigin.IR_BUILTINS_STUB + }.apply { + parent = kotlinJvmInternalPackage + val src = addTypeParameter("T", pluginContext.irBuiltIns.anyNType) + val dst = addTypeParameter("R", pluginContext.irBuiltIns.anyNType) + addValueParameter("v", src.defaultType) + returnType = dst.defaultType + }.symbol + + val javaUtilArrayList: IrClassSymbol = + createClass(javaUtil, "ArrayList", ClassKind.CLASS, Modality.OPEN) + + val javaUtilLinkedHashMap: IrClassSymbol = + createClass(javaUtil, "LinkedHashMap", ClassKind.CLASS, Modality.OPEN) + + val arrayListConstructor: IrConstructorSymbol = javaUtilArrayList.owner.addConstructor().apply { + addValueParameter("p_0", pluginContext.irBuiltIns.intType) + }.symbol + + val arrayListAdd: IrSimpleFunctionSymbol = + javaUtilArrayList.owner.addFunction("add", pluginContext.irBuiltIns.booleanType).apply { + addValueParameter("p_0", pluginContext.irBuiltIns.anyNType) + }.symbol + + val linkedHashMapConstructor: IrConstructorSymbol = + javaUtilLinkedHashMap.owner.addConstructor().apply { + addValueParameter("p_0", pluginContext.irBuiltIns.intType) + }.symbol + + val linkedHashMapPut: IrSimpleFunctionSymbol = + javaUtilLinkedHashMap.owner.addFunction("put", pluginContext.irBuiltIns.anyNType).apply { + addValueParameter("p_0", pluginContext.irBuiltIns.anyNType) + addValueParameter("p_1", pluginContext.irBuiltIns.anyNType) + }.symbol + } + + moduleFragment.transform(object: IrElementTransformerVoidWithContext() { + override fun visitClassNew(declaration: IrClass): IrStatement { + if (declaration.name.asString() == "A") { + addFunWithExprBody(declaration) + } else if (declaration.name.asString() == "B") { + addFunWithUnsafeCoerce(declaration) + } else if (declaration.name.asString() == "C") { + addFunWithStubClass(declaration) + } else if (declaration.name.asString() == "D") { + addStaticFieldWithExprInit(declaration) + } else if (declaration.name.asString() == "E") { + addFunWithArrayListAdd(declaration) + addFunWithLinkedHashMapPut(declaration) + } + + return super.visitClassNew(declaration) + } + + fun unsafeCoerce(value: IrExpression, fromType: IrType, toType: IrType): IrExpression { + return IrCallImpl.fromSymbolOwner(-1, -1, toType, AndroidSymbols().unsafeCoerceIntrinsic).apply { + putTypeArgument(0, fromType) + putTypeArgument(1, toType) + putValueArgument(0, value) + } + } + + private fun arrayListAdd(): IrExpression { + // ArrayList(1).add(null) + var androidSymbols = AndroidSymbols() + return IrCallImpl.fromSymbolOwner(-1, -1, pluginContext.irBuiltIns.booleanType, androidSymbols.arrayListAdd).apply { + dispatchReceiver = IrConstructorCallImpl.fromSymbolOwner(-1,-1, androidSymbols.javaUtilArrayList.typeWith(), androidSymbols.arrayListConstructor).apply { + putValueArgument(0, IrConstImpl.int(-1, -1, pluginContext.irBuiltIns.intType, 1)) + } + putValueArgument(0, IrConstImpl.constNull(-1,-1, pluginContext.irBuiltIns.anyNType)) + } + } + + private fun linkedHashMapPut(): IrExpression { + // LinkedHashMap(1).put(null, null) + var androidSymbols = AndroidSymbols() + return IrCallImpl.fromSymbolOwner(-1, -1, pluginContext.irBuiltIns.anyNType, androidSymbols.linkedHashMapPut).apply { + dispatchReceiver = IrConstructorCallImpl.fromSymbolOwner(-1,-1, androidSymbols.javaUtilLinkedHashMap.typeWith(), androidSymbols.linkedHashMapConstructor).apply { + putValueArgument(0, IrConstImpl.int(-1, -1, pluginContext.irBuiltIns.intType, 1)) + } + putValueArgument(0, IrConstImpl.constNull(-1,-1, pluginContext.irBuiltIns.anyNType)) + putValueArgument(1, IrConstImpl.constNull(-1,-1, pluginContext.irBuiltIns.anyNType)) + } + } + + private fun addFunWithArrayListAdd(declaration: IrClass) { + declaration.declarations.add(pluginContext.irFactory.buildFun { + name = Name.identifier("") + returnType = pluginContext.irBuiltIns.booleanType + }. also { + it.body = DeclarationIrBuilder(pluginContext, it.symbol) + .irExprBody( + arrayListAdd() + ) + it.parent = declaration + }) + } + + private fun addFunWithLinkedHashMapPut(declaration: IrClass) { + declaration.declarations.add(pluginContext.irFactory.buildFun { + name = Name.identifier("") + returnType = pluginContext.irBuiltIns.anyNType + }. also { + it.body = DeclarationIrBuilder(pluginContext, it.symbol) + .irExprBody( + linkedHashMapPut() + ) + it.parent = declaration + }) + } + + private fun addFunWithUnsafeCoerce(declaration: IrClass) { + val uintType = pluginContext.referenceClass(FqName("kotlin.UInt"))!!.owner.typeWith() + declaration.declarations.add(pluginContext.irFactory.buildFun { + name = Name.identifier("") + returnType = uintType + }. also { + it.body = DeclarationIrBuilder(pluginContext, it.symbol) + .irExprBody( + unsafeCoerce(IrConstImpl.int(-1, -1, pluginContext.irBuiltIns.intType, 1), pluginContext.irBuiltIns.intType, uintType) + ) + it.parent = declaration + }) + } + + private fun addFunWithExprBody(declaration: IrClass) { + declaration.declarations.add(pluginContext.irFactory.buildFun { + name = Name.identifier("") + returnType = pluginContext.irBuiltIns.intType + }. also { + it.body = DeclarationIrBuilder(pluginContext, it.symbol) + .irExprBody( + IrConstImpl.int(-1, -1, pluginContext.irBuiltIns.intType, 42) + ) + it.parent = declaration + }) + } + + private fun addStaticFieldWithExprInit(declaration: IrClass) { + declaration.declarations.add(pluginContext.irFactory.buildProperty { + name = Name.identifier("bar") + isConst = true + visibility = DescriptorVisibilities.PRIVATE + }.also { irProperty -> + irProperty.backingField = pluginContext.irFactory.buildField { + name = Name.identifier("bar") + type = pluginContext.irBuiltIns.stringType + isStatic = true + visibility = DescriptorVisibilities.PRIVATE + }.also { irField -> + irField.initializer = DeclarationIrBuilder(pluginContext, irField.symbol) + .irExprBody( + IrConstImpl.string(-1, -1, pluginContext.irBuiltIns.stringType, "Foobar") + ) + irField.parent = declaration + } + irProperty.parent = declaration + }) + } + + val javaLangPackage = IrExternalPackageFragmentImpl.createEmptyExternalPackageFragment(pluginContext.moduleDescriptor, FqName("java.lang")) + + private fun makeJavaLangClass(fnName: String) = pluginContext.irFactory.buildClass { + name = Name.identifier(fnName) + kind = ClassKind.CLASS + origin = IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB + }.apply { + parent = javaLangPackage + createImplicitParameterDeclarationWithWrappedDescriptor() + } + + // This adds a function with a parameter whose type is a real class without its supertypes specified, + // mimicking the behaviour of the Kotlin android extensions gradle plugin, which refers to some real + // Android classes through these sorts of synthetic, incomplete references. The extractor should + // respond by replacing them with the real version available on the classpath. + // I pick the particular java.lang class "ProcessBuilder" since it is (a) always available and + // (b) not normally extracted by this project. + private fun addFunWithStubClass(declaration: IrClass) { + declaration.declarations.add(pluginContext.irFactory.buildFun { + name = Name.identifier("") + returnType = pluginContext.irBuiltIns.unitType + }. also { addedFn -> + val processBuilderStub = makeJavaLangClass("ProcessBuilder") + val processBuilderStubType = processBuilderStub.defaultType + val startProcessMethod = processBuilderStub.addFunction { + name = Name.identifier("start") + origin = IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB + modality = Modality.FINAL + returnType = pluginContext.referenceClass(FqName("java.lang.Process"))!!.owner.defaultType + }.apply { + addDispatchReceiver { type = processBuilderStubType } + } + + val paramSymbol = addedFn.addValueParameter("param", processBuilderStubType) + DeclarationIrBuilder(pluginContext, addedFn.symbol).apply { + addedFn.body = irExprBody(irCall(startProcessMethod).apply { dispatchReceiver = irGet(paramSymbol) }) + addedFn.parent = declaration + } + }) + } + }, null) + } +} diff --git a/java/ql/integration-tests/linux-only/kotlin/custom_plugin/plugin/resources/META-INF/services/org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar b/java/ql/integration-tests/linux-only/kotlin/custom_plugin/plugin/resources/META-INF/services/org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar new file mode 100644 index 00000000000..5d546a3b00a --- /dev/null +++ b/java/ql/integration-tests/linux-only/kotlin/custom_plugin/plugin/resources/META-INF/services/org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar @@ -0,0 +1 @@ +com.github.codeql.TestComponentRegistrar diff --git a/java/ql/integration-tests/linux-only/kotlin/custom_plugin/rootClasses.expected b/java/ql/integration-tests/linux-only/kotlin/custom_plugin/rootClasses.expected new file mode 100644 index 00000000000..1f41ac1e6bb --- /dev/null +++ b/java/ql/integration-tests/linux-only/kotlin/custom_plugin/rootClasses.expected @@ -0,0 +1,4 @@ +| file://:0:0:0:0 | fake.kotlin | FakeKotlinClass | +| file://:0:0:0:0 | java.lang | Object | +| file://:0:0:0:0 | kotlin | Any | +| file://:0:0:0:0 | kotlin | TypeParam | diff --git a/java/ql/integration-tests/linux-only/kotlin/custom_plugin/rootClasses.ql b/java/ql/integration-tests/linux-only/kotlin/custom_plugin/rootClasses.ql new file mode 100644 index 00000000000..640ae984d14 --- /dev/null +++ b/java/ql/integration-tests/linux-only/kotlin/custom_plugin/rootClasses.ql @@ -0,0 +1,5 @@ +import java + +from ClassOrInterface ci +where not exists(ci.getASupertype()) +select ci.getPackage(), ci.toString() diff --git a/java/ql/integration-tests/linux-only/kotlin/custom_plugin/staticinit.expected b/java/ql/integration-tests/linux-only/kotlin/custom_plugin/staticinit.expected new file mode 100644 index 00000000000..606bbd3f338 --- /dev/null +++ b/java/ql/integration-tests/linux-only/kotlin/custom_plugin/staticinit.expected @@ -0,0 +1 @@ +| d.kt:0:0:0:0 | bar | d.kt:0:0:0:0 | Foobar | diff --git a/java/ql/integration-tests/linux-only/kotlin/custom_plugin/staticinit.ql b/java/ql/integration-tests/linux-only/kotlin/custom_plugin/staticinit.ql new file mode 100644 index 00000000000..de6bd1ca92e --- /dev/null +++ b/java/ql/integration-tests/linux-only/kotlin/custom_plugin/staticinit.ql @@ -0,0 +1,5 @@ +import java + +from Field f, Expr init +where init = f.getInitializer() +select f, init diff --git a/java/ql/integration-tests/linux-only/kotlin/custom_plugin/test.py b/java/ql/integration-tests/linux-only/kotlin/custom_plugin/test.py new file mode 100644 index 00000000000..98610959b58 --- /dev/null +++ b/java/ql/integration-tests/linux-only/kotlin/custom_plugin/test.py @@ -0,0 +1,6 @@ +from create_database_utils import * +import subprocess + +subprocess.call("./build_plugin", shell=True) +run_codeql_database_create( + ["kotlinc -J-Xmx2G -Xplugin=plugin.jar a.kt b.kt c.kt d.kt e.kt"], lang="java") diff --git a/java/ql/integration-tests/linux-only/kotlin/qlpack.yml b/java/ql/integration-tests/linux-only/kotlin/qlpack.yml new file mode 100644 index 00000000000..11adb1f538b --- /dev/null +++ b/java/ql/integration-tests/linux-only/kotlin/qlpack.yml @@ -0,0 +1,2 @@ +libraryPathDependencies: + - codeql-java diff --git a/java/ql/integration-tests/linux-only/kotlin/use_java_library/javasrc/extlib/BoundedGenericTest.java b/java/ql/integration-tests/linux-only/kotlin/use_java_library/javasrc/extlib/BoundedGenericTest.java new file mode 100644 index 00000000000..1bc13098a62 --- /dev/null +++ b/java/ql/integration-tests/linux-only/kotlin/use_java_library/javasrc/extlib/BoundedGenericTest.java @@ -0,0 +1,8 @@ +package extlib; + +public class BoundedGenericTest { + + public void method(T t) { } + +} + diff --git a/java/ql/integration-tests/linux-only/kotlin/use_java_library/javasrc/extlib/ComplexBoundedGenericTest.java b/java/ql/integration-tests/linux-only/kotlin/use_java_library/javasrc/extlib/ComplexBoundedGenericTest.java new file mode 100644 index 00000000000..16d0d950e0c --- /dev/null +++ b/java/ql/integration-tests/linux-only/kotlin/use_java_library/javasrc/extlib/ComplexBoundedGenericTest.java @@ -0,0 +1,8 @@ +package extlib; + +public class ComplexBoundedGenericTest { + + public void method(A a, B b) { } + +} + diff --git a/java/ql/integration-tests/linux-only/kotlin/use_java_library/javasrc/extlib/GenericTest.java b/java/ql/integration-tests/linux-only/kotlin/use_java_library/javasrc/extlib/GenericTest.java new file mode 100644 index 00000000000..d953cf90b98 --- /dev/null +++ b/java/ql/integration-tests/linux-only/kotlin/use_java_library/javasrc/extlib/GenericTest.java @@ -0,0 +1,10 @@ +package extlib; + +public class GenericTest { + + public void method(T t) { } + + public void takesSelfMethod(GenericTest selfLike) { } + +} + diff --git a/java/ql/integration-tests/linux-only/kotlin/use_java_library/javasrc/extlib/Lib.java b/java/ql/integration-tests/linux-only/kotlin/use_java_library/javasrc/extlib/Lib.java new file mode 100644 index 00000000000..f533e43c527 --- /dev/null +++ b/java/ql/integration-tests/linux-only/kotlin/use_java_library/javasrc/extlib/Lib.java @@ -0,0 +1,35 @@ +package extlib; + +import java.util.*; + +public class Lib { + + public void testParameterTypes( + char p1, + byte p2, + short p3, + int p4, + long p5, + float p6, + double p7, + boolean p8, + Lib simpleClass, + GenericTest simpleGeneric, + BoundedGenericTest
Incorrect closing of the connection leads to the creation of different states for the server and client, which can be exploited by an attacker.
The following example shows the incorrect and correct usage of function SSL_shutdown.